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

Node+Express修改res.send发送非原body对象报错及疑问

问题分析与解决方案

环境:Node 16.14.2, Express 4.18.1

核心原因:重写res.send触发的递归调用陷阱

你遇到的错误本质是Express原生res.send的内部逻辑,与你重写后的方法形成了无限递归,具体细节:

  • Express的res.send在接收非字符串/Buffer的对象时,会自动调用res.json()处理,而res.json()内部又会再次调用res.send()。
  • 你重写res.send后,原生方法内部触发的res.send()已经是你重写后的版本,而非最初的原生方法,这就形成了循环调用,最终导致栈溢出(Maximum call stack size exceeded)或枚举错误。
  • 发送原body不报错,是因为原body可能已经被Express预处理过(比如已转为字符串、或响应状态已标记为发送中),不会触发二次调用逻辑。

为什么转字符串就能正常运行?

当你把对象转为JSON字符串后,originalSend接收的是字符串类型,Express的res.send会直接处理字符串响应,不会触发res.json()的调用链,自然也就避开了递归循环。

正确的重写方式:阻断递归

要彻底解决问题,需要确保原生res.send内部调用的是最初的原生方法,而非你重写后的版本,以下是两种可行方案:

方案1:临时恢复原生res.send

app.use(function (req, res, next) {
    const originalSend = res.send;
    res.send = function (body) {
        // 临时恢复原生send方法,避免内部递归
        res.send = originalSend;
        // 执行自定义逻辑,修改响应体
        const modifiedBody = { ...body, "USER": req.user };
        // 调用原生方法发送响应
        const result = originalSend.call(this, modifiedBody);
        // 重新挂载重写后的send方法(如果后续请求还需要)
        res.send = arguments.callee;
        return result;
    };
    next();
});

方案2:直接用res.json处理对象

如果你的场景主要返回JSON数据,可以直接针对对象类型调用res.json,绕开res.send的内部调用链:

app.use(function (req, res, next) {
    const originalSend = res.send;
    res.send = function (body) {
        if (typeof body === 'object' && body !== null) {
            // 处理对象类型,直接调用res.json
            return res.json({ ...body, "USER": req.user });
        }
        // 非对象类型,调用原生send方法
        return originalSend.call(this, body);
    };
    next();
});

总结

重写Express响应方法时,必须注意原生方法的内部调用链,避免触发递归循环。转字符串只是临时规避方案,更稳妥的方式是通过恢复原生方法或直接调用对应类型的响应方法(如res.json)来处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:15:42