I'm trying to log every request made to my sails application, but I can't find a way to log the response associated with a request.
I added this custom middleware in the config/http.js file :
myRequestLogger: function (req, res, next) {
req.on("end", function(){
sails.log(res.statusCode);
});
return next();
}
But it doesn't work properly, I can get the 200 codes, buta res.forbidden or res.notFound response is not logged. Any idea about how I could handle that ?
Thank you
You can override that in api/responses itself. Here is simplified override:
// api/responses/forbidden.js
module.exports = function(err, viewOrRedirect) {
// ... Sails logic
this.req._sails.log.verbose();
}
But, if you expect that your middleware above can do this, you're wrong. Your middleware should looks similar to this:
myRequestLogger: function(req, res, next) {
req._sails.log.verbose('YOUR LOG');
return next();
}
Ok, I have found the answer by reading this stackoverflow post : https://stackoverflow.com/a/11841877/2700309
Apparently there is a 'finish' event emitted just before the response is send to the client. So the right code would be :
myRequestLogger: function (req, res, next) {
res.on("finish", function(){
sails.log(res.statusCode);
});
return next();
}
And this seems to work!
Related
I have this helper :
function loginRequired(msg){ // this is the helper
return function(req, res, next){
if (req.user.is_authenticated){ // example
return next()
}
//else
req.flash('error_msg',msg)
return res.redirect('/')
}
}
and I have this route ( I`m using the helper in this route ) :
router.post('/new', loginRequired(msg='You are not allowed here'), async (req, res)=>{
// code
})
The problem is that the function returned by the helper is not being executed, when I request this route, it keeps loading forever and the content is never sent.
There isn't anything obviously wrong with the loginRequired() function and how you're using it so the problem is probably elsewhere. The only thing I see is that if req.user doesn't exist, then it would throw.
For further debugging, I would suggest you do this to make sure your route is being matched.
function logRoute(msg) {
return function(req, res, next) {
console.log(msg);
next();
}
}
router.post('/new', logRoute("/new handler"), loginRequired(msg='You are not allowed here'), async (req, res)=>{
// code
});
And, make sure you see /new handler in the console. If you don't even see that, then the problem is further upstream with how your route is declared as it isn't matching an incoming request. You would have to show us the rest of that code for us to see how the router is being used.
I have two endpoints in a node js app:
app.get('search', myGetController);
app.post('add', myPostController);
For simplicity, let's assume both services have only the following code:
exports.myGetController = function(req, res) {
res.status(404).json({ error: "not found" });
};
I want to have a middleware that is executed after the processing of the controllers, but before they are sent to the browser, so I can add a header based on the body of the response.
// process all responses to add ed25519
app.use(function(req, res, next) {
res.setHeader('CharCount', [How To get Body content]);
next();
});
I have two questions:
First of all, I would like to have all my controllers pass by that middleware after processing.
Second, I would like to access the body content so I can generate a header based on its content.
UPDATE
I have tried the suggested answer someone posted, and it is not working, or I am missing something.
This is what I have (before setting up my routes):
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('myToken', generateHeaderBasedOnBody(oldResJson));
oldResJson.call(res, body);
}
next();
});
The response that is being passed to my method is an empty string, even though the response sent by the service is not empty. Am I doing this in the wrong place, or what am I missing?
One solution for this issue would be to override the res.json function like so:
// process all responses to add ed25519
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('CharCount', /* Use body here */);
oldResJson.call(res, body);
}
next();
});
By doing this, you don't even need to change your controllers.
I'm somewhat new to NodeJS, and current I used Express and Request ( https://github.com/request/request ) to forward my app request to REST api server, current my code shown below:
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api')).pipe(res);
});
this code works when the REST API server is OK, but if the rest api server goes down, my nodejs app also goes down, because request stream will fail and the error is not caught by my app.
I checked the Request github page, it provides one way to handle the stream error, like
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
console.log(err);
})).pipe(res);
});
this can only log the error and prevent my NodeJS app crashing, but I want to change the response when error occurred so that the changed response can be piped to final one, for example, what I want to do in pseudocode:
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
console.log(err);
// what I want to do in pseudocode
response.statusCode = 500;
response.json = {
reason: err.errno
};
})).pipe(res);
});
Are there any ways to solve my problems? Thanks for any ideas!
Untested but could you pass the error back to middleware to handle the reponse?
app.use('/rest/*', function(req, res, next) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
return next(err)
})).pipe(res);
});
Handled like so
// Exception handling
app.use(function (error, req, res, next) {
console.log(error);
res.status(500).send(JSON.stringify(error));
next();
});
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.)
I have expressjs application with straitfort route processing like the following:
app.route('/').get(function(req, res, next) {
// handling code;
});
app.route('/account').get(function(req, res, next) {
// handling code;
});
app.route('/profile').get(function(req, res, next) {
// handling code;
});
At now I put all my code inside route handler but I want try to delegate it to some class such as the following.
app.route('/').get(function(req, res, next) {
new IndexPageController().get(req, res, next);
});
app.route('/account').get(function(req, res, next) {
new AccountPageController().get(req, res, next);
});
app.route('/profile').get(function(req, res, next) {
new ProfilePageController().get(req, res, next);
});
So what do you thing about the approach above and meybe you know the better one?
As you can see in the Express Response documentation - the response (req) can send information to the client by a few methods. The easiest way is to use req.render like:
// send the rendered view to the client
res.render('index');
Knowing this means that you can do whatever you want in another function, and at the end just call res.render (or any other method that sends information to the client). For example:
app.route('/').get(function(req, res, next) {
ndexPageController().get(req, res, next);
});
// in your IndexPageController:
function IndexPageController() {
function get(req, res, next) {
doSomeDatabaseCall(function(results) {
res.render('page', results);
}
}
return {
get: get
}
}
// actually instantiate it here and so module.exports
// will be equal to { get: get } with a reference to the real get method
// this way each time you require('IndexPageController') you won't
// create new instance, but rather user the already created one
// and just call a method on it.
module.exports = new IndexPageController();
There isn't strict approach to this. You can pass the response and someone else call render. Or you can wait for another thing to happen (like db call) and then call render. Everything is up to you - you just need to somehow send information to the client :)