flask层必须在初始化时设置max_content_length(单位字节,仅整数),否则无效;它由werkzeug在解析前拦截并返回413,不读请求体、无内存开销,且需同步调整nginx的client_max_body_size及gunicorn等wsgi服务器限制。

Flask层必须设 MAX_CONTENT_LENGTH,且只能在初始化时写
413 错误不是 Flask 主动抛的异常,而是 Werkzeug 在解析请求前就拦截并返回的。它只看 Content-Length 请求头,不读请求体,所以效率高、无内存开销。
这个配置必须在 app = Flask(__name__) 之后、任何 @app.route 之前设置,否则无效。常见错误是把它塞进某个视图函数里,或者用字符串赋值(比如 '16MB'),而它只接受整数(单位:字节)。
-
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024表示 100MB - 不能靠
request.files['f'].stream.read()或.save()后再判断大小——此时文件已接收完毕,起不到限流作用 - 该配置对整个请求体生效,包括所有表单字段 + 多个文件,不是单个文件限制
Nginx 的 client_max_body_size 不同步就会白配
即使 Flask 允许 100MB,Nginx 默认只放行 1MB,请求根本到不了 Flask。错误现象是前端报 413,但 Flask 日志里完全没记录,说明被代理层截了。
必须在 Nginx 配置的 http、server 或 location 块中显式加一句:
client_max_body_size 100M;
改完要重载配置:nginx -s reload,不是 restart。如果用了 Docker,注意配置是否挂载正确;如果用了 Cloudflare,它也有独立的上传大小限制(默认 100MB,但可低至 10MB),得单独查控制台。
Gunicorn 或其他 WSGI 服务器也会卡住大请求
生产环境常用 Gunicorn,它默认 --limit-request-body 是 1MB(即 1048576)。哪怕 Flask 和 Nginx 都调大了,Gunicorn 仍会先拒掉。
启动时需显式传参:
gunicorn --limit-request-body 104857600 app:app
或在配置文件中写 limit_request_body = 104857600。单位是字节,别漏掉。
- Apache 用户则要检查
LimitRequestBody指令 - Uvicorn(ASGI)对应参数是
--limit-concurrency和--limit-max-requests,但大文件主要看--limit-request-body
真传大文件,别全读进内存
调高 MAX_CONTENT_LENGTH 只是让请求进来,不代表安全。用 request.files['f'].read() 或 request.get_data() 会把整个文件加载进内存,1GB 文件直接 OOM。
正确做法是流式处理:
- 优先用
request.files['f'].save('/path/to/file')—— 它内部已做分块写入,不额外占内存 - 若需校验或转存,用
request.stream分块读:chunk = request.stream.read(8192),每次只拿 8KB - 前端支持的话,强烈建议上分片上传(如 tus、uppy),服务端只收片、校验、拼接,彻底避开单次大请求瓶颈
真正难的不是“怎么放开限制”,而是“怎么不让数据进内存”。很多团队只改了 MAX_CONTENT_LENGTH 就以为搞定,结果上线后内存暴涨、服务抖动——那是因为没意识到 Werkzeug 放行之后,你自己的代码才是真正的风险点。











