Dlaczego program Internet Explorer nie wysyła treści postu HTTP przy wywołaniu Ajax po awarii?

114

Jesteśmy w stanie wiarygodnie odtworzyć następujący scenariusz:

  1. Utwórz małą stronę HTML, która wysyła żądania AJAX do serwera (przy użyciu HTTP POST)
  2. Odłącz się od sieci i połącz ponownie
  3. Monitoruj pakiety generowane przez IE po awarii

Po nieudanym połączeniu sieciowym IE wysyła następne żądanie AJAX, ale wysyła tylko plik nagłówek HTTP (nie treść) podczas wykonywania postu HTTP. Powoduje to różnego rodzaju problemy na serwerze, ponieważ jest to tylko częściowe żądanie. Wygoogluj ten problem z Bing, a znajdziesz wiele osób narzekających na „losowe błędy serwera” przy użyciu AJAX lub niewyjaśnionych awarii AJAX.

Wiemy, że IE (w przeciwieństwie do większości innych przeglądarek) zawsze wysyła HTTP POST jako DWA pakiety TCP / IP. Nagłówek i treść są wysyłane osobno. W przypadku bezpośrednio po awarii, IE wysyła tylko nagłówek . IE nigdy nie wysyła ładunku, a serwer ostatecznie odpowiada limitem czasu.

Więc moje pytanie brzmi - dlaczego tak się zachowuje? Wydaje się to błędne w oparciu o specyfikację HTTP, a inne przeglądarki nie zachowują się w ten sposób. Czy to po prostu błąd? Z pewnością powoduje to spustoszenie w każdej poważnej aplikacji internetowej opartej na technologii AJAX.

Informacje referencyjne:

Istnieje podobny problem, wywołany przez limity czasu podtrzymania aktywności HTTP, które są krótsze niż 1 minuta i jest udokumentowany tutaj:

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
źródło
6
To doskonałe, dobrze zdefiniowane pytanie, które zasługuje na odpowiedź. Niestety jest to trochę nie na temat. Nie jestem pewien, czy byłoby lepiej na webmasters.stackexchange.com lub superuser.stackexchange.com .
Stephen
3
@ gilly3, myślę, że coś musi być ze mną nie tak, ponieważ to przeczytałem i po prostu
kiwałem
1
@ gilly3: po przetłumaczeniu na holenderski byłoby to poprawne, ponieważ „googelen” to czasownik (nawet zdefiniowany w holenderskim słowniku) oznaczający „przeszukiwać sieć” w języku niderlandzkim. Tak, jest zapisywane jako „googelen”, a nie „googlen”. Wiem, dziwne. Możesz więc po prostu powiedzieć: „Googel dit probleem met Bing”. i byłoby poprawne.
11
@ gilly3: Co to jest Bing? Wygoogluję to.
Rocket Hazmat
5
"dlaczego zachowuje się w ten sposób?" - czy zgodziłbyś się na odpowiedź „Ludzie Microsoft, choć w większości genialni, są częścią kultury programowania zasadniczo odmiennej od tych z nas, którzy weszli w erę cyfrową dzięki DEC, Unix, Apple, Commodore lub innym, i mają tendencję do robienia rzeczy, które sprawiają, że reszta z nas wzdycha ze zdumienia, nie z powodu ich błyskotliwości, ale ich nadmiernej komplikacji i całkowitego zepsucia rzeczy, które są proste i proste dla reszty z nas ”?
jcomeau_ictx

Odpowiedzi:

28

Wydaje się, że nie ma jasnej odpowiedzi na to pytanie, więc jako substytut podam moje dane empiryczne i przedstawię sposoby obejścia tego problemu. Może jakiś insider MS pewnego dnia rzuci trochę światła na to ...

  1. Jeśli HTTP Keep-Alive jest wyłączone na serwerze, ten problem zniknie. Innymi słowy, twój serwer HTTP 1.1 odpowie na każde żądanie Ajax Connection: Closelinią odpowiedzi. To sprawia, że ​​IE jest szczęśliwy, ale powoduje, że każde żądanie Ajax otwiera nowe połączenie. Może to mieć znaczący wpływ na wydajność, szczególnie w sieciach z dużymi opóźnieniami.

  2. Problem jest łatwo uruchamiany, jeśli żądania Ajax są wysyłane w krótkich odstępach czasu. Na przykład wysyłamy żądania Ajax co 100 ms, a następnie zmienia się stan sieci, błąd jest łatwy do odtworzenia. Chociaż większość aplikacji prawdopodobnie nie wysyła takich żądań, możesz mieć kilka wywołań serwera występujących bezpośrednio po sobie, co może prowadzić do tego problemu. Mniej gadatliwości sprawia, że ​​IE jest zadowolona.

  3. Dzieje się tak nawet bez uwierzytelniania NTLM.

  4. Dzieje się tak, gdy limit czasu utrzymywania aktywności HTTP na serwerze jest krótszy niż domyślny (który domyślnie wynosi 60 sekund w systemie Windows). Szczegóły podane w odnośniku, o którym mowa.

  5. Nie dzieje się tak w przypadku przeglądarki Chrome ani Firefox. FF wysyła jeden pakiet, więc wydaje się całkowicie unikać tego problemu.

  6. Dzieje się tak w IE 6, 7, 8. Nie można odtworzyć z IE 9 beta.

Dodgyrabbit
źródło
4
Czy istnieją inne sposoby rozwiązania tego problemu? Jakaś poprawka javascript? Próbowałem spojrzeć na różne obiekty XMLHTTP i nadal nie rozwiązały problemu.
Berlin Brown
11

Artykuł bazy wiedzy Microsoft zatytułowany Gdy używasz przeglądarki Microsoft Internet Explorer lub innego programu do ponownego wykonania operacji POST, publikowane są tylko dane nagłówka, które rozwiązują ten problem.

Artykuł zawiera poprawkę. W przypadku nowszych przeglądarek, takich jak IE8, jest napisane, że poprawka jest już dołączona, ale należy ją włączyć w ustawieniach rejestru na komputerze klienckim.

juliański
źródło
1
Mam ten problem z IE10, o którym artykuł nie wspomina.
ClearCloud8
6
Artykuł wspomina teraz o IE11, więc wygląda na to, że nigdy nie zostało to naprawione.
torf
Wydaje mi się, że mam ten problem na stronie produkcyjnej - klienty użytkownika powiązane z problemem odpowiadają IE 8, 9, 10 i 11.
millhouse
Czy ktoś znalazł obejście? W szczególności wysyłam 307 i FF, Chrome, Safari ponownie przesyłam dane do nowego punktu końcowego - IE tego nie robi. Nie mogę poprosić użytkowników o poprawkę / poprawkę rejestru.
Brad Gunn
2

Miałem podobny problem, gdy niektóre starsze wersje IE odsyły tylko nagłówek, a nie treść POST. Mój problem okazał się być związany z IE i NTLM. Ponieważ nie wspomniałeś o NTLM, prawdopodobnie to nie pomoże, ale na wszelki wypadek:

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

reassembler
źródło
Twój link był pomocny w rozwiązaniu podobnego problemu w IE 11 i IIS 6.
Harminder
1

To długa perspektywa, ale IE (a nawet Firefox) czasami „pamięta” połączenie, którego używa do żądania HTTP. Uwagi / przykłady:

  • W Firefoksie, jeśli zmienię ustawienia proxy i wbiję SHIFT-RELOAD na stronie, nadal używa starego proxy. Jeśli jednak zabiję stare proxy („killall squid”), zacznie ono używać nowego proxy.

  • Czy po rozłączeniu / ponownym połączeniu otrzymujesz nowy adres IP lub coś podobnego? Czy możesz w jakiś sposób monitorować stary adres IP, aby sprawdzić, czy IE wysyła dane na ten teraz martwy adres?

  • Domyślam się, że IE wysyła dane, po prostu w złym kierunku. Może być wystarczająco sprytne, aby nie buforować połączeń sieciowych dla pakietów „POST”, ale może nie być wystarczająco inteligentne, aby robić to w przypadku ładunków POST.

  • Prawdopodobnie nie ma to wpływu na większość aplikacji AJAX, ponieważ ludzie rzadko rozłączają się i ponownie łączą z ich sieciami?


źródło
2
Myślę, że problem jest ostatni. Myślę, że Microsoft stosuje zasadę „rzadko się zdarza: nie implementuj”. :)
1
Monitoruję cały ruch HTTP od źródła do celu. Mogę potwierdzić, że (a) mój adres IP nie zmienił się i (b) nie ma próby wysłania czegokolwiek innego. IE otwiera nowe gniazdo i wysyła częściowe żądanie. Sposób, w jaki przeczytałem artykuł MS, jest taki, że jedna z ich aktualizacji bezpieczeństwa zepsuła IE. Następnie stworzyli łatkę, aby to naprawić. Ale na wypadek, gdybyś chciał, żeby zachowywał się w stary „zepsuty” sposób, możesz dodać ten klucz rejestru. Retry_HeaderOnlyPOST_OnConnectionReset. Próbuję tylko zrozumieć to szaleństwo.
Dodgyrabbit
Ostatni punkt: jeśli masz aplikację Ajax, która sonduje okresowo, powiedzmy 10 sekund, okazuje się, że jeśli pozostanie otwarta przez kilka godzin, ten błąd będzie się niezmiennie występował. Prawdopodobnie zanikło połączenie Wi-Fi lub sieć jest szkicowa - ale z naszego doświadczenia wynika, że ​​ten problem jest bardzo realny.
Dodgyrabbit
1

Czy używasz uwierzytelniania NTLM?

Podczas korzystania z uwierzytelniania NTLM IE nie wysyła danych końcowych. Wysyła informacje z nagłówka, oczekuje nieautoryzowanej autoryzacji wysłania odpowiedzi, a po „ponownym uwierzytelnieniu” wysyła wiadomość.

The-MeLLeR
źródło
Nie używamy uwierzytelniania NTLM. Dzieje się z anonimowymi prośbami.
Dodgyrabbit
0

Miałem dziś podobny problem podczas używania $ .ajax i byłem w stanie go naprawić, ustawiając async na false.

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

robbie kouwenberg
źródło