11

Is it possible to access the XMLHttpRequest object from the success callback of the $.ajax() function? Specifically I need access to XMLHttpRequest.responseBody in IE. Per the documentation the returned jqXHR object does not expose the .responseBody property.

This seems to be a minor oversite that has a huge impact when dealing with binary data. If the .responseBody property or the underlying XMLHttpRequest object is not accessible I'll have to skip jQuery for ajax and code it in, shudder, pure javascript.

Update

I am infact looking for the responceBody variable, not the responceText variable that is readily accessible from within $.ajax()

Justin808
  • 20,859
  • 46
  • 160
  • 265
  • possible duplicate of [Getting AJAX response body for use in error callback](http://stackoverflow.com/questions/2084484/getting-ajax-response-body-for-use-in-error-callback) – balexandre Jun 01 '11 at 06:31

5 Answers5

8

You can use beforeSend callback too:

$.ajax({
    beforeSend: function(jqXHR, settings){
        // Here you are the XHR object
        console.log(settings.xhr());
    }
});
Manuel Bitto
  • 5,073
  • 6
  • 39
  • 47
  • 2
    Not sure why this doesn't have more votes, seems like the best solution to me. – tomswift Feb 01 '13 at 22:34
  • I think it's because for years you couldn't count on beforeSend necessarily working for all browsers. I assume it's an issue that's been fixed over time, but I think people are still gun-shy of using any event except for the most important ones such as success and error. – Ringo Jun 11 '13 at 18:20
  • 9
    The proble is that ir returns a new instance of XMLHttpRequest instead of the one being used for the request, so any changes won't take effect. – Macario Oct 27 '13 at 08:44
7

The xhr function for the ajax request can be overriden.

$.ajax({
  ...
  xhr: function(){
    var xhr = jQuery.ajaxSettings.xhr();
    // do stuff with xhr;
    return xhr;
  }

});

Or to elaborate on Manuel Bitto's answer, the xhr instance can be accessed from beforeSend callback:

$.ajax({
  beforeSend: function(jqXHR, settings){
    var xhr = jQuery.ajaxSettings.xhr();
    settings.xhr = xhr
    // Do stuff with the xhr instance for this request
    xhr.onprogress = function(){

    }
    console.log(xhr);
  }
});
Macario
  • 2,214
  • 2
  • 22
  • 40
  • I understand that settings.xhr is a function returning a xhr object, not the object itself. (from http://api.jquery.com/jQuery.ajax/#advanced-options) does this work anyway? – simohe Nov 09 '18 at 09:40
3

Provide the xhr settings field to create the XMLHttpRequest, and retain a reference to the object. A quick way to do this is by adding it to the settings object (which is accessible via this in the callbacks).

$.ajax({
    url: "/whatever",
    xhr: function(){
        return this._xhr = new XMLHttpRequest();
    },
    success: function(){
        console.log("Original XHR:", this._xhr);
    }
});
Glenn Lane
  • 3,892
  • 17
  • 31
  • This is the only solution that worked for me. All the other answers just seem to return new instances, not the current XMLHttpRequest. – slightlyfaulty Feb 11 '20 at 23:12
2

I, too, was looking to get at the underlying XMLHttpRequest object in order to get at the 'onprogress' and 'upload' properties (found in more recent browsers that use XMLHttpRequest2) so that I could do native upload progress handling instead of using hacks. After digging through the jQuery source I found that you CAN get at it via jQuery.ajaxSettings.xhr(). It's a function that returns a raw XMLHttpRequest.

See here: https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js

Hope that helps.

Aquarelle
  • 8,864
  • 1
  • 17
  • 11
1

I know this is an old question, but I just solved it.

What do we know about the situation? We know that jQuery no longer passes around the original XmlHttpRequest object, nor any references to it. We know that instead if passes around a "superset" that has most of the attributes. AND, we know that jQuery still uses an XmlHttpRequest to do the AJAX call.

So, if the browser still gets a callback and is passed the actual XmlHttpRequest, can we programatically access it? Using arguments.callee.caller, Yes. We. Can.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee

By the time your hook fires (success, fail, whatever), you have just a few guarantees: You are in the callback callstack, the first function (the callback) has the XHR, and it has no caller.

So, loop through the callstack (arguments.callee.caller.arguments.callee.caller...) until the caller is null, then look at the arguments! The first argument will be the callback Event object, and that event will have the XHR object created by the browser in the srcElement attribute.

$.ajax({
  url: 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F',
  type: 'get',
  success: function(data, textStatus, jqXHR) {
    var caller = arguments.callee.caller;
    while(caller.arguments.callee.caller != null) {
      caller = caller.arguments.callee.caller;
    }
    console.log(caller.arguments[0]);
    console.log(caller.arguments[0].srcElement.responseURL);
  }
});
Nate
  • 1,268
  • 13
  • 20
  • 1
    You sould neither use `callee` nor `caller` in production code. The different variations are either not standart, deprecated or do not exist anymore at all. – t.niese Sep 09 '16 at 17:33
  • As further information: [Why was the arguments.callee.caller property deprecated in JavaScript?](http://stackoverflow.com/questions/103598/why-was-the-arguments-callee-caller-property-deprecated-in-javascript/235760#235760) – t.niese Sep 09 '16 at 17:41
  • 1
    Jquery doesn't seem to understand what "superset" means. – Zamicol Oct 12 '16 at 20:19