Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

大文件上传失败:大小限制、UPLOAD_FILE_SIZE_LIMIT、Nginx设置、分割上传实践

简介

在知识库建设项目中,经常出现“尝试上传大于100MB的PDF失败”的问题。文件越大,问题就越超出“上传失败”的范围,并级联到反向代理限制、后端配置限制、存储写入以及后续的解析、分块和索引。

在本文中,我们确定了导致大文件上传失败的多个层,并解释了实用的解决方案,从更改每个层的设置到构建预处理管道。


症状

症状错误消息示例故障层
上传在浏览器中途停止(网络错误)浏览器/客户端
413 请求实体太大413 Payload Too LargeNginx / 反向代理
文件大小限制错误File size exceeds the limitDify后端
上传成功但处理未完成(超时/状态仍在处理中)分析/指标处理
写入 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_LIMIT15 (MB)单个文件最大上传大小
UPLOAD_FILE_BATCH_LIMIT5一次可上传的文件数
UPLOAD_IMAGE_FILE_SIZE_LIMIT10 (MB)图像文件的最大大小
ETL_TYPEdify文档分析引擎(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  >=  実際のファイルサイズ

常见矛盾的例子:

nginxDify结果
1m(默认)15MBNginx 413 错误
200m15MB(默认)Dify 后端大小错误
200m200MBOK(但要注意后续处理超时)

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