post请求的提交数据的几种方式
前言
HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据,本文主要讨论 POST 提交数据的几种方式。
我们知道,HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。
协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求满足上面的格式就可以。
但是,数据发送出去,还要服务端解析成功才有意义。一般服务端语言如 php、python 等,以及它们的 framework,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。下面就正式开始介绍它们。
个人理解:get请求其实就是将参数以key=value&key=value的形式拼在url发往服务器,所以get请求没有那么多复杂的说法;而post请求规定提交的数据必须放在消息主体(entity-body)中,但没有对形式的规定,所以就有了各种各样的方式;
引出问题
1 | var ajax = new XMLHttpRequest(); |
需要注意的是,ajax.send()的内容可以是data1的格式(JSON.stringfy()得来),也可以是data2的格式(qs.stringfy()得来),两种的方式都可以;
另外ajax.send()不能直接发送对象,后端接受会变成[object Object],而对于axios库,直接发送对象,它会自动转成json字符串;
在后端为django的代码中测试
1 | def test(request): |
如何是data1的格式就是json字符串的话,request.POST是无法获取到东西的,data2格式通过request.POST是可以获取到的,但前提是请求的Content-type必须设置为application/x-www-form-urlencoded,否则都获取不到结果,只能从request.body中获得原始数据;
之所以这样是因为django框架在处理响应时,只对Content-type为application/x-www-form-urlencoded的情况做了处理,(具体可以查看django的源码中class HttpRequest(object)对post的处理部分)
django之所以这么做,是因为什么呢?下面先说一下关于post的几种请求方式
application/x-www-form-urlencoded
这是post的默认请求方式,在post请求不设置Content-type时的默认值;
1 | <form action="http://localhost:8000/api/test/" method="post"> |
这也是原始提交表单的方式,在表单提交的方式里,浏览器会把表单里的数据,以key=value&key=value的形式发送给服务器;个人理解,由于这种最初的提交方式,决定了application/x-www-form-urlencoded下对数据的处理;
所以,在ajax请求的年代,其实传哪种(data1和data2)格式都可以,不同的是,服务器是以Content-type的类型来决定如何处理数据的;
这种post的类型的时候可以向服务器发送数据,而数据的格式应为键值对
key=value&key=value,js对象可以通过qs.stringfy()来序列化得到;不过,qs在序列化数组的时候默认会序列化为arr[]=value&arr[]=value的形式;这时需要配置下qs,指定数组的编码格式;否则后端获取不到该数组;
django接收数组的时候用
request.POST.getlist();如果前端序列化带了[],后端也需要带,或者要前端序列化的时候去掉[];
指定数组的编码格式和对应的结果
1 | let params = [1, 2, 3]; |
application/json
这种方式就是告诉服务器,传输的数据为json字符串,所以对应的数格式应为json字符串,js对象可以通过JSON.stringfy()来序列化得到;这是一种略新的格式,可能早期的ie等浏览器不支持
如果发送对象比较复杂比如
[{"id":"001","name":"小明"},{"id":"002","name":"小军"}];这时候还是简单的用json字符串为好,表单提交的方式可能会造成后端解析困难的情况,另外也很难看懂结果;
multipart/form-data
这种类型主要用来上传文件(可上传多个),也可以发送键值对;(该内容后续展开)
text/plain (text/json/xml/html)
数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符。postman软件里标的是RAW,application/json包含在RAW里;
binary
暂没用过,只在postman中看到过,相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。