Por que o Internet Explorer não envia o corpo da postagem HTTP em uma chamada Ajax após a falha?

114

Somos capazes de recriar com segurança o seguinte cenário:

  1. Crie uma pequena página HTML que faça solicitações AJAX a um servidor (usando HTTP POST)
  2. Desconecte-se da rede e reconecte-se
  3. Monitore os pacotes que o IE gera após a falha

Após uma falha na conexão de rede, o IE faz a próxima solicitação AJAX, mas envia apenas o cabeçalho HTTP (não o corpo) ao fazer a postagem HTTP. Isso causa todos os tipos de problemas no servidor, pois é apenas uma solicitação parcial. Pesquise no Google esse problema com o Bing e você encontrará muitas pessoas reclamando de "erros aleatórios do servidor" usando AJAX ou falhas inexplicáveis ​​de AJAX.

Sabemos que o IE (ao contrário da maioria dos outros navegadores) sempre envia um HTTP POST como DOIS pacotes TCP / IP. O cabeçalho e o corpo são enviados separadamente. No caso diretamente após uma falha, o IE apenas envia o cabeçalho . O IE nunca envia a carga útil e o servidor eventualmente responde com um tempo limite.

Portanto, minha pergunta é - por que isso se comporta dessa maneira? Parece errado com base na especificação HTTP e outros navegadores não se comportam dessa maneira. É simplesmente um bug? Certamente isso cria confusão em qualquer aplicativo da Web baseado em AJAX sério.

Informação de referência:

Há um problema semelhante, acionado por tempos limites de HTTP keep-alive menores que 1 minuto e está documentado aqui:

http://us.generation-nt.com/xmlhttprequest-post-sometimes-fails-when-server-using-keep-aliv-help-188813541.html

http://support.microsoft.com/default.aspx?kbid=831167

Dodgyrabbit
fonte
6
Esta é uma pergunta excelente e bem definida que merece uma resposta. Infelizmente, isso é um pouco fora do assunto. Não tenho certeza se seria melhor em webmasters.stackexchange.com ou superuser.stackexchange.com .
Stephen
3
@ gilly3, acho que algo deve estar errado comigo, porque li isso e estava apenas concordando ...
Ryley
1
@ gilly3: quando traduzido para o holandês, isso seria correto, pois 'googelen' é um verbo (mesmo definido no dicionário holandês) que significa 'pesquisar na web' em holandês. Sim, é escrito 'googelen' e não 'googlen'. Estranho, eu sei. Então, você poderia apenas dizer: 'Googel dit problem at Bing.' e estaria correto.
11
@ gilly3: O que é o Bing? Vou pesquisar no Google.
Rocket Hazmat
5
"por que se comporta dessa maneira?" - você aceitaria como resposta "O pessoal da Microsoft, embora em sua maioria brilhante, faz parte de uma cultura de programação fundamentalmente diferente daquela de nós que entramos na era digital através de DEC, Unix, Apple, Commodore ou outras origens, e tendem a fazer coisas que fazem o resto de nós ficar surpreso, não com seu brilho, mas com sua complicação e corrupção total de coisas que são simples e diretas para o resto de nós "?
jcomeau_ictx

Respostas:

28

Não parece haver uma resposta clara para essa pergunta, portanto, fornecerei meus dados empíricos como um substituto e apresentarei algumas maneiras de contorná-los. Talvez algum insider da MS algum dia lance alguma luz sobre isso ...

  1. Se HTTP Keep-Alive estiver desabilitado no servidor, esse problema desaparece. Em outras palavras, seu servidor HTTP 1.1 responderá a cada solicitação Ajax com uma Connection: Closelinha na resposta. Isso mantém o IE feliz, mas faz com que cada solicitação Ajax abra uma nova conexão. Isso pode ter um impacto significativo no desempenho, especialmente em redes de alta latência.

  2. O problema é acionado facilmente se as solicitações Ajax forem feitas em rápida sucessão. Por exemplo, fazemos solicitações Ajax a cada 100 ms e, em seguida, o status da rede muda, o erro é fácil de reproduzir. Embora a maioria dos aplicativos provavelmente não faça essas solicitações, você pode muito bem ter algumas chamadas de servidor acontecendo uma após a outra, o que pode levar a esse problema. Menos tagarela mantém o IE feliz.

  3. Isso acontece mesmo sem autenticação NTLM.

  4. Isso acontece quando o tempo limite de HTTP keep-alive no servidor é menor do que o padrão (que é de 60 segundos no Windows). Detalhes fornecidos no link em questão.

  5. Isso não acontece com o Chrome ou Firefox. O FF envia um pacote, portanto, parece evitar esse problema por completo.

  6. Isso acontece no IE 6, 7, 8. Não foi possível reproduzir com o IE 9 beta.

Dodgyrabbit
fonte
4
Existem outras maneiras de resolver este problema? Qualquer correção de javascript? Tentei examinar os vários objetos XMLHTTP e eles ainda não corrigiram o problema.
Berlin Brown
11

O artigo da Microsoft KB intitulado Quando você usa o Microsoft Internet Explorer ou outro programa para executar uma operação de re-POST, apenas os dados do cabeçalho são postados parece corrigir esse problema.

O artigo fornece um hotfix. Para navegadores posteriores, como o IE8, ele informa que o hotfix já está incluído, mas precisa ser ativado nas configurações do registro no PC cliente.

Julian
fonte
1
Estou tendo esse problema com o IE10, que o artigo não menciona.
ClearCloud8
6
O artigo agora menciona até o IE11, então parece que isso nunca foi corrigido.
peater
Acredito que estou enfrentando esse problema em um local de produção - os agentes do usuário associados ao problema correspondem ao IE 8,9,10 e 11.
millhouse,
Alguém encontrou uma solução alternativa? Especificamente, eu envio um 307 e FF, Chrome, Safari repassam os dados para o novo endpoint - o IE não. Não posso pedir aos meus usuários que façam um patch de hotfix / registro.
Brad Gunn
2

Eu tive um problema semelhante, onde algumas versões mais antigas do IE enviariam de volta apenas o cabeçalho e não o corpo de um POST. Meu problema acabou por ser relacionado ao IE e NTLM. Já que você não mencionou NTLM, isso provavelmente não ajuda, mas apenas no caso:

http://support.microsoft.com/kb/251404

remontador
fonte
Seu link foi útil para resolver um problema semelhante no IE 11 e IIS 6.
Harminder
1

Esta é uma hipótese remota, mas o IE (e até o Firefox) às vezes "se lembra" da conexão que usa para uma solicitação HTTP. Notas / exemplos:

  • No Firefox, se eu alterar as configurações de proxy e clicar em SHIFT-RELOAD em uma página, ele ainda usará o proxy antigo. No entanto, se eu matar o proxy antigo ("killall squid"), ele começará a usar o novo proxy.

  • Ao desconectar / reconectar, você recebe um novo endereço IP ou algo semelhante? Você pode de alguma forma monitorar o endereço IP antigo para ver se o IE está enviando dados para aquele endereço agora morto?

  • Meu palpite é que o IE está enviando os dados, apenas pelo caminho errado. Pode ser inteligente o suficiente para não armazenar em cache as conexões de rede para pacotes "POST", mas pode não ser inteligente o suficiente para fazer isso para cargas úteis POST.

  • Isso provavelmente não afeta a maioria dos aplicativos AJAX, já que as pessoas raramente se desconectam e se reconectam às suas redes.


fonte
2
Acho que o problema é o último. Acho que a Microsoft usa uma política do tipo "raramente acontece: não implemente". :)
1
Eu monitoro todo o tráfego HTTP da origem ao destino. Posso confirmar que (a) meu endereço IP não mudou e (b) não há tentativa de enviar mais nada. O IE abre um novo soquete e envia uma solicitação parcial. Do jeito que li o artigo da MS, uma de suas atualizações de segurança quebrou o IE. Em seguida, eles criaram um patch para corrigir isso. Mas apenas no caso de você querer que ele se comportasse da maneira antiga "quebrada", pode adicionar essa chave de registro. Retry_HeaderOnlyPOST_OnConnectionReset. Apenas tentando entender a loucura.
Dodgyrabbit
Em seu último ponto: se você tiver um aplicativo Ajax que faz pesquisas periodicamente, digamos 10 segundos, descobrimos que, se deixado aberto por algumas horas, esse erro invariavelmente acontecerá. Provavelmente conexão Wifi que cai ou rede incompleta - mas nossa experiência este problema é muito real.
Dodgyrabbit
1

Você está usando autenticação NTLM?

Ao usar a autenticação NTLM, o IE não envia pós-dados. Ele envia informações de cabeçalho, espera uma resposta não autorizada, envia autorização e, após a 'reautenticação', envia a postagem.

The-MeLLeR
fonte
Não usamos autenticação NTLM. Acontece com solicitações anônimas.
Dodgyrabbit
0

Tive um problema semelhante hoje ao usar $ .ajax e consegui corrigi-lo definindo async como false.

$.ajax({
  async: false, 
  url: '[post action url]',
  data: $form.serialize(),
  type: 'POST',
  success: successCallback
});

robbie kouwenberg
fonte