如何在`res.send`之后但在响应离开服务器之前挂钩,当知道res.statusCode时==>

问题描述 投票:7回答:1

我已经通过app.use()使用Express.js中的middleware工具来挂接所有请求并记录一条消息,但是发现res.statusCode几乎总是200 ,我检查的是不正确的。我认为这是默认值,并且由于尚未用我自己的statusCoderes.send(204)替换,因此始终为200

[我知道我可以在每个请求中的每个res.send(x)之后记录该消息,但是您可能会想到,这很麻烦。

所以,问题是:

我在哪里/如何将我的中间件功能与只在一个地方的条件挂钩,res.statusCode是客户端真正看到的那个?

相关代码:

// Log API requests.
app.use(function (req, res, next) {
    logger.info('API request.', {
        module: 'core'
        data  : {
            req: {
                method: req.method,
                url   : req.url,
                ip    : req.ip
            },
            res: {
                status_code: res.statusCode // Always 200 and not the really one.
            }
        }
    });

    next();
});

app.use(app.router);

如果我移动app.use(app.router),中间件将不会执行。

javascript node.js express middleware
1个回答
16
投票

res继承自http.ServerResponse in the standard library。这意味着它是带有EventEmitter事件的finish。因此,在您的中间件中,注册finish事件并在该事件触发时进行日志记录:

app.use(function (req, res, next) {
    res.on('finish', function() {
        logger.info('API request.', {
            module: 'core'
            data  : {
                req: {
                    method: req.method,
                    url   : req.url,
                    ip    : req.ip
                },
                res: {
                    status_code: res.statusCode
                }
            }
        });
    });

    next();
});

当然,您可以向res.once注册,但是finish事件只能触发一次,因此除非标准库中存在错误,否则不必这样做。

根据您的请求,这不一定会在“ res.send之后但响应离开服务器之前发生”-finish事件上的文档仅声明

[T]他的事件在响应头和主体的最后一段已移交给操作系统以通过网络传输时发出。

因此,某些响应可能已经离开服务器。但是,我相信这是您不需猴子补丁express就能获得的最接近的距离,对此我建议不要使用。

© www.soinside.com 2019 - 2024. All rights reserved.