Related to https://github.com/zeit/next.js/issues/6290
We need to run some logic after every route is handled.
We have a Prometheus client where we report performance metrics.
"handleRequest" does not call next and therefore our code is never invoked.
Custom Server Example
// Runs before each requests
server.use((req, res, next) => {
res.locals.startEpoch = Date.now();
next();
});
server.get("/", (req, res) => {
return handleRequest(req, res, "/", req.query);
});
server.get("*", (req, res) => {
return handleRequest(req, res);
});
// Runs after each requests - **THIS NEVER GETS INVOKED**
server.use((req, res, next) => {
const responseTimeInMs = Date.now() - res.locals.startEpoch;
httpRequestDurationMicroseconds
.labels(req.method, req.route.path, res.statusCode)
.observe(responseTimeInMs);
next();
});
handleRequest should call next
This would solve https://github.com/zeit/next.js/issues/7499 as well allowing people to add middlewares
I've not found a workaround
Maybe, instead of a middleware, you can use the res.on('finish') event for this in your main request handler?
Next.js does not provide a middleware, it ends the request when you call handle. So like @janpot is saying you'll probably want to add on finish or similar.
@timneutkens could you expand why adding a Middleware concept would be a bad idea for this framework ?
@timneutkens NextJS is great, I think it could be Amazing if I knew what is the correct way to open a dialogue about features such as middlewares or at least understanding why it does not fit the ZEIT's vision.
In the meantime, this is how to work around it as @Janpot kindly advised.
const handle = app.getRequestHandler();
const metricsInterval = Prometheus.collectDefaultMetrics();
const httpRequestDurationMicroseconds = new Prometheus.Histogram({
name: "http_request_duration_ms",
help: "Duration of HTTP requests in ms",
labelNames: ["method", "route", "code"],
buckets: [0.1, 5, 15, 50, 100, 200, 300, 400, 500] // buckets for response time from 0.1ms to 500ms
});
const onFinish = (req, res) => {
res.on("finish", () => {
const responseTimeInMs = Date.now() - res.locals.startEpoch;
httpRequestDurationMicroseconds
.labels(req.method, req.route.path, res.statusCode)
.observe(responseTimeInMs);
});
// Runs before each requests
server.use((req, res, next) => {
res.locals.startEpoch = Date.now();
next();
});
server.get("/_next/*", (req, res) => {
onFinish(req, res);
/* serving _next static content using next.js handler */
handle(req, res);
});
server.get("/", (req, res) => {
onFinish(req, res);
return handle(req, res, "/", req.query);
});
server.get("/dashboard", (req, res) => {
onFinish(req, res);
return handle(req, res, "/dashboard", req.query);
});
};
There already was an open RFC before this issue was posted: https://github.com/zeit/next.js/issues/7208