关于使用 jQuery 处理二进制 AJAX 响应有很多问题,例如 this、this 和 this。没有帮助。
目标:(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.
答案 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
函数代替 always
或 complete
更方便(这些也会出错)。在其中,您可以获得 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>