content-type 描述前端发送的数据格式
推荐博客:https://blog.csdn.net/danielzhou888/article/details/72861097
简单请求
http : HEAD GET POST
Content-Type只能是下列类型中的一个
application/x-www-from-urlencoded form表单请求
multipart/form-data 需要在表单中进行文件上传时,就需要使用该格式
text/plain 纯文本格式
复杂请求
只要不满足简单请求都是复杂请求
复杂请求先发送预检 OPTIONS
利用中间件加响应头解决跨域
# 中间件:
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
def process_response(self, request, response):
# 简单请求,加个响应头就可以了
response["Access-Control-Allow-Origin"] = "*" # 允许所有的源(针对的是浏览器的同源策略)
if request.method == "OPTIONS":
response["Access-Control-Allow-Headers"] = "Content-Type,a,token"
# 当是预检请求时,允许携带Content-Type,a,token请求头
# content-type允许的是请求头中的Contend-Type键值对,
# 简单请求只允许application/x-www-from-urlencoded、multipart/form-data、text/plain这三种类型的请求,
# 当前端发送json请求时,如果不设置content-type就不被允许
# a ,token请求头时我们在前端发送axios自定义的请求头
response["Access-Control-Allow-Methods"] = "POST, PUT, PATCH, DELETE" # 除了简单请求外这些请求方式也都允许
return response
# views.py文件
from course.utils.authentication import MyAuth
class CourseView(ModelViewSet):
authentication_classes = [MyAuth, ] # 进行局部认证,所有走这个视图函数的都需要认证,在我们这里是都要携带token请求头
queryset = Course.objects.all()
serializer_class = CourseModelSerializer
def list(self, request, *args, **kwargs):
print(request.META.get('HTTP_A'))
print(request.META.get('HTTP_TOKEN'))
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
response={"code":1000,"data":None,"err_msg":""}
if page is not None:
serializer = self.get_serializer(page, many=True)
response["data"]=serializer.data
return self.get_paginated_response(response)
serializer = self.get_serializer(queryset, many=True)
response["data"] = serializer.data
return Response(response)
# authentication.py 自己写的认证组件
from rest_framework import authentication
from rest_framework.exceptions import AuthenticationFailed
from course.models import Userinfo, UserToken
class MyAuth(authentication.BaseAuthentication):
def authenticate(self, request):
if request.method == "OPTIONS": # 复杂请求走预检时,直接返回,走CorsMiddleWare中间件中的process_response,给响应加允许的头
return
token = request.META.get('HTTP_TOKEN') # 不是复杂请求时,从request.META拿到请求头携带的数据,django会对我们的请求头做处理,前端axios发送的请求头是token,django拿到的请求头就会变成HTTP_TOKEN,而且这里的request也是restframework重新封装后的request
user_obj = UserToken.objects.filter(token=token).first() # 获取前端传过来的token
if not user_obj:
raise AuthenticationFailed("无效的token")
return user_obj.user, token
# 前端axios请求文件
category_click_all: function () {
this.current = -1;
let that = this;
// console.log(this.$store.state.token,'token已经从仓库中拿到了)
this.$axios.request({
url: "http://127.0.0.1:8000/course/", //请求地址
method: "get",
headers: {
a: '1',
token: this.$store.state.token, //携带的请求头
},
}).then(function (res) {
console.log("res:", res);
that.course_list = res.data.data
}).catch(function (data) {
console.log(data)
})
},
#浏览器跨域:
1,先走预检请求 request.method == "OPTIONS",这和get post是同级别的请求
2,vue发axios携带请求头时,get请求,这是第二次请求
当没有认证组件时,第一次请求在视图函数中没有找到相应的函数来处理options请求,最后走中间件,在response响应头中添加了允许的请求头和所有的源,表示允许携带请求头
第二次请求是get请求,视图函数可以进行处理,可以在request.META中拿到请求头,当然最后走中间件process_response
当有认证组件时,第一次请求到来先走认证组件,在认证组件中进行判断,如果是options请求return,这是执行中间件的process_response方法,响应预检请求
第二次请求get请求,这是就可以拿到request.META中的请求头数据了