跨域和同源

同源

概念

两个浏览器的域名、协议、端口相同,即说这两个浏览器是同源的。

限制

1、Cookie、LocalStorage 和 IndexDB 无法读取;
2、DOM 和 Js 对象无法获得,禁止对不同源页面 DOM 进行操作;
3、禁止使用 Ajax 对象向不同源的服务器地址发起 HTTP 请求


跨域

概念

跨域指浏览器不能执行其他网站的脚本,可以通过各种方式避开其安全限制。

跨域方案

1、JSONP

Jsonp 是 json 的一种"使用模式",可以让网页从别的网站获取资料,即跨域读取数据。

实现

通过动态创建 script,再请求一个带参网址实现跨域通信。
1、声明一个回调函数(show),其函数名当作参数值,传递给跨域请求数据的服务器,函数形参为要获取的目标数据。
2、创建一个 script 标签,把跨域的API数据接口地址,赋值给 src,还要在这个地址中向服务器传递第一步创建好的回调函数函数名(可以通过问号传参?callback=show),服务器接收到请求后,需要进行特殊的处理,把传递进来的函数名和数据拼接成一个字符串,例如传递进来的函数名是 show,它准备好的数据是 show(‘内容’)。
3、最后服务器把准备的数据通过 HTTP 协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。

document.querySelector('.show').addEventListener('click',function(){
  var script = document.createElement('script');
  script.src = 'url?callback=show';
  document.head.appendChild(script);
  document.head.removeChild(script);
})
缺点

(1)JSONP 只支持 get,因为 script 标签只能使用 get 请求。
(2)JSONP 需要后端配合返回指定格式的数据。
(3)可能会遭受XSS攻击,不安全。

2、CORS

服务端设置Access-Control-Allow-Origin就可以开启CORS,客户端发起Ajax请求,看服务端Access-Control-Allow-Origin中是否包含域名,包含则进行跨域通信。

实现
document.querySelector('.show').addEventListener('click',function(){
  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'url', true);
  xhr.onload = function(){
  	if(xhr.readyState === 4){
  	  if((xhr.status>=200 && xhr.status<=300)|| xhr.status==304) { 
        show(JSON.parse(xhr.responseText)); 
      }
    } else { 
      console.log('error'); 
    }
  } 
  xhr.send();
})
简单请求

简单请求要同时满足以下两个条件:
(1)使用 GET / HEAD / POST 方法之一。
(2)Content-Type 的值为 text/plain、multipart/form-data、application/x-www-from-urlencoded 之一。

简单请求时,浏览器会在头信息中,增加一个 origin 字段,此字段用来说明本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求。如果不在许可的范围,服务器会返回一个正常的HTTP回应。如果这个回应的头信息中没有包含 Access-Control-Allow-Origin 字段,就抛出错误。这种错误无法通过状态码识别。

复杂请求

不符合简单请求规则的便是复杂请求,复杂请求的CORS设置,会在正式通信之前,增加一次HTTP查询请求,称为预检请求,该请求是 option 方法,通过该请求知道服务端是否允许跨域请求。
预检请求中,浏览器先询问服务器,当前网页的域名是否在服务器的许可名单中,以及可以使用哪些HTTP动词和头信息字段,只有得到肯定答复,浏览器才会发出正式的XML请求,否则就会报错。

3、document.domain + iframe跨域

仅限主域相同,子域不同的跨域应用场景。
原理: 两个页面都通过 js 强制设置 document.domain 为基础主域,就实现了同域。

4、location.hash + iframe跨域

a 与 b 跨域相互通信,通过中间页 c 来实现。 三个页面,不同域之间利用 iframe 的 location.hash 传值,相同域之间直接 js 访问来通信。

5、window.name + iframe跨域

通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。

6、postMessage跨域

可以跨域操作的window属性之一,用于解决以下问题:
(1)页面和其打开的新窗口的数据传递
(2)多窗口之间消息传递
(3)页面与嵌套的iframe消息传递
(4)以上三个场景的跨域数据传递

windowName.postMessage('内容', 'url') 

postMessage() 方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

7、代理

启一个代理服务器,实现数据的转发。
原理: 同源策略是浏览器需要遵循的标准,而服务器之间请求无需遵循同源策略。

步骤

(1)接受客户端请求 。
(2)将请求转发给服务器。
(3)拿到服务器响应数据。
(4)将响应转发给客户端。
代理

8、nginx反向代理

最简单的跨域方式,只需修改 nginx 的配置即可解决跨域问题,支持所有浏览器、session,不需要修改任何代码,也不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器,域名与 domain1 相同但端口不同,反向代理访问domain2接口,可以修改 cookie 中 domain 信息,方便当前域 cookie 的写入,实现跨域。

参考文章:https://www.jianshu.com/p/3edac882a923https://www.jianshu.com/p/8b3839de3105https://www.jianshu.com/p/2896288494df

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值