2012-10-23 29 views
5

Với trình duyệt Chrome mới nhất, tôi đang cố gắng sử dụng sockjs ứng dụng khách để liên lạc với máy chủ phụ trợ phía sau haproxy. Trên localhost của tôi (không có haproxy ở giữa), điều này hoạt động tốt - khách hàng có thể kết nối, gửi và nhận tin nhắn bằng giao thức websocket. Ví dụ:Websocket handshake treo cứng với HAProxy

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

Khi tôi triển khai nó trên máy chủ với HAProxy, điều kỳ lạ xảy ra mà sockjs nghĩ kết nối được mở (như trong conn.readyState === SockJS.OPEN và 'msg gửi' xuất hiện trong giao diện điều khiển log), tuy nhiên, websocket bắt tay chỉ đơn giản là treo và msg là không bao giờ nhận được bởi máy chủ. Dưới đây là những gì tôi nhìn thấy trong log 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" 

Chú ý rằng các bản ghi thứ hai msg chỉ xuất hiện khi tôi tắt máy tính, máy chủ backend đằng sau haproxy. Trước khi tắt máy, không có lỗi trong nhật ký nhưng việc bắt tay websocket không hoàn thành và không nhận được tin nhắn từ máy chủ.

Sử dụng công cụ phát triển của Chrome, tại tab Network, tôi thấy như sau:

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 

Và cả hai 'Loại' và 'Thời gian trễ' của đối tượng cho thấy websocket 'chờ' dưới tab mạng lưới Những công cụ phát triển.

Cuối cùng, đây là haproxy cấu hình của tôi (phiên bản 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 

Có ai biết tại sao điều này đang xảy ra? Có phải do một số cấu hình haproxy hoặc thậm chí một số cài đặt mạng chung của máy chủ (ví dụ: iptables)?

P.S. Tôi đã thử kích hoạt http-pretend-keepalive trong haproxy, nhưng nó không hoạt động.

Trả lời

1

Nhiều khả năng, bạn có tường lửa trong suốt trong mạng của bạn và nó messes lên các kết nối WebSocket đi đến cổng 80.

Để xác minh đó là trường hợp:

  1. Make haproxy lắng nghe trên cổng khác nhau và thử nếu nó bắt đầu hoạt động;
  2. Thử truy cập dịch vụ của bạn bên ngoài mạng của bạn.

Nếu nó bắt đầu hoạt động, thì có sự cố với mạng của bạn.

Thật không may, SockJS sẽ không sử dụng phương tiện dự phòng trong trường hợp này, vì khách hàng nghĩ rằng nó được kết nối, nhưng kết nối không thực sự được thiết lập.

Giải pháp có thể: làm cho haproxy lắng nghe trên hai cổng, trên cổng 80 cho lưu lượng truy cập web của bạn và cổng khác cho lưu lượng truy cập SockJS. Điều này đảm bảo rằng các proxy HTTP trong suốt sẽ không gây rối với các kết nối websocket của bạn.

1

Tôi đã gặp phải trường hợp này, tôi không nhớ máy chủ đó là gì, nhưng nó không hoàn toàn tương thích với đặc tả WebSocket. Thật vậy, nó không thành công vì nó tìm thấy mã thông báo "đóng" trong tiêu đề Kết nối, cùng với mã thông báo "Nâng cấp", trong khi thông số nói rằng mã "Nâng cấp" là cần thiết và (may mắn thay) không đề xuất loại bỏ mã thông báo khác.

Về lý thuyết, nếu bạn sử dụng "tùy chọn http-giả vờ-giữ-sống" như bạn đã nhận xét, nó sẽ hoạt động. Ít nhất là nó đã làm cho tôi. Nhưng có thể có một vấn đề khác ở đây.

2

Giống như @Joes cho biết, đó là lỗi của tường lửa không đúng. Một số người nói rằng, ví dụ như FortiGate gây ra điều đó.

Thảo luận nhiều hơn: https://github.com/sockjs/sockjs-client/issues/94

SockJS Phục vụ qua SSL dường như giải quyết vấn đề.

Các vấn đề liên quan