HTML 表单 enctype 怎么选?urlencoded 和 multipart 区别
结论:表单里有 <input type="file"> 就必须用 enctype="multipart/form-data";纯文本字段直接用默认的 application/x-www-form-urlencoded 即可;text/plain 只在调试时用,生产环境不要碰。另外记住一点:enctype 只在 method="post" 时生效。
enctype 是什么?什么时候才生效?
enctype(encoding type)是 <form> 标签的属性,用来指定浏览器把表单数据打包成请求体时使用的编码格式。它只有三个合法值:application/x-www-form-urlencoded(默认值)、multipart/form-data、text/plain。
关键点是:当 method="get" 时,表单数据会拼进 URL 的查询串,根本没有请求体,enctype 完全不起作用。HTML 规范明确要求 method="get" 时 enctype 必须是 application/x-www-form-urlencoded,你写 multipart/form-data 浏览器也会忽略。
所以第一个决策条件是:先看你的表单是不是 POST。
urlencoded 和 multipart/form-data 有什么区别?
结论:两者的本质差别是"文本编码"和"二进制封装"——urlencoded 把每个字节做百分号转义后拼成一行字符串,multipart 把每个字段切成独立区块原样传输。
application/x-www-form-urlencoded 的格式是 name=value&name2=value2。所有非 ASCII 字符先按 UTF-8 编码,再逐字节转成 %XX,空格转成 +,&、=、+ 要转义成 %26、%3D、%2B。代价是:一个非 ASCII 字节要占 3 个字符,二进制数据的体积平均膨胀 2~3 倍,1MB 的图片会撑成 2MB 以上的请求体。
multipart/form-data 的格式是用一个随机 boundary(边界字符串)把各字段隔开,每个部分带自己的 Content-Disposition: form-data; name="xxx",文件字段还带 filename 和 Content-Type。二进制数据不做任何编码,体积等于原始大小,每部分只多几十到一百多字节的头部开销。
用 urlencoded 提交文件会怎样?
结论:文件内容根本不会上传,服务器只能拿到一个文件名字符串。
<input type="file"> 在 urlencoded 模式下,提交的是它的 value,也就是用户选中的文件名(如 photo.jpg),字节内容被丢弃。后端既拿不到流,也写不出文件。所以在 PHP 里,$_FILES 只有在 multipart/form-data 时才非空;urlencoded 提交时 $_FILES 是空数组,文件名混在 $_POST 里。
fetch / axios 传 FormData 还需要手动设 enctype 吗?
结论:不需要,也千万不要手动设 Content-Type。
用 FormData 时,浏览器或运行时会自动生成 boundary 并设置完整的 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXX。如果你手写 headers: {'Content-Type': 'multipart/form-data'},boundary 就丢了,后端解析会直接失败。axios 传 FormData 同理,不要配 header,让它自己判断。
text/plain 为什么不能用?
结论:它只是给人看的调试格式,后端框架不解析它。
text/plain 的格式是每行一个 name=value,不做任何转义。如果值里出现换行符,结构当场崩掉。PHP 不会把它的内容放进 $_POST,Java、Node 的主流 body parser 也默认不处理。唯一用途是打开浏览器 DevTools 看一眼原始结构。
实际项目里怎么选?
按这个顺序判断即可:
- 表单含
<input type="file">→enctype="multipart/form-data"; - 全是文本字段 → 什么都不写,用默认的
urlencoded; - 用
GET提交 → 不用管enctype; - 永不使用
text/plain。
最后别忘了服务端体积限制:Nginx 的 client_max_body_size 默认是 1m,PHP 的 post_max_size 默认 8M、upload_max_filesize 默认 2M。超过这些值会返回 413 或让 $_POST/$_FILES 变空,这跟 enctype 选错的表现很像,排查时一起看。用 curl 测试时记住:-d 发的是 urlencoded,-F 发的才是 multipart。
原文链接:https://www.gj0.com/thread-1019.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。