Access node response object in middleware after next()


#1

Hello everyone!

I have a weird problem. I’m trying to do a middleware which reacts on certain response status code.

It should always run, so I thought a server middleware should be the right spot.

I did a middleware like this:

class MyMiddleware {
    async handle (ctx, next) {
        await next()
        console.log(ctx.response.response.statusCode)
    }
}

Now, I noticed that the output was always 200 regardless of what actually happened.

I then debugged my problem with a test case of a “response.redirect” in a controller and noticed the following:

  1. After the “response.redirect” line, response.response.statusCode == 302 and response._lazyBody.method == ‘redirect’.
  2. With a server middleware, the code after “next()” would run before my controller even ran! I would not have expected that. I saw CORS headers in the response object at that point (the CORS middleware is also a server middleware) which made me suspect that me “await next()” returns only after all server middleware is completed (not the whole HTTP lifecycle as I expected). So, response.response.statusCode == 200 and response._lazyBody.method == “send”.
  3. With a global middleware, the code after “next()” would run at the time I expect (after the controller ran). However, again repsonse.response.statusCode == 200 at that point, even though it was 302 before (in the controller), but this time, response._lazyBody.method == “redirect”.

Why is it like this? How can I run code after everything else was done with the response, in all cases (also 404) and without getting the response data being reset somehow?

This issue also made me understand why my request logger didn’t work (which was using a similar mechanism) - I definitely need a way to fix this, otherwise my log output is not as useful as I hoped because it cannot read info from the response.

Thanks,
David


#2

Do it when the response is ready to be written.

class MyMiddleware {
    async handle (ctx, next) {
        await next()
        ctx.response.response.on('finish', () => {
          console.log(ctx.response.response.statusCode)
        })
    }
}

#3

Thanks, that works! :slight_smile: