Прокси с 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
Ответ 8
Я создал чрезвычайно простой модуль, который делает именно это:
https://github.com/koppelaar/auth-proxy
Ответ 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