为了避免同域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服务器(或最终用户),所以运气不好。


当前回答

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

其他回答

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

存档

我做了类似的事情,但我用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);
});

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

我没有一个明确的样本,但一个与普通http代理包。一个非常精简的版本的代理,我用在我的博客。

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

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

proxyOption中的xfwd: true使能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 Header的参考:https://en.wikipedia.org/wiki/X-Forwarded-For

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

我使用下面的设置将/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: ['/']
}));

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

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