Express response body after send - node.js

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.

Related

Getting exception on webhook from Stripe

I'm trying to set up a webhook from Stripe to handle the payment_intent.succeeded event, but I get an exception. This is my code from the Node backend (I have extracted all the relevant parts I hope. Let me know if anything else is needed):
const stripeWebHookSecret = 'whsec_WA0Rh4vAD3z0rMWy4kv2p6XXXXXXXXXX';
import express from 'express';
const app = express();
app.use(bodyParser.urlencoded({ extended:true }));
app.use(bodyParser.json());
app.use(session({ <some params here> }));
const openRouter = express.Router();
registerOpenPaymentRoutes(openRouter);
app.use('/open', openRouter);
And the implementation of registerOpenPaymentRoutes looks like this:
export const registerOpenPaymentRoutes = (router) => {
router.post('/payment/intent/webhook', bodyParser.raw({type: 'application/json'}), (req, res) => {
let signature = req.headers['stripe-signature'];
try {
let event = stripe.webhooks.constructEvent(req.body, signature, stripeWebHookSecret);
switch(event.type){
case 'payment_intent.succeeded':
let intent = event.data.object;
res.json({ message: 'Everything went smooth!', intent });
default:
res.status(400).json({ error: 'Event type not supported' });
}
}
catch (error){
res.status(400).json({ message: `Wrong signature`, signature, body: req.body, error });
}
});
}
So far so good.When I fire a test webhook event from the Stripe dashboard, I hit the endpoint, but get the result from the catch block. The error message is as follows:
No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing"
I'm returning the signature with the error message as well as you see above, and the signature looks like this:
"t=1557911017,v1=bebf499bcb35198b8bfaf22a68b8879574298f9f424e57ef292752e3ce21914d,v0=23402bb405bfd6bd2a13c310cfecda7ae1905609923d801fa4e8b872a4f82894"
As far as I understand from the documentation, what is needed to get the raw request body as mentioned are the bodyParser.raw({type: 'application/json'})argument to the router that I already have there.
Can anyone see the missing part?
It's because you've already set your express app to use the bodyParser.json() middleware, which clashes with the bodyParser.raw() middleware you set up in your webhook route.
If you remove the app.use(bodyParser.json()); line your webhooks will work as intended, but then the rest of your routes won't have a parsed body, which isn't ideal.
I suggest adding a custom middleware to choose the bodyParser version based on route. Something like:
// only use the raw bodyParser for webhooks
app.use((req, res, next) => {
if (req.originalUrl === '/payment/intent/webhook') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
Then explicitly use the bodyParser.raw() middleware on the webhook routes.
I came up with the very same problem, the answer above gave me an idea on how to solve it but didn't make the gig for me, so thanks for pointing me in the right direction.
I share the way it worked for me to bring the body raw without too much effort
I just add in my index.js after
app.use(bodyParser.urlencoded({ extended: false }));
this
app.use(
bodyParser.json({
verify: function (req, res, buf, encoding) {
req.rawBody = buf;
},
})
);
app.use(
bodyParser.urlencoded({
extended: false,
verify: function (req, res, buf, encoding) {
req.rawBody = buf;
},
})
);
And then on the function where I needed a raw body I used:
router.post("/webhook",express.raw({ type: "application/json" }),async (req, res) => {
const sig = req.headers["stripe-signature"];
const body = req.rawBody; //here I got the raw body
});
And that was enough to pass the (in this case) stripe validation
Hope to be helpful to somebody!
Have a great coding!

Express.js storing the rawBody with middleware.

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

NodeJS http post data empty

I am not able to get the data in the http post method of express nodejs.I am posting data from angular2. When i inspect in the network section of chrome, the payload is visible but the same data is received blank at app.post method.Please help me.
angular2 code
this.headers = new Headers();
this.headers.append('Content-Type', 'x-www-form-urlencoded');
let body = JSON.stringify({name:"Lionel Messi"});
return this.http
.post('http://localhost:8081/save',body
,this.headers);
}
nodejs code
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/save', function (req, res) {
console.log("Got a POST request for the homepage");
console.log(req.body);// output - {}
res.send('Hello POST');
})
Network Section in Chrome....payload is proper
alert method in node.js will not work . You need to use console.log("Hello");
Second thing is to get body data , use req.body.name
My way of writing code is like below and it works
$http({
method: 'POST',
url: 'http://localhost:8081/save',
data: {name:"Lionel Messi"}
})
.success(function(data) {
return data
})
.error(function(error) {
// handle error
});
Other way you can try is:
$http.post('http://localhost:8081/save', {name:"Lionel Messi"})
.then(function(data) {return data})
.catch(function() {console.log("Error Occured");});
You can do it like this-
Suppose you have sent username and password from your browser by post method.
app.post("/ url,function(request,response)
{ var username=request.body.username;
var password=request.body.password;})

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

Connect or Express middleware to modify the response.body

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.

Resources