Closing WebSocket correctly (HTML5, Javascript)
Asked Answered
W

7

143

I am playing around with HTML5 WebSockets. I was wondering, how do I close the connection gracefully? Like, what happens if user refreshes the page, or just closes the browser?

There is a weird behavior when a user just refresh the page without calling websocket.close() - when they return after the refresh it will hit the websocket.onclose event.

Whipstall answered 27/1, 2011 at 4:16 Comment(0)
B
129

According to the protocol spec v76 (which is the version that browser with current support implement):

To close the connection cleanly, a frame consisting of just a 0xFF byte followed by a 0x00 byte is sent from one peer to ask that the other peer close the connection.

If you are writing a server, you should make sure to send a close frame when the server closes a client connection. The normal TCP socket close method can sometimes be slow and cause applications to think the connection is still open even when it's not.

The browser should really do this for you when you close or reload the page. However, you can make sure a close frame is sent by doing capturing the beforeunload event:

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

I'm not sure how you can be getting an onclose event after the page is refreshed. The websocket object (with the onclose handler) will no longer exist once the page reloads. If you are immediately trying to establish a WebSocket connection on your page as the page loads, then you may be running into an issue where the server is refusing a new connection so soon after the old one has disconnected (or the browser isn't ready to make connections at the point you are trying to connect) and you are getting an onclose event for the new websocket object.

Bumbailiff answered 27/1, 2011 at 15:51 Comment(2)
It is possible that in Firefox that the connection seems to hang around into the next page load. I can't find a reference but I think there may have been a bug about this. The other possibility is that the onclose event is triggered unexpectedly, or maybe on purpose, as the user navigates/page is reloaded. I've posted a question asking what the expected behaviour should be, which browser has it right and how we implement auto-reconnect.Volans
consider these problems with onbeforeunload eventBairn
R
38

The thing of it is there are 2 main protocol versions of WebSockets in use today. The old version which uses the [0x00][message][0xFF] protocol, and then there's the new version using Hybi formatted packets.

The old protocol version is used by Opera and iPod/iPad/iPhones so it's actually important that backward compatibility is implemented in WebSockets servers. With these browsers using the old protocol, I discovered that refreshing the page, or navigating away from the page, or closing the browser, all result in the browser automatically closing the connection. Great!!

However with browsers using the new protocol version (eg. Firefox, Chrome and eventually IE10), only closing the browser will result in the browser automatically closing the connection. That is to say, if you refresh the page, or navigate away from the page, the browser does NOT automatically close the connection. However, what the browser does do, is send a hybi packet to the server with the first byte (the proto ident) being 0x88 (better known as the close data frame). Once the server receives this packet it can forcefully close the connection itself, if you so choose.

Ringtail answered 1/12, 2011 at 14:11 Comment(3)
a practical example on the server side how to manage this hybi packet?Fennel
It seems insane that it doesn't close the connection. The WebSocket variable is wiped out on page reload, so why would the connection remain open if it can't be accessed? Reusing the connection wouldn't make sense either.Ticonderoga
Any code samples on how to send close frame from a websocket client(i.e Browser). I am using ws npm moduleTacy
W
36

Very simple, you close it :)

var myWebSocket = new WebSocket("ws://example.org"); 
myWebSocket.send("Hello Web Sockets!"); 
myWebSocket.close();

Did you check also the following site And check the introduction article of Opera

Woodprint answered 27/1, 2011 at 4:19 Comment(0)
B
5

As mentioned by theoobe, some browsers do not close the websockets automatically. Don't try to handle any "close browser window" events client-side. There is currently no reliable way to do it, if you consider support of major desktop AND mobile browsers (e.g. onbeforeunload will not work in Mobile Safari). I had good experience with handling this problem server-side. E.g. if you use Java EE, take a look at javax.websocket.Endpoint, depending on the browser either the OnClose method or the OnError method will be called if you close/reload the browser window.

Bairn answered 17/1, 2015 at 11:22 Comment(1)
In my case, Connection is getting closed during data transfer, It works well in case of Opera and iOS family browsers. Please help me out.. I am fighting with this issue since last two weeks. https://mcmap.net/q/160753/-file-transfer-from-browser-to-locally-connected-iphone/2225439Repulse
R
4

please use this

var uri = "ws://localhost:5000/ws";
var socket = new WebSocket(uri);
socket.onclose = function (e){
    console.log(connection closed);
};
window.addEventListener("unload", function () {
    if(socket.readyState == WebSocket.OPEN)
        socket.close();
});

Close browser doesn't trigger websocket close event. You must call socket.close() manually.

Ranit answered 13/1, 2021 at 9:51 Comment(1)
Looks like, as @Bairn says, the unload event isn't reliable.Ullman
F
1

By using close method of web socket, where you can write any function according to requirement.

var connection = new WebSocket('ws://127.0.0.1:1337');
    connection.onclose = () => {
            console.log('Web Socket Connection Closed');
        };
Feder answered 19/6, 2018 at 12:5 Comment(0)
J
1

The beforeunload event should be avoided. From MDN:

Especially on mobile, the beforeunload event is not reliably fired.

Additionally, it should only be used for saving user data, not closing out a websocket connection.

Rather than closing the connection on beforeunload, I would use the pagehide or (fallback) unload event, as the Chrome developer documentation suggests.

const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
window.addEventListener(terminationEvent, (event) => {
    if (event.persisted === false) {
        // client is gone
        socket.onclose = function () { };
        socket.close();
    }
});

Besides being recommended by the spec, the advantage of this approach is that you can still have a prompt confirming the user wants to leave (window.addEventListener("beforeunload", () => return "Are you sure?");) without disconnecting the user if they choose to stay on the page. As the Chrome docs say (emphasis added):

The document is still visible and the event is still cancelable at this point.

This could result in unintended closing of the websocket connection if the user doesn't actually leave the page.

Jud answered 12/1, 2023 at 1:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.