【问题标题】:Express.js: reverse proxying different web app along with assetsExpress.js:反向代理不同的 Web 应用程序以及资产
【发布时间】:2014-03-07 08:01:27
【问题描述】:

我想允许 Express 中经过身份验证的客户端访问在服务器上运行但在不同端口上的其他 Web 应用程序。

例如,我在 http://myDomain 上运行 express,而在端口 9000 上运行另一个应用程序。我希望能够通过http://myDomain/proxy/9000 访问其他应用程序。

我使用node-http-proxy取得了一点成功,例如:

function(req, res) {
  var stripped = req.url.split('/proxy')[1];
  var path = stripped.split('/');
  var port = path.shift();
  var url = path.join('/');

  req.url = url;
  proxy.web(req, res, {
    target: 'http://127.0.0.1:' + port
  });
}

然而,最大的问题是当 web 应用程序发出 GET 请求时,例如 /js/lib.js,它解析为 http://myDomain/js/lib.js,这是有问题的,因为 express 不知道这些资产。正确的请求是http://myDomain/proxy/9000/js/lib.js。如何路由所有这些额外的请求?

【问题讨论】:

  • 在您的示例中,/js/ 目录中的所有内容都应该进行身份验证吗?
  • 除了更改代理之外,您是否可以更改其他应用程序以生成代理友好的 URL?
  • @Dan,/js/ 目录中的所有内容也应该经过身份验证。
  • @MattBakaitis,这是不可行的,因为我无法直接控制这些其他应用程序,我只想对用户进行身份验证并将他们引导到他们应该去的地方。
  • 与其使用/proxy/9000 之类的东西,为什么不将所有到/js/* 的请求路由到端口9000?

标签: javascript node.js express proxy node-http-proxy


【解决方案1】:

您需要做的是用新的 URL 模式替换初始页面中的 URL。发生的事情是您的反向代理返回的初始页面引用了:
/js/lib.js 或http://myDomain/js/lib.js
因此,当浏览器发出第二个请求时,它的反向代理模式错误。

根据传入的请求,您知道模式应该是什么样子。在您的示例中,它是http://myDomain/proxy/9000。然后从http://127.0.0.1:9000/ 上运行的另一台服务器获取相应的页面。您对该文件中的任何资源进行字符串替换。您需要尝试该模式,但您可能会寻找 'script src="/' 或 'href="/' 并且您可能会发现正则表达式有助于该模式,例如,如果 src 属性不是第一个列在脚本标签中。

例如,您可能会找到 'scr="/',然后将其替换为 'src="/proxy/9000/',这样当浏览器请求该本地资源时,它会通过您的端口来'重新寻找。这需要进行实验,并且它是一个很棒的算法,可以编写单元测试以达到完美。

完成替换后,您只需将该页面流式传输到客户端。 res.send() 会为你做这件事。

您可能会发现其他一些有用的东西是,ExpressJS 为您提供了一种提取端口号的方法,比您现在做的麻烦少一点。看看这个例子:

app.get('/proxy/:port', function(req, res){
    console.log('port is ' + req.params.port);
});

【讨论】:

  • 感谢您的回复!我基本上能够实现这一点。我很难过的一件事是为 websocket 连接执行此操作。这是我要代理的应用程序之一的示例,IPython Notebook (github.com/ipython/ipython/blob/master/IPython/html/static/…),它启动了指向 location.host 的 ws 连接,但它需要指向 myDomain/proxy/9000。应用程序提供的代码被缩小,因此尝试重写启动连接的 javascript 行会很困难。
  • 你能分叉它并使用你的分叉版本吗?如果是这样,您可以将第二个参数传递给该函数(除了 json),它是代理主机名。另一种选择:您可以在调用此函数之前更改 location.host 的值吗?
【解决方案2】:

我不认为http://myDomain/proxy/9000 是正确的做法。网页将假定站点的域只是myDomain 而不是myDomain/proxy/9000,因为这是标准所说的。

使用9000.proxy.myDomain 之类的子域会更好地满足您的用例。

【讨论】:

  • 对于我的用例来说,新的端口是动态开放的,所以我觉得及时生成新的子域是不可行的。
  • 您一定认为“生成”子域比使用新的子文件夹更困难。它不一定是。无论之前应用于您的子文件夹设置的规则如何,也适用于子域设置。如果您担心使用 DNS 注册新的子域,请使用通配符,例如 *.proxy.myDomain
  • 为什么您的应用程序在运行时会动态绑定到端口?这听起来像是一个可能值得重新考虑的方面。如果没有,它至少可以帮助我们了解您真正需要的是什么。
  • 具体应用根据用户数量创建新的Docker容器。每个 Docker 容器都有不同的 Web 服务,这些服务将在创建时打开,然后我想将用户引导到相应的容器。
  • 另一个问题是保持身份验证,有没有办法在快速重定向到子域时保持页面的身份验证?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-04
  • 2017-11-22
  • 2021-07-14
  • 2021-11-25
  • 2019-06-23
  • 2017-04-12
  • 1970-01-01
相关资源
最近更新 更多