[ Django ] django前后端分离项目解决跨域问题

1,945 阅读4分钟

这是我参与8月更文挑战的第24天,活动详情查看: 8月更文挑战

微信公众号搜索 程序媛小庄 人生苦短 一起学Python

同源策略

同源策略:

它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现,是浏览器对访问到的结果进行了拦截。

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

比如:我在本地上的域名是127.0.0.1:8000,请求另外一个域名:127.0.0.1:8001一段数据

浏览器上就会报错,这个就是同源策略的保护,如果浏览器对javascript没有同源策略的保护,那么一些重要的机密网站将会很危险。

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

跨域资源共享

跨域资源共享

允许不同的域来我的服务器拿数据

跨域问题

我的服务器返回数据给其他域,被浏览器拦截

跨域请求分类

  • 简单请求
只要同时满足以下两大条件,就属于简单请求
    (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
  • 非简单请求:凡是不同时满足上面两个条件,就属于非简单请求。

  • 简单请求与非简单请求的区别

简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。

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

解决跨域问题

跨域问题

举例说明:127.0.0.1:8002向127.0.0.1:8000发送请求,后者会返回数据给前者,但是在前者的浏览器被拦截

Access to XMLHttpRequest at 'http://127.0.0.1:8000/get/' from origin 'http://127.0.0.1:8002' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

简单请求跨域问题解决方案

  • 解决方案:

由于在浏览器中的报错信息提示:No 'Access-Control-Allow-Origin' header is present on the requested resource.因此需要为服务器设置响应头:Access-Control-Allow-Origin = ‘域名’ 或 ‘*’

代码示例:

# 被访问的服务端的视图类代码
from rest_framework.views import APIView
from rest_framework.response import Response


class TestView(APIView):
    def get(self,request):
        print('xxxx')
        # 需要在被访问的服务端的response对象中加入'Access-Control-Allow-Origin':'http://127.0.0.1:8002',意思就是当我向http://127.0.0.1:8002发送数据时,对方浏览器允许接收我的数据
        return Response('ok',headers={'Access-Control-Allow-Origin':'http://127.0.0.1:8002'})


    def post(self,request):
        print(111111111)
        return Response('ok',headers={'Access-Control-Allow-Origin':'http://127.0.0.1:8002'})
    
# 返送ajax请求的前端页面代码及视图函数
def index(request):
    response = render(request,'index.html')
    return response


# 前端代码
<body>
    <button id="btn">click me</button>

    <script>
        $('#btn').click(function () {
            $.ajax({
                url:'http://127.0.0.1:8000/get/',
                type:'get',
                success:function (data) {
                    console.log(data);

                }
            })
        })

    </script>
</body>

非简单请求解决方案

代码实例:

前端页面发送ajax请求,请方式是post,并且携带了json格式数据,属于非简单请求。

非简单请求会发送两次请求,第一是预检请求options,第二次是post请求。

简单请求只需要允许域名即可,非简单请求还需要允许['Access-Control-Allow-Headers'] = 'Content-Type'

  • 总结:使用自定义中间件解决跨域请求问题

将中间件配置到配置文件中即可,在视图函数中就不需要单独配置了。

from django.utils.deprecation import MiddlewareMixin


class MyMiddle(MiddlewareMixin):
    def process_response(self,request,response):
        response['Access-Control-Allow-Origin'] = '*'
        if request.method == 'OPTIONS':
            response['Access-Control-Allow-Headers'] = 'Content-Type'
        return response

第三方插件解决跨域问题 django-cors-headers

  • 安装

pip install django-cors-headers

  • 添加到settings的app中
INSTALLED_APPS = (
	...
	'corsheaders',
	...
)
  • 添加到中间件中
MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
	...
	'corsheaders.middleware.CorsMiddleware',
	'django.middleware.common.CommonMiddleware',
	...
]
  • settings.py中配置如下代码
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
	'*'
)
CORS_ALLOW_METHODS = (
	'DELETE',
	'GET',
	'OPTIONS',
	'PATCH',
	'POST',
	'PUT',
	'VIEW',
)

CORS_ALLOW_HEADERS = (
	'XMLHttpRequest',
	'X_FILENAME',
	'accept-encoding',
	'authorization',
	'content-type',
	'dnt',
	'origin',
	'user-agent',
	'x-csrftoken',
	'x-requested-with',
	'Pragma',
)

结语

文章首发于微信公众号程序媛小庄,同步于掘金

码字不易,转载请说明出处,走过路过的小伙伴们伸出可爱的小指头点个赞再走吧(╹▽╹)