2012-10-23 230 views
5

使用最新的Chrome瀏覽器,我試圖使用sockjs客戶端與位於haproxy後面的後端服務器進行通信。在我的本地主機上(中間沒有haproxy),這工作正常 - 客戶端可以使用websocket協議連接,發送和接收消息。例如:Websocket握手掛起HAProxy

conn.onopen = function() { 
    if (conn.readyState === SockJS.OPEN) { 
     conn.send("hello server"); 
     console.log("msg sent"); 
    } 
}; 

有一次,我與HAProxy在服務器上部署它,奇怪的事情發生是sockjs認爲連接是打開(如conn.readyState === SockJS.OPEN和「發送味精」出現在控制檯日誌),然而,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握手未完成,服務器也沒有收到msg。

使用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.我試過在haproxy中啓用http-pretend-keepalive,但它不起作用。

回答

1

最有可能的,你有透明防火牆在網絡中,它打亂了WebSocket連接將端口80

要驗證的話:

  1. 製作HAProxy的聽不同的端口和嘗試,如果它開始工作;
  2. 嘗試在您的網絡之外訪問您的服務。

如果它開始工作,那麼有什麼東西錯了你的網絡。

不幸的是,SockJS不會在這種情況下使用備用運輸,因爲客戶認爲它連接,但並沒有真正建立連接。

作爲可能的解決方案:使haproxy偵聽兩個端口,在端口80上爲您的Web流量和不同的端口爲SockJS流量。這保證透明的HTTP代理不會混淆你的websocket連接。

1

我已經遇到這種情況,我不記得是哪個服務器,但它不符合WebSocket的規範完全兼容。事實上,它失敗了,因爲它發現連接標題中的「關閉」標記以及「升級」標記,而規範說明需要「升級」標記,並且(幸運的是)不建議拒絕其他標記。

理論上,如果您使用了「選項http-pretend-keep-alive」,就像您評論過的那樣,它應該可以工作。至少它爲我做了。但也許這裏有一個不同的問題。