2011-10-03 18 views
25

por lo que entiendo el concepto de eventos enviados por el servidor (EventSource):¿Cómo funcionan realmente los eventos enviados por el servidor?

  • Un cliente se conecta a un punto final a través de EventSource
  • cliente se limita a escuchar a los mensajes enviados desde el punto final

Lo Estoy confundido acerca de cómo funciona en el servidor. He echado un vistazo a diferentes ejemplos, pero el que viene a la mente es el de Mozilla: http://hacks.mozilla.org/2011/06/a-wall-powered-by-eventsource-and-server-sent-events/

Ahora bien, esto puede ser solo un mal ejemplo, pero tiene sentido cómo funcionaría el servidor, como yo lo entiendo :

  • Algo cambia en un almacén de datos, como por ejemplo una base de datos
  • a del lado del servidor encuestas de guión el almacén de datos cada enésimo segundo
  • Si la secuencia de comandos de sondeo da cuenta de un cambio, un evento enviados por el servidor se dispara y se los clientes

¿Tiene sentido? ¿Es así realmente como funciona desde una perspectiva básica?

Respuesta

40

El sitio del doctor HTML5 tiene un great write-up en eventos enviados por el servidor, pero intentaré proporcionar aquí un resumen (razonablemente) breve también.

Los eventos enviados por el servidor son, en esencia, una conexión http de larga ejecución, un tipo de mime especial (text/event-stream) y un agente de usuario que proporciona la API EventSource. Juntos, estos constituyen la base de una conexión unidireccional entre un servidor y un cliente, donde los mensajes pueden enviarse del servidor al cliente.

En el lado del servidor, es bastante simple. Todo lo que necesita hacer es configurar las siguientes cabeceras http:

Content-Type: text/event-stream 
Cache-Control: no-cache 
Connection: keep-alive 

Asegúrese de responder con el código 200 y no 204 o cualquier otro código, ya que esto hará que las aplicaciones de usuario compatibles para desconectar. Además, asegúrese de no finalizar la conexión en el lado del servidor. Ahora puede comenzar a enviar mensajes a través de esa conexión. En nodejs (usando expreso), esto podría ser algo como lo siguiente:

app.get("/my-stream", function(req, res) { 
    res.status(200) 
     .set({ "content-type" : "text/event-stream" 
      , "cache-control" : "no-cache" 
      , "connection" : "keep-alive" 
      }) 

    res.write("data: Hello, world!\n\n") 
}) 

En el cliente, sólo tiene que utilizar la API EventSource, como usted señaló:

var source = new EventSource("/my-stream") 
source.addEventListener("message", function(message) { 
    console.log(message.data) 
}) 

Y eso es todo, básicamente.

Ahora, en la práctica, lo que realmente sucede aquí es que la conexión se mantiene viva por el servidor y el cliente por medio de un contrato mutuo. El servidor mantendrá la conexión activa durante el tiempo que considere oportuno. Si lo desea, puede finalizar la conexión y responder con un 204 No Content la próxima vez que el cliente intente conectarse. Esto hará que el cliente deje de intentar reconectarse. No estoy seguro de si hay una forma de finalizar la conexión de forma que se le indique al cliente que no se vuelva a conectar, salteándose así el cliente que intenta volver a conectarse una vez.

Como el cliente mencionado mantendrá la conexión activa también, e intentará volver a conectar si se cae. El algoritmo para reconectar se especifica en el spec, y es bastante directo.

Un bit muy importante que hasta ahora apenas he tocado es el tipo de mimo. El tipo de mime define el formato del mensaje que baja por la conexión. Sin embargo, tenga en cuenta que no dicta el formato del contenido de los mensajes, solo la estructura de los mensajes mismos. El tipo de mimo es extremadamente directo. Los mensajes son esencialmente pares de información clave/valor. La clave debe ser una de un conjunto predefinido:

  • id - el identificador del mensaje
  • de datos - los datos reales
  • de eventos - el tipo de evento
  • reintento - milleseconds el agente de usuario debe esperar antes de reintentar una conexión fallida

Se deben ignorar las demás teclas. Mensajes se delimitan mediante el uso de dos caracteres de nueva línea: \n\n

El siguiente es un mensaje válido: (últimos caracteres de nueva línea añaden a la verbosidad)

data: Hello, world! 
\n 

El cliente verá esto como: Hello, world!.

Como es la siguiente:

data: Hello, 
data: world! 
\n 

El cliente verá esto como: Hello,\nworld!.

Eso resume bastante bien lo que los eventos enviados por el servidor son: una conexión http de larga ejecución que no está en caché, un tipo de mime y una API javascript simple.

Para obtener más información, sugiero leer el specification. Es pequeño y describe las cosas muy bien (aunque los requisitos del lado del servidor podrían resumirse un poco mejor). Recomiendo leer el comportamiento esperado con ciertos códigos de estado http, por ejemplo.

+3

Esto es genial para los detalles sobre el cliente y cómo funciona la conexión, pero si el evento necesita ser enviado para un cambio de base de datos, ¿supongo que no hay otra opción que sondear constantemente la base de datos en el servidor? Creo que esto es lo que estaba preguntando la operación. ¿Existe una solución más eficiente del lado del servidor? Obviamente, no se necesitarían muchas conexiones en un servidor de pequeñas empresas para comenzar a ralentizar las cosas si hay bucles buscando constantemente cambios de DB. –

+1

El cliente simplemente recibe un mensaje cada vez que el servidor decide enviar uno, nunca sondea nada. El servidor es libre de descubrir por sí mismo cuándo y por qué enviar un mensaje. Eso puede ser implementado en el lado del servidor usando encuestas o cualquier técnica que se ajuste a la factura. Las conexiones en el servidor se podrían agrupar y se podría enviar un mensaje por cada conexión, lo que le daría una especie de funcionalidad de transmisión. Por lo tanto, el servidor podría ser la única conexión a un DB, pero transmitir a toneladas de clientes conectados al servidor. Creo que la pregunta era más general que eso sin embargo. –

+2

Que reintento: milisegundos bit - genio! Me salvó la piel! –

Cuestiones relacionadas