Search code examples
node.jsnode-http-proxy

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();
}

Solution

  • 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();
    }