Proxy con express.js

Para evitar problemas de AJAX del mismo dominio, quiero que mi servidor web node.js reenvíe todas las solicitudes de URL /api/BLABLA a otro servidor, por ejemplo other_domain.com:3000/BLABLA , y devuelva al usuario lo mismo que este remoto Servidor devuelto, de forma transparente.

Todas las demás URL (junto a /api/* ) deben ser servidas directamente, sin proxy.

¿Cómo logro esto con node.js + express.js? ¿Puedes dar un ejemplo de código simple?

(Tanto el servidor web como el servidor remoto 3000 están bajo mi control, ambos ejecutan node.js con express.js)


Hasta ahora encontré este https://github.com/nodejitsu/node-http-proxy/ , pero leer la documentación no me hizo más sabio. Terminé con

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

pero nada se devuelve al servidor web original (o al usuario final), así que no hay suerte.

Desea utilizar http.request para crear una solicitud similar a la API remota y devolver su respuesta.

Algo como esto:

 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's end client request as well res.writeHead(cres.statusCode); res.end(); }); cres.on('end', function(){ // finished, let's 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(); }); 

Aviso: Realmente no he intentado lo anterior, por lo que podría contener errores de análisis con suerte, esto le dará una pista sobre cómo hacer que funcione.

Hice algo similar pero utilicé solicitud en su lugar:

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

Espero que esto ayude, me tomó un tiempo darme cuenta de que podía hacer esto 🙂

Para extender la respuesta de trigoman (créditos completos para él) para trabajar con POST (también podría funcionar con PUT, etc.):

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

Encontré una solución más corta y sencilla que funciona a la perfección, y también con autenticación, utilizando 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 }); 

Y luego simplemente:

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

Nota: como lo menciona @MaxPRafferty, use req.originalUrl en lugar de baseUrl para preservar la cadena de consulta:

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

Actualización: Como lo mencionó Andrew (¡gracias!), Hay una solución ya hecha que utiliza el mismo principio:

 npm i --save http-proxy-middleware 

Y entonces:

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

Documentación: http-proxy-middleware en Github

Sé que llego tarde a esta fiesta, pero espero que esto ayude a alguien.

Utilicé la siguiente configuración para dirigir todo en /rest a mi servidor backend (en el puerto 8080), y todas las demás solicitudes al servidor frontend (un servidor de webpack en el puerto 3001). Es compatible con todos los métodos HTTP, no pierde ninguna meta-información de solicitud y es compatible con websockets (que necesito para la recarga en caliente)

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

Ok, aquí hay una respuesta lista para copiar y pegar que usa el módulo npm requerido (‘solicitar’) y una variable de entorno * en lugar de un proxy codificado):

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

Primero instale Express y http-proxy-middleware

 npm install express http-proxy-middleware --save 

Entonces en tu 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'); }); 

En este ejemplo, servimos el sitio en el puerto 3000, pero cuando finaliza una solicitud con / api, lo redireccionamos a localhost: 8080.

http: // localhost: 3000 / api / login redirigir a http: // localhost: 8080 / api / login

He creado un módulo extremadamente simple que hace exactamente esto: https://github.com/koppelaar/auth-proxy

Encontré una solución más corta que hace exactamente lo que quiero https://github.com/nodejitsu/node-http-proxy/

Después de instalar http-proxy

 npm install http-proxy --save 

Úselo como abajo en su servidor / index / app.js

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

Realmente he pasado días buscando en todas partes para evitar este problema, probé muchas soluciones y ninguna de ellas funcionó, solo esta.

Espero que también ayude a alguien más 🙂

No tengo una muestra rápida, pero sí una con paquete de http-proxy simple. Una versión muy simple del proxy que usé para mi blog.

En resumen, todos los paquetes de proxy http de nodejs funcionan a nivel de protocolo http, no a nivel tcp (socket). Esto también es cierto para el middleware expreso y todo expreso. Ninguno de ellos puede hacer proxy transparente, ni NAT, lo que significa mantener la IP de origen del tráfico entrante en el paquete enviado al servidor web de fondo.

Sin embargo, el servidor web puede capturar la IP original de los encabezados reenviados de http x y agregarla al registro.

El xfwd: true en proxyOption habilita la función de encabezado x-forward para 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(); 

Referencia para el encabezado X-Forwarded: https://en.wikipedia.org/wiki/X-Forwarded-For

Versión completa de mi proxy: https://github.com/J-Siu/ghost-https-nodejs-proxy