Python 文件上传实现中的关键问题

1次阅读

flask中request.files为空主因是表单未设enctype=”multipart/form-data”;django需检查中间件、视图参数及content_type;文件过大需调nginx client_max_body_size和框架限制;保存时须用绝对路径、建目录、校验权限与文件名。

Python 文件上传实现中的关键问题

Flask 中 request.files 为空的常见原因

不是前端没发,也不是后端写错了,大概率是表单没设对 enctype。HTML 表单默认用 application/x-www-form-urlencoded,这种编码会把文件内容转成字符串丢掉,request.files 自然为空。

  • 表单必须显式声明:<form enctype="multipart/form-data"></form>
  • 确保 <input type="file">name 属性和后端 request.files.get("xxx") 中的 "xxx" 完全一致(区分大小写)
  • 如果用了 JavaScript 动态构造 FormData,别漏掉 append("file", input.files[0]),光 append 其他字段没用
  • chrome DevTools 的 Network → Payload 标签页里能看到实际发了什么,确认有没有 ------WebKitFormBoundary 开头的分隔符

Django 的 request.FILES 获取不到文件的典型场景

Django 对文件上传更“严格”,request.FILES 为空往往不是编码问题,而是中间件或视图配置没到位。

  • 确保 settings.py 中有 FILE_UPLOAD_HANDLERS 默认值(通常不用改),且没被意外清空
  • 视图函数必须带 request 参数,且不能是类视图中忘了写 def post(self, request): 而误写成 def post(self):
  • 如果是 APIView 或 DRF 视图,得用 request.FILES.get("file"),而不是 request.data.get("file") —— 后者只处理 jsON body,不触碰 multipart 数据
  • 调试时直接打印 request.META.get("CONTENT_TYPE"),如果不是以 multipart/form-data 开头,说明请求根本没走对路

文件过大导致上传失败的拦截点

用户上传 200MB 视频失败,错误却显示 400 或 500,背后可能是多层限制在悄悄起作用,每层都得单独调。

  • Web 服务器层:Nginx 默认 client_max_body_size 1m,需在 httpserverlocation 块里改成比如 100m
  • python 框架层:Flask 默认不限,但 Werkzeug 有 MAX_CONTENT_LENGTH 配置(单位字节),Django 则靠 DATA_UPLOAD_MAX_MEMORY_SIZEFILE_UPLOAD_MAX_MEMORY_SIZE
  • 浏览器本身也有隐式限制(如某些旧版 safari 对超大表单响应慢甚至卡死),建议前端加 inputaccept 和 JS 文件大小校验,提前拦住明显超限的文件

保存上传文件时容易忽略的路径与权限问题

代码能跑通、文件也能读到,但 open("uploads/xxx.jpg", "wb")FileNotFoundErrorPermissionError,十有八九是路径没算对或目录没写权限。

立即学习Python免费学习笔记(深入)”;

  • 别用相对路径硬写 "uploads/",用 os.path.join(os.path.dirname(__file__), "uploads") 或更稳妥的 pathlib.Path(__file__).parent / "uploads"
  • 保存前务必检查并创建目录:os.makedirs(upload_dir, exist_ok=True)
  • linux 服务器上,运行 Web 进程的用户(如 www-data)必须对目标目录有 w 权限;用 ls -ld uploads 看属组和权限位
  • 别直接用用户传来的 filename 作保存名,要清洗:os.path.basename(filename) 防路径穿越,再加随机前缀防重名

文件上传看着简单,但每一层(浏览器、Web 服务器、框架、OS)都有自己的规则和默认值,漏掉任意一个,就可能让文件在半路消失。

text=ZqhQzanResources