Довольно тайна здесь. У меня есть веб-приложение ASP.NET MVC 4 с использованием проверки подлинности Windows, которая поддерживается более 18 месяцев без проблем. Недавно он был развернут на новый сайт, и я столкнулся со следующим, очень странным поведением.
Я использую вызов jQuery 1.8.2 $.ajax
для данных POST для конечных точек сервера для обновления данных. Это работает отлично, за исключением одной страницы, где AJAX POST запускает новое соглашение NTLM. Та же проблема проявляется в Chrome, IE и Firefox. Хотя проблема одинакова во всех браузерах, она проявляется несколько по-разному:
- Firefox: получен ответ 401 Challenge с сервера и открывается диалоговое окно с именем пользователя/пароля с запросом учетных данных в бесконечном цикле. Отмена проверки учетных данных приводит к сбою запроса с помощью неавторизованного ответа.
- IE: нет ответа от сервера, и статус запроса отображается как "(Отменено)" на мониторе сети.
- Chrome: от сервера нет ответа, а статус запроса показывает "(отказ)" на мониторе сети.
Основная проблема заключается в том, что заголовок Connection: keep-alive
не отправляется с проблемным запросом AJAX, но в других случаях. Однако базовый код JavaScript почти идентичен, и функция AJAX правильно работает в среде разработки, которая также настроена на использование проверки подлинности Windows.
Кроме того, попытка набора заголовка запроса Connection
в обратном вызове beforeSend
не имеет эффекта.
Любое понимание корня проблемы или способы выделения любой разницы между двумя AJAX POST наиболее ценятся.
Рабочий код и заголовки запроса
$.ajax({
url: url,
type: "POST",
data: $("#myForm").serialize(),
cache: false,
success: function (response) {
}
});
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:621
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:www.xxx.yyy.zzz
Origin:http://www.xxx.yyy.zzz
Referer:http://www.xxx.yyy.zzz/app/resource/path
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With:XMLHttpRequest
Сбой кода и заголовков запросов
$.ajax({
url: url,
type: "POST",
data: data,
cache: false,
success: function (data, status, xhr) {
}
});
WARN: Provisional headers are shown
Accept:*/*
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Origin:http://www.xxx.yyy.zzz
Referer:http://www.xxx.yyy.zzz/app/resource/item/1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With:XMLHttpRequest
Я также просмотрел сетевой процесс в браузере Chrome chrome://net-internals/#events
. Вот журнал событий из неудавшегося запроса в точке, в которой он отклоняется от успешного. В случае неудавшегося запроса "HTTP/1.1 401 Unauthorized" успешный запрос получает ответ "HTTP/1.1 200 OK", предположительно из-за присутствия заголовка Connection: keep-alive
.
2303: URL_REQUEST
Start Time: 2015-04-28 13:53:41.788
t=14736 [st= 0] +REQUEST_ALIVE [dt=71]
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] +URL_REQUEST_START_JOB [dt=70]
--> load_flags = 2688000 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
--> method = "POST"
--> priority = "LOW"
--> upload_id = "0"
--> url = "http://..."
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] HTTP_CACHE_GET_BACKEND [dt=0]
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=14736 [st= 0] +HTTP_STREAM_REQUEST [dt=0]
t=14736 [st= 0] HTTP_STREAM_REQUEST_BOUND_TO_JOB
--> source_dependency = 2305 (HTTP_STREAM_JOB)
t=14736 [st= 0] -HTTP_STREAM_REQUEST
t=14736 [st= 0] +HTTP_TRANSACTION_SEND_REQUEST [dt=0]
t=14736 [st= 0] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
--> POST ... HTTP/1.1
Host: www.xxx.yyy.zzz
Connection: keep-alive
Content-Length: 105
Accept: */*
Origin: http://www.xxx.yyy.zzz
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://www.xxx.yyy.zzz/app/resource/item/1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
t=14736 [st= 0] HTTP_TRANSACTION_SEND_REQUEST_BODY
--> did_merge = true
--> is_chunked = false
--> length = 105
t=14736 [st= 0] -HTTP_TRANSACTION_SEND_REQUEST
t=14736 [st= 0] +HTTP_TRANSACTION_READ_HEADERS [dt=0]
t=14736 [st= 0] HTTP_STREAM_PARSER_READ_HEADERS [dt=0]
t=14736 [st= 0] HTTP_TRANSACTION_READ_RESPONSE_HEADERS
--> HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
X-UA-Compatible: IE=9
Date: Tue, 28 Apr 2015 18:53:41 GMT
Content-Length: 1293
Edit
Игра с другим запросом с консоли дает следующую таблицу результатов (в Chrome). Текущий базовый URL http://IPAddress
/app/topic/item
, и весь тест просто выполняет $.ajax({ url: url, type: 'POST' })
+--------------------------------------+----------------------------+
| URL | Response |
+--------------------------------------+----------------------------+
| http://IP/app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| //IP/app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| /app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE |
| 1/subitem/1 | net::ERR_INVALID_HANDLE |
| 1/foo | 404 (Not Found) [expected] |
| 1 | 302 (Redirect) [expected] |
+--------------------------------------+----------------------------+
Поскольку ошибка только влияет на подмножество методов действий POST
в одном контроллере, я изначально думал, что это проблема на стороне сервера, но после обнаружения проблемы с отсутствующим Connection
, на самом деле это проблема на стороне клиента. Точно как проблема срабатывает, для меня остается загадкой.
Я также убедился, что заголовки ответов для рабочей страницы и проблемной страницы одинаковы. Наиболее важно, заголовок Persistent-Auth: true
всегда возвращается в обоих случаях.