socket.io apache2 的 https 代理配置

socket.io https proxy config for apache2

我有一个工作 socket.io 设置,其中有一个 JavaScript-client 和一个 python-server。 客户端基本上只有一行: WebSocket 握手期间出错:意外的响应代码:404

socket = io.connect('');

服务器脚本可以在 https://github.com/miguelgrinberg/python-socketio/blob/master/examples/server/wsgi/app.py 找到 - 我是 运行 端口 5000 上的服务器。

关于客户端和服务器,您可能需要了解的是它们在我的本地主机 apache 安装上运行良好,并且 socket.io 从 GET 请求开始并从那里升级到 websocket。这是成功握手的样子:

http://localhost:5000/socket.io/?EIO=3&transport=polling&t=N1kLfSx
http://localhost:5000/socket.io/?EIO=3&transport=polling&t=N1kLfTI&sid=70ddae8b36da4f0f8f9a851fa2c0121e
ws://localhost:5000/socket.io/?EIO=3&transport=websocket&sid=70ddae8b36da4f0f8f9a851fa2c0121e

现在我们有了一个 websocket,剩下的通信就是 运行 通过它。

我这两天一直在尝试的是在我的网络服务器上获取示例 运行 - 所以我正在寻找一个有效的 apache https 配置,它代理请求到端口上的后端服务器5000.

我尝试了数十种配置变体,其中 none 有效 - 它们看起来都与此非常相似。 URL-rewriting 部分用于在初始握手成功后代理 websocket 连接。

RewriteEngine On
RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
RewriteCond %{QUERY_STRING} transport=websocket    [NC]
RewriteRule /(.*)           ws://localhost:5000/ [P,L]

ProxyPass        /socket.io/ http://localhost:5000/socket.io/
ProxyPassReverse /socket.io/ http://localhost:5000/socket.io/

Apache 将第一个 socket.io GET 请求转发给服务器,服务器回复:

    ÿ0{"sid":"2efa0dbbce4c4eef958e70b393639610","upgrades":["websocket"],"pingTimeout":60000,"pingInterval":25000}ÿ42["my_response",{"data":"Connected","count":0}]ÿ40

然后一个 websocket 被打开并立即再次关闭(代码 404)。然后客户端发送失败的 POST 请求(代码 400)。然后客户端从第 1 步重新开始:发出 GET 请求,获取新的 session id...

ÿXX 特殊字符也出现在工作的本地主机通信中 - 所以它们似乎属于那里)。

我做错了什么?

更新 - 接近解决方案!

我尝试了几个 Python 和 socket.io 示例服务器的 NodeJS 实现以及几个客户端脚本——它们都产生了同样的问题,这证实了我的论点,即 Apache 是问题所在。

我安装了 Nginx 并找到了一个终于可以工作的配置! 这些是神奇的线条:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

我现在正在使用 debug-server 打印所有收到的 HTTP 请求,以将 Nginx 请求与 Apache2 请求进行比较,目的是将 Apache2 配置为传递与 Nginx 相同的 headers。

最后一个挑战似乎是将 Nginx 配置行转换为 Apache2。听起来比实际更容易。不过,这将是解决问题的关键。

终于!经过一周的研究,我终于找到了一个可行的解决方案:

我将此代码放入我的 Apache2 配置的部分:

        ProxyRequests off
        ProxyVia on
        RewriteEngine On

        RewriteEngine On
        RewriteCond %{HTTP:Connection} Upgrade [NC]
        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteRule /(.*) ws://127.0.0.1:8080/ [P,L]

        ProxyPass               / http://127.0.0.1:5000/
        ProxyPassReverse        / http://127.0.0.1:5000/

有一百万种配置,我都试过了 - 这是唯一适合我的配置。问题是 Apache2 没有转发 "Upgrade=websocket" 和 "Connection=upgrade" headers。给定的重写命令使 Apache2 添加这些 headers 到代理连接。

在研究这个的过程中,我首先找到了一个有效的 Nginx 配置,然后我将其转换为 Apache2。所以如果你有 Nginx 的问题,你可以在这里使用它:

        location / {
                proxy_pass http://127.0.0.1:5000/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

这个小小的 NodeJS TCP 服务器在调试 HTTP 方面帮了我很多 headers: https://riptutorial.com/node-js/example/22405/a-simple-tcp-server