Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reverse proxy client POST & PUT requests using node-http-proxy

I'm trying to use the node-http-proxy as a reverse proxy, but I can't seem to get POST and PUT requests to work. The file server1.js is the reverse proxy (at least for requests with the url "/forward-this") and server2.js is the server that receives the proxied requests. Please explain what I'm doing incorrectly.

Here's the code for server1.js:

// File: server1.js
//

var http = require('http');
var httpProxy = require('http-proxy');

httpProxy.createServer(function (req, res, proxy) {
    if (req.method == 'POST' || req.method == 'PUT') {
        req.body = '';

        req.addListener('data', function(chunk) {
            req.body += chunk;
        });

        req.addListener('end', function() {
            processRequest(req, res, proxy);
        });
    } else {
        processRequest(req, res, proxy);
    }

}).listen(8080);

function processRequest(req, res, proxy) {

    if (req.url == '/forward-this') {
        console.log(req.method + ": " + req.url + "=> I'm going to forward this.");

        proxy.proxyRequest(req, res, {
            host: 'localhost',
            port: 8855
        });
    } else {
        console.log(req.method + ": " + req.url + "=> I'm handling this.");

        res.writeHead(200, { "Content-Type": "text/plain" });
        res.write("Server #1 responding to " + req.method + ": " + req.url + "\n");
        res.end();
    }
}

And here's the code for server2.js:

// File: server2.js
// 

var http = require('http');

http.createServer(function (req, res, proxy) {
    if (req.method == 'POST' || req.method == 'PUT') {
        req.body = '';

        req.addListener('data', function(chunk) {
            req.body += chunk;
        });

        req.addListener('end', function() {
            processRequest(req, res);
        });
    } else {
        processRequest(req, res);
    }

}).listen(8855);

function processRequest(req, res) {
    console.log(req.method + ": " + req.url + "=> I'm handling this.");

    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write("Server #2 responding to " + req.method + ': url=' + req.url + '\n');
    res.end();
}
like image 951
Jason Roberts Avatar asked Feb 27 '13 19:02

Jason Roberts


People also ask

What is reverse proxy with example?

A reverse proxy is a server that sits in front of web servers and forwards client (e.g. web browser) requests to those web servers. Reverse proxies are typically implemented to help increase security, performance, and reliability.

What is the best reverse proxy?

NGINX Plus and NGINX are the best-in-class reverse proxy and load balancing solutions used by high-traffic websites such as Dropbox, Netflix, and Zynga.

Why is it called a reverse proxy?

What is a reverse proxy? As its name implies, a reverse proxy does the exact opposite of what a forward proxy does. While a forward proxy proxies on behalf of clients (or requesting hosts), a reverse proxy proxies on behalf of servers.


3 Answers

http-proxy depends on the data and end events for POST / PUT requests. The latency between the time that server1 receives the request and when it is proxied means that http-proxy misses those events entirely. You have two options here to get this to work correctly - you can buffer the request or you can use a routing proxy instead. The routing proxy seems the most appropriate here since you only need to proxy a subset of requests. Here's the revised server1.js:

// File: server1.js
//

var http = require('http');
var httpProxy = require('http-proxy');
var proxy = new httpProxy.RoutingProxy();

http.createServer(function (req, res) {
    if (req.url == '/forward-this') {
        return proxy.proxyRequest(req, res, {
            host: 'localhost',
            port: 8855
        });
    }

    if (req.method == 'POST' || req.method == 'PUT') {
        req.body = '';

        req.addListener('data', function(chunk) {
            req.body += chunk;
        });

        req.addListener('end', function() {
            processRequest(req, res);
        });
    } else {
        processRequest(req, res);
    }

}).listen(8080);

function processRequest(req, res) {
    console.log(req.method + ": " + req.url + "=> I'm handling this.");

    res.writeHead(200, { "Content-Type": "text/plain" });
    res.write("Server #1 responding to " + req.method + ": " + req.url + "\n");
    res.end();
}
like image 78
squamos Avatar answered Nov 03 '22 01:11

squamos


In addition to @squamos

How to write a node express app that serves most local files, but reroutes some to another domain?

var proxy = new httpProxy.RoutingProxy();

"Above code is working for http-proxy ~0.10.x. Since then lot of things had changed in library. Below you can find example for new version (at time of writing ~1.0.2)"

var proxy = httpProxy.createProxyServer({});
like image 21
Casper Avatar answered Nov 02 '22 23:11

Casper


Here is my solution for proxying POST requests. This isn't the most ideal solution, but it works and is easy to understand.

var request = require('request');

var http = require('http'),
    httpProxy = require('http-proxy'),
    proxy = httpProxy.createProxyServer({});

http.createServer(function(req, res) {
    if (req.method == 'POST') {
        request.post('http://localhost:10500/MyPostRoute',
                     {form: {}},
                     function(err, response, body) {
                         if (! err && res.statusCode == 200) {
                            // Notice I use "res" not "response" for returning response
                            res.writeHead(200, {'Content-Type': "application/json"});
                            res.end(body);
                         }
                         else {
                             res.writeHead(404, {'Content-Type': "application/json"});
                             res.end(JSON.stringify({'Error': err}));
                         }
                     });
    }
    else  if (req.method == 'GET') {
        proxy.web(req, res, { target: 'http://localhost/9000' }, function(err) {
            console.log(err) 
        });
    }

The ports 10500 and 9000 are arbitrary and in my code I dynamically assign them based on the services I host. This doesn't deal with PUT and it might be less efficient because I am creating another response instead of manipulating the current one.

like image 21
NuclearPeon Avatar answered Nov 03 '22 01:11

NuclearPeon