美文网首页
跨域问题

跨域问题

作者: 鬼泣_89b6 | 来源:发表于2019-06-29 16:50 被阅读0次

    什么是跨域

    跨域是指一个域下的文档(脚本)视图去访问另一个域下的资源,这里的跨域是广义的

    广义的跨域:
    资源转跳:a连接、重定向、表单提交
    资源嵌入:link标签 script标签 frame标签(html5不支持),还有样式中 background:url()、@font-face()等文件外链
    脚本请求:JS发起的ajax请求,dom和JS对象的跨域操作等
    狭义的跨域:
    所谓狭义的跨域是由浏览器同源策略限制的一类请求场景

    什么是同源策略

    同源策略/SOP(Same origin policy) 是一种约定,由Netscape公司1995年引入浏览器,他是浏览器最核心也是最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS CSRF等攻击.所谓同源指的是"协议 + 域名 + 端口" 三者相同,即便两个不同的域名指向同一个ip地址,也非同源

    url的组成

    关于xxs攻击/csrf攻击
    https://www.cnblogs.com/wzj4858/p/8259944.html
    https://baijiahao.baidu.com/s?id=1618267672561552800&wfr=spider&for=pc

    同源策略限制了以下几种行为
    1、cookie、LocalStorage(局部处理器,通过 JS 操作) 和 IndexDB(本地存储) 无法读取
    2、DOM(HTML节点树) 和 JS 对象无法获得
    3、AJAX 请求发送后,被浏览器拦截
    但是有三个标签是允许跨域加载资源:
    <img src='xxx'>
    <link href='xxx'>
    <script src='xxx'>

    常见跨域场景
    '当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。'
    
    URL                                      说明                    是否允许通信
    http://www.domain.com/a.js
    http://www.domain.com/b.js         同一域名,不同文件或路径           允许
    http://www.domain.com/lab/c.js
    
    http://www.domain.com:8000/a.js
    http://www.domain.com/b.js         同一域名,不同端口                不允许
     
    http://www.domain.com/a.js
    https://www.domain.com/b.js        同一域名,不同协议                不允许
     
    http://www.domain.com/a.js
    http://192.168.4.12/b.js           域名和域名对应相同ip              不允许
     
    http://www.domain.com/a.js
    http://x.domain.com/b.js           主域相同,子域不同                不允许
    http://domain.com/c.js
     
    http://www.domain1.com/a.js
    http://www.domain2.com/b.js        不同域名                         不允许
    

    由此可得 当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。都会被浏览器拦截

    特别说明两点:
    第一:如果是协议和端口造成的跨域问题“前台”是无能为力的。
    第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

    这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?

    跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

    常见解决跨域问题的方案

    1.通过jsonp跨域
    2.跨域资源共享(CORS)
    3.nginx反向代理

    一 通过jsonp跨域

    通常为了减轻web服务器的负载,我们把js css img 等静态资源分离到另一台独立域名的服务器上,在HTML页面中通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信

    jsonp缺点:
    有局限性,只能实现get一种请求;
    不安全,可能会遭受xss攻击

    jsonp和ajax对比:

    jsonp和ajax相同,都是客户端向服务端发送请求,从服务器获取数据的方式.但是ajax属于同源策略,jsonp属于非同源策略(跨域请求)

    1. 原生实现:
    下面有两个端口 8080 和 8088 因为端口的不同,导致非同源,所以,一旦进行访问,就会被拦截
    在前后端不分离的情况下:
    访问  path('index/',onBack)  index路由执行 onBack函数
    函数:
    def onBack(request):
        print('成功')
        return HttpResponse('少时诵诗书')
    前端:
    <script>
        // 创建 script 标签 并指定类型
        var script = document.createElement('script');
        script.type = 'text/html';
    
        // 指定路由 和 回调函数 callback=jsonCallback
        script.src = 'http://127.0.0.1:8088/hahaha?callback=jsonCallback';
        // 添加到 文件头中
        document.body.appendChild(script);
    
        // 回调函数
        function jsonCallback(res) {
            console.log(data);
        }
    </script>
    注意:前端转跳的是域名 'hahaha' 端口 8088 并且执行了回调函数 jsonCallback()
    

    前端页面成功的显示了 少时诵诗书 这个关键词
    单纯的拿到数据并不能让我们满意。一个合适的请求函数,必然包含对成功、失败、超时的处理,就像我们上面写的那个简单示例,一旦出现异常,就不能让我们满意了。
    在这一点上不得不说Jquery做的很好,Jquery的Jsonp函数包含了对各种情况的处理,还伪造了一个http状态码的返回。
    jsonp和ajax不同 是拿不到状态码的,但是jQuery对于所有的错误都赋予了一个404的状态码对比其他的组件库(axios-jsonp, axios-jsonp-pro, jsonp, fetch=jsonp-es6), 要不就是完全没有对超时的处理,要不然就是把错误和超时混成一谭,更有甚者,有些都不能自定义callback函数的名字。这简直太过分了。
    为什么我们不选择jQuery呢 : 因为太大了webpack引入jQuery后瞬间增大了80k,单独将jsonp打包出来也有70k,问我的源码只有20k,这是我无法接受的

    1. JQuery ajax
    有了原生JS的对比,jQuery更是简单
    // 引入 jQuery
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script>
        $.ajax({
            url: 'http://127.0.0.1:8080/hahaha',  //发送请求
            type: 'get',
            dataType:'jsonp', // 请求方式为 jsonp
            success: function (res) {  // 执行回调函数
                console.log(res)
            }
        });
    </script>
    
    1. vue.js
    1、安装 vue jsonp        # npm install jsonp
    2、在main.js中导入vue-jsonp        # 导入jsonp   import VueJsonp from 'vue-jsonp'  封装jsonp vue.use(VueJsonp)
    3、编写代码  格式:  this.$http.jsonp('url',[可选参数,使用{}传参]).then(成功回调函数,失败回调函数);
    

    还有一个关于创建公共方法jsonp.js : vue_music:JSONP

    二、 跨域资源共享(CORS)

    跨来源资源共享(CORS)是一份浏览器技术的规范,提供了Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是JSONP 模式的现代版。与JSONP 不同,CORS 除了GET 要求方法以外也支持其他的HTTP 要求。用CORS 可以让网页设计师用一般的XMLHttpRequest,这种方式的错误处理比JSONP 要来的好。另一方面,JSONP 可以在不支持CORS 的老旧浏览器上运作。现代的浏览器都支持CORS。所以只要后端实现CORS就实现了跨域

    虽然设置CORS和前端没有什么关系,但是通过这种方式解决问题的话会在发送请求时出现两种情况:简单请求 、复杂请求

    • 简单请求: 满足以下两大条件就属于简单请求

        请求方式GETPOSTHEAD 只请求页面首部
        请求头信息:Content-Type的值仅限于三者之一: text/plain 纯文本multipart/form-dataapplication/x-www-form-urlencoded
        注意:请求中的任意XMLHttpRequestUpload对象均没有注册任何时间监听器;XMLHttpRequestUpload对象可以使用XMLHttpRequest.upload属性访问

    • 复杂请求

    不属于简单请求的都是复杂请求
    复杂请求在正式通信前都会先发送预检 ,该请求是option方法,通过该请求来指导服务端是否允许跨域请求. option 利用中间件加响应头解决跨域问题

    from django.utils.deprecation import MiddlewareMixin
    
    
    class MyCore(MiddlewareMixin):  # 解决跨域问题
        def process_response(self, request, response):
            response["Access-Control-Allow-Origin"] = '*'  # 解决简单请求的跨域问题
            if request.method == 'OPTIONS':  # 复杂请求会发送option预检;解决复杂请求的跨域问题
                response["Access-Control-Allow-Headers"] = 'Content-Type'
                response["Access-Control-Allow-Methods"] = 'POST,DELETE,PUT'
            return response
    

    对于自己前后端分离的项目,跨域只存在于测试阶段(前后端交互用json数据,这就是复杂请求),放到服务器不存在跨域问题,因为有nginx

    一些常用的键值对
    // 设置哪个源可以访问我
    'Access-Control-Allow-Origin', origin
    // 允许携带哪个头访问我
    'Access-Control-Allow-Headers', 'name'
    // 允许哪个方法访问我
    'Access-Control-Allow-Methods', 'PUT'
    // 允许携带cookie
    'Access-Control-Allow-Credentials', true
    // 预检的存活时间
    'Access-Control-Max-Age', 6
    // 允许返回的头
    'Access-Control-Expose-Headers', 'name'
    

    三 nginx反向代理

    使用nginx反向代理实现跨域,是最简单的跨域方式。

    正向代理和反向代理.png
    图解:
    在正向代理中,Proxy和Client同属于一个LAN(图中方框内),隐藏了客户端信息;
    在反向代理中,Proxy和Server同属于一个LAN(图中方框内),隐藏了服务端信息;
    实际上,Proxy在两种代理中做的事情都是替服务器代为收发请求和响应,不过从结构上看正好左右互换了一下,所以把后出现的那种代理方式称为反向代理了。
    反向代理的作用:
    (1)保证内网的安全,通常将反向代理作为公网访问地址,Web服务器是内网
    (2)负载均衡,通过反向代理服务器来优化网站的负载

    相关文章

      网友评论

          本文标题:跨域问题

          本文链接:https://www.haomeiwen.com/subject/iiqhpqtx.html