Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery: access binary AJAX response inside complete function or access XHR object outside of callback functions?

There are many questions on handling binary AJAX responses with jQuery like this, this, and this. None help.

Goals: (1) dynamically determine if a response contains binary data, and handle it differently from text; (2) analyze response headers; and (3) do both from a single function.

Ideally, this can be done from the complete function, but the complete function doesn't have access to the XHR object. jqXHR is supposed to be a superset of the XHR object, but XHR.response is blank.

The return value of $.ajax(settings) contains the binary data, but the XHR object is no longer available -- so it seems not possible to analyze the response headers.

Is it possible to access the binary AJAX response inside the complete callback or access the XHR object outside of the callback functions? The

// 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.
like image 725
Crashalot Avatar asked Jan 17 '26 12:01

Crashalot


2 Answers

I assume you're using jQuery v1.5+. The complete callback was deprecated in favor of always, which includes the response body. I could get it, along with the response headers, in a single function doing something like:

$.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)
      }
    }
  })

This should work in your example too. Let me know if that worked.

like image 149
Carlos Jiménez Avatar answered Jan 20 '26 00:01

Carlos Jiménez


I don't know if you are constrained by some archaic version of jQuery, but you can actually do all of that.

The return value of $.ajax(settings) contains the binary data, but the XHR object is no longer available -- so it seems not possible to analyze the response headers.

Technically, no. The return value of $.ajax(settings) is jqXHR object, So you can access the same object that you get within the callbacks. In your code, you are using the async/await pattern, and thus not able to access the jqXHR object. But you can do so

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

This way, you will get both the jqXHR object and the response object.

Ideally, this can be done from the complete function, but the complete function doesn't have access to the XHR object. jqXHR is supposed to be a superset of the XHR object, but XHR.response is blank.

Because you are accessing it at the wrong time. In order for the response property to be populated, you have to wait until readyState 4 instead of 2. Refer to XHR readyState.
Then again, you can get the response object within the complete callback too. Just treat the xhr callback parameter the same way you would do the $.ajax(settings) response.

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

If you are using the newer versions of jQuery (I guess the last 2-3 year ones), you can even write this neat code

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

And if you literally need the XHR object, you can do this hack too.

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);
like image 25
gliesefire Avatar answered Jan 20 '26 01:01

gliesefire



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!