.同源策略

1.什么是同源策略

同源策略阻止从一个domain源加载的文档或脚本获取或设置另一个源加载的文档的属性。这个策略可以追溯到 Netscape Navigator 2.0 这里的同源是指访问文档的 协议、端口(如果指明了的话)和主机名都相同。 在同源策略中有一个例外,脚本可以设置 document.domain 的值为当前域的一个后缀,比如域aaa.xxx.com的后缀可以是xxx.com。如果这样做的话,短的域将作为后续同源检测的依据。例如,假设在 http://aaa.xxx.com/dir/other.html 中的一个脚本执行了下列语句:

document.domain = "xxx.com"; 这条语句执行之后,页面将会成功地通过对 http://xxx.com/dir/page.html 的同源检测。

举个例子比如有http://aaa.xxx.com/a.html http://bbb.xxx.com/b.html两个网页,然后将b.html通过iframe的方式嵌在a.html中,那么默认情况下是无法在a.html中通过js脚本操作b.html中的元素的。

2.同源策略的困扰

浏览器安全模型规定,XMLHttpRequest、框架(frame)等只能在一个域中通信。从安全角度考虑,这个规定很合理;但是,也确实给分布式(面向服务、混搭等等本周提到的概念)Web开发带来了麻烦。比如企业内部的网站,有时候需要整合多个应用的页面,并做处理,这个时候便受到同源策略的影响. 特别是ajax非常流行的今天,需要异步和其他应用交互的场景也非常的多,但ajax是通过XMLHttpRequest这个js对象来进行操作的,所以必然受到同源策略的约束。

.常用解决方案

为了实现跨域通信,通常的解决方案有4种:

Flash
远程主机中需要部署一个crossdomain.xml文件,而且,Flash作为一门专有技术,其前途尚不明朗;换句话说,开发人员很可能要学习一种目标不确定的编程语言。

框架:

另一个办法就是使用框架(frames),将第三方站点的资源包含进来,但是包含进来的资源同样要受到同源策略的限制。

反向代理:

通过反向代理我们可以将对domain B的请求 ,转换成对domain A的请求,这样就可以保证以同源的方式来访问原本非同源的页面。

就是在服务器端发送请求,服务器充当一个到达第三方资源的代理中继。需要一些服务器的支持,并且带宽和潜伏时间也要加倍(远程服务器-代理服务器-客户端)。

Script标签:
无法确切知道内容是否有效,没有标准的实现方法,又可能被认为是一种“安全风险”。

浏览器是允许src使用非同源的文件的,

<script type="text/javascript"

src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">
<
/script>

这样我们就可以想出一个办法来变相的和非同源的文档交互,我们可以将scriptsrc属性设置为一个动态的请求的地址,并给他传递一个回掉函数,服务器端根据这个回掉函数的名字,构造出一个方法调用机算好方法调用的参数。 举例

<html>

<body>

<div id="result"></div>

</body>

<script type="text/javascript"

src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">

</script>

<script type="text/javascript">

function callback(data){

    $('#result').html(data);

}

</script>

<script type="text/javascript"

src="http://127.0.0.1/~Luke/test/test.js">

</script>

</html>

test.js的内容可以放在任何地方 callback('just test'); 当然test.js也可以是任何动态的内容

.src的扩展:JSONP

理解 JSONPJSON With Padding的意思。 jsonjs对象的表示方法,这里就不多说。 jsonp的方式从根本上其实就是上一节中所讲的script引用的方法,只是所引用的那个文件不是静态的js文件,而是一个动态的内容。其返回的内容是回掉函数的调用,重要的是函数调用的时候,使用了根据请求的参数获取的json对象对回掉函数的参数进行填充。这就是jsonp名字的来由。

假设我在80端口的apache下部署了一个静态的页面

<html><body>

<div id="result"></div>

</body>

<script type="text/javascript"

src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">

</script>

<script type="text/javascript">

function show(data){

    $('#result').html(data.name);

}

</script>

<script type="text/javascript"

src="http://127.0.0.1:8080/?name=Luke&callback=show">

</script></html>

然后8080端口部署了一个web.py的代码

import web

urls = ("/.*", "hello")

app = web.application(urls, globals())

class hello:

    def GET(self):

        p = web.input()

        return '%s({name:"%s"})'%(p.callback,p.name)

if __name__ == "__main__":

    app.run()

这样之后可以通过访问http://localhost/~Luke/test/test.html看到结果

jQuery中的jsonp支持 jquey现在也提供了jsonp的调用方式,

  $(document).ready(function(){

        $.ajax({

             url:'http://127.0.0.1:8080/?name=Luke&callback=?',

             dataType:"jsonp",

             jsonp:"jsonpcallback",

             success:function(data){

                    $('#result').html(data.name);

             }

        });

    });

注意这里并不是ajax调用。 或者

$.getJSON("http://127.0.0.1:8080/?name=Luke&callback=?",

function(data){

   $('#result').html(data.name);

   });

其实现原理就是在运行的时候,会将我们提供的匿名回掉函数动态生成一个有名字的callback函数,并创建一个src为上述地址的script元素,末尾的问号替换成动态生成的callback函数名,并在head中动态插入script的代码。 但是由于这种方式是GET方法,所以能够传递的参数的量是有限的。

注意:

JSONP是一个非常强大的构建mashp的方法,可是不是一个解决跨域访问问题的万能药。它也有一些缺点:

第一也是最重要的:JSONP不提供错误处理。如果动态插入的代码正常运行,你可以得到返回,但是如果失败了,那么什么都不会发生。你无法获得一个404的错误,也不能取消这个请求。

另外一个重要的缺点是如果使用了不信任的服务会造成很大的安全隐患。