前言:我们知道,服务端通常是根据请求头(headers)里面的 Content-Type 字段来判断请求中的消息主体是用何种方式进行编码的,然后再对主体进行解析。所以我们需要先了解一下POST的数据编码格式。
POST数据编码格式
POST的数据编码格式由Content-Type决定,而Content-Type有多种值,每个值都代表不同的数据格式
1、常见的媒体格式类型:
- text/html : HTML格式
- text/plain :纯文本格式
- text/xml : XML格式
- image/gif :gif图片格式
- image/jpeg :jpg图片格式
- image/png:png图片格式
2、以applicaton开头的媒体类型:
- application/json : JSON数据格式
- application/xhtml+xml :XHTML格式
- application/xml : XML数据格式
- application/atom+xml :Atom XML聚合格式
- application/pdf :pdf格式
- application/javascript :js格式
- application/msword : Word文档格式
- application/octet-stream : 二进制流数据(如常见的文件下载)
- application/x-www-form-urlencoded :form表单默认的数据格式类型,form表单数据被编码为key/value格式发送到服务器。
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式。
其中POST提交可能用到的Content-Type类型如下:
- multipart/form-data
- application/x-www-form-urlencoded
- text/xml
- application/javascript
- application/json
- text/html
- text/plain
在此我们会讨论其中常见的三种数据格式及其后台解析操作,为了方便测试,我们采用ApiPost(也可以使用PostMan)接口调试软件发起POST请求,后台则用NodeJS+Express搭配服务器。
后台解析请求主体的数据可能需要安装的模块,body-parser,multiparty;
其中,body-parser可用于express对请求进行分析,根据req.body字段便可以获得请求的主体。由于body-parser与Express分离了,所以需要自己重新安装该模块
安装命令:npm install body-parser
multiparty可用于接收提交的文件和解析form-data编码的数据
安装命令:npm install multiparty
// 引入模块
var express = require('express');
var path = require('path');
var ejs = require('ejs');
var app = express();
//var bodyParser=require('body-parser');
// app.use(bodyParser.json());
// app.use(bodyParser.urlencoded({ extended: false }));
// 数据post接口路由
app.post('/action/:module', function (req, res) {
var c_path = req.params.module;
var Action = require('./action/' + c_path);
Action.execute(req, res);
});
// 设置views路径和模板
app.set('views', __dirname);
app.set('view engine', 'html');
app.engine('html', ejs.__express);
app.use('/', express.static(__dirname));
// 启动一个服务,监听从8080端口进入的所有连接请求
var server = app.listen(8888, function(){
var host = server.address().address;
var port = server.address().port;
console.log('Listening at http://%s:%s', host, port);
});
PS:这里我的测试接口为http://localhost:8888/action/postTry,该接口会将POST请求里面的请求主体返回,这样我们可以看到POST的 数据在不同编码格式中是如何进行编码的
一、application/x-www-form-urlencoded
主要用于如下:
1.1、最常见的POST提交数据方式。
1.2、原生form默认的提交方式(可以使用enctype指定提交数据类型)。
1.3、jquery,zepto等默认post请求提交的方式
application/x-www-form-urlencoded 是最常用的一种请求编码方式,支持GET/POST等方法,所有数据变成键值对的形式 key1=value1&key2=value2
的形式,并且特殊字符需要转义成utf-8编号,如空格会变成 %20;
开始测试:
发送请求
用ApiPost发送请求,选择编码格式为application/x-www-form-urlencoded,我们输入字段name和value作为传送的参数,分别取值为111111和22222,在ApiPost可以查看返回的数据
解析数据
由图片结果,我们可以看到我们发送的请求主体里面的数据为以下结果
name=111111&value=22222
这与我们上述所述一致,现在我们需要在NodeJS里面进行解析,得到数据。以下为服务端解析代码
//导入querystring模块(解析post请求数据)
var querystring = require('querystring');
exports.execute = function (req, res) {
//console.log(req.body)
/*如果使用了body-parser,则可以使用使用req.body获取到请求主体,
但是下方的req.on事件就会失去作用,因为此时数据以及接收完毕,所以没有办法触发处理事件*/
//面对post提交,nodejs用监听的写法处理
//data是一个事件,表示一个小包传输完毕后做的事情
var result = "";
req.on("data", function (chunk) {
//console.log("小包传输完毕");
result += chunk;
});
//end也是一个事件,表示所有的包传输完毕
req.on("end", function () {
//所有的包传输完毕
result = decodeURI(result); // 前端提交中文数据时会进行url编码,所以先进行译码
var resultObject = querystring.parse(result);//对数据进行解析
//var result = JSON.parse(result);
//console.log(resultObject);
console.log(resultObject)//打印解析结果
message['status'] = 200;
message['msg'] = '提交成功';
res.send(result)
});
};
由于x-www-form-urlencoded是类似于url编码的一种编码方式,所以我们可以利用NodeJS内置的querystring模块进行解析,打印的解析结果如下:
[Object: null prototype] { name: '111111', value: '22222' }
这时候我们已经成功将请求主体由字符串解析为对象,可以通过访问对象属性的方式进行数据的访问。
二、multipart/form-data
使用表单上传文件时,必须指定表单的 enctype属性值为 multipart/form-data. 请求体被分割成多部分,每部分使用 --boundary分割;
开始测试:
发送请求
用ApiPost发送请求,选择编码格式为multipart/form-data,我们输入字段name和value作为传送的参数,分别取值为111111和22222,在ApiPost可以查看返回的数据
解析数据
由图片结果,我们可以看到我们发送的请求主体里面的数据为以下结果
------WebKitFormBoundaryeDD6NSO9tLOAABh5
Content-Disposition: form-data; name="name"
111111
------WebKitFormBoundaryeDD6NSO9tLOAABh5
Content-Disposition: form-data; name="value"
22222
------WebKitFormBoundaryeDD6NSO9tLOAABh5--
由于NodeJS无法使用querystring直接将以上请求主体直接解析为对象,另外,上述提到的body-parser也不支持解析form-data编码的数据,此时的req.body={},这时候我们可以使用multiparty模块来进行数据的解析,具体可查看以下代码
var multiparty = require('multiparty');
//生成multiparty对象,并配置文件上传目标路径
var form = new multiparty.Form({ uploadDir: 'images/images' });
form.parse(req, function(err, fields, files) {
var message = {};
if (err) {
message["Code"] = 1;
message["Msg"] = err;
} else {
message['name'] = fields.name[0]; //可根据fields获取其他数据,name以及values
message['value'] = fields.value[0];
}
res.send(message);
});
打印结果如下
{ name: '111111', value: '22222' }
三、application/json
实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。而且现在服务端基本都可以处理JSON数据,所以不会出现什么大问题。
开始测试:
发送请求
用ApiPost发送请求,选择编码格式为application/json,我们输入字段name和value作为传送的参数,分别取值为111111和222222,在ApiPost可以查看返回的数据
解析数据
由图片结果,我们可以看到我们发送的请求主体里面的数据为以下结果
{
"name": "111111",
"value": "222222"
}
此时的数据解析我们可以用JSON.parse对字符串进行解析获得对象
// res.send(req.body)
//面对post提交,nodejs用监听的写法处理
//data是一个事件,表示一个小包传输完毕后做的事情
var result = "";
req.on("data", function (chunk) {
//console.log("小包传输完毕");
result += chunk;
});
//end也是一个事件,表示所有的包传输完毕
req.on("end", function () {
//所有的包传输完毕
result = decodeURI(result); // 前端中文数据提交时会进行url编码,所以先进行译码
var resultObject = JSON.parse(result);
console.log(resultObject)
res.send(result)
});
打印结果如下
{ name: '111111', value: '222222' }
另外,我们常用的axios HTTP工具库发起的axios post方法默认使用application/json格式编码数据,这个也可以说明在post请求中,使用这种编码格式应该是更加方便的。
个人觉得,在不需要进行文件上传的操作的时候,尽量还是选择application/json,因为在后台对数据的解析会变得比较简单,服务器基本都已经可以实现json数据的解析和封装了。