jQuery:在完整函数内访问二进制 AJAX 响应还是在回调函数外访问 XHR 对象?

时间:2021-06-25 08:11:05

标签: javascript jquery ajax

关于使用 jQuery 处理二进制 AJAX 响应有很多问题,例如 thisthisthis。没有帮助。

目标:(1)动态判断一个响应是否包含二进制数据,并以不同于文本的方式处理; (2) 分析响应头;和 (3) 从一个函数中同时完成。

理想情况下,这可以通过 complete 函数完成,但 complete 函数无权访问 XHR 对象。 jqXHR 应该是 XHR 对象的超集,但 XHR.response 为空。

$.ajax(settings) 的返回值包含二进制数据,但 XHR 对象不再可用——因此似乎无法分析响应头。

是否可以在 complete 回调内访问二进制 AJAX 响应或在回调函数外访问 XHR 对象?

// Assume @data contains body and URL values.

let settings = {
    url: data.url,
    method: "post",
    timeout: 0,
    contentType: false,
    processData: false,
    data: data.body,
    xhr: function() {
                // Create XMLHttpRequest object.
                let xhr = new XMLHttpRequest();

                // Handle event for when response headers arrive.
                xhr.onreadystatechange = function() {
                    if (xhr.readyState == 2) {
                        if (xhr.status == 200) {
                            xhr.responseType = 'blob';
                        } else {
                            xhr.responseType = 'text';
                        }
                    }
                };

                return xhr;
    },
    complete: function(xhr, status, error) {
        // Can access response headers but not binary response here.
    }
};

let response = await $.ajax(settings);
// @response is blob but cannot access XHR object here.

3 个答案:

答案 0 :(得分:1)

我不知道您是否受到某些过时的 jQuery 版本的限制,但实际上您可以做到所有这些。

<块引用>

$.ajax(settings) 的返回值包含二进制数据,但 XHR 对象不再可用——因此似乎无法分析响应头。

技术上,没有。 $.ajax(settings) 的返回值是 jqXHR 对象,因此您可以访问在回调中获得的相同对象。 在您的代码中,您使用的是 async/await 模式,因此无法访问 jqXHR 对象。但是你可以这样做

let jqXHR = $.ajax(settings);
jqXHR.then((response) => {
    console.log(response);
    console.log(res.getAllResponseHeaders());
});

这样,您将同时获得 jqXHR 对象和响应对象。

<块引用>

理想情况下,这可以从完整函数中完成,但完整函数无权访问 XHR 对象。 jqXHR 应该是 XHR 对象的超集,但 XHR.response 为空。

因为您在错误的时间访问它。为了填充 response 属性,您必须等到 readyState 4 而不是 2。请参阅XHR readyState
然后,您也可以在完整回调中获取响应对象。 只需像处理 xhr 响应一样处理 $.ajax(settings) 回调参数。

complete: function(xhr, status, error) {
    res.then((response) => {
        console.log(response);
        console.log(res.getAllResponseHeaders());
    });
}

如果您使用的是较新版本的 jQuery(我猜是最近 2-3 年的),您甚至可以编写这个简洁的代码

complete: async function (xhr, status, error) {
    console.log(xhr.getAllResponseHeaders());
    console.log(await xhr);
}

如果您字面上需要 XHR 对象,您也可以进行此 hack。

let xhr;
let settings = {
    //rest of things
    xhr: function () {
        return xhr = new XMLHttpRequest();
    }
};
let jqXHR = $.ajax(settings);
xhr.onreadystatechange = function() {
    if (xhr.readyState == 2) {
        if (xhr.status == 200) {
            xhr.responseType = 'blob';
        } else {
            xhr.responseType = 'text';
        }
    }
};
let response = await jqXHR;
console.log(response);

答案 1 :(得分:0)

我假设您使用的是 jQuery v1.5+。 complete 回调已被弃用,取而代之的是包含响应正文的 always。我可以在单个函数中获取它以及响应标头,执行以下操作:

$.ajax({
    url: 'https://static.wikia.nocookie.net/5dabc4c4-7cdb-438d-ba57-6b09afffcbb4',
    method: 'get',
})
  .always((responseBody, responseStatus, xhr) => {
    // You don't need this check when using .done()
    if (responseStatus === 'success') {
      if (xhr.getResponseHeader('content-type').startsWith('image')) {
        processImage(responseBody)
      }
    }
  })

这也适用于您的示例。让我知道这是否有效。

答案 2 :(得分:0)

为了动态确定响应,使用 success 函数代替 alwayscomplete 更方便(这些也会出错)。在其中,您可以获得 jqXHR 对象,您可以读取发回的数据类型。在确定它是二进制后(在下面的代码中,它是 image/png),您可以将响应从文本转换为二进制,并可选择将其放入 Blob。像这样:

let data = {
    url: "https://www.gravatar.com/avatar/cc0c5253923613abd592330ed8adb3a0?s=48&d=identicon&r=PG",
    body: {}
}
let settings = {
    url: data.url,
    method: "post",
    timeout: 0,
    contentType: false,
    processData: false,
    data: data.body,
    success: function(response, status, jqXHR) {
        var type = jqXHR.getResponseHeader('content-type');
        console.log(response);
        console.log(type);
        if(type === 'image/png'){
            var output = [];
            for (var i = 0; i < response.length; i++) {
                  output.push( response[i].charCodeAt(0).toString(2) + " ");
            }
            output = new Blob(output, {type : type});
            console.log(output);
        }
        else{
            console.log('type is not image/png');
        }
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.log("an error was encountered", errorThrown);
    }
};

$.ajax(settings);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

相关问题