JavaScript 复习之 同源限制

所谓“同源”指的是“三个相同”:协议相同、域名相同及端口相同。

非同源,共有三种行为受到限制。

  1. 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。

  2. 无法接触非同源网页的 DOM。

  3. 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。

window.postMessage()

这个 API 为window对象新增一个window.postMessage方法,允许跨窗口通信,不论这俩个窗口是否同源。

// 父窗口打开一个子窗口
var popup = window.open('http://bbb.com', 'title');
// 父窗口向子窗口发消息
popup.postMessage('Hello World!', 'http://bbb.com');
复制代码

方法接受两个参数,第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,即“协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。

子窗口向父窗口发送消息的写法类似。

// 子窗口向父窗口发消息
window.opener.postMessage('Nice to see you', 'http://aaa.com');
复制代码

父子窗口通过message事件,监听对方的消息。

// 父窗口和子窗口都可以用下面的代码,
// 监听 message 消息
window.addEventListener('message', function (e) {
  console.log(e.data);
},false);
复制代码

message事件的参数是事件对象event,提供三个属性

  1. event.source:发送消息的窗口
  2. event.origin:消息发向的网址
  3. event.data:消息内容

下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postMessage('Nice to see you!', '*');
}
复制代码

上面代码有几个地方需要注意。首先,receiveMessage函数里面没有过滤信息的来源,任意网址发来的信息都会被处理。其次,postMessage方法中指定的目标窗口的网址是一个星号,表示该信息可以向任意网址发送。通常来说,这两种做法是不推荐的,因为不够安全,可能会被恶意利用。

event.origin属性可以过滤不是发给本窗口的消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  if (event.origin !== 'http://aaa.com') return;
  if (event.data === 'Hello World') {
    event.source.postMessage('Hello', event.origin);
  } else {
    console.log(event.data);
  }
}
复制代码

AJAX

同源政策规定,AJAX 请求只能发给同源的网址,否则就报错。

除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。

  • JSONP

  • WebSocket

  • CORS

jsonp

是服务器和客户端跨源通信的常用方法,特点就是简单适用。

基本思想是,网页通过添加一个<scritp>元素,向服务器请求 JSON 数据,这种做法不受同源策略限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

首先,网页动态插入<scritp>元素,由他向跨源网址发出请求。

function addScriptTag(src){
    let script = document.createElement('script');
    script.setAttribute('type','text/javascript');
    script.src = src;
    document.body.appendChild(script);
}

window.onload = function(){
    addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data){
    console.log('Your public IP address is: ' + data.ip);
}
复制代码

上面代码通过动态添加<script>元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于 JSONP 是必需的。

服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

foo({
  "ip": "8.8.8.8"
});
复制代码
WebSocket

是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源策略,只要服务器支持,就可以通过它进行跨源通信。

下面是一个浏览器 发出的 WebStock 请求的头部信息

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
复制代码

上面代码,有一个origin,表示请求的请求源,即发自哪个域名。

正因为有了这个字段,所以 WebStock 才没有实行同源策略。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就可以做出如下回应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
复制代码
CORS

是跨源资源分享(Cross-Origin Resource Sharing)的缩写。属于跨源 AJAX 请求的根本解决方法。允许任何类型的请求。

CORS 需要浏览器和服务器同时支持,目前所有浏览器都支持该功能。

实现 CORS 通信的关键是服务器,只要服务器实现了 CORS 接口,就可以跨域通信。

转载于:https://juejin.im/post/5c7e9d7bf265da2ddf78adae

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值