• 跨域


    浏览器的同源策略

    浏览器有一个同源策略,它会阻止非同源的请求。非同源是指 域名不同 或者 端口不同。浏览同源策略只对 表单、ajax请求生效,不同拦截src的请求。

    ​ 例如: 我在 127.0.0.1:8000 的页面 去调用 127.0.0.1:8001/api/test , 就会被浏览器拦截,因为端口不同,属于非同源请求。

    ​ src请求是指这种标签中带有src属性的请求:

    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    
    <img src="http:/127.0.0.1:8082/media/pic/5cm.jpg">
    

    什么是 CORS 请求?

    CROS (cross origin resource share): 跨域资源共享。

    请求方 与 被请求资源 为 非同源的请求就是 CORS 请求,也叫做跨域请求,分为两种:

    • 简单请求
    1. http 方法 为 HEAD / GET / POST 
    
    2. http 请求头不超出这几种字段(可以没有但不能超出)
    
          Accept,  Accept-Language,  Content-Language,  Content-Type
    
          其中 Content-Type 只能是以下几种类型:
    
             application/x-www-from-urlencoded
             multipart/form-data
             text/plain
    
    
    • 复杂请求

      不满足简单请求条件的都属于复杂请求。

    解决跨域问题

    跨域问题重现

    1. 在 django 中开一个后端接口 http://127.0.0.1:8000/api/test
    #新增路由
    from app01.views import Cors_test
    path('api/test', Cors_test.as_view(),),
    
    # 新增视图函数
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class Cors_test(APIView):
        def get(self,request):
            return Response('ok')
    
    1. 在前端代码中使用 ajax 调用后端的接口

    Document ```
    1. 以服务器的方式打开前端代码文件 http://127.0.0.1:5500/templates/test.html ,并触发ajax请求,跨域报错

    JSONP

    jsonp 就是将需要跨域的链接作为src请求获取后端资源,避免跨域拦截。这样的方式有一些局限性,只能发送get请求,现在一般不用了。例如:

    html 代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" referrerpolicy="no-referrer"></script>
    </head>
    <body>
        <button id="btn1">click</button>
        <script type="text/javascript">
            // 定义一个handle函数,供后端调用传参
            function handle(data){
                // 这里写你需要的操作
                alert(data)
            }
        </script>
    
        <!-- 调用后端接口,后端返回的内容将作为js代码执行 -->
        <script type="text/javascript" src='http://127.0.0.1:8000/api/test'></script>
    </body>
    </html>
    

    后端的视图函数

    class Cors_test(View):
        def get(self,request):
            # 这里的handle('ok')传到前端将会看作js代码执行,即执行html的handle函数
            response = HttpResponse("handle('ok')")
            return response
    

    访问测试:

    vscode 安装 live Server插件,使我们的html文件可以以服务器的方式打开。

    理想情况下现在应该是alert('ok'),跳出一个ok的弹窗。但是这里报了一个CORB的错误。

    什么是CORB?

    全称为 Cross-Origin Read Blocking,跨域读取阻止,浏览器在加载可以跨域资源时,在资源载入页面之前,对其进行识别和拦截的算法:

    这个算法中有一个要点和本文相关:

    • 如果 response 包含 X-Content-Type-Options: nosniff 响应头部,下面两种情况的请求将被阻止:

      • 请求类型是"style” 但是 MIME 类型不是 “text/css”,
      • 请求类型是"script” 但是 MIME 类型不是JavaScript MIME 类型。

      请求类型我们可以看请求头中的Sec-Fetch-Dest, MIME 类型可以看返回头的 Content-Type, 请求的数据类型和返回的数据类型不一致,就很容易被 CORB机制拦截。

    怎么解决此处CORB的拦截问题?

    将 Content-Type 请求头 设置为 text/javascript;charset=UTF-8 或者 X-Content-Type-Options 请求头设置为空。

    所以视图函数的中配置:

    class Cors_test(APIView):
        def get(self,request):
            response = HttpResponse("handle('ok')")
            # response['X-Content-Type-Options'] = ""
            response['Content-Type']="text/javascript;charset=UTF-8"
    
            return response
    

    看一下效果:

    添加请求头

    在 django 中,自定义中间件,给返回的response添加请求头。

    对于简单请求,添加 Access-Control-Allow-Origin 请求头即可:

    因为简单请求的请求方法以及请求头只要允许跨域,就默认允许携带。

    from django.utils.deprecation import MiddlewareMixin
    
    class Mymiddleware(MiddlewareMixin):
        def process_response(self, request, response):
            response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:5500'
            return response
    

    对于复杂请求:

    例如ajax中使用put方法,会报错:

    复杂请求时,浏览器会先发一个预检请求 ,就是这个options,这里报错 put请求不被允许。

    ajax中添加简单请求中没有的请求头 contentType: 'application/json' 时,也会报错

    所以就需要在中间件中添加 allow headers 与 allow methods

    class Mymiddleware(MiddlewareMixin):
        def process_response(self, request, response):
            # 简单请求只需加这一个响应头
            response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:5500'
            
            # 复杂请求还需额外添加对应的响应头
            if request.method == 'OPTIONS':
                response["Access-Control-Allow-Methods"] = "PUT,PATCH,DELETE"
                response["Access-Control-Allow-Headers"] = "Content-Type"
            return response
    

    此时前端请求代码为:

    <button id="btn1">click</button>
    <script type="text/javascript">
        $('#btn1').click(
            function(){
                $('#send').attr('src','http://127.0.0.1:8000/api/test')
                $.ajax({
                    // put方法 --复杂请求
                    method: 'put',
                    url: 'http://127.0.0.1:8000/api/test',
                    // 'application/json'格式 --复杂请求
                    contentType: 'application/json',
                    success: function(data){
                        console.log(data)
                    }
                })
            }
        )
    </script>
    

    后端视图函数代码为:

    class Cors_test(APIView):
        def get(self,request):
            response = HttpResponse('ok')
            return response
    
        def put(self,request):
            response = HttpResponse('put ok')
            return response
    

    访问效果:

  • 相关阅读:
    记一次开发的日常2020-01-09
    python configparser模块
    python logging模块
    python eval() hasattr() getattr() setattr() 函数使用方法详解
    redis 连接池
    Python 数据库连接池
    Object arrays cannot be loaded when allow_pickle=False
    注册网站 captcha reCHAPTCHA 错误
    网站收藏
    Python创建命令行应用的工具 tools for command line application in python
  • 原文地址:https://www.cnblogs.com/huandada/p/16308225.html
Copyright © 2020-2023  润新知