Proxy con express.js
Frecuentes
Visto 199,192 veces
195
Para evitar problemas de AJAX del mismo dominio, quiero que mi servidor web node.js reenvíe todas las solicitudes desde la URL /api/BLABLA
a otro servidor, por ejemplo other_domain.com:3000/BLABLA
, y devolver al usuario lo mismo que devolvió este servidor remoto, de forma transparente.
Todas las demás URL (además de /api/*
) deben ser notificados directamente, sin representación.
¿Cómo logro esto con node.js + express.js? ¿Puede dar un ejemplo de código simple?
(tanto el servidor web como el remoto 3000
el servidor está bajo mi control, ambos ejecutan node.js con express.js)
Hasta ahora encontre esto https://github.com/http-party/node-http-proxy , pero leer la documentación allí 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 no se devuelve nada al servidor web original (o al usuario final), así que no hubo suerte.
10 Respuestas
235
solicita ha quedado obsoleto a partir de febrero de 2020, dejaré la respuesta a continuación por razones históricas, pero considere pasar a una alternativa que se detalla en este , el asunto de.
Archivos
Hice algo similar pero usé solicita en 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 :)
contestado el 06 de mayo de 20 a las 16:05
Gracias, mucho más simple que usar la solicitud HTTP de Node.js: Alex Turpin
Aún más simple, si también canaliza la solicitud: stackoverflow.com/questions/7559862/… - Stephan Hoyer
Solución agradable y limpia. Publiqué una respuesta para que funcione también con la solicitud POST (de lo contrario, no reenvía el cuerpo de su publicación a la API). Si editas tu respuesta, me complacería eliminar la mía. - Henrik Peinar
Ver también esta respuesta para mejorar el manejo de errores. - Tamlyn
@Jonathan @trigoman ahora que request
ha quedado en desuso (consulte el aviso en github.com/solicitud/solicitud), ¿cuál es la alternativa? - cervecero
110
Encontré una solución más corta y muy sencilla que funciona a la perfección, y también con autenticación, usando 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', {
proxyReqPathResolver: 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 preparada 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 para unirme a esta fiesta, pero espero que esto ayude a alguien.
Respondido el 23 de junio de 20 a las 08:06
El req.url no tiene la URL completa, así que actualicé la respuesta para usar req.baseUrl en lugar de req.url - Vinoth Kumar
También me gusta usar req.originalUrl en lugar de baseUrl para conservar las cadenas de consulta, pero es posible que este no sea siempre el comportamiento deseado. - MaxPRafferty
@MaxPRafferty - comentario válido. Vale la pena señalar. Gracias. - Egoístas
Esta es la mejor solución. Estoy usando http-proxy-middleware, pero es el mismo concepto. No haga girar su propia solución de proxy cuando ya hay excelentes. - Andrés
hay otro paquete que es más simple de usar npm install express-proxy-server --save var proxy = require('express-proxy-server'); aplicación.use('/proxy', proxy('ejemplo.org/api')); - mustafa hussain
65
Quieres usar http.request
para crear una solicitud similar a la API remota y devolver su respuesta.
Algo como esto:
const http = require('http');
// or use import http from 'http';
/* your app config here */
app.post('/api/BLABLA', (oreq, ores) => {
const 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: oreq.headers,
};
const creq = http
.request(options, pres => {
// set encoding
pres.setEncoding('utf8');
// set http status code based on proxied response
ores.writeHead(pres.statusCode);
// wait for data
pres.on('data', chunk => {
ores.write(chunk);
});
pres.on('close', () => {
// closed, let's end client request as well
ores.end();
});
pres.on('end', () => {
// finished, let's finish client request as well
ores.end();
});
})
.on('error', e => {
// we got an error
console.log(e.message);
try {
// attempt to set error message and http status
ores.writeHead(500);
ores.write(e.message);
} catch (e) {
// ignore
}
ores.end();
});
creq.end();
});
Aviso: Realmente no he probado 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.
Respondido el 17 de diciembre de 19 a las 15:12
Sí, algunas modificaciones fueron necesarias, pero me gusta más esto que introducir una nueva dependencia adicional del módulo "Proxy". Un poco detallado, pero al menos sé exactamente lo que está pasando. Salud. - user124114
Parece que necesita hacer res.writeHead antes de que se escriba la falla de datos; de lo contrario, obtendrá un error (los encabezados no se pueden escribir después del cuerpo). - setec
@ user124114 - ponga la solución completa que ha usado - Michal Tsadok
parece que tendrá problemas para configurar los encabezados de esta manera. Cannot render headers after they are sent to the client
- Shnd
Actualicé la respuesta a la sintaxis es6 y solucioné el problema de writeHead: mekwall
50
Extender trígonoLa respuesta de (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);
});
contestado el 23 de mayo de 17 a las 12:05
No pude hacerlo funcionar con PUT. Pero funciona muy bien para GET y POST. ¡¡Gracias!! - mariano desanze
@Protron para solicitudes PUT solo usa algo como if(req.method === 'PUT'){ r = request.put({uri: url, json: req.body}); }
- davnicwil
Si necesita pasar encabezados como parte de una solicitud PUT o POST, asegúrese de eliminar el encabezado de longitud de contenido para que la solicitud pueda calcularlo. De lo contrario, el servidor receptor podría truncar los datos, lo que provocaría un error. - Carlos Rymer
@Henrik Peinar, ¿me ayudará esto cuando haga una solicitud de publicación de inicio de sesión y espero redirigir desde web.com/api/login a web.com/? valik
25
Usé 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 webpack en el puerto 3001). Admite todos los métodos HTTP, no pierde ninguna metainformación de solicitud y admite 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);
contestado el 07 de mayo de 16 a las 10:05
Este es el único que también se ocupa de los sockets web. - seg0ndHand
16
Primero instale express y http-proxy-middleware
npm install express http-proxy-middleware --save
Luego 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, atendemos el sitio en el puerto 3000, pero cuando una solicitud finaliza con /api, la redirigimos a localhost:8080.
http://localhost:3000/api/login redirigir a http://localhost:8080/api/login
Respondido el 17 de enero de 17 a las 16:01
6
Ok, aquí hay una respuesta lista para copiar y pegar usando el módulo npm require('request') 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);
});
respondido 25 mar '16, 11:03
En lugar de una declaración de caso, todas las cuales hacen lo mismo excepto que usan una función de solicitud diferente), primero puede desinfectar (por ejemplo, una declaración if que llame a su valor predeterminado si el método no está en la lista de métodos aprobados), y luego simplemente hacer r = solicitud[método](/* el resto */); - Paul
2
Encontré una solución más corta que hace exactamente lo que quiero https://github.com/http-party/node-http-proxy
Después de instalar http-proxy
npm install http-proxy --save
Úselo como se muestra a continuación 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 pasé días buscando en todas partes para evitar este problema, probé muchas soluciones y ninguna funcionó excepto esta.
Espero que también ayude a alguien más :)
Respondido el 24 de enero de 20 a las 10:01
1
Creo que deberías usar cors npm
const app = express();
const cors = require('cors');
var corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));
Respondido 06 Abr '21, 03:04
0
No tengo una muestra expresa, sino una con llano http-proxy
paquete. Una versión muy simplificada del proxy que usé para mi blog.
En resumen, todos los paquetes de proxy http de nodejs funcionan en el nivel del protocolo http, no en el nivel tcp (socket). Esto también es válido para express y todos los middleware express. Ninguno de ellos puede hacer proxy transparente, ni NAT, lo que significa mantener la IP de la fuente de tráfico entrante en el paquete enviado al servidor web back-end.
Sin embargo, el servidor web puede recoger la IP original de los encabezados reenviados por http x y agregarla al registro.
La xfwd: true
in proxyOption
habilitar 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
respondido 24 mar '17, 13:03
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas node.js proxy express reverse-proxy or haz tu propia pregunta.
la forma en que lo haces me funciona, sin ninguna modificación. Saule
Aunque era un poco tarde para responder, estaba enfrentando un problema similar y lo resolvió eliminando el analizador del cuerpo para que el cuerpo de la solicitud no se analice antes de enviarlo por proxy. - VyvIT