I am currently making an application in Node.js, with the Express web server plug-in. I want to count the total data sent by the web server.
To do this, I need to get the 'Content-Length' field of an outgoing HTTP header. However, I need to do this right after the data is added.
If I need to alter core Express scripts, can somebody tell me which file this is contained in?
If you just want to count it, you can use a middleware for that:
var totalBytes = 0;
app.use(function(req, res, next) {
res.on('finish', function() {
totalBytes += Number(res.get('content-length') || 0);
});
next();
});
You have to include very early in the middleware stack, before any other middleware whose contents you want to count.
Also, this doesn't count any streamed data, for which no Content-Length header is set.
You could add middleware to monkey-patch the response methods. It’s ugly but better than altering core Express files.
This calculates total body bytes for standard and streamed responses. Place this before any other app.use() directives.
app.use(function(req, res, next) {
res.totalLength = 0;
var realResWrite = res.write;
res.write = function(chunk, encoding) {
res.totalLength += chunk.length;
realResWrite.call(res, chunk, encoding);
};
var realResEnd = res.end;
res.end = function(data, encoding) {
if (data) { res.totalLength += data.length; }
console.log('*** body bytes sent:', res.totalLength);
realResEnd.call(res, data, encoding);
};
next();
});
If you want to count it on each request then you can try below code!!!
var totalByte=0;
app.all('*', function(req,res, next){
res.on('finish', function() {
totalByte = parseInt(res.getHeader('Content-Length'), 10);
if(isNaN(totalByte))
totalByte = 0;
});
next();
});
Please remember totalByte is a global variable here and it added value on each request
Related
i would like to limit the request size for an upload in the following case (simplified):
app = Express();
router = Express.Router();
router.use('/upload', (req, res, next) => {
const writeStream = fs.createWriteStream('filename');
req.pipe(writeStream);
});
app.use(router);
As you can see, no form or similar is used (no way to change this). Therefore, the data is provided as a raw data stream.
As I could not find any existing modules for this case (body-parser does not work for this case, raw-body can also not be used as the stream should be left untouched), my current approach would be to use the following code as a middleware for express:
function(req, res, next) {
if (req.headers['content-length'] > limit) {
res.set("Connection", "close");
res.status(413).end();
return;
}
let received = 0;
req.on('data', (chunk) => {
received += chunk.length;
if (received > limit) {
res.set("Connection", "close");
res.status(413).end();
}
})
next();
})
Is there any better way to do this? Is there any existing npm package that can do this job?
In the end I solved it by using the answer provided by #ambianBeing and rewrote the function that afterwards handles the buffer instead of a stream.
I am trying to use middleware in express.js to get the rawBody of a request. It seems that its not reading the data chunks in the use command. Is this because the data variable doesn't exist??? I also tried placing this command before the call webserver.use(bodyParser.json()); (since I also need the json).It doesn't work whether I place before or after...
webserver.use(function(req, res, next) {
req.rawBody = '';
req.on('data', function(chunk) {
logger.error('in here'); //doesn't go into data.
req.rawBody += chunk;
});
logger.error(req.rawBody); //raw.rawBody is completely empty
next();
});
webserver.post('/slack/receive', function(req, res) {
//gets inside here after
});
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);
},
I am trying to modify the response with the help of a proxy created using node-http-proxy.
However I am not able to access the response headers. I want to access the response headers since I would like to modify javascript files and send the modified javascript files to the client.
This is my code:
var httpProxy = require('http-proxy');
var url = require('url');
var i = 0;
httpProxy.createServer(function(req, res, next) {
var oldwriteHead = res.writeHead;
res.writeHead = function(code, headers) {
oldwriteHead.call(res, code, headers);
console.log(headers); //this is undefined
};
next();
}, function(req, res, proxy) {
var urlObj = url.parse(req.url);
req.headers.host = urlObj.host;
req.url = urlObj.path;
proxy.proxyRequest(req, res, {
host: urlObj.host,
port: 80,
enable: {xforward: true}
});
}).listen(9000, function() {
console.log("Waiting for requests...");
});
writeHead() doesn't necessarily have to be called with an array of headers, write() can also send headers if necessary.
If you want to access headers (or set them), you can use this:
res.writeHead = function() {
// To set:
this.setHeader('your-header', 'your-header-value');
// To read:
console.log('Content-type:', this.getHeader('content-type'));
// Call the original method !!! see text
oldwriteHead.apply(this, arguments);
};
I'm using apply() to pass all the arguments to the old method, because writeHead() can actually have 3 arguments, while your code only assumed there were two.
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.