如何在Node.js中忽略或覆盖Content-Type请求头处理非JSON请求
问题
我有一个Node.js服务器,收到的请求Content-Type为application/json,但请求体并非JSON格式,而是如下形式的form-urlencoded原始文本:
client_id=q9r71WPJtK5JWbkq7LAATEhQoXHQCJ9z&code_verifier=CiC6e0mZirQAwKkLvhiitiVuEvf2ZaFD7hsENkAhxyO&grant_type=authorization_code&code=TkdVtUfvtb4vKyJTRa9Z5F5G6_R8cwj6eIR6VGd0Tt0XX&redirect_uri=https%3A%2F%2Fuat.test.com.au
在Postman中测试时,若设置Content-Type为application/json,服务器接收的req.body为空对象{};若设置为text/plain,则能正确获取请求体。由于正在模拟外部供应商系统,短期内无法修改其请求的Content-Type。请问是否有办法强制Node.js将该请求视为文本而非JSON来处理?
当前使用的Express代码如下:
const express = require('express'); const app = express(); const PORT = 3000; // Without this middleware app.use(express.text()); app.post('/oauth/token', function (req, res) { console.log(req.body); res.end(); }) app.listen(PORT, function (err) { if (err) console.log(err); console.log("Server listening on PORT", PORT); });
Postman生成的curl示例如下:
curl --location 'http://127.0.0.1:3000/oauth/token' \ --header 'content-type: application/json' \ --data 'client_id=q9r71WPJtK5JWbkq7LAATEhQoXHQCJ9z&code_verifier=CiC6e0mZirQAwKkLvhiitiVuEvf2ZaFD7hsENkAhxyO&grant_type=authorization_code&code=TkdVtUfvtb4vKyJTRa9Z5F5G6_R8cwj6eIR6VGd0Tt0XX&redirect_uri=https%3A%2F%2Fuat.tab.com.au'
目前尝试的方向是寻找忽略或覆盖请求头中Content-Type的方法。
解决方案
方法1:扩展express.text()的类型匹配规则
express.text()默认仅处理text/plain类型请求,可通过type参数扩展匹配范围,让它同时处理application/json类型请求:
const express = require('express'); const app = express(); const PORT = 3000; // 让text中间件兼容application/json和text/plain类型 app.use(express.text({ type: ['text/plain', 'application/json'] })); app.post('/oauth/token', function (req, res) { console.log('原始请求体:', req.body); // 若需要解析为对象,可使用querystring模块处理 const querystring = require('querystring'); const parsedBody = querystring.parse(req.body); console.log('解析后的对象:', parsedBody); res.end(); }) app.listen(PORT, function (err) { if (err) console.log(err); console.log("Server listening on PORT", PORT); });
方法2:自定义中间件强制读取请求体为文本
如果需要更灵活的控制,可编写自定义中间件,直接读取请求流并转换为文本,完全忽略请求头的Content-Type:
const express = require('express'); const app = express(); const PORT = 3000; // 自定义中间件:强制读取请求体为文本 app.use((req, res, next) => { let rawData = ''; req.on('data', chunk => { rawData += chunk.toString(); }); req.on('end', () => { req.body = rawData; next(); }); }); app.post('/oauth/token', function (req, res) { console.log('原始请求体:', req.body); // 可选:解析为form-urlencoded对象 const querystring = require('querystring'); const parsedBody = querystring.parse(req.body); console.log('解析后的对象:', parsedBody); res.end(); }) app.listen(PORT, function (err) { if (err) console.log(err); console.log("Server listening on PORT", PORT); });
方法3:用express.urlencoded直接解析为对象
由于请求体本身是form-urlencoded格式,可让express.urlencoded处理application/json类型请求,直接得到解析后的对象:
const express = require('express'); const app = express(); const PORT = 3000; // 让urlencoded中间件兼容application/json和标准form-urlencoded类型 app.use(express.urlencoded({ extended: true, type: ['application/x-www-form-urlencoded', 'application/json'] })); app.post('/oauth/token', function (req, res) { // 直接获取解析后的对象 console.log(req.body); res.end(); }) app.listen(PORT, function (err) { if (err) console.log(err); console.log("Server listening on PORT", PORT); });
内容的提问来源于stack exchange,提问作者Tim Lane
相关产品推荐
相关产品推荐

