• drf 异常捕获


    异常捕获

       使用drf进行前后端分离时,有的时候当后端出现异常,返回的数据格式并不是JSON,你可能会发现下面这样的情况:

       image-20201101215346205

       它会返回给你一个HTML文档,这显然对于前端开发工程师来说是非常不友好的。

       所以我们通常会将这种情况给他处理掉,学习如何处理之前要看drf是如何对异常进行处理的。

    源码阅读

       首先APIView中的dispatch()方法中有关于异常的捕获,它的异常捕获是从执行认证开始,直到封装返回对象结束。代码如下:

        def dispatch(self, request, *args, **kwargs):
    
            self.args = args
            self.kwargs = kwargs
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:  # 异常捕获开始
                self.initial(request, *args, **kwargs)
                if request.method.lower() in self.http_method_names:
                    handler = getattr(self, request.method.lower(),  
                                      self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
    
                response = handler(request, *args, **kwargs)
            except Exception as exc:
                response = self.handle_exception(exc)  # 如果发生异常,则执行这里
    
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response
    

       在self.handle_exception()这个方法中,你可以看到如下代码:

       def handle_exception(self, exc):
    
            if isinstance(exc, (exceptions.NotAuthenticated,
                                exceptions.AuthenticationFailed)):  # 判断这个异常是不是属于AuthenticationFailed这个异常,是它就会默认给你处理好
                auth_header = self.get_authenticate_header(self.request)
    
                if auth_header:
                    exc.auth_header = auth_header
                else:
                    exc.status_code = status.HTTP_403_FORBIDDEN
    
            exception_handler = self.get_exception_handler()  
    
            context = self.get_exception_handler_context()
            response = exception_handler(exc, context)  # 核心代码就在这里,它会返回这个异常的种类 return self.settings.EXCEPTION_HANDLER。
            你可以导入  from rest_framework.views import exception_handler 来看看它到底是怎么处理的
    
            if response is None:   # 如果这个种类是None时,drf将不再处理这个异常,而是交由Django进行处理,所以你会看见返回大黄页
                self.raise_uncaught_exception(exc)  
    
            response.exception = True
            return response
    

       它的处理如下:

    def exception_handler(exc, context):
    
        if isinstance(exc, Http404):
            exc = exceptions.NotFound()
        elif isinstance(exc, PermissionDenied):
            exc = exceptions.PermissionDenied()
    
        if isinstance(exc, exceptions.APIException):
            headers = {}
            if getattr(exc, 'auth_header', None):
                headers['WWW-Authenticate'] = exc.auth_header
            if getattr(exc, 'wait', None):
                headers['Retry-After'] = '%d' % exc.wait
    
            if isinstance(exc.detail, (list, dict)):
                data = exc.detail
            else:
                data = {'detail': exc.detail}
    
            set_rollback()
            return Response(data, status=exc.status_code, headers=headers)
    	# ===========以上都是drf能够去处理的异常
        return None 
    

    自定异常

       ok,既然它会将drf没有处理的异常丢给原生Django然后返回大黄页,那么能不能让drf丢给我们写的程序来进行处理呢?

       答案是肯定的。你只需要在全局做一下设置就好了,演示开始。

    全局配置

       首先我们要让发生异常时,第一步就是来运行我们的异常捕获程序,所以要在全局的settings.py中做配置:

    from rest_framework.settings import DEFAULTS
    REST_FRAMEWORK = {
        'EXCEPTION_HANDLER': "app01.aberrant.exception_catch"
    }
    

    书写异常

       如果发生drf无法捕获的异常,就由我们来处理,直接返回未知错误以及错误详情即可。

    from rest_framework.views import exception_handler
    from rest_framework.response import Response
    from rest_framework import status
    
    def exception_catch(exc,context):
        # 首先我们做一个切面,拦截掉result。如果它是None则代表会返回大黄页,我们来处理
        result = exception_handler(exc,context)
        if not result:
            # 如果是None,返回未知错误和错误详情,并且返回服务无法使用的状态码
            return Response(data="unkown mistake, details:%s"%(str(exc)),status=status.HTTP_503_SERVICE_UNAVAILABLE)
        return result
    

       下面我们自己造了一个异常,发现了它返回的不是大黄页了:

    class BookAPI(ListAPIView):
        queryset = Book.objects.all()
        serializer_class = BookModelSerializers
        filter_backends = [BookModelSerializers]  # 过滤时放入的是一个序列器,当然会抛出异常
    
    # 返回结果
    "unkown mistake, details:'BookModelSerializers' object has no attribute 'filter_queryset'"
    
  • 相关阅读:
    Maximum Flow Exhaustion of Paths Algorithm
    ubuntu下安装java环境
    visualbox使用(二)
    vxworks一个超级奇怪的错误(parse error before `char')
    February 4th, 2018 Week 6th Sunday
    February 3rd, 2018 Week 5th Saturday
    February 2nd, 2018 Week 5th Friday
    February 1st, 2018 Week 5th Thursday
    January 31st, 2018 Week 05th Wednesday
    January 30th, 2018 Week 05th Tuesday
  • 原文地址:https://www.cnblogs.com/Yunya-Cnblogs/p/13912068.html
Copyright © 2020-2023  润新知