浅析跨域

一、什么是跨域

跨域是指从一个域名的网页去请求另一个域名的资源。
只要协议、域名、端口有任何一个不同,就是不同的域。

浏览器的同源策略

同源是指:协议、域名和端口都相同
浏览器在执行脚本前,会先检查脚本是否同源,只有同源脚本才会被执行。
同源策略是浏览器最核心也是最基本的安全功能。用于防御跨站脚本攻击。
浏览器对script、img等没有跨域限制。

二、跨域的几种方法

1. 跨域资源共享CORS

CORS是一个W3C标准。
基本思想是使用自定义的HTTP头部,让服务器能声明哪些来源可以通过浏览器访问该服务器上的资源。
服务端响应头设置:

1
2
3
4
5
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials

客户端只需要正常发送请求。注意跨域请求默认不携带cookie信息,需要设置

1
xhr.withCredentials = true;

关于CORS的详细说明:阮一峰:跨域资源共享CORS详解

2. jsonp跨域

jsonp依赖的根据是浏览器的同源策略对script没有限制。
先来看一个例子:
A客户端要请求B服务器的data:
A客户端:

1
2
3
4
5
6
<script type="text/javascript">
function handleResponse(data){
// 处理data
}
</script>
<script src="http://domainB.com/data.php?callback=handleResponse"></script>

B服务端(data.php):

1
2
3
4
5
<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

B服务端data.php输出结果为:

1
handleResponse(['a','b','c'])

A客户端加载

1
<script src="http://domainB.com/data.php?callback=handleResponse"></script>

完成后,会执行之前定义的handleResponse(data)方法,并且把数据([‘a’,’b’,’c’])传入。
这样就达到了我们想要获取B服务端数据的目的。

  • 优点:兼容性好
  • 缺点:只支持get请求。

    3. 代理

    同源策略是浏览器的,服务器没有该限制。所以可以通过服务器来解决跨域问题。
    A Client ===> A Server ===> B Server ===> A Client

    4.document.domain+iframe

    浏览器的同源策略限制了浏览器中不同域的框架之间是不能进行js交互操作的。
    父窗口(http://www.example.com/a.html):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <script type="text/javascript">
    function test(){
    var iframe = document.getElementById('ifame');
    var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
    var doc = win.document;//这里获取不到iframe里的document对象
    var name = win.frameName;//这里同样获取不到子页面中的属性
    }
    </script>
    <iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>

子窗口(http://example.com/b.html):

1
2
3
<script type="text/javascript">
var frameName = "child";
</script>

跨域方法:两个页面都通过js设置example.com为主域,就实现了同域

1
document.domain = 'example.com';

5.window.postMessage

这是html5的新特性,window.postMessage() 方法被调用时,会在页面的所有脚本执行完毕之后( 在该方法之后设置的事件、之前设置的timeout 事件,等等)向目标窗口派发一个 MessageEvent 消息。
MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
详细介绍MDN
注意:
为了安全:

  • 用于接收消息的任何事件监听器必须首先使用origin和source属性来检查消息的发送者的身份
  • 当使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*
  • 如果不希望从其他网站接收message,就不要为message事件添加任何事件侦听器

    6.websocket

    也是html5的新特性。没有同源限制,客户端可以与任意服务器通信。
    阮一峰:websocket教程

参考:
https://segmentfault.com/a/1190000000718840
http://blog.csdn.net/ligang2585116/article/details/73072868?locationNum=13&fps=1