Динамически изменять тип ответа с сервера при ajax запросе
У меня такая проблема.
Есть сайт по автоматической генерации документов. Пользователь заполняет форму, данные отправляются по ajax на сервер и ответ приходит в виде Blob и отдается на скачивание.
Настройка ajax выглядит так:
$.ajax({
...
xhrFields: {
responseType: 'blob',
},
success(data) {
let link = document.createElement('a');
link.download = 'Документы.zip';
let blob = new Blob([data], {type: 'application/zip'});
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);
}
...
})
Но, допустим, на сервере ошибка и мы передаем информацию о ней в виде json. Иными словами, ответ может быть как Blob (в случае успеха), так и json (если ошибка).
Проблема заключается в том, что в настройках ajax установлено responseType: 'blob', и любой ответ он воспринимает как Blob, соответственно, распарсить json и показать пользователю ошибку я не могу.
А если не устанавливать responseType: 'blob', тогда я не смогу отдать на скачивание файл.
Вопрос заключается в том, могу ли я динамически определить тип ответа сервера и уже потом определить что делать?
Ответы (1 шт):
Пришлось попотеть над решением. Смысл в том, чтобы, как правильно говорили в комментариях, изменять responseType в зависимости от кода ответа сервера (200 - успех, все остальное - ошибка).
responseType мы можем изменить не позднее readyState == 2
Вот рабочий код.
// Специального предусмотренного способа изменить обработчик события onreadystatechange
//в jquery нет, это прямо прописано в документации, поэтому меняем его
//перед отправкой запроса
beforeSend (jqXHR, settings) {
let self = this;
let xhr = settings.xhr;
settings.xhr = function () {
let output = xhr();
output.onreadystatechange = function () {
if (typeof(self.readyStateChanged) == "function") {
self.readyStateChanged(this);
}
};
return output;
};
},
// Когда readyState == 2, присваиваем значение responseType в зависимости от кода ответа
// (200 - успешно, а значит к нам идет blob, все остальное - ошибка, а значит это текст)
readyStateChanged (xhr: XMLHttpRequest) {
if(xhr.readyState == 2) {
xhr.responseType = xhr.status == 200 ? "blob" : "text";
}
},