一、express.urlencoded 核心作用
express.urlencoded 是 Express 框架内置的请求体解析中间件 ,专门用于解析 HTTP 请求中 Content-Type 为 application/x-www-form-urlencoded 格式的请求体数据。
补充说明
application/x-www-form-urlencoded格式是 HTTP 表单提交的默认格式(<form>标签不指定enctype属性时默认使用该格式)。- 该格式的数据会将表单内容编码为键值对字符串(例如:
username=zhangsan&age=20&hobby=game),通过请求体传递给服务器。 - 解析后的请求体数据会被挂载到
req.body属性上,供后续路由处理器直接使用(如果不使用该中间件,req.body会是undefined)。
二、底层实现原理
express.urlencoded 并非 Express 从零实现,而是基于第三方中间件 body-parser 封装而来(Express 4.16.0 及以上版本将 body-parser 的核心功能内置,无需手动安装 body-parser 即可使用)。
其解析流程大致如下:
- 中间件接收 HTTP 请求的数据流(请求体数据是分段传输的)。
- 拼接所有分段数据,得到完整的
key=value&key=value格式字符串。 - 对字符串进行 URL 解码(处理特殊字符,例如
%20解码为空格、%40解码为@)。 - 将解码后的字符串分割为键值对,最终转换为 JavaScript 对象(例如
{ username: 'zhangsan', age: '20' })。 - 将转换后的对象挂载到
req.body上,继续执行后续中间件/路由。
三、基本使用
1. 前置条件
-
Express 版本 ≥ 4.16.0(内置该中间件,无需额外安装依赖)。
-
若使用低于 4.16.0 的 Express 版本,需手动安装
body-parser:bashnpm install body-parser --save并通过
body-parser.urlencoded使用(用法与内置express.urlencoded一致)。
2. 基础用法(全局注册)
全局注册后,所有路由都能解析 application/x-www-form-urlencoded 格式的请求体:
javascript
// 引入 Express
const express = require('express');
const app = express();
// 全局注册 express.urlencoded 中间件
app.use(express.urlencoded());
// 路由处理器:使用 req.body 获取解析后的请求体数据
app.post('/user', (req, res) => {
console.log('解析后的请求体:', req.body);
console.log('用户名:', req.body.username);
console.log('年龄:', req.body.age);
res.send(`接收成功!用户名:${req.body.username},年龄:${req.body.age}`);
});
// 启动服务
const port = 3000;
app.listen(port, () => {
console.log(`服务已启动,访问 http://localhost:${port}`);
});
3. 局部注册
仅对指定路由生效,适合仅部分接口需要解析该格式请求体的场景:
javascript
const express = require('express');
const app = express();
// 仅 /user 路由生效
app.post('/user', express.urlencoded(), (req, res) => {
res.send(`接收成功!${JSON.stringify(req.body)}`);
});
// /product 路由不解析 application/x-www-form-urlencoded 格式(req.body 为 undefined)
app.post('/product', (req, res) => {
console.log('req.body:', req.body); // undefined
res.send('未解析请求体');
});
app.listen(3000, () => {
console.log('服务启动于 3000 端口');
});
四、核心配置项详解
express.urlencoded 支持传入一个配置对象 express.urlencoded([options]),核心配置项如下:
1. extended(最核心配置)
- 类型:
Boolean,可选值true/false,默认值(Express 新版已默认true,旧版默认false)。 - 作用:指定解析请求体时使用的库,决定解析后的对象格式。
(1)extended: false
- 底层使用
querystring库(Node.js 内置库,无需额外安装)。 - 限制:仅能解析单层键值对 ,无法解析嵌套对象(例如
user[name]=zhangsan&user[age]=20会被解析为{ 'user[name]': 'zhangsan', 'user[age]': '20' },而非嵌套对象)。 - 适用场景:请求体数据为简单单层结构,无需嵌套对象。
示例:
javascript
app.use(express.urlencoded({ extended: false }));
// 前端提交:user[name]=zhangsan&user[age]=20&hobby=game
// 解析后 req.body:{ 'user[name]': 'zhangsan', 'user[age]': '20', hobby: 'game' }
(2)extended: true
- 底层使用
qs库(第三方库,Express 内置依赖,无需手动安装)。 - 优势:支持解析嵌套对象、数组、复杂数据结构,功能更强大。
- 适用场景:请求体数据包含嵌套结构(如表单提交多层数据)或数组。
示例:
javascript
app.use(express.urlencoded({ extended: true }));
// 前端提交1:嵌套对象 → user[name]=zhangsan&user[age]=20
// 解析后 req.body:{ user: { name: 'zhangsan', age: '20' } }
// 前端提交2:数组 → hobby[0]=game&hobby[1]=music
// 解析后 req.body:{ hobby: ['game', 'music'] }
// 前端提交3:复杂嵌套 → info[address][city]=beijing&info[address][area]=chaoyang
// 解析后 req.body:{ info: { address: { city: 'beijing', area: 'chaoyang' } } }
2. limit
- 类型:
String/Number。 - 作用:限制请求体的大小,防止过大的请求体导致服务器压力过大。
- 默认值:
'100kb'(100 千字节)。 - 取值说明:
- 数字类型:表示字节数(例如
limit: 102400等价于 100kb)。 - 字符串类型:支持
kb(千字节)、mb(兆字节)、gb(吉字节)等单位(例如limit: '2mb')。
- 数字类型:表示字节数(例如
- 超出限制时:服务器会返回
413 Request Entity Too Large错误。
示例:
javascript
// 限制请求体最大为 2 兆字节
app.use(express.urlencoded({ extended: true, limit: '2mb' }));
3. parameterLimit
- 类型:
Number。 - 作用:限制请求体中键值对的最大数量。
- 默认值:
1000。 - 超出限制时:服务器会返回
413 Request Entity Too Large错误。 - 适用场景:防止恶意提交大量键值对占用服务器资源。
示例:
javascript
// 限制键值对最大数量为 2000
app.use(express.urlencoded({ extended: true, parameterLimit: 2000 }));
4. type
- 类型:
String/Array/Function。 - 作用:指定该中间件需要解析的
Content-Type类型,默认值为'application/x-www-form-urlencoded'。 - 扩展用法:支持解析自定义的
Content-Type,或多个Content-Type。
示例:
javascript
// 1. 解析自定义 Content-Type:application/x-www-form-urlencoded; charset=utf-8
app.use(express.urlencoded({
extended: true,
type: 'application/x-www-form-urlencoded; charset=utf-8'
}));
// 2. 解析多个 Content-Type
app.use(express.urlencoded({
extended: true,
type: ['application/x-www-form-urlencoded', 'application/custom-form']
}));
5. verify
- 类型:
Function,格式为verify(req, res, buf, encoding) => void。 - 作用:自定义验证逻辑,在解析请求体之前对原始请求体数据(
buf为 Buffer 类型,encoding为编码格式)进行验证。 - 若验证失败:抛出错误即可,中间件会终止解析并将错误传递给 Express 的错误处理中间件。
示例:
javascript
// 验证请求体是否包含指定关键字
app.use(express.urlencoded({
extended: true,
verify: (req, res, buf, encoding) => {
const bodyStr = buf.toString(encoding);
// 若请求体不包含 username 关键字,抛出错误
if (!bodyStr.includes('username')) {
throw new Error('请求体必须包含 username 字段');
}
}
}));
// 错误处理中间件
app.use((err, req, res, next) => {
res.status(400).send(`请求错误:${err.message}`);
});
五、常见使用场景
-
普通表单提交 :前端
<form>标签默认提交格式为application/x-www-form-urlencoded,后端需用express.urlencoded解析。html<!-- 前端表单 --> <form action="http://localhost:3000/user" method="post"> 用户名:<input type="text" name="username"><br> 年龄:<input type="number" name="age"><br> <button type="submit">提交</button> </form> -
原生 AJAX 提交表单格式数据 :前端手动构造键值对字符串并设置
Content-Type。javascript// 前端 AJAX const xhr = new XMLHttpRequest(); xhr.open('POST', 'http://localhost:3000/user'); // 设置 Content-Type xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 构造请求体数据 const data = 'username=zhangsan&age=20'; xhr.send(data); -
第三方工具模拟表单请求 :如 Postman、curl 中选择
form-data(注意:Postman 中form-data对应multipart/form-data,x-www-form-urlencoded需单独选择该格式)。
六、与其他请求体解析中间件的区别
Express 中常用的请求体解析中间件有 3 个,需注意区分:
| 中间件 | 解析的 Content-Type | 适用场景 |
|---|---|---|
express.urlencoded |
application/x-www-form-urlencoded |
普通表单提交、简单键值对数据 |
express.json |
application/json |
AJAX/接口请求、JSON 格式数据 |
multer |
multipart/form-data |
文件上传(含表单+文件) |
注意
-
这三个中间件可同时注册,Express 会根据请求的
Content-Type自动匹配对应的解析中间件。 -
示例:同时支持 JSON 和表单格式请求体
javascriptconst express = require('express'); const app = express(); // 同时注册两个解析中间件 app.use(express.json()); // 解析 JSON 格式 app.use(express.urlencoded({ extended: true })); // 解析表单格式 // 该路由可接收两种格式的请求体 app.post('/data', (req, res) => { res.send(`解析后的请求体:${JSON.stringify(req.body)}`); }); app.listen(3000);
七、常见问题与解决方案
1. req.body 为 undefined
- 原因1:未注册
express.urlencoded中间件。 - 原因2:请求的
Content-Type不是application/x-www-form-urlencoded(例如是application/json但未注册express.json)。 - 原因3:中间件注册顺序错误(路由注册在中间件之前,导致路由执行时中间件未生效)。
- 解决方案:
- 确保注册
express.urlencoded({ extended: true })。 - 检查前端请求的
Content-Type是否正确。 - 确保中间件注册在路由之前(Express 中间件/路由按注册顺序执行)。
- 确保注册
2. 嵌套对象解析失败
- 原因:
extended配置为false,querystring库不支持嵌套解析。 - 解决方案:将
extended设置为true,使用qs库解析嵌套数据。
3. 提示 413 Request Entity Too Large
-
原因:请求体大小超出
limit配置限制,或键值对数量超出parameterLimit限制。 -
解决方案:增大
limit或parameterLimit的值。javascriptapp.use(express.urlencoded({ extended: true, limit: '5mb', // 增大请求体大小限制 parameterLimit: 5000 // 增大键值对数量限制 }));
八、最佳实践
- 全局注册+默认配置 :绝大多数场景下,直接全局注册
app.use(express.urlencoded({ extended: true }))即可满足需求。 - 按需配置限制 :若接口需要接收较大表单数据(如包含长文本),手动增大
limit值。 - 配合
express.json一起使用:现代项目通常同时支持 JSON 和表单格式请求体,两个中间件一起注册更灵活。 - 使用错误处理中间件:捕获解析失败或验证失败的错误,返回友好提示。
总结
express.urlencoded专门解析application/x-www-form-urlencoded格式请求体,解析后数据挂载在req.body上。- 核心配置
extended: true(支持嵌套数据)是绝大多数场景的首选,limit用于限制请求体大小。 - 需与
express.json(解析 JSON)、multer(解析文件上传)区分使用,中间件需注册在路由之前。 - 常见问题:
req.body为undefined多是中间件未注册或注册顺序错误,嵌套解析失败需开启extended: true。