在HTTP请求中,POST
、PUT
和PATCH
三种请求方法中包含请求体,Node.js 原生HTTP模块中,请求体要基于流的方式接收和解析。body-parser
是一个HTTP请求体解析中间件,使用这个模块可以解析JSON、Raw、文本、URL-encoded格式的请求体,Express
框架中就是使用这个模块做为请求体解析中间件。
1. 请求体解析
1.1 原生环境中的解析
Node.js 原生HTTP模块中,是将用户请求数据封装到了用于请求对象req
中,该对象是一个IncomingMessage
,该对象同时也是一个可读流对象。在原生HTTP服务器,或不依赖第三方解析模块时,可以像下面这样接收并解析请求体:
const http = require(‘http‘); //用http模块创建一个http服务端 http.createServer(function(req, res) { if (req.method.toLowerCase() === ‘post‘) { var body = ‘‘; req.on(‘data‘, function(chunk){ body += chunk; }); req.on(‘end‘, function(){ if(req.headers[‘content-type‘].indexOf(‘application/json‘)!==-1){ // JSON 格式请求体解析 JSON.parse(body); } else if(req.headers[‘content-type‘].indexOf(‘application/octet-stream‘)!==-1){ // Raw 格式请求体解析 // …… } else if(req.headers[‘content-type‘].indexOf(‘text/plain‘)!==-1){ // text 文本格式请求体解析 // …… } else if(req.headers[‘content-type‘].indexOf(‘application/x-www-form-urlencoded‘)!==-1){ // URL-encoded 格式请求体解析 // …… } else { // 其它格式解析 } }) } else { res.end(‘其它提交方式‘); } }).listen(3000);
1.2 使用body-parser
解析请求体
body-parser
模块是一个Express/Connect
中间件,它使用非常简单且功能强大,可以像下面这样用这个模块解析请求体:
Express/Connect 项层处理
Express
框架默认使用body-parser
做为请求体解析中间件,创建Express项目后,可以在app.js
文件中看到如下代码:
/* 引入依赖项 */ var express = require(‘express‘); // …… var bodyParser = require(‘body-parser‘); var routes = require(‘./routes/index‘); var users = require(‘./routes/users‘); var app = express(); // …… // 解析 application/json app.use(bodyParser.json()); // 解析 application/x-www-form-urlencoded app.use(bodyParser.urlencoded());
这样就在项目的Application级别,引入了body-parser
模块处理请求体。在上述代码中,模块会处理application/x-www-form-urlencoded
、application/json
两种内容格式的请求体。经过这个中间件处理后,就可以在所有路由处理器的req.body
中访问请求参数。
解析Express具体路由
在实际应用中,不同路径(路由)可能会要求用户使用不同的内容类型,body-parser
还支持为单个Express路由添加请求体解析:
var express = require(‘express‘) var bodyParser = require(‘body-parser‘) var app = express() // 创建 application/json 解析 var jsonParser = bodyParser.json() // 创建 application/x-www-form-urlencoded 解析 var urlencodedParser = bodyParser.urlencoded({ extended: false }) // POST /login 获取 URL编码的请求体 app.post(‘/login‘, urlencodedParser, function (req, res) { if (!req.body) return res.sendStatus(400) res.send(‘welcome, ‘ + req.body.username) }) // POST /api/users 获取 JSON 编码的请求体 app.post(‘/api/users‘, jsonParser, function (req, res) { if (!req.body) return res.sendStatus(400) // create user in req.body })
指定请求类型
body-parser
还支持为某一种或一类内容类型的请求体指定解析方式,指定时可以通过在解析方法中添加type
参数修改指定Content-Type
的解析方式。
如,可以对text/plain
内容类型使用JSON
解析:
app.use(bodyParser.json({ type: ‘text/plain‘ }))
这一选项更多是用在非标准请求头的解析中,如下:
// 解析自定义的 JSON app.use(bodyParser.json({ type: ‘application/*+json‘ })) // 解析自定义的 Buffer app.use(bodyParser.raw({ type: ‘application/vnd.custom-type‘ })) // 将 HTML 请求体做为字符串处理 app.use(bodyParser.text({ type: ‘text/html‘ }))
2. body-parser
模块的API
通过npm install body-parser
命令安装模块后,可以通过以下方式获取模块引用:
var bodyParser = require(‘body-parser‘)
bodyParser
变量是对中间件的引用。请求体解析后,解析值都会被放到req.body
属性,内容为空时是一个{}
空对象。
2.1 bodyParser.json()
- 解析JSON格式
bodyParser.json(options)
返回一个仅解析json
格式数据的中间件。这个方法支持任意Unicode编码的请求体,且支持gzip
和deflate
编码的数据压缩。
Option是一个包含以下可选值的对象
inflate
- 设置为true
时,deflate
压缩数据会被解压缩;设置为true
时,deflate
压缩数据会被拒绝。默认为true
。limit
- 设置请求的最大数据量。默认为‘100kb‘
reviver
- 传递给JSON.parse()
方法的第二个参数,详见JSON.parse()strict
- 设置为true
时,仅会解析Array
和Object
两种格式;设置为false
会解析所有JSON.parse
支持的格式。默认为true
type
- 该选项用于设置为指定MIME类型的数据使用当前解析中间件。这个选项可以是一个函数或是字符串,当是字符串是会使用type-is来查找MIMI类型;当为函数是,中间件会通过fn(req)
来获取实际值。默认为application/json
。verify
- 这个选项仅在verify(req, res, buf, encoding)
时受支持
2.2 bodyParser.raw()
- 解析二进制格式
bodyParser.raw(options)
返回一个将所有数据做为Buffer
格式处理的中间件。这个方法支持gzip
和deflate
编码的数据压缩。解析后,其后的所有的req.body
中将会是一个Buffer
数据。
Option是一个包含以下可选值的对象
inflate
- 设置为true
时,deflate
压缩数据会被解压缩;设置为true
时,deflate
压缩数据会被拒绝。默认为true
。limit
- 设置请求的最大数据量。默认为‘100kb‘
type
- 该选项用于设置为指定MIME类型的数据使用当前解析中间件。这个选项可以是一个函数或是字符串,当是字符串是会使用type-is来查找MIMI类型;当为函数是,中间件会通过fn(req)
来获取实际值。默认为application/octet-stream
。verify
- 这个选项仅在verify(req, res, buf, encoding)
时受支持
2.3 bodyParser.text()
- 解析文本格式
bodyParser.text(options)
返回一个仅处理字符串格式处理的中间件。这个方法支持gzip
和deflate
编码的数据压缩。解析后,其后的所有的req.body
中将会是一个字符串值。
Option是一个包含以下可选值的对象
defaultCharset
- 如果Content-Type
后没有指定编码时,使用此编码。默认为‘utf-8‘
inflate
- 设置为true
时,deflate
压缩数据会被解压缩;设置为true
时,deflate
压缩数据会被拒绝。默认为true
。limit
- 设置请求的最大数据量。默认为‘100kb‘
type
- 该选项用于设置为指定MIME类型的数据使用当前解析中间件。这个选项可以是一个函数或是字符串,当是字符串是会使用type-is来查找MIMI类型;当为函数是,中间件会通过fn(req)
来获取实际值。默认为application/octet-stream
。verify
- 这个选项仅在verify(req, res, buf, encoding)
时受支持
2.4 bodyParser.urlencoded()
- 解析文本格式
bodyParser.urlencoded(options)
返回一个处理urlencoded
数据的中间件。这个方法默认使用UTF-8编码,且支持gzip
和deflate
编码的数据压缩。解析后,其后的所有的req.body
中将会是一个键值对对象。
Option是一个包含以下可选值的对象
extended
- 当设置为false
时,会使用querystring库解析URL编码的数据;当设置为true
时,会使用qs
库解析URL编码的数据。后没有指定编码时,使用此编码。默认为true
inflate
- 设置为true
时,deflate
压缩数据会被解压缩;设置为true
时,deflate
压缩数据会被拒绝。默认为true
。limit
- 设置请求的最大数据量。默认为‘100kb‘
parameterLimit
- 用于设置URL编码值的最大数据。默认为1000
type
- 该选项用于设置为指定MIME类型的数据使用当前解析中间件。这个选项可以是一个函数或是字符串,当是字符串是会使用type-is来查找MIMI类型;当为函数是,中间件会通过fn(req)
来获取实际值。默认为application/octet-stream
。verify
- 这个选项仅在verify(req, res, buf, encoding)
时受支持