跨域

886 阅读3分钟

跨域是指三者任意不同的资源之间由于受到浏览器的同源策略限制无法正常交互通信。
最常见的实际场景就是项目开发中请求第三方其他域下的资源。如果不处理跨域问题,浏览器会发出警告:

同源策略

同源策略限制了从同一个源的文件或脚本与来自另一个源的资源进行交互,这是用于隔离潜在恶意文件的重要安全机制。

跨域解决方案

  • JSONP
    浏览器同源策略允许<script>标签的跨域资源嵌套,<script>不受同源策略限制。
    比如:通常为了减轻web服务器的负载,我们把js、img、css等静态资源分离到另一台独立域名的服务器上,在html页面中再通过对应的标签<script>加载不同域下的资源。
    与后端交互:
<!--原生实现
    前端设置好回调函数,并把回调函数当做请求url的参数
    后端接受到请求后,返回回调函数名和需要的数据
    返回的数据传入到回调函数中并执行
-->
<script>
    function jsonpCallback(data){
        alert("获取到数据")
        console.log(data)
    }
</script>
<script src="http://127.0.0.1:3000?callback=jsonpCallback">
</script>
<script>
<!--也可以使用AJAX请求方式来跨域请求-->
    function jsonpCallback(data){
        alert("获取数据")
        console.log(data)
    }
    $.ajax({
        type:'GET',
        url:'http://127.0.0.1:3000',
        dataType:'jsonp',               //设置为jsonp类型
        jsonpCallback:jsonpCallback     //自定义回调函数
    })
</script>

优点:兼容性好、缺点:只支持GET方式的HTTP请求,不能解决不同域下的不同页面之间的通信

  • CORS
    服务端未设置CORS跨域字段,服务端会拒绝并发出错误警告
    服务端设置Access-Control-Allow-Origin字段,值是具体的域名或者通配符'*',就可以进行跨域请求

缺点:需要后端支持

  • Serve Proxy
    通过服务端代理请求方式解决跨域问题。同源策略只是针对浏览器的安全策略,对服务器没有这种限制。具体步骤如下:
  1. 前端正常请求服务端提供的接口url
  2. 通过服务端设置代理发送请求,然后把请求到的数据返回给前端
  • location.hash + iframe
    解决不同域的不同页面之间的通信问题:
  1. 不同域的a页面和b页面通信。在a页面通过iframe嵌入b页面,并给iframe的src拼接一个hash值
  2. b页面接受到a传的hash值,知道a页面在尝试与自己通信,然后通过改变parent.location.hash值,将要通信的数据传给a页面的hash值
  3. 但是在IE和Chrome下不允许子页面直接修改父页面的hash值,于是在b页面中通过iframe嵌入一个与a同域的代理页面c,通过c将数据传给a
  4. 在b的iframe的将数据通过src链接的hash传给c。由于c与a同域,c可以直接修改a的hash值或者调用a的全局函数

缺点:jash传递的数据容量有限、数据直接暴露在url中

  • document.domain + iframe
    限于主域相同子域不同的资源跨域问题解决。原理:两个页面通过强制设置document.domain为基础主域,就实现了同域。
//父窗口http://www.domain.com/a.html
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = "domain.com";
    var user = 'admin';
</script>

//子窗口http://child.domain.com/b.html
<script>
    document.domain = "domain.com";
    //获取父窗口中的变量
    alert("get parent user = " + window.parent.user)
</script>
  • window.name + iframe
    window.name的特性,name值在不同的页面(甚至不同域)加载之后依然存在,并且可以支持非常长的name值(2MB)
  • window.postMessage

未完待续。。。本着学习和总结的心态,若文中有什么问题或者其他想法请大家指出

参考

juejin.cn/post/684490… segmentfault.com/a/119000001…