B4RL1V3
B4RL1V3

Reputation: 51

Make a Node js proxy with multiple targets depending on the body of the request

I need to make a Node js proxy server which depending on the content in the body will redirect to one server or another.

Example: I send a request to the server 127.0.0.1:8080 with the data {"tag": "server_1"}. This server will read the data and if the tag is "server_1" then it sends the request to the server 127.0.0.1:8081 otherwise the request goes to the 127.0.0.1:8082.

I started to make a proxy but I cannot modify the hostname, the port and the protocol according to the received data.

Here is my code:

const http = require('http');
const https = require('https');

const proxyHostname = '0.0.0.0';
const proxyPort = 8080;

const primaryServerProtocol = "http";
const primaryServerHostname = "127.0.0.1";
const primaryServerPort = 8081;

const secondaryServerProtocol = "https";
const secondaryServerHostname = "127.0.0.1";
const secondaryServerPort = 8082;

const proxyServer = http.createServer((clientRequest, clientResponse) => {
    const serverRequestOptions = {
        hostname: primaryServerHostname,
        port: primaryServerPort,
        path: clientRequest.url,
        method: clientRequest.method,
        headers: clientRequest.headers,
        rejectUnauthorized: false
    }
    
    /***********************
    let data = [];
    clientRequest.on('data', function (chunk) {
        data.push(chunk);
    });

    clientRequest.on('end', function () {
        data = Buffer.concat(data).toString();

        if (data.includes("server_2")) {
            // Set options...
        }
    });
    ***********************/

    const proxy = https.request(serverRequestOptions, (serverResponse) => {
        clientResponse.writeHead(serverResponse.statusCode, serverResponse.headers);
        serverResponse.pipe(clientResponse, {
            end: true
        });
    });

    clientRequest.pipe(proxy, {
        end: true
    });
});

proxyServer.listen(proxyPort, proxyHostname, () => {
    console.log(`Server running at http://${proxyHostname}:${proxyPort}`);
});

I also tried with http-proxy but I have a preference for the vanilla solution but I don't really understand how the pipes work for my case.

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

const proxyHostname = '0.0.0.0';
const proxyPort = 8080;

const primaryServerProtocol = "http:";
const primaryServerHostname = "127.0.0.1";
const primaryServerPort = 8081;

const secondaryServerProtocol = "https:";
const secondaryServerHostname = "127.0.0.1";
const secondaryServerPort = 8082;

const options = {
    target: {
        protocol: primaryServerProtocol,
        host: primaryServerHostname,
        port: primaryServerPort,
    },
    secure: false
};

const proxy = httpProxy.createProxyServer();

const proxyServer = http.createServer((req, res) => {
    proxy.web(req, res, options);
});

/***********************
proxy.on('proxyReq', (proxyReq, req) => {
    let data = '';

    req.on('data', chunk => {
        data += chunk;
    });

    req.on('end', () => {
        if (data.includes("server_2")) {
            // Set options...
        }
    });
});
***********************/

proxyServer.listen(proxyPort, proxyHostname, () => {
    console.log(`Server running at http://${proxyHostname}:${proxyPort}`);
});

This code works but sends to the correct server with a delay request ... Do you have an idea or a solution?

Upvotes: 3

Views: 1652

Answers (1)

B4RL1V3
B4RL1V3

Reputation: 51

I post my solution for those who might be interested :

const http = require('http');
const https = require('https');

const proxyHostname = '0.0.0.0';
const proxyPort = 8080;

const primaryServerHostname = "127.0.0.1";
const primaryServerPort = 8081;

const secondaryServerHostname = "127.0.0.1";
const secondaryServerPort = 8082;

const proxyServer = http.createServer((clientRequest, clientResponse) => {
    const serverRequestOptions = {
        path: clientRequest.url,
        method: clientRequest.method,
        headers: clientRequest.headers,
        rejectUnauthorized: false
    }

    let requestBody = [];
    clientRequest.on('data', (chunk) => {
        requestBody.push(chunk);
    });

    clientRequest.on('end', () => {
        requestBody = Buffer.concat(requestBody).toString();

        if (requestBody.includes("server_2")) {
            serverRequestOptions.hostname = secondaryServerHostname;
            serverRequestOptions.port = secondaryServerPort;
        } else {
            serverRequestOptions.hostname = primaryServerHostname;
            serverRequestOptions.port = primaryServerPort;
        }

        const proxy = https.request(serverRequestOptions, (serverResponse) => {
            clientResponse.writeHead(serverResponse.statusCode, serverResponse.headers);
            serverResponse.pipe(clientResponse);
        });

        proxy.on('error', (err) => {
            console.error(err);
            clientResponse.statusCode = 500;
            clientResponse.end(err.message);
        });
    
        proxy.write(requestBody);
        proxy.end();
    });

    clientRequest.on('error', (err) => {
        console.error(err);
        clientResponse.statusCode = 400;
        clientResponse.end(err.message);
    });
    
    clientResponse.on('error', (err) => {
        console.error(err);
        clientResponse.end(err.message);
    });
});

proxyServer.listen(proxyPort, proxyHostname, () => {
    console.log(`Server running at http://${proxyHostname}:${proxyPort}`);
});

Upvotes: 2

Related Questions