I would like to have a middleware function which modifies the response body.
This is for an express server.
Something like:
function modify(req, res, next){
res.on('send', function(){
res.body = res.body + "modified"
});
next();
}
express.use(modify);
I don't understand what event to listen for. Any help or documentation would be appreciate.
You don't need to listen to any events. Just make it
function modify(req, res, next){
res.body = res.body + "modified";
next();
}
And use it after you use the router. This way after all your routes have executed you can modify the body
I believe the OP actually wants to modify the response stream once a middleware has handled the request. Look at the bundled Compress middleware implementation for an example of how this is done. Connect monkey patches the ServerResponse prototype to emit the header event when writeHead is called, but before it is completed.
express-mung is designed for this. Instead of events its just more middleware. Your example would look something like
const mung = require('express-mung')
module.exports = mung.json(body => body.modifiedBy = 'me');
Overwriting the response's write method seemed to work for me with Express 4. This allows modifying the response's body even when it's a stream.
app.use(function (req, res, next) {
var write = res.write;
res.write = function (chunk) {
if (~res.getHeader('Content-Type').indexOf('text/html')) {
chunk instanceof Buffer && (chunk = chunk.toString());
chunk = chunk.replace(/(<\/body>)/, "<script>alert('hi')</script>\n\n$1");
res.setHeader('Content-Length', chunk.length);
}
write.apply(this, arguments);
};
next();
});
Just make sure to register this middleware before any other middleware that may be modifying the response.
There seems to be a module for doing just this called connect-static-transform, check it out:
https://github.com/KenPowers/connect-static-transform
A connect middleware which allows transformation of static files before serving them.
And it comes with examples, like this one.
Related
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 am unable to send the res (request object) between functions. The following code is executed by my app.js (main express middleware):
//app.js calls File.js
//File1.js
var file2 = require('./File2.js);
export.modules = function (req,res,next) {
file2(data) {
res.send(data); //<-- this is not working
}
}
//File2.js
export.modules = function(data){
data = 'test';
}
Also I do not understand when to use next() or when to use res.end().
Its really hard to understand from you code snippets, so i will address your second question regarding next vs send
You use next inside your middlewares, which means you dont want yet to respond to your client with data, but you want to proccess the data from another middleware down the line, when you reach your final middleware you need to use res.send();
note that you cannot use res.send multiple times, so you must call it when you finished your processing and want to respond the data to the user.
you must use middleware with express as following:
var app = express();
app.use(function(req,res, next){
// some proccessing
req.proccessData = "12312312";
next();
})
app.use(function(req,res, next){
// here you respond the data to the client
res.send(req.proccessData);
})
You can also use this with routes(get, post and etc...) Just add next as third param to the route when you want to send data to next stage
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
I need to modify the response data a module sends to the client, as the module uses res.send i can't seem to figure out a way for me to modify the data before it's carried out to the client.
Is there any kind of middleware/event that I can use to catch the res.send and modify the data before its executed?
I am aware that router.use exists but it's called before the router.post function and not before the res.send is sent to the client. So I need some kind of middleware which is called after the router.post function is done but before anything is sent to the client.
Well you can override the send function:
app.use(function (req, res) {
var send = res.send;
res.send = function (body) { // It might be a little tricky here, because send supports a variety of arguments, and you have to make sure you support all of them!
// Do something with the body...
send.call(this, body);
};
});
If you want to support more than just calling send(like calling end method), then you have to override more functions...
You can check connect-livereload on how it adds a script to any html output.
One more solution from here:
expressApp.use(function (req, res, next) {
req.on("end", function () {
console.log('on request end');
});
next();
});
Important Note: To work, this needs to be placed before body parser since it recreates the response object. see this answer
It can be done by overriding res.send
We override the res.send function to capture the response body in our API analytics tool as follows
// It will monkey patch the res.send.
// The patch intercepts the send invocation, executes is logic such as atatus.setResponseBody
// then restores the original send function and invokes that to finalize the req/res chain
const resSendInterceptor = (res, send) => (content) => {
// Set response body in Atatus Analytics
// Atatus is our API analytics tool
atatus.setResponseBody(content || '');
// TODO: You can modify your response body as you wish.
// Invoke the original send function.
res.send = send;
send.apply(this, arguments);
};
// Express Middleware
app.use((req, res, next) => {
// Overrides res.send
res.send = resSendInterceptor(res, res.send);
return next();
});
Your lack of code makes it really hard to answer your question, but you could use something like
Express 4.0:
router.use('/path', function (req, res) {
// Modify req
});
.use on a route will parse that before continuing on to the actual route so if somebody submitted a form or something, it will hit the .use before it goes to the .post or .get
Or you can do
Express 4.0:
app.use(function (req, res) {
// Modify Req
if (req.body.hasOwnProperty('some_form_name')) {
// Do Somthing
}
});
Which is the same thing, but it will be called before every request for every route.
Not sure if this answers your question but I think this might be what you're looking for?
I'm developing a sails.js (node.js framework based on express) aplication, which is going great but ]I can't solve this detail...
I need to send POST requests cross domain from internet explorer 8 and 9. For that I'm forced to use xDomainRequest object, wich doesn't allow to set a Content type header.
So, when the request gets to the server the content type is "text/plain", which doesn't fire the bodyParser express middleware, so my req.body is an empty object and I can't see the payload I'm sending from the client.
For this I've tried two things with no luck:
First I wanted to set a header to the request in my first middleware, which is of course not available:
req.set("Content-type", "Apli.....
Then, I created a middleware that listens to req.on('data'), like this:
var data = "";
req.on('data', function(chunk){
data += chunk;
});
req.on('end', function(){
req.rawBody = data;
next();
});
But the data event never fires!
Does anyone know how can I access my raw payload, so I can parse it myself.
Thanks!
with newest version of Sails, using express is deprecated.
I needed to use a specific parser to get raw data from Stripe API.
Here is my code, maybe it will help somebody :
bodyParser: function(req, res, next) {
var skipper = require('skipper')();
var rawParser = require("body-parser").raw({type: "*/*"});
// Create and return the middleware function
return function(req, res, next) {
sails.log.debug(req.headers);
if (req.headers && req.headers['stripe-signature']) {
sails.log.info('request using raw parser middleware');
return rawParser(req, res, next);
}
// Otherwise use Skipper to parse the body
sails.log.info('request using skipper middleware');
return skipper(req, res, next);
};
},
I think in this case you're going to have to implement your own body parser, which you can set as sails.config.express.bodyParser or create a config/express.js file like:
var express = require('express');
module.exports.express = {
bodyParser: function(options) {
// Get default body parser from Express
var defaultBodyParser = express.bodyParser(options);
// Get function for consumung raw body, yum.
var getBody = require('raw-body');
return function (req, res, next) {
// If there's no content type, or it's text/plain, parse text
if (!req.headers['content-type'] ||
req.headers['content-type'].match('text/plain')) {
// flag as parsed
req._body = true;
// parse
getBody(req, {
limit: 100000, // something reasonable here
expected: req.headers['content-length']
}, function (err, buf) {
if (err) return next(err);
// Make string from buffer
buf = buf.toString('utf8').trim();
// Set body
req.body = buf.length ? {content: buf} : {}
// Continue
next();
});
}
// Otherwise try the default parsers
else return defaultBodyParser(req, res, next);
};
}
You'll have to npm install express and npm install raw-body. Note that this example uses the default Express body parser as a fallback, not the default Sails body parser which isn't exposed anywhere (and is mostly the same as Express anyway, sans the JSON retry).
maxime's answer is mostly correct. minor modification needed as follows:
bodyParser: function(req, res, next) {
var skipper = require('skipper')();
var rawParser = require("body-parser").raw({type: "*/*"});
// Create and return the middleware function
sails.log.debug(req.headers);
if (req.headers && req.headers['stripe-signature']) {
sails.log.info('request using raw parser middleware');
return rawParser(req, res, next);
}
// Otherwise use Skipper to parse the body
sails.log.info('request using skipper middleware');
return skipper(req, res, next);
},