大文件上传失败:大小限制、UPLOAD_FILE_SIZE_LIMIT、Nginx设置、分割上传实践
简介
在知识库建设项目中,经常出现“尝试上传大于100MB的PDF失败”的问题。文件越大,问题就越超出“上传失败”的范围,并级联到反向代理限制、后端配置限制、存储写入以及后续的解析、分块和索引。
在本文中,我们确定了导致大文件上传失败的多个层,并解释了实用的解决方案,从更改每个层的设置到构建预处理管道。
症状
| 症状 | 错误消息示例 | 故障层 |
|---|---|---|
| 上传在浏览器中途停止 | (网络错误) | 浏览器/客户端 |
| 413 请求实体太大 | 413 Payload Too Large | Nginx / 反向代理 |
| 文件大小限制错误 | File size exceeds the limit | Dify后端 |
| 上传成功但处理未完成 | (超时/状态仍在处理中) | 分析/指标处理 |
| 写入 S3/MinIO 时出错 | PutObject failed / Connection reset | 对象存储 |
原因分析
大文件上传失败发生在以下五层中的一层(或多层):
flowchart TD
A[ファイルアップロード] --> B[レイヤー1: ブラウザ/クライアント]
B --> C[レイヤー2: リバースプロキシ Nginx/Ingress]
C --> D[レイヤー3: Dify バックエンド]
D --> E[レイヤー4: オブジェクトストレージ]
E --> F[レイヤー5: 後続処理パイプライン]
B -.->|タイムアウト| B1[接続切れ]
C -.->|413エラー| C1[body size制限]
D -.->|サイズ制限| D1[UPLOAD_FILE_SIZE_LIMIT]
E -.->|書込失敗| E1[権限/容量]
F -.->|処理超過| F1[解析タイムアウト]
第 1 层:浏览器/客户端
- 浏览器内存限制(特别是当您打开大量选项卡时)
- 网络连接不稳定
- 浏览器文件上传超时
第 2 层:反向代理(Nginx/Kubernetes 入口)
这是最常见的故障点。 Dify 的自托管环境几乎总是以 Nginx 或 Kubernetes Ingress 为前端。在默认设置中,请求正文大小限制通常在 1MB 到 10MB 左右。
Nginx 默认设置:
# デフォルト: client_max_body_size 1m;
# → 1MB を超えるファイルが 413 エラーで拒否される
第 3 层:配置 Dify 后端
Dify 本身也将文件大小的上限设置为环境变量。
| 环境变量 | 默认值 | 描述 |
|---|---|---|
UPLOAD_FILE_SIZE_LIMIT | 15 (MB) | 单个文件最大上传大小 |
UPLOAD_FILE_BATCH_LIMIT | 5 | 一次可上传的文件数 |
UPLOAD_IMAGE_FILE_SIZE_LIMIT | 10 (MB) | 图像文件的最大大小 |
ETL_TYPE | dify | 文档分析引擎(dify/非结构化) |
第 4 层:对象存储
Dify 支持以下文件存储位置:
- 本地文件系统 -亚马逊S3 -Azure Blob 存储 -谷歌云存储
- 腾讯云 COS -华为云OBS
- MinIO(S3兼容)
每个存储对分段上传和单次上传限制的支持不同(S3:5GB、Azure Blob:256MB 等),因此请提前检查。
###第5层:后续处理管道
即使文件本身上传成功,还需要进行以下后续处理才能将其注册到知识库中,并且每次都有超时的风险。
アップロード → テキスト抽出 → チャンク分割 → Embedding生成 → ベクトルDB書込
对于超过 100MB 的 PDF:
- 文本提取需要几分钟到几十分钟
- 大量 API 调用来生成数千个块的嵌入
- 大量写入矢量数据库
解决方案
解决方案 1:更改 Nginx/反向代理设置
对于 Nginx:
# /etc/nginx/nginx.conf または /etc/nginx/conf.d/default.conf
http {
# リクエストボディの最大サイズを 200MB に拡大
client_max_body_size 200m;
# アップロードタイムアウトの延長
client_body_timeout 300s;
# プロキシタイムアウトの延長
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
# 大容量リクエストのバッファ設定
client_body_buffer_size 10m;
client_body_temp_path /tmp/nginx_upload;
}
对于 Kubernetes Ingress(Nginx 入口控制器):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dify-ingress
annotations:
# リクエストボディの最大サイズ
nginx.ingress.kubernetes.io/proxy-body-size: "200m"
# タイムアウト設定
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
spec:
rules:
- host: dify.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dify-web
port:
number: 80
对于与 Docker Compose 捆绑在一起的 Nginx: 编辑 docker/nginx/conf.d/default.conf 并以相同的方式设置 client_max_body_size 200m; 和代理超时。
解决方案2:调整Dify环境变量
在 .env 文件或 docker-compose.yml 中设置以下内容:
# ファイルアップロード制限の拡大
UPLOAD_FILE_SIZE_LIMIT=200 # 200MB に変更
UPLOAD_FILE_BATCH_LIMIT=10 # バッチ上限を10ファイルに
# ドキュメント解析エンジンの変更(大容量PDF対応)
ETL_TYPE=Unstructured # Unstructured.io を使用
UNSTRUCTURED_API_URL=http://unstructured:8000/general/v0/general
# ワーカー設定の調整
CELERY_WORKER_AMOUNT=4 # バックグラウンドワーカー数
设置更改后的反映:
# Docker Compose 環境の場合
cd /path/to/dify/docker
docker compose down
docker compose up -d
# 設定が反映されたことを確認
docker compose exec api env | grep UPLOAD
解决方案 3:配置对象存储
对于亚马逊 S3:
# .env ファイル
STORAGE_TYPE=s3
S3_ENDPOINT=https://s3.ap-northeast-1.amazonaws.com
S3_BUCKET_NAME=dify-storage
S3_ACCESS_KEY=YOUR_ACCESS_KEY
S3_SECRET_KEY=YOUR_SECRET_KEY
S3_REGION=ap-northeast-1
对于 MinIO(兼容本地 S3):
# .env ファイル
STORAGE_TYPE=s3
S3_ENDPOINT=http://minio:9000
S3_BUCKET_NAME=dify-storage
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_REGION=us-east-1
S3_USE_AWS_MANAGED_IAM=false
解决方案 4:文件预处理管道
我们强烈建议您不要按原样上传大于100MB的PDF,而应提前对其进行预处理。
Python 中的 PDF 预处理脚本(使用 PyPDF2):
from PyPDF2 import PdfReader, PdfWriter
import os
def split_pdf(input_path: str, output_dir: str, max_pages: int = 50):
"""大容量PDFをページ数で分割する"""
reader = PdfReader(input_path)
os.makedirs(output_dir, exist_ok=True)
for start in range(0, len(reader.pages), max_pages):
writer = PdfWriter()
for p in range(start, min(start + max_pages, len(reader.pages))):
writer.add_page(reader.pages[p])
out = os.path.join(output_dir, f"part{start//max_pages+1}.pdf")
with open(out, "wb") as f:
writer.write(f)
# 使用例: split_pdf("/path/to/large.pdf", "/path/to/output/", max_pages=30)
OCR 预处理(针对扫描 PDF):
# OCRmyPDF で日本語OCR処理
pip install ocrmypdf
ocrmypdf --language jpn --deskew --clean input_scan.pdf output_ocr.pdf
解决方案 5:使用 Dify API 进行编程上传
从 API 而不是浏览器 UI 上传大文件可以更轻松地控制超时。
import requests, os
def upload_document(api_base, api_key, dataset_id, file_path):
url = f"{api_base}/datasets/{dataset_id}/document/create_by_file"
with open(file_path, "rb") as f:
resp = requests.post(url,
headers={"Authorization": f"Bearer {api_key}"},
files={"file": (os.path.basename(file_path), f, "application/pdf")},
data={"data": '{"indexing_technique":"high_quality","process_rule":{"mode":"automatic"}}'},
timeout=600)
return resp.json() if resp.status_code == 200 else None
# 分割済みPDFを順次アップロード
for pdf in sorted(os.listdir("/path/to/split_pdfs/")):
if pdf.endswith(".pdf"):
upload_document("https://dify.example.com/v1", "YOUR_KEY", "DATASET_ID",
f"/path/to/split_pdfs/{pdf}")
解决方案 6:按主题拆分知识库
不要将大量文档塞进一个知识库,而是按主题将其拆分。
Before:
ナレッジベース「全社マニュアル」 ← 500MB分のPDF
After:
ナレッジベース「人事規程」 ← 就業規則、福利厚生、評価制度
ナレッジベース「IT手順書」 ← VPN、メール、セキュリティ
ナレッジベース「経理マニュアル」 ← 経費精算、請求、税務
ナレッジベース「製品仕様書」 ← 製品A仕様、製品B仕様
好处:
- 轻松更新个人文档
- 提高搜索准确性(因为域缩小了)
- 上传失败影响范围有限
注意事项
1. 预上传清单
上传文件之前,请检查以下内容:
- 文件大小是否小于或等于
UPLOAD_FILE_SIZE_LIMIT? - Nginx / Ingress 的
client_max_body_size够用吗? - 您是否删除了不必要的页面(空白、封面、目录、索引)?
- 如果是扫描版PDF,是否经过OCR处理?
- 文件是否损坏? (检查是否可以用PDF阅读器打开。)
2.设置值的一致性检查
检查各层的限值是否一致。
Nginx client_max_body_size >= UPLOAD_FILE_SIZE_LIMIT >= 実際のファイルサイズ
常见矛盾的例子:
| nginx | Dify | 结果 |
|---|---|---|
| 1m(默认) | 15MB | Nginx 413 错误 |
| 200m | 15MB(默认) | Dify 后端大小错误 |
| 200m | 200MB | OK(但要注意后续处理超时) |
3.大文件操作流程标准化
flowchart TD
A[原本PDF] --> B{サイズ > 15MB?}
B -->|No| C[そのままアップロード]
B -->|Yes| D[前処理パイプライン]
D --> E[空白ページ除去]
E --> F[OCR処理 if スキャンPDF]
F --> G{サイズ > 15MB?}
G -->|No| C
G -->|Yes| H[チャプター/ページ分割]
H --> I[分割ファイルを順次アップロード]
C --> J[インデックス処理完了を確認]
I --> J
J --> K[検索品質テスト]
4. 监控
定期通过API调用GET /datasets/{dataset_id}/documents,检查每个文档的indexing_status是否变为completed。如果长时间停留在processing,则怀疑后续管道超时。
总结
上传大于 100MB 的 PDF 失败通常无法通过更改单个设置来解决。 Nginx 的请求体大小限制、Dify 的 UPLOAD_FILE_SIZE_LIMIT、对象存储配置以及后续的解析管道超时都会产生级联效应。
最有效的方法不仅是调整上传限制,还需要构建文件预处理管道,在上传之前将大文件分割并优化为合适的大小。这不仅提高了上传成功率,还提高了知识库的搜索质量。
参考资料
-Environment Variables - Dify Docs -Deploy Dify with Docker Compose -ファイルアップロード | Dify Docs(日本語) -ナレッジパイプラインをオーケストレーションする | Dify Docs