Apache 2.4.7 mod_proxy_wstunnel隧道太多(HTTP以及WS)

我在Ubuntu 14.04 LTS上运行Apache 2.4.7作为反向代理。 这个Apache服务器充当许多不同后端应用程序的入口点,这些应用程序可以通过<Location>块中的不同mod_proxyconfiguration来访问

我需要提供对使用WebSockets的应用程序的反向代理访问。 该应用程序是一个Java Spring应用程序,通过HTTP提供HTML和其他静态文件,然后在加载页面后使用WebSocket作为dynamic数据。

我已经使用以下configuration在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上不可用的Apacheauthentication模块,我不能在生产中使用它。

我想要做的,在伪Apache的configuration是:

 <Location /newapp/> if not WebSockets: ProxyPass http://newapp.example.com:8080/ ProxyPassReverse / else ProxyPass ws://newapp.example.com:8080/ ProxyPassReverse / </Location> 

Apache的mod_proxy_wstunnel模块让我觉得这应该是可能的。 WebSocket可以通过URL /api/socket/... ,所以我尝试使用单独的<Location>块来分隔两种types的ProxyPass

 <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进行 – 比如GET /newapp/static/someimage.png ,出现了一些问题。 这个请求不匹配WebSocket Location,所以我希望它代理GET /static/someimage.pnghttp://newapp.example.com:8080/

相反,应用程序服务器收到一个GET /newapp/static/someimage.png的请求,并返回一个404,因为这不是它意识到的URL。 这会中断应用程序,因为应该运行的HTTP请求会失败。

笔记:

  • 这不仅仅发生在图像上 – GET /newapp/api/ajax/someapicall也会通过不正确的代理。
  • 这并不总是发生。 当testing的东西来完成这个问题,我设法让应用程序完全工作。 这可能是基于时间的 – 我做了任何新的HTTP请求之前,我离开了应用程序运行几分钟,没有与它交互。 当我做出新的HTTP请求时,他们正确地通过了。
  • 禁用<Location /newapp/api/socket/>部分会导致两件事 – WebSocket无法连接,并且HTTP请求继续工作。
  • 在通过浏览器的刷新button刷新页面后,我发现了这个问题。 而不是再次加载页面,我看到了应用程序的404屏幕。

我认为正在发生:

我认为mod_proxy_wstunnel一旦被匹配/newapp/api/socket/的第一个请求激活,就会接pipe来自客户端的所有进一步入站请求,无论它们是否与Location匹配。 我testing了这个通过添加一个RequestHeader set Test "some_identifying_value"指令到每个Location – 静态文件的HTTP请求&为/api/socket/info有他们的Test头,但不正确的代理HTTP请求没有Test头文件,这表明他们正在被直接传递而没有被Apache指令处理。

最终,我的问题是这样的:是否有可能configuration任何版本的Apache(我很高兴升级!)反向代理基于WebSocket的应用程序,使得HTTP请求也正确地反向代理后,WebSocket有连接的? 如果是的话,这是如何configuration的?

我使用Apache 2.4作为我的春季启动应用程序的代理,这个应用程序提供了一些其他API调用,websockets(sockjs)和一些静态页面。 我有一些问题让websocket工作,秘密是添加你看到下面的重写规则 ,现在它适用于我,我的apache虚拟主机configuration看起来像这样:

 <VirtualHost *:443> SSLEngine on SSLCertificateFile /etc/httpd/ssl/my.crt SSLCertificateKeyFile /etc/httpd/ssl/my.key SSLCertificateChainFile /etc/httpd/ssl/intermediate.crt ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ ProxyRequests Off RewriteEngine on RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC] RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC] RewriteRule .* ws://localhost:6868%{REQUEST_URI} [P] ServerName my.dnsname.com </VirtualHost> 

安德斯的答案让我有95%的方式。

基本情况:

  • 我们在newapp.example.com上有一个服务器
  • 端口8080运行HTTP和WebSockets
  • 响应WebSockets请求的URL是/api/socket/
  • 我们正在将此应用程序反向代理为http://apps.example.com/newapp/

这是如何在<Location>块中为上述场景configurationWebSockets和HTTP反向代理:

 <Location /newapp/> ProxyPass http://newapp.example.com:8080/ ProxyPassReverse / RewriteEngine on RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC] RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC] RewriteRule /api/(.*) ws://newapp.example.com:8080/api/$1 [P] </Location> 

最后的重写规则是至关重要的 – 如果没有它,我们会将request /newapp/api/socket传递给WebSocket服务器 – 拒绝它。

正则expression式parsing了api之后的所有东西 – 可能有更好的方法来捕获这个块,但这个工作。 然后我们必须记住readd /api/到最后的redirectURL。

最重要的是,HTTP请求在WebSocket连接build立后继续工作!