Express.js storing the rawBody with middleware. - node.js

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
});

Related

Express Limit Request Size

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.

Express response body after send

I'm using express I would like to audit response after I send it
var app = express();
app.use(audit.auditRequest); // working fine
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(expressValidator({
customValidators: validations.customValidators,
customSanitizers: sanitizers.customSanitizers
}));
app.use(auth.authenticate);
app.use('/myPath', myPathHandler);
app.use(errorHandler.handleErrors);
**app.use(audit.auditResponse);**
errorHandler, for example, looks like this:
...
res.status(500).send({ message : "abc", code: 5010, description : "def" });
next(); // call audit middleware
and then audit middleware looks like this:
...
auditModule.auditResponse = function auditResponse(req, res, next) {
auditLogger.info('Response', res.body);
// but res.body is undefined
};
...
Any idea why?
As much as I'm aware response body isn't just available as easily as property on response.
So : res.body isn't going to work. So, I have a work-around. We can catch data from response write, accumulate it and add it into res.body manually. Inject this as a middleware so it will work. Pls note it should be injected before any .compress().
Inject as middleware (this is in ES6 & will work in Node.js directly, but if you want I'll change the answer to ES5):
server.use((req, res, next) => {
const original_write = res.write,
original_end = res.end,
chunks = [];
res.write = function(chunk) {
chunks.push(chunk);
original_write.apply(res, arguments);
};
res.end = function(chunk) {
if (chunk)
chunks.push(chunk);
res.body = Buffer.concat(chunks).toString('utf8');
original_end.apply(res, arguments);
};
next();
});
Now you can happily use res.body after your you send the response. :D
Note: the res.body will be a utf8 encoded String. Parse it back to json if it was an object.
Try req.body instead of res.body.

Node.js express: Getting HTTP header before it is sent

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

sails.js Getting a POST payload with text/plain content type

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);
},

How to write to response from HTTP Client Node.JS

I have the following...
var request = require('request');
exports.list = function(req, res){
res.send("Listing");
};
exports.get = function(req, res){
request.get("<URL>", function (err, res, body) {
if (!err) {
res.send(body,"utf8");
}
});
};
This fails with the following....
TypeError: Object #<IncomingMessage> has no method 'send'
How do I do this?
UPDATE tried to use write instead of send but...
/Users/me/Development/htp/routes/property.js:9
res.setHeader('Content-Type', 'text/html');
^
TypeError: Object #<IncomingMessage> has no method 'setHeader'
Also writing out to the console instead works fine.
Problem was with scope of variables, my response output was the same name as the response object I got back in my callback. Changing this around (resp vs res) made it work....
exports.get = function(req, res){
request.get("<url>", function (err, resp, body) {
if (!err) {
res.send(body);
}
});
};
What you are trying to do, is to make Request > Response server. But you are using Request module, that allows to get stuff rather than respond.
What you need is http or better get express.js and use it, as it is straight forward and well popular web framework for exactly what you need.
I wasn't aware OP is using Express. You will encounter a similar error if you attempt to use req.send with the vanilla HTTP module instead of Express.
var http = require('http');
function requestHandler(req, res){
//res.send(200, '<html></html>'); // not a valid method without express
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end('<html><body>foo bar</body></html>');
};
http.createServer(handler).listen(3000);

Resources