我在 Ubuntu 14.04 LTS 上运行 Apache 2.4.7 作为反向代理。此 Apache 服务器充当许多不同后端应用程序的入口点,这些应用程序通过<Location>
块中的不同 mod_proxy 配置访问
我需要为使用 WebSockets 的应用程序提供反向代理访问。该应用程序是一个 Java Spring 应用程序,它通过 HTTP 提供 HTML 和其他静态文件,然后在页面加载后使用 WebSocket 获取动态数据。
我Nginx
使用以下配置让应用程序在后面运行:
location /newapp/ {
proxy_pass http://newapp.example.com:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
不幸的是,由于需要 Nginx 上不可用的 Apache 身份验证模块,我无法在生产中使用它。
在伪 Apache-config 中,我想做的是:
<Location /newapp/>
if not WebSockets:
ProxyPass http://newapp.example.com:8080/
ProxyPassReverse /
else
ProxyPass ws://newapp.example.com:8080/
ProxyPassReverse /
</Location>
Apachemod_proxy_wstunnel
模块让我认为这应该是可能的。WebSocket 是在 URL 上访问的/api/socket/...
,所以我尝试ProxyPass
使用单独的<Location>
块分隔两种类型:
<Location /newapp/>
ProxyPass http://newapp.example.com:8080/ disablereuse=on
ProxyPassReverse /
ProxyPassReverseCookieDomain newapp.example.com apps.example.com
ProxyPassReverseCookiePath http://newapp.example.com:8080/ /newapp/
</Location>
<Location /newapp/api/socket/>
ProxyPass ws://newapp.example.com:8080/api/socket/
ProxyPassReverse /
</Location>
这最初是有效的——浏览器请求http://apps.example.com/newapp/,页面通过 HTTP 加载,静态资产被加载,JavaScript 代码连接到 websocket,一切都很棒。
但是,当通过 HTTP 发出新请求时,例如 for GET /newapp/static/someimage.png
,就会出现问题。此请求与 WebSocket 位置不匹配,因此我希望它能够代理GET /static/someimage.png
到http://newapp.example.com:8080/
.
相反,应用程序服务器收到请求GET /newapp/static/someimage.png
并返回 404,因为这不是它知道的 URL。这会破坏应用程序,因为应该工作的 HTTP 请求会失败。
笔记:
- 这不仅发生在图像上 -
GET /newapp/api/ajax/someapicall
也被错误地代理。 - 这并不总是发生。在测试完成这个问题的过程中,我设法让应用程序完全运行。这可能是基于时间的——在发出任何新的 HTTP 请求之前,我让应用程序运行了几分钟而没有与之交互。当我确实发出新的 HTTP 请求时,它们正确地通过了。
- 禁用该
<Location /newapp/api/socket/>
部分会导致两件事发生 - WebSocket 无法连接,并且 HTTP 请求继续工作。 - 通过浏览器的刷新按钮刷新页面后,我发现了这个问题。我没有再次加载页面,而是看到了应用程序的 404 屏幕。
我认为正在发生的事情:
我认为mod_proxy_wstunnel
,一旦被第一个匹配请求激活/newapp/api/socket/
,就会接管来自客户端的所有进一步的入站请求,无论它们是否匹配Location
。RequestHeader set Test "some_identifying_value"
我通过向每个指令添加一个指令来测试这一点Location
- 静态文件的 HTTP 请求和 for在它们上/api/socket/info
有Test
标头,但错误代理的 HTTP 请求上没有Test
标头,这表明它们被直接传递而没有由 Apache 指令处理。
最终,我的问题是:是否可以将任何版本的 Apache(我很高兴升级!)配置为反向代理基于 WebSocket 的应用程序,从而在 WebSocket 之后也正确地反向代理 HTTP 请求连接的?如果是这样,这是如何配置的?
安德斯的回答让我成功了 95%。
基本场景:
newapp.example.com
/api/socket/
http://apps.example.com/newapp/
这是如何在一个
<Location>
块中为上述场景配置 WebSockets 和 HTTP 反向代理:最终的重写规则至关重要——没有它,我们会将请求
/newapp/api/socket
传递给 WebSocket 服务器——它将被拒绝。正则表达式在之后解析所有内容
api
- 可能有更好的方法来捕获该块,但这有效。然后我们必须记住重新添加/api/
到最终的重定向 URL。最重要的是,在 WebSocket 连接建立后,HTTP 请求继续工作!
我在我的 spring boot 应用程序前面使用 apache 2.4 作为代理,这个应用程序提供一些 rest api 调用、websockets (sockjs) 和一些静态页面。我在让 websocket 工作时遇到了一些问题,秘密是添加你在下面看到的重写规则,现在它对我有用,我的 apache 虚拟主机配置如下所示: