1、同源策略
同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。这个策略可以追溯到 Netscape Navigator 2.0。
Mozilla 认为两个页面拥有相同的源,如果它们的协议、端口(如果指明了的话)和主机名都相同。下表给出了相对http://store.company.com/dir/page.html同源检测的结果:
URL 结果 原因 http://store.company.com/dir2/other.html | 成功 | |
http://store.company.com/dir/inner/another.html | 成功 | |
https://store.company.com/secure.html | 失败 | 协议不同 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同 |
http://news.company.com/dir/other.html | 失败 | 主机名不同 |
同源策略,简单地说就是要求动态内容(例如,JavaScript或者VBScript)只能阅读与之同源的那些HTTP应答和cookies,而不能阅读来自不同源的内容。更为有趣的是,同源策略对写操作没有任何限制。
2、JSONP
以上同源策略是基于安全考虑的,当前域不能访问其他域的东西。但这也带来一个问题,不同域之间如何协助。
先看一个简单的不同源请求的例子。准备2段代码,用来模拟2个不同源的服务器,分别部署在2个不同的web容器上。为了方便,我们直接使用jquery进行异步请求,不使用原生的 XMLHttpRequest.
localfile.html
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html>
- <head>
- <title></title>
- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
- <body>
- <script type="text/javascript">
- $(document).ready(function () {
- $.get('./sayhello.js', function(result) {});
- $.get('http://freeyun.duapp.com/jsonp/sayhello.js', function(result) {});
- });
- </script>
- </body>
- </html>
sayhello.js
- alert("hello jsonp");
这两个文件同时放到一个远程的服务器freeyun.duapp.com和本机的容器localhost的容器上。
在本机访问http://localhost:8080/jsonp/localfile.html,我们只能看到一个 hello jsonp的提示框。
通过F12打开chrome流程器的调试窗口,刷新,在network一栏可以看到如下信息:
对于远程服务器的请求出错了。
在console栏可以看到出错信息为:
XMLHttpRequest cannot load http://freeyun.duapp.com/jsonp/sayhello.js. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin.
这个也就是因不同源导致了一个跨域请求失败。
那怎么解决这个问题呢?你一定发现了刚刚我们localfile.html里对jquery的引用,script标签里src属性里的jquery路径和我们的本地服务器并不是同源的,也就是说script标签里的src属性里的路径不受同源策略的限制的。
我们修改一下localfile.html
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html>
- <head>
- <title></title>
- <script type="text/javascript" src="http://freeyun.duapp.com/jsonp/sayhello.js"></script>
- </head>
- <body>
- </body>
- </html>
重新访问localfile.html,这样依然会弹出 hello jsonp 的提示框,也就是说我们能过本地服务器访问到的远程服务器信息。
- 通过script标签的开放策略,抓到的资料并不是 JSON,而是任意的 JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
JSON只是一种数据描述格式,究竟是JSONP还是其他的“XXP”、“YYP”其实只是2个不同源的服务器之间的数据交换采用什么样的格式而已。
因为跨域的请求主要是为了能从别的服务器上获取数据,那么一般在数据获取完成后本地服务器都会做相应的数据处理,所以在JSONP这种模式里,会要求把返回结果放到本地一个回调函数中,这样就能直接通过本地回调方法对数据进行加工,这也就是我们常说的JSONP模式。