跨域问题

同源策略

  1、同源策略,是浏览器为了保护用户信息安全的一种安全机制

  2、所谓的同源就是指代通信的两个地址(例如服务端接口地址与浏览器客户端页面地址)之间比较,是否协议、域名(IP)和端口相同

  3、不同源的客户端脚本[javascript]在没有得到服务端的明确授权的情况下,浏览器会拒绝显示服务端信息提供给前端ajax/axios

CORS(跨域资源共享)简介

  1、CORS是一个W3C标准,全称是"跨域资源共享",它允许浏览器向跨源的后端服务器发出ajax请求,从而克服了AJAX只能同源使用的限制。

    实现CORS主要依靠后端服务器中响应数据中设置响应头信息返回的

  2、CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

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

  4、因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

  注:容易混淆的点:

  • CORS:跨域资源共享
  • CSRF:跨站请求伪造
  • XSS:跨站脚本攻击

CORS基本流程

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

  浏览器发出CORS简单请求只需要在头信息之中增加一个Origin字段。

  浏览器发出CORS非简单请求会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

  浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。

  只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

CORS两种请求详情

  1、简单请求和非简单请求

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

(1) 请求方法是以下三种方法之一:
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

    凡是不同时满足上面两个条件,就属于非简单请求。

  2、浏览器对这两种请求的处理,是不一样的。

    简单请求和非简单请求的区别

    简单请求:一次请求,直接发真正的请求,如果允许,数据拿回来,如果不允许,浏览器拦截

    非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输,非简单请求发两次,第一次是OPTIONS请求,如果允许跨域,再发真正的请求

    预检:检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息

    如何预检:

      如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过

Access-Control-Request-Method

      如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过

Access-Control-Request-Headers

解决跨域问题(服务端)

  简单请求

    1、原Django项目:apps/user/views.py

from django.http import JsonResponse

def test(request):
    obj = JsonResponse({'name':'279工程','price':6000000})
    # 值针对简单请求
    obj['Access-Control-Allow-Origin'] = '*'    # 允许所有IP访问
    return obj

    2、原Django项目:apps/user/urls.py

from django.urls import path
from user import views

urlpatterns = [
    path('test/', views.test),
]

    3、注释掉CSRF

    4、在创建1个Django项目(用另外的端口)

      emplates中创建index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">点我</button>

</body>
<script>
    $('#btn').click(function () {
        $.ajax({
            url: 'http://127.0.0.1:8000/user/test/',
            method: 'get',
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

    viwes.py

from django.shortcuts import render


def index(request):
    return render(request, 'index.html')

    urls.py

from django.urls import path
from app01 import views

urlpatterns = [
    path('test/', views.index),
]

  非简单请求
    原Django项目apps/user/views.py
from django.http import JsonResponse


def test(request):
    obj = JsonResponse({'name': 'Darker', 'age': '18'})
    if request.method == 'OPTIONS':
        obj['Access-Control-Allow-Headers'] = 'Content-Type,authorization'  # 或者填写 *
    obj['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8002'    # 8002端口是当前项目的
    return obj

    新Django项目templates/index.html

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<button id="btn">点我</button>

</body>
<script>
    $('#btn').click(function () {
        let obj = {name: 'Darker'}
        $.ajax({
            url: 'http://127.0.0.1:8000/user/test/',
            method: 'post',
            contentType: 'application/json',
            headers: {authorization: 'Darker'},
            data: JSON.stringify(obj),
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

  中间件处理

    在原Django项目的根路径创建mymiddle.py - 自定义中间件

from django.utils.deprecation import MiddlewareMixin


class CoreMiddle(MiddlewareMixin):
    def process_response(self, request, response):
        if request.method == 'OPTIONS':
            response['Access-Control-Allow-Headers'] = 'Content-Type, authorization'    # 如果是 * 就代表全部IP都可以访问
        response['Access-Control-Allow-Origin'] = '*'
        return response

    在原Django项目的dev.py的中间件中添加自定义中间件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'mymiddle.CoreMiddle',    # 这一句是新加的
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

    原Django项目apps/user/views中替换成如下代码

from django.http import JsonResponse


def test(request):
    return JsonResponse({'name': 'Darker', 'age': '18'})

解决跨域问题(第三方)

  下载

pip install django-cors-headers

  app注册

    INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
    ]

  中间件注册

    MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
  ]

  配置文件配置

# 允许简单请求,所有地址 相当于CORS_ORIGIN_ALLOW_ALL="*"
CORS_ALLOW_ALL_ORIGINS = True
# 运行的请求
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'POST',
    'PUT',
)

# 允许的请求头
CORS_ALLOW_HEADERS = (
    'accept-encoding',
    'authorization',  # jwt
    'content-type',  # json
    'origin',
    'user-agent',
    'Pragma',
)

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2022-04-21 20:17  那就凑个整吧  阅读(26)  评论(0编辑  收藏  举报