2018-12-22
基础知识
Http请求消息体的格式为:request-line(请求行)、header(头部)、blank-line(空格行)和body(消息体)。Request-line声明了请求地址、方法和版本号,header部分声明请求的附加信息,Blank-line(空格行)用于分隔header和body,body部分是请求的消息体,可以为空。如下图所示:
Body不是必须的,也没有格式要求。通常Get类型的请求,body部分可以为空,参数在header中以key-value格式传输即可;Post类型的请求,通过body传输数据。由于body可以传输任意格式的数据格式,为了让接收方知道怎么解析数据,发送方需要在header中,使用Content-Type字段声明body部分的数据格式。
常见的Content-Type
以下介绍如无特殊说明,发送端默认是浏览器,接受端默认是使用Express搭建的Http服务。其他终端使用http时,推荐参照浏览器的标准。
application/x-www-form-urlencoded
HTML默认的表单提交方式,发送urlencoded格式的纯文本数据。发送如下:
<form name="form" action="test-form" method="post"> <input type="text" name="key1" value="value1"> <input type="text" name="key2" value="value2"> <input type="submit" value="Submit"> </form>
点击提交按钮,表单发起的http请求header里自动带着“Content-Type: application/x-www-form-urlencoded”,Body中的数据以“key1=value1&key2=value2”的文本格式传输。
如果使用Axios发送json数据,需要把json先格式化成“key1=value1&key2=value2”的形式。推荐使用一个叫QS的库,使用方式如下:
import axios from 'axios' import qs from 'qs' let options = { headers: { 'Content-Type': 'application/x-www-form-urlencoded', } } let Request = axios.post(reqUrl, qs.stringify(params), options).then((response)=>{ return response.data })
服务端收到请求之后,通常需要把body的内容转换成json使用。有些框架自带了处理,但Express需要引入中间件来处理。推荐使用body-parser,使用方法如下:
let express = require('express'); let app = express(); let bodyParser = require('body-parser'); module.exports = app; app.use(bodyParser.urlencoded()); app.post('/test-form', function (req, res) { console.log(req.body); res.send(req.body); });
multipart/form-data
Http协议最开始是不支持文件上传的。直到1995年发布的规范《RFC 1867-Form-based File Upload in HTML》,新增了一个Content-Type类型用于发送文件,这就是我们今天熟知的multipart/form-data。multipart是“多部分”的意思,意味着body中的数据允许有多部分组成,可以同时传递文本数据和二进制数据。
使用HTML表单提交时,只需要在form标签内加上enctype="multipart/form-data",如下:
<form name="form" action="test-data" method="post" enctype="multipart/form-data"> <input type="file" id="file"/> <input type="submit" value="Submit"> </form>
点击提交按钮,表单发起的http请求header里带着“Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryG4tAWTT3yikZt0WN”。前面的说明了使用multipart/form-data格式传递数据,而boundary后跟的一串字符表示的是分隔符。分隔符发起请求是会重新生成,所以每次请求都是不一样的。查看Body中的数据如下:
------WebKitFormBoundaryG4tAWTT3yikZt0WN Content-Disposition: form-data; name="key1" value1 ------WebKitFormBoundaryG4tAWTT3yikZt0WN Content-Disposition: form-data; name="key2"; filename="test.zip" Content-Type: application/octet-stream [文件二进制数据] ------WebKitFormBoundaryG4tAWTT3yikZt0WN--
可以看到请求的内容使用boundary分隔符进行区分,文本内容和文件可以同时发送。对于每个key,在分隔符后都会标明数据类型和格式等,然后使用空行隔开,再附带value值。
使用Axios发送文件时,只需要在headers里加上“'Content-Type': 'multipart/form-data'”即可,不需要对数据进行格式化。
Express接收文件依然需要引入中间件来处理。推荐使用multer,使用方法如下:
let express = require('express'); let app = express(); let multer = require('multer'); module.exports = app; let upload = multer({ dest: 'upload/' }); app.post('/test-data', upload.single('key2'), function (req, res, next) { let file = req.file; console.log(file); console.log(req.body); res.json({ key1: req.body.key1, key2: file.filename }); });
上传的文件会储存在dest声明的路径里。req.file可以获取到上传的文件信息,req.body可以同时获取到其他文本格式传输的数据。
application/json
接口最常用的格式,body的内容就直接是json格式的文本。发送时仅需要在headers里加上“'Content-Type': 'application/json'”即可,如下:
import axios from 'axios' let options = { headers: { 'Content-Type': 'application/json', } } let Request = axios.post(reqUrl, params, options).then((response)=>{ return response.data })
接收时也可以用body-parser,使用方法如下:
let express = require('express'); let app = express(); let bodyParser = require('body-parser'); module.exports = app; app.use(bodyParser.json()); app.post('/test-json', function (req, res) { console.log(req.body); res.send(req.body); });
text/plain
纯文本格式,body的内容就只是文本。发送仅需在headers里加上“'Content-Type': 'text/plain'”即可。接收时也可以用body-parser,使用方法如下:
let express = require('express'); let app = express(); let bodyParser = require('body-parser'); module.exports = app; app.use(bodyParser.text()); app.post('/test-text', function (req, res) { console.log(req.body); res.send(req.body); });
类似的有text/html,内容是html格式,传输网页时会用到。还有text/xml,内容是XML,XML-RPC之类的规范会用到。
总结
本文介绍了Http请求时候的几种常用的Content-Type。
Http响应也会带Content-Type,原理和请求的一致,目的是让接收方知道怎么解析数据。响应的Content-Type又被称为Mime-type(Multipurpose Internet Mail Extensions,媒体类型),由于接收方终端的差异(浏览器差异),场景比请求的复杂一点点,后面有机会再另外写一篇博客吧。
参考文献
本文未经许可禁止转载,如需转载请联系 JAY@oonne.com