I haven't been able to find anything in express's documentation, but is there such thing as request post processing? I am using a custom token authentication scheme using passport and I would like the ability to automatically update the token in a response header after making a request, mostly a hashed timestamp for authentication purposes. For discussion purposes, let's say I want the following function to execute after each request:
function requestPostProcess(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
}
Ideally, I'd like to be able to do this without having to call next() in each of my routes. Is that even possible?
If you want to add the token to the response,
1) You can create a middleware that adds the token as soon as the request comes, and before it is processed. Put this before request handlers.
Example,
app.use(function(req, res, next){
res.token = updateToken();
next();
})
The glitch here is that, the token will come with all the responses but that can be something you may accept, since it is a timestamp. Plus you can even handle errors using middlewares, and remove the token when the status is not 200.
Advantage: minimal changes required, with proper error handling it works great.
Disadvantage: it tells the time when request was received and not when the response was ready.
2) If you want to put the response after the process is completed, meaning the time when the response was ready, then you may need to create a utility function that sends back all the responses, and you always call that function. That utility function will check the status and appends the token.
function sendResponseGateway(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
res.send()
}
Now whenever you are ready to send response, you can call this function.
Disadvantage: function needs to be called everywhere and you will not be writing "res.send" anywhere.
Advantage :you have a gateway of sending response, you can do additional stuff like encoding, adding more headers etc. in that function and all those response modification stuff happens at one place.
Related
I can access the session object data when using post method but session object data is null when using get method.How can i access session object data using get method.
I am using express-session.
Front-end Code
For POST method
axios.post(url,{params:data},{withCredentials: "true"})
For GET method
axios.get(url,{params:data},{withCredentials: "true"})
Back-end Code
Middleware for both get and post requests.
router.use((req: Request, res: Response, next: NextFunction) => {
console.log(req);
if (req.session && req.session.username) next();
else res.status(401).send("Unauthorized");
});
axios.get() only takes two arguments (not three). The first is the URL and the second is the options. You are passing the options in the third spot which axios.get() does not look at. Therefore, it never sees the withCredentials: true option and thus doesn't send the session cookie and thus your server doesn't know how to find the session.
So, change from this:
axios.get(url,{params:data},{withCredentials: "true"})
to this:
axios.get(url,{withCredentials: "true"})
Note, there is no data argument for axios.get() because a GET does not send a request body, only a POST or PUT send the body. See the doc here.
Note: This bites people regularly with axios. .post() and .get() need a different number of arguments.
Is there a way to add middleware to the end of an express app or router chain that gets called to track whether or not the res / response was sent or not?
I mean, regardless of if:
A response is sent (string, JSON, etc.)
A static served file.
No file found in the static folder.
A catch-all callback was reached.
An error middleware was reached.
Example
For instance, if I wanted to log everything...
whether a response was successful or not, ie: it served a file via a express.static( ... ) middleware, some data fetched from a DB, or a custom middleware, or again... if it failed / threw an error...,
is there a way to invoke a callback at the very end?
So far from what I can understand, it seems like, by design, if a static file gets served successfully (via express.static), it doesn't call next(), so the chain stops there.
And for any custom-made middlewares using res.send(), you normally wouldn't want to call next() afterwards since it could cause some undesirable side-effects (errors with headers getting resent).
For error-handlers, that's easier since all unsuccessful responses can be caught here.
But how can it output both successful / unsuccessful responses? Could this be something that should be done without middlewares?
The solution I went with ended up being slightly different from this one by #idbehold, but in a nutshell, at the very top of the express app middleware chain, I had to hook a callback to the res Response object's finish event which gets triggered for most (all?) HTTP status-codes I needed to track a successfully served request.
app.use( ( req, res, next ) => {
res.on( 'finish', () => {
var codeStr = String( res.statusCode );
codeStr = codeStr[res.statusCode < 400 ? 'green' : 'red'];
var output = [req.method.green, req.fullUrl().green, codeStr];
trace( output.join( ' ' ) );
} );
next();
});
I can now get things like:
EDIT
Alright! So provided you also have an error-handler at the "end" of your middleware chain that serves something with an error 404 code, that will trigger the finish event on the res object.
Example of such an error-handler:
app.use( ( err, req, res, next ) => {
trace( "Error!".red );
trace( err );
res.status( 404 ).send(); // Triggers 'finish' on res.
})
There's a conceptual difficulty with the asynchronous architecture of node.js and Express for doing this. I'll describe the general problem and then discuss a few possible work-arounds.
First, each Express handler can be asynchronous. Thus, it gets called and returns pretty much immediately and nobody outside of that world knows whether it is still waiting for some asynchronous operation to finish before eventually sending its response or if it just failed to do anything. You literally can't tell from the outside world.
Second, you can monitor a given request to see if it either calls an error handler or if it sends a response. There is no way to monitor a request handler to see if it just failed to send anything because of the reason above - you have no way of knowing if its still waiting for some asynchronous thing to finish.
So, here's the best I could recommend:
Hook res.end() to see when it gets called. This is an indication that the response is now done (whether error or success). You can see an example of doing that in the express-afterware module that Medet linked in an above comment. The general idea is that you'd have your own middleware somewhere very early in the chain that overrides res.end() so you can see when its called. That early middleware would just install the override and call next() to continue the handler chain. Then, when the response is finished, your override would see that res.end() got called. This should work for all cases where the response is sent.
Then, you still need to handle cases where no response is sent (which is probably due to faulty code since all requests should get a response eventually). The only way I know of to do that is to implement some sort of timeout for a request. You can either use a built-in mechanism server.setTimeout() or you can implement your own inside your middleware (same middleware as describe in step 1). Then, after some timeout that you specify, if no response has yet been sent, you would take over and send some error response.
Install your own error middlewares early in the chain that will see and log all errors. Note that res.end() will still be called so the behavior in step 1 will still be triggered even for errors (error responses still call res.end()).
You can trigger a piece of code at the end of a request by using the finish event of the response object. The finish event is emitted when the response has been sent to the client and all the data has been flushed to the network.
app.use(function(req, res, next) {
res.on('finish', function() {
console.log('Request finished');
});
next();
});
I would like to handle both POST and GET requests as a single request, such that all of my routings and subsequent functions only need to process a single request, rather than duplicating everything once for GET and again for POST.
So I figure the simplest way of doing this is to convert a POST to a GET early on using middleware, is there any problem with this ?
if(req.method=='POST'){
req.method = 'GET';
req.query = req.body;
delete(req.body);
}
You can have the same handler function for the both requests i.e
app.get('/', handlerFunction);
app.post('/', handlerFunction);
You can have express respond to all POST requests as 302 redirects to the same URL (these are always GET requests).
Here's some sample code:
// Redirect all post requests
app.post('^*$', function(req, res) {
// Now just issue the same request again, this time as a GET
res.redirect(302, req.url);
});
});
Side note: this will work but I wouldn't recommend this as a long term solution. If you decide you do need to handle POST requests differently from GET requests and the maintainability will become a pain. In the long run, you're better off having a clear definition for how to handle POST and GET requests rather than treating them the same.
Recommended approach is to have the same handler function for both in this case. for eg.
app.get('/path', handler);
app.post('/path', handler);
I am turning around in stackoverflow without finding an answer to my question. I have used expressJS fur several days in order to make an access webpage that returns first an interstitial and then a webpage depending on several informations I can get from the requester IP and so on.
My first idea for the interstitial was to use this piece of code:
var interstitial = function(req, res, next) {
res.render('interstitial');
next();
}
router.get('/', interstitial, nextPage);
setting a timeout on the next nextPage callback function of router.get().
However it looks that I could not do that. I had an error "Error: Can't set headers after they are sent.". I suppose this is due to the fact that res.render already give a response to the request and in the philosophy of express, the next function is passing the req, res args for another reply to another function that possibly could do it. Am I right?
In that case, is there a way to give several answer, with timeout to one request? (a res.render, and after that in the next callback a rest.send...).
Or is this mandatory to force client to ask a request to give back another response? (using js on the client side for instance, or timers on client side, or maybe discussing with client script using socket.io).
Thanks
Not sure I fully understand, but you should be placing all your deterministic logic within the function of the handler you're using for your endpoint.
Kinda like so:
router.get('/', function(req, res){
var origin = request.origin;
if (origin == '11.22.33.44'){
res.send('Interstitial Page.');
}else{
res.send('Home Page');
}
});
You would replace the simple text responses with your actual pages, but the general idea is that once that endpoint is handled you can't next() it to secondary handler.
The typical middleware in express is used before the request hits the routes, for example there's authentication first, then the code of the specific route is executed, then the response is sent.
I am wondering whether it is possible to have a thing like a middleware after a route is hit.
Say I have five routes that all respond with some json and I wanted to log the sent json everytime one of the routes is hit.
I could go and log manually everytime I send a response in a route, like this:
console.log(data);
res.json(data);
but this seems redundant to me. A better approach could be to wrap that in a function to call in the route, but that would require to pass the response object everytime like this:
/* instead of the above */
send(data, res);
/* and then somewhere else usable for all routes */
function send(data, res) {
console.log(data);
res.json(data);
}
this also seems a bit like bad practice to me, so I'm wondering whether this would be the preferred way or if there's a way to use some kind of 'middleware', which would allow to send the response in the usual way and hook in after that.
It is not really possible to attach a middleware which executes after the route, but you can execute a middleware, which binds a finish event on response,
app.use(function(req, res, next){
res.on('finish', function(){
// Do whatever you want this will execute when response is finished
});
next();
});
also https://stackoverflow.com/a/21858212/3556874