跨域

跨域通信的方式

  • JSONP
  • CORS
  • Hash
  • postMessage
  • WebSoket

同源策略

  • 端口相同
  • 域名相同
  • 协议相同

例子:http://www.example.com/dir/page.html 这个网址,协议是http,域名是www.example.com,端口是80

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。是浏览器做的努力

同源策略限制范围

  • Cookie、LocalStorage 和 IndexDB 无法读取
  • DOM 无法获得
  • AJAX 请求不能发送

CROS跨域资源请求

CORS(Cross-origin resource sharing)跨域资源请求

浏览器在请求一个跨域资源的时候,如果是跨域的Ajax请求,他会在请求头中加一个origin字段,但他是不知道这个资源服务端是否允许跨域请求的。浏览器会发送到服务端,如果服务器返回的头中没有'Access-Control-Allow-Origin': '对应网址或 * ' 的话,那么浏览器就会把请求内容给忽略掉,并且在控制台报错

CORS限制

允许的请求方法

  • GET
  • POST
  • HEAD

允许的Content-Type

  • text/plain
  • multipart/form-data
  • application/x-www-form-ulencoded

其他类型的请求方法和Content-Type需要通过预请求验证后然后才能发送

CORS预请求

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求。

服务器在HTTP header中加入允许请求的方法和Content-Type后,其他指定的方法和Content-Type就可以成功请求了

1
2
3
'Access-Control-Allow-Headers': '允许Content-Type'
'Access-Control-Allow-Methods': '允许的请求方法'
'Access-Control-Max-Age': '预请求允许其他方法和类型传输的时间'

JSONP跨域

浏览器上虽然有同源限制,但是像 srcipt标签、link标签、img标签、iframe标签,这种在标签上通过src地址来加载一些内容的时候浏览器是允许进行跨域请求的

所以JSONP的原理就是:

  • 创建一个script标签,这个script标签的src就是请求的地址;
  • 这个script标签插入到DOM中,浏览器就根据src地址访问服务器资源
  • 返回的资源是一个文本,但是因为是在script标签中,浏览器会执行它
  • 而这个文本恰好是函数调用的形式,即函数名(数据),浏览器会把它当作JS代码来执行即调用这个函数
  • 只要提前约定好这个函数名,并且这个函数存在于window对象中,就可以把数据传递给处理函数。

Hash值跨域通信

背景:在页面A下提供iframe或frame嵌入了跨域的页面B

容器页面 -> 嵌入页通信:

在A页面中改变B的url中的hash值,B不会刷新,但是B可以用过window.onhashchange事件监听到hash变化

postMessage通信

1
2
3
4
5
6
7
8
// 窗口A中
window.postMessage('data', 'http://A.com');
// 窗口B中
window.addEventListener('message', function(event) {
console.log(event.origin); // http://A.com
console.log(event.source); // A 对象window引用
console.log(event.data); // 数据
})

WebSoket 跨域通信

1
2
3
4
5
6
7
8
9
10
11
12
13
var ws = new WebSocket('wss://echo.websoket.org') //这个是后端端口

ws.onopen = function(evt) {
ws.send('some message')
}

ws.onmessage = function (evt) {
console.log(evt.data);
}

ws.onclose = function(evt){
console.log('连接关闭');
}

document.domain

该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。

只需要给页面添加 document.domain = ‘test.com’ 表示二级域名都相同就可以实现跨域