• 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);
                  }
              })
    客户端
  • 相关阅读:
    geoserver 文件系统
    geoserver 源码介绍
    geoserver 开发2
    geoserver 开发1
    geoserver笔记
    linux 下安装gult
    LINUX 笔记5
    SQLSTATE[HY000] [2002] 乱码
    微信开发
    javascript记忆
  • 原文地址:https://www.cnblogs.com/mona524/p/7711053.html
Copyright © 2020-2023  润新知