What does enctype='multipart/form-data' mean?
What does enctype=’multipart/form-data’ mean?
技术背景
在进行 POST 请求时,需要对请求体中的数据进行编码。HTML 表单提供了三种编码方法:application/x-www-form-urlencoded(默认值)、multipart/form-data 和 text/plain。此外,曾有计划添加 application/json 编码方式,但该计划已被放弃。
实现步骤
选择合适的编码类型
- 客户端代码编写:
- 当表单包含
<input type="file">元素时,使用multipart/form-data。 - 若表单不包含文件上传元素,可使用
multipart/form-data或application/x-www-form-urlencoded,但application/x-www-form-urlencoded效率更高。
- 当表单包含
- 服务器端代码编写:使用预写的表单处理库,如 Perl 的
CGI->param或 PHP 的$_POST超全局变量,这些库会处理不同编码格式的差异,无需手动解析服务器接收到的原始输入。
生成示例
可以使用 nc -l 或 ECHO 服务器,以及浏览器或 cURL 等用户代理来生成示例。以下是具体步骤:
- 将表单保存到一个最小的
.html文件中:
1 | |
- 创建要上传的文件:
1 | |
- 运行 ECHO 服务器:
1 | |
- 在浏览器中打开 HTML 文件,选择文件并点击提交,然后检查终端输出。
核心代码
multipart/form-data 示例
Firefox 发送的请求示例:
1 | |
application/x-www-form-urlencoded 示例
将 enctype 改为 application/x-www-form-urlencoded 后,Firefox 发送的请求示例:
1 | |
最佳实践
- 避免使用
text/plain编码,因为它不易被计算机可靠解析,仅适用于调试。 - 当表单包含文件上传时,使用
multipart/form-data编码。 - 对于不包含文件上传的表单,优先使用
application/x-www-form-urlencoded编码,因为它效率更高。 - 在服务器端,使用预写的表单处理库来处理表单数据,避免手动解析原始输入。
常见问题
为什么 multipart/form-data 中的边界字符串比 Content-Type 中指定的边界多两个连字符?
这是因为标准要求边界字符串以两个连字符 -- 开头。其他连字符是浏览器实现任意边界的方式。
application/x-www-form-urlencoded 为什么不适合用于文件上传?
application/x-www-form-urlencoded 会对非打印字符进行编码,每个非打印字符会增加 3 倍的开销。文件上传通常包含大量非打印字符,使用该编码方式会导致效率低下。此外,application/x-www-form-urlencoded 只会发送文件名,而不会发送文件内容。
如何确定上传文件的 Content-Type?
浏览器会自动确定上传文件的 Content-Type,具体确定方式可参考:https://stackoverflow.com/questions/1201945/how-is-mime-type-of-an-uploaded-file-determined-by-browser。
表单提交时的安全问题有哪些?
根据 RFC 7578 Section 7,表单处理软件应谨慎处理用户提供的表单数据,因为其中可能包含机密或个人识别信息。multipart/form-data 本身不提供完整性检查、保密性保证、避免用户混淆等安全功能,这些问题需要由表单填充和表单数据解释应用程序来解决。接收和处理表单的应用程序必须小心,不要将未打算发送的数据返回给请求的表单处理站点。在解释 Content-Disposition 头字段中的文件名时,要注意不要意外覆盖接收方文件空间中的文件。