form 的 enctype 必须设为 multipart/form-data,否则无法上传二进制文件;需配合 method="POST",且后端须用框架内置机制(如 PHP 的 $_FILES、FastAPI 的 UploadFile)解析,同时同步调整 Nginx、PHP 等服务器上传限制。

form 的 enctype 必须设为 multipart/form-data
浏览器默认用 application/x-www-form-urlencoded 编码表单,这种编码会把文件内容转成 URL 安全字符串(比如空格变 +、中文变 %E4%BD%A0),根本没法传二进制文件。只有显式设成 multipart/form-data,浏览器才会把每个字段拆成独立部分,用随机 boundary 分隔,并原样发送原始字节。
常见错误是只写了 <input type="file"> 却忘了改 enctype,结果后端收不到文件——$_FILES(PHP)或 request.files(Flask/FastAPI)始终为空,但 $_POST 或 request.form 还能收到其他字段,容易误以为“只是文件没传成功”。
-
<form enctype="multipart/form-data" method="POST">是硬性要求,不能省略 - 即使表单里只有 1 个
<input type="file">,其他全是文本框,也必须设 - 不要写成
enctype="multipart/formdata"(漏了短横线)或"Multipart/Form-Data"(大小写敏感,浏览器可能忽略)
后端接收时不能依赖 Content-Type 字符串解析
HTTP 请求头里的 Content-Type 看起来像 multipart/form-data; boundary=----WebKitFormBoundaryabc123,但后端框架通常不靠手动解析这个字符串来提取文件。真正起作用的是整个请求体的结构:每段以 --boundary 开头,包含 Content-Disposition 头说明字段名和文件名,后面紧跟原始数据。
所以别自己写正则去拆 boundary,直接用框架内置处理逻辑:
- PHP:检查
$_FILES['fieldname']['error'] === UPLOAD_ERR_OK,而不是读$_SERVER['CONTENT_TYPE'] - Node.js(Express):必须加
multer中间件,app.use(multer().single('myfile')),原生req.body拿不到文件 - Python(FastAPI):参数声明为
file: UploadFile = File(...),不是从request.headers里找
enctype 和 method="POST" 必须同时满足
GET 请求压根不允许带 body,而 multipart/form-data 的数据全在 body 里,所以 method 只能是 POST(或 PUT,但表单原生只支持 POST 和 GET)。如果写成 <form enctype="multipart/form-data" method="GET">,浏览器会静默降级为 application/x-www-form-urlencoded,且不报错——你看到的只是 URL 里一堆乱码参数,文件彻底消失。
- HTML 表单不支持
PUT或PATCH,想用得靠 JSfetch+FormData - 测试时用浏览器开发者工具的 Network 面板看真实请求头,确认
Content-Type是multipart/form-data,且有boundary - 如果后端返回 400 或空文件,先查前端发出去的请求是否真带了
boundary,而不是只盯后端代码
大文件上传要同步调整服务器配置
enctype 设对只是第一步。Nginx、Apache、PHP、Node.js 都有各自默认的上传限制,比如 PHP 的 upload_max_filesize 和 post_max_size,Nginx 的 client_max_body_size。这些值只要有一个比文件小,上传就会失败——但错误表现五花八门:PHP 可能返回空 $_FILES,Nginx 直接 413,浏览器 Network 面板里请求状态可能是 (failed) net::ERR_CONNECTION_RESET。
- PHP:修改
php.ini里的upload_max_filesize = 20M和post_max_size = 21M(后者需略大于前者) - Nginx:在
server或location块里加client_max_body_size 20M; - Node.js(Express + multer):初始化时指定
limits: { fileSize: 20 * 1024 * 1024 } - 改完配置记得重启服务,光刷新页面没用
实际调测时,最容易被忽略的是 Nginx 和 PHP 配置的协同——比如 PHP 允许传 50M,但 Nginx 卡在 1M,前端连请求体都发不完,后端根本收不到任何东西。


















