同源策略 jsonp CORS 跨域

时间:2022-12-18 11:11:31

浏览器的同源策略

  • 限制了浏览器往不同的源发请求,阻止读取响应数据。

    <div >
        <button id="btn">点我获取数据</button>
    </div>
    
    $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/index/',
            success:function (res) {
                console.log(res)
            },
            error:function (err) {
                console.log(err)
            }
        })
    })

    所报错误:

    Access to XMLHttpRequest at 'http://127.0.0.1:8001/index' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • a标签 以及form表单的 请求不会被浏览器阻止

    注意 from 标签的请求地址最后的 /

    <!-- a标签  实现跨域-->
    <a href="http://127.0.0.1:8001/index">点击获取 数据</a>
    
    
    <!-- form表单提交post  实现跨域-->
    <form action="http://127.0.0.1:8001/index/" method="post">
        <input type="text" name="">
        <button>提交</button>
    </form>
    
    def index(request):
        if request.method == 'POST':
            print(request.POST.get('name'))
            return HttpResponse('form 200 OK')
    
        return HttpResponse('{}'.format('a标签请求'))

跨域

跨域问题

JSONP 实现

  • 写法:

    • 使用引用 JS 文件的 方式 给服务器发送请求
    • 在引用之前定义一个函数
    <script>
        // 定义一个 函数 用于接收返回的数据
        function func(data){
            console.log(data)
        }
    </script>
    
    <!-- 引用服务器的接口实现数据传递 -->
    <script src="http://127.0.0.1:8001/index"></script>
    
    <!-- 相当于执行 func函数 -->
    <script>
        func(data)
    </script>
    
    • 在view 视图中 返回 一个 "func(data)" 函数 的 调用 字符串形式 前端会自动根据函数名调用 定义好的 函数对象并且接收数据
    def index(request):
        import json
        data = {'name': '张紫益', 'age': 18}
        # 返回一个函数的 调用方法
        return HttpResponse('index({})'.format(json.dumps(data, ensure_ascii=False)))
  • 缺点:

    ​ 前后端都要支持

    ​ 只能发GET请求

CORS跨域

  • 简单请求和非简单请求

    同时满足以下两个条件的是简单请求:

    (1) 请求方法是一下三种方法之一:

    • HEAD
    • GET
    • POST

    (2) HTTP 的头信息不超过一下几种字段

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content--Type: 只限于 application/x-www-form-urlencoded, multipart/form-data,texxt/plain
  • 简单请求

    前端正常 提交 ajax 请求

    后端要给响应头加上 Access-Control-Allow-Origin

    
        data = {'name': '张紫益', 'age': 18}
    
        ret = HttpResponse('{}'.format(json.dumps(data, ensure_ascii=False)))
        # 给 response 对象 添加响应头  指定 发送请求的主机地址 
        ret['Access-Control-Allow-Origin'] = 'http://localhost:63342'
        # 或者 让所有的 简单请求 都通过 
        ret['Access-Control-Allow-Origin'] = '*'   // * 所有
          # 启用 控制 允许 起源
        return ret
    • 将响应求头加入到 中间件中 避免每次都要写

      from django.utils.deprecation import MiddlewareMixin
      
      class CORSMiddleware(MiddlewareMixin):
      
          def process_response(self, request, response):
              response['Access-Control-Allow-Origin'] = '*'
              return response
      
      # 注册中间件
      # 在中间件的 第一行注册  因为响应 是倒叙的 
  • 非简单请求:

    区别 : 前段请求的 ajax 中 加入了 contenttype: 'application/json' 的 请求头

    请求的 类型 就变成了 POTIONS 类型

    • 后端要给响应头加上

      如果修改了Content-Type: Access-Control-Allow-Headers

    前端中

    $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/index/',
            type:'post',
    //  设置的 非简单 请求  会 将请求方式 该为   POTIONS
            contentType:'application/json',
            success:function (res) {
                var aa = JSON.parse(res)
                console.log(aa)
                console.log(JSON.stringify(aa))
            },
            error:function (err) {
                console.log(err)
            }
        })
    })

    Django 中

        data = {'name': '张紫益', 'age': 18}
    
        ret = HttpResponse('{}'.format(json.dumps(data, ensure_ascii=False)))
        # 判断 请求 是否是 非简单请求
        if request.method =='OPTIONS':
            # 设置 响应头让其 通过
            ret['Access-Control-Allow-Headers'] = 'content-type'
        return ret

    PUT或DELETE请求

    如果使用的是PUT或DELETE请求 :设置响应头 Access-Control-Allow-Methods = 'PUT'

     data = {'name': '张紫益', 'age': 18}
    
        ret = HttpResponse('{}'.format(json.dumps(data, ensure_ascii=False)))
        # 判断 请求 是否是 非简单请求
        if request.method =='OPTIONS':
            # 设置 响应头让其 通过
            ret['Access-Control-Allow-Headers'] = 'content-type'
            # 设置  put  delete  请求的 响应头
            ret['Access-Control-Allow-Methods'] = 'PUT, DELETE'
        return ret

前端:

JSON 的 序列化 与反序列化

data = ' {'name': '张紫益', 'age': 18}'

// 序列化    parse  解析
var obj = JSON.parse(data)
console.log(obj)

// 反序列化
var str =JSON.stringify(obj)
console.log(str)

django-core-headers

使用django f夫人

详见博客 同源策略及JSONP、CORS跨域

安装

pip install django-cors-headers

注册APP

INSTALLED_APPS = [
    ...
    'app01.apps.App01Config',
    'corsheaders',  #  将 corsheaders 这个APP注册
]

添加中间件

必须放在最前面,因为要先解决跨域的问题。只有允许跨域请求,后续的中间件才会正常执行。

MIDDLEWARE = [
    'corsheaders.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',
]

配置

你可以选择不限制跨域访问 允许所有

CORS_ORIGIN_ALLOW_ALL = True

或者你可以选择设置允许访问的白名单

CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    # '<YOUR_DOMAIN>[:PORT]',
    '127.0.0.1:8080'
)