http-party / node-http-proxy

A full-featured http proxy for node.js
https://github.com/http-party/node-http-proxy
Other
13.91k stars 1.97k forks source link

node-http-proxy XHR post call hanging #843

Open elankeeran opened 9 years ago

elankeeran commented 9 years ago

Create a simple express app and try to do proxy.

Proxy working fine when request is GET but it getting hang on post XHR call

var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var httpProxy = require('http-proxy');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
var apiProxy = httpProxy.createProxyServer();
app.use(function(req, res,next){
    apiProxy.web(req, res, { target: 'http://localhost:9000' } );

});
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

module.exports = app;

Googled and got this solution https://github.com/nodejitsu/node-http-proxy/issues/180

var restreamer = function (){
        return function (req, res, next) { //restreame
            req.removeAllListeners('data')
            req.removeAllListeners('end')
            next()
            process.nextTick(function () {
                if(req.body) {
                    req.emit('data', JSON.stringify(req.body))
                }
                req.emit('end')
            })
        }
    }

    app.use(restreamer());

but now application not hanging. I am getting response 404 not found. and getting below error

/Volumes/Data/nodejs/express-apps/myapp/node_modules/http-proxy/lib/http-proxy/index.js:119
    throw err;
          ^
Error: socket hang up
    at createHangUpError (_http_client.js:215:15)
    at Socket.socketOnEnd (_http_client.js:300:23)
    at Socket.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)
yhojann-cl commented 9 years ago

Same problem with reverse proxy and jQuery ajax post call:

/home/whk/demo/node/node_modules/http-proxy/lib/http-proxy/index.js:119 throw err; ^ Error: socket hang up at createHangUpError (http.js:1473:15) at Socket.socketCloseListener (http.js:1523:23) at Socket.emit (events.js:95:17) at TCP.close (net.js:466:12)

Talk this: http://stackoverflow.com/questions/18692580/node-js-post-causes-error-socket-hang-up-code-econnreset#answer-18693340

prashantbaid commented 9 years ago

I tried this solution. Content-Length is already correctly set in request object. In the above code, the request object is coming from the browser, so it should directly go to http-proxy and get the response.

yhojann-cl commented 9 years ago

it can work but it's a bug.

jcrugzz commented 9 years ago

I would try and not parse the body when proxying a request. Errors are also not being handled so you cannot gracefully respond to the client when the remote server you are proxying to is down or something happens when communicating with said remote server.

yhojann-cl commented 9 years ago

Crash in:

POST /test/?id=42 HTTP/1.1 Host: facilmed.cl User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x8664; rv:38.0) Gecko/20100101 Firefox/38.0 Accept: application/json, text/javascript, /_; q=0.01 Accept-Language: es-CL,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: http://.../?id=42 Content-Length: 107 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache

do=calendarioMes&datetime=2015-06-01+00%3A00%3A00&profesionalId=268188&user-token=xxx&type=json

tarkeshwars commented 9 years ago

I was trying to use it for a specific endpoint instead of a middleware but that didn't work. it doesn't even throw an error, just says can't get/*\ and fails. Am I doing something wrong or there's an issue with express compatibility?

Here's my code for the reference:

var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var httpProxy = require('http-proxy');
var app = express();

app.set('subdomain offset', 1); 
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
var apiProxy = httpProxy.createProxyServer();

app.get('/',function(req,res){
  res.sendStatus(200)
})

app.get("/proxy/*", function(req, res){
  apiProxy.web(req, res, { target: 'http://www.fundamine.com' } );
});

var port = process.env.PORT || 3000;
app.listen(port);  
module.exports = app;
prashantbaid commented 9 years ago

body-parser middleware is causing the problem. If you remove it, then it will work. This is just a hack, we need to find a solution to this problem.

tarkeshwars commented 9 years ago

Hey @prashantbaid! I tried what you suggested. Removed both the body-parser and cookie-parser. It still doesn't work. It still fails without any error. Any idea why? Here's the exact code that I'm using:

 var express = require('express');
 var path = require('path');
 var logger = require('morgan');
 var httpProxy = require('http-proxy');
 var app = express();

 app.set('subdomain offset', 1); 

 var apiProxy = httpProxy.createProxyServer();

 app.get('/',function(req,res){
  res.sendStatus(200)
 })

 app.get("/proxy/*", function(req, res){
    apiProxy.web(req, res, { 
        target: 'http://www.fundamine.com',
        changeOrigin:true        // if absent the proxy request fails without an explicit error
     } );
 });

 var port = process.env.PORT || 3000;
 app.listen(port);  
 module.exports = app;
tarkeshwars commented 9 years ago

Got it to work. For others facing the same issue, the 'changeOrigin' option must be set to true. And @prashantbaid was right about the body-parser. On adding it, http-proxy doesn't work.