在Spa单页面横行的时代,前后端交互基本都是Json交互(也有通过FormData的,比如上传文件)。而在之前的Jsp,Php前后不分家的时候,前后交互好大一部分都是通过Form表单来完成的。From标签个属性叫 enctype
,这属性指定了Form的Content-Type,可取的只有application/x-www-form-urlencoded, multipart/form-data, text/plain。
而Content-Type包含3个部分:
- media-type: 资源或数据的 MIME type (必填)
- charset: 字符编码标准
- boundary: 对于多部分实体,boundary 是必需的,其包括来自一组字符的1到70个字符,已知通过电子邮件网关是非常健壮的,而不是以空白结尾。它用于封装消息的多个部分的边界
application/x-www-form-urlencoded 是Form默认的Content-Type:表单提交时编码必须遵循以下标准:
- key和value都会被编码。空格被替换为‘+’,保留字编码对着参照 [RFC1738],非转义字符被替换为‘’%hh‘’的格式(一个%和两个代表示ASCII码的16进制数字),换行被替换为‘%D0%0A’(对应CR LF),都可以通过encodeURI函数转换,详细还请查阅 mdn
- key和value用‘=’来分隔,每一对key和value用‘&’来分隔
比如:
multipart/form-data 是用FormData来传递数据,和上边的区别是,FormData用来传递大数据(非ascii字符和二进制数据),具体请参考另一篇文章 post使用form-data和x-www-form-urlencoded的本质区别 (这篇博客讲的感觉很详细了),编码规则如下:
- 包含一个Content-Disposition字段,值为form-data
- 一个name属行,值为对应表单key的name字段
- 所有的Mime传输一样,用CR LF(‘%0D%0A’)来分隔数据
比如:划线处为规则3
接下我详细说下multipart/form-data编码,假设我们有以下Form
<FORM action="http://server.com/cgi/handle"enctype="multipart/form-data"method="post"><P>What is your name? <INPUT type="text" name="submit-name"><BR>What files are you sending? <INPUT type="file" name="files"><BR><INPUT type="submit" value="Send"> <INPUT type="reset"> </FORM>
当用户输入‘Larry’在文本input中,还选择了一个文本文件‘file1.txt’,然后点击提交按钮,传向后台的body体为:
Content-Type: multipart/form-data; boundary=AaB03x--AaB03xContent-Disposition: form-data; name="submit-name"Larry--AaB03xContent-Disposition: form-data; name="files"; filename="file1.txt"Content-Type: text/plain... contents of file1.txt ...--AaB03x--
我们看到蓝色部分,就是Content-Type,参考上上边提到的,少了charset,多了个boundary(我们知道,在application/x-www-form-urlencoded 中是用‘&’来告诉服务器每一个key和value,比如一个get请求: http://localhost:8080/api?name=John&age=12 ,
那么在multipart/form-data我们怎么告诉服务器呢,答案就是boundary,有了这个字段,服务器就知道一个value是从哪里开始和到哪里结束,这个字段开发者是不用写的,浏览器会自动加上,网上说我们也可以自行设置,比如你可以设置你喜欢的字符,但是我没有成功,每次都是随机的给分配一个,测试如下:)
回到刚才的Form表单,如果用户选择了第二个文件‘file2.gif’,传输结构会是以下:
Content-Type: multipart/form-data; boundary=AaB03x--AaB03xContent-Disposition: form-data; name="submit-name"Larry--AaB03xContent-Disposition: form-data; name="files"Content-Type: multipart/mixed; boundary=BbC04y--BbC04yContent-Disposition: file; filename="file1.txt"Content-Type: text/plain... contents of file1.txt ...--BbC04yContent-Disposition: file; filename="file2.gif"Content-Type: image/gifContent-Transfer-Encoding: binary...contents of file2.gif...--BbC04y----AaB03x--