I'm attempting to pipe a request for handling by a remote server, along the following lines:
var destination = request(url);
req.pipe(destination).pipe(res);
This works just fine for GET
requests. But for POST
requests I'm struggling. An important point to note, I think, is that for POST
requests I'm using a body parser before my POST
route handler in order to extract the body from the POST
request... it's just a basic text body parser because the body contains plain text:
var postRouteHandler = someFunction;
var bodyParser = require('body-parser');
var textParser = bodyParser.text({
limit: '50kb'
});
app.use('/postRoute', [textParser, postRouteHandler]);
From this issue and this issue it seems to me that doing any processing on the POST
request before you pipe it will cause a problem. Indeed, when I remove the parser, the piping seems to work OK.
The problem is that I need to examine the body first, to do some initial processing and then to determine whether or not to pipe the request on to the remote server at all. So I need to parse the body before piping.
Is there any way around this problem?
The issue is that with streams (like req
), once you've read it you can't reset it.
Because body-parser
has read the stream already, piping it won't work because that will try to read the stream again (which at that point has been exhausted).
A workaround would be take the text read by body-parser
, and create a minimal req
"clone" in order for request
to be able to pass the request along:
var intoStream = require('into-stream');
var bodyParser = require('body-parser');
var textParser = bodyParser.text({ limit: '50kb' });
var postRouteHandler = function(req, res) {
let text = req.body;
if (! shouldPipe(text)) {
return res.sendStatus(400); // or whatever
}
// Here's where the magic happens: create a new stream from `text`,
// and copy the properties from `req` that `request` needs to pass
// along the request to the destination.
let stream = intoStream(text);
stream.method = req.method;
stream.headers = req.headers;
// Pipe the newly created stream to request.
stream.pipe(request(url)).pipe(res);
};
app.use('/postRoute', [textParser, postRouteHandler]);