如何在中间件中获取响应体?

kka*_*gil 6 node.js express

我想用响应信息记录每个请求。

我尝试使用中间件,但遇到了问题。

res.body 未定义。

app.use((req, res, next) => {

    var time = Date.now();

    res.on('finish', function() {
        var clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
        var method = req.method;
        var path = req.baseUrl;
        var duration = Date.now() - time;

        console.log({
            clientIp,
            elapsedTime: `${duration}ms`,
            hostname: req.headers.host,
            level: 'INFO',
            method,
            path,
            phase: process.env.NODE_ENV,
            reqBody: req.body,
            reqHeaders: req.headers,
            resBody: res.body,
            resHeaders: res.getHeaders(),
            status: res.statusCode
        });
    });

    next();
});
Run Code Online (Sandbox Code Playgroud)

实际上客户端上有响应数据。

如何在中间件中获得响应体?

小智 13

拦截响应正文并将res.json其存储起来res.locals以供稍后访问。

app.express.use((req, res, next) => {
  const oldJson = res.json;
  res.json = (body) => {
    res.locals.body = body;
    return oldJson.call(res, body);
  };
  next();
});
Run Code Online (Sandbox Code Playgroud)


Sag*_*uri 10

可以通过覆盖response.json函数拦截响应。通过这样做,并添加我们的custom function,每次response.json()调用都会触发我们的拦截功能。

中间件/response.filter.js:

// Response Interceptor Middleware
export default (request, response, next) => {
    try {
        const oldJSON = response.json;
        response.json = (data) => {
            // For Async call, handle the promise and then set the data to `oldJson`
            if (data && data.then != undefined) {
                // Resetting json to original to avoid cyclic call.
                return data.then((responseData) => {
                    // Custom logic/code.
                    response.json = oldJSON;
                    return oldJSON.call(response, responseData);
                }).catch((error) => {
                    next(error);
                });
            } else {
                // For non-async interceptor functions
                // Resetting json to original to avoid cyclic call.
                // Custom logic/code.
                response.json = oldJSON;
                return oldJSON.call(response, finalResponse);
            }
        }
    } catch (error) {
        next(error);
    }
}
Run Code Online (Sandbox Code Playgroud)

Server.js文件中,注册中间件:

// Server.js file
import externalResponseFilter from "./middleware/response.filter.js:";

// Create Express server
const app = express();

// Response interceptor - Initialization.
app.use(externalResponseFilter);
Run Code Online (Sandbox Code Playgroud)

并且在您返回 的控制器中response,返回response.json()函数而不是response.send()

如果需要任何其他解释,请告诉我。