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

app.use(bodyParser.json()) breaks http-proxy-middleware for HTTP POST JSON with express #320

Closed
contractpendev opened this issue Jan 21, 2019 · 9 comments · Fixed by #492

Comments

@contractpendev
Copy link

For a test case of the following

curl -X POST --header 'Content-Type: application/json' --header 'Accept: text/html' -d '{ "$class": "org.accordproject.cicero.contract.AccordContractState", "stateId": "test2" }' 'http://domain/path'

Where http://domain/path uses http-proxy-middleware with express then the introduction of app.use(bodyParser.json()) for express with this http-proxy-middleware, all together the app.use(bodyParser.json()) breaks this.

This is an unexpected surprise and finding this cause of this error was difficult.

@contractpendev
Copy link
Author

Maybe related #126

@repl-chris
Copy link

FYI I worked around this issue like so:

options.onProxyReq = (proxyReq, req: Request, res) => {
  if (!req.body || !Object.keys(req.body).length) {
    return;
  }

  const contentType = proxyReq.getHeader('Content-Type');
  const writeBody = (bodyData: string) => {
    proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
    proxyReq.write(bodyData);
  };

  if (contentType === 'application/json') {
    writeBody(JSON.stringify(req.body));
  }

  if (contentType === 'application/x-www-form-urlencoded') {
    writeBody(querystring.stringify(req.body));
  }
}

@hughfenghen
Copy link

contentType maybe contain chareset (contentType: 'application/json; charset:utf-8').
So, should be change contentType === 'application/json' to contentType.includes('application/json')

FYI I worked around this issue like so:

options.onProxyReq = (proxyReq, req: Request, res) => {
  if (!req.body || !Object.keys(req.body).length) {
    return;
  }

  const contentType = proxyReq.getHeader('Content-Type');
  const writeBody = (bodyData: string) => {
    proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
    proxyReq.write(bodyData);
  };

  if (contentType === 'application/json') {  // contentType.includes('application/json')
    writeBody(JSON.stringify(req.body));
  }

  if (contentType === 'application/x-www-form-urlencoded') {
    writeBody(querystring.stringify(req.body));
  }
}

@miller345
Copy link

I instead excluded the proxied requests from the body parser middleware: https://stackoverflow.com/questions/27117337/exclude-route-from-express-middleware

@stuartZhang
Copy link

@sostenesg7
Copy link

sostenesg7 commented Mar 18, 2020

You just need to reorder the middlewares;
put bodyParser after all proxy middlewares and routes without proxy after bodyParser
ex:

app.use('/proxy/routex', myProxy);
app.use('/proxy/routey', myProxy);

... //then, after all proxys
app.use(bodyParser.json());

//and now, all no proxy routes
app.use('/api', (req,res)=>{
//TODO
});

app.get('/api/test', (req,res)=>{
//TODO
});

sarumont added a commit to sarumont/http-proxy-middleware that referenced this issue Jul 30, 2020
Things like body-parser can break proxying anything with a body. This
checks for that (req.body will become an Object) and streams the body
into the proxy request.

Fixes chimurai#90, chimurai#320, chimurai#417 - and maybe some more
@Florian-Schoenherr
Copy link

Same with polka.
@sostenesg7's solution worked.

@ftntming
Copy link

ftntming commented Nov 6, 2020

FYI I worked around this issue like so:

options.onProxyReq = (proxyReq, req: Request, res) => {
  if (!req.body || !Object.keys(req.body).length) {
    return;
  }

  const contentType = proxyReq.getHeader('Content-Type');
  const writeBody = (bodyData: string) => {
    proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
    proxyReq.write(bodyData);
  };

  if (contentType === 'application/json') {
    writeBody(JSON.stringify(req.body));
  }

  if (contentType === 'application/x-www-form-urlencoded') {
    writeBody(querystring.stringify(req.body));
  }
}

Saved my soul

sarumont added a commit to sarumont/http-proxy-middleware that referenced this issue Jan 12, 2021
Things like body-parser can break proxying anything with a body. This
checks for that (req.body will become an Object) and streams the body
into the proxy request.

Fixes chimurai#90, chimurai#320, chimurai#417 - and maybe some more
@rcollette
Copy link

Just a use case and slight variations on the work around.

I'm using the Okta Middlware for Node library, which requires body parser, but then I want to include the user's access token in proxied api calls, according to the token relay pattern:
https://developer.okta.com/blog/2020/08/14/spring-gateway-patterns

The requires me to implement the aforementioned fix, but I don't see a requirement to define writeBody as a capture so mine looks like:

// From poxy options
onProxyReq: (targetRequest: ClientRequest, clientRequest: Request) => {
    // Headers must be set before doing anything to the body.
    if (clientRequest?.userContext?.tokens?.access_token) {
      targetRequest.setHeader('Authorization', 'Bearer ' + clientRequest.userContext.tokens.access_token);
    }
    fixBody(targetRequest, clientRequest);
}


/**
 * http-proxy-middleware is not compatible with bodyparser and must appear before it without this fix.
 * @see see https://github.com/chimurai/http-proxy-middleware/issues/320
 * @param proxyReq
 * @param req
 */
function fixBody(proxyReq: ClientRequest, req: Request): void {
  if (!req.body || !Object.keys(req.body).length) {
    return;
  }
  const contentType = proxyReq.getHeader('Content-Type') as string;
  if (contentType.includes('application/json')) {
    writeBody(proxyReq, JSON.stringify(req.body));
  }
  if (contentType === 'application/x-www-form-urlencoded') {
    writeBody(proxyReq, querystring.stringify(req.body));
  }
}

function writeBody(proxyReq: ClientRequest, bodyData: string) {
  proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
  proxyReq.write(bodyData);
}

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

Successfully merging a pull request may close this issue.

9 participants