Cerrar WebSocket correctamente (HTML5, Javascript)

127

Estoy jugando con HTML5 WebSockets. Me preguntaba, ¿cómo cierro la conexión con gracia? ¿Qué sucede si el usuario actualiza la página o simplemente cierra el navegador?

Hay un comportamiento extraño cuando un usuario simplemente actualiza la página sin llamar websocket.close(); cuando regresa después de la actualización, llegará al websocket.oncloseevento.

Andy Hin
fuente

Respuestas:

111

De acuerdo con la especificación de protocolo v76 (que es la versión que implementa el navegador con soporte actual):

Para cerrar la conexión limpiamente, se envía una trama que consta de solo un byte 0xFF seguido de un byte 0x00 desde un par para solicitar que el otro cierre la conexión.

Si está escribiendo un servidor, debe asegurarse de enviar un marco cerrado cuando el servidor cierre una conexión de cliente. El método normal de cierre del socket TCP a veces puede ser lento y hacer que las aplicaciones piensen que la conexión aún está abierta incluso cuando no lo está.

El navegador realmente debería hacer esto por usted cuando cierre o vuelva a cargar la página. Sin embargo, puede asegurarse de que se envíe un marco cerrado capturando el evento beforeunload:

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

No estoy seguro de cómo puede obtener un evento onclose después de actualizar la página. El objeto websocket (con el controlador onclose) ya no existirá una vez que la página se vuelva a cargar. Si está intentando establecer de inmediato una conexión WebSocket en su página a medida que se carga la página, es posible que se encuentre con un problema en el que el servidor rechaza una nueva conexión tan pronto después de que la anterior se haya desconectado (o el navegador no esté listo) para hacer conexiones en el punto que está intentando conectarse) y obtiene un evento cerrado para el nuevo objeto websocket.

canaca
fuente
2
Es posible que en Firefox parezca que la conexión se cuelga en la carga de la página siguiente. No puedo encontrar una referencia, pero creo que puede haber un error al respecto. La otra posibilidad es que el oncloseevento se active inesperadamente, o tal vez a propósito, a medida que el usuario navega / la página se vuelve a cargar. He publicado una pregunta preguntando cuál debería ser el comportamiento esperado, qué navegador es el correcto y cómo implementamos la reconexión automática.
Leggetter
44
considere estos problemas con el onbeforeunloadevento
artkoenig
35

La cuestión es que hay 2 versiones principales de protocolo de WebSockets en uso hoy en día. La versión anterior que usa el [0x00][message][0xFF]protocolo, y luego está la nueva versión que usa paquetes formateados Hybi .

Opera y iPod / iPad / iPhones utilizan la versión de protocolo anterior, por lo que es realmente importante que se implemente la compatibilidad con versiones anteriores en los servidores WebSockets. Con estos navegadores que utilizan el protocolo anterior, descubrí que la actualización de la página, la navegación fuera de la página o el cierre del navegador hacen que el navegador cierre automáticamente la conexión. ¡¡Excelente!!

Sin embargo, con los navegadores que utilizan la nueva versión del protocolo (por ejemplo, Firefox, Chrome y eventualmente IE10), solo cerrar el navegador hará que el navegador cierre automáticamente la conexión. Es decir, si actualiza la página o se aleja de la página, el navegador NO cierra automáticamente la conexión. Sin embargo, lo que hace el navegador es enviar un paquete hybi al servidor con el primer byte (el identificador de protocolo) 0x88(mejor conocido como el marco de datos cercano). Una vez que el servidor recibe este paquete, puede cerrar la conexión por la fuerza, si así lo desea.

theoobe
fuente
44
¿Un ejemplo práctico en el lado del servidor de cómo administrar este paquete hybi?
albanx
9
Parece una locura que no cierre la conexión. La variable WebSocket se borra en la recarga de la página, entonces, ¿por qué la conexión permanecería abierta si no se puede acceder? Reutilizar la conexión tampoco tendría sentido.
Triynko
@albanx revisa mi respuesta a continuación
artkoenig
Cualquier código de muestra sobre cómo enviar un marco cerrado desde un cliente websocket (es decir, navegador). Estoy usando el módulo ws npm
Shaik Syed Ali
3

Como mencionó theoobe , algunos navegadores no cierran los sockets web automáticamente. No intente manejar ningún evento de "cerrar ventana del navegador" del lado del cliente. Actualmente no hay una forma confiable de hacerlo, si considera la compatibilidad con los principales navegadores de escritorio y móviles (por ejemplo onbeforeunload, no funcionará en Mobile Safari). Tenía buena experiencia con el manejo de este problema del lado del servidor. Por ejemplo, si usa Java EE, eche un vistazo a javax.websocket.Endpoint , dependiendo del navegador, se llamará al OnClosemétodo o al OnErrormétodo si cierra / recarga la ventana del navegador.

artkoenig
fuente
1
En mi caso, Connection se cierra durante la transferencia de datos, funciona bien en el caso de los navegadores de la familia Opera e iOS. Por favor, ayúdenme. Estoy luchando con este problema desde las últimas dos semanas. stackoverflow.com/q/30799814/2225439
Mrug
2

Mediante el uso del método de cierre de socket web, donde puede escribir cualquier función de acuerdo con los requisitos.

var connection = new WebSocket('ws://127.0.0.1:1337');
    connection.onclose = () => {
            console.log('Web Socket Connection Closed');
        };
Akanksha Raizada
fuente