Usando eventos enviados pelo servidor
=====================================

O desenvolvimento de um aplicativo da Web que usa eventos enviados pelo servidor (en-US) é 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` (en-US):


```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 with JavaScript enabled. Enable JavaScript to view data.