Pergunta

Eu tenho um proxy Apache para um aplicativo Meteor e o Apache e o Meteor estão em duas máquinas separadas.Eu preciso disso, pois o Apache precisa servir muitos sites reais e não seria uma boa ideia instalar o aplicativo Meteor nesta máquina devido aos seus recursos limitados.

No entanto, o handshake do WebSocket falha com o código de resposta 400 "Pode atualizar apenas para websocket" se eu tentar conectar-me externamente por meio do proxy.Tudo funciona bem quando eu me conecto diretamente da LAN à máquina de meteoros.Quando o WebSocket falha, o SockJS/Meteor volta para o XHR, mas infelizmente isso traz alguns bugs no aplicativo em questão.Então eu realmente preciso que o WebSocket funcione na maioria dos casos.

Corrigi minha instalação do Apache com o patch mencionado aqui: https://stackoverflow.com/a/16998664Parecia que tudo correu bem, mas nada mudou...

Minhas diretivas de proxy do Apache atualmente são as seguintes:

ProxyRequests Off
ProxyPreserveHost On
ModPagespeed Off
<proxy>
Order deny,allow
Allow from all
</proxy>
ProxyPass / http://10.0.2.6:3000/
ProxyPassReverse / http://10.0.2.6:3000/

E eu até sei o que está desencadeando o problema.O proxy apache mexe com o cabeçalho.O cabeçalho da solicitação original do pacote em questão saindo da minha máquina é assim:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent

Enquanto o pacote é encaminhado do proxy Apache assim:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent
X-Forwarded-For: 24.xxx.xxx.xxx
X-Forwarded-Host: example.com
X-Forwarded-Server: example.com
Connection: Keep-Alive

Portanto, "Atualização" é removida e "Conexão" alterada e o handshake do websocket falha.Agora eu poderia tentar sempre definir "Upgrade" como "websocket" com uma diretiva RequestHeader.No entanto, isso não parece certo e acho que traria outros problemas, então fiquei pensando se existe uma solução real para esse problema.Ou isso é algo do patch https://stackoverflow.com/a/16998664 deveria resolver e algo deu errado do meu lado ao aplicá-lo?

Pelo que li, mudar para o nginx pode tornar essa configuração mais fácil.Vou considerar isso, mas quando possível, gostaria de fazer isso com o Apache, pois o nginx tornaria outras coisas mais complicadas e me custaria muito tempo.

Foi útil?

Solução

Usamos isso para Apache e um aplicativo SockJS por trás do Apache.O Apache está executando o proxy WebSocket automaticamente, mas você precisa reescrever o esquema para ws, caso contrário, ele retornará ao XHR.Mas somente se a conexão for um handshake WebSocket.Adicionar o seguinte resolverá seu problema :) (nota:mudar o localhost:3000 de acordo com seu próprio URL de back-end.

RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

Outras dicas

Esta resposta é baseada na resposta de Fatih.Sua solução falha em navegadores que enviam um cabeçalho de solicitação de conexão diferente de "Upgrade", como "keep-alive, Upgrade".Este foi o meu caso com o Firefox 42.

Para resolver o problema também no Firefox, altere o RewriteCond do Apache da seguinte maneira:

RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

(^Atualizar$ torna-se Atualizar$)

Queria colocar isso como um comentário à resposta de Fatih, mas não tenho a reputação necessária.

Depois de ler várias respostas, postar no fórum do Meteor e muitos testes, aqui está toda a enchilada que funcionou para mim.As outras respostas estavam um tanto incompletas ou pelo menos não funcionaram para mim.

Eu tive que fazer:

sudo a2enmod proxy_wstunnel 

Também tive que adicionar um ProxyPass e ProxyPassReverse e alterar ^Upgrade$ para Upgrade$ de outra resposta SO.

<VirtualHost *:80>
    ServerName  some-domain.com

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

</VirtualHost>

então reinicie o Apache.

Verifiquei no console e não há nenhum erro agora e nenhuma solicitação xhr.Então presumo que esteja funcionando corretamente

Eu gostaria de poder fornecer uma resposta direta com instruções do Apache, mas como você mencionou o nginx e o fato é que é difícil de configurar, gostaria de sugerir uma alternativa que realmente use o nginx, mas proteja você de todas as complexidades.

O tutorial em https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial percorre as etapas para configurar Passageiro Fusão com ou sem nginx (ele usa nginx internamente de qualquer maneira) para implantações Meteor de produção de várias instâncias que podem ser escalonadas para utilizar todos os núcleos em seu servidor.

É tão fácil quanto:

$ cd meteor-app-directory
$ mkdir public tmp
$ passenger start

Fatih-Arslana resposta com Derwiwiea alteração funcionou perfeitamente.Uma coisa que tive que usar foi colocar wss em vez de es, porque meu serviço funciona apenas em https.

RewriteEngine on  
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]  
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]  
RewriteRule .* wss://localhost:3000%{REQUEST_URI} [P]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top