一.同源策略

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.同源策略的困扰

在如今各种各样的应用中,比如企业内部的网站,有时候需要整合多个应用的页面,并做处理,这个时候便受到同源策略的影响. 特别是ajax非常流行的今天,需要异步和其他应用交互的场景也非常的多,但ajax是通过XMLHttpRequest这个js对象来进行操作的,所以必然受到同源策略的约束。

二.常用解决方案

1.反向代理

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

2.script引用的方法

大家也许都知道下面的这种js脚本引用的方式,而浏览器是允许src使用非同源的文件的,

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

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

<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也可以是任何动态的内容

三.JSONP

理解JSONP JSONP是JSON With Padding的意思。 json是js对象的表示方法,这里就不多说。 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方法,所以能够传递的参数的量是有限的。