`

跨域访问

 
阅读更多

首先要弄清楚域是含义。这里引用百度知道里的域的一个概念说明:

域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust Relation)。信任关系是连接在域与域之间的桥梁。当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可以跨网分配文件和打印机等设备资源,使不同的域之间实现网络资源的共享与管理。

有一种简明的说法来解释广域跨域:跨域访问,简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容。由于安全原因,跨域访问是被各大浏览器所默认禁止的。

在广域网环境中,由于浏览器的安全限制,网络连接的跨域访问时不被允许的,XmlHttpRequest也不例外。但有时候跨域访问资源是必需的。

同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。同源策略不阻止将动态脚本元素插入文档中。

参考理论一:在浏览器中不能直接来跨域访问,而在服务器端没有跨域安全限制。

这样的话,可以在服务端完成跨域访问,而在客户端来取得结果就可以了。

参考理论二:同源策略不阻止动态脚本元素插入,脚本访问可以跨域。

以下直接引用:

具体情况有:

一、本域和子域的相互访问: www.aa.com和book.aa.com

二、本域和其他域的相互访问: www.aa.com和www.bb.com 用 iframe

三、本域和其他域的相互访问: www.aa.com和www.bb.com 用 XMLHttpRequest访问代理

四、本域和其他域的相互访问: www.aa.com和www.bb.com 用 JS创建动态脚本

解决方法:

一、如果想做到数据的交互,那么www.aa.com和book.aa.com必须由你来开发才可以。可以将book.aa.com用iframe添加到 www.aa.com的某个页面下,在www.aa.com和iframe里面都加上document.domain = "aa.com",这样就可以统一域了,可以实现跨域访问。就和平时同一个域中镶嵌iframe一样,直接调用里面的JS就可以了。(这个办法我没有尝试,不过理论可行)

二、当两个域不同时,如果想相互调用,那么同样需要两个域都是由你来开发才可以。用iframe可以实现数据的互相调用。解决方案就是用window.location对象的hash属性。hash属性就是http://domian/web/a.htm#dshakjdhsjka 里面的#dshakjdhsjka。利用JS改变hash值网页不会刷新,可以这样实现通过JS访问hash值来做到通信。不过除了IE之外其他大部分浏览器只要改变hash就会记录历史,你在前进和后退时就需要处理,非常麻烦。不过再做简单的处理时还是可以用的。大体的过程是页面a和页面b在不同域下,b通过iframe添加到a里,a通过JS修改iframe的hash值,b里面做一个监听(因为JS只能修改hash,数据是否改变只能由b自己来判断),检测到b的hash值被修改了,得到修改的值,经过处理返回a需要的值,再来修改a的hash值(这个地方要注意,如果a 本身是那种查询页面的话比如http://domian/web/a.aspx?id=3,在b中直接parent.window.location是无法取得数据的,同样报没有权限的错误,需要a把这个传过来,所以也比较麻烦),同样a里面也要做监听,如果hash变化的话就取得返回的数据,再做相应的处理。

三、这种情形是最经常遇到的,也是用的最多的了。就是www.aa.com和www.bb.com你只能修改一个,也就是另外一个是别人的,人家告诉你你要取得数据就访问某某连接参数是什么样子的,最后返回数据是什么格式的。而你需要做的就是在你的域下新建一个网页,让服务器去别人的网站上取得数据,再返回给你。domain1下的a向同域下的GetData.aspx请求数据,GetData.aspx向domain2下的 ResponseData.aspx发送请求,ResponseData.aspx返回数据给GetData.aspx, GetData.aspx再返回给a,这样就完成了一次数据请求。GetData.aspx在其中充当了代理的作用。

四、这个和上个的区别就是请求是使用<script>标签来请求的,这个要求也是两个域都是由你来开发才行。原理就是JS文件注入,在本域内的a 内生成一个JS标签,它的SRC指向请求的另外一个域的某个页面b,b返回数据即可,可以直接返回JS的代码。因为script的src属性是可以跨域的。

总结:

第一种情况:域和子域的问题,可以完全解决交互。

第二种情况:跨域,实现过程非常麻烦,需要两个域开发者都能控制,适用于简单交互。

第三种情况:跨域,开发者只控制一个域即可,实现过程需要增加代理取得数据,是常用的方式。

第四种情况:跨域,两个域开发者都需要控制,返回一段js代码。

参考:

http://blog.csdn.net/axzywan/archive/2009/01/19/3837311.aspx

http://www.liehuo.net/a/200912/0111192.html

http://www.ibm.com/developerworks/cn/web/wa-aj-jsonp1/index.html#intro

博客园大道至简

http://www.cnblogs.com/jams742003/

———————————————————————————–

->Javascript跨域访问解决方案

(1).http://www.doc88.com/p-5430102852.html

(2).由于安全方面的考虑, Javascript 被限制了跨域访问的能力,但是有时候我们希望能够做一些合理的跨域访问的事情,那么怎么办呢?

这里分两类情况:

         一、基于同一父域的子域之间页面的访问
                 参见如下 3 个 domain 域:

1 、 taobao.com
2 、 jipiao.taobao.com
3 、 promotion.taobao.com

它们有相同的父域   taobao.com

         二、基于不同父域页面之间的访问
                 参见如下 3 个 domain 域:

1 、 taobao.com
2 、 baidu.com

3 、 sina.com.cn

     它们具有不同的父域。

解决它们之间跨域的方案:

<!–[if !supportLists]–>① <!–[endif]–>服务器 Proxy:   域 A 的页面 JS 需要访问域 B 下的链接获取数据,该方案在域 A 的服务器端建立一个 Proxy 程序 ( 可能是 ASP 、 servlet 等任何服务端程序 ) ,域 A 的页面 JS 直接调用本域下的 Proxy 程序, proxy 程序负责将请求发送给域 B 下的链接并获取到数据,最后再通过 Proxy 将数据返回给页面 JS 使用。

经过的访问流程就是: 域 A 下 JS– à 域 A 下 Proxy— à 域 B 下的链接

例子:

第一步:

  域 A:  http://Jipiao.taobao.com/test.htm     页面上 javascript 脚本

 

<mce:script type=”text/javascript”><!–  
    Var sUrl=” http://Jipiao.taobao.com/proxy.do ”; // 本域下代理地址   
var callback =  
{  
   success: function(res) {   alert(res.responseText);   },   
   failure: function(res) {  alert(‘failure’);},   
   argument:{}   
}   
  YAHOO.util.Connect.asyncRequest(’GET’, sUrl, callback, null);     
// –></mce:script> 

 

第二步:

Proxy 程序 ( 这里假定是一个 servlet) :

 

Public class Proxy extends …….{   
..doGet(……..){   
HttpClient  client=……;   
GetMethod get= new   GetMethod(" www.baidu.com/xxxxx.do ") ;// 访问域 B 的链接   
int statusCode = client.executeMethod( get );   
if (statusCode != HttpStatus.SC_OK) {   
byte[] responseBody = get.getResponseBody();  
String res=new String(responseBody);  
Httpresponse.getWriter().write(res);//  
将数据返回给域  
A  
    }   
}   
}  

 

<!–[if !supportLists]–>② <!–[endif]–>  Script 标签 : 域 A 页面 http://Jipiao.taobao.com/test.htm 的 head 中写一个空的 Script 标签

 

<html>   
  <head>   
  <mce:script id=”remoteScript” type=”text/javascript” src="””" mce_src="””" /><!–  
  <head>   
  <body>   
<script type=”text/javascript” >   
  Var remoteScript=document.getElementById(‘remoteScript’);   
  remoteScript.src=” www.baidu.com/xxxxx.do”;// 域 B 的链接   
  alert(remote.test);// 使用域 B 返回的 JSON 数据   
  alert(f[0]);   
// –></mce:script>   
  </body>   
</html>  

 

注意:这种方案要求域 B 返回的数据必须是合法的 JSON 格式或者如 JS 文件的格式。

域 B 返回的数据格式如下:

  1. Var remote={test:’hello’};   
  2. Var f=[‘2,1];   
  3. {“test”:"hello","arrays":[2,1]} 

对于基于同一父域的子域之间页面的访问这一类情况,还有第三种方式:
    ③ 隐藏 iframe: 即域 A jipiao.taobao.com/yyyy.htm 的页面上写一个隐藏的 iframe ,

 

<html>   
  <head>   
<head>   
  <body>   
<mce:script type=”text/javascript” ><!–  
  Document.domain=”taobao.com”;   
  Var remoteHtml=document.getElementById(“remoteHtml”);   
remoteHtml.src=”promotion.taobao.com/xxxx.htm”;// 这里访问域 B 的链接   
var document=remoteHtml.ContentDocument;   
  …// 这里就可以使用 document 来操作域 B 中页面 xxx.htm 的数据了   
// –></mce:script>   
<iframe id=”remoteHtml” src="””" mce_src="””"   style="”diapay:none”/" mce_style="”diapay:none”/">   
  </body>   
</html>

 

这里 promotion.taobao.com/xxxx.htm 页面也需要设置 document.domain="taobao.com" , 这种方法才能奏效。之所以这种 iframe 的方法不适合不同父域之间的跨域,是因为设置 document.domain 只能设置为自己的父域,而不是能设置为其他域,例如 :jiapiao.taobao.com 只能设置 document.domain=”taobao.com” ,而不是是 document.domain=”baidu.com”

优缺点比较:

  这里列举的三种方案各有优缺点:

  Proxy 方案优点是可以适用用于几乎所有的跨域访问,而且只需要要一个域中进行开发,另一个域可以提供任何类型格式的数据。缺点是这种方案经过了中间 Proxy ,所以延迟可能稍微大一点,并且会加重本域服务器的负荷,开发工作量也稍微大一点。

  Script 标签的方案可以说是非常简单的,不用几行代码就搞定了事,不过它对返回的数据格式要求有点严格,只能是 Json 格式数据 , 如果是其他格式的数据,那么这种方法就无能为力了。

隐藏 iframe 方式也很简单,它可以处理任何返回的数据格式,但它只适用在具有同一个父域下的跨域请求上,并且要求其他域得配合开发,即需要设置 document.domain

推荐阅读文章:http://www.cnblogs.com/passer/archive/2008/07/16/1243811.html

================

补充:Script标签标签方法最好要求服务端返回的json需要有句柄,即 如 json={…} 什么的。因为客户端需要使用这个句柄来引用。如果没有,客户端JS只有采用 var json=eval(jsonStr)方式来执行,效率不是很高。还有一种形式就是客户端传入要回调的方法。例如 xxxx.do?callbackApi=ca

服务端接收到callbackApi参数后,将json包装在ca中,如:ca({…..});

客户端定义回调函数就可以访问了。

   function ca(json){

         …….

   }

不论如何,这种方法对于服务端都有一定耦合。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lovingprince/archive/2008/09/20/2954675.aspx

 

———————————————————————————–

->SilverLight 跨域访问解决方案

SilverLight 出于对安全性的考虑默认情况下对URL的访问进行了严格的限制,只允许访问同一子域下的URL资源。

下表列出了Silverlight 2.0 中 URL 访问规则:

image

如果WCF与SilverLight Web不是在同一站点,那么我们就要在被访问端的根域放上两个XML文件clientaccesspolicy.xml,crossdomain.xml
如果要通过WebClinet访问另一站点的资源,那么需要在被访问站点放上域访问策略xml文件,不然在Complete事件里面的事件参数报告空对象引用。

clientaccesspolicy.xml文件格式如何,切忌最好要将编码设置为utf-8,否则极易出错

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="*"/>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

crossdomain.xml文件格式

crossdomain.xml的格式非常简单,其根节点为<cross-domain-policy> ,其下包含一个或多个<allow-access-from>节点,<allow-access-from>有一个属性 domain,其值为允许访问的域,可以是确切的 IP 地址、一个确切的域或一个通配符域(任何域)。下边是两个例子:

程序代码
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="http://www.lishewen.com.cn/ " />
<allow-access-from domain="*.lishewen.com.cn" />
<allow-access-from domain="222.217.221.16" />
</cross-domain-policy>

程序代码
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

第二个例子允许任何域的访问。对于crossdomain.xml文件存放位置,建议将其存放于站点根目录中!

如:http://bbs.lishewen.com.cn/crossdomain.xml

关于clientaccesspolicy.xml,crossdomain.xml的具体说明,请大家参看MSDN http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx

自:http://gstarwd.javaeye.com/blog/564146

------------------------

AJAX不能跨域访问是什么意思,我想没有亲自遇到这个问题的人,可能根本就不理解.现在我给出一个例子,让大家体会一下什么是跨域访问.这个页面就是一个HTML文件,源码我附文章后面了.

注: 这个页面并不高深,例子只有一个HTML页面,没有引用什么特别的库之类的.例子的目的只是让对AJAX不能跨域访问有一个感性的认识.就好比,你如何告诉一个没见过汽车的人,告诉他什么是汽车,讲半天,还不如直接给个汽车给他看看,他就知道什么是汽车了.但你要他直接给一个清晰的定义,或者是让他明白汽车的动力学,这就是很难的了,也不是本文的目的.


下面这个简单的代码只要复制到一个本地html文件中即可,就可以把任何URL指定的网页显示出来[注1],但是同样的页面,你如果放到tomcat之类的容器下面,就无法打开,甚至通过网络邻居访问都不行.



分析1:为什么好好的页面却得不到期望的结果:
为什么JS语法没有什么问题,放在网络邻居与web容器中就不能正常运行了呢,这就是AJAX所说的不能跨域访问,因为浏览器你这个JS程序是来自容器,它就限制你只能正常访问同一容器里的的资源[注:2],比如你通过http://www.okajax.com访问到一个页面,那么这个页面的JS就只能访问okajax.com的资源,而不能访问www.baidu.com.


为什么IE在通过本地文件能正常运行这个页面的,我是在XP下测试的,可能IE把本地这个域处理成了一个特殊的域,从这个域得到的JS程序,权限可以略微放松些,这样可能易用性就会好些,要知道安全性与使用的方便性可是此消彼长的关系.所以IE选择了易用性,在安全问题上放了一个黄灯,为什么说是黄灯呢,因为它在运行这个页面时,IE会给出一个安全提示,告诉你这个页面存在风险.

分析2:为什么要限制AJAX跨域访问[注3]:
可以肯定的说是出于安全的需要,但我没有找到什么资料明确这个问题分析,我只能通过看其它资料来自己体会了,我自己发现的一个安全问题就是:
AJAX 可能会把用户的cookie信息泄漏出去,比如我往别用户的Gmail信箱里面发嵌有JS脚本的邮件.这些脚本读取gmail.com域中的 cookies信息,然后通过AJAX发送给我的个人网站,这样我的个人网站就可以得到这个用户的Gmail的cookies.我然后把它提取出来,我就可以不用密码来访问这个用户的Gmail邮箱了.
这个只是我能想到的,我想如果能够让AJAX能够跨域访问的话,肯定还有其它一些安全问题.


[1];对这个测试页面好像只有在一种情况下才能正常执行:就是通过IE打开本地文件。如果用FireFox就算是通过本地文件打开它也不能正常运行。
[2]: 为了把问题简单说明,我说了只能访问同一容器里面的资源,实际上是不精确的,真正的还是应该通过域来区分,同一个容器里面的资源也可能是指向不同的域.同一个域的各个资源也可能分布在不同的容器中.比如:tomcat中有好2个虚拟目录,你用不同的域名来指向这两个虚拟目录,这个容器中的两个虚拟目录就是不同的域了.不同容器的资源也可能属于同一个域,比如我申请一个域名:okajax.com,我设置 www.okajax.com指向www.baidu.com,而bbs.okajax.com指向www.google.com。这样baidu与google的首页就都属于okajax.com这个域了.
[3]: 本文没有区分AJAX的跨域与JS的跨域,因为AJAX就是通过JS来发现请求的,它们实际上是一回事。
[4]: 在代码中,我定义了变量 var url = 'http://bbs.okajax.com/thread-10982-1-1.html';    你可以把它修改为任何你能访问的地址,
[5]:本文的内容全是自己的瞎体会的,如果有什么不对的有高手发现了,希望大家能指出。这也是本文的主要目的。
重要的一个演示地址:
http://163sd.com/demo/6ky/ky1.html
在页面里我请求的是ajax论坛的一个帖子,在ie下看是没有权限
ff下是uncaught exception: (¹Õ XMLHttpRequest.open öCP ³
的错误
这个就代表跨域了
但是代码存到本地
用ie看就ok了。。。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics