我正在尝试测试简单的ping&使用Ratchet与WebSockets进行pong响应。我的WebSocket服务器没有看到来自我的web浏览器的WebSocket客户端的任何响应,但浏览器可以很好地看到WebSocket发送的数据包。我正在努力寻找原因。
我目前的猜测是:
- 我缺少一些HTTP标头
- 我必须在浏览器
wsclient.send(encodeFrame("{'action': 'pong'}"));
上对数据包进行编码 - CloudFlare未将WS流中的数据包识别为有效数据包,并对其进行了猛烈抨击
- EC2实例中的CloudFlare或nginx正在进行一些奇怪的缓冲
- Ratchet无法识别最低IOServer级别的数据包,并对其进行了猛烈抨击
- 但我从未从这个级别得到任何错误或异常
设置:
- Linux服务器@亚马逊EC2
- DNS@CloudFlare提供免费计划和加速+强制HTTPS重定向
- HTTP服务器是nginx
- nginx上没有HTTPS(Cloudflare重定向HTTPS->EC2 HTTP)
- WebSocket服务器(棘轮)在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服务器,但在任何级别(App、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流显示,来自浏览器的pongs具有"密钥屏蔽的数据:<some hex>
",但来自Ratched的ping是而不是屏蔽的。
连接摘要:
页面加载:
本地机器http://host/&rar;CloudFlare HTTPS重定向https://host/&rar;http://host-with-amazon-public-ip/&rar;http://host-with-amazon-NAT-ip/&rar;加载wss WebSocket连接到/api
的HTML+JS页面
到/api
:的WebSocket连接
CloudFlare HTTPS重定向wss://host/api&rar;http://host-with-amazon-public-ip/api&rar;http://host-with-amazon-NAT-ip/api&rar;本地服务器nginx重定向/api&rar;127.0.0.1:65000
&rar;连接升级&rar;WebSocket流.rar;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;
}
}
Web套接字目前仅在业务和企业级别可用。你提到你在免费计划中。这就是问题所在。
问题是您的提供程序拒绝Connection和Update标头。您可以访问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函数并手动添加要请求的字段。但这是不安全的。。。