Usando eventos enviados pelo servidor

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

io error: No such file or directory (os error 2) (/home/runner/work/yari/yari/mdn/translated-content/files/pt-br/web/api/server-sent_events/index.md)

O desenvolvimento de um aplicativo da Web que usa eventos enviados pelo servidor é simples. Você precisará de um pouco de código no servidor para transmitir eventos para o front-end, mas o código do lado do cliente funciona quase de forma idêntica a websockets em parte do tratamento eventos de entrada. Esta é uma conexão unidirecional, portanto, você não pode enviar eventos de um cliente para um servidor.

Recebendo eventos do servidor

A API de eventos enviados pelo servidor está contida na interface EventSource; para abrir uma conexão com o servidor para começar a receber eventos dele, crie um novo objeto EventSource com a URL de um script que gera os eventos. Por exemplo:

js
const evtSource = new EventSource("ssedemo.php");

Se o script do gerador de eventos estiver hospedado em uma origem diferente, um novo objeto EventSource deve ser criado com a URL e um dicionário de opções. Por exemplo, supondo que o script do cliente esteja em example.com:

js
const evtSource = new EventSource("//api.example.com/ssedemo.php", {
  withCredentials: true,
});

Depois de instanciar a origem do evento, você pode começar a ouvir as mensagens do servidor anexando um manipulador para o evento message:

js
evtSource.onmessage = (event) => {
  const newElement = document.createElement("li");
  const eventList = document.getElementById("list");

  newElement.textContent = `message: ${event.data}`;
  eventList.appendChild(newElement);
};

Este código escuta as mensagens recebidas (ou seja, avisos do servidor que não possuem um campo event) e anexa o texto da mensagem a uma lista no HTML do documento.

Você também pode escutar eventos com addEventListener():

js
evtSource.addEventListener("ping", (evento) => {
  const novoElemento = document.createElement("li");
  const eventList = document.getElementById("list");
  const time = JSON.parse(event.data).time;
  newElement.textContent = `ping em ${time}`;
  eventList.appendChild(newElement);
});

Este código é semelhante, exceto que será chamado automaticamente sempre que o servidor enviar uma mensagem com o campo event definido como "ping"; ele então analisa o JSON no campo data e gera essa informação.

Aviso: quando não usado em HTTP/2, o SSE sofre de uma limitação ao número máximo de conexões abertas, o que pode ser especialmente doloroso ao abrir várias guias, pois o limite é por navegador e é definido para um número muito baixo (6). O problema foi marcado como "Não será corrigido" no Chrome e no Firefox. Esse limite é por navegador + domínio, o que significa que você pode abrir 6 conexões SSE em todas as guias para www.example1.com e outras 6 conexões SSE para www.example2.com (por Stackoverflow). Ao usar HTTP/2, o número máximo de streams HTTP simultâneos é negociado entre o servidor e o cliente (o padrão é 100).

Enviando eventos do servidor

O script do lado do servidor que envia eventos precisa responder usando o tipo MIME text/event-stream. Cada notificação é enviada como um bloco de texto finalizado por um par de novas linhas. Para obter detalhes sobre o formato do fluxo de eventos, consulte Formato do fluxo de eventos.

O código PHP para o exemplo que estamos usando aqui segue:

php
date_default_timezone_set("America/New_York");
header("Cache-Control: no-store");
header("Content-Type: text/event-stream");

$counter = rand(1, 10);
while (true) {
  // A cada segundo, envia um evento "ping".

  echo "evento: ping\n";
  $curDate = date(DATE_ISO8601);
  echo 'data: {"time": "' . $curDate . '"}';
  echo "\n\n";

  // Envia uma mensagem simples em intervalos aleatórios.

  $counter--;

  if (!$counter) {
    echo 'data: Esta é uma mensagem no momento ' . $curDate . "\n\n";
    $counter = rand(1, 10);
  }

  ob_end_flush();
  flush();

  // Interrompe o loop se o cliente abortou a conexão (fechou a página)

  if (connection_aborted()) break;

  sleep(1);
}

O código acima gera um evento a cada segundo, com o tipo de evento "ping". Os dados de cada evento são um objeto JSON contendo o carimbo de data/hora ISO 8601 correspondente à hora em que o evento foi gerado. Em intervalos aleatórios, uma mensagem simples (sem tipo de evento) é enviada. O loop continuará funcionando independentemente do status da conexão, portanto, uma verificação é incluída para quebrar o loop se a conexão foi fechada (por exemplo, o cliente fecha a página).

você pode encontrar um exemplo completo que usa o código mostrado neste artigo no GitHub — veja [Simple SSE demo using PHP](https://github.com/mdn/dom-examples/tree/main /servidor-enviados-eventos).

Manipulação de erros

Quando ocorrem problemas (como um tempo limite de rede ou problemas relacionados a controle de acesso), um evento de erro é gerado. Você pode agir sobre isso programaticamente implementando o retorno de chamada onerror no objeto EventSource:

js
evtSource.onerror = (err) => {
  console.error("EventSource falhou:", err);
};

Fechando streams de eventos

Por padrão, se a conexão entre o cliente e o servidor for fechada, a conexão será reiniciada. A conexão é finalizada com o método .close().

js
evtSource.close();

Formato do fluxo de eventos

O fluxo de eventos é um fluxo simples de dados de texto que deve ser codificado usando UTF-8. As mensagens no fluxo de eventos são separadas por um par de caracteres de nova linha. Dois pontos como o primeiro caractere de uma linha é essencialmente um comentário e é ignorado.

Nota: A linha de comentário pode ser usada para evitar que as conexões atinjam o tempo limite; um servidor pode enviar um comentário periodicamente para manter a conexão ativa.

Cada mensagem consiste em uma ou mais linhas de texto listando os campos dessa mensagem. Cada campo é representado pelo nome do campo, seguido por dois pontos, seguido pelos dados de texto para o valor desse campo.

Campos

Cada mensagem recebida tem alguma combinação dos seguintes campos, um por linha:

event

Uma string que identifica o tipo de evento descrito. Se isso for especificado, um evento será despachado no navegador para o ouvinte para o nome do evento especificado; o código-fonte do site deve usar addEventListener() para ouvir eventos nomeados. O manipulador onmessage é chamado se nenhum nome de evento for especificado para uma mensagem.

data

O campo de dados para a mensagem. Quando o EventSource recebe várias linhas consecutivas que começam com data:, ele as concatena, inserindo um caractere de nova linha entre cada uma. As novas linhas à direita são removidas.

id

o ID do evento para definir o último valor do ID do evento do objeto EventSource.

retry

O tempo de reconexão. Se a conexão com o servidor for perdida, o navegador aguardará o tempo especificado antes de tentar se reconectar. Deve ser um número inteiro, especificando o tempo de reconexão em milissegundos. Se um valor não inteiro for especificado, o campo será ignorado.

Todos os outros nomes de campo são ignorados.

Nota: se uma linha não contiver dois pontos, a linha inteira será tratada como o nome do campo com uma string de valor vazia.

Exemplos

Mensagens somente de dados

No exemplo a seguir, há três mensagens enviadas. O primeiro é apenas um comentário, pois começa com dois pontos. Como mencionado anteriormente, isso pode ser útil como um mecanismo de manutenção se as mensagens não forem enviadas regularmente.

A segunda mensagem contém um campo de dados com o valor "algum texto". A terceira mensagem contém um campo de dados com o valor "outra mensagem\ncom duas linhas". Observe o caractere especial de nova linha no valor.

bash
: este é um fluxo de teste

dados: algum texto

dados: outra mensagem
dados: com duas linhas

Eventos nomeados

Este exemplo envia eventos nomeados. Cada um tem um nome de evento especificado pelo campo event e um campo data cujo valor é uma string JSON apropriada com os dados necessários para que o cliente atue no evento. O campo data pode, é claro, ter qualquer string de dados; não precisa ser JSON.

bash
evento: userconnect
data: {"username": "bobby", "time": "02:33:48"}

evento: mensagem do usuário
data: {"username": "bobby", "time": "02:34:11", "text": "Olá a todos."}

evento: userdisconnect
data: {"username": "bobby", "time": "02:34:23"}

evento: mensagem do usuário
data: {"username": "sean", "time": "02:34:36", "text": "Tchau, bobby."}

Misturando e combinando

Você não precisa usar apenas mensagens sem nome ou eventos digitados; você pode misturá-los em um único fluxo de eventos.

bash
evento: userconnect
data: {"username": "bobby", "time": "02:33:48"}

data: Aqui está uma mensagem do sistema de algum tipo que será usada
dados: para realizar alguma tarefa.

evento: mensagem do usuário
data: {"username": "bobby", "time": "02:34:11", "text": "Olá a todos."}

Especificações

Specification
HTML Standard
# the-eventsource-interface

Compatibilidade com navegadores

BCD tables only load in the browser