使用express.js代理

为了避免同域AJAX问题,我希望我的node.js web服务器将所有来自URL /api/BLABLA的请求转发到另一个服务器,例如other_domain.com:3000/BLABLA,并透明地将此远程服务器返回的相同内容返回给用户。

所有其他url(除了/api/*)将直接提供,不需要代理。

我如何实现这与node.js + express.js?你能给出一个简单的代码示例吗?

(web服务器和远程3000服务器都在我的控制下,都运行node.js与express.js)


到目前为止,我发现这个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
});
});

但是什么也没有返回到原来的web服务器(或最终用户),所以运气不好。

229627 次浏览

你想要使用http.request来创建一个类似的远程API请求,并返回它的响应。

就像这样:

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();
});

注意:我没有真正尝试上面的方法,所以它可能包含解析错误,希望这能给你一个提示,告诉你如何让它工作。

请求已于2020年2月弃用,由于历史原因,我将在下面留下答案,但请考虑转移到此问题中列出的替代方案。

存档

我做了类似的事情,但我用请求代替:

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);
});

我希望这能有所帮助,我花了一段时间才意识到我可以做到这一点:)

扩展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);
});

好的,这里有一个现成的复制粘贴答案,使用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:

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);
});

我找到了一个更短和非常直接的解决方案,它可以无缝工作,并且使用身份验证,使用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
});

然后很简单:

app.use('/api/*', apiProxy);

注意:正如@MaxPRafferty提到的,使用req.originalUrl代替baseUrl来保存查询字符串:

    forwardPath: req => url.parse(req.baseUrl).path

更新:正如Andrew提到的(谢谢!),有一个现成的解决方案,使用相同的原理:

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)

文档:Github上的http-proxy-middleware

我知道我迟到了,但我希望这能帮到别人。

我使用以下设置将/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);

我找到了一个更短的解决方案,这正是我想要的https://github.com/http-party/node-http-proxy

在安装http-proxy之后

npm install http-proxy --save

在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: ['/']
}));

为了避免这个问题,我真的花了好几天的时间到处寻找,尝试了很多解决方案,但没有一个有效,除了这个。

希望这也能帮助到其他人:)

首先安装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

我没有一个快递样品,但一个与普通http-proxy包装。一个非常精简的版本的代理,我用在我的博客。

简而言之,所有nodejs的http代理包都工作在http协议级别,而不是tcp(socket)级别。对于express和所有的express中间件来说也是如此。它们都不能进行透明代理,也不能进行NAT,这意味着将传入流量源IP保存在发送到后端web服务器的数据包中。

但是,web服务器可以从http x转发的报头中提取原始IP并将其添加到日志中。

proxyOption中的xfwd: truehttp-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 Header的引用:https://en.wikipedia.org/wiki/X-Forwarded-For

完整版本的代理:https://github.com/J-Siu/ghost-https-nodejs-proxy

我认为你应该使用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