O HTTP / 2 torna os websockets obsoletos?

268

Estou aprendendo sobre o protocolo HTTP / 2. É um protocolo binário com pequenos quadros de mensagens. Permite a multiplexação de fluxo em uma única conexão TCP. Conceitualmente, parece muito semelhante ao WebSockets.

Existem planos para obsoletos websockets e substituí-los por algum tipo de solicitação HTTP / 2 sem cabeçalho e mensagens push iniciadas pelo servidor? Ou o WebSockets complementará o HTTP / 2?

vbezhenar
fonte
Acho que a resposta aceita está correta, os websockets ainda são a solução preferida para aplicativos da web se comunicarem com o servidor bidirecionalmente, incluindo mensagens enviadas pelo servidor. O HTTP é usado para mais do que apenas navegadores e, quando o cliente e o servidor podem usar a API de baixo nível, eles não precisam de websockets. Ainda assim, a maioria das pessoas usa HTTP para aplicativos da Web e se preocupa principalmente com APIs expostas a JavaScript. Se os moderadores pensam que a resposta aceita deve ser diferente, não me oponho a isso, pois essa pergunta aparentemente gera muitos pontos de vista e minha opinião pode estar errada.
vbezhenar 20/01

Respostas:

162

Pelo que entendi, o HTTP / 2 não substitui o websocket, mas visa padronizar o protocolo SPDY.

No HTTP / 2, o push do servidor é usado nos bastidores para melhorar o carregamento de recursos pelo cliente a partir do navegador. Como desenvolvedor, você realmente não se importa com isso durante o seu desenvolvimento. No entanto, com o Websocket, o desenvolvedor pode usar a API capaz de consumir e enviar mensagens com uma conexão full-duplex exclusiva.

Essas não são as mesmas coisas e devem se complementar.

Guillaume D.
fonte
3
Obrigado Guillaume pela sua resposta. No entanto, eu estou querendo saber se você (ou alguém) poderia adicionar alguma referência da especificação HTTP / 2. O que li de blogs e assim por diante - com HTTP / 2, há uma verdadeira comunicação bidirecional?
Martin Meeser
3
Não tenho certeza se a especificação HTTP / 2 é o lugar certo para fornecer detalhes sobre as origens do HTTP / 2 e como ela difere do websocket. No entanto, você pode ver facilmente que, com o HTTP / 2, estamos usando uma comunicação bidirecional: goo.gl/IJVxWS (páginas 6 e 13)
Guillaume D.
27
O HTTP / 2 é de fato bidirecional, mas não simétrico, o que significa que apenas o cliente pode enviar uma solicitação adequada e o servidor pode enviar respostas e promessas de solicitação (push). Isso torna os websockets diferentes no sentido de que ambas as partes são mais "iguais" em termos do que têm permissão para enviar / receber.
George Antoniadis
3
Existe um excelente podcast na Rádio de Engenharia de Software do IEEE sobre as origens do HTTP2. Eu acho que é isso: se-radio.net/2015/07/episode-232-mark-nottingham-on-http2
Max Murphy
2
resposta semelhante com lógica completa pode ser encontrada neste artigo InfoQ aqui: infoq.com/articles/websocket-and-http2-coexist
Mantrid
151

Depois de terminar de ler a especificação HTTP / 2 , acho que o HTTP / 2 faz websockets obsoletos na maioria dos casos de uso, mas talvez não todos.

PUSH_PROMISE(conhecido coloquialmente como push do servidor) não é o problema aqui. Isso é apenas uma otimização de desempenho.

O principal caso de uso para Websockets em um navegador é ativar o fluxo bidirecional de dados. Portanto, acho que a pergunta do OP passa a ser se o HTTP / 2 faz um trabalho melhor ao ativar o fluxo bidirecional no navegador, e acho que sim.

Primeiro de tudo, é bi-di. Basta ler a introdução à seção de fluxos :

Um "fluxo" é uma sequência bidirecional independente de quadros trocados entre o cliente e o servidor em uma conexão HTTP / 2. Os fluxos têm várias características importantes:

Uma única conexão HTTP / 2 pode conter vários fluxos abertos simultaneamente, com os quadros de intercalação de terminais de vários fluxos.

Os fluxos podem ser estabelecidos e usados ​​unilateralmente ou compartilhados pelo cliente ou servidor.

Os fluxos podem ser fechados por qualquer um dos pontos de extremidade.

Artigos como este (vinculados em outra resposta) estão errados sobre esse aspecto do HTTP / 2. Eles dizem que não é bidi. Olha, há uma coisa que não pode acontecer com o HTTP / 2: depois que a conexão é aberta, o servidor não pode iniciar um fluxo regular, apenas um fluxo push. Mas quando o cliente abre um fluxo enviando uma solicitação, os dois lados podem enviar quadros DATA através de um soquete persistente a qualquer momento - bidi completo.

Isso não é muito diferente dos websockets: o cliente precisa iniciar uma solicitação de atualização do websocket antes que o servidor também possa enviar dados.

A maior diferença é que, diferentemente dos websockets, o HTTP / 2 define sua própria semântica de multiplexação: como os fluxos obtêm identificadores e como os quadros carregam o ID do fluxo em que estão. O HTTP / 2 também define a semântica de controle de fluxo para priorizar fluxos. Isso é importante na maioria das aplicações do mundo real de bidi.

(Esse artigo errado também diz que o padrão Websocket tem multiplexação. Não, não tem. Não é realmente difícil descobrir isso, basta abrir o Websocket RFC 6455 e pressionar ⌘-F e digite "multiplex". Depois de ler

O protocolo pretende ser extensível; versões futuras provavelmente introduzirão conceitos adicionais, como multiplexação.

Você descobrirá que há uma extensão de rascunho de 2013 para a multiplexação do Websocket. Mas não sei quais navegadores, se houver, suportam isso. Eu não tentaria criar meu webapp SPA na parte de trás dessa extensão, especialmente com o HTTP / 2 chegando, o suporte pode nunca chegar).

A multiplexação é exatamente o tipo de coisa que você normalmente deve fazer sempre que abre um soquete da Web para bidi, por exemplo, para ativar um aplicativo de página única com atualização reativa. Estou feliz que esteja na especificação HTTP / 2, resolvida de uma vez por todas.

Se você quiser saber o que o HTTP / 2 pode fazer, consulte o gRPC. O gRPC é implementado no HTTP / 2. Veja especificamente as opções de streaming half e full duplex que o gRPC oferece. (Observe que o gRPC atualmente não funciona em navegadores, mas isso ocorre porque os navegadores (1) não expõem o quadro HTTP / 2 ao javascript do cliente e (2) geralmente não oferecem suporte a Trailers, que são usados ​​em a especificação gRPC.)

Onde os websockets ainda podem ter um lugar? O grande problema é servidor-> navegador empurrado dados binários. O HTTP / 2 permite dados binários enviados pelo servidor-> pelo navegador, mas não é exposto no JS do navegador. Para aplicativos como enviar quadros de áudio e vídeo, esse é um motivo para usar websockets.

Edição: 17/01 2020

Com o tempo, essa resposta subiu gradualmente até o topo (o que é bom, porque esta resposta é mais ou menos correta). No entanto, ainda existem comentários ocasionais dizendo que isso não está correto por vários motivos, geralmente relacionados a alguma confusão PUSH_PROMISEou como realmente consumir servidor orientado a mensagens -> envio de cliente em um aplicativo de página única. E há um caso de uso para websockets em um navegador, que são dados binários enviados por servidor. Para dados textuais, incluindo JSON, não use websockets, use SSE.

Para recapitular: o protocolo HTTP / 2 é bi-di completo. No entanto, os navegadores modernos não expõem o protocolo HTTP / 2 orientado a quadros ao JavaScript . No entanto, se você fizer várias solicitações para a mesma origem em uma conexão HTTP / 2, todo esse tráfego ficará multiplexado em uma conexão (e é com isso que nos preocupamos!).

Portanto, se você precisa criar um aplicativo de bate-papo em tempo real, digamos, onde você precisa transmitir novas mensagens de bate-papo para todos os clientes na sala de bate-papo que possuem conexões abertas, você pode (e provavelmente deve) fazer isso sem os websockets.

Você usaria eventos enviados pelo servidor para enviar mensagens para baixo e a API de busca para enviar solicitações. Eventos enviados pelo servidor (SSE) é uma API pouco conhecida, mas bem suportada, que expõe um fluxo de servidor para cliente orientado a mensagens. Embora não pareça com o JavaScript do cliente, seu navegador (se ele suporta HTTP / 2) reutilizará uma única conexão TCP para multiplexar todas essas mensagens. Não há perda de eficiência e, de fato, é um ganho em relação aos websockets. Precisa de vários fluxos? Abra várias fontes de eventos! Eles serão automaticamente multiplexados para você.

Além de serem mais eficientes em termos de recursos e com menos latência inicial do que um handshake de websocket, os Eventos Enviados pelo Servidor têm a propriedade agradável de que eles retornam automaticamente e trabalham com HTTP / 1.1. Mas quando você tem uma conexão HTTP / 2, eles funcionam incrivelmente bem.

Aqui está um bom artigo com um exemplo do mundo real de como realizar o SPA de atualização reativa.

masonk
fonte
21
Essa resposta discorda parcialmente das outras, incluindo a aceita, e também é a melhor resposta, pois se baseia em fontes diretas.
Sudo
7
Concordo plenamente com esta resposta e com o comentário. O HTTP / 2 é bidirecional baseado em fluxo.
Martin Meeser
3
Na verdade resposta correta, o cara deu ao trabalho de verificar as fontes e aplicação no mundo real (grpc)
Vladimir Akopyan
1
Nos websockets, o servidor não pode iniciar o envio de bytes arbitrários até que o cliente inicie uma solicitação de atualização do websocket, mas pode enviar a qualquer momento. No HTTP / 2, o servidor não pode iniciar o envio de bytes até que o cliente inicie uma conexão de dados, mas pode enviar bytes a qualquer momento. Qual a diferença funcional? Como eu apontei, o recurso PUSH_PROMISE é um arenque vermelho. Não é a razão pela qual o HTTP / 2 substitui os soquetes da web. É apenas uma pequena otimização de desempenho para o lado. Não tem nada a ver com o coração do HTTP / 2, que é o bidi streaming.
masonk
1
Esta resposta está simplesmente errada. Confunde tantos aspectos que é facilmente confuso. No entanto, o cerne da questão é que os fluxos HTTP / 2 "bidi" são orientados por resposta de solicitação (e limitados em número), enquanto o protocolo WebSockets é um protocolo bidirecional de mensagem verdadeira (não é baseado em resposta de solicitação, exceto para a fase do aperto de mão). Essa é uma enorme diferença que não pode ser superada apenas pela leitura incorreta da especificação (como o @masonk parece ter feito sem querer).
Myst
65

Eu digo Não ( Websockets não são obsoletos ).

O primeiro e mais frequentemente ignorado problema é que o envio HTTP / 2 não é aplicável e pode ser ignorado por proxies, roteadores, outros intermediários ou até pelo navegador.

ou seja (do rascunho HTTP2):

Um intermediário pode receber notificações do servidor e optar por não encaminhá-las para o cliente . Em outras palavras, como usar as informações enviadas depende desse intermediário. Da mesma forma, o intermediário pode optar por enviar push adicionais ao cliente, sem nenhuma ação do servidor.

Portanto, o HTTP / 2 Push não pode substituir WebSockets.

Além disso, as conexões HTTP / 2 fecham após um tempo.

É verdade que o padrão afirma que:

As conexões HTTP / 2 são persistentes. Para obter o melhor desempenho, espera-se que os clientes não fechem as conexões até que seja determinado que nenhuma comunicação adicional é necessária (por exemplo, quando um usuário navega para fora de uma página da web específica) ou até que o servidor feche a conexão.

Mas...

Os servidores são incentivados a manter as conexões abertas pelo maior tempo possível, mas podem terminar as conexões inativas, se necessário. Quando um dos terminais escolhe fechar a conexão TCP da camada de transporte, o terminal final DEVE enviar primeiro um quadro GOAWAY (Seção 6.8), para que ambos os terminais possam determinar com segurança se os quadros enviados anteriormente foram processados ​​e concluam ou finalizam graciosamente as tarefas restantes necessárias.

Mesmo que a mesma conexão permita enviar conteúdo enquanto está aberto e mesmo que o HTTP / 2 resolva alguns dos problemas de desempenho introduzidos pelo 'keep-alive' do HTTP / 1.1 ... as conexões HTTP / 2 não são mantidas abertas indefinidamente .

Uma página da Web também não pode reiniciar uma conexão HTTP / 2 depois de fechada (a menos que voltemos a puxar muito, isso é).

EDIT (2017, dois anos depois)

As implementações do HTTP / 2 mostram que várias guias / janelas do navegador compartilham uma única conexão HTTP / 2, o que significa que pushnunca saberá a qual guia / janela pertence, eliminando o uso pushcomo substituto dos Websockets.

EDIT (2020)

Não sei por que as pessoas começaram a votar de forma negativa. De qualquer forma, os anos desde que a resposta foi postada inicialmente provaram que o HTTP / 2 não pode substituir o WebSockets e não foi projetado para isso.

Concedido, o HTTP / 2 pode ser usado para encapsular conexões WebSocket, mas essas conexões encapsuladas ainda exigirão o protocolo WebSocket e afetarão a maneira como o contêiner HTTP / 2 se comporta.

Myst
fonte
4
Os soquetes do WS também não ficarão abertos para sempre. As diferenças são fluxos; O HTTP / 2 fornece vários fluxos de fluxo, o que significa que o controle de fluxo no servidor é muito diferente e geralmente sem bloqueio. O WS (como protocolo) precisa ter processamento de entrada não regulamentado. O controle de fluxo é implementado mais alto na pilha. Para segurança e integridade do servidor, o HTTP / 2 é muito melhor que o WS.
vínculo
4
@bond, eu concordo que o HTTP / 2 tem muitas vantagens como uma camada de transporte (compartilhar uma única conexão entre várias guias do navegador é apenas um exemplo). No entanto, ele não foi projetado como uma camada de comunicação . É uma questão funcional. Ambos os protocolos respondem a diferentes necessidades. ou seja, implementar um sshterminal no navegador é muito fácil ao usar Websockets. Seria uma dor de cabeça total no HTTP / 2, especialmente se mais de uma guia estiver aberta. Além disso, e se o navegador (ou um dos proxies HTTP / 2) fechar a conexão? O cliente pode simplesmente assumir que não há novos dados disponíveis? voltamos às pesquisas.
Myst
1
O navegador pode fechar facilmente sua conexão WS. Essa é a vida com qualquer tipo de rede. Para ser sincero, a multiplexação no HTTP / 2 é um exagero. O protocolo realmente não precisava dele. Com a abertura de vários fluxos, você começa a ter problemas com os buffers TCP que limitam a taxa de transferência. Concordo com você que o WS é melhor no que faz que HTTP / 2. Fundamentalmente, o WS é algo que precisa de muitos controles de nível superior para impedir que os usuários façam coisas ruins.
vínculo
2
Para citar o tio Ben (Homem-Aranha): "Lembre-se, com grande poder vem grande responsabilidade". Sim, @bond, você está muito certo. Websockets, sendo um protocolo muito "bruto", requer um design de servidor mais responsável. E sim, o WS pode ser fechado tão facilmente quanto o HTTP / 2, mas o WS suporta o oncloseretorno de chamada, portanto, nenhuma pesquisa é necessária. Quanto à multiplexação, acho que era uma necessidade e não uma escolha. keep-alivefalhou e a única maneira de evitar o "primeiro na linha" de desempenho foi arriscar a multiplexação. O tempo dirá :)
Myst
1
Do ponto de vista do design do servidor, a multiplexação de saída é um problema complicado e caro. Exige que a mecânica de IO faça pesquisas internas, o que é caro demais. A menos que você esteja transmitindo documentos grandes, a multiplexação nem funcionará porque a solicitação provavelmente terá respondido e armazenado em buffer totalmente internamente antes que o segundo se torne disponível e a multiplexação falhe na execução. O RTMP possui multiplexação de saída, mas apenas o servidor da Adobe faz isso. É incrível como o HTTP / 2 está próximo do RTMP.
vínculo
40

A resposta é não. O objetivo entre os dois é muito diferente. Existe até uma RFC para WebSocket sobre HTTP / 2 que permite fazer várias conexões WebSocket através de um único canal HTTP / 2 TCP.

O WS sobre HTTP / 2 será uma peça de conservação de recursos, diminuindo o tempo para abrir novas conexões e permitindo mais canais de comunicação sem a despesa adicional de mais soquetes, IRQs flexíveis e buffers.

https://tools.ietf.org/html/draft-hirano-httpbis-websocket-over-http2-01

vinculo
fonte
Isso é incrível! Existe algum exemplo público de um cliente Javascript que implementou isso? Não consigo encontrar nenhum exemplo. O que eu precisaria fazer? Esse é um bom recurso? undertow.io/blog/2015/04/27/An-in-depth-overview-of-HTTP2.html
RaisinBranCrunch
Alguém conhece uma fonte das reivindicações acima sobre 1) encontrar o comprimento do cabeçalho, 2) colocar os nomes dos campos em menor número?
Pim Heijden
A @PimHeijden que detecta o comprimento do cabeçalho no HTTP / 1.x requer um loop por todos os bytes que procuram o marcador final de 4 bytes. Isso é muito caro. A insensibilidade de maiúsculas e minúsculas dos nomes dos campos também significa que qualquer correspondência de campo deve ser feita para a versão maiúscula e minúscula dos caracteres. Isso requer conhecimento de todo o conjunto de caracteres em maiúsculas e minúsculas para as verificações. Na 2.x, você pode assumir que são minúsculas.
vínculo
@RaisinBranCrunch Você não pode controlar nada disso através do Javascript. O navegador faz tudo por você.
vínculo
@bond Atualmente, estou usando HTTP / 2 com Nginx e proxy_pass para enviar conexões de websocket a um servidor de soquete, mas quando tenho um único usuário aberto várias guias no site, o servidor de soquete o trata como várias conexões. Eu diria que, se o HTTP / 2 estiver multiplexando conexões em um pipe TCP, o servidor o tratará como uma conexão. Isso está errado? Existe alguma maneira de verificar se o servidor não está fazendo conexões extras desnecessárias?
RaisinBranCrunch
23

Bem, para citar este artigo da InfoQ :

Bem, a resposta é claramente não, por uma razão simples: Como vimos acima, o HTTP / 2 apresenta o Server Push, que permite ao servidor enviar proativamente recursos para o cache do cliente. No entanto, ele não permite enviar dados para o próprio aplicativo cliente. Os envios de servidor são processados ​​apenas pelo navegador e não são exibidos no código do aplicativo, o que significa que não há API para o aplicativo receber notificações para esses eventos.

E, portanto, o envio de HTTP2 é realmente algo entre o navegador e o servidor, enquanto os Websockets realmente expõem as APIs que podem ser usadas pelo cliente (javascript, se estiver sendo executado no navegador) e pelo código do aplicativo (executado no servidor) para transferir dados em tempo real.

Jeet Prakash
fonte
5

A troca de mensagens e o streaming simples (não o áudio, o streaming de vídeo) podem ser feitos via multiplexação Http / 2 e WebSockets. Portanto, há alguma sobreposição, mas os WebSockets têm protocolo bem estabelecido, muitas estruturas / APIs e menos sobrecarga de cabeçalhos. Aqui está um bom artigo sobre o tópico .

Dennis R
fonte
2

Haverá implementação do WebSocket no HTTP / 2. https://tools.ietf.org/html/rfc8441

Dzintars
fonte
Não, não haverá ... a conexão WebSocket será encapsulada através do HTTP / 2, mas o HTTP / 2 não substituirá o protocolo, nem ficará obsoleto.
Myst
@Myst Eu disse isso?
Dzintars 18/01
2
Não, você não disse isso, eu disse. Você escreveu que haverá uma implementação do WebSocket no HTTP / 2, que o IMHO parecia muito curto e um tanto enganoso devido à omissão de detalhes importantes.
Myst
2

Por enquanto, em abril de 2020, o HTTP / 2 não está tornando obsoletos os WebSockets. A maior vantagem do WebSockets sobre HTTP2 é que

HTTP/2 works only on Browser Level not Application Level

Significa que o HTTP / 2 não oferece nenhuma API JS como WebSockets para permitir a comunicação e transferir algum tipo de JSON ou outros dados para o servidor diretamente do Aplicativo (por exemplo, Site). Então, até onde eu acredito, o HTTP / 2 só tornará obsoletos os WebSockets se começar a oferecer API como WebSockets para conversar com o servidor. Até que seja apenas uma versão atualizada e mais rápida do HTTP 1.1.

Arejado
fonte
2

A partir de hoje, não.

O HTTP / 2, comparado ao HTTP, permite manter uma conexão com um servidor. A partir daí, você pode ter vários fluxos de dados ao mesmo tempo. A intenção é que você possa enviar várias coisas ao mesmo tempo, mesmo sem o cliente solicitando. Por exemplo, quando um navegador solicita a index.html, o servidor também pode pressionar index.csse index.js. O navegador não solicitou, mas o servidor pode fornecê-lo sem ser solicitado, pois pode presumir que você desejará em alguns segundos.

Isso é mais rápido do que o HTTP / 1 alternativa de obter index.html, analisá-lo, descobrindo que ele precisa index.jse index.csse , em seguida, a construção de 2 outras solicitações para esses arquivos. O HTTP / 2 permite que o servidor envie dados que o cliente nem solicitou.

Nesse contexto, é semelhante ao WebSocket, mas não por design. O WebSocket deve permitir uma comunicação bidirecional semelhante a uma conexão TCP ou serial. É um soquete onde os dois se comunicam. Além disso, a principal diferença é que você pode enviar pacotes de dados arbitrários em bytes brutos, não encapsulados no protocolo HTTP. Os conceitos de cabeçalhos, caminhos, cadeias de consulta só acontecem durante o handshake, mas o WebSocket abre um fluxo de dados.

A outra diferença é que você obtém muito mais acesso otimizado ao WebSocket em Javascript, enquanto que com o HTTP, ele é tratado pelo navegador. Tudo o que você obtém com HTTP é o que você pode caber no XHR/ fetch(). Isso também significa que o navegador irá começar a interceptar e modificar cabeçalhos HTTP sem você ser capaz de controlá-lo (por exemplo: Origin, Cookies, etc). Além disso, o que o HTTP / 2 é capaz de enviar por push é enviado ao navegador. Isso significa que o JS nem sempre (se é que sabe) sabe que as coisas estão sendo empurradas. Novamente, faz sentido index.csse index.jsporque o navegador o armazenará em cache, mas não muito para pacotes de dados.

É realmente tudo em nome. HTTP significa HyperText Transfer Protocol. Estamos voltados para o conceito de transferência de ativos. O WebSocket trata da construção de uma conexão de soquete na qual dados binários são transmitidos bidirecionalmente.


O que realmente não estamos discutindo é o SSE (Eventos Enviados pelo Servidor). Enviar dados para o aplicativo (JS) não é a intenção do HTTP / 2, mas é para o SSE. O SSE fica realmente fortalecido com o HTTP / 2. Mas não é um substituto real para o WebSockets quando o importante é os dados em si, não os pontos finais variáveis ​​atingidos. Para cada terminal no WebSocket, um novo fluxo de dados é criado, mas com o SSE é compartilhado entre a sessão HTTP / 2 já existente.


Resumidos aqui, estão os objetivos de cada um:

  • HTTP - responda a uma solicitação com um ativo
  • HTTP / 2 - responda a uma solicitação com vários ativos
  • SSE - Responda com um fluxo de eventos de texto unidirecional (UTF-8)
  • WebSocket - Crie um fluxo de dados binários bidirecionais
Pavio curto
fonte