node.js 使用 express.js 代理
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10435407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Proxy with express.js
提问by user124114
To avoid same-domain AJAX issues, I want my node.js web server to forward all requests from URL /api/BLABLAto another server, for example other_domain.com:3000/BLABLA, and return to user the same thing that this remote server returned, transparently.
为了避免同域 AJAX 问题,我希望我的 node.js Web 服务器将来自 URL 的所有请求转发/api/BLABLA到另一个服务器,例如other_domain.com:3000/BLABLA,并将此远程服务器返回的相同内容透明地返回给用户。
All other URLs (beside /api/*) are to be served directly, no proxying.
所有其他 URL(除了/api/*)都将直接提供,无需代理。
How do I achieve this with node.js + express.js? Can you give a simple code example?
我如何使用 node.js + express.js 实现这一点?能举个简单的代码例子吗?
(both the web server and the remote 3000server are under my control, both running node.js with express.js)
(网络服务器和远程3000服务器都在我的控制之下,都运行 node.js 和 express.js)
So far I found this https://github.com/http-party/node-http-proxy, but reading the documentation there didn't make me any wiser. I ended up with
到目前为止,我找到了这个https://github.com/http-party/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
});
});
but nothing is returned to the original web server (or to the end user), so no luck.
但是没有任何东西返回到原始 Web 服务器(或最终用户),所以没有运气。
采纳答案by mekwall
You want to use http.requestto create a similar request to the remote API and return its response.
您想使用它http.request来创建对远程 API 的类似请求并返回其响应。
Something like this:
像这样的东西:
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();
});
Notice: I haven't really tried the above, so it might contain parse errors hopefully this will give you a hint as to how to get it to work.
注意:我还没有真正尝试过上面的方法,所以它可能包含解析错误,希望这会给你一个关于如何让它工作的提示。
回答by trigoman
requesthas been deprecated as of February 2020, I'll leave the answer below for historical reasons, but please consider moving to an alternative listed in this issue.
Archive
档案
I did something similar but I used requestinstead:
我做了类似的事情,但我用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);
});
I hope this helps, took me a while to realize that I could do this :)
我希望这会有所帮助,我花了一段时间才意识到我可以做到这一点:)
回答by Selfish
I found a shorter and very straightforward solution which works seamlessly, and with authentication as well, using express-http-proxy:
我找到了一个更短且非常简单的解决方案,它可以无缝地工作,并且还可以使用身份验证,使用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
});
And then simply:
然后简单地:
app.use('/api/*', apiProxy);
Note: as mentioned by @MaxPRafferty, use req.originalUrlin place of baseUrlto preserve the querystring:
注意:正如@MaxPRafferty 所提到的,使用req.originalUrl代替baseUrl来保留查询字符串:
forwardPath: req => url.parse(req.baseUrl).path
Update: As mentioned by Andrew (thank you!), there's a ready-made solution using the same principle:
更新:正如 Andrew 所提到的(谢谢!),有一个使用相同原理的现成解决方案:
npm i --save http-proxy-middleware
And then:
进而:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', {target: 'http://www.example.org/api'});
app.use(apiProxy)
Documentation: http-proxy-middleware on Github
文档:Github 上的 http-proxy-middleware
I know I'm late to join this party, but I hope this helps someone.
我知道我加入这个聚会迟到了,但我希望这对某人有所帮助。
回答by Henrik Peinar
To extend trigoman's answer (full credits to him) to work with POST (could also make work with PUT etc):
扩展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);
});
回答by Anthony De Smet
I used the following setup to direct everything on /restto my backend server (on port 8080), and all other requests to the frontend server (a webpack server on port 3001). It supports all HTTP-methods, doesn't lose any request meta-info and supports websockets (which I need for hot reloading)
我使用以下设置将所有内容定向/rest到我的后端服务器(端口 8080),并将所有其他请求定向到前端服务器(端口 3001 上的 webpack 服务器)。它支持所有 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);
回答by C. Dupetit
First install express and http-proxy-middleware
首先安装 express 和 http-proxy-middleware
npm install express http-proxy-middleware --save
Then in your server.js
然后在你的 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');
});
In this example we serve the site on port 3000, but when a request end with /api we redirect it to localhost:8080.
在这个例子中,我们在端口 3000 上为站点提供服务,但是当请求以 /api 结束时,我们将其重定向到 localhost:8080。
http://localhost:3000/api/loginredirect to http://localhost:8080/api/login
http://localhost:3000/api/login重定向到http://localhost:8080/api/login
回答by coderofsalvation
Ok, here's a ready-to-copy-paste answer using the require('request') npm module and an environment variable *instead of an hardcoded proxy):
好的,这是使用 require('request') npm 模块和环境变量 * 而不是硬编码代理的准备复制粘贴答案:
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:
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);
});
回答by hzitoun
I found a shorter solution that does exactly what I want https://github.com/http-party/node-http-proxy
我找到了一个更短的解决方案,它完全符合我的要求https://github.com/http-party/node-http-proxy
After installing http-proxy
安装后 http-proxy
npm install http-proxy --save
Use it like below in your server/index/app.js
在你的 server/index/app.js 中像下面一样使用它
var proxyServer = require('http-route-proxy');
app.use('/api/BLABLA/', proxyServer.connect({
to: 'other_domain.com:3000/BLABLA',
https: true,
route: ['/']
}));
I really have spent days looking everywhere to avoid this issue, tried plenty of solutions and none of them worked but this one.
我真的花了几天时间到处寻找以避免这个问题,尝试了很多解决方案,但没有一个有效,只有这个。
Hope it is going to help someone else too :)
希望它也能帮助别人:)
回答by John Siu
I don't have have an express sample, but one with plain http-proxypackage. A very strip down version of the proxy I used for my blog.
我没有快递样品,但有普通http-proxy包装的样品。我在博客中使用的代理的精简版。
In short, all nodejs http proxy packages work at the http protocol level, not tcp(socket) level. This is also true for express and all express middleware. None of them can do transparent proxy, nor NAT, which means keeping incoming traffic source IP in the packet sent to backend web server.
简而言之,所有 nodejs http 代理包都在 http 协议级别工作,而不是 tcp(socket) 级别。这也适用于 express 和所有 express 中间件。它们都不能做透明代理,也不能做 NAT,这意味着将传入流量源 IP 保留在发送到后端 Web 服务器的数据包中。
However, web server can pickup original IP from http x-forwarded headers and add it into the log.
但是,Web 服务器可以从 http x 转发的标头中获取原始 IP 并将其添加到日志中。
The xfwd: truein proxyOptionenable x-forward header feature for http-proxy.
将xfwd: true在proxyOption启用X转发头功能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();
Reference for X-Forwarded Header: https://en.wikipedia.org/wiki/X-Forwarded-For
X-Forwarded 标头参考:https: //en.wikipedia.org/wiki/X-Forwarded-For
Full version of my proxy: https://github.com/J-Siu/ghost-https-nodejs-proxy
我的代理的完整版本:https: //github.com/J-Siu/ghost-https-nodejs-proxy

