如何在Node.js中验证有效的application/x-www-form-urlencoded数据
验证application/x-www-form-urlencoded格式的解决方案
直接上可行的方案,针对你用Connect框架的场景,核心是先做格式合法性校验,再解析数据,避开querystring强制解析的问题:
1. 明确规范格式
application/x-www-form-urlencoded的核心规则:
- 数据由
&分隔的键值对组成 - 键和值必须是URL编码格式(允许的未编码字符:
0-9A-Za-z-_.~,其他字符需转成%XX形式) - 数组格式支持两种写法:
key[]=val1&key[]=val2或key[0]=val1&key[1]=val2
2. 编写覆盖数组场景的正则
之前的正则没适配数组格式,下面这个正则能匹配所有符合规范的情况:
const formUrlEncodedRegex = /^(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~]|\[\d*\])+=(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~])*)(?:&(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~]|\[\d*\])+=(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~])*)*$/;
^和$确保整个字符串完全匹配,没有多余内容- 键部分允许URL编码字符、合法未编码字符,以及数组格式的
[]/[数字] - 值部分允许空(比如
key=),同样支持URL编码和合法未编码字符 - 多个键值对用
&分隔,不允许末尾残留&
3. Connect框架下的实现代码
自定义中间件先获取原始请求体,做格式校验,通过后再解析:
const connect = require('connect'); const querystring = require('node:querystring'); const app = connect(); // 正则定义 const formUrlEncodedRegex = /^(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~]|\[\d*\])+=(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~])*)(?:&(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~]|\[\d*\])+=(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-_.~])*)*$/; // 自定义校验+解析中间件 app.use((req, res, next) => { // 只处理POST且Content-Type符合的请求 if (req.method !== 'POST' || req.headers['content-type'] !== 'application/x-www-form-urlencoded') { return next(); } let rawBody = ''; // 收集原始请求体 req.on('data', chunk => { rawBody += chunk.toString(); }); req.on('end', () => { // 允许空请求体的话,加|| rawBody === '' const isValid = formUrlEncodedRegex.test(rawBody); if (!isValid) { res.statusCode = 400; return res.end('无效的application/x-www-form-urlencoded格式'); } // 格式合法,解析后挂载到req.body req.body = querystring.parse(rawBody, '&', '=', { arrayLimit: 1000 }); next(); }); }); // 测试路由 app.use((req, res) => { if (req.method === 'POST' && req.body) { res.end(`解析后的请求体:${JSON.stringify(req.body)}`); } else { res.end('请发送POST请求,Content-Type设为application/x-www-form-urlencoded'); } }); app.listen(3000, () => { console.log('服务运行在3000端口'); });
注意事项
- 如果需要允许空的请求体(比如前端提交空表单),把
isValid的判断改成rawBody === '' || formUrlEncodedRegex.test(rawBody) querystring.parse的arrayLimit参数可以调整,控制同一个键能解析成数组的最大元素数,超过会转成对象- 正则已经校验了URL编码的合法性(
%后面必须跟两位十六进制数),不用额外处理
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

