PROBLEM
I've been looking for request/response timeouts for Express.js but everything seems to be related to the connection rather than the request/response itself.
If a request is taking a long time, it should be timed out. Obviously this shouldn't happen but even a simple mistake as having a route handler without a call to the callback or without res.send(), the browser will keep waiting for a reply forever.
An empty route handler is a perfect example of this.
app.get('/sessions/', function(req, res, callback){});
FIX
I added the following before app.use(app,router); and it seemed to add the timeout functionality. Does anyone have any experience/opinion on this?
app.use(function(req, res, next){
res.setTimeout(120000, function(){
console.log('Request has timed out.');
res.send(408);
});
next();
});
Note that I've set the timeout to 2 minutes.
There is already a Connect Middleware for Timeout support:
var timeout = express.timeout // express v3 and below
var timeout = require('connect-timeout'); //express v4
app.use(timeout(120000));
app.use(haltOnTimedout);
function haltOnTimedout(req, res, next){
if (!req.timedout) next();
}
If you plan on using the Timeout middleware as a top-level middleware like above, the haltOnTimedOut middleware needs to be the last middleware defined in the stack and is used for catching the timeout event. Thanks #Aichholzer for the update.
Side Note:
Keep in mind that if you roll your own timeout middleware, 4xx status codes are for client errors and 5xx are for server errors. 408s are reserved for when:
The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.
You don't need other npm modules to do this
var server = app.listen();
server.setTimeout(500000);
inspired by https://github.com/expressjs/express/issues/3330
or
app.use(function(req, res, next){
req.setTimeout(500000, function(){
// call back function is called when request timed out.
});
next();
});
An update if one is using Express 4.2 then the timeout middleware has been removed so need to manually add it with
npm install connect-timeout
and in the code it has to be (Edited as per comment, how to include it in the code)
var timeout = require('connect-timeout');
app.use(timeout('100s'));
In case you would like to use timeout middleware and exclude a specific route:
var timeout = require('connect-timeout');
app.use(timeout('5s')); //set 5s timeout for all requests
app.use('/my_route', function(req, res, next) {
req.clearTimeout(); // clear request timeout
req.setTimeout(20000); //set a 20s timeout for this request
next();
}).get('/my_route', function(req, res) {
//do something that takes a long time
});
If you need to test your api, this solotion can you help.
I used this in middleware to test my frontend.
For exmaple: if you need to test loader in frontend.
const router = require('express').Router();
const { data } = require('./data');
router.get('/api/data', (req, res, next) => {
setTimeout(() => {
res.set('Content-Type', 'application/json')
res.status(200).send(data)
next()
}, 2000)
})
module.exports = router;
request.setTimeout(< time in milliseconds >) does the job
https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback
You can try:
return await new Promise((resolve) =>
setTimeout(() => {
resolve(resp);
}, 3000),
);
In above code, 3000 = 3 sec.
Change it according to your requirement.
I have not tried for very long scenarios though. Let me know the results in comments.
Before you set your routes, add the code:
app.all('*', function(req, res, next) {
setTimeout(function() {
next();
}, 120000); // 120 seconds
});
Related
I am using express and Connect Timeout Middleware to handle the timeouts.
It works great, but I the default node http server's timeout is set to two minutes.
Therefore if I want to set my timeout middleware to a value greater than two minutes, I also have to increase the http server timeout to be slightly bigger (otherwise my connect timeout handler is not called)
const app = express();
const http = new Http.Server(app);
http.setTimeout((4 * 60 * 1000) + 1); <-- Must set this
app.use(timeout('4m'));
How can I avoid this ? Am I missing something ?
If you want to use the connect-timeout middleware, you can't avoid it, since the middleware does not change the socket timeout, which defaults to 2 minutes.
There are two possible ways to avoid it, either using server.setTimeout() or request.setTimeout.
In case you only want to change the timeout to a few routes, and leave the default timeout to the rest, the recommended approach is to use: request.setTimeout
app.use('/some-routes', (req, res, next) => {
req.setTimeout((4 * 60 * 1000) + 1);
next();
}, timeout('4m'));
An alternative to setting the req.setTimeout to a value greater than the connect-timeout value, is dropping the connect-timeout middleware and using another work around, which is also not ideal.
You can check this old Node.js issue https://github.com/nodejs/node-v0.x-archive/issues/3460
function haltOnTimedout (req, res, next) {
if (!req.timedout) next()
}
app.use('/some-routes', (req, res, next) => {
req.setTimeout(4 * 60 * 1000); // No need to offset
req.socket.removeAllListeners('timeout'); // This is the work around
req.socket.once('timeout', () => {
req.timedout = true;
res.status(504).send('Timeout');
});
next();
});
app.use(haltOnTimedout);
// But if the timeout occurs in the middle of a route
// You will need to check if the headers were sent or if the request timedout
app.get('/some-routes', async(req, res, next) => {
// some async processing...
await asyncOperation();
if (!res.headersSent) // or !req.timedout
res.send('done');
});
Except for the obvious, async/await and the middleware signatures, koa's middleware app.use(async (ctx, next) => {...}) vs express app.use(function (req, res, next) {...})
How would koa's middleware make a difference ? Why would that be called onion model ?
------ update ------
My original question probably wasn't clearly enough. I was wondering why koa middleware is better than express middleware ?
------ update 2 ------
As Mastering Koa Middleware explained the error handling is indeed better in koa.
Well, in koajs, there is the option of cascading the middlewares:
An example from the koa page states this:
// logger
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// response
app.use(async ctx => {
ctx.body = 'Hello World';
});
Compared to express, the flow of the above code will be:
Logger middleware will pause execution of its own code, and move on
to x-response-time middleware,
x-response-time will stat a time, then pause its code execution and
hand control over to the next middleware (response),
The next middleware is response, it will set the response in the
body, then unwind code execution back to x-response-time
x-response-time will continue its code execution from where it left
off and calculate the time it took to set the response, then unwind
code execution back to the logger middleware
Logger middleware will log the response time.
Given the above example, you could use this to your advantage. The first middleware (logger) can be swapped with one that catches exceptions, such that it will wrap all the following middlewares in a try catch block
Express next is called at the end of middleware call and gives the control to next middleware. Previous middleware is unaware of how next middleware is executed. Middlewares can interact in one way, the last middleware is usually responsible for sending a request.
As Koa 2 documentation explains, next() returns the result of next middleware in the stack, i.e. a promise:
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
Koa middlewares can interact in two ways, it's unnecessary that the last middleware in the stack sends a response, response assignment can be delegated to previous middleware. Since the response isn't sent explicitly like res.send() but after middleware stack execution is finished, it's possible to modify it in other middlewares (this can be used for good or bad):
app.use(function thirdPartyMiddlewareWeCannotChange(ctx, next) {
if (!auth)
ctx.redirect('/login');
next();
});
app.use(router.routes());
router.get('/no-auth-here', (ctx) => {
ctx.status = 200;
ctx.body = 'hi';
});
I want to log all requests like this:
8:04:20 PM - info: /api/v2 200
8:04:22 PM - info: /api/v2/asdf 200
However, in express, the middleware is called before the request is processed, so I cannot get the real response code. I always get 200. What is the right approach to accomplish this?
You can use morgan to log your requests:
const morgan = require("morgan");
app.use(morgan('dev'));
For more documentation visit morgan. Yo may also be interested in
on-finished package to execute arbitrary code on request completion.
Here you go:
app.use((req, res, next)=> {
console.log('I run on every request!');
next();
})
Have your middleware below your routes and in your routes add a third parameter on the callback like this:
app.get( "/", function( req, res, next ) {
res.send(something);
next();
});
app.use(function(req, res, next) {
console.log('after request is done');
});
I want to create a middleware function in express.js. which can monitor every requests and responses. I created a middleware but it can only monitor the requests, not the responses.
function middlewareFunc (req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
You should know that res in function(req, res, next) is a instance of class http.ServerResponse. So it can be listen on finish event, please see the link: https://nodejs.org/api/stream.html#stream_event_finish
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterRequest);
res.removeListener('close', afterRequest);
// action after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
});
app.use(app.router);
app.use() and middleware can be used for "before" and a combination of the close and finish events can be used for "after."
For that you can write two middlewares
1) Before all request endpoints.
//middleware
function middlewareFunEarlier(req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
app.use(middlewareFunEarlier);
app.get('/', function(req, res, next){
//do something
res.end();
});
2) After all end points. And you must have to use next() in all endpoints
app.get('/', function(req, res, next){
//do something
next();
});
app.use(middlewareFunLater);
//middlware
function middlewareFunLater(req, res, next){
console.log(res);
res.end();
}
It can be work around with existing tools.
Ok, so first of all, the reason you are only seeing the requests is because of how middleware works. Everything gets run once in a certain order, and runs only once. When your middleware gets run it is most likely before the response has been created. In order to get the response you would have to make your code run when your controller goes to render or something like that.
Second of all, it seems like basic logging is all you need.(weather it be with a library or just console logging stuff.)
There are a few posts on this question but none that answers the issue directly, head-on. Let me clarify that I understand (or so I think) the use of next(), next('route'), return next(), return and their impact on control flow.
My entire middleware for the app consists of a series of app.use, as in:
app.use(f1);
app.use(f2);
app.use(f3);
app.use(f4);
...
In each of these middlewares, I have possibility of sending the response and be done without any need for further processing. My problem is that I am unable to stop the processing from going to the next middleware.
I have a clumsy work around. I just set a res.locals.completed flag after sending a response. In all the middlewares, at the very start, I check this flag and skip processing in the middleware if the flag is set. In the very first middleware, this flag is unset.
Surely, there must be a better solution, what is it? I would think that Express implicitly would do this checking and skip the middlewares through some express-specific method?
According to the express documentation on http://expressjs.com/guide/using-middleware.html
If the current middleware does not end the request-response cycle,
it must call next() to pass control to the next middleware,
otherwise the request will be left hanging.
so if a middleware needs to end the request-response early, simply do not call next() but make sure that the middleware really ends the request-response by calling res.end, res.send, res.render or any method that implicitely calls res.end
app.use(function (req, res, next) {
if (/* stop here */) {
res.end();
} else {
next();
}
});
Here is an example server showing that it works
var express = require('express');
var app = express();
var count = 0;
app.use(function(req, res, next) {
console.log('f1');
next();
})
app.use(function(req, res, next) {
console.log('f2');
if (count > 1) {
res.send('Bye');
} else {
next();
}
})
app.use(function(req, res, next) {
console.log('f3');
count++;
next();
})
app.get('/', function (req, res) {
res.send('Hello World: ' + count);
});
var server = app.listen(3000);
you will see the after 3 requests, the server shows "Bye" and f3 is not reached