-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
hanging POST requests #180
Comments
I believe your issue may be solved by using the |
@AvianFlu: Thanks for the buffer pointer, but this ended up being caused by express's body-parsing. Instead of declaring the API route (for proxying) within express routes, I configured it as middleware and Some coffeescript of the solution:
|
You're correct - express's body parsing turns the request stream into a regular object. The solution is either to buffer it, as I was suggesting, or to deal with the request before the parsing, as you ended up doing. Glad you figured it out! |
…iscover when you run into it. If there was an error, people would search for the error text, but there isn't.
I ran into this problem too .. [email protected], [email protected], [email protected]. In my case, it turns out that http-proxy's buffer doesn't play well with connect's bodyParser middleware. The buffer is adding listeners for the 'data' and 'end' events to the request object so that it can re-emit them later (on a call to proxyRequest, e.g.). The bodyParser middleware is also adding listeners for the 'data' and 'end' events to the request object but they are never removed. So when re-emitted by the buffer, they're picked up a second time by the bodyParser. This can result in JSON parse errors and "Can't render headers after they are sent to the client" exceptions (and probably other errors). |
For those having issues with this, I found that this information seemed a bit out of date or difficult to implement (too much so for me, at least), compared to using connect-restreamer. That approach is outlined in the middleware example for using the bodyParser: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/middleware/bodyDecoder-middleware.js |
So, How to solve this problem? |
connect-restreamer worked for me. The last thing in my middle-ware is: app.use(require('connect-restreamer')()); Then I have a can do the proxy request normally: var httpProxy = require('http-proxy');
var routingProxy = new httpProxy.RoutingProxy();
app.get('/proxy/', function (req, res) {
routingProxy.proxyRequest(req, res, {
host : host,
port : port
});
}); Configuring the proxy as part of middleware before bodyParser (if this is an option for you) also worked for me. I did not attempt the buffer solution. |
Also, simply not using the |
This thread has helped me. Thanks everyone. |
Helpful, Thanks! |
For some reason, If anyone wants yet another fix, I ended up just calling bodyParser manually. So the proxying worked since bodyParser is not in the middleware. The code looked like:
|
The order of middlewared does matter. Using the bodyParser before the httpProxy does break the requests with JSON body. For more detailed discussion refer to http-party/node-http-proxy#180
Man, you saved my life! |
Thanks for that solution it works fine |
Restreamer works for me. I needed to leave bodyParser because my proxy was conditional upon the contents of the request body. Here is a working example authored by someone else: |
The example from bodyDecoder pointed out by @gdw2 does not work for me. I get
Using I am using express instead of connect.
This may related to this issue however. |
@FoxxMD same behavior here |
For those in the unfortunate position not being able to rearrange/remove the bodyparser middleware:
Hope that helps. This was really frustrating. |
Thanks all - I went with OP's suggestion and moved the proxy route above the bodyParser middleware |
I used all of the solution above, _but it's not worked anyway_. And this is my solution: var proxy = httpProxy.createProxyServer();
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if(req.method=="POST"&&req.body){
proxyReq.write(req.body);
proxyReq.end();
}
});
var headers = {};
if(req.method=="POST"&&req.body){
var data = JSON.stringify(req.body);
req.body = data;
headers = {
"Content-Type": "application/json",
"Content-Length": data.length
}
}
proxy.web(req, res, {
target: url,
headers:headers
}); |
@vvpvvp,Can i modify/add |
None of these solutions work with the latest version of express & http-proxy, any suggestions? Here is what my code looks like - I still get the hanging POST request issue. I am just trying to read the POST body before conditionally proxying the request.
EDIT: I am now getting a 'write after end' error which is odd because I am using restreamer. |
@vvpvvp big thinks for your tips |
@narciero I am also getting same error. Did you find any workaround for this ? |
Putting this before using the express body parser worked for me! Thanks for the help guys. |
Hi I have done slightly similar yet different fix for this, without using any restreamer, take a look here Idea is to not use the body-parser as middleware instead apply only to the matched routes in my local web server and hence don't bring in the body-parser at all in between proxy and the local web server Comments, suggestions welcome |
Here is my solution: import { createServer as createHttpServer } from 'http'
import { createProxyServer } from 'node-http-proxy'
function parseBody(message) {
const body = []
return new Promise((resolve, reject) => {
message.on('data', c => body.push(c))
message.on('end', () => resolve(body))
message.on('error', err => reject(err))
})
}
export default function createServer(proxyCfg, port) {
const proxyServer = createProxyServer(proxyCfg)
.on('proxyReq', onProxyReq)
function onProxyReq(proxyReq, req, res) {
if (req.body && req.body.length) {
proxyReq.write(new Buffer(req.body[0]))
proxyReq.end()
}
}
createHttpServer(async (req, res) => {
req.body = parseBody(req)
if (!res.headersSent) {
proxyServer.web(req, res)
}
}).listen(port)
} |
The bodyDecoder-middleware.js example shows a similar implementation of this: //restream parsed body before proxying
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if(req.body) {
let bodyData = JSON.stringify(req.body);
// incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json
proxyReq.setHeader('Content-Type','application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
// stream the content
proxyReq.write(bodyData);
}
}); Amazing, this issue is 5 years old... |
For anyone who has this issue of POST requests timing out through the proxy because of the post body, the middleware solution linked above (https://github.com/nodejitsu/node-http-proxy/blob/master/examples/middleware/bodyDecoder-middleware.js) worked for me. However, it did have a 'gotcha' - the code looks for an exact match on the contentType header, which might not happen: proxy.on( 'proxyReq', ( proxyReq, req, res, options ) => {
if ( !req.body || !Object.keys( req.body ).length ) {
return;
}
let contentType = proxyReq.getHeader( 'Content-Type' );
let bodyData;
if ( contentType.includes( 'application/json' ) ) {
bodyData = JSON.stringify( req.body );
}
if ( contentType.includes( 'application/x-www-form-urlencoded' ) ) {
bodyData = queryString.stringify( req.body );
}
if ( bodyData ) {
proxyReq.setHeader( 'Content-Length', Buffer.byteLength( bodyData ) );
proxyReq.write( bodyData );
}
}); Hope this helps someone who comes here (I should really put it on StackOverflow, shouldn't I?). |
@kevteljeur what the |
As per the linked example for the full code: https://nodejs.org/dist/latest-v8.x/docs/api/querystring.html |
@vshih @kevteljeur thank you, I have tried this modified approach, that now is also in the examples, but for some reason it does not forward the body as json and I get an error. Asked on SF as well. The error by middleware side was
The error on the backend (tornado) was while I did the reastream like //restream parsed body before proxying
proxy.on('proxyReq', function (proxyReq, req, res, options) {
if (!req.body || !Object.keys(req.body).length) {
return;
}
var contentType = proxyReq.getHeader('Content-Type');
var bodyData;
if (contentType === 'application/json') {
bodyData = JSON.stringify(req.body);
}
if (contentType === 'application/x-www-form-urlencoded') {
bodyData = queryString.stringify(req.body);
}
if (bodyData) {
console.log("------", bodyData);
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
}
});
proxy.on('proxyRes', function (proxyRes, req, res) {
modifyResponse(res, proxyRes, function (response) {
if (!MXMUtil.empty(response) && !MXMUtil.empty(response.message) && !MXMUtil.empty(response.message.body)) { // valid response
if (!MXMUtil.empty(response.message.body.error)) { // error response
var message = self.processor.createErrorMessage(500, '', response.message.body.error);
response = message;
} else { // valid response
var message = self.processor.prepareResponse(req_start, response.message.body);
response = message;
}
}
return response; // return value can be a promise
});
});
proxy.on('error', function (error, req, res) {
var errorMessage = self.processor.createErrorMessage(500, '', error.message);
res.send(errorMessage);
res.end();
});
proxy.web(req, res, {
// url string to be parsed with the url module
target: target_uri,
// true/false, Default: false - changes the origin of the host header to the target URL
changeOrigin: true,
// true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request
ignorePath: true
}); the express uses
I have also tried a simpler approach that was: if (req.body && req.body.length) {
proxyReq.setHeader('Content-Type','application/json');
proxyReq.write(new Buffer(req.body[0]));
proxyReq.end();
} In that case I get a json decoding error, while the |
Here is my full code. I spent lot of time on this. I just posting this code to save your time.
|
It working with me. Thanks |
Hi,
I'm using express and trying to proxy certain requests to a different server, as follows (simplified):
...but POST requests to my server appear to just hang, and never arrive at the target server.
I'm working on a stripped-down-but-working example of this but thought I'd ask first. Has anyone seen this behavior, or are there good examples of node-http-proxy coexisting with express?
Thanks!
The text was updated successfully, but these errors were encountered: