跳转底部

跨域问题

 

 

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中的请求头数据了

  

 

 

posted on 2018-11-15 14:49  afly666  阅读(146)  评论(0编辑  收藏  举报

导航

回到顶部