node.js - nodejs - Proxy con express.js
nodejs proxy request (10)
Bien, aquí hay una respuesta lista para copiar y pegar usando el módulo require (''request'') npm 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);
});
Para evitar problemas AJAX del mismo dominio, quiero que mi servidor web node.js reenvíe todas las solicitudes desde URL /api/BLABLA
a otro servidor, por ejemplo other_domain.com:3000/BLABLA
, y devuelva al usuario lo mismo que este control remoto servidor devuelto, de forma transparente.
Todas las demás URL (junto a /api/*
) se deben servir 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 ejecutando node.js con express.js)
Hasta ahora encontré esto https://github.com/nodejitsu/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 hay suerte.
Creé un módulo extremadamente simple que hace exactamente esto: https://github.com/koppelaar/auth-proxy
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.
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 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 he pasado días buscando en todas partes para evitar este problema, intenté muchas soluciones y ninguna de ellas funcionó, excepto esta.
Espero que ayude a alguien más también :)
Encontré una solución más corta y muy 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 se menciona en @MaxPRafferty, use req.originalUrl
en lugar de baseUrl
para conservar la cadena de consulta:
forwardPath: req => url.parse(req.baseUrl).path
Actualización: como 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 para unirme a esta fiesta, pero espero que esto ayude a alguien.
Hice algo similar, pero usé la request 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 :)
No tengo una muestra expresa, pero sí una con el paquete http-proxy
. Una versión muy reducida del proxy que utilicé para mi blog.
En resumen, todos los paquetes proxy http nodej trabajan en el nivel de protocolo http, no en el nivel tcp (socket). Esto también es cierto para expreso y todo el middleware expreso. Ninguno de ellos puede hacer proxy transparente, ni NAT, lo que significa mantener IP de origen de tráfico entrante en el paquete enviado al servidor web de fondo.
Sin embargo, el servidor web puede recoger la dirección IP original de los encabezados http x-forward y agregarla al registro.
xfwd: true
en proxyOption
habilita la función x-forward header 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 X-Forwarded Header: https://en.wikipedia.org/wiki/X-Forwarded-For
La versión completa de mi proxy: https://github.com/J-Siu/ghost-https-nodejs-proxy
Para extender la respuesta de (créditos completos para él) para trabajar con POST (también podría hacer el trabajo 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);
});
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, servimos el sitio en el puerto 3000, pero cuando una solicitud finaliza con / api lo redirigimos a localhost: 8080.
http://localhost:3000/api/login redirigir a http://localhost:8080/api/login
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);