4 pontos por GN⁺ 2024-03-19 | 1 comentários | Compartilhar no WhatsApp
  • Em apps web em tempo real, a escolha entre Long Polling, WebSockets, SSE, WebRTC e WebTransport para entregar eventos do servidor ao cliente muda bastante a latência, a bidirecionalidade, a dificuldade de implementação e as restrições operacionais
  • WebSockets oferecem comunicação bidirecional por uma única conexão de longa duração, mas em produção é comum usar bibliotecas como Socket.IO por causa de detecção de perda de conexão, reconexão e heartbeats de ping-pong
  • Server-Sent Events são um fluxo unidirecional de servidor→cliente baseado em HTTP, então a implementação e o tratamento de reconexão são mais simples, mas a API padrão EventSource tem limitações para enviar corpo POST ou cabeçalhos customizados
  • WebTransport suporta múltiplos streams e transporte confiável e não confiável com base em HTTP/3 QUIC, mas em março de 2024 ainda estava em Working Draft e sem suporte nativo no Safari e no Node.js, então ainda é difícil considerá-lo uma opção universal
  • Encerramento em segundo plano no mobile, limite de conexões por domínio, proxies e firewalls corporativos, e perda de eventos durante reconexões significam que apps reais também precisam de lógica de recuperação de sincronização e testes de infraestrutura

Evolução das tecnologias de comunicação em tempo real entre servidor e cliente

  • Em aplicações web em tempo real, a capacidade de o servidor enviar eventos ao cliente virou um requisito central
  • No início, o Long Polling, funcionando sobre HTTP, era usado como forma de mensagens entre servidor e cliente possível no navegador
  • Depois, os WebSockets surgiram como uma forma mais robusta de comunicação bidirecional
  • Server-Sent Events (SSE) oferecem de forma mais simples uma comunicação unidirecional apenas do servidor para o cliente
  • WebTransport tem potencial para se tornar uma abordagem mais eficiente, flexível e escalável, mas hoje ainda tem suporte limitado
  • WebRTC pode ser considerado para alguns casos de uso mais específicos de eventos entre servidor e cliente, mas tem um propósito diferente para ser tratado como opção principal

Long Polling

  • Long Polling é uma forma de simular comunicação push do servidor com requisições XHR comuns
  • Quando o cliente mantém uma requisição aberta para o servidor, o servidor segura a resposta até que haja novos dados
  • Depois de enviar a nova informação, a conexão é fechada, e o cliente imediatamente inicia a próxima requisição
  • Em comparação com o polling periódico tradicional, as atualizações chegam mais rápido e é possível reduzir tráfego de rede desnecessário e carga no servidor
  • Ainda assim, é menos eficiente do que tecnologias em tempo real como WebSockets, e pode haver latência dependendo do momento em que os dados são enviados
  • A implementação no cliente é simples, mas no backend é difícil garantir que clientes em reconexão não percam eventos

WebSockets

  • WebSockets criam uma única conexão de longa duração entre cliente e servidor e oferecem comunicação full-duplex
  • Depois que a conexão é estabelecida, ambos os lados podem enviar dados de forma independente sem o overhead do ciclo HTTP de requisição-resposta
  • São adequados para apps como chats em tempo real, jogos e plataformas financeiras, que exigem baixa latência e atualizações frequentes
  • A API básica de WebSocket é fácil de usar, mas em produção o tratamento de perda e recriação de conexão fica complexo
  • Como é difícil detectar se a conexão ainda está realmente utilizável, normalmente se adicionam heartbeats de ping-and-pong
  • Por essa complexidade, em muitos casos usa-se uma biblioteca como Socket.IO, que também oferece fallback para Long Polling quando necessário

Server-Sent Events

  • Server-Sent Events (SSE) são uma forma padrão de enviar atualizações do servidor para o cliente sobre HTTP
  • Diferentemente de WebSockets, foram projetados apenas para comunicação unidirecional servidor→cliente
  • São adequados para situações como feeds de notícias ao vivo, placares esportivos e atualizações em tempo real, em que o cliente não precisa enviar mensagens ao servidor
  • O SSE pode ser visto como uma única requisição HTTP que permanece aberta enquanto o backend vai transmitindo a resposta linha por linha à medida que eventos acontecem
  • No cliente do navegador, recebe-se o fluxo de eventos ao inicializar uma instância de EventSource
  • O EventSource, ao contrário de WebSockets, reconecta automaticamente quando a conexão cai
  • O servidor deve definir o cabeçalho Content-Type como text/event-stream e formatar campos como tipo do evento, payload de dados, ID do evento e tempo de retry de acordo com a especificação SSE

WebTransport

  • WebTransport é uma API para comunicação eficiente e de baixa latência entre clientes web e servidores
  • Ela usa o protocolo HTTP/3 QUIC para enviar dados por vários streams
  • Suporta tanto transporte confiável quanto não confiável, além de transmissão de dados sem ordenação
  • Pode ser uma ferramenta poderosa para apps que precisam de rede de alto desempenho, como jogos em tempo real, streaming ao vivo e plataformas colaborativas
  • Em março de 2024, o WebTransport estava em status de Working Draft e ainda não tinha suporte amplo
  • Ainda não pode ser usado no Safari e também não tem suporte nativo no Node.js
  • Mesmo quando o suporte se ampliar, a API é bastante complexa, então é provável que o uso aconteça mais por meio de bibliotecas construídas sobre WebTransport do que diretamente no código da aplicação

WebRTC

  • WebRTC é um projeto open source e um padrão de API que fornece recursos de comunicação em tempo real em navegadores e apps móveis sem plugins
  • Suporta conexões peer-to-peer para troca de áudio, vídeo e dados entre navegadores
  • Usa protocolos como ICE, STUN e TURN para atravessar NAT e firewalls
  • O WebRTC foi criado para interação cliente-cliente, mas também é possível usá-lo em comunicação servidor-cliente fazendo o servidor agir como se fosse um cliente
  • Como essa abordagem só serve para casos de uso de nicho, ela fica fora da comparação principal entre opções
  • Para o WebRTC funcionar, de qualquer forma é necessário um servidor de sinalização, que acabará rodando sobre WebSockets, SSE ou WebTransport
  • Por isso, o argumento de usar WebRTC como substituto direto dessas tecnologias fica mais fraco

Principais restrições por tecnologia

  • Transmissão de dados bidirecional

    • Apenas WebSockets e WebTransport suportam receber dados do servidor e enviar dados do cliente na mesma conexão
    • Long Polling até permite isso em teoria, mas não é recomendado porque enviar novos dados durante uma conexão long-polling existente exige outra requisição HTTP
    • No Long Polling, é melhor enviar dados cliente→servidor por uma requisição HTTP separada sem interferir na conexão já existente
    • SSE não suporta envio de dados adicionais para o servidor
    • A API nativa EventSource também não consegue enviar dados como POST no corpo HTTP nem mesmo na requisição inicial
    • Os dados acabam tendo de ir em parâmetros de URL, o que não é bom do ponto de vista de segurança, já que credentials podem vazar em logs do servidor, proxies e caches
    • O RxDB evita esse problema usando um polyfill de eventsource em vez da EventSource API nativa, e essa biblioteca adiciona recursos como cabeçalhos HTTP customizados
    • O fetch-event-source da Microsoft permite enviar dados no body e usar requisições POST em vez de GET
  • Limite de conexões por domínio

    • A maioria dos navegadores modernos permite 6 conexões por domínio, e esse limite restringe a usabilidade geral de abordagens estáveis de mensagens servidor→cliente
    • O limite de 6 conexões também é compartilhado entre abas do navegador, então se a mesma página estiver aberta em várias abas, elas precisarão dividir o mesmo pool de conexões
    • A RFC do HTTP/1.1 recomenda um número ainda menor: 2 conexões por servidor ou proxy
    • Essa política faz sentido para evitar DDoS usando visitantes, mas pode causar problemas quando uma comunicação legítima entre servidor e cliente precisa de várias conexões
    • Para contornar isso, é preciso usar HTTP/2 ou HTTP/3 para que o navegador abra apenas uma conexão por domínio e lide com os dados por multiplexação
    • Mesmo em HTTP/2 e HTTP/3, a configuração SETTINGS_MAX_CONCURRENT_STREAMS limita a quantidade real de streams simultâneos, e o padrão da maioria das configurações é 100 concurrent streams
    • O navegador até pode aumentar o limite para APIs específicas como EventSource, mas os issues relacionados no Chromium e no Firefox estão marcados como “won’t fix”
  • Reduzindo o número de conexões em apps de navegador

    • Em apps de navegador, é preciso assumir que o usuário pode abrir o app em várias abas ao mesmo tempo
    • Por padrão, cada aba pode abrir uma conexão própria de stream com o servidor, mas na maioria dos casos isso é desnecessário
    • É possível manter apenas uma conexão mesmo com várias abas abertas e compartilhá-la entre elas
    • O RxDB usa o pacote npm broadcast-channel com LeaderElection para manter apenas um replication stream entre servidor e cliente
    • Esse pacote também pode ser usado isoladamente em outras aplicações, sem depender do RxDB

Restrições operacionais em mobile, proxies e firewalls

  • Em sistemas operacionais móveis como Android e iOS, é difícil manter conexões abertas continuamente, incluindo WebSockets
  • O sistema operacional móvel pode colocar o app em segundo plano após um tempo de inatividade e encerrar conexões abertas
  • Esse comportamento faz parte da estratégia de gerenciamento de recursos para economizar bateria e otimizar desempenho
  • Por isso, desenvolvedores costumam usar notificações push móveis em vez de conexões persistentes quando o servidor precisa enviar dados ao cliente
  • As notificações push permitem que o servidor informe ao app sobre novos dados sem manter uma conexão aberta o tempo todo e podem induzir ações ou atualizações no app
  • Em ambientes corporativos, proxies e firewalls podem bloquear conexões que não sejam HTTP, dificultando colocar servidores WebSocket na infraestrutura
  • Nesses cenários, o SSE, por ser baseado em HTTP, pode ser uma forma mais fácil de integração corporativa
  • Long Polling também pode ser uma opção, já que usa apenas requisições HTTP comuns

Comparação de desempenho

  • Ao comparar WebSockets, SSE, Long Polling e WebTransport, é preciso considerar junto latência, throughput, carga no servidor e escalabilidade
  • O repositório realtime-web, que testou tempos de mensagem em uma implementação de servidor em Go, mostra resultados em que WebSockets, WebRTC e WebTransport têm desempenho semelhante
  • Como o WebTransport é uma tecnologia nova baseada em HTTP/3, mais otimizações de desempenho podem surgir após março de 2024
  • O WebTransport foi otimizado para reduzir consumo de energia, mas essa métrica não foi testada
  • Latência

    • WebSockets oferecem a menor latência por causa da comunicação full-duplex sobre uma única conexão persistente
    • SSE também oferece baixa latência na comunicação servidor→cliente, mas o cliente precisa de uma requisição HTTP adicional para enviar mensagens ao servidor
    • Long Polling tem latência maior porque cria uma nova conexão HTTP a cada envio de dados
    • No Long Polling, a latência pode aumentar bastante se, no momento em que o servidor tenta enviar um evento, o cliente estiver abrindo uma nova conexão
    • WebTransport deve oferecer baixa latência semelhante à de WebSockets, aproveitando a multiplexação mais eficiente e o congestion control do HTTP/3
  • Throughput

    • WebSockets podem atingir alto throughput graças à conexão persistente, mas problemas de backpressure, quando o cliente não consegue processar os dados na mesma velocidade em que o servidor envia, podem afetar o desempenho
    • SSE tem menos overhead que WebSockets e pode oferecer throughput potencialmente maior em broadcast unidirecional de servidor→cliente
    • Long Polling em geral tem throughput baixo e consome mais recursos do servidor por causa do overhead de abrir e fechar conexões com frequência
    • WebTransport deve suportar alto throughput tanto para streams unidirecionais quanto bidirecionais dentro de uma única conexão e pode superar WebSockets em cenários que exigem vários streams
  • Escalabilidade e carga no servidor

    • WebSockets podem aumentar bastante a carga no servidor à medida que o número de conexões mantidas cresce, afetando a escalabilidade em apps com muitos usuários
    • SSE tende a escalar melhor em cenários em que o principal requisito é enviar atualizações do servidor para o cliente
    • O SSE usa requisições HTTP comuns, sem procedimentos de WebSocket como protocol upgrade, então o overhead de conexão é menor
    • Long Polling é o menos escalável por causa da criação frequente de conexões e faz mais sentido apenas como mecanismo de fallback
    • WebTransport foi projetado com foco em alta escalabilidade com base na eficiência de conexões e streams do HTTP/3, e pode reduzir carga no servidor em relação a WebSockets e SSE

Recomendações por caso de uso

  • SSE é a opção mais direta de implementar e, por usar o protocolo HTTP/S existente, facilita evitar limitações de firewalls corporativos e outros problemas técnicos que aparecem com protocolos diferentes
  • Também é fácil de integrar ao Node.js e a outros frameworks de servidor
  • É adequado para apps como feeds de notícias, cotações de ações e streaming de eventos ao vivo, em que atualizações servidor→cliente acontecem com frequência
  • WebSockets são fortes em cenários que exigem comunicação bidirecional contínua
  • Em casos como jogos no navegador, aplicativos de chat e atualizações esportivas ao vivo com interação constante, costumam ser a principal escolha
  • WebTransport tem potencial, mas ainda não tem suporte amplo em frameworks de servidor e carece de compatibilidade com Node.js e Safari
  • O WebTransport depende de HTTP/3, e o suporte a HTTP/3 em muitos servidores web, como o nginx, ainda está em estado experimental
  • É uma tecnologia voltada para o futuro, com suporte a transporte confiável e não confiável, mas ainda não é uma escolha viável para a maioria dos casos de uso atuais
  • Long Polling é, em geral, uma abordagem ultrapassada por causa da ineficiência e do alto overhead de abrir repetidamente novas conexões HTTP
  • Pode ser usado como fallback em ambientes que não suportam WebSockets ou SSE, mas não é recomendado para uso geral por suas limitações de desempenho

Problema de perda de eventos durante reconexão

  • Ao construir funcionalidades sobre qualquer tecnologia de streaming em tempo real, é preciso considerar interrupções de conexão e reconexões
  • Se o cliente estiver conectando, reconectando ou offline, ele pode não receber no stream eventos que ocorram no servidor
  • Se o servidor transmite sempre o conteúdo completo, como cotações de ações, eventos perdidos podem não ser importantes
  • Se o backend transmite apenas resultados parciais, os eventos perdidos precisam ser tratados obrigatoriamente
  • Não escala bem fazer o backend lembrar quais eventos foram enviados com sucesso para cada cliente
  • É melhor tratar esse problema com lógica no lado do cliente
  • O RxDB Sync Engine usa dois modos de operação
    • checkpoint iteration mode: consulta repetidamente os dados do backend com requisições HTTP normais até o cliente voltar a ficar sincronizado
    • event observation mode: mantém o cliente sincronizado com atualizações do stream em tempo real
  • Quando a conexão do cliente cai ou ocorre um erro, a replicação muda temporariamente para checkpoint iteration mode até alcançar novamente o mesmo estado do servidor
  • Essa abordagem compensa eventos perdidos e permite que o cliente permaneça sempre sincronizado com o servidor no mesmo estado exato

O que verificar em infraestrutura corporativa

  • Em infraestrutura corporativa, podem ocorrer problemas com tecnologias de streaming em geral
  • Proxies e firewalls podem bloquear tráfego ou quebrar requisições e respostas de forma não intencional
  • Ao implementar um app em tempo real nesses ambientes, o primeiro passo é testar se a tecnologia escolhida realmente funciona nessa infraestrutura

1 comentários

 
GN⁺ 2024-03-19
Opiniões no Hacker News
  • Sempre tive um carinho por Server-Sent Events. É simples e fácil de usar/implementar

    • Com IPv6, agora é fácil torná-lo totalmente escalável e, se for feito direito, basta entregar ao cliente uma lista de serviços SSE para que ele funcione quase sem estado, ficando muito mais fácil de escalar
      WebSocket fica bem complicado de escalar quando o uso passa de certo nível
    • Por ser simples, dá para escalar com CDN com muito mais facilidade do que WebSocket: https://www.fastly.com/blog/server-sent-events-fastly
    • Concordo. Mas há um limite de 6 streams SSE por origem por instância do navegador, então, sem adicionar complexidade no lado do cliente, 6 abas pode ser o limite
      https://crbug.com/275955
    • A desvantagem é que é preciso codificar o payload em base64 ou remover quebras de linha
      Fico me perguntando por que não fizeram simplesmente como uma resposta de streaming multipart. Ela também suporta metadados e é um formato implementado de forma muito comum
    • Funciona até com Apache prefork comum e PHP
  • Há algumas desvantagens adicionais a considerar
    WebSocket não tem controle de fluxo (backpressure) nem multiplexação, então, se você precisar disso, tem que criar por conta própria ou usar algo como RSocket. SSE também não consegue enviar dados binários diretamente, exigindo uma codificação como base64
    WebTransport trata desses problemas e também resolve o bloqueio HOL, mas me preocupa que surja um problema parecido com a transição do Python 2→3 ou do IPv6, em que as pessoas tendem a continuar usando a versão existente e os benefícios do upgrade parecem pequenos
    Enquanto os navegadores continuarem funcionando via TCP, algumas redes podem simplesmente bloquear UDP e, portanto, HTTP/3/WebTransport

    • O bloqueio HOL é um problema, mas TCP oferece controle de fluxo. Se você não está usando isso, então está indo para cima de HTTP/3
      A preocupação de que a transição para WebTransport possa ser lenta é a mesma que se poderia ter dito antes sobre transporte TLS, HTTP/3 e XHR. Como a estrutura é dominada por alguns poucos motores de navegador importantes, a distribuição de novos recursos e protocolos de navegador é relativamente fácil
      Pela lógica de que algumas redes bloqueiam UDP porque TCP está disponível, seria parecido dizer que, como HTTP 1.1 sem TLS está disponível, HTTP/2 e TLS continuariam sendo bloqueados. Não é completamente falso, mas, olhando para a ampla adoção de HTTP/2 e especialmente de TLS, não parece ser um problema tão grande quanto se imagina
    • Sempre ouço falar de redes que bloqueiam UDP, mas nunca vi uma de fato. Muita coisa roda sobre UDP
      Talvez em um escritório pequeno ou em um ambiente corporativo distópico digno de filme alguém possa fechar isso, mas não entendo por que o fato de algumas redes poderem proibir UDP seria tão relevante. Algumas redes também bloqueiam google.com ou wikipedia.com, mas isso não faz esses serviços fracassarem
    • WebSocketStream chegará em breve ao Chrome e adiciona backpressure: https://chromestatus.com/feature/5189728691290112
    • Uma abordagem melhor que base64 é o binary-sse: https://github.com/luciopaiva/binary-sse
    • Nesse caso, HTTP/2 ainda deve funcionar, então a preocupação com multiplexação diminui
  • A explicação do texto sobre WebRTC não está correta. WebRTC cliente/servidor é possível mesmo sem um “servidor de sinalização” separado; o próprio servidor pode fazer a sinalização
    São necessárias apenas algumas viagens de ida e volta a mais, não um servidor separado. Canais de dados WebRTC funcionam muito bem como substitutos de WebSocket ou SSE, especialmente quando se quer evitar bloqueio HOL. Também há muitas bibliotecas, como Pion ou str0m, que fazem quase todo o trabalho
    A afirmação de que a API WebTransport é complexa também parece exagerada. Se você não precisa dos recursos avançados, pode ignorá-los; se quiser usá-la como WebSocket, basta abrir um único stream bidirecional e praticamente acabou. Para evitar bloqueio HOL, abra um stream por mensagem. É um pouco mais complexo, mas não a ponto de exigir obrigatoriamente uma biblioteca, e o GitHub Copilot provavelmente consegue até escrever o código. Ainda assim, o WebTransport ainda está amadurecendo, então não há muitas bibliotecas de servidor, e o suporte no Safari ainda está sendo aguardado

    • Acho estranho dizer que WebRTC cliente/servidor pode ser feito sem um “servidor de sinalização”
      Normalmente, o servidor de sinalização é implementado com WebSocket. A menos que você esteja propondo um bootstrap descentralizado dos clientes existentes, não dá para implementá-lo com o próprio WebRTC
  • Se você está criando para clientes com infraestrutura de TI tradicional de “enterprise” e “segurança”, é melhor adicionar um botão de atualizar e encerrar o assunto
    Na minha experiência nesses ambientes, o que sempre falhou — e não dava para consertar por causa de procedimentos intermináveis — foi justamente a tentativa de criar recursos em tempo real para esse tipo de cliente

    • Jetty/CometD faz fallback para long polling se outros métodos de transporte não funcionarem
    • Sinceramente, todas as tecnologias dessa família têm seus próprios problemas, e o botão de atualizar não é exceção
    • O navegador tem um botão de atualizar, mas provavelmente, se o usuário clicar nele, a aplicação vai quebrar
  • WebSocket e SSE viram uma grande dor de cabeça para gerenciar conforme a escala cresce. Especialmente no backend, é preciso ter observabilidade separada, e, se não forem implementados com muito cuidado em dispositivos móveis, a depuração no frontend vira um pesadelo
    Os dispositivos desligam ou desaceleram a rede para economizar bateria, ainda mais quando você não faz I/O explicitamente por meio de uma API dedicada
    Criar uma nova conexão é uma operação cara, e o servidor precisa armazenar estado em algum lugar. Se essa camada de armazenamento de estado tiver problemas, o cliente fica tentando de novo, atinge timeouts e fica preso para sempre a uma operação cara. Também não é uma forma de controlar facilmente a vazão enquanto impõe carga lentamente ao banco de dados
    Em termos de confiabilidade, pela minha experiência, long polling foi o melhor. Mesmo que um fluxo orientado a eventos seja realmente importante, é melhor ter uma arquitetura em duas camadas, em que o frontend faz long polling para um backend de camada 1, e essa camada 1 assina via WebSocket um backend de camada 2; o controle de confiabilidade fica muito melhor

    • Concordo totalmente. Já vi gente dar um tiro no próprio pé com WebSocket e SSE. Long polling tem custo, mas acho que é a abordagem mais explicável e escalável
    • SSE oferece suporte a long polling. Você pode fazer o servidor fechar a conexão quando quiser
      SSE oferece reconexão automática e também inclui o último ID visto, permitindo que o servidor continue sem interrupções
    • O artigo linkado aborda boa parte desses pontos, e o rxdb tem mecanismos que mitigam várias dessas preocupações
  • Não está no artigo, mas short polling também é relevante. Não é uma forma de enviar mensagens do servidor para o cliente, mas ainda é útil quando não há outra opção, como em hospedagem compartilhada
    Pela minha experiência, mesmo com um intervalo de polling longo — por exemplo, 20 segundos — funciona bastante bem se cada resposta vier junto com uma lista de mensagens. Quando o usuário aperta um botão, o cliente envia uma requisição ao servidor, e o servidor responde com os dados e a lista de mensagens mais recente, deixando o cliente atualizado

    • Também se aplica a dados que mudam rapidamente. Especialmente se a proporção de atualizações incluídas durante o polling for alta
  • Até hoje não entendo por que WebSocket e SSE ainda não oferecem suporte ao envio de headers como Authorization na requisição inicial. Eles acabam deixando toda a autenticação de serviços em tempo real nas mãos de quem implementa
    Talvez exista uma boa forma na especificação, mas já vi tantas abordagens diferentes que, a esta altura, dá para dizer que na prática não existe

    • A EventSource API deixa muito a desejar. Sou mantenedor do polyfill de EventSource mais usado, mas recentemente comecei um projeto que recria um cliente EventSource de forma mais moderna: https://github.com/rexxars/eventsource-client
      Além de lidar com headers customizados, ele também oferece suporte a todos os métodos de requisição (POST, PATCH etc.), inclusão de corpo na requisição, assinatura de eventos nomeados e definição do last event ID inicial. Também pode ser usado como iterador assíncrono
      Gosto da simplicidade de Server-Sent Events, mas a API EventSource parece ter sido implementada às pressas e simplesmente deixada como estava
      [1]: https://github.com/eventsource/eventsource
    • A requisição inicial não pode enviar todos os headers HTTP padrão, além de cookies?
    • Cookies são enviados
    • Também há certificados TLS
    • Venho usando isso há anos; estou deixando passar alguma coisa?
  • Pode ser uma ideia ingênua, mas, assumindo HTTP/2 ou superior, a combinação de EventSource com fetch() para envio de mensagens parece tão boa quanto outros protocolos que usam uma única conexão TCP. Com HTTP/3, que usa UDP, é ainda melhor
    Isso partindo do pressuposto de que só é necessário manter a conexão enquanto a aba está em primeiro plano. Fico curioso para saber quais problemas apareceram quando tentaram essa abordagem na prática

    • Uma das limitações é que SSE é apenas texto, então não dá para enviar dados binários de forma eficiente. É preciso usar alguma codificação como base64
    • Há uma biblioteca que faz o que você quer
      https://www.npmjs.com/package/@microsoft/fetch-event-source
    • Eu pensei exatamente a mesma coisa. Com HTTP/2 e SSE, parece que 99% do problema estaria resolvido
      Fiquei curioso para saber se seria possível levar SSE mais longe, reduzindo ainda mais latência, uso de memória e recursos de CPU, em vez de fazer algo completamente diferente
    • Se o principal caso de uso for servidor→cliente, então sim
  • Acho meio curioso ver textos assim. No fim dos anos 90, projetei um sistema de leilões online, e não havia absolutamente nenhuma requisição XHR
    Todas as atualizações em tempo real eram tratadas com server-push/streaming HTTP. Na época, não era fácil lidar com todas as conexões abertas, mas, com a arquitetura adequada, dava para chegar a uma escala aceitável

    • Passei muito tempo explicando às pessoas a importância do streaming HTTP, e definitivamente não é uma batalha fácil
      As vantagens de HTTP/2 ou HTTP/3 são ótimas, mas também é importante saber o que dá para aproveitar em HTTP 1.1, que é suportado praticamente em todos os lugares
  • Sinto um pouco de saudade do long polling. Comparado às tecnologias mais recentes, era realmente simples. Sinto isso mesmo achando que o WebRTC é o melhor

    • SSE não é particularmente mais complexo que long polling. A diferença é só que o servidor não fecha a conexão logo depois de enviar a resposta
      Em vez disso, ele volta a esperar por dados e envia respostas adicionais pelo mesmo stream
    • Eu queria que fosse simples assim, mas não é
      A rede do Second Life usa HTTPS com long polling para “canais de eventos”, e o servidor envia mensagens de evento ao cliente por esse canal. A maioria das mensagens vai por UDP, mas mensagens que precisam de criptografia ou são grandes vão pelo canal de eventos HTTPS/TCP
      No lado do cliente, o cliente em C++ usa libcurl, cujas configurações padrão de timeout não combinam com long polling. O libcurl derruba a conexão e cria uma nova requisição, e isso pode resultar em perda ou duplicação de mensagens
      No lado do servidor, o Apache fica na frente do servidor de simulação real para filtrar tentativas de conexão irrelevantes, mas o Apache também tem seus próprios timeouts, interrompendo conexões e fazendo o cliente tentar novamente
      Eles tentam evitar perdas com números de sequência das mensagens, mas o servidor do Second Life ignora os números de sequência que o cliente devolve como confirmação. Alguns servidores compatíveis do Open Simulator também pulam números sequenciais
      O resultado é um sistema baseado em HTTPS que pode perder ou duplicar mensagens que deveriam ser confiáveis. Se algumas mensagens forem perdidas, a atividade do usuário dentro do jogo simplesmente para
      As pessoas que projetaram isso foram embora há muito tempo, e os funcionários atuais não sabiam o quanto essa confusão era grave. Usuários externos tiveram que encontrar e documentar o problema, e funcionários da empresa estão tentando corrigi-lo há meses. Parece difícil o bastante para que, no momento, estejam adiando o trabalho
      Portanto, long polling não é “simples a ponto de ser idiota”. A abordagem correta provavelmente é enviar mensagens de keep-alive com frequência suficiente para que as camadas TCP e HTTPS não deem timeout. Assim, Apache e libcurl permanecem em um caminho que funciona bem
    • Ainda é usado com frequência. Há muitas aplicações em que faz sentido aceitar o overhead das requisições em troca de manter tudo dentro do contexto de uma API HTTP existente
    • Hoje em dia ainda dá para usar long polling com HTTP/2, e ele não vai desaparecer