使用最新的Chrome浏览器,我尝试使用sockjs
客户端与haproxy
后面的后端服务器进行通信。在我的localhost(中间没有haproxy
),这很好 - 客户端可以使用websocket
协议连接,发送和接收消息。例如:
conn.onopen = function() {
if (conn.readyState === SockJS.OPEN) {
conn.send("hello server");
console.log("msg sent");
}
};
一旦我在HAProxy
的服务器上部署它,奇怪的是sockjs
认为连接已打开(如在conn.readyState === SockJS.OPEN
中,并且'msg sent'出现在控制台日志中)但是,websocket
握手只会挂起,服务器永远不会收到msg。以下是我在haproxy
日志中看到的内容:
Oct 23 09:08:25 localhost.localdomain haproxy[14121]: 129.xx.xxx.105:55000 [23/Oct/2012:09:08:24.459] public www/content 777/0/0/1/778 200 375 - - ---- 3/3/0/1/0 0/0 "GET /sockjs/info HTTP/1.1"
Oct 23 09:10:54 localhost.localdomain haproxy[14121]: 129.xx.xxx.105:55015 [23/Oct/2012:09:08:25.398] public www/content 0/0/0/1/149017 101 147 - - CD-- 4/4/0/0/0 0/0 "GET /sockjs/478/kyi342s8/websocket HTTP/1.1"
请注意,只有当我关闭haproxy
后面的后端服务器时,才会显示第二个日志消息。在关闭之前,日志中没有错误,但websocket握手没有完成,服务器没有收到任何消息。
使用Chrome的开发者工具,在“网络”标签中,我看到以下内容:
Request URL:ws://www.mysite.com/sockjs/478/kyi342s8/websocket
Request Method:GET
Status Code:101 Switching Protocols
Request Headers
Connection:Upgrade
Host:www.mysite.com
Origin:http://www.mysite.com
Sec-WebSocket-Extensions:x-webkit-deflate-frame
Sec-WebSocket-Key:TFEIKYhlqWWBZKlXzXAuWQ==
Sec-WebSocket-Version:13
Upgrade:websocket
(Key3):00:00:00:00:00:00:00:00
Response Headers
Connection:Upgrade
Sec-WebSocket-Accept:D+s3va02KH6QTso24ywcdxcfDgM=
Upgrade:websocket
(Challenge Response):00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
websocket
对象的“类型”和“时间延迟”在开发人员工具的网络标签下显示为“待定”。
最后,这是我的haproxy
配置(版本1.4.22):
global
log 127.0.0.1 local1 info
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn 4096
chroot /usr/share/haproxy
uid 99
gid 99
daemon
#debug
#quiet
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
maxconn 500
timeout connect 6s
frontend public
mode http
bind *:80
timeout client 300s
option http-server-close
#option http-pretend-keepalive
# define ACLs
acl host_static hdr_beg(host) -i static. data.
acl host_www hdr_beg(host) -i www.
acl url_static path_end .ico .txt .pdf .png .jpg .css .js .csv
acl is_stats path_beg /haproxy/stats
# define rules
use_backend nginx if host_static or host_www url_static
use_backend stats if is_stats
default_backend www
backend nginx
timeout server 20s
server nginx 127.0.0.1:8484
backend stats
stats enable
stats uri /haproxy/stats
backend www
timeout server 300s
option forwardfor
#no option httpclose
option http-server-close
server sockcontent 127.0.0.1:8080
有谁知道为什么会这样?是由于某些haproxy
配置,还是服务器的某些常规网络设置(例如iptables
)?
P.S。我已尝试在http-pretend-keepalive
中启用haproxy
,但它不起作用。
答案 0 :(得分:2)
就像@Joes所说,这是防火墙行为不端的错误。有人说,例如FortiGate会导致这种情况。
更多讨论:https://github.com/sockjs/sockjs-client/issues/94
通过SSL服务SockJS似乎解决了这个问题。
答案 1 :(得分:1)
我已经遇到过这种情况,我不记得它是什么服务器,但它并不完全符合WebSocket规范。实际上,它失败了,因为它在Connection标头中找到了“close”标记以及“Upgrade”标记,而规范说需要“升级”标记,并且(幸运的是)并不建议拒绝其他标记。 / p>
理论上,如果您使用了“选项http-pretend-keep-alive”,那么它应该可以正常工作。至少它对我有用。但也许这里有一个不同的问题。
答案 2 :(得分:1)
最有可能的是,你的网络中有透明的防火墙,它会混淆到端口80的websocket连接。
验证是否是这种情况:
如果它开始工作,那么您的网络就出现了问题。
不幸的是,在这种情况下,SockJS不会使用回退传输,因为客户端认为它已连接,但连接并未真正建立。
尽可能的解决方案:让haproxy监听两个端口,端口80用于Web流量,不同端口用于SockJS流量。这可以保证透明的HTTP代理不会弄乱你的websocket连接。