• 浏览器的同源策略,及如可跨域


    1、同源策略

      所谓同源是指,域名,协议,端口相同。当一个浏览器的打开一个页面时中,页面请求非同源的URL时,请求能正常响应,但是浏览器会判断请求的URL和本页面的URL是否同源,

    如果非同源的话,就会在本页面返回一个错误,并且得不到返回的数据。

    2、解决跨域的方法

    2.1、CORS通信实现跨域请求

      浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

      只要同时满足以下两大条件,就属于简单请求。 

    (1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么put、delete等肯定是非简单请求)
    HEAD
    GET
    POST
    (2)HTTP的头信息不超出以下几种字段:(如果比这些请求头多,那么一定是非简单请求)
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vue的axios默认的请求体信息格式是json的,ajax默认是urlencoded的。
    

    对于简单的请求只需要我么请求URL的响应函数views里面配置响应头Access-Control-Allow-Origin

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script>
            function func(name) {
                alert(name)
    
            }
        </script>
        <script src="http://127.0.0.1:8001/base/"></script>
    </head>
    <body>
    
    <form>
        <input type="button" id="id_button" value="button">
    
    </form>
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <script>
        $("#id_button").click(function () {
            $.ajax({
                url:'http://127.0.0.1:8001/base/',
                type:'GET',
                success:function () {
                    alert('1111')
    
                }
            })
    
        })
    </script>
    </body>
    </html>
    index.html
    from django.shortcuts import render,HttpResponse
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        response = HttpResponse('func("wuzhiib")')
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
       # 在我们请求的URL的views里面设置,’*‘表示允许所有URL通过
        return response
    views.py

    浏览器对简单请求和复杂请求的处理是不一样的

    * 简单请求和非简单请求的区别?
    
       简单请求:一次请求
       非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
    * 关于“预检”
    
    - 请求方式:OPTIONS
    - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
    - 如何“预检”
         => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
            Access-Control-Request-Method
         => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
            Access-Control-Request-Headers

    如果在Ajax请求中加入ContentType就会使普通的请求变成复杂的请求。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script>
            function func(name) {
                alert(name)
    
            }
        </script>
        <script src="http://127.0.0.1:8001/base/"></script>
    </head>
    <body>
    
    <form>
        <input type="button" id="id_button" value="button">
    
    </form>
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <script>
        $("#id_button").click(function () {
            $.ajax({
                url:'http://127.0.0.1:8001/base/',
                type:'GET',
                contentType:'application/json',
                success:function () {
                    alert('1111')
    
                }
            })
    
        })
    </script>
    </body>
    </html>
    index.html

    对对于复杂的请求要在对应的头里面做设置,Contenttype只需要在响应头里面设置X-Content-Type-Options

    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    
    # Create your views here.
    
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        response = HttpResponse('func("wuzhiib")')
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
        response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
        return response
    views.py

    3、JsonP实现跨域

      非同源的URL不能阻止src属性的请求,也就是说通过src属性我们能跨域请求数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script>
            function func(name) {
                alert(name)
            }
        </script>
        <!--利用script标签来实现跨域请求,返回的是func(''wuzhibin),相当于实现上面func函数的调用-->
        <script src="http://127.0.0.1:8001/base/"></script>
    </head>
    <body>
    
    <form>
        <input type="button" id="id_button" value="button">
    
    </form>
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <script>
        $("#id_button").click(function () {
            $.ajax({
                url:'http://127.0.0.1:8001/base/',
                type:'GET',
                contentType:'application/json',
                success:function () {
                    alert('1111')
    
                }
            })
    
        })
    </script>
    </body>
    </html>
    index.html
    from django.shortcuts import render,HttpResponse
    
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        response = HttpResponse('func("wuzhiib")')
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
        response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
        #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
        response['X-Content-Type-Options'] ="application/json" 
        return response
    views.py

    注意如果如果不配之响应头的X-Content-Type-Options属性,浏览器会报一个错误

    上面就是Jsonp实现的原理,这个只是哟个简单的例子,一般我们都需要能够动态的实现标签的创建

    动态创建script标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <button onclick="f()">sendAjax</button>
    <!--动态创建标签Script-->
    <script>
        function addScriptTag(src){
             var script = document.createElement('script');
             script.setAttribute("type","text/javascript");
             script.src = src;
             document.head.appendChild(script);
             // document.body.removeChild(script);
        }
        // 接受返回数据的回调函数
        function func(name){
            alert("hello"+name)
        }
        function f(){
             addScriptTag("http://127.0.0.1:8001/base/")
        }
    </script>
    </body>
    </html>
    index.Html

    views.py与上面一直

    from django.shortcuts import render,HttpResponse
    
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        response = HttpResponse('func("wuzhiib")')
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
        response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
        #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
        response['X-Content-Type-Options'] ="application/json"
        return response
    views.py

    上面的例子中,我们在前端定义函数的时,另一个域明显是不知道我们我们前端定义的是func的,所以我们需要将函数名传给跨域的views函数动态生成返回函数名

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <button onclick="f()">sendAjax</button>
    <!--动态创建标签Script-->
    <script>
        function addScriptTag(src){
             var script = document.createElement('script');
             script.setAttribute("type","text/javascript");
             script.src = src;
             document.head.appendChild(script);
             // document.body.removeChild(script);
        }
        // 接受返回数据的回调函数
        function func(name){
            var name=name
            alert("hello"+name)
        }
        function f(){
             addScriptTag("http://127.0.0.1:8001/base/?callbacks=func")
        }
    </script>
    </body>
    </html>
    index.html
    from django.shortcuts import render,HttpResponse
    
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        # 返回给跨域请求的数据
        data = 'wuzhibin'
        #获取跨域请求的函数名
        callback = request.GET.get('callbacks')
        print(callback)
    
        response = HttpResponse("%s('%s')"%(callback,data))
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
        response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
        #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
        response['X-Content-Type-Options'] ="application/json"
        return response
    view.py
    Ajax中使用Jsonp

    在实际的用处中,在Ajax中使用跨站请求数据的场景比较多一些。而不是单独生产动态生成一个Script标签去请求数据

    from django.shortcuts import render,HttpResponse
    from django.http import JsonResponse
    
    def index(request):
        return render(request,'index.html')
    
    def base(request):
        import json
        # 返回给跨域请求的数据,一般都是字典的格式
        data = {
            'key1':'value1',
            'key2':'value2',
            'k3':'value3',
            'k4':'value4',
        }
        #等到跨域的方法名
        callbacks = request.GET.get("callbacks")
    
        response =HttpResponse("%s('%s')"%(callbacks,json.dumps(data)))
        response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
        response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
        #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
        response['X-Content-Type-Options'] ="application/json"
        return response
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <button onclick="f()">sendAjax</button>
    <!--动态创建标签Script-->
    
    <script>
    function f(){
          $.ajax({  //大家会发现我的type请求方法没写,默认是get请求
                url:"http://127.0.0.1:8001/base/",
                dataType:"jsonp",
                jsonp: 'callbacks',
                jsonpCallback:"SayHi"
           });
       }
    function SayHi(arg){
                // 将字符串转发为字典的格式
               var data = JSON.parse(arg);
                alert(data.key1);  //k1是后端返回的数据中的键值对的键
            }
    </script>
    </body>
    </html>
    index.html

     也能通过Ajax的success函数获取跨域的数据,这种方式比较简单些

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <script src="/static/jquery-2.1.4.min.js"> </script>
    <button onclick="f()">sendAjax</button>
    <!--动态创建标签Script-->
    
    <script>
    function f(){
          $.ajax({  //大家会发现我的type请求方法没写,默认是get请求
                url:"http://127.0.0.1:8001/base/",
                dataType:"jsonp",
                jsonp: 'callbacks',
                jsonpCallback:"SayHi",
                success:function (rag) {
                    var data = JSON.parse(rag)
                    alert(data.key1)
                }
           });
       }
    </script>
    </body>
    </html>
    index.html

    views.py函数和上面保持一致

    人生苦短,我用cnblog
  • 相关阅读:
    【go语言】Windows下go语言beego框架安装
    分页
    MongoDB用户与权限管理
    MongoDB安装在Centos7下安装
    centos7安装mysql5.7.33 tar包方式
    文件路径分隔符
    python之批量打印网页为pdf文件
    Python驱动SAP GUI完成自动化(五)
    动态内存与智能指针
    关联容器
  • 原文地址:https://www.cnblogs.com/wuzhibinsuib/p/13066532.html
Copyright © 2020-2023  润新知