[英]Proxy with express.js
To avoid same-domain AJAX issues, I want my node.js web server to forward all requests from URL /api/BLABLA
to 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
所有请求/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?我如何使用 node.js + express.js 实现这一点? Can you give a simple code example?能举个简单的代码例子吗?
(both the web server and the remote 3000
server are under my control, both running node.js with express.js) (web 服务器和远程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.到目前为止,我找到了这个https://github.com/http-party/node-http-proxy ,但阅读那里的文档并没有让我更明智。 I ended up with我结束了
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 服务器(或最终用户),所以没有运气。
request has 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 .自 2020 年 2 月起,请求已被弃用,出于历史原因,我将在下面留下答案,但请考虑转向本期中列出的替代方案。
I did something similar but I used request instead:我做了类似的事情,但我用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 :)我希望这会有所帮助,我花了一段时间才意识到我可以做到这一点:)
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', {
proxyReqPathResolver: req => url.parse(req.baseUrl).path
});
And then simply:然后简单地:
app.use('/api/*', apiProxy);
Note: as mentioned by @MaxPRafferty, use req.originalUrl
in place of baseUrl
to 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.我知道我加入这个聚会迟到了,但我希望这对某人有所帮助。
You want to use http.request
to 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.注意:我还没有真正尝试过上面的方法,所以它可能包含解析错误,希望这会给你一个关于如何让它工作的提示。
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);
});
I used the following setup to direct everything on /rest
to my backend server (on port 8080), and all other requests to the frontend server (a webpack server on port 3001).我使用以下设置将/rest
上的所有内容定向到我的后端服务器(端口 8080),并将所有其他请求定向到前端服务器(端口 3001 上的 webpack 服务器)。 It supports all HTTP-methods, doesn't lose any request meta-info and supports websockets (which I need for hot reloading)它支持所有 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);
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/login redirect to http://localhost:8080/api/login http://localhost:3000/api/login重定向到http://localhost:8080/api/login
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);
});
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 :)希望它也能帮助别人:)
I think you should use cors npm
我认为你应该使用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));
https://www.npmjs.com/package/cors https://www.npmjs.com/package/cors
I don't have have an express sample, but one with plain http-proxy
package.我没有快递样本,但有一个带有普通http-proxy
包的样本。 A very strip down version of the proxy I used for my blog.我在博客中使用的代理的精简版。
In short, all nodejs http proxy packages work at the http protocol level, not tcp(socket) level.简而言之,所有 nodejs http 代理包都在 http 协议级别工作,而不是 tcp(socket) 级别。 This is also true for express and all express middleware.这也适用于 express 和所有 express 中间件。 None of them can do transparent proxy, nor NAT, which means keeping incoming traffic source IP in the packet sent to backend web server.它们都不能做透明代理,也不能做 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: true
in proxyOption
enable 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.