node-http-proxy icon indicating copy to clipboard operation
node-http-proxy copied to clipboard

Cannot forward Post and PUT request using proxy.web method

Open tamilvjm opened this issue 8 years ago • 9 comments

Cannot forward Post and PUT request using proxy.web method. can you help me how to fix this issue

tamilvjm avatar Feb 21 '17 12:02 tamilvjm

It's not responding while forwarding put request

tamilvjm avatar Feb 22 '17 07:02 tamilvjm

The problem seems like a stream "issue". Are you using something before sending the proxy request?

For example:

http.createServer((req, res) => {
    anyBody(req, res, { limit: process.env.MAX_BODY_SIZE || '2mb' }, (err, body) => {
        req.body = body;
        proxy.web(req, res, { secure: false, proxyTimeout: process.env.TIMEOUT || 8000, xfwd: true, toProxy: true, changeOrigin: true});
    });
}).listen(1234);

That works like a charm for NON BODY requests, like GET, HEAD or DELETE. But POST, for example, has lost its data stream before sending to proxy.web. The upstream server will get the data, but no response will be received.

UPDATE

worked after:

proxy.on('proxyReq', (proxyReq, req) => {
        if (req.body) {
            const 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);
        }
    });

zanaca avatar Feb 27 '17 18:02 zanaca

when I use proxyReq.write(bodyData), it call like this: throw new Error('Can't set headers after they are sent.'); How can I fix it?

clojurie avatar Mar 12 '17 07:03 clojurie

I hit the same bug. @zanaca solution seems to work ;)

oldrich-s avatar Apr 29 '17 12:04 oldrich-s

I have hit the same bug. However, I had to modify @zanaca's solution to get it to work in all the situations that I was encountering:

  proxy.on('proxyReq', (proxyReq, req) => {
    if (req.body && req.complete) {
      const bodyData = JSON.stringify(req.body);
      proxyReq.setHeader('Content-Type', 'application/json');
      proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
      proxyReq.write(bodyData);
    }
  });

Just a head's up if you hit this problem.

danbell avatar Feb 08 '18 21:02 danbell

My target server is Tomcat Server for Java. The page post the JSON data through ajax and I use request.getParameter("data") to get my posted data in Java. And then I try @zanaca ‘s method, but it doesn't work. On Java Server, I tried to output the request inputstream for this post action without http-proxy. I saw the correct output was

data=%7B%22%E8%B4%A7%E5%B8%81%E5%9E%8B%22%3A%7B%22wealth%22%3A10000%2C%22url

And I tried to output the request inputstream for this post action with @zanaca ‘s method. I saw the wrong output was

{"data":"{"璐у竵鍨媆":{"wealth":10000,"url":"r

I can't modify my Java code, so if I want to use the request.getParameter("data") to get the data in Java, I must joint the String for inputstream to match Java's need. So I rewrote the method. Maybe someone need this code for Java back-end server:

proxy.on('proxyReq', function (proxyReq, req, res, options) {
    if (req.body) {
        // var bodyData = encodeURIComponent(JSON.stringify(req.body))
        var postStr = "";
        for(var key in req.body){
            postStr = postStr + encodeURIComponent(key) + "=" + encodeURIComponent(req.body[key]) + "&";
        }
        postStr = postStr.substr(0, postStr.length - 1);
        for(var key in req.headers){
            proxyReq.setHeader(key, req.headers[key])
        }
        // 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(postStr))
        // stream the content
        proxyReq.write(postStr)
    }
})

Because there are non-English language in my post data, So I should use encodeURIComponent() to encode the data.

pek77 avatar May 11 '18 18:05 pek77

It seems that I hit the same bug. I used to http-proxy to build a mock server. and I want to conditional proxy the request based on the req body. It works for the GET method, but it just hangs for the PUT method. My code looks like the following:

let server = http.createServer(function(req, res){
    let body = [];
    req.on('error', (err) => {
      console.error(err);
    }).on('data', (chunk) => {
      body.push(chunk);
    }).on('end', () => {
      body = Buffer.concat(body).toString();
      body = queryString.parse(body);
      if(bodyMeetRequirement(body)){
        console.log('return MockData');
        returnMockData(mockData, res);
      }else{
        proxy.on('error', function (err, req, res){
          console.log('Both Remote Server and MockData are not available');
          res.writeHead(500, {
            'Content-Type': 'text/plain'
          });
          res.end('Both Remote Server and MockData are not available');
        });
      }
      proxy.web(req, res, {target: server_url});
    });
}).listen(server_port);

Can somebody help me, I have been struggling in the problem for like 3 days and could not figure out why.

ghost avatar Jul 19 '18 03:07 ghost

#667 Solved my issue.

ghost avatar Jul 20 '18 02:07 ghost

The problem seems like a stream "issue". Are you using something before sending the proxy request?

For example:

http.createServer((req, res) => {
    anyBody(req, res, { limit: process.env.MAX_BODY_SIZE || '2mb' }, (err, body) => {
        req.body = body;
        proxy.web(req, res, { secure: false, proxyTimeout: process.env.TIMEOUT || 8000, xfwd: true, toProxy: true, changeOrigin: true});
    });
}).listen(1234);

That works like a charm for NON BODY requests, like GET, HEAD or DELETE. But POST, for example, has lost its data stream before sending to proxy.web. The upstream server will get the data, but no response will be received.

UPDATE

worked after:

proxy.on('proxyReq', (proxyReq, req) => {
        if (req.body) {
            const 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);
        }
    });

Thanks @zanaca ! This solution worked for me.

RakeshChouhan avatar Apr 18 '23 17:04 RakeshChouhan