Почему при загрузке XMLHttpRequest в Firefox происходит сбой?
Я реализую загрузчик файлов, где пользователь может загрузить один или несколько файлов, используя XMLHttpRequest
, Я не пользуюсь fetch
поскольку я должен быть в состоянии обеспечить визуальную обратную связь о прогрессе загрузки пользователю.
Проблема возникает, когда сервер перестает обрабатывать загрузку до ее завершения (например, закрытие соединения с 413 Payload Too Large
ошибка, если загружаемые файлы слишком велики). Если такая ошибка возникает при использовании Safari или Chrome, они остановят загрузку, как я собираюсь.
Однако в Firefox он, похоже, игнорирует это и повторяет загрузку несколько раз, прежде чем остановиться.
Мой код выглядит следующим образом:
// Initialize a new request object.
let req = new XMLHttpRequest();
// Set expected response as JSON.
req.responseType = 'json';
// Set event handlers.
req.upload.onreadystatechange = function(e) { console.log(e.type); }
req.upload.onuploadstart = function(e) { console.log(e.type); }
req.upload.onprogress = function(e) { console.log(e.type); }
req.upload.onabort = function(e) { console.log(e.type); }
req.upload.onload = function(e) { console.log(e.type); }
req.upload.ontimeout = function(e) { console.log(e.type); }
req.upload.onuploadend = function(e) { console.log(e.type); }
// Open request, set request header.
req.open('POST', '/some-endpoint', true);
req.setRequestHeader('Content-type', 'multipart/form-data;boundary=---some-boundary---');
// Create FormData object to submit.
let fd = new FormData(formElement);
// Send data.
req.send(fd);
В Safari и Chrome, когда я загружаю файл, слишком большой для сервера, чтобы принять его, в результате чего сервер закрывает соединение с ответом о состоянии 413, события запускаются в следующем порядке:
loadstart
progress (multiple)
Failed to load resource (413 Request Entity Too Large)
как я и предполагал. В Firefox события запускаются в следующем порядке:
loadstart
progress (multiple, ignoring connection closes and restarting upload multiple times)
loadend
Firefox не запускает load
, error
, abort
, или же timeout
событие до loadend
событие, как указано в XMLHttpRequest.upload
документация
Просмотр сетевых вкладок каждого из инструментов разработчика браузеров показывает, что Chrome и Safari оба распознают, что сервер ответил 413, но Firefox не распознал никакого статуса ответа (даже после того, как loadend
).
Версии Firefox Quantum 62.0b3 (64-разрядная версия). Safari - это 11.0.1. Chrome 67.0.3396.99.
Итак, вопрос: почему Firefox не может распознать, что произошла ошибка сервера во время загрузки, и отменить загрузку, где Safari и Chrome могут? и есть ли способ, которым я могу решить это?
1 ответ
Как предположил Коди Г., это может быть ошибка или связанная с ней ошибка в Firefox.
Это не отвечает на оригинальный вопрос. Тем не менее, он предоставляет обходной путь, и, надеюсь, некоторую потенциально полезную информацию для всех остальных.
Firefox, Safari и Chrome запускают все события в одном и том же порядке при успешной загрузке (т. Е. Когда сервер не отправляет ответ или не закрывает соединение до завершения загрузки). Этот порядок:
readystatechange (readyState = 1)
loadstart
progress (1...n times)
load
loadend
readystatechange (readyState = 2)
readystatechange (readyState = 4)
...как и ожидалось.
Safari и Chrome генерируют события в том же порядке, когда загрузка не удалась (т.е. когда сервер закрывает соединение и отправляет ответ). Этот порядок:
readystatechange (readyState = 1)
loadstart
progress (1...n times)
[the server responds with an error, which does *not* trigger an error event]
readystatechange (readyState = 2)
readystatechange (readyState = 3)
readystatechange (readyState = 4)
Firefox, с другой стороны, запускает события в следующем порядке, когда загрузка не удалась:
readystatechange (readyState = 1)
loadstart
progress (1...n times, including retrying from the start more than once when the server responds or closes the connection)
readystatechange (readyState = 2)
readystatechange (readyState = 3)
readystatechange (readyState = 4)
error
loadend
Мой обходной путь для предотвращения повторного запуска загрузки Firefox несколько раз безо всякой причины - включить переменную, отслеживающую ранее загруженную сумму:
let prevLoaded = 0;
xhr.upload.addEventListener('progress', function(e) {
if (prevLoaded !== 0 && e.loaded <= prevLoaded) {
xhr.abort();
return;
}
prevLoaded = e.loaded;
}, false);
Это приводит к отмене запроса. Safari и Chrome не будут запускать этот код, так как другие события запускаются раньше, чем могут. С этим кодом, порядок запуска событий Firefox для неудачных загрузок становится:
readystatechange (readyState = 1)
loadstart
progress (1...n times, but almost always stopping after the server closes the connection or responds with an error)
readystatechange (readyState = 4)
abort
loadend