Node-http-proxy: No way to grab POST body before sending request?

Created on 7 Jul 2014  路  11Comments  路  Source: http-party/node-http-proxy

Hi all, I need to generate a signature based on the POST body. If I put the proxy.web on the request end method it simply does not work. Has anyone accomplished reading the POST body?

Most helpful comment

@seglo I tried the buffer option suggested by @jcrugzz and it works like a charm. Idea is to retrieve the body by consuming the request stream, and to store the buffered result on a stream that we will pass to the buffer property when calling proxy.web().

Example here, first with a middleware to retrieve the body (you will recognize part of your code as I work with connect-prism):

var app = connect()
  .use(function (req, res, next) {
    var buffer = '';
    req.on('data', function(data) {
      buffer += data;

      // Too much POST data, kill the connection!
      if (buffer.length > 1e6) {
        req.connection.destroy();
      }
    });

    req.on('end', function() {
      req.body = buffer;

      //Here we create a new stream with the buffered body on it
      var bufferStream = new stream.PassThrough();
      bufferStream.end(new Buffer(buffer));
      req.bodyStream = bufferStream;

      next();
    });

Then, when calling the proxy, just pass this stream:

proxy.web(req, res, {buffer: req.bodyStream});

All 11 comments

I have the same issue. In fact, when trying to grab any data off the body (for example, Basic Authorization), you can't use the node paradigm of on('data') followed by on('end', function() { proxy.web(req, res) }.

I have the same problem. No way to grab POST body.

In order for this to work, you need to buffer the entire request BEFORE proxying it. We don't support this innately in the API because everything is supposed to be streaming and happen ASAP. There is a buffer option in the proxy.web(req, res, { buffer: bufferStream}) that should allow you to do this. There needs to be some better modules around this interaction. I will be trying to figure something out around this when I have some time but let me know how the testing goes!

@jcrugzz Can you elaborate on how you can use the buffer stream to accomplish the task of grabbing the POST body in the response?

@seglo let me try and put together a working example today.

@jcrugzz As you've probably noticed my project relies on this sort of functionality. Right now it's a bit of a hack, so if you could share an example of how this might work it would be appreciated. Thanks!

I was able to use bodyParser in combination with restreamer to access the body. Here is an example authored by someone else:

https://github.com/nodejitsu/node-http-proxy/blob/master/examples/middleware/bodyDecoder-middleware.js

Thanks for pointing everyone to the correct existing example @gdw2. I'm going to close this issue.

@seglo I tried the buffer option suggested by @jcrugzz and it works like a charm. Idea is to retrieve the body by consuming the request stream, and to store the buffered result on a stream that we will pass to the buffer property when calling proxy.web().

Example here, first with a middleware to retrieve the body (you will recognize part of your code as I work with connect-prism):

var app = connect()
  .use(function (req, res, next) {
    var buffer = '';
    req.on('data', function(data) {
      buffer += data;

      // Too much POST data, kill the connection!
      if (buffer.length > 1e6) {
        req.connection.destroy();
      }
    });

    req.on('end', function() {
      req.body = buffer;

      //Here we create a new stream with the buffered body on it
      var bufferStream = new stream.PassThrough();
      bufferStream.end(new Buffer(buffer));
      req.bodyStream = bufferStream;

      next();
    });

Then, when calling the proxy, just pass this stream:

proxy.web(req, res, {buffer: req.bodyStream});

I was in a similar situation where I need to load response. Hope it helps: http://www.acuriousanimal.com/2015/08/31/how-to-read-from-a-writable-stream-httpserverresponse-in-node.html

After some searching, and combining information from several posts, the following works for me:

const httpProxy = require('http-proxy')
const proxy = httpProxy.createProxyServer({
  target: {
    protocol: 'https:',
    host: [domain name],
    port: 443
  },
  changeOrigin: true
})

app.use((req, res, next) => {
  if (req.url.search([Regular Expression]) >= 0) {
    return proxy.web(req, res)
  } else {
    ...
  }
})

//Assuming content type of 'application/x-www-form-urlencoded'
proxy.on('proxyReq', function (proxyReq, req, res, options) {
  if (req.body) {
    var bodyData = Object.keys(req.body)
      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(req.body[key])}`)
      .join('&')

    proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData))
    proxyReq.write(bodyData)
  }
})

I hope this helps someone, I spent several hours attempting to resolve POST requests failing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sisyphsu picture sisyphsu  路  3Comments

isawk picture isawk  路  5Comments

tbc1 picture tbc1  路  4Comments

guillaume-at-palo picture guillaume-at-palo  路  4Comments

DominicTobias picture DominicTobias  路  3Comments