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,**kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:  # 异常捕获开始
            self.initial(request,**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,**kwargs)
        except Exception as exc:
            response = self.handle_exception(exc)  # 如果发生异常,则执行这里

        self.response = self.finalize_response(request,response,**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'"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有需要的朋友自行下载。
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。ViewSet在开发接口中不经常用。
一、Django介绍Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django 是一个开放源代码的 Web 应用框架,由 Python 写成。Django 遵守 BSD 版权,初次发布于 2005 年 7 月, 并于 2008 年 9 月发布了第一个正式版本 1.0 。Django学习线路Django 采用了 MVT 的软件设计模式,即模型(Model),视图(View)和模板(Template)。这个MVT模式并
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小白快速搭建django项目,并对可能出现的报错进行了分析
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的MysqlDB连接,Python3 支持支持pymysql 所有需要在app里面的__init__加上下面配置:
url: re_path('authors/$', views.AuthorView.as_view()), re_path('book/(?P\d+)/$', vie
前提 关于html寻找路线: template 如果在各个APP中存在, Django 会优先找全局template 文件下的html文件,如果全局下的template文件没有相关的html Djan
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
from bs4 import BeautifulSoup#kindeditordef kindeditor(request): s = ''' <li><s
view.py 配置 html 配置
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault('content_type&#
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
return HttpResponse("OK") 返回一个字符串 return redirect("/index/") 返回URL return render
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault('content_type&#
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况
自动发送 > 依赖jQuery文件 实例-->GET请求: 手动发送 > 依赖浏览器XML对象(也叫原生ajax) Ajax主要就是使用 【XmlHttpRequest】对象来完成请
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
return HttpResponse("OK") 返回一个字符串 return redirect("/index/") 返回URL return render