You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js代理转发x-www-form-urlencoded POST请求时req.body为空问题

问题描述

我用bash命令 wget -q -T 25 --post-data "aa=bb&cc=dd" --no-check-certificate "$url" 将第三方API的数据从本地机器发给自己,但ISP屏蔽了第三方地址,所以搭建了一个Node.js代理服务器,接收数据后转发到第三方服务器。现在的问题是转发后req.body是空对象,搞不懂原因。

以下是简化后的代理API和模拟第三方API的Node.js代码:

const http = require('http')
const compression = require('compression')
const express = require('express')

const httpServerPort = process.env.SERVER_PORT   /// 设置你的端口

const app = express()
app.use(express.urlencoded({ extended: true, limit: '50mb' }))
app.use(compression())

const httpServer = http.createServer(app)

httpServer.listen(httpServerPort, () => {
    console.log(`HTTP server started on port ${httpServerPort}`)
})

app.post('/api/v1/agent_proxy', async (req, res) => {
    try {
        const postData = querystring.stringify(req.body)
//        console.log(postData)
        const options = {
            hostname: 'localhost',
            port: httpServerPort,
            path: '/api/v1/simu_api',
            method: 'POST',
            Headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                "Content-Length": Buffer.byteLength(postData)
            }
        }

        const innerReq = http.request(options, (innerRes) => {
            innerRes.on('data', (d) => {
                console.log(`statusCode: ${res.statusCode}`) 
                res.sendStatus(200)
            });
        });

        innerReq.on('error', (error) => {
            console.error(error)
            res.sendStatus(500)
        });

        innerReq.write(postData)
        innerReq.end()

    } catch (err) {
        console.error(err)
        res.sendStatus(501)
    }
})

app.post('/api/v1/simu_api', async (req, res) => {
    try {
////////// 这里能看到问题:req.body == {},但它应该是{aa: 'bb', cc: 'dd'} /////////
        console.log(req.body) 
    } catch (err) {
        console.error(err)
        res.sendStatus(501)
    }
    res.sendStatus(200)
})
问题原因及修复方案

1. 缺少querystring模块引入

代码中使用了querystring.stringify()但未引入该模块,会导致运行报错,无法生成有效的postData。需要在代码顶部添加:

const querystring = require('querystring')

2. 请求头字段名错误

options中的Headers应为小写的headers——Node.js的http.request要求该字段名必须小写,大写的话不会被识别,导致转发请求缺少正确的Content-Type头,express.urlencoded中间件无法解析请求体,最终req.body为空。

3. 代理请求响应处理逻辑缺陷

当前代码仅监听innerRes的data事件,如果模拟API没有返回数据(仅返回状态码),回调不会触发,代理接口会一直处于挂起状态。需要改为监听end事件确保响应处理完成。

修复后的完整代码

const http = require('http')
const compression = require('compression')
const express = require('express')
const querystring = require('querystring') // 新增模块引入

const httpServerPort = process.env.SERVER_PORT || 3000 // 增加默认端口,避免未设置环境变量时出错

const app = express()
app.use(express.urlencoded({ extended: true, limit: '50mb' }))
app.use(compression())

const httpServer = http.createServer(app)

httpServer.listen(httpServerPort, () => {
    console.log(`HTTP server started on port ${httpServerPort}`)
})

app.post('/api/v1/agent_proxy', async (req, res) => {
    try {
        const postData = querystring.stringify(req.body)
        console.log(postData) // 可打开日志确认数据是否正确生成

        const options = {
            hostname: 'localhost',
            port: httpServerPort,
            path: '/api/v1/simu_api',
            method: 'POST',
            headers: { // 改为小写的headers
                "Content-Type": "application/x-www-form-urlencoded",
                "Content-Length": Buffer.byteLength(postData)
            }
        }

        const innerReq = http.request(options, (innerRes) => {
            // 监听end事件确保响应处理完成
            innerRes.on('end', () => {
                console.log(`statusCode: ${innerRes.statusCode}`) // 这里应使用innerRes的状态码
                res.sendStatus(200)
            });
            
            // 处理响应数据,避免内存泄漏
            innerRes.on('data', (d) => {
                // 可根据需求处理返回的数据
            });
        });

        innerReq.on('error', (error) => {
            console.error(error)
            res.sendStatus(500)
        });

        innerReq.write(postData)
        innerReq.end()

    } catch (err) {
        console.error(err)
        res.sendStatus(501)
    }
})

app.post('/api/v1/simu_api', async (req, res) => {
    try {
        console.log(req.body) // 现在应能正确输出{ aa: 'bb', cc: 'dd' }
    } catch (err) {
        console.error(err)
        res.sendStatus(501)
    }
    res.sendStatus(200)
})

验证步骤

  1. 安装依赖:npm install express compression
  2. 设置端口环境变量或使用默认的3000端口
  3. 启动服务器:node 你的文件名.js
  4. 执行bash命令:wget -q -T 25 --post-data "aa=bb&cc=dd" --no-check-certificate "http://localhost:3000/api/v1/agent_proxy"
  5. 查看服务器日志,simu_api接口中的req.body应能正确输出预期对象。

内容的提问来源于stack exchange,提问作者Qua285

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:45:40