Почему Internet Explorer не отправляет тело сообщения HTTP при вызове Ajax после сбоя?

114

Мы можем достоверно воссоздать следующий сценарий:

  1. Создайте небольшую HTML-страницу, которая делает запросы AJAX к серверу (используя HTTP POST)
  2. Отключитесь от сети и снова подключитесь
  3. Отслеживайте пакеты, которые IE генерирует после сбоя

После сбоя сетевого подключения IE выполняет следующий запрос AJAX, но при отправке HTTP-сообщения отправляет только заголовок HTTP (а не тело). Это вызывает всевозможные проблемы на сервере, поскольку это только частичный запрос. Погуглите эту проблему с Bing, и вы найдете множество людей, жалующихся на «случайные ошибки сервера» с использованием AJAX или необъяснимые сбои AJAX.

Мы знаем, что IE (в отличие от большинства других браузеров) всегда отправляет HTTP POST в виде ДВУХ пакетов TCP / IP. Заголовок и тело отправляются отдельно. В случае, если сразу после сбоя IE отправляет только заголовок . IE никогда не отправляет полезную нагрузку, и сервер в конечном итоге отвечает тайм-аутом.

Итак, у меня вопрос - почему он так себя ведет? Это кажется неправильным, исходя из спецификации HTTP, и другие браузеры так себя не ведут. Это просто ошибка? Несомненно, это разрушит любое серьезное веб-приложение на основе AJAX.

Справочная информация:

Существует аналогичная проблема, вызванная тайм-аутом HTTP keep-alive, который короче 1 минуты, и документирована здесь:

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
источник
6
Это отличный, четко сформулированный вопрос, заслуживающий ответа. К сожалению, это немного не по теме. Не уверен, что будет лучше на webmasters.stackexchange.com или superuser.stackexchange.com .
Стивен
3
@ gilly3, я думаю, что со мной что-то не так, потому что я прочитал это и просто кивнул ...
Ryley
1
@ gilly3: при переводе на голландский это было бы правильно, поскольку «googelen» - это глагол (даже определенный в голландском словаре), означающий «искать в Интернете» на голландском языке. Да, это пишется «гугелен», а не «гуглэн». Странно, я знаю. Итак, вы можете просто сказать: «Googel dit проблема встретила Bing». и было бы правильно.
11
@ gilly3: Что такое Bing? Я собираюсь погуглить.
Rocket Hazmat
5
"Почему он так себя ведет?" - согласитесь ли вы с ответом: «Люди Microsoft, хотя по большей части блестящие, являются частью культуры программирования, фундаментально отличной от тех из нас, кто пришел в цифровую эпоху через DEC, Unix, Apple, Commodore или другие фонды, и склонны делать вещи, которые заставляют всех нас задыхаться от удивления, но не от их блеска, а от их чрезмерного усложнения и тотального искажения вещей, которые просты и понятны для остальных "?
jcomeau_ictx

Ответы:

28

На этот вопрос, похоже, нет однозначного ответа, поэтому я предоставлю свои эмпирические данные в качестве замены и предложу несколько способов обойти это. Может быть, какой-нибудь инсайдер MS однажды прольет свет на это ...

  1. Если HTTP Keep-Alive отключен на сервере, эта проблема исчезнет. Другими словами, ваш сервер HTTP 1.1 будет отвечать на каждый запрос Ajax Connection: Closeстрокой в ​​ответе. Это делает IE счастливым, но заставляет каждый запрос Ajax открывать новое соединение. Это может существенно повлиять на производительность, особенно в сетях с высокой задержкой.

  2. Проблема возникает легко, если запросы Ajax выполняются в быстрой последовательности. Например, мы делаем запросы Ajax каждые 100 мс, а затем состояние сети меняется, ошибку легко воспроизвести. Хотя большинство приложений, вероятно, не отправляют такие запросы, у вас вполне может быть несколько вызовов сервера, происходящих сразу друг за другом, что может привести к этой проблеме. Меньше болтливости делает IE счастливым.

  3. Это происходит даже без аутентификации NTLM.

  4. Это происходит, когда время ожидания проверки активности HTTP на сервере короче, чем значение по умолчанию (которое по умолчанию составляет 60 секунд в Windows). Подробности указаны в соответствующей ссылке.

  5. Этого не происходит с Chrome или Firefox. FF отправляет один пакет, поэтому, похоже, полностью избегает этой проблемы.

  6. Это происходит в IE 6, 7, 8. Невозможно воспроизвести с IE 9 beta.

Dodgyrabbit
источник
4
Есть ли другие способы решить эту проблему? Любое исправление javascript? Я попытался просмотреть различные объекты XMLHTTP, но они все еще не устранили проблему.
Berlin Brown
11

Статья базы знаний Майкрософт под названием « Когда вы используете Microsoft Internet Explorer или другую программу для выполнения операции повторной POST, только данные заголовка публикуются , чтобы решить эту проблему.

В статье содержится исправление. Для более поздних браузеров, таких как IE8, говорится, что исправление уже включено, но его необходимо включить в настройках реестра на клиентском ПК.

юлианский
источник
1
У меня возникла эта проблема с IE10, о которой в статье не упоминается.
ClearCloud8
6
В статье теперь упоминается IE11, так что похоже, что это никогда не исправлялось.
peater
Я полагаю, что столкнулся с этой проблемой на
рабочем
Кто-нибудь нашел обходной путь? В частности, я отправляю 307 и FF, Chrome, Safari репост данных в новую конечную точку - IE этого не делает. Я не могу попросить своих пользователей установить исправление / заплатку реестра.
Брэд Ганн
2

У меня была аналогичная проблема, когда некоторые старые версии IE отправляли обратно только заголовок, а не тело POST. Моя проблема оказалась связана с IE и NTLM. Поскольку вы не упомянули NTLM, это, вероятно, не поможет, но на всякий случай:

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

повторная сборка
источник
Ваша ссылка помогла решить аналогичную проблему в IE 11 и IIS 6.
Harminder
1

Это длинный снимок, но IE (и даже Firefox) иногда «запоминает» соединение, которое он использует для HTTP-запроса. Примечания / примеры:

  • В Firefox, если я изменю настройки прокси-сервера и нажму SHIFT-RELOAD на странице, он все равно будет использовать старый прокси. Однако, если я убью старый прокси («killall squid»), он начнет использовать новый прокси.

  • При отключении / повторном подключении вы получаете новый IP-адрес или что-то подобное? Можете ли вы каким-то образом отслеживать старый IP-адрес, чтобы узнать, отправляет ли IE данные на этот теперь мертвый адрес?

  • Я предполагаю, что IE отправляет данные по неправильному пути. Он может быть достаточно умен, чтобы не кэшировать сетевые соединения для пакетов POST, но может быть недостаточно умен, чтобы делать это для полезных данных POST.

  • Это, вероятно, не влияет на большинство приложений AJAX, поскольку люди редко отключаются и повторно подключаются к своим сетям?


источник
2
Думаю, проблема последняя. Я думаю, что Microsoft использует политику «редко бывает: не внедряйте». :)
1
Я отслеживаю весь HTTP-трафик от источника до места назначения. Я могу подтвердить, что (а) мой IP-адрес не изменился и (б) нет попытки отправить что-либо еще. IE открывает новый сокет и отправляет частичный запрос. Как я прочитал статью MS, одно из их обновлений безопасности сломало IE. Затем они создали патч, чтобы исправить это. Но на всякий случай, если вы хотите, чтобы он вел себя по-старому, «сломанный», вы можете добавить этот ключ реестра. Retry_HeaderOnlyPOST_OnConnectionReset. Просто пытаюсь разобраться в безумии.
Dodgyrabbit
По вашему последнему пункту: если у вас есть приложение Ajax, которое периодически опрашивает, скажем, 10 секунд, мы обнаруживаем, что если оставить его открытым на несколько часов, эта ошибка неизбежно произойдет. Вероятно, обрывается соединение Wi-Fi или сеть ненадежно - но по нашему опыту эта проблема вполне реальна.
Dodgyrabbit
1

Вы используете аутентификацию NTLM?

При использовании аутентификации NTLM IE не отправляет пост-данные. Он отправляет информацию заголовка, ожидает несанкционированного ответа на отправку авторизации и после повторной аутентификации отправляет сообщение.

-Меллер
источник
Мы не используем аутентификацию NTLM. Бывает с анонимными запросами.
Dodgyrabbit
0

Сегодня у меня была аналогичная проблема при использовании $ .ajax, и я смог исправить ее, установив для async значение false.

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

Робби Коувенберг
источник