25

I wanted to know if anyone has had experience with trying to remove the 'X-Requested-With' header from the ajax request made by jquery (or plain JS). is it possible?

2nd part: do you know if Grease Monkey's ajax requests set this header?

Thanks

header looks like this:

X-Requested-With XMLHttpRequest
npdoty
  • 4,729
  • 26
  • 25
mkoryak
  • 57,086
  • 61
  • 201
  • 257
  • I think one of the advantages of having this header set is so that you can check for it in your server-side script and determine whether it was indeed an AJAX request and therefore how to handle it? – MrWhite Jul 30 '10 at 15:34
  • 2
    w3d: and the disadvantage of having server side know when you made an ajax request is that they can prevent you from doing it in your GM script – mkoryak Feb 05 '11 at 21:52

6 Answers6

30

The solution for removing the header in jQuery proposed by @vamp is on the right track, but as others have stated it will still result in an empty X-Requested-With header being sent.

The beforeSend callback receives jQuery's XHR object (jqXHR), rather than the actual XMLHttpRequest object (xhr), which is not even instantiated until after beforeSend is called.

The setRequestHeader method in jqXHR adds headers to an object, which is then iterated later using the xhr method of the same name, just after adding the X-Requested-With entry to the headers object.

Here's the part in jQuery where this is happening:

if ( !options.crossDomain && !headers["X-Requested-With"] ) {
    headers["X-Requested-With"] = "XMLHttpRequest";
}

for ( i in headers ) {
    xhr.setRequestHeader( i, headers[ i ] );
}

Which leads to the problem: If you don't specify the X-Requested-With header, then jQuery will (unless the crossDomain setting evaluates false, but that may not be the desired solution). It then immediately sets the xhr headers, which can not be unset.


To prevent sending the X-Requested-With header with jQuery.ajax:

jQuery.ajax provides a setting, xhr, which overrides jQuery's built-in factory method for creating the XMLHttpRequest object. By wrapping this factory method, and then wrapping the browser's native setRequestHeader method, the call from jQuery to set the X-Requested-With header can be ignored.

jQuery.ajax({

    url: yourAjaxUrl,

    // 'xhr' option overrides jQuery's default
    // factory for the XMLHttpRequest object.
    // Use either in global settings or individual call as shown here.
    xhr: function() {
        // Get new xhr object using default factory
        var xhr = jQuery.ajaxSettings.xhr();
        // Copy the browser's native setRequestHeader method
        var setRequestHeader = xhr.setRequestHeader;
        // Replace with a wrapper
        xhr.setRequestHeader = function(name, value) {
            // Ignore the X-Requested-With header
            if (name == 'X-Requested-With') return;
            // Otherwise call the native setRequestHeader method
            // Note: setRequestHeader requires its 'this' to be the xhr object,
            // which is what 'this' is here when executed.
            setRequestHeader.call(this, name, value);
        }
        // pass it on to jQuery
        return xhr;
    },

    success: function(data, textStatus, jqXHR) {
        // response from request without X-Requested-With header!
    }

    // etc...

});
Synexis
  • 1,255
  • 14
  • 14
  • I have a script that makes a cross domain request, which should have been a simple CORS request, but because jQuery automatically adds the `X-Requested-With` header, which is considered custom, it made the browser make an unnecessary CORS preflight check. Thanks for sharing this, I was going crazy trying to figure out why I couldn't skip the preflight. – Dooms101 Nov 30 '15 at 20:18
7

To do this with jQuery, set your request as cross-domain. Example:

server.php

<?='<pre>'.print_r($_SERVER,1);?>

client.js

$.ajax({ url: 'server.php', crossDomain: true }).success(function(r){document.write(r)})
f.ardelian
  • 6,716
  • 8
  • 36
  • 53
  • 1
    This worked for me trying to access the Pinterest API using jQuery (e.g. https://api.pinterest.com/v3/pidgets/users/USERNAME/pins/) – Tebbers Mar 11 '16 at 13:30
7

why not? try:

(function(){
    $.ajaxSettings.beforeSend=function(xhr){
        xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }});
    };
})(jQuery);

good luck!

vamp
  • 120
  • 1
  • 2
  • Not that I really expected it to be browser-specific, but it worked fine for me in Firefox 4, Chrome 10, IE 9, and Opera 11. For what I am needing, I don't mind altering *all* AJAX requests, but I wonder if there is a way to make this happen for only specific requests. – patridge May 13 '11 at 14:02
  • Can't you add a beforeSend callback to the $.ajax call itself? –  Jun 06 '11 at 20:02
  • According to @Marin's [mostly identical] answer, it looks like you can. In a [sample jsFiddle](http://jsfiddle.net/patridge/amA3W/), I remove the `X-Requested-With` header and fail to remove the `Referer` header (Chrome won't let it happen). For extra fun, I also put together a [fiddle with this all-requests version](http://jsfiddle.net/patridge/h4Lvp/). – patridge Mar 06 '12 at 16:01
  • 15
    Does NOT work. Only sets the header's value to an empty string. The header is still sent. – Nicholas Shanks Feb 21 '13 at 09:42
3

"2nd part: do you know if Grease Monkey's ajax requests set this header?"

No, Greasemonkey's GM_xmlhttpRequest() does not set this header (although you can certainly add it).

The default request issued by GM_xmlhttpRequest() looks just like a normal browser request.
For example:

GM_xmlhttpRequest
({
    method:     "GET",
    url:        "http://google.com/",
    onload:     function(response) {alert(response.responseText); }
});

Looks like this to my packet sniffer:

GET / HTTP/1.1
    Request Method: GET
    Request URI: /
    Request Version: HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: UTF-8,*
Keep-Alive: 115
Connection: keep-alive
Cookie: blah, blah, blah, blah, blah...
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
0

jQuery doesn't expose a method to do this at the moment, there was a ticket on it a while back related to Firefox errors, but rather than making it an option, they fixed the error issue in Firefox.

If you're curious, you can see where it's added here, but you can't remove it without editing/overriding jQuery core: http://github.com/jquery/jquery/blob/master/src/ajax.js#L370

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
-2

You may consider this:

$.ajax({
  url: 'http://fiddle.jshell.net/favicon.png',
  beforeSend: function( xhr ) {
    xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }});
  },
  success: function( data ) {
    if (console && console.log){
      console.log( 'Got data without the X-Requested-With header' );
    }
  }
});
Marin Purgar
  • 189
  • 2
  • 11
  • 2
    While the `beforeSend` section is identical, this is a more granular way of removing the header (per-request vs. all requests as @vamp did it). That said, there should probably be clarification of how it is different in the answer to help those looking for this type of solution. – patridge Mar 06 '12 at 15:20
  • 1
    Does NOT work. Only sets the header's value to an empty string. The header is still sent. – Nicholas Shanks Feb 21 '13 at 09:42