HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。
其中 POST 一般用来向服务端提交数据,具体到项目中,前后端交互时必须首先约定编码方式,本文主要讨论 POST 提交数据的几种编码方式。
HTTP协议规定 POST 提交的数据必须放在消息主体(body)中,但协议并没有规定数据必须使用什么编码方式。
服务端通常是根据请求头headers
中的 Content-Type
字段来获知请求中的消息主体是用何种方式编码,再对body
进行解析。
所以用post方法提交数据,必须指定Content-Type头,如果不指定,浏览器会添加默认的Content-Type头。
目前常见的 POST 提交数据方式见下
html中的form标签可以实现表单提交数据,form的enctype
属性用于设置编码方式,默认值为application/x-www-form-urlencoded,发送请求时Content-Type头为application/x-www-form-urlencoded
<form action="/api/login" method="post" enctype="application/x-www-form-urlencoded">
<p>用户名: <input type="text" name="username" value="admin">p>
<p>密码: <input type="test" name="password" value="123456">p>
<input type="submit" value="登录" >
form>
编码方式为 application/x-www-form-urlencoded时,数据在发送到服务器之前,会将表单内的数据转换为键值对(所有的字段都被作为字符串处理),字段形式为fieldname=value,用&分隔每个字段。比如,username=admin&password=123456,并将所有字符都会进行URL 转码。
在线URL编码解码:http://tool.chinaz.com/tools/urlencode.aspx
enctype
属性值值 | 描述 |
---|---|
application/x-www-form-urlencoded | 在发送前编码所有字符(默认) |
multipart/form-data | 不对字符编码,在使用包含文件上传控件的表单时,必须使用该值。 |
text/plain | 空格转换为 “+” 加号,但不对特殊字符编码。 |
var xhr=new XMLHttpRequest();
xhr.open("POST","https://www.fastmock.site/mock/d6b39fde63cbe98a4f2fb92ff5b25a6d/api/add",true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
编码方式为 multipart/form-data时需要首先在HTTP请求头设置一个分隔符,即:boundary的属性值,然后,将每个字段用分隔符分隔,最后一个分隔符表示结束。
数据将被编码为一条消息,由于存在分隔符,既可以上传键值对,也可以上传文件,通常用于上传二进制的文件。
如果使用表单上传文件,需要将表单的enctype设置为multipart/form-data
<form action="/api/upload" method="post" enctype="multipart/form-data">
<input type="file" name="thumbnail">
<input type="test" name="caption">
<input type="submit" value="提交" >
form>
可以在js中创建一个FormData对象提交数据,使用 FormData对象,浏览器会自动识别并添加请求头 Content-Type: multipart/form-data
下面是一个带预览功能的上传图片的例子:
<div>
<img src="" id="img">
<input type="file" id="thumbnail">
<button id="btn">上传button>
div>
<script>
window.onload=function () {
var btn=document.getElementById("btn");
var file = document.getElementById('thumbnail');
var img = document.getElementById('img');
//图片预览
file.addEventListener('change',function (event) {
var uploadFile = event.target.files[0]
if (uploadFile) {
var reader = new FileReader();// 创建流对象
reader.readAsDataURL(uploadFile)
}
reader.onload = function(e) {
img.src = e.target.result
}
})
//图片上传
btn.addEventListener('click',function () {
var formData = new FormData();
formData.append("caption", "缩略图");
formData.append('thumbnail', file.files[0]);
var xhr= new XMLHttpRequest();
xhr.open("POST", "http://localhost:5000/api/upload");
xhr.send(formData);
})
}
script>
目前常用的Content-Type类型,用来告诉服务端消息主体是序列化后的 JSON 字符串
。一些前端框架中post请求默认采用这种编码方式。前端无法将表单的enctype属性指定为application/json,通常使用ajax的方式发送这种编码形式的请求。
var xhr= new XMLHttpRequest();
xhr.open("POST","/api/",true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({"login_name": "test", "login_password": "123456"}));
var xhr1 = new XMLHttpRequest();
xhr1.open("POST", "http://localhost:5000/api/users/login", true);
xhr1.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr1.send("login_name=test&login_password=123456");
var xhr2 = new XMLHttpRequest();
var formData = new FormData();
formData.append("login_name", "test");
formData.append("login_password", "123456");
xhr2.open("POST", "http://localhost:5000/api/users/login", true);
xhr2.send(formData);
var xhr3 = new XMLHttpRequest();
xhr3.open("POST", "http://localhost:5000/api/users/login", true);
xhr3.setRequestHeader("Content-Type", "application/json");
xhr3.send(JSON.stringify({"login_name": "test", "login_password": "123456"}));