利用iframe跨子域获取json数据:方案及注意事项

数据消费者所在子域: 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), 则跨子域操作会失败。

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.