数据消费者所在子域: http://page.kentphp.net/
数据提供者所在子域: http://text.kentphp.net/
方案
提供端搞一个proxy,用作消费端的iframe
<!--提供端:http://text.kentphp.net/proxy.htm --> <!- Hey, I'm proxy-->
<!--消费端:http://page.kentphp.net/page.htm--> <iframe id="proxy" src="http://text.kentphp.net/proxy.htm"> </iframe> <script> document.domain="kentphp.net"; </script>
提供端proxy和消费端设置同样的document.domain
<!--提供端:http://text.kentphp.net/proxy.htm --> <script> document.domain ="kentphp.net"; </script>
<!--消费端:http://page.kentphp.net/page.htm--> <script> document.domain ="kentphp.net"; </script>
消费端通过proxy发起ajax请求,但使用自己的回调函数
<!--消费端:http://page.kentphp.net/page.htm--> <script> var iframe=document.getElementById('proxy'); var iJs=iframe.contentWindow.$; //iframe的JS根句柄;这里之所以能拿到这个句柄,是因为本页面和proxy页面都将domain显式设置成了同一个值 iJs.get("http://text.kentphp.net/dummyJson.htm",function(data){//这里的ajax get之所以能成功,是因为proxy的原生domain和dummyJson.htm的domain相同。 alert(data); }); </script>
这样就可以了。
说明,及注意事项
1. iframe页面能把’$’函数暴露给父页面,是因为两者的domain都是kentphp.net; iframe页面能顺利请求dummyJson.htm, 是因为两者的domain都是text.kentphp.net. 也就是说,
iframe有两个domain name, 一个是原生的text.kentphp.net, 另一个是被显式设置的kentphp.net; 奇怪的是,显式设置改变不了原生值。
2. 要想跨域,必须
在消费端和提供端都显式设置document.domain; 想在page.kentphp.net下访问kentphp/dummyJson.htm,是不是在page.kentphp.net中修改一下domain就可以? 在我测试过的浏览器中,都不行,正如上一条所暗示的,显式设置的domain跟原生的domain是彼此独立的,消费端改一下domain,然后“一厢情愿”地访问提供端的数据,是不会成功的。firefox给出的说明是:Mozilla distinguishes a document.domain property that has never been set from one explicitly set to the same domain as the document’s URL, even though the property returns the same value in both cases … Were it not for this special policy, every site would be subject to XSS from its subdomains (for example, https://bugzilla.mozilla.org could be attacked by bug attachments on https://bug*.bugzilla.mozilla.org)
3. 实验表明,
在大多数浏览器中,即使两个子域的端口不一样,仍然可以跨子域。也就是说iframe的暴露欲望很强,只要双方都显式设置了document.domain,iframe就愿意暴露自己的’$’函数,端口不同也没关系。
不过,这种做法未必被所有浏览器支持,最好慎用。
4. 如果两个子域的schme不一样(http V.S. https), 则跨子域操作会失败。