Динамически изменять тип ответа с сервера при 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 шт):

Автор решения: Ivan K.

Пришлось попотеть над решением. Смысл в том, чтобы, как правильно говорили в комментариях, изменять 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";
                }
            },
→ Ссылка