How to play with cross domain request

  sonic0002        2016-11-06 00:48:54       11,342        0    

What is cross domain request

In simple, cross domain request is to request resource from other domain in one domain. Note, the "other domain" doesn't just mean domain name only, it includes much more. If the protocol, domain name, port is not the same, two domains will be considered different. 

Below example describes what is considered as different domain.

http://www.a.com/a.js
http://www.a.com/b.js               # Same domain
http://www.a.com/lab/a.js         # Same domain
http://www.a.com/script/b.js     # Same domain
http://www.a.com:8000/a.js      # Different domain
https://www.a.com/b.js             # Different domain
http://70.32.92.74/b.js             # Different domain
http://script.a.com/b.js             # Different domain
http://a.com/b.js                       # Different domain
http://www.example.com/a.js    # Different domain

It's frequently needed to request resource provided by other domains such as public APIs from Google, Facebook etc. But this opens a security black hole that the site issues the request may get smashed. Hence all mainstream browsers have restrictions on performing cross domain request. This enforces the security of the site but brings inconvenience to many applications which depend on public APIs from other sites.

Note : If a cross domain request is happening because of different protocol or port, the front end has no way to resolve the cross domain request restriction.

Resolve cross domain request restriction

document.domain

Browsers have a same origin policy, it has following restrictions

  • An AJAX request can not request resource from a different origin
  • Pages from different domains within iframes cannot communicate with each other. Though the window object can be obtained between different windows, the properties and methods of the window object cannot be obtained.  For example, if there is a page http://www.a.com/a.html, it contains an iframe whose src is http://a.com/b.html. Apparently the page a.html has a different domain as the one in the iframe, hence it's impossible to get objects from the iframe within a.html.
    <script type="text/javascript">
        function test(){
            var iframe = document.getElementById('ifame');
            var win = iframe.contentWindow;// Can get window
            var doc = win.document;// Cannot get document object of iframe
            var name = win.name;// Cannot get name property
        }
    </script>
    <iframe id = "iframe" src="http://a.com/b.html" onload = "test()"></iframe>

In above case, document.domain can be used. The document.domain only needs to be set to the same domain in above two pages. However, there is one restriction of document.domain, document.domain can only be set to itself or its parent domain and the root domain must be the same.

In http://www.a.com/a.html , write below code:

<iframe id = "iframe" src="http://a.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
    document.domain = 'a.com';//Set root domain
    function test(){
        alert(document.getElementById('iframe').contentWindow);// Can get window object
    }
</script>

In http://a.com/b.html , write below code:

document.domain = 'a.com';

This method only applies to communications between different subdomains of the same root domain.

location.hash

Parent window can read/write iframe src, and iframe can also read/write parent URL. hash(#) is part of an URL and is used for hook something in a page. The server usually doesn't care about hash and the change to this will not create a new HTTP request. 

hash can be used to exchange data between two domains. Each window can update location(In IE and Chrome, the value of parent.location.hash cannot be changed, hence a proxy iframe is needed to update the parent location hash value).

Assuming that the parent page is http://a.com/a.html, and it contains an iframe whose src is http://b.com/b.html. To achieve communication between these two pages, below steps are needed.

Send data from a.html to b.html

  • Change iframe src to something like http://b.com/b.html#paco
  • b.html will listen to the onhashchange event and see that the url is changed and get the data

Send data from b.html to a.html

  • In b.html, create a hidden iframe whose src is from a.com and append the data to be sent to a.com. For example, http://a.com/proxy.html#data
  • proxy.html will listen to onhashchange event and get the data and update a.html URL hash(since proxy.html and a.html is in same domain)
  • a.html will listen to onhashchange event and get the data

The code in b.html looks like:

try {  
    parent.location.hash = 'data';  
} catch (e) {  
    var ifrproxy = document.createElement('iframe');  
    ifrproxy.style.display = 'none';  
    ifrproxy.src = "http://a.com/proxy.html#data";  
    document.body.appendChild(ifrproxy);  
}

The code in proxy.html looks like:

parent.parent.location.hash = self.location.hash.substring(1);

HTML 5 postMessage method

All mainstream browsers support this feature. This features includes the onmessage event to receive the message and the postMessage method to send the message. 

If a.html contains an iframe whose src is from b.com, the postMessage method can be used.

in a.html,

window.onload = function() {  
    var ifr = document.getElementById('ifr');  
    var targetOrigin = "http://b.com";  
    ifr.contentWindow.postMessage('hello world!', targetOrigin);  
};

In b.html from b.com

var onmessage = function (event) {  
  var data = event.data;//Message  
  var origin = event.origin;//Message origin  
  var source = event.source;   
  if(origin=="http://a.com"){  
console.log(data);//hello world!  
  }  
};  
if (typeof window.addEventListener != 'undefined') {  
  window.addEventListener('message', onmessage, false);  
} else if (typeof window.attachEvent != 'undefined') {  
  //for ie  
  window.attachEvent('onmessage', onmessage);  
}

jsonp

All above methods are bidirectional which means both sides can send and receive data. jsonp is unidirectional, it can only request data from other domain.

In a.html, create a script tag and set its src to the script from other domain.

<script type="text/javascript">
    function dosomething(jsondata){
        // Get json data
    }
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

There is a callback parameter after the script src, it will be the callback function after request completion.

In data.php, below code can be there.

$callback = $_GET['callback'];// Get parameter
$data = array('a','b','c');// Response data
echo $callback.'('.json_encode($data).')';// Output response

The final output will be dosomething([‘a’,’b’,’c’]); and it can be executed in a.html.

Pros and cons

Pros : It doesn't have same origin restriction and it has good compatibility even in old browsers

Cons : It only supports GET request but not POST request

CORS(Cross Origin Resource Sharing)

CORS defines how the browser interacts with the web server. It will have a specific HTTP header field which tells whether the server allows cross origin requests. The whole CORS interaction is done between browser and server, hence the user no needs to do anything. Only the server needs to have proper configuration to enable it.

To enable CORS, the server side needs to set Access-Control-Allow-Origin response header.

CORS has following advantages compared to jsonp:

  • It supports not only GET request but also other requests such as POST
  • It can use XMLHttpRequest to send and receive data and has better error handling mechanism

window.name

window object has name property which can be shared by all pages within the same window session. This can be used to share data between different domains. Note, window.name can only contain String value due to security consideration.

Other cross domain mechanisms such as middleware cross domain, proxy server, Flash URLLoader, dynamic script tag creation are not discussed here.

Reference : http://damonare.github.io/2016/10/30/%E5%89%8D%E7%AB%AF%E8%B7%A8%E5%9F%9F%E6%95%B4%E7%90%86/

FRONT END  JSONP  CROSS DOMAIN  CROSS ORIGIN  CORS  DOCUMENT.DOMAIN  WINDOW.NAME 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

After changing one line of code

After changing one line of code, everything doesn't feel good.