Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

254
Views
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.
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

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.

over 4 years ago · Santiago Trujillo Report

0

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);
over 4 years ago · Santiago Trujillo Report

0

In order to dynamically determine the response, it's more convenient to use the success function instead of always or complete (these will also run on error). In it, you get the jqXHR object and you can read the data type that was sent back. After determining that it is binary (in the code below, it's image/png), you can convert the response from text to binary, and optionally put it in a Blob. Like so:

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>

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!