request: Can't pipe from request that has a POST body
I’m trying to create a new request object by piping from an Express request. This works fine for GET requests, but for POST requests that have a body, the body does not seem to be copied into the new request. I tried copying over the body manually like so:
let pipedReq = req.pipe(request({ url: 'http://www.example.com', form: req.body }));
This copies over the body but then I get a “write after end” error when pipedReq is cleaned up. Might be related to #1659.
It’s easy to reproduce the problem with the following simple Express app:
'use strict';
let express = require('express');
let request = require('request');
let app = express();
app.use('/', (req, res) => {
req.pipe(request.post({ url: 'http://www.example.com', form: { foo: 'bar' }}));
});
app.listen(process.env.PORT || 3000);
Backtrace:
Error: write after end
at ClientRequest.OutgoingMessage.write (_http_outgoing.js:413:15)
at Request.write (/.../node_modules/request/request.js:1354:25)
at end (/.../node_modules/request/request.js:548:16)
at Immediate._onImmediate (/.../node_modules/request/request.js:576:7)
at processImmediate [as _immediateCallback] (timers.js:358:17)
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 24 (9 by maintainers)
I know this is old, but I had a hard time finding a suitable solution to this, and thought it might be useful to others.
As shown in the https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options, adding this makes it so the new stream isn’t automatically terminated when req is terminated.
While this caused this example to work, I’ve noticed some issues making a proxy for other methods using this. The body somehow causes it to close everything properly, but without a body it still hangs. If using a json body parser, this shouldn’t cause a problem since it causes the body to be read as
{}even when there is no body, but without one it could still have issues. My current solution is to check for a content-length header on the request, and use the options object if one exists.I actually used
.pipe(res)in my real example and I verified that it doesn’t work. It doesn’t appear to send the request and it hangs. Since your example works, I quickly found the cause of the problem:It looks to me like when I use
body-parser, the piping no longer works. Do you agree and, if so, do you have any idea what the cause might be?Yep, if you take a look at my first comment again:
body-parserprocesses the request before entering your middleware, but you need the raw request to pipe it successfully.I don’t know too much about express or request (just using these for a single-page app proxy without really understanding how they work), but this fixed the
write after enderror for me:Instead of:
GETrequests does not have a body, that’s by design.This one works (your example):
Using this to make the request:
some=datagot sent.Where is that, I’m not following you.
Let me explain my use case. I implemented a simple web API proxy (see https://github.com/salsita/web-api-proxy). All it does is receive HTTP requests and redirect them to another host, replacing URL parameters if necessary with environment variables on the proxy server. The point is to avoid having to embed secret keys into client code.
It works great for GET requests, but I recently had a requirement to use it for POST as well. So I’m not initializing the body of my request as in your previous comment since the body is coming through the Express request. Your most recent example definitely works but that doesn’t really help me. What I need to do is:
It seems to me that if
reqhas a body, it doesn’t get copied over in this case. And anyway, the truth is that I do need to modify the body (since it might have placeholders that I need to replace using environment variables) so I’m going to have to do:req.pipe(request.post({ url: 'http://some/new/url', form: { some: 'form', data: 'here' }));That causes an exception to be thrown due to what I suspect is a bug in
request.Anyway, I can build a completely new
requestobject myself, but I wanted to make sure that I wasn’t missing something and also to report this issue in case it is a bug.@simov It’s the sample in my original post. If I use this one then the body is not sent:
If I use this then I get that exception:
Try with this one:
In case you want to modify the body, just construct a new request and pipe to the response.