Cách tạo proxy http đơn giản trong node.js?


82

Tôi đang cố gắng tạo một máy chủ proxy để chuyển HTTP GETcác yêu cầu từ máy khách đến trang web của bên thứ ba (giả sử google). Proxy của tôi chỉ cần phản chiếu các yêu cầu đến với đường dẫn tương ứng của chúng trên trang web đích, vì vậy nếu url được yêu cầu của khách hàng của tôi là:

127.0.0.1/images/srpr/logo11w.png

Tài nguyên sau sẽ được cung cấp:

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

Đây là những gì tôi nghĩ ra:

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

Nó hoạt động tốt với các trang html, nhưng đối với các loại tệp khác, nó chỉ trả về một trang trống hoặc một số thông báo lỗi từ trang web đích (thay đổi ở các trang web khác nhau).


1
Mặc dù việc sử dụng câu trả lời http, một trật tự các module liên quan từ thấp đến trừu tượng cao là: node, http, connect, expresslấy từ stackoverflow.com/questions/6040012/...
neaumusic

Câu trả lời:


102

Tôi không nghĩ rằng nên xử lý phản hồi nhận được từ máy chủ của bên thứ ba. Điều này sẽ chỉ làm tăng dung lượng bộ nhớ của máy chủ proxy của bạn. Hơn nữa, đó là lý do tại sao mã của bạn không hoạt động.

Thay vào đó, hãy thử chuyển phản hồi cho khách hàng. Hãy xem xét đoạn mã sau:

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

1
cảm ơn, nhưng vấn đề là tôi cần xử lý và / hoặc thao tác phản hồi của máy chủ bên thứ 3, sau đó chuyển nó cho khách hàng của tôi. bất kỳ ý tưởng làm thế nào để thực hiện điều đó?
Nasser Torabzade

4
Bạn sẽ cần phải duy trì các tiêu đề loại nội dung trong trường hợp đó. Dữ liệu HTML hoạt động như bạn đã đề cập vì loại nội dung được mặc định text/htmlcho hình ảnh / pdf hoặc bất kỳ nội dung nào khác, đảm bảo bạn chuyển đúng tiêu đề. Tôi sẽ có thể trợ giúp nhiều hơn nếu bạn chia sẻ những sửa đổi nào bạn áp dụng cho các câu trả lời.
vmx

5
bạn không nên sử dụng mô-đun proxy: github.com/nodejitsu/node-http-proxy ?
Maciej Jankowski

1
Có ai biết cách giữ tiêu đề yêu cầu không?
Phil

1
đẹp, nhưng không hoàn toàn đúng ... nếu máy chủ từ xa có một chuyển hướng, mã này sẽ không làm việc
Zibri

27

Đây là một triển khai sử dụng node-http-proxytừ 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);

4
Tôi nghĩ rằng node-http-proxy chủ yếu dành cho proxy ngược ..., Từ máy khách bên ngoài đến máy chủ nội bộ chạy trên IP cục bộ và các cổng không chuẩn thông qua proxy nút ngược chấp nhận kết nối trên các cổng tiêu chuẩn trên địa chỉ IP công cộng.
Nắng

@Samir Chắc chắn, đó là một trong những điều bạn có thể làm với nó. Nó khá linh hoạt.
bosgood

12

Đây là một máy chủ proxy sử dụng yêu cầu xử lý chuyển hướng. Sử dụng nó bằng cách nhấn vào URL proxy của bạn 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");
    }
}

3
Xin chào henry, làm cách nào để thêm tiêu đề cho yêu cầu?
KCN

Dòng, res.end(e);sẽ gây ra mộtTypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer. Received an instance of Error
Niel de Wet

6

Siêu đơn giản và dễ đọc, đây là cách bạn tạo máy chủ proxy cục bộ cho máy chủ HTTP cục bộ chỉ với Node.js (được thử nghiệm trên v8.1.0 ). Tôi thấy nó đặc biệt hữu ích cho việc kiểm tra tích hợp nên đây là chia sẻ của tôi:

/**
 * 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


4

Mã của bạn không hoạt động với các tệp nhị phân vì chúng không thể được truyền thành chuỗi trong trình xử lý sự kiện dữ liệu. Nếu bạn cần thao tác các tệp nhị phân, bạn sẽ cần sử dụng bộ đệm . Xin lỗi, tôi không có ví dụ về việc sử dụng bộ đệm vì trong trường hợp của tôi, tôi cần thao tác với các tệp HTML. Tôi chỉ kiểm tra loại nội dung và sau đó đối với các tệp văn bản / html, hãy cập nhật chúng khi cần:

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

3

Đây là phiên bản được tối ưu hóa hơn cho câu trả lời của Mike ở trên giúp trang web có Loại nội dung phù hợp, hỗ trợ yêu cầu POST và GET và sử dụng trình duyệt của bạn Tác nhân người dùng để các trang web có thể xác định proxy của bạn như một trình duyệt. Bạn có thể chỉ cần đặt URL bằng cách thay đổi url =và nó sẽ tự động đặt nội dung HTTP và HTTPS mà không cần thực hiện theo cách thủ công.

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


app.use('/', function(clientRequest, clientResponse) {
    var url;
    url = 'https://www.google.com'
    var parsedHost = url.split('/').splice(2).splice(0, 1).join('/')
    var parsedPort;
    var parsedSSL;
    if (url.startsWith('https://')) {
        parsedPort = 443
        parsedSSL = https
    } else if (url.startsWith('http://')) {
        parsedPort = 80
        parsedSSL = http
    }
    var options = { 
      hostname: parsedHost,
      port: parsedPort,
      path: clientRequest.url,
      method: clientRequest.method,
      headers: {
        'User-Agent': clientRequest.headers['user-agent']
      }
    };  
  
    var serverRequest = parsedSSL.request(options, function(serverResponse) { 
      var 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(3000)
  console.log('Running on 0.0.0.0:3000')

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


1

Tôi juste đã viết một proxy trong nodejs xử lý HTTPS với giải mã thông báo tùy chọn. Proxy này cũng có thể thêm tiêu đề xác thực proxy để đi qua proxy của công ty. Bạn cần đưa ra đối số là url để tìm tệp proxy.pac nhằm định cấu hình việc sử dụng proxy của công ty.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.