{"id":713,"date":"2012-12-10T09:30:11","date_gmt":"2012-12-10T08:30:11","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=713"},"modified":"2012-12-10T23:05:30","modified_gmt":"2012-12-10T22:05:30","slug":"cross-domain-ajax-guide","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/cross-domain-ajax-guide\/","title":{"rendered":"Cross Domain AJAX Guide"},"content":{"rendered":"<p>As it is widely known, AJAX Requests are only possible if <b>port, protocol and domain<\/b> of sender and receiver are equal. This means, that the following requests <b>generally won&#8217;t work<\/b>:<\/p>\n<ul>\n<li>Requesting <span style=\"background:#FFCCCC\"><i>http<b>s<\/b>:\/\/foo.bar\/target.php<\/i><\/span><\/span> from <span style=\"background:#CCFFCC\"><i>http:\/\/foo.bar\/source.php<\/i><\/span><\/li>\n<li>Requesting <span style=\"background:#FFCCCC\"><i>http:\/\/<b>sub.<\/b>foo.bar<\/i><\/span> from <span style=\"background:#CCFFCC\"><i>http:\/\/foo.bar<\/i><\/span><\/li>\n<li>Requesting <span style=\"background:#FFCCCC\"><i>http:\/\/foo.bar<b>:5000<\/b><\/i><\/span> from <span style=\"background:#CCFFCC\"><i>http:\/\/foo.bar<\/i><\/span><\/li>\n<\/ul>\n<div id=\"attachment_714\" style=\"width: 542px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/remote-fail.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-714\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/remote-fail.png\" alt=\"Failed remote AJAX\" title=\"Failed remote AJAX\" width=\"532\" height=\"83\" class=\"size-full wp-image-714\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/remote-fail.png 532w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/remote-fail-300x46.png 300w\" sizes=\"auto, (max-width: 532px) 100vw, 532px\" \/><\/a><p id=\"caption-attachment-714\" class=\"wp-caption-text\">Failed remote AJAX<\/p><\/div>\n<p>Having this cleared out, we will cover ways around this restriction.<\/p>\n<h2>CORS<\/h2>\n<p>CORS stands for <i>Cross-origin resource sharing<\/i> and has to be supported on the server side. If we take jQuery, the <b>requesting side<\/b> will look like this:<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\n$.ajax({\r\n    type: &#039;POST&#039;,\r\n    url: &#039;http:\/\/d1303.de\/remote\/cors.php&#039;,\r\n    crossDomain: true,\r\n    data: &quot;my_request_is=foo&quot;,\r\n    dataType: &#039;json&#039;,\r\n    success: function(responseData, textStatus, jqXHR) \r\n\t{\r\n        console.log(responseData);\r\n    },\r\n    error: function (responseData, textStatus, errorThrown) \r\n\t{\r\n\t\tconsole.warn(responseData, textStatus, errorThrown);\r\n        alert(&#039;CORS failed - &#039; + textStatus);\r\n    }\r\n});\r\n<\/pre>\n<p>Be aware of the <b>crossDomain: true<\/b>. But take care! This will only work as expected, if the server side sends the appropriate response headers for CORS.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nheader(&#039;Access-Control-Allow-Origin: *&#039;);\r\nheader(&#039;Access-Control-Allow-Methods: POST, GET, OPTIONS&#039;);\r\nheader(&#039;Access-Control-Max-Age: 1000&#039;);\r\nheader(&#039;Access-Control-Allow-Headers: Content-Type&#039;);\r\n\r\necho json_encode(array(&quot;your_request_was&quot; =&gt; $_POST[&#039;my_request_is&#039;]));\r\n<\/pre>\n<p>Here, we accept requests from each and every source for the request methods POST, GET and OPTIONS. For more details regarding the various parameters, see <a href=\"http:\/\/www.w3.org\/TR\/2008\/WD-access-control-20080912\/#syntax\">this W3C document<\/a>. For example, you can accept requesting domains like so:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nswitch ($_SERVER[&#039;HTTP_ORIGIN&#039;]) {\r\n    case &#039;http:\/\/from.com&#039;: \r\n\tcase &#039;https:\/\/from.com&#039;:\r\n\t\theader(&#039;Access-Control-Allow-Origin: &#039;.$_SERVER[&#039;HTTP_ORIGIN&#039;]);\r\n\t\theader(&#039;Access-Control-Allow-Methods: POST, GET, OPTIONS&#039;);\r\n\t\theader(&#039;Access-Control-Max-Age: 1000&#039;);\r\n\t\theader(&#039;Access-Control-Allow-Headers: Content-Type&#039;);\r\n\t\t\r\n\t\techo json_encode(array(&quot;your_request_was&quot; =&gt; $_POST[&#039;my_request_is&#039;]));\r\n\t\t\r\n    break;\r\n}\r\n<\/pre>\n<p>For more ways to implement CORS on the server side, see <a href=\"http:\/\/enable-cors.org\/\">enable-cors.org<\/a>.<\/p>\n<div id=\"attachment_715\" style=\"width: 483px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/cors.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-715\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/cors.png\" alt=\"CORS\" title=\"CORS\" width=\"473\" height=\"500\" class=\"size-full wp-image-715\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/cors.png 473w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/cors-283x300.png 283w\" sizes=\"auto, (max-width: 473px) 100vw, 473px\" \/><\/a><p id=\"caption-attachment-715\" class=\"wp-caption-text\">CORS<\/p><\/div>\n<p>Browser support is excellent (IE >= 8, Firefox >= 3.5, Chrome >= 3).<\/p>\n<h2>JSONP<\/h2>\n<p>Let&#8217;s move on to the next way of making Cross Domain AJAX possible: JSONP. Like CORS, the server has to support JSONP. Basically, the client tells the server the callback function for the response. The server then wraps the response in this callback function. Example? Example!<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\n$.ajax({\r\n    type: &#039;GET&#039;,\r\n    url: &#039;http:\/\/d1303.de\/remote\/jsonp.php&#039;,\r\n    data: &quot;my_request_is=foo&quot;,\r\n    dataType: &#039;jsonp&#039;,\r\n    success: function(responseData, textStatus, jqXHR) \r\n\t{\r\n        console.log(&quot;the response is&quot;, responseData);\r\n    },\r\n    error: function (responseData, textStatus, errorThrown) \r\n\t{\r\n\t\tconsole.warn(responseData, textStatus, errorThrown);\r\n        alert(&#039;JSONP failed - &#039; + textStatus);\r\n    }\r\n});\r\n<\/pre>\n<p>Let&#8217;s look at the request:<\/p>\n<div id=\"attachment_717\" style=\"width: 378px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/jsonp.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-717\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/jsonp.png\" alt=\"JSONP\" title=\"JSONP\" width=\"368\" height=\"71\" class=\"size-full wp-image-717\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/jsonp.png 368w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/jsonp-300x57.png 300w\" sizes=\"auto, (max-width: 368px) 100vw, 368px\" \/><\/a><p id=\"caption-attachment-717\" class=\"wp-caption-text\">JSONP<\/p><\/div>\n<p>jQuery automatically appends a no cache-parameter with the timestamp and &#8211; more interesting &#8211; the <b>callback<\/b>. On the server side, we can now do the following:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\n$callback = $_GET[&#039;callback&#039;];\r\n$response = json_encode(array(&quot;your_request_was&quot; =&gt; $_GET[&#039;my_request_is&#039;]));\r\n\r\necho $callback . &quot;(&quot; . $response . &quot;)&quot;;\r\n<\/pre>\n<p>This way, the servers response looks like this:<\/p>\n<div id=\"attachment_718\" style=\"width: 527px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/JSONP-response.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-718\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/JSONP-response.png\" alt=\"JSONP response\" title=\"JSONP response\" width=\"517\" height=\"57\" class=\"size-full wp-image-718\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/JSONP-response.png 517w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2012\/12\/JSONP-response-300x33.png 300w\" sizes=\"auto, (max-width: 517px) 100vw, 517px\" \/><\/a><p id=\"caption-attachment-718\" class=\"wp-caption-text\">JSONP response<\/p><\/div>\n<p>jQuery is now able to invoke the success callback with this information. It is also possible, to specify your own callback with a more readable name, see the <a href=\"http:\/\/api.jquery.com\/jQuery.ajax\/\">$.ajax docs<\/a>.<\/p>\n<p>\nAs far as I know, there are no browser compatibility issues at all.\n<\/p>\n<h2>iframe<\/h2>\n<p>This is more a hack than a &#8222;clean&#8220; solution. The theory behind this approach is to place a hidden iframe to your requesting page via javascript and then construct a hidden form, that is posting to the iframe. This way, it&#8217;s possible to get around the cross domain issue.<\/p>\n<p><b>The function:<\/b><\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\nfunction postIframe(target_url, method, params) \r\n{\r\n\t\/\/Add iframe\r\n\tvar iframe = document.createElement(&quot;iframe&quot;);\r\n\tdocument.body.appendChild(iframe);\r\n\tiframe.style.display = &quot;none&quot;;\r\n\t\r\n\t\/\/Give the frame a name\r\n\tvar frame_name = &quot;frame_name&quot; + (new Date).getTime();\r\n\tiframe.contentWindow.name = frame_name;\r\n\r\n\t\/\/build the form\r\n\tvar form = document.createElement(&quot;form&quot;);\r\n\tform.target = frame_name;\r\n\tform.action = target_url;\r\n\tform.method = method;\r\n\r\n\t\/\/loop through all parameters\r\n\tfor (var key in params)\r\n\t{\r\n\t\tif (params.hasOwnProperty(key))\r\n\t\t{\r\n\t\t\tvar input = document.createElement(&quot;input&quot;);\r\n\t\t\tinput.type = &quot;hidden&quot;;\r\n\t\t\tinput.name = key;\r\n\t\t\tinput.value = params[key];\r\n\t\t\tform.appendChild(input);\r\n\t\t}\r\n\t}\r\n\r\n\tdocument.body.appendChild(form);\r\n\tform.submit();\r\n}\r\n<\/pre>\n<\/p>\n<p>As we see, a hidden iframe is put on the page. After that, we create a form containing all request parameters as a hidden form field. Finally, the form is programatically sent. We can now trigger the request like this:<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\nvar obj = { my_request_is: &quot;foo&quot;, bar: &quot;baz&quot; };\r\npostIframe(&quot;http:\/\/d1303.de\/remote\/iframe.php&quot;, &quot;POST&quot;, obj);\r\n<\/pre>\n<p>However, there is one big downside: There is no easy way to get the server response from our request, this is more like a &#8222;fire and forget&#8220; one way-request. If you really want to stick to this approach, <a href=\"http:\/\/softwareas.com\/cross-domain-communication-with-iframes\">here is more info on that<\/a>.<\/p>\n<h2>Other approaches<\/h2>\n<p>Even though CORS and JSONP are the most popular methods of doing cross domain AJAX, there are other ways. <\/p>\n<ul>\n<li>Take a look at the relatively new <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/DOM\/window.postMessage\">window.postMessage<\/a> (part of the HTML5 feature set) &#8211; examples <a href=\"http:\/\/davidwalsh.name\/window-postmessage\">here<\/a> and <a href=\"http:\/\/ejohn.org\/blog\/cross-window-messaging\/\">here<\/a>.<\/li>\n<li>Another classic approach that is typically taken for this kind of problem is to place a server side script in the language of your choice (e.g. PHP) on your server and request this script via AJAX &#8211; which is not a problem, because requesting side and responding side are on the same domain. Your server side script then forwards the request to the remote location and responds back to your script. See the excellent article <a href=\"http:\/\/gonzalo123.com\/2012\/08\/13\/building-a-simple-api-proxy-server-with-php\/\">Building a simple API proxy server with PHP<\/a> for more details.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>As it is widely known, AJAX Requests are only possible if port, protocol and domain of sender and receiver are equal. This means, that the following requests generally won&#8217;t work: Requesting https:\/\/foo.bar\/target.php from http:\/\/foo.bar\/source.php Requesting http:\/\/sub.foo.bar from http:\/\/foo.bar Requesting http:\/\/foo.bar:5000 &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/cross-domain-ajax-guide\/\">Weiterlesen <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":{"footnotes":""},"categories":[12,3],"tags":[],"class_list":["post-713","post","type-post","status-publish","format-standard","hentry","category-javascript","category-webdev"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/713","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=713"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/713\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}