Đóng WebSocket chính xác (HTML5, Javascript)


127

Tôi đang chơi xung quanh với HTML5 WebSockets. Tôi đã tự hỏi, làm thế nào để tôi đóng kết nối duyên dáng? Giống như, điều gì xảy ra nếu người dùng làm mới trang hoặc chỉ đóng trình duyệt?

Có một hành vi kỳ lạ khi người dùng chỉ làm mới trang mà không gọi websocket.close()- khi họ quay lại sau khi làm mới, nó sẽ đánh websocket.onclosesự kiện.

Câu trả lời:


110

Theo giao thức spec v76 (là phiên bản mà trình duyệt có hỗ trợ hiện tại thực hiện):

Để đóng kết nối một cách sạch sẽ, một khung chỉ bao gồm một byte 0xFF theo sau là một byte 0x00 được gửi từ một đồng đẳng để yêu cầu các đồng nghiệp kia đóng kết nối.

Nếu bạn đang viết một máy chủ, bạn nên đảm bảo gửi một khung đóng khi máy chủ đóng kết nối máy khách. Phương thức đóng socket TCP bình thường đôi khi có thể bị chậm và khiến các ứng dụng nghĩ rằng kết nối vẫn mở ngay cả khi không.

Trình duyệt thực sự sẽ làm điều này cho bạn khi bạn đóng hoặc tải lại trang. Tuy nhiên, bạn có thể đảm bảo một khung đóng được gửi bằng cách chụp sự kiện trước khi tải:

window.onbeforeunload = function() {
    websocket.onclose = function () {}; // disable onclose handler first
    websocket.close();
};

Tôi không chắc chắn làm thế nào bạn có thể nhận được một sự kiện được đăng tải sau khi trang được làm mới. Đối tượng websocket (với trình xử lý đóng gói) sẽ không còn tồn tại sau khi trang tải lại. Nếu bạn ngay lập tức cố gắng thiết lập kết nối WebSocket trên trang của mình khi tải trang, thì bạn có thể gặp phải sự cố khi máy chủ từ chối kết nối mới ngay sau khi kết nối cũ bị ngắt kết nối (hoặc trình duyệt chưa sẵn sàng để tạo kết nối tại điểm bạn đang cố gắng kết nối) và bạn đang nhận được một sự kiện được đóng gói cho đối tượng websocket mới.


2
Có thể trong Firefox, kết nối dường như bị treo trong lần tải trang tiếp theo. Tôi không thể tìm thấy một tài liệu tham khảo nhưng tôi nghĩ có thể có một lỗi về điều này. Khả năng khác là onclosesự kiện được kích hoạt bất ngờ, hoặc có thể có chủ đích, khi người dùng điều hướng / trang được tải lại. Tôi đã đăng một câu hỏi hỏi hành vi dự kiến ​​sẽ là gì, trình duyệt nào có quyền và cách chúng tôi thực hiện tự động kết nối lại.
Leggetter

4
xem xét những vấn đề này với onbeforeunloadsự kiện
artkoenig


35

Vấn đề của nó là có 2 phiên bản giao thức chính của WebSockets được sử dụng hiện nay. Phiên bản cũ sử dụng [0x00][message][0xFF]giao thức, và sau đó là phiên bản mới sử dụng các gói được định dạng Hybi .

Phiên bản giao thức cũ được Opera và iPod / iPad / iPhone sử dụng, do đó, điều thực sự quan trọng là khả năng tương thích ngược được thực hiện trong các máy chủ WebSockets. Với các trình duyệt này sử dụng giao thức cũ, tôi phát hiện ra rằng làm mới trang hoặc điều hướng khỏi trang hoặc đóng trình duyệt, tất cả dẫn đến trình duyệt tự động đóng kết nối. Tuyệt quá!!

Tuy nhiên, với các trình duyệt sử dụng phiên bản giao thức mới (ví dụ: Firefox, Chrome và cuối cùng là IE10), chỉ đóng trình duyệt sẽ dẫn đến trình duyệt tự động đóng kết nối. Điều đó có nghĩa là, nếu bạn làm mới trang hoặc điều hướng khỏi trang, trình duyệt KHÔNG tự động đóng kết nối. Tuy nhiên, những gì trình duyệt làm, là gửi một gói hybi đến máy chủ với byte đầu tiên (nhận dạng proto) 0x88(được gọi là khung dữ liệu đóng). Khi máy chủ nhận được gói này, nó có thể tự đóng kết nối, nếu bạn chọn.


4
một ví dụ thực tế về phía máy chủ làm thế nào để quản lý gói hybi này?
albanx

9
Có vẻ điên rồ rằng nó không đóng kết nối. Biến WebSocket bị xóa trên tải lại trang, vậy tại sao kết nối vẫn mở nếu không thể truy cập? Sử dụng lại kết nối cũng không có ý nghĩa.
Triynko

@albanx kiểm tra câu trả lời của tôi dưới đây
artkoenig 17/1/2015

Bất kỳ mẫu mã nào về cách gửi khung đóng từ máy khách websocket (tức là Trình duyệt). Tôi đang sử dụng mô-đun ws npm
Shaik Syed Ali

3

Như được đề cập bởi theoobe , một số trình duyệt không tự động đóng websockets. Đừng cố xử lý bất kỳ sự kiện "đóng cửa sổ trình duyệt" nào phía máy khách. Hiện tại không có cách nào đáng tin cậy để làm điều đó, nếu bạn xem xét hỗ trợ các trình duyệt di động máy tính để bàn chính (ví dụ: onbeforeunloadsẽ không hoạt động trong Mobile Safari). Tôi đã có kinh nghiệm tốt với việc xử lý vấn đề này phía máy chủ. Ví dụ: nếu bạn sử dụng Java EE, hãy xem javax.websocket.Endpoint , tùy thuộc vào trình duyệt, OnClosephương thức hoặc OnErrorphương thức sẽ được gọi nếu bạn đóng / tải lại cửa sổ trình duyệt.


1
Trong trường hợp của tôi, Kết nối đang bị đóng trong khi truyền dữ liệu, Nó hoạt động tốt trong trường hợp trình duyệt gia đình Opera và iOS. Xin hãy giúp tôi ra .. Tôi đang chiến đấu với vấn đề này kể từ hai tuần trước. stackoverflow.com/q/30799814/2225439
Mrug

2

Bằng cách sử dụng phương pháp đóng của ổ cắm web, nơi bạn có thể viết bất kỳ chức năng nào theo yêu cầu.

var connection = new WebSocket('ws://127.0.0.1:1337');
    connection.onclose = () => {
            console.log('Web Socket Connection Closed');
        };
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.