{"id":342,"date":"2012-06-10T09:37:41","date_gmt":"2012-06-10T16:37:41","guid":{"rendered":"http:\/\/sloanseaman.com\/wordpress\/?p=342"},"modified":"2012-06-10T09:37:41","modified_gmt":"2012-06-10T16:37:41","slug":"ajax-interception","status":"publish","type":"post","link":"http:\/\/sloanseaman.com\/wordpress\/2012\/06\/10\/ajax-interception\/","title":{"rendered":"Ajax Interception"},"content":{"rendered":"<h3>The Problem<\/h3>\n<p>I recently had a problem where I needed to intercept any AJAX based calls from the browser to, well, anything.  After a lot of Googling and digging through StackOverflow all I ever found were suggestions for event listeners specific to JQuery or partial solutions that didn&#8217;t really work.<\/p>\n<p\/>\nThere are many instances where you want to grab all the AJAX calls being made.  For debugging, for interception to override existing functionality, for parameter injection, etc.<\/p>\n<h3>The Solution<\/h3>\n<p>The code I wrote is a JQuery plug in but should work for any AJAX calls even if not in JQuery code.  <\/p>\n<p\/>\nFirst, if you are not familiar with basic AJAX functionality, it&#8217;s all based around the XMLHttpRequest object.  I suggest you read <A href=\"http:\/\/www.w3schools.com\/xml\/xml_http.asp\">W3Schools<\/a> and <a href=\"https:\/\/developer.mozilla.org\/en\/XMLHttpRequest\">Mozilla&#8217;s<\/a> descriptions.\n<\/p>\n<p>Lets look at the code now.  Source code available here: <a href=\"http:\/\/www.sloanseaman.com\/code\/ajaxInterceptor.js\">ajaxInterceptor.js<\/a><\/p>\n<pre class=\"brush: jscript; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\/*\r\n * Util for intercepting all ajax calls \r\n * \r\n * Options:\r\n * open : {\r\n *   fn : function() {}, \/\/ function to call when open is called\r\n *   scope : xxx         \/\/ Scope to execution function in\r\n * },\r\n * send  : {\r\n *   fn : function() {}, \/\/ function to call when set is called\r\n *   scope : xxx         \/\/ Scope to execution function in\r\n * },\r\n * setRequestHeader  : {\r\n *   fn : function() {}, \/\/ function to call when setRequestHeader is called\r\n *   scope : xxx         \/\/ Scope to execution function in\r\n * },\r\n *\/\r\n\r\n(function( $ ) {\r\n\tvar defaultOptions = {\r\n\t\topen \t\t\t\t:  { },\r\n\t\tsend \t\t\t\t:  { },\r\n\t\tsetRequestHeader  \t:  { }\r\n\t}\r\n\r\n\tvar options;\r\n\tvar aiOpen = window.XMLHttpRequest.prototype.open;\r\n\tvar aiSend = window.XMLHttpRequest.prototype.send;\r\n\tvar aiSet  = window.XMLHttpRequest.prototype.setRequestHeader;\r\n\tvar recurrsion = false;\r\n\t\r\n\tvar methods = {\r\n\t\tinit : function(opts) {\r\n\t\t\toptions = $.extend(true, defaultOptions, opts);\r\n\t\t\tmethods.enable();\r\n\t\t},\r\n\t\t\r\n\t\tenable : function() {\r\n\t\t\twindow.XMLHttpRequest.prototype.open = function(method,url,async,uname,pswd) {\r\n\t\t\t\tif (options.open.fn) {\r\n\t\t\t\t\toptions.open.fn.call(options.open.scope?options.open.scope:this, \r\n\t\t\t\t\t\tmethod,\r\n\t\t\t\t\t\turl,\r\n\t\t\t\t\t\tasync,\r\n\t\t\t\t\t\tuname,\r\n\t\t\t\t\t\tpswd);\r\n\t\t\t\t}\r\n\t\t\t\taiOpen.call(this, method,url,async,uname,pswd);\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\twindow.XMLHttpRequest.prototype.send = function(data) {\r\n\t\t\t\tif (options.send.fn &amp;&amp; !recurrsion) {\r\n\t\t\t\t\trecurrsion = true;\r\n\t\t\t\t\toptions.send.fn.call(options.send.scope?options.send.scope:this, \r\n\t\t\t\t\t\tdata);\r\n\t\t\t\t\trecurrsion = false;\r\n\t\t\t\t}\r\n\t\t\t\taiSend.call(this, data);\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\twindow.XMLHttpRequest.prototype.setRequestHeader = function(key, value) {\r\n\t\t\t\tif (options.setRequestHeader.fn) {\r\n\t\t\t\t\toptions.setRequestHeader.fn.call(options.setRequestHeader.scope?options.setRequestHeader.scope:this, \r\n\t\t\t\t\t\tkey, \r\n\t\t\t\t\t\tvalue);\r\n\t\t\t\t}\r\n\t\t\t\taiSet.call(this, key, value);\r\n\t\t\t};\r\n\t\t},\r\n\t\t\r\n\t\tdisable : function() {\r\n\t\t\twindow.XMLHttpRequest.prototype.open = aiOpen;\r\n\t\t\twindow.XMLHttpRequest.prototype.send = aiSend;\r\n\t\t\twindow.XMLHttpRequest.prototype.setRequestHeader = aiSet;\r\n\t\t}\r\n\t}\r\n\r\n\t$.fn.ajaxInterceptor = function( method ) {\r\n\t\tif ( methods[method] ) {\r\n\t\t\treturn methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));\r\n\t\t} else if ( typeof method === 'object' || ! method ) {\r\n\t\t\treturn methods.init.apply( this, arguments );\r\n\t\t} else {\r\n\t\t\t$.error( 'Method ' +  method + ' does not exist on ajaxInterceptor' );\r\n\t\t}    \r\n\t};\r\n})(jQuery);\r\n\r\n<\/pre>\n<p>Lets go over the code so you can understand what is going on.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\tvar defaultOptions = {\r\n\t\topen \t\t\t\t:  { },\r\n\t\tsend \t\t\t\t:  { },\r\n\t\tsetRequestHeader  \t:  { }\r\n\t}\r\n<\/pre>\n<p>First thing I do is set up the defaults that developers can override as well as ensure that I don&#8217;t get any &#8216;undefined&#8217; errors in the javacript.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\tvar options;\r\n\tvar aiOpen = window.XMLHttpRequest.prototype.open;\r\n\tvar aiSend = window.XMLHttpRequest.prototype.send;\r\n\tvar aiSet  = window.XMLHttpRequest.prototype.setRequestHeader;\r\n\tvar recurrsion = false;\r\n<\/pre>\n<p>Next I define some variables but the key thing to pay attention to is the <code>aiOpen<\/code>, <code>aiSend<\/code>, and <code>aiSet<\/code> variables.  What this is actually doing is taking the <code>XMLHttpRequest<\/code>&#8216;s open, send, and setRequestHeader methods and placing them into variables.  I can use this later to disable whatever I do in the code by reverting my changes to these variables.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\ninit : function(opts) {\r\n\toptions = $.extend(true, defaultOptions, opts);\r\n\tmethods.enable();\r\n},\r\n<\/pre>\n<p>The init() method does nothing more that take in any options the developer passes in, use them to override the defaultOptions and store the resulting combination of the two into the <code>options<\/code> variable.  After that it calls the enable() method.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nwindow.XMLHttpRequest.prototype.open = function(method,url,async,uname,pswd) {\r\n\tif (options.open.fn) {\r\n\t\toptions.open.fn.call(options.open.scope?options.open.scope:this, \r\n\t\t\tmethod,\r\n\t\t\turl,\r\n\t\t\tasync,\r\n\t\t\tuname,\r\n\t\t\tpswd);\r\n\t}\r\n\taiOpen.call(this, method,url,async,uname,pswd);\r\n};\r\n<\/pre>\n<p>The first part of the <code>enable<\/code> method overrides the <code>XMLHttpRequest<\/code>&#8216;s <code>open<\/code> method with my method.  All my method does is call a method that the developer might have passed via the options and then calls the normal <code>open<\/code> method.  This way we can run whatever method we want before the <code>open<\/code> is actually executed.<\/p>\n<p\/>\nThe next two methods are just variations on a theme.  The <code>send<\/code> and <code>setRequestHeader<\/code> do the exact same thing as <code>open<\/code> so I won&#8217;t go over them (hope you don&#8217;t mind)<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\ndisable : function() {\r\n\twindow.XMLHttpRequest.prototype.open = aiOpen;\r\n\twindow.XMLHttpRequest.prototype.send = aiSend;\r\n\twindow.XMLHttpRequest.prototype.setRequestHeader = aiSet;\r\n}\r\n<\/pre>\n<p>As I mentioned before, one of the main reasons I placed the methods in variables is to undo what I overwrote.  In this case I&#8217;m just restoring the original functionality of the XMLHttpRequest object any time the <code>disable<\/code> is called.<\/p>\n<h3>Example Usage<\/h3>\n<p>Lets now show a few ways this can be used.  The most common would be to intercept any calls to the AJAX service on the server side.  This is in XMLHttpRequest object terms, the <code>send<\/code> call.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;script src=&quot;jquery-1.7.2.min.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script src=&quot;ajaxInterceptor.js&quot;&gt;&lt;\/script&gt;\r\n&lt;script&gt;\r\n$(document).ajaxInterceptor({\r\n\tsend : {\r\n\t\tfn : function(data) { alert('send'); }\r\n\t}\r\n});\r\n<\/pre>\n<p>First we need to bring in the JQuery library and of course the ajaxInterceptor library itself.  Next we attach it to the <code>document<\/code> as that is basically the root of what we want (basically we are just attaching it to one of the most parent objects but really we could attach it to anything).<\/p>\n<p\/>\nWe then pass in the option &#8220;send&#8221; and a function that will <code>alert('send')<\/code> any time <code>send<\/code> is called.<\/p>\n<p\/>\nThat&#8217;s all there is to it!  If you put your code in the <code>fn: function<\/code> and it will be executed whenever any AJAX <code>send<\/code> is called.  <\/p>\n<p\/>\nI should note that the data that is passed in is the same data object that would be passed to the underlying <code>XMLHttpRequest send<\/code> function.  Also, the <code>send<\/code> can be passed a <code>scope<\/code> if you want your method to execute in a specific scope.<\/p>\n<p\/>\n<p>The next example is how to disable the code if you ever need to.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n$(document).ajaxInterceptor(&quot;disable&quot;);\r\n<\/pre>\n<p>Again, pretty easy.  The code follows the standard JQuery plug-in methodology.<\/p>\n<p\/>\n<p>I hope this code helps you out.  I really could not find any good examples anywhere that were as encompassing as this one.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Problem I recently had a problem where I needed to intercept any AJAX based calls from the browser to, well, anything. After a lot of Googling and digging through StackOverflow all I ever found were suggestions for event listeners &hellip; <a href=\"http:\/\/sloanseaman.com\/wordpress\/2012\/06\/10\/ajax-interception\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[17,10],"tags":[29,26,19],"_links":{"self":[{"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/posts\/342"}],"collection":[{"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/comments?post=342"}],"version-history":[{"count":11,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/posts\/342\/revisions"}],"predecessor-version":[{"id":359,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/posts\/342\/revisions\/359"}],"wp:attachment":[{"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/media?parent=342"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/categories?post=342"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sloanseaman.com\/wordpress\/wp-json\/wp\/v2\/tags?post=342"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}