Прокси с express.js

Чтобы избежать проблем с AJAX в одном домене, я хочу, чтобы мой веб-сервер node.js пересылал все запросы из URL /api/BLABLA на другой сервер, например other_domain.com:3000/BLABLA, и возвращал пользователю то же самое, что и этот удаленный сервер, прозрачно.

Все остальные URL-адреса (рядом с /api/*) должны обслуживаться напрямую, без проксирования.

Как достичь этого с помощью node.js + express.js? Можете ли вы привести простой пример кода?

(как веб-сервер, так и удаленный сервер 3000 находятся под моим управлением, оба выполняются node.js с помощью express.js)


До сих пор я нашел этот https://github.com/nodejitsu/node-http-proxy/, но чтение документации там не помогло мне. Я закончил с

var proxy = new httpProxy.RoutingProxy();
app.all("/api/*", function(req, res) {
    console.log("old request url " + req.url)
    req.url = '/' + req.url.split('/').slice(2).join('/'); // remove the '/api' part
    console.log("new request url " + req.url)
    proxy.proxyRequest(req, res, {
        host: "other_domain.com",
        port: 3000
    });
});

но ничего не возвращается на исходный веб-сервер (или конечному пользователю), поэтому не повезло.

Ответ 1

Вы хотите использовать http.request, чтобы создать аналогичный запрос к удаленному API и вернуть его ответ.

Что-то вроде этого:

var http = require('http');

/* your app config here */

app.post('/api/BLABLA', function(req, res) {

  var options = {
    // host to forward to
    host:   'www.google.com',
    // port to forward to
    port:   80,
    // path to forward to
    path:   '/api/BLABLA',
    // request method
    method: 'POST',
    // headers to send
    headers: req.headers
  };

  var creq = http.request(options, function(cres) {

    // set encoding
    cres.setEncoding('utf8');

    // wait for data
    cres.on('data', function(chunk){
      res.write(chunk);
    });

    cres.on('close', function(){
      // closed, let end client request as well 
      res.writeHead(cres.statusCode);
      res.end();
    });

    cres.on('end', function(){
      // finished, let finish client request as well 
      res.writeHead(cres.statusCode);
      res.end();
    });

  }).on('error', function(e) {
    // we got an error, return 500 error to client and log error
    console.log(e.message);
    res.writeHead(500);
    res.end();
  });

  creq.end();

});

Примечание. Я действительно не пробовал вышеуказанное, поэтому он может содержать ошибки синтаксического разбора, надеюсь, это даст вам подсказку о том, как заставить его работать.

Ответ 2

Я сделал что-то подобное, но вместо этого использовал request:

var request = require('request');
app.get('/', function(req,res) {
  //modify the url in any way you want
  var newurl = 'http://google.com/';
  request(newurl).pipe(res);
});

Надеюсь, это поможет, мне потребовалось некоторое время, чтобы понять, что я могу это сделать:)

Ответ 3

Чтобы продлить trigoman ответ (полные кредиты ему) для работы с POST (может также работать с PUT и т.д.):

app.use('/api', function(req, res) {
  var url = 'YOUR_API_BASE_URL'+ req.url;
  var r = null;
  if(req.method === 'POST') {
     r = request.post({uri: url, json: req.body});
  } else {
     r = request(url);
  }

  req.pipe(r).pipe(res);
});

Ответ 4

Я нашел более короткое и очень простое решение, которое работает без проблем, а также с помощью проверки подлинности, используя express-http-proxy:

const url = require('url');
const proxy = require('express-http-proxy');

// New hostname+path as specified by question:
const apiProxy = proxy('other_domain.com:3000/BLABLA', {
    forwardPath: req => url.parse(req.baseUrl).path
});

А потом просто:

app.use("/api/*", apiProxy);

Примечание: как указано в @MaxPRafferty, используйте req.originalUrl вместо baseUrl, чтобы сохранить запрос:

    forwardPath: req => url.parse(req.baseUrl).path

Обновление: Как уже упоминалось Эндрю (спасибо!), есть готовое решение, использующее тот же принцип: `

npm i --save http-proxy-middleware

И затем:

const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', {target: http://www.example.org/api'});
app.use(apiProxy)

Документация: http-proxy-middleware на Github

Я знаю, что опаздываю, чтобы присоединиться к этой вечеринке, но я надеюсь, что это кому-то поможет.

Ответ 5

Я использовал следующую настройку, чтобы направить все на /rest на мой серверный сервер (на порт 8080) и все остальные запросы на внешний сервер (сервер webpack на порт 3001). Он поддерживает все HTTP-методы, не теряет метаданных запроса и поддерживает websockets (который мне нужен для горячей перезагрузки)

var express  = require('express');
var app      = express();
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var backend = 'http://localhost:8080',
    frontend = 'http://localhost:3001';

app.all("/rest/*", function(req, res) {
  apiProxy.web(req, res, {target: backend});
});

app.all("/*", function(req, res) {
    apiProxy.web(req, res, {target: frontend});
});

var server = require('http').createServer(app);
server.on('upgrade', function (req, socket, head) {
  apiProxy.ws(req, socket, head, {target: frontend});
});
server.listen(3000);

Ответ 6

Итак, вот ответ готовой к копированию и вставке с использованием модуля npm require ('request') и переменной окружения * вместо жестко запрограммированного прокси-сервера:

CoffeeScript

app.use (req, res, next) ->                                                 
  r = false
  method = req.method.toLowerCase().replace(/delete/, 'del')
  switch method
    when 'get', 'post', 'del', 'put'
      r = request[method](
        uri: process.env.PROXY_URL + req.url
        json: req.body)
    else
      return res.send('invalid method')
  req.pipe(r).pipe res

JavaScript:

app.use(function(req, res, next) {
  var method, r;
  method = req.method.toLowerCase().replace(/delete/,"del");
  switch (method) {
    case "get":
    case "post":
    case "del":
    case "put":
      r = request[method]({
        uri: process.env.PROXY_URL + req.url,
        json: req.body
      });
      break;
    default:
      return res.send("invalid method");
  }
  return req.pipe(r).pipe(res);
});

Ответ 7

Сначала установите express и http-proxy-middleware

npm install express http-proxy-middleware --save

Затем в вашем server.js

const express = require('express');
const proxy = require('http-proxy-middleware');

const app = express();
app.use(express.static('client'));

// Add middleware for http proxying 
const apiProxy = proxy('/api', { target: 'http://localhost:8080' });
app.use('/api', apiProxy);

// Render your site
const renderIndex = (req, res) => {
  res.sendFile(path.resolve(__dirname, 'client/index.html'));
}
app.get('/*', renderIndex);

app.listen(3000, () => {
  console.log('Listening on: http://localhost:3000');
});

В этом примере мы обслуживаем сайт на порту 3000, но когда запрос заканчивается с /api, мы перенаправляем его на localhost: 8080.

http://localhost:3000/api/login перенаправить на http://localhost:8080/api/login

Ответ 9

Я нашел более короткое решение, которое делает именно то, что я хочу https://github.com/nodejitsu/node-http-proxy/

После установки http-proxy

npm install http-proxy --save

Используйте его, как показано ниже, в вашем сервере /index/app.js

var proxyServer = require('http-route-proxy');
app.use('/api/BLABLA/', proxyServer.connect({
  to: 'other_domain.com:3000/BLABLA',
  https: true,
  route: ['/']
}));

Я действительно проводил дни, глядя повсюду, чтобы избежать этой проблемы, попробовал множество решений, и никто из них не работал, но этот.

Надеюсь, что это тоже поможет кому-то другому:)

Ответ 10

У меня нет экспресс-образца, но с простым пакетом http-proxy. Очень полосатая версия прокси, которую я использовал для своего блога.

Короче говоря, все пакеты http-прокси nodejs http работают на уровне протокола HTTP, а не на уровне tcp (socket). Это справедливо и для экспресс-доставки, и для всех распространенных промежуточных программ. Ни один из них не может выполнять прозрачный прокси-сервер или NAT, что означает сохранение IP-адреса источника входящего трафика в пакете, отправленном на серверный веб-сервер.

Тем не менее, веб-сервер может перенести исходный IP-адрес из HTTP-переадресованных заголовков и добавить его в журнал.

xfwd: true в proxyOption включить функцию заголовка x-forward для http-proxy.

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

proxyConfig = {
    httpPort: 8888,
    proxyOptions: {
        target: {
            host: 'example.com',
            port: 80
        },
        xfwd: true // <--- This is what you are looking for.
    }
};

function startProxy() {

    proxy
        .createServer(proxyConfig.proxyOptions)
        .listen(proxyConfig.httpPort, '0.0.0.0');

}

startProxy();

Ссылка для заголовка X-Forwarded: https://en.wikipedia.org/wiki/X-Forwarded-For

Полная версия моего прокси: https://github.com/J-Siu/ghost-https-nodejs-proxy