Резюме
При использовании идентичного кода (на основном сайте asp.net) в разных браузерах при просмотре страницы IIS на локальном хосте XMLHttpRequest
обнаруживает какую-то ошибку и вызывает ее событие ошибки и устанавливает статус равным нулю, несмотря на наличие успешно прочитал данные (сеть показывает 200 OK) и сохранил их в responseText
.
На производственном / промежуточном веб-сервере код всегда работает нормально.
Файлы открытого текста, по-видимому, по какой-то причине работают нормально и локально (строго говоря, они обрабатываются более ранним промежуточным программным обеспечением), но сгенерированный контент (HTML и JSON) с обычными заголовками выдает ошибку.
У меня вопрос: почему он выдает эту ошибку сейчас, а не раньше?
Ответ ниже ...
Полное оригинальное сообщение
Еще совсем недавно (2-3 дня назад) вызовы AJAX с использованием $ .get () jQuery работали нормально на моей машине для разработки и в промежуточных / производственных средах.
Со вчерашнего дня (когда я заметил) вызовы AJAX теперь не работают на локальной версии сайта и работают нормально на рабочей версии.
Я пробовал в Firefox, Edge и Opera - у всех был одинаковый результат. Я сгенерировал наиболее урезанный код, который мог и все еще могу выдать тот же результат ошибки - который почти полностью исключает мой код.
Я проверил примечания к выпуску Firefox и Edge и не смог найти ничего подходящего для меня.
Локальный хост использует самозаверяющий тестовый сертификат, который имеет исключение в Firefox. Промежуточный сайт имеет настоящий сертификат, подписанный третьей стороной.
Полный код страницы:
<html>
<head>
<style>@media print {#ghostery-purple-box {display:none !important}}</style>
</head>
<body>
<h1>hi</h1>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</body>
</html>
Затем я запускаю этот javascript в окне консоли каждого браузера:
$.ajax({url:'/Test',error:function(a,b,c){alert(b)}, success:function(a){alert(a);}});
простите за форматирование, единственная строка была для более простого копирования / вставки и тестирования.
вывод в каждой конфигурации, о которой я могу думать, это то, что часть alert(b)
запускается, а b
равняется «ошибке».
Единственным отличием в двух конфигурациях является URL:
https://localhost:44300/Test
против
https://[productionfqdn]:444/Test
И заголовки обратно от веб-серверов, локально это IIS Express и удаленно это IIS - оба поддержаны Kestrel как часть сайта ASP.NET Core - хотя я исключил что-либо из этого как возможную часть проблема (я не буду вдаваться в подробности перехода к предыдущей версии кода, пока не понял, что это не имеет ничего общего с моей базой кода).
IIS Express: (dev)
HTTP/2.0 200 OK
content-type: text/html; charset=utf-8
server: Kestrel
x-sourcefiles: [redacted]
x-powered-by: ASP.NET
date: Tue, 26 Mar 2019 23:05:06 GMT
X-Firefox-Spdy: h2
IIS: (постановка)
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel
Strict-Transport-Security: max-age=2592000
Date: Tue, 26 Mar 2019 23:04:47 GMT
Результат вызовов на локальный сайт успешен, в devtools в FireFox я вижу, что ожидаемые данные были возвращены, в этом случае те же данные, которые были получены из / Test для запуска теста в первом место.
В результате тех же вызовов на промежуточном сайте выдается предупреждение с текстом html, как указано выше.
Я ожидаю, что эти две среды приведут к одному и тому же результату, а именно к получению html-текста.
Есть идеи? Я сбит с толку!
Редактировать 2019-03-28
Я попытался из контекста той же страницы сделать то же самое с ванильным XMLHttpRquest и получил следующее:
var x = new XMLHttpRequest();
undefined
x.open('GET', '/Test')
undefined
x.send(null)
undefined
x
XMLHttpRequest { onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "", status: 0, statusText: "", responseType: "",
response: "<h1>hi</h1>\r\n<script type=\"text/javascript\" src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>"
Где можно ясно увидеть ожидаемый ответ от веб-сервера в поле ответа объекта. (разрыв строки для наглядности)
То же самое, прямо как изображение из браузера devtools:
![Firefox javascript console](https://i.stack.imgur.com/EXz6j.png)
Редактировать 2 2019-03-28
(кроме того, на вкладке сети отображаются данные, возвращающиеся в порядке)
Так как последнее редактирование показало, что jQuery делает что-то глупое, я решил запустить отладчик и посмотреть, что происходит в jQuery. В текущей версии (3.3.1) я сломал строку 9300, то есть после того, как запрос был выполнен и после того, как jQuery оценил его. Я обнаружил, что функция done имеет значения, которые различаются для моего локального (dev) и удаленного (stg) веб-серверов:
Местное
![Local web server values](https://i.stack.imgur.com/ZITve.png)
Remote
![Remote web server values](https://i.stack.imgur.com/769lj.png)
Основной смысл в том, что локальная версия jQuery запускается в done()
с status = 0
, тогда как удаленная версия запускается в done()
с status = 200
, что имеет смысл.
В обеих версиях поле состояния локальной переменной response
равно 'success'. В строке 9247 jQuery оценивает переменную status
, переданную в done()
, и поскольку 0
не передается, isSuccess
устанавливается в false
.
Однако сеть показывает:
![enter image description here](https://i.stack.imgur.com/NbUDl.png)
Я буду продолжать копать, но буду следить за любыми проницательными ответами:)
Редактировать 3
Значит, done()
вызывается из строки 9538:
callback = function( type ) {
return function() {
if ( callback ) {
callback = errorCallback = xhr.onload =
xhr.onerror = xhr.onabort = xhr.ontimeout =
xhr.onreadystatechange = null;
if ( type === "abort" ) {
xhr.abort();
} else if ( type === "error" ) {
// Support: IE <=9 only
// On a manual native abort, IE9 throws
// errors on any property access that is not readyState
if ( typeof xhr.status !== "number" ) {
complete( 0, "error" );
} else {
complete(
// File: protocol always yields status 0; see #8605, #14207
xhr.status,
xhr.statusText
);
}
Строка перед if ( typeof xhr.status !== "number" ) {
проверяет xhr.status
, что означает 0
, а не фактический код состояния, несмотря на то, что он определенно возвращает 200. Это объясняет, откуда приходит сообщение «ошибка»! В done()
проверяется этот код состояния:
isSuccess = status >= 200 && status < 300 || status === 304;
Так откуда взялся этот 0? *
![jQuery handling XHR completion](https://i.stack.imgur.com/0gSus.png)
Редактировать 4
В конечном счете, проблема, похоже, в том, что XMLHttpRequest
дает мне статус 0 от localhost, и не было до нескольких дней назад. Супер разочарование:
var x = new XMLHttpRequest(); x.open('GET', 'https://localhost:44300/Test'); x.send(null);
undefined
x
XMLHttpRequest { onreadystatechange: null, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "",
status: 0, statusText: "", responseType: "", response: "" }
var x = new XMLHttpRequest(); x.open('GET', 'https://127.0.0.1:44300/Test'); x.send(null);
undefined
x
XMLHttpRequest { onreadystatechange: null, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "",
status: 0, statusText: "", responseType: "", response: "" }
Редактировать 5
Итак, снова, пытаясь свести его к минимуму, необходимо сделать ошибку. Я немного заглянул в jquery и заметил, что XHR вызывал обратный вызов ошибки JQ (назначенный xhr.onerror
), поэтому я сделал то же самое:
var x = new XMLHttpRequest()
XMLHttpRequest { onreadystatechange: null, readyState: 0, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "", status: 0, statusText: "", responseType: "", response: "" }
x.onerror = function () {console.log('error happened')};
function onerror()
x.open('GET','/Test')
undefined
x.send(null)
undefined
error happened
x
XMLHttpRequest { onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "", status: 0, statusText: "", responseType: "", response: "<h1>hi</h1>\r\n<script type=\"text/javascript\" src=\"https://code.jquery.com/jquery-3.3.1.js\"></script>" }
Это привело к тому, что в сообщении было указано «произошла ошибка», поэтому я могу с уверенностью сказать, что это не jQuery, а нечто странное, вызывающее локальную ошибку.
Редактировать 6
Изменил выше, чтобы быть x.onerror = function (e) {console.log('error happened'); console.log(e)};
, чтобы выбросить ошибку и получил это:
error
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: null
defaultPrevented: false
eventPhase: 0
explicitOriginalTarget: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
isTrusted: true
lengthComputable: false
loaded: 0
originalTarget: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
returnValue: true
srcElement: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
target: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
timeStamp: 594573
total: 0
type: "error"
Который не проливает много света.
Редактировать 7
Изменение моей тестовой страницы, чтобы она была более полной, чтобы я мог лучше тестировать:
<code><script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript">
var x = new XMLHttpRequest();
$(document).ready(function () {
x.onerror = function (e) { console.log('error happened'); console.log(e); $('#err').text(e); };
x.onreadystatechange = function () {
if (x.readyState == 4) {
$('#test').text(x.responseText);
}
};
//x.open('GET', '/test.txt');
x.open('GET', '/Search/Server?term=[redacted]');
x.send(null);
});
</script>
<h1>hi</h1>
<div style="border: 1px solid black">
<pre id="test">
Когда я спрашиваю /test.txt
, он работает нормально, status = 200
без ошибок
Когда я спрашиваю /Test
, который представляет собой приведенный выше код, status = 0
, возникает ошибка (без полезной информации о том, почему)
Когда я запрашиваю /Search/Server?term=[redacted]
, который возвращает правильно сформированный json, status = 0
, ошибка произведена (без полезной информации)
Заголовки AJAX (рабочие)
HTTP/2.0 304 Not Modified
content-type: text/plain
last-modified: Thu, 28 Mar 2019 06:20:18 GMT
accept-ranges: bytes
etag: "1d4e52e505b3d27"
server: Kestrel
x-sourcefiles: [redacted]
x-powered-by: ASP.NET
date: Thu, 28 Mar 2019 06:47:09 GMT
X-Firefox-Spdy: h2
Заголовки AJAX (не работают)
HTTP/2.0 200 OK
content-type: text/html; charset=utf-8
server: Kestrel
x-sourcefiles: [redacted]
x-powered-by: ASP.NET
date: Thu, 28 Mar 2019 06:46:18 GMT
X-Firefox-Spdy: h2
HTTP/2.0 200 OK
content-type: application/json; charset=utf-8
server: Kestrel
x-sourcefiles: [redacted]
x-powered-by: ASP.NET
date: Thu, 28 Mar 2019 06:37:41 GMT
X-Firefox-Spdy: h2
может ли быть charset
в заголовке content-type
?!
Возможно, стоит повторить, что все эти вызовы с точным одним и тем же кодом прекрасно работают в производстве / постановке - те же браузеры, та же аутентификация (не то, что она актуальна после того, как это произошло), те же относительные URL-адреса, используемые и т. д. Единственное отличие состоит в том, что prd / stg является IIS и имеет реальный сертификат, а local является IIS express и использует самоподписанный исключение. Это я могу думать.