【问题标题】:How to set up an apache proxy for Meteor/SockJS and WebSocket?如何为 Meteor/SockJS 和 WebSocket 设置 apache 代理?
【发布时间】:2023-04-09 02:17:02
【问题描述】:

我有一个流星应用程序的 apache 代理,而 apache 和流星在两台不同的机器上。我需要这种方式,因为 apache 必须为许多真实网站提供服务,并且由于资源有限,在这台机器上安装流星应用程序并不是一个好主意。

但是,如果我尝试通过代理从外部连接,WebSocket 握手会失败,响应代码为 400“只能升级到 websocket”。当我从局域网内直接连接到流星机器时,一切正常。 当 WebSocket 失败时,SockJS/Meteor 会退回到 XHR,但不幸的是,这会在相关应用程序中带来一些错误。所以我真的需要 WebSocket 在大多数情况下工作。

我使用此处提到的补丁修补了我的 apache 安装:https://stackoverflow.com/a/16998664 看起来一切顺利,但没有任何改变......

我的 apache 代理指令目前如下:

ProxyRequests Off
ProxyPreserveHost On
ModPagespeed Off
<proxy>
Order deny,allow
Allow from all
</proxy>
ProxyPass / http://10.0.2.6:3000/
ProxyPassReverse / http://10.0.2.6:3000/

而且我什至知道是什么引发了问题。 apache 代理弄乱了标头。离开我机器的有问题的数据包的原始请求标头如下所示:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent

当数据包像这样从 apache 代理转发时:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent
X-Forwarded-For: 24.xxx.xxx.xxx
X-Forwarded-Host: example.com
X-Forwarded-Server: example.com
Connection: Keep-Alive

所以“升级”被删除并且“连接”被改变,所以 websocket 握手失败。现在我可以尝试始终使用 RequestHeader 指令将“升级”设置为“websocket”。但是,这感觉不对,我想它会带来其他问题,所以我想知道是否有真正的解决方案来解决这个问题?或者这是来自https://stackoverflow.com/a/16998664 的补丁应该解决的问题,而我在应用它时出了点问题?

从我读到的切换到 nginx 可以使这个设置更容易。我会考虑这一点,但如果可能的话,我想用 apache 来做这件事,因为 nginx 会使其他事情变得更复杂并花费我很多时间。

【问题讨论】:

    标签: apache proxy websocket meteor sockjs


    【解决方案1】:

    我们将它用于 Apache 和 Apache 背后的 SockJS 应用程序。 Apache 正在自动进行 WebSocket 代理,但您必须将方案重写为 ws 否则它会回退到 XHR。但前提是连接是 WebSocket 握手。添加以下内容将解决您的问题:)(注意:将localhost:3000相应地更改为您自己的后端网址。

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade [NC]
    RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]
    

    【讨论】:

    • 这是解决方案。所有其他答案都对我不起作用;它们只会导致对 SockJS 的请求超时。这是唯一适用于所有 Web 套接字的自动且透明的答案。
    • 在哪里添加这个 sn-p?
    • 这是完整的 .htaccess 文件(在我的共享主机提供程序上没有全局配置)还是我应该添加一些行,例如使用 http 协议重写规则?
    • 此答案在 Firefox 上无法正常工作,请参阅@derwiwie 的答案以获得更灵活的版本。
    【解决方案2】:

    此答案基于 Fatih 的答案。对于发送“升级”以外的连接请求标头(例如“保持活动,升级”)的浏览器,他的解决方案失败了。 Firefox 42 对我来说就是这种情况。

    要解决 Firefox 的问题,请将 apache RewriteCond 更改如下:

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]
    

    ^Upgrade$ 变为 Upgrade$

    我想将此作为对 Fatih 回答的评论,但我缺乏必要的声誉。

    【讨论】:

    • 我在 指令中使用了这个 sn-p,它运行良好(终于!)。
    • 我的英雄 - 想知道为什么 Chrome 能正常工作,而 Firefox 不能。从^Upgrade$ 中删除^ 对我有用。我对语法知之甚少,但谢谢! :)
    • 太棒了,花了两个多小时才找到这个 sn-p!效果很好
    【解决方案3】:

    在阅读了几个答案后,在 Meteor 论坛上发帖,这里的很多试验都是对我有用的整个辣酱玉米饼馅。其他答案有些不完整,或者至少对我不起作用。

    我必须这样做:

    sudo a2enmod proxy_wstunnel 
    

    还必须添加 ProxyPass 和 ProxyPassReverse 并将 ^Upgrade$ 更改为 Upgrade$ 从另一个 SO 答案。

    <VirtualHost *:80>
        ServerName  some-domain.com
    
        RewriteEngine on
        RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
        RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
        RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]
    
        ProxyPass / http://localhost:3000/
        ProxyPassReverse / http://localhost:3000/
    
    </VirtualHost>
    

    然后重新启动 Apache。

    我检查了控制台,现在没有错误,也没有 xhr 请求。所以我认为它工作正常

    【讨论】:

    • 我的英雄 - 想知道为什么 Chrome 能正常工作,而 Firefox 不能。从^Upgrade$ 中删除^ 对我有用。我对语法知之甚少,但谢谢! :)
    【解决方案4】:

    我希望我能够通过 apache 指令直接回复您,但由于您提到了 nginx,而且事实是,它很难配置,我想权衡一下实际使用 nginx 的替代方案,但是保护您免受所有复杂性的影响。

    https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial 上的教程介绍了为多实例生产 Meteor 部署设置 Phusion Passenger 使用或不使用 nginx 的步骤(无论如何它在内部使用 nginx),可以扩展以利用服务器中的所有内核。

    这很简单:

    $ cd meteor-app-directory
    $ mkdir public tmp
    $ passenger start
    

    【讨论】:

      【解决方案5】:

      Fatih-ArslanDerwiwie 的修改的回答就像魅力一样。 我必须使用的一件事是使用 wss 而不是 ws,因为我的服务仅适用于 https。

      RewriteEngine on  
      RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]  
      RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]  
      RewriteRule .* wss://localhost:3000%{REQUEST_URI} [P]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-12
        • 2018-10-12
        • 2013-10-27
        • 1970-01-01
        • 2014-03-10
        • 2016-04-12
        • 1970-01-01
        • 2012-09-05
        相关资源
        最近更新 更多