zoukankan      html  css  js  c++  java
  • CORS 跨域资源共享

    CORS 定义

    CORS Cross-Origin Resource Sharing(CORS)跨来源资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。CORS是W3c工作草案,它定义了在跨域访问资源时浏览器和服务器之间如何通信。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。W3C CORS 工作草案
    同源策略:是浏览器最核心也最基本的安全功能;同源指的是:同协议,同域名和同端口。精髓:认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源;参考:JavaScript 的同源策略
    JSON & JSONP:JSON 是一种基于文本的数据交换方式,或者叫做数据描述格式。JSONP是资料格式JSON的一种“使用模式”,可以让网页从别的网域要资料,由于同源策略,一般来说位于server1.example.com的网页无法与不是 server1.example.com的服务器沟通,而HTML的script元素是一个例外。利用script元素的这个开放策略,网页可以得到从其他来源动态产生的JSON资料,而这种使用模式就是所谓的JSONP

    解决方法原理

         1、原理1:前端发送数据虽然ajax受同源策略限制。但是前端<script>、<img>、<iframe>等节点元素发送数据不受同源策略限制(凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>)。ajax可以仿照前端script节点元素发送数据从而绕过浏览器同源策略限制,即jsonp方法(绕过策略,后们进入)。

         2、原理2:前端向异域名发送ajax数据之所以不能接受到数据是由于收浏览器的同源策略影响,所以我们可以通过代理的方式来让代理帮我们发送数据到服务端,并且让代理帮我们接收服务端数据,因为代理上接受和发送数据不是通过浏览器进行发送接受的,所以不会受同源策略的影响。比如说python中的requests模块是专门仿造浏览器发送和接受请求的。

         3、原理3:前端发送ajax数据之所以受同源策略限制是因为服务端返回数据没有设置响应头,浏览器通过判断响应头来是否接受数据,所以我们就可以在服务端发送数据之前设置好响应头信息,即CORS方法

    CORS 对比 JSONP

    都能解决 Ajax直接请求普通文件存在跨域无权限访问的问题

    1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
    2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
    3. JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS

    解决方法:

    一:jsonp 

    1.script方法(客户端根据script元素标签属性自动生成jsonp方法),须知<script>、<img>、<iframe>中的src属性都是通过get方式将请求的数据下载下来(下载的数据是字符串形式的变量),然后通过本地的js渲染下载的数据,就和服务端中数据一摸一样。

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script>
            function fun(arg) {
                alert(arg)
            }
        </script>
        <script src="http://127.0.0.1:8000/get_data.html"></script>
    
    </head>
    客户端 html
    def get_data(request):
    
        return HttpResponse('fun("机密数据")')
    Django 视图函数

    2、input方法(客户端根据input元素标签属性手动生成jsonp方法)

    <body>
        <input type="text" />
        <div id="i1"></div>
        <input type="button" onclick="jsonp('http://127.0.0.1:8000/get_data.html')"  value="发送JSONP请求"/>
        <script src="/static/jquery-3.2.1.js"></script>
        <script>
                function fun(arg) {
                alert(arg);
     
                document.head.removeChild(tag);
            }
     
            function jsonp(url){
                tag = document.createElement('script');
                tag.src = url;
                document.head.appendChild(tag);
            }
        </script>
    客户端 html
    def get_data(request):
     
        return HttpResponse('fun("机密数据")')
    Django 视图函数

    3、input方法+url方法(客户端根据url传递的相应参数使服务端返回相对应的字符串)

    <body>
        <h1>皇家赌场</h1>
        <input type="text" />
        <div id="i1"></div>
     
        <input type="button" onclick="jsonp('http://127.0.0.1:8000/get_data.html?callback=funcvvvvvv')"  value="发送JSONP请求"/>
        <script src="/static/jquery-3.2.1.js"></script>
        <script>
                function funcvvvvvv(arg) {
                alert(arg);
     
                document.head.removeChild(tag);
            }
     
            function jsonp(url){
                tag = document.createElement('script');
                tag.src = url;
                document.head.appendChild(tag);
            }
        </script>
    </body>
    客户端 html
    def get_data(request):
        func_name = request.GET.get('callback')
        return HttpResponse('%s("机密数据")' %func_name)
    服务端

    4、jsonp方法(客户端通过jsonp方式发送ajax实际上不是发送ajax请求,而是把ajax内的数据转换成script标签和相应的函数,根据script标签属性来发送数据)

    <body>
    <h1>皇家赌场</h1>
    <input type="text"/>
    <div id="i1"></div>
     
    <input type="button" onclick="Jsonp2()" value="发送JSONP2请求"/>
     
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function Jsonp2() {
            $.ajax({
                url: "http://127.0.0.1:8000/get_data.html",
                type: 'GET',
                dataType: 'JSONP',
                success: function (data) {
                    alert(data);
                }
            })
        }
    </script>
    </body>
    客户端,html
    def get_data(request):
        func_name = request.GET.get('callback')
        return HttpResponse('%s("机密数据")' %func_name)
    服务端

     5、jsonp完整版

    (dataType告诉ajax我其实是通过生成script标签发送数据,jsonp实际上是向url上添加一个键值对来告诉客户端返回的字符串的格式,jsonpCallback实际上是客户端接受到数据后执行对应的函数)

    <body>
    <h1>皇家赌场</h1>
    <input type="button" onclick="Jsonp3()" value="发送JSONP3请求"/>
     
    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function Jsonp3() {
            $.ajax({
                url: "http://127.0.0.1:8000/get_data.html",
                type: 'GET',
                dataType: 'JSONP',
                jsonp: 'callback',
                jsonpCallback: 'list'
            })
        }
        function list(arg) {
            console.log(arg)
            alert(arg)
        }
     
    </script>
    </body>
    客户端,html
    def get_data(request):
        func_name = request.GET.get('callback')
        return HttpResponse('%s("机密数据")' %func_name)
    服务端

     二:代理:

      在python中可以通过requests模块来实现代理

    三:CORS方法

      在客户端设置代码(直接通过ajax发送数据)

    <body>
        <h1>皇家赌场</h1>
        <script src="/static/jquery-3.2.1.js"></script>
        <script>
            $.ajax({
                url: "http://127.0.0.1:8000/get_data.html?xxx=666",
                type: 'GET',
                success: function(data){
                    console.log(data);
                }
            })
        </script>
    </body>
    客户端,html

       在服务端局部设置响应头(*代表匹配所有,也可以跟正则表达式匹配)

    def get_data(request):
        response = HttpResponse("机密数据")
        response['Access-Control-Allow-Origin'] = "*"
        # response['Access-Control-Allow-Origin'] = "http://127.0.0.1:8000"
        return response
    服务端

    注:

    1、如果想在全局设置响应头信息就可以直接在django中间件中设置

    2、简单请求 和 非简单请求(同时满足以下两个条件时,则是简单请求,否则为复杂请求

          条件:1、请求方式:HEAD、GET、POST

               2、请求头信息:
                    Accept
                    Accept-Language
                    Content-Language
                    Last-Event-ID
                    Content-Type 对应的值是以下三个中的任意一个
                                    application/x-www-form-urlencoded
                                    multipart/form-data
                                    text/plain
    3、简单请求和非简单请求的区别?
       简单请求:一次请求
       非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”(options),只有“预检”通过后才再发送一次请求用于数据传输,"
    4、关于“预检”
         1、请求方式:OPTIONS
         2、什么是预检
            预检其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
         3、如何预检?
             1、如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
                Access-Control-Request-Method
             2、 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
                Access-Control-Request-Headers
    复杂请求的配置:
    def get_data(request):
        if request.method == "OPTIONS":
            # 预检也要有返回值,可以为空,并且允许所以用户预检,允许预检方式为PUT,运行预检头的值为xxx
            response = HttpResponse()
            response['Access-Control-Allow-Origin'] = "*"
            # response['Access-Control-Allow-Methods'] = "PUT"
            response['Access-Control-Allow-Headers'] = "xxx"
    
           response['Access-Control-Allow-Headers']="true"
           return response   
      elif request.method == "GET":      
        response = HttpResponse("机密数据")       
        response['Access-Control-Allow-Origin'] = "*"      
        return response
    服务端
    function JqSendRequest(){
              $.ajax({
                  url: "http://c2.com:8000/test/",
                  type: 'PUT',
                  dataType: 'text',
                  headers: {'k1': 'v1'},
                  xhrFields:{withCredentials: true},#如果设置想要头必须加上这句话
                  success: function(data, statusText, xmlHttpRequest){
                      console.log(data);
                  }
              })
    客户端
  • 相关阅读:
    sqlplus时报Linux-x86_64 Error: 13: Permission denied
    thrift之TTransport层的缓存传输类TBufferedTransport和缓冲基类TBufferBase
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 合并石子
  • 原文地址:https://www.cnblogs.com/mona524/p/7711053.html
Copyright © 2011-2022 走看看