admin管理员组

文章数量:1134576

I'm trying to create a proxy server to pass HTTP GET requests from a client to a third party website (say google). My proxy just needs to mirror incoming requests to their corresponding path on the target site, so if my client's requested url is:

127.0.0.1/images/srpr/logo11w.png

The following resource should be served:

.png

Here is what I came up with:

http.createServer(onRequest).listen(80);

function onRequest (client_req, client_res) {
    client_req.addListener("end", function() {
        var options = {
            hostname: 'www.google',
            port: 80,
            path: client_req.url,
            method: client_req.method
            headers: client_req.headers
        };
        var req=http.request(options, function(res) {
            var body;
            res.on('data', function (chunk) {
                body += chunk;
            });
            res.on('end', function () {
                 client_res.writeHead(res.statusCode, res.headers);
                 client_res.end(body);
            });
        });
        req.end();
    });
}

It works well with html pages, but for other types of files, it just returns a blank page or some error message from target site (which varies in different sites).

I'm trying to create a proxy server to pass HTTP GET requests from a client to a third party website (say google). My proxy just needs to mirror incoming requests to their corresponding path on the target site, so if my client's requested url is:

127.0.0.1/images/srpr/logo11w.png

The following resource should be served:

http://www.google.com/images/srpr/logo11w.png

Here is what I came up with:

http.createServer(onRequest).listen(80);

function onRequest (client_req, client_res) {
    client_req.addListener("end", function() {
        var options = {
            hostname: 'www.google.com',
            port: 80,
            path: client_req.url,
            method: client_req.method
            headers: client_req.headers
        };
        var req=http.request(options, function(res) {
            var body;
            res.on('data', function (chunk) {
                body += chunk;
            });
            res.on('end', function () {
                 client_res.writeHead(res.statusCode, res.headers);
                 client_res.end(body);
            });
        });
        req.end();
    });
}

It works well with html pages, but for other types of files, it just returns a blank page or some error message from target site (which varies in different sites).

Share Improve this question edited Jun 3, 2020 at 20:27 Tarick Welling 3,2554 gold badges20 silver badges46 bronze badges asked Dec 3, 2013 at 12:47 Nasser TorabzadeNasser Torabzade 6,7008 gold badges29 silver badges36 bronze badges 1
  • 1 Even though the answer uses http, an order of related modules from low to high abstraction are: node, http, connect, express taken from stackoverflow.com/questions/6040012/… – neaumusic Commented Aug 8, 2016 at 0:08
Add a comment  | 

8 Answers 8

Reset to default 142

I don't think it's a good idea to process response received from the 3rd party server. This will only increase your proxy server's memory footprint. Further, it's the reason why your code is not working.

Instead try passing the response through to the client. Consider following snippet:

var http = require('http');

http.createServer(onRequest).listen(3000);

function onRequest(client_req, client_res) {
  console.log('serve: ' + client_req.url);

  var options = {
    hostname: 'www.google.com',
    port: 80,
    path: client_req.url,
    method: client_req.method,
    headers: client_req.headers
  };

  var proxy = http.request(options, function (res) {
    client_res.writeHead(res.statusCode, res.headers)
    res.pipe(client_res, {
      end: true
    });
  });

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

Here's an implementation using node-http-proxy from nodejitsu.

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

http.createServer(function(req, res) {
    proxy.web(req, res, { target: 'http://www.google.com' });
}).listen(3000);

Here's a more optimized version of Mike's answer above that gets the websites Content-Type properly, supports POST and GET request, and uses your browsers User-Agent so websites can identify your proxy as a browser. You can just simply set the URL by changing url = and it will automatically set HTTP and HTTPS stuff without manually doing it.

/* eslint-disable @typescript-eslint/no-var-requires */
// https://stackoverflow.com/a/63602976/470749
const express = require('express');

const app = express();
const https = require('https');
const http = require('http');
// const { response } = require('express');

const targetUrl = process.env.TARGET_URL || 'https://jsonplaceholder.typicode.com'; // Run localtunnel like `lt -s rscraper -p 8080 --print-requests`; then visit https://yourname.loca.lt/todos/1 .

const proxyServerPort = process.env.PROXY_SERVER_PORT || 8080;

// eslint-disable-next-line max-lines-per-function
app.use('/', function (clientRequest, clientResponse) {
  const parsedHost = targetUrl.split('/').splice(2).splice(0, 1).join('/');
  let parsedPort;
  let parsedSSL;
  if (targetUrl.startsWith('https://')) {
    parsedPort = 443;
    parsedSSL = https;
  } else if (targetUrl.startsWith('http://')) {
    parsedPort = 80;
    parsedSSL = http;
  }
  const options = {
    hostname: parsedHost,
    port: parsedPort,
    path: clientRequest.url,
    method: clientRequest.method,
    headers: {
      'User-Agent': clientRequest.headers['user-agent'],
    },
  };

  const serverRequest = parsedSSL.request(options, function (serverResponse) {
    let body = '';
    if (String(serverResponse.headers['content-type']).indexOf('text/html') !== -1) {
      serverResponse.on('data', function (chunk) {
        body += chunk;
      });

      serverResponse.on('end', function () {
        // Make changes to HTML files when they're done being read.
        // body = body.replace(`example`, `Cat!`);

        clientResponse.writeHead(serverResponse.statusCode, serverResponse.headers);
        clientResponse.end(body);
      });
    } else {
      serverResponse.pipe(clientResponse, {
        end: true,
      });
      clientResponse.contentType(serverResponse.headers['content-type']);
    }
  });

  serverRequest.end();
});

app.listen(proxyServerPort);
console.log(`Proxy server listening on port ${proxyServerPort}`);

Here's a proxy server using request that handles redirects. Use it by hitting your proxy URL http://domain.com:3000/?url=[your_url]

var http = require('http');
var url = require('url');
var request = require('request');

http.createServer(onRequest).listen(3000);

function onRequest(req, res) {

    var queryData = url.parse(req.url, true).query;
    if (queryData.url) {
        request({
            url: queryData.url
        }).on('error', function(e) {
            res.end(e);
        }).pipe(res);
    }
    else {
        res.end("no url found");
    }
}

Super simple and readable, here's how you create a local proxy server to a local HTTP server with just Node.js (tested on v8.1.0). I've found it particular useful for integration testing so here's my share:

/**
 * Once this is running open your browser and hit http://localhost
 * You'll see that the request hits the proxy and you get the HTML back
 */

'use strict';

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

const PROXY_PORT = 80;
const HTTP_SERVER_PORT = 8080;

let proxy = net.createServer(socket => {
    socket.on('data', message => {
        console.log('---PROXY- got message', message.toString());

        let serviceSocket = new net.Socket();

        serviceSocket.connect(HTTP_SERVER_PORT, 'localhost', () => {
            console.log('---PROXY- Sending message to server');
            serviceSocket.write(message);
        });

        serviceSocket.on('data', data => {
            console.log('---PROXY- Receiving message from server', data.toString();
            socket.write(data);
        });
    });
});

let httpServer = http.createServer((req, res) => {
    switch (req.url) {
        case '/':
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end('<html><body><p>Ciao!</p></body></html>');
            break;
        default:
            res.writeHead(404, {'Content-Type': 'text/plain'});
            res.end('404 Not Found');
    }
});

proxy.listen(PROXY_PORT);
httpServer.listen(HTTP_SERVER_PORT);

https://gist.github.com/fracasula/d15ae925835c636a5672311ef584b999

Your code doesn't work for binary files because they can't be cast to strings in the data event handler. If you need to manipulate binary files you'll need to use a buffer. Sorry, I do not have an example of using a buffer because in my case I needed to manipulate HTML files. I just check the content type and then for text/html files update them as needed:

app.get('/*', function(clientRequest, clientResponse) {
  var options = { 
    hostname: 'google.com',
    port: 80, 
    path: clientRequest.url,
    method: 'GET'
  };  

  var googleRequest = http.request(options, function(googleResponse) { 
    var body = ''; 

    if (String(googleResponse.headers['content-type']).indexOf('text/html') !== -1) {
      googleResponse.on('data', function(chunk) {
        body += chunk;
      }); 

      googleResponse.on('end', function() {
        // Make changes to HTML files when they're done being read.
        body = body.replace(/google.com/gi, host + ':' + port);
        body = body.replace(
          /<\/body>/, 
          '<script src="http://localhost:3000/new-script.js" type="text/javascript"></script></body>'
        );

        clientResponse.writeHead(googleResponse.statusCode, googleResponse.headers);
        clientResponse.end(body);
      }); 
    }   
    else {
      googleResponse.pipe(clientResponse, {
        end: true
      }); 
    }   
  }); 

  googleRequest.end();
});    

I juste wrote a proxy in nodejs that take care of HTTPS with optional decoding of the message. This proxy also can add proxy-authentification header in order to go through a corporate proxy. You need to give as argument the url to find the proxy.pac file in order to configurate the usage of corporate proxy.

https://github.com/luckyrantanplan/proxy-to-proxy-https

here is one that I made:

var http = require("http")
var Unblocker = require("unblocker")
var unblocker = Unblocker({})
http.createServer(function(req,res){
  unblocker(req,res,function(err){
    var headers = {"content-type": "text/html"}
    if(err){
      res.writeHead(500, headers)
      return res.end(err.stack || err)
    }
    if(req.url == "/"){
      res.writeHead(200, headers)
      return res.end(
        `
        <title>Seventh Grade by Gary Soto</title>
        <embed src="https://www.cforks.org/Downloads/7.pdf" width="1500" height="1500"/>
        `
      )
    }else{
      res.writeHead(404, headers)
      return res.end("ERROR 404: File Not Found.");
    }
  })
})
.listen(8080)

demo: view the demo:

本文标签: javascriptHow to create a simple http proxy in nodejsStack Overflow