• 如何使用CORS解决跨域问题


    一,为什么会有跨域问题

      跨域问题的出现,是因为浏览器的同源策略对ajax请求进行阻拦了,但是并不是所有的请求都给做当做跨域,;像是一般的href属性,a标签什么的都不进行拦截

    二,什么是同源策略

      同源策略是一种约定,它是浏览器最核心也会是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

      它约定请求的url地址,必须与浏览器的url地址处于同域上,也就是域名,端口,协议都相同。

      如果不同,就会报错:

    已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8001/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。

      实际上的结果是,请求以及被发送过去了,目标服务器也对做出了响应,只是浏览器对非同源请求的放回结果做了拦截。

    三,CORS简介

      CORS,跨域资源共享,它需要浏览器和服务器同事支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

      整个CORS通信中,都是浏览器自动完成的,不需要用户的参与,对于开发者来说cors通信与同源的ajax没有差别,代码完全一样。浏览器一旦发现ajax请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有察觉。

      要实现cors通信,主要是在服务器,也就是获得数据的一方做处理。

    四,cors基本的流程

      1,浏览器将请求分为两类,一类是简单请求,一类是非简单请求,满足下列条件的就是简单请求,否则即使非简单请求:

    条件:
        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
     
    注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

      2,简单请求和复杂请求的区别:

        简单请求:一次请求

        非简单请求:两次请求,在发送数据之前会先发第一次请求做预检,只有预检通过后在发一次请求作为数据传输。

      3,关于预检:

    - 请求方式:OPTIONS
    - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
    - 如何“预检”
         => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
            Access-Control-Request-Method
         => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
            Access-Control-Request-Headers

      4,CORS优缺点

        CORS的优点:可以发任意请求

        CORS的缺点:上是复杂请求的时候得先做一个预检,再发真实的请求,发了两次请求会有性能上的损耗。

    五,实现CORS请求

      局部使用:

        简单请求(get)客户端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <button id="a" class="btn btn-success">go</button>
    <script>
        $("#a").click(function () {
            $.ajax({
                url:'http://127.0.0.1:8000/time/',
                type:'get',
                success:function (data) {
                    alert(data)
                }
                }
            )
        })
    </script>
    </body>
    </html>

        简单请求服务端:

    def get_time(request):
        if request.method == 'GET':
            ntime = time.strftime('%Y-%m-%d %X')
            obj = HttpResponse(ntime)
            obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
            return obj

        复杂请求(post+contentType)客户端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <button id="a" class="btn btn-success">go</button>
    <script>
        $("#a").click(function () {
            $.ajax({
                url:'http://127.0.0.1:8000/money/',
                type:'post',
                contentType:'application/json',
                data:{"name":"yjh"},
                success:function (data) {
                    alert(data)
                }
                }
            )
        })
    </script>
    </body>
    </html>

        复杂请求服务端:

    from django.http import QueryDict
    def get_money(request):
        # print(request.body)
        if not request.body:
            obj = HttpResponse('1000000000000')
        else:
            data = request.body # post请求传过来的数据以二进制的形式存放于request.body
            # 将request.body的二进制数据转化为字典形式
            dic = QueryDict(data.decode('utf-8'),encoding='utf-8')
            name = dic.get('name')
            obj = HttpResponse(name)
        if request.method == 'OPTIONS':
            obj['Access-Control-Allow-Headers'] = 'Content-Type'
        obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
        return obj

    六:全局配置

      由于是全局配置,所以应该写在中间件中。然而,我们知道浏览器是在返回的时候出现的禁用,因此我们我们需要重写process_response方法。

      第一步:在应用文件夹根目录中,新建一个my_middleware.py文件

      第二步:在该py文件夹中写上:

    from django.utils.deprecation import MiddlewareMixin
    class CorsMiddleWare(MiddlewareMixin):
        def process_response(self,request,response):
            if request.method=="OPTIONS":
                #可以加*
                response["Access-Control-Allow-Headers"]="Content-Type"
            response["Access-Control-Allow-Origin"] = "http://localhost:8080"
            return response

      第三步:在settings.py中配置:

    MIDDLEWARE = [
        'app01.my_middleware.CorsMiddleware',
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

      

  • 相关阅读:
    关于 SQL Server 的事务隔离
    Joplin与阿里云OSS做同步
    vite配置vitepluginstyleimport插件后启动报错
    FireDAC组件快照
    mvn site:java.lang.NoClassDefFoundError: org/apache/maven/doxia/siterenderer/DocumentContent
    MySQL8 二进制日志
    MySQL8配置文件
    创建一个 autocomplete 输入系统 前端 + 后端
    5.Ceph 基础篇 认证
    修复 Elasticsearch 集群的常见错误和问题
  • 原文地址:https://www.cnblogs.com/ay742936292/p/11151628.html
Copyright © 2020-2023  润新知