为了避免同域AJAX问题,我希望我的node.js Web服务器将来自URL /api/BLABLA
的所有请求转发到另一个服务器,例如other_domain.com:3000/BLABLA
,并返回用户同样的事情,这个远程服务器透明地返回。
所有其他网址(/api/*
旁边)将直接投放,不代理。
如何使用node.js + express.js实现此目的?你能给出一个简单的代码示例吗?
(Web服务器和远程3000
服务器都在我的控制之下,都运行带有express.js的node.js)
到目前为止,我发现了这个https://github.com/nodejitsu/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
});
});
但没有任何内容返回到原始Web服务器(或最终用户),所以没有运气。
答案 0 :(得分:185)
我做了类似的事情,但我改为使用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);
});
我希望这会有所帮助,花了一段时间才意识到我能做到这一点:)
答案 1 :(得分:53)
我找到了一个更简洁,更直接的解决方案,它可以无缝地运行,并且使用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
});
然后简单地说:
app.use('/api/*', apiProxy);
注意:如@MaxPRafferty所述,使用req.originalUrl
代替baseUrl
来保留查询字符串:
forwardPath: req => url.parse(req.baseUrl).path
更新:正如安德鲁所说(谢谢!),有一个现成的解决方案使用相同的原则:
npm i --save http-proxy-middleware
然后:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', {target: 'http://www.example.org/api'});
app.use(apiProxy)
文档:http-proxy-middleware on Github
我知道我很晚才加入这个派对,但我希望这对某人有所帮助。
答案 2 :(得分:43)
扩展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);
});
答案 3 :(得分:40)
您希望使用http.request
创建与远程API类似的请求并返回其响应。
这样的事情:
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();
});
注意:我没有真正尝试过上述内容,因此它可能包含解析错误,希望这会为您提供有关如何使其工作的提示。
答案 4 :(得分:19)
我使用以下设置将/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);
答案 5 :(得分:6)
首先安装express和http-proxy-middleware
npm install express http-proxy-middleware --save
然后在你的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');
});
在此示例中,我们在端口3000上提供站点服务,但是当请求以/ api结尾时,我们将其重定向到localhost:8080。
http://localhost:3000/api/login重定向到http://localhost:8080/api/login
答案 6 :(得分:5)
好的,这是使用require('请求')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:
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);
});
答案 7 :(得分:2)
我创建了一个非常简单的模块,它完全按照以下方式执行: https://github.com/koppelaar/auth-proxy
答案 8 :(得分:1)
我找到了一个更短的解决方案,完全符合我的要求https://github.com/nodejitsu/node-http-proxy/
安装http-proxy
npm install http-proxy --save
在服务器/ index / app.js中使用如下所示
var proxyServer = require('http-route-proxy');
app.use('/api/BLABLA/', proxyServer.connect({
to: 'other_domain.com:3000/BLABLA',
https: true,
route: ['/']
}));
我真的花了好几天到处寻找避免这个问题,尝试了很多解决方案,但没有一个能够解决这个问题。
希望它也会帮助其他人:)
答案 9 :(得分:0)
我没有明确的样本,但有一个普通的http-proxy
包。我用于博客的代理版本。
简而言之,所有nodejs http代理包都在http协议级别工作,而不是tcp(socket)级别。快递和所有快速中间件也是如此。他们都不能做透明代理,也不能做NAT,这意味着将传入的流量源IP保存在发送到后端Web服务器的数据包中。
但是,Web服务器可以从http x-forwarded标头中提取原始IP并将其添加到日志中。
xfwd: true
proxyOption
为http-proxy
启用x-forward标头功能。
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();
X-Forwarded标头的参考:https://en.wikipedia.org/wiki/X-Forwarded-For
答案 10 :(得分:0)
我认为你应该使用 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));