2012-10-23 33 views
5

Korzystając z najnowszej przeglądarki Chrome, próbuję użyć klienta sockjs do komunikacji z serwerem zaplecza, który znajduje się za haproxy. Na moim localhost (bez haproxy w środku), działa to dobrze - klient może łączyć się, wysyłać i odbierać wiadomości przy użyciu protokołu websocket. Na przykład:Uwierzytelnianie Websocket wisi z HAProxy

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

Kiedy wdrożyć go na serwerze z HAProxy, dziwne rzeczy się dzieje, że sockjs uważa, że ​​połączenie jest otwarte (jak w conn.readyState === SockJS.OPEN i „msg wysłane” pojawia się w dzienniku konsoli), jednak websocket handshake po prostu się zawiesza i msg nigdy nie jest odbierany przez serwer. Poniżej jest to, co widzę w dzienniku 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" 

Zauważ, że drugi log msg pojawia się tylko wtedy wyłączyć serwer backend za haproxy. Przed zamknięciem nie występuje błąd w dzienniku, ale uzgadnianie websocket nie kończy się i serwer nie otrzymuje wiadomości.

Używanie narzędzi deweloperskich Chrome jest w zakładce Network, widzę następujące:

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 

i obie „typ” i „czas uśpienia” z websocket obiektu show „Czeka” na karcie sieciowej narzędzia deweloperskie.

Wreszcie, jest to mój haproxy config (wersja 01.04.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 

Czy ktoś wie dlaczego tak się dzieje? Czy jest to spowodowane pewną konfiguracją haproxy, czy nawet ogólnymi ustawieniami sieci serwera (np. iptables)?

P.S. Próbowałem, umożliwiając http-pretend-keepalive w haproxy, ale to nie działa.

Odpowiedz

1

Najprawdopodobniej masz przezroczysty firewall w sieci i to bałagan połączeń websocket zamiar porcie 80.

Aby sprawdzić, czy jest to przypadek:

  1. Producent haproxy nasłuchiwać na innym porcie i spróbować, jeśli zaczęło działać;
  2. Spróbuj uzyskać dostęp do swojej usługi poza swoją siecią.

Jeśli zacznie działać, oznacza to, że w sieci jest coś nie tak.

Niestety, SockJS nie będzie korzystać z transportu zastępczego w tym przypadku, ponieważ klient uważa, że ​​jest on połączony, ale połączenie nie zostało nawiązane.

Możliwe rozwiązanie: wykonaj haproxy nasłuch na dwóch portach, na porcie 80 dla ruchu w sieci i na innym porcie dla ruchu SockJS. Gwarantuje to, że przezroczyste serwery proxy HTTP nie będą mieszały się z połączeniami websocket.

1

Już spotkałem się z tym przypadkiem, nie pamiętam, który to serwer, ale nie był całkowicie zgodny ze specyfikacją WebSocket. Rzeczywiście, nie udało się, ponieważ znalazł token "close" w nagłówku Connection, wraz z tokenem "Upgrade", podczas gdy specyfikacja mówi, że token "Upgrade" jest potrzebny i (na szczęście) nie sugeruje odrzucania innych.

Teoretycznie, jeśli użyjesz "opcji http-pretend-keep-alive", skomentowałeś, to powinno działać. Przynajmniej dla mnie. Ale może jest tu inny problem.

2

Tak jak @Joes powiedział, jest to wina niewłaściwie działających zapór ogniowych. Niektórzy mówią, że na przykład FortiGate to powoduje.

Więcej dyskusja: https://github.com/sockjs/sockjs-client/issues/94

serwowania SockJS ponad SSL wydaje się rozwiązać problem.