Skip to content
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

POST request body is not proxied to the servers #40

Closed
dejewi opened this issue Dec 7, 2015 · 35 comments
Closed

POST request body is not proxied to the servers #40

dejewi opened this issue Dec 7, 2015 · 35 comments
Labels

Comments

@dejewi
Copy link

dejewi commented Dec 7, 2015

I have in my backend defined:

var proxy = proxyMiddleware('/api', {
        target: 'http://somehost.zero',
        proxyTable: {
            '/api/one': 'http://somehost.one',
            '/api/two': 'http://somehost.two',
        }
    });
app.use(proxy);

and when I'm proxing POST request (lets say to the '/api/one': 'http://somehost.one' ) I don't know why but server http://somehost.one get request without body.

Did you had similar problem?

@chimurai
Copy link
Owner

chimurai commented Dec 7, 2015

I haven't tested the proxyTable option with POST requests yet.

Which version of http-proxy-middleware are you using?
And which server/version do you use? (connect, express or something else?)

Could you provide an example to show this problem?
This will speed up the debugging process.

@dejewi
Copy link
Author

dejewi commented Dec 8, 2015

Hi,
I use:
"express": "~4.0.0",
"http-proxy-middleware": "^0.9.0",

@dejewi
Copy link
Author

dejewi commented Dec 8, 2015

Here is example
https://github.com/dejewi/proxy-bug

@chimurai
Copy link
Owner

chimurai commented Dec 8, 2015

Thanks.

How does your post request (url) look like?

@3goats
Copy link

3goats commented Dec 8, 2015

Hi, I'm seeing this issue too using browsersync.

var proxy = proxyMiddleware('/api', {
  target: 'https://xxx.xxx.xxx.xxx',
  changeOrigin: true,    // for vhosted sites, changes host header to match to target's host
  secure: false
});

My API does not appear to get the body:

POST https://xxx.xxx.xxx.xxx/api/authorize/ 415 (Unsupported Media Type)

@dejewi
Copy link
Author

dejewi commented Dec 9, 2015

@chimurai it looks like:
POST http://my.app.host:2000/api/operation/zero/minus/something/else
or
POST http://my.app.host:2000/api/one/something

and in both cases data which I'm sending is:
{something: 'one', else: 'two'}

@3goats
Copy link

3goats commented Dec 9, 2015

Sorry - do you mean this works for you or am I doing something wrong with my post request ?

@chimurai
Copy link
Owner

chimurai commented Dec 9, 2015

Did a little test and I am able to receive POST data at the target server.

I noticed you are using the body-parser middleware:
https://github.com/dejewi/proxy-bug/blob/master/app.js#L16

You might want to change to order of the middlwares you are using.
Try moving the http-proxy-middleware above the body-parser

source: http://stackoverflow.com/a/25651651/3841188

Hope this solves the issue.

@dejewi dejewi closed this as completed Dec 10, 2015
@dejewi
Copy link
Author

dejewi commented Dec 10, 2015

Yes, this solved my problem. Thank you very much for your help.

@yousefamar
Copy link

yousefamar commented Sep 14, 2016

Apologies for resurrecting this, but anybody aware of another way to avoid this issue when you can't change the order of middleware (e.g. if you're adding proxies at runtime)?

@IrynaBu
Copy link

IrynaBu commented Sep 19, 2016

The same question :)

@jgf5013
Copy link

jgf5013 commented Sep 25, 2016

I'm having this same (or a very similar) problem when using browser-sync with http-proxy-middleware. The middleware is moving my POST request to a GET request using x-www-form-urlencoded, which is being rejected by the server.

@chimurai
Copy link
Owner

chimurai commented Sep 25, 2016

If you can't change the order of the middleware; You can restream the parsed body before proxying the request. This should fix the POST request:

// restream parsed body before proxying
var restream = 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);
    }
}

var apiProxy = proxyMiddleware('/api', {
    target: 'https://xxx.xxx.xxx.xxx',
    onProxyReq: restream
});


var app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(apiProxy);                // with restreaming

source: node-http-proxy/examples/middleware/bodyDecoder-middleware.js. (http-party/node-http-proxy#1027)

@joshparolin
Copy link

Spent a few hours trying to debug this same issue while setting up multiple proxies. The request would hang at the target. Moving proxyMiddleware above bodyParser solved my problem as well. Thank you!

@piyushbeli
Copy link

For my purpose, I was able to make this work by changing the order i.e. putting body-parser after proxy-middleware..
Thanks.

@jeffvandyke
Copy link

jeffvandyke commented Jun 1, 2017

GRRR! Hi :) I arrived here from trying to figure out why webpack-dev-server was proxying a POST request and dropping the json body content somewhere on its way to the server. @chimurai 's fix ended up working, but I wasn't even using bodyParser to start with. Are there any webpack-dev-server gurus that know any simpler solution than:

1. npm install --save body-parser
2. adding in webpack.config.js: devServer.setup = function (app) { app.use(require('body-parser').json()); }
3. adding devServer.proxy["/url/to/proxy"].onProxyReq = /*the function @chimurai so generously provided
4. making sure that the request (which uses fetch) adds the Content-Type: application/json header to the options

which all works, again, finally, but is there any easier way? I'm worried about others who might have to spend a lot of time tracking down that issue.

@jeffvandyke
Copy link

It seems to work now with Webpack 3.6.0 - I tried removing my fix after I had an issue trying to post JSON.stringify(true), and the proxy no longer chokes on the json body, no matter the shape!

@jamesjtong
Copy link

I ran into a similar issue where the proxied post parameters weren't being included. The issue was that the request headers didn't specify application/json.

  Accept: "application/json",
  "Content-Type": "application/json",
};

It is strange that isn't any error being specified or logged and that the post body is just ignored.

@chping2125
Copy link

@chimurai why ? This solved my problem ,but why body-parser middleware is causing the problem.

@aryeharmon
Copy link

@chimurai becuase it changes the req.body property

@edmundo096
Copy link

edmundo096 commented Apr 14, 2018

@chping2125 Not sure about @aryeharmon answer, but as I understand, the request body data is a node stream (if you remember express tutorials, the req object inherits from a node's stream), which bodyparser pipes (and this thus "empties") out the data from the request stream.

See this here https://github.com/expressjs/body-parser/blob/master/lib/read.js#L162

That is why chimurai said on his post (#40 (comment)) that his middleware patch "restreams" the body data, not to the original req stream (since is a "read only "ReadableStream") but into the proxy middleware's request stream (like if bodyparser never emptied out the request data body).

This kind of transforms the data 2 times, but its an example solution that he proposed (and doesn't handles if was parsed from application/x-www-form-urlencoded).

Hope it's clearer now.

@cloudhary
Copy link

Using @chimurai's method above to restream code, I'm hitting an error saying that I cannot set the headers because they have been sent to client already. Any idea why?

_http_outgoing.js:503 throw new errors.Error('ERR_HTTP_HEADERS_SENT', 'set'); ^ Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at validateHeader (_http_outgoing.js:503:11) at ClientRequest.setHeader (_http_outgoing.js:510:3) at ProxyServer.restream (/usr/src/app/node/routes.js:103:20) at ProxyServer.emit (/usr/src/app/node_modules/eventemitter3/index.js:184:35) at ClientRequest. (/usr/src/app/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:132:27) at ClientRequest.emit (events.js:185:15) at tickOnSocket (_http_client.js:649:7) at onSocketNT (_http_client.js:665:5) at process._tickCallback (internal/process/next_tick.js:178:19)

For now, I'm going to find a way to use bodyParser only on the specific routes which don't use http-proxy-middleware. Thanks!

@christiaanwesterbeek
Copy link

christiaanwesterbeek commented Sep 4, 2019

Here #40 (comment)

I just spend 2 days ripping out my hair

And here #177 (comment)

I just spent three days trying to figure out why my proxy was hanging, until I stumbled upon this issue.

And here #150 (comment)

OMFG I have been trying to make this work for 2 days and that totally did it

And I just lost a few hours as well.

Just underscoring that if you see your GET requests being proxied just fine, but your POST requests seem to hang and not being proxied, this issue is providing solutions.

joshuatz added a commit to joshuatz/gcp-proxy-func that referenced this issue Dec 3, 2019
 * http-proxy-middleware was not passing the POST body along - it was being dropped
 * There are lots of threads on this, but the most helpful was here:
chimurai/http-proxy-middleware#40 (comment)
 * Followed advice and recipe
(https://github.com/http-party/node-http-proxy/blob/master/examples/middleware/bodyDecoder-middleware.js) to parse body and
then re-stream in request
 * Tested and working with POST and even application/x-www-form-urlencoded
tkottke90 added a commit to tkottke90/server-manager-v2 that referenced this issue Mar 7, 2020
The body parser was manipulating the request in transit which caused
POST reqests with json to hang and never reach the server

See this issue in http-proxy-middleware's github:
chimurai/http-proxy-middleware#40
@gryslik
Copy link

gryslik commented Jul 27, 2021

Hi all,

If anyone is still looking at this, this worked for me too. For those new to express/node, if you use the express generator the proxyMiddleware must be before the chunk below:

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

I got it working by putting it directly after the app.set commands and before the app.use(logger('dev)) command.

@cawoodm
Copy link

cawoodm commented Sep 19, 2022

If I remove body-parser middleware then req.body is always undefined and restream fails because it has nothing to parse.

@AmosSpark
Copy link

Here #40 (comment)

I just spend 2 days ripping out my hair

And here #177 (comment)

I just spent three days trying to figure out why my proxy was hanging, until I stumbled upon this issue.

And here #150 (comment)

OMFG I have been trying to make this work for 2 days and that totally did it

And I just lost a few hours as well.

Just underscoring that if you see you're GET requests being proxied just fine, but your POST requests seem to hang and not being proxied, this issue is providing solutions.

Thank you

@RichWK
Copy link

RichWK commented Jan 19, 2023

If you can't change the order of the middleware; You can restream the parsed body before proxying the request. This should fix the POST request:

6+ years later and this is still a lifesaver. Thank you!!

@ToshKoevoets
Copy link

ToshKoevoets commented Feb 4, 2023

If you really cant rewrite the order, you can rebuild back the body, mind you this is in JSON format.


onProxyReq : (proxyReq, req, res) => {
        if ((req.method == "POST" ||req.method == "PUT")  && req.body) {
           let body = req.body;
           let newBody = '';
           delete req.body;

           try {
             newBody = JSON.stringify(body);
             proxyReq.setHeader( 'content-length', Buffer.byteLength(newBody, 'utf8'));
             proxyReq.write( newBody );
             proxyReq.end();
           } catch (e) {
             console.log('Stringify err', e)
           }
         }
     },
}

@chimurai chimurai mentioned this issue Feb 8, 2023
2 tasks
@chimurai chimurai mentioned this issue May 9, 2023
2 tasks
deshmukhmayur added a commit to deshmukhmayur/apikey-auth-proxy that referenced this issue May 24, 2023
Moved the body-parser middleware below the http-proxy-middleware
A known issue causes unexpected behaviour if the `bodyparser` is loaded
before `http-proxy-middleware`.
Ref: chimurai/http-proxy-middleware#40 (comment)
deshmukhmayur added a commit to deshmukhmayur/apikey-auth-proxy that referenced this issue May 24, 2023
Moved the body-parser middleware below the http-proxy-middleware
A known issue causes unexpected behaviour if the `bodyparser` is loaded
before `http-proxy-middleware`.
Ref: chimurai/http-proxy-middleware#40 (comment)
deshmukhmayur added a commit to deshmukhmayur/apikey-auth-proxy that referenced this issue May 24, 2023
Moved the body-parser middleware below the http-proxy-middleware
A known issue causes unexpected behaviour if the `bodyparser` is loaded
before `http-proxy-middleware`.
Ref: chimurai/http-proxy-middleware#40 (comment)
@tverilytt
Copy link

If you can't change the order of the middleware; You can restream the parsed body before proxying the request. This should fix the POST request:

6+ years later and this is still a lifesaver. Thank you!!

Still is for sure 😎

@hengkydev
Copy link

in version 3 you can just doing something like this,
is from official documentation, without moving the body parser middleware

const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * Fix bodyParser
   **/
  on: {
    proxyReq: fixRequestBody,
  },
});

@Prakhar301101
Copy link

Prakhar301101 commented Sep 1, 2024

in version 3 you can just doing something like this, is from official documentation, without moving the body parser middleware

const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * Fix bodyParser
   **/
  on: {
    proxyReq: fixRequestBody,
  },
});

was struggling with the POST request part since the last few days
thanks @hengkydev for this fix

@SantoshKumarRavi
Copy link

in version 3 you can just doing something like this,
is from official documentation, without moving the body parser middleware

const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * Fix bodyParser
   **/
  on: {
    proxyReq: fixRequestBody,
  },
});

Thanks for sharing

@tverilytt
Copy link

I ran into this issue with request body urlencoded form data (and header Content-Type application/x-www-form-urlencoded).
I use the fixRequestBody, and "use" http-proxy-middleware before express.urlencoded.

The origin protocol is HTTPS, and target HTTP, so I thought that might be the reason.

I changed the request body to JSON (and header Content-Type application/json), and use express.json(), then the body was passed on to the target :-)

So maybe request body type JSON is to prefer, if possible... :-)

Cheers
-jo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests