EmberYu / vic-blog

9 stars 0 forks source link

跨域的10086种方式 #2

Open EmberYu opened 5 years ago

EmberYu commented 5 years ago

浏览器中的跨域

身为一个前端开发,跨域算是最常见的一种问题了,在开发中如果遇到请求在console报下面这个错误,那么基本上就肯定是遇到跨域问题了。

image

什么是跨域?

在了解跨域之前,我们首先应该要知道什么是同源策略,假设没有同源策略是浏览器安全的基石,如果不满足同源策略,那么有三种行为将受到限制

必须满足以下三个条件,两个页面才可以被称之为同源

所以,不是同源之间的请求,我们称之为跨域请求

跨域的意义?

假设A网站是一家银行网页,那么用户在登录A网站进行消费之后,忘记关闭页面,此时打开了一个新的页面B页面,如果没有同源政策,那么B页面可以携带A的cookie登录信息去A网页的后端API发起转账请求,这是一种十分危险的操作。由此可见,同源政策可以更好的保护用户隐私,是有必要性的。

为什么要解决跨域?

我们先看一下以下几个域名

以上三个域名,我们可以发现都是属于QQ旗下的,互相之间也不是同源(一级域名相同,但是二级域名不同)。那么假设我们不能共享彼此的Cookie,那么我们是否需要维护三套登录系统API,三套Cookie呢?这对开发来说,相当于无形中增加了不必要的重复工作。所以,在确保安全的情况下,有时候我们需要某些方法来实现跨域

跨域的解决方案

Jsonp

jsonp是最常见的跨域解决方案之一了,主要是它具有良好的兼容性。我们知道,<script>标签是可以加载不同域的资源的(不然我们也无法直接引入某些框架的CDN文件使用)。而且<script>标签加载完成后其内的代码会自动执行。那么我们如果想要实现某个跨域请求,可以用下面几个步骤

  1. 在本地声明跨域的方法

    var jsonpFunc = function (params) {
       // dosomeThing...
    }
  2. 动态的创建<script>标签,请求至目标接口,返回对该方法的调用

    var jsonpScript = document.createElement('script');
    jsonpScript.type = 'text/javascript'
    
    // 这里一般与后端约定传入callback参数来告知后端函数名,由后端来返回对该函数名的调用
    // 返回值为 jsonpFunc(param);
    jsonpScript.src = 'http://someApi.com?callback=jsonpFunc'; 
    
    document.head.appendChild(script);

document.domain + iframe

两个页面通过js强制设置document.domain为同一主域,就实现了同域

这种方法只适用于一级域名相同,二级域名不同的页面

  1. 父窗口:www.domain.com/a.html

    <iframe id="frame" src="http://mail.domain.com/b.html"></iframe>
    <script>
    document.domain = 'domain.com'
    var user = 'admin';
    </script>
  2. 子窗口:mail.domain.com/b.html

    <script>
    document.domain = 'domain.com'
    
    alert(window.parent.user) // 'admin'
    </script>

location.hash + iframe跨域

利用hash值改变不刷新页面的特性,通过监听hashchange事件来实现跨域通信

A想要与B通信,可以通过中间页C来实现,三个页面利用iframe的location.hash传值。

原理就是A页面嵌套B页面,B页面中嵌套C页面,虽然hash是单向传递的,但是因为C跟A同源,所以A的变更传到B,B的变更传到C以后,C页面能通过parent.parent访问同源的A页面

window.name + iframe跨域

利用window.name在不同页面加载后依然存在,并且可以支持非常长的值(2MB)

利用同一页面跳转会保留window.name值,具体原理为

postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一

postMessage主要用来解决以下问题

postMessage接收两个参数

具体可以看MDN的postMessage

跨域资源共享(CORS)

​ 只服务端设置Access-Control-Allow-Origin即可,前端无须设置。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

WebSocket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。

websocket

鸣谢

浏览器同源政策及其规避方法 - 阮一峰老师

前端常见跨域解决方案