【问题标题】:Ratchet is not receiving WebSocket packet from browser?Ratchet 没有从浏览器接收 WebSocket 数据包?
【发布时间】:2016-01-29 14:26:53
【问题描述】:

我正在尝试使用 Ratchet 通过 WebSocket 测试简单的 ping & pong 响应。我的 WebSocket 服务器没有看到来自我的 Web 浏览器的 WebSocket 客户端的任何响应但是 WebSocket 服务器发送的数据包可以被浏览器看到。我正在寻找原因。

我目前的猜测是:

  • 我缺少一些 HTTP 标头
  • 我必须在浏览器wsclient.send(encodeFrame("{'action': 'pong'}")); 上对数据包进行编码
  • CloudFlare 未将 WS 流中的数据包识别为有效数据包并对其进行处理
  • EC2 实例中的 CloudFlare 或 nginx 正在做一些奇怪的缓冲
  • Ratchet 无法识别最低 IOServer 级别的数据包并对其进行处理
    • 但我从来没有从这个级别得到任何错误或异常

设置:

  • Linux 服务器@Amazon EC2
  • DNS @ CloudFlare 开启免费计划和加速 + 开启强制 HTTPS 重定向
  • HTTP 服务器是 nginx
  • nginx 上没有 HTTPS(Cloudflare 重定向 HTTPS -> EC2 HTTP)
  • WebSocket 服务器 (Ratchet) 在 EC2 上以 127.0.0.1:65000 运行
  • Nginx 将 /api 重定向到 127.0.0.1:65000(棘轮)

在 EC2 实例上使用自己的 WebSocket 客户端进行测试:

  • 127.0.0.1:65000 工作正常
  • <Amazon NAT IP of instance>:80 工作正常
  • <Amazon public IP of instance>:80 工作正常
  • <CloudFlare IP of Amazon public IP>:80 在应用程序实现级别连接到 WebSocket 服务器,但在任何级别(应用程序、WsServer、HTTPServer)上的 onMessage 方法上都看不到数据包
  • <CloudFlare IP of Amazon public IP>:443 给出 400 Bad Request 因为测试客户端只是简单的 TCP 流

从本地机器测试:

直接连接到由 CloudFlare 的缓存 IP 提供的主机。 Dojox.Socket 连接到wss://host/api。在 Ratchet 的应用程序实现级别上再次看到连接(onOpen 被触发)。我的浏览器看到 ping 数据包正常,因此从 Ratchet 发送工作正常。

但后来我尝试从浏览器向ping 发送pong 回复,并且onMessage 方法从未在Ratched 的任何级别上触发。连接保持打开状态,如果我使用 Fiddler 观看,ping 和 pong 都会不断发送,但 WebSocket 服务器永远不会收到这些 pong (onMessage)。

在 Fiddler 的 WebSocket 流之后显示来自浏览器的 pong 具有“数据被密钥屏蔽:<some hex>”,但来自 Ratched 的 ping 被屏蔽。

连接摘要:

页面加载:

本地机器http://host/→CloudFlare HTTPS 重定向https://host/http://host-with-amazon-public-ip/http://host-with-amazon-NAT-ip/→HTML + JS 页面加载 wss WebSocket 连接到/api

WebSocket 连接到/api

CloudFlare HTTPS 重定向 wss://host/api → http://host-with-amazon-public-ip/apihttp://host-with-amazon-NAT-ip/api → 本地服务器 nginx 重定向 /api → 127.0.0.1:65000 → 连接升级 → WebSocket 流 → Web 浏览器的 WebSocket 流

nginx.conf

server {
  listen 80;

  server_name test.example.com;
  root /home/raspi/test/public;
  autoindex off;
  index index.php;

  access_log /home/raspi/test/http-access.log;
  error_log /home/raspi/test/http-error.log notice;

  location / { 
    index index.php; 
    try_files $uri $uri/ /index.php?$args;
  }

 location /api {
    access_log /home/raspi/test/api-access.log;
    error_log /home/raspi/test/api-error.log;

    expires epoch;

    proxy_ignore_client_abort on;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_cache off;
    proxy_pass http://127.0.0.1:65000/;

    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header Connection "keep-alive, Upgrade";
    proxy_set_header Upgrade "websocket";
    proxy_set_header Accept-Encoding "gzip, deflate";
    proxy_set_header Sec-WebSocket-Extensions "permessage-deflate";
    proxy_set_header Sec-WebSocket-Protocol "game";
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location ^~ /js/app/ {
    try_files $uri /;
    expires epoch;
    add_header Cache-Control "no-cache" always;
  }

  location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt)$ {
    try_files $uri /;
    access_log off;
    expires max;
  }

  location = /robots.txt  { access_log off; log_not_found off; }
  location = /favicon.ico { access_log off; log_not_found off; }    
  location ~ /\. { access_log off; log_not_found off; deny all; }

  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$; 
    fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; 
    fastcgi_index index.php; 
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 
    include fastcgi_params; 
  }
}

【问题讨论】:

  • 您的 Cloudflare 帐户是否支持 websockets? blog.cloudflare.com/cloudflare-now-supports-websockets 由于 websockets 通过“升级”HTTP 连接来工作的方式,单向服务器到客户端的传输似乎在某些情况下可能可以通过不支持的代理来实现。完全支持该协议并假定服务器仍在返回 HTTP 响应正文。

标签: nginx amazon-ec2 websocket cloudflare ratchet


【解决方案1】:

Web 套接字目前仅在商业和企业级别可用。你提到你在免费计划。这就是这里的问题。

【讨论】:

    【解决方案2】:

    问题在于您的提供商拒绝连接和更新标头。你可以去Ratchet/WebSocket/Version/RFC6455/HandshakeVerifier.php修改代码为:

        ...
        public function verifyAll(RequestInterface $request) {
        $passes = 0;
    
        $passes += (int)$this->verifyMethod($request->getMethod());
        $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion());
        $passes += (int)$this->verifyRequestURI($request->getPath());
        $passes += (int)$this->verifyHost((string)$request->getHeader('Host'));
        $passes += (int)$this->verifyUpgradeRequest((string)$request->getHeader('Upgrade'));
        $passes += (int)$this->verifyConnection((string)$request->getHeader('Connection'));
    
        die((string)$request);
        ...
    

    您会看到结果请求没有必填字段;

    解决方法:覆盖 WsServer::onOpen 函数并手动添加该字段以请求。但这是不安全的……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-09
      • 2015-10-10
      • 2013-01-11
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      相关资源
      最近更新 更多