• Django(50)drf异常模块源码分析


    异常模块源码入口

    APIView类中dispatch方法中的:response = self.handle_exception(exc)
     

    源码分析

    我们点击handle_exception跳转,查看该方法源码

    def handle_exception(self, exc):
        """
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        """
        # 判断异常类型是否是没有认证的类型,最后返回403状态码
        if isinstance(exc, (exceptions.NotAuthenticated,
                            exceptions.AuthenticationFailed)):
            # WWW-Authenticate header for 401 responses, else coerce to 403
            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)
        
        # 如果响应为内容为空,则抛出异常
        if response is None:
            self.raise_uncaught_exception(exc)
    
        response.exception = True
        return response
    

    以上源码最为关键的一句就在于exception_handler = self.get_exception_handler(),我们可以点击查看该方法源码

    def get_exception_handler(self):
        """
        Returns the exception handler that this view uses.
        """
        return self.settings.EXCEPTION_HANDLER
    

    该方法返回该视图的异常处理方法,从返回的内容,我们可以知道,该方法在settings文件中有个默认值,进入settings可查看到

    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
    

    异常处理的默认方法就是views下的exception_handler方法,我们再进入查看该方法源码

    def exception_handler(exc, context):
        """
        Returns the response that should be used for any given exception.
    
        By default we handle the REST framework `APIException`, and also
        Django's built-in `Http404` and `PermissionDenied` exceptions.
    
        Any unhandled exceptions may return `None`, which will cause a 500 error
        to be raised.
        """
        # 判断异常是否是404
        if isinstance(exc, Http404):
            exc = exceptions.NotFound()
    
        # 判断异常是否是没有权限
        elif isinstance(exc, PermissionDenied):
            exc = exceptions.PermissionDenied()
    
        # 判断异常是否是drf的基类异常,该异常提供了状态码和异常字段detail
        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
            
            # 判断detail是否是list类型或dict类型
            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)
    
        return None
    

    从上述代码我们可以知道,当response返回为None时,是不会返回异常信息,而是直接抛出异常,所以我们可以自定义异常类
     

    自定义异常

    在我们的app目录下,创建utils包,并创建exceptions文件,并写入如下源码:

    from rest_framework.response import Response
    from rest_framework.views import exception_handler as drf_exception_handler
    
    
    def exception_handler(exc, context):
        response = drf_exception_handler(exc, context)
        if response is None:
            print(f"{context['view']} - {context['request'].method} - {exc}")
            return Response(status=500, data="服务器错误")
        return response
    

    最后我们将默认异常信息配置改为自己的配置即可,在settings文件中写入如下配置

    REST_FRAMEWORK = {
        'EXCEPTION_HANDLER': 'drf_app.utils.exceptions.exception_handler',
    }
    

    以后碰到response响应为None的时候,我们就会抛出服务器错误的异常信息
     

    总结

    为什么要自定义异常模块?

    1. 所有经过drfAPIView视图类产生的异常,都可以提供异常处理方案
    2. drf默认提供了异常处理方案(rest_framework.views.exception_handler),但是处理范围有限
    3. drf提供的处理方案两种,处理了返回异常现象,没处理返回None(后续就是服务器抛异常给前台)
    4. 自定义异常的目的就是解决drf没有处理的异常,让前台得到合理的异常信息返回,后台记录异常具体信息
  • 相关阅读:
    最小生成树(Prime算法)
    Spiral Matrix
    大于非负整数N的第一个回文数 Symmetric Number
    毁灭者问题
    查看Centos7虚拟机的IP
    创建Redis集群时遇到问题(二)
    EditPlus通过FTP远程连接Linux
    Redis集群搭建
    创建Redis集群时遇到问题(一)
    安装redis报错“系统 Ruby 版本过低”的解决办法
  • 原文地址:https://www.cnblogs.com/jiakecong/p/14862110.html
Copyright © 2020-2023  润新知