如何解决js跨域问题

所谓js跨域问题,是指在一个域下的页面中通过js访问另一个不同域下的数据对象,出于安全性考虑,几乎所有浏览器都不允许这种跨域访问。现假设一个站下有两个域名A.com、B.com,下面结合具体实例,介绍在什么情况下会产生跨域问题以及如何解决它。

1、Ajax跨域请求

在A.com域下有一个页面,http://A.com/test.jsp,页面代码为:

  1. <script src="jquery-1.8.2.min.js" type="text/javascript"></script>  
  2. <script type="text/javascript">  
  3. $(function() {  
  4.     var ajax_url = "http://B.com/info.jsp";  
  5.     // var ajax_url = "http://A.com/info.jsp";  
  6.     $.get(ajax_url, function(data) {  
  7.         alert(data);  
  8.     });  
  9. });  
  10. </script>  

如果以上页面通过ajax异步请求B.com下的info.jsp,就会产生跨域问题,而如果请求本域下的info.jsp,就会正常alert返回的信息。

 2、页面中嵌入iframe

在A.com域下有一个页面,http://A.com/test.jsp,页面代码为:

  1. <body>  
  2. <div id="div_info"></div>  
  3. <iframe src="http://B.com/child.jsp"></iframe>  
  4. </body>  

我们看到child.jsp页面是在域B.com下的,

  1. <script src="jquery-1.8.2.min.js" type="text/javascript"></script>  
  2. <script type="text/javascript">  
  3. $(function() {  
  4.     $(window.parent.document).find("#div_info").html("Hello");  
  5. });  
  6. </script>  

如上,在child.jsp中控制A.com域下test.jsp的页面元素div_info,即产生跨域问题,页面test.jsp中将不会显示字符串"Hello",但如果child.jsp也是在域A.com下,在test.jsp页面上就能看到"Hello"。

请注意,有一种情况经常会让大家误以为存在跨域问题,实则不然,如下:

在A.com域下有一个页面,http://A.com/test.jsp,页面代码为:

  1. <div id="div_info"></div>  
  2. <script src="http://B.com/outer.js" type="text/javascript"></script>  

如上,outer.js在B.com域下,代码为:

  1. // outer.js  
  2. $(function() {  
  3.     $("#div_info").html("Hello");  
  4. });  

在这种情况下,并不会产生跨域问题,虽然test.jsp页面在域A.com下,其引用的outer.js是在域B.com下,页面test.jsp中的div仍然会显示"Hello"。(script的src不存在跨域问题)

如何解决跨域问题,共有三种解决方案。

1、在跨域的服务端使用Proxy

在A.com域下的页面http://A.com/test.jsp

  1. <script type="text/javascript" src="jquery-1.8.2.min.js" ></script>  
  2. <script type="text/javascript" src="http://B.com/proxy.jsp"></script>  

如上,test.jsp页面要获取B.com域下的信息,不能再使用Ajax方式异步获取,而是在<script>标签内加入一个服务端的代理,直接返回javascript语句,http://B.com/proxy.jsp的代码如下:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%  
  3.     out.print("alert('Hello');");  
  4. %>  

2、使用Jsonp

在A.com域下的页面http://A.com/test.jsp

  1. <script src="jquery-1.8.2.min.js" type="text/javascript"></script>  
  2. <script type="text/javascript">  
  3. $(function() {  
  4.     $.getJSON("http://B.com/jsonp.jsp?callback=?", function(data){  
  5.         alert(data);  
  6.     });  
  7. });  
  8. </script>  

如上,test.jsp页面要获取B.com域下的信息,可以通过Jsonp方式获取http://B.com/jsonp.jsp中的内容,jsonp.jsp的代码如下:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%  
  3.     String callback = request.getParameter("callback");  
  4.     out.print(callback + "(\"Hello\")");  
  5. %>  

 3、使用iframe解决js跨域问题

baidu salon分享会上黄方荣主讲的《WEB数据交互的艺术》中提到一个非常优雅绝妙的解决方案!话不多说,直接上解决方案原理图:

该图要解决的问题说明如下
在AAA.com域名下的index.htm页面中内嵌了BBB.com域 名下的一个页面index.htm,正常情况下iframe内部的index.htm页面是无法访问父页面index.htm中的任何dom对象或者js 函数的,因为跨域,但我们经常又需要做一些参数回传的事情怎么办呢?以上的这种实现方式就很好的解决了这个问题;

解决方案的关键优雅之处在于浏览器虽然会禁止js跨域访问页面中的对象,但对于iframe的层级关系引用并没有做限制,即parent仍然可用;该方案就是利用了2层内嵌 iframe、使用第二级iframe中的页面与parent.parent的页面是同域名的关系,从而避免跨域问题实现两个页面间相关数据的传递,本质上就是利用parent.parent实现对父父页面中js的回调!

举个实际的案例:
功能描述:
A域名下的页面index.htm中内嵌了一个iframe页 面,iframe内引用的是B域名的sub-index.htm页面,但是为了避免出现在index.htm页面中出现滚动条,我们需要明确知道sub- index.htm页面的高度和宽度,可是sub-index.htm的页面内容是不可控的,可能会根据不同用户页面大小会不一样;问题就是如何把 sub-index.htm页面的高度和宽度传递给index.htm页面?

具体操作流程
1、在index.htm页面中声明一个js函数process(height, width);用来实现设置页面内iframe的高度和宽度;
2、 在sub-index.htm页面中再内嵌一个隐藏的iframe,iframe的src指向A域名下的页面ex.htm?height=xx& width=yy,该页面没有任何内容,只是用来传递sub-index.htm页面加载完之后的宽度和高度这两个数据的,页面内js拿到request 中的参数之后直接调用parent.parent.process(height, width);完成对父页面宽度和高度的设置。

posted on 2013-04-02 15:15  摩帆士  阅读(1647)  评论(0编辑  收藏  举报