Django-rest-framework 中的全局异常处理

Posted

技术标签:

【中文标题】Django-rest-framework 中的全局异常处理【英文标题】:Global Exception Handling in Django-rest-framework 【发布时间】:2020-06-11 01:34:42 【问题描述】:

有没有办法在不使用 django rest 框架中的 try-except 块的情况下全局处理所有异常。

我想将 django 抛出的 html 错误页面转换为自定义的 json 对象响应。

我在我的应用中创建了一个 exception.py 文件

def custom_exception_handler(exc, context=None):
    response = exception_handler(exc)


    if isinstance(exc, HttpResponseServerError):  
        custom_response_data =  
            'detail': 'Internal Server Error' # custom exception message
        
        response.data = custom_response_data

    return response

我已经在 settings.py 中配置了。

REST_FRAMEWORK = 
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER':'my_project.my_app.exceptions.custom_exception_handler'

【问题讨论】:

您可以编写自己的中间件来处理异常。但是,这并不能处理其他中间件的异常 AFAIU。 @Thomas hesse 你能举个例子吗? 我确实提供了一个答案,希望它可以帮助你。这确实不是什么新鲜事,但希望对您有所帮助。 【参考方案1】:

由于我遇到了导致我提出这个问题的类似情况,我将按照与 Django Rest Framework 相关的原始问题进行回答,而不仅仅是 Django。

我了解您希望全局处理视图中引发的异常,而无需在每个视图模块上定义 try/except 块。

DRF 允许您定义自己的自定义异常处理机制 (docs)。 这是一个例子:

在 my_custom_except_handler.py:

import logging
from rest_framework.views import exception_handler
from django.http import JsonResponse
from requests import ConnectionError

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first
    response = exception_handler(exc, context)

    # checks if the raised exception is of the type you want to handle
    if isinstance(exc, ConnectionError):
        # defines custom response data
        err_data = 'MSG_HEADER': 'some custom error messaging'

        # logs detail data from the exception being handled
        logging.error(f"Original error detail and callstack: exc")
        # returns a JsonResponse
        return JsonResponse(err_data, safe=False, status=503)

    # returns response as handled normally by the framework
    return response

如文档中所述,定义的响应对象是指:

异常处理函数应该返回一个 Response 对象,或者如果无法处理异常,则返回 None。如果处理程序返回 None 那么异常将被重新引发并且 Django 将返回一个标准的 HTTP 500 'server error' 响应。

换句话说,只有在处理这些异常docs时,'response'才会为None:

APIException 的子类。 Django 的 Http404 异常。 Django 的 PermissionDenied 异常。

如果您的自定义处理程序返回 None,那么框架将“正常”处理异常,返回典型的 500 服务器错误。

最后记得在settings.py中设置需要的key:

REST_FRAMEWORK = 'EXCEPTION_HANDLER': 
    'my_project.my_app.my_custom_except_handler.custom_exception_handler'

希望对你有帮助!

【讨论】:

【参考方案2】:

您的问题的明确答案是

至少我不知道如何在Django中全局做到这一点,而全局包括中间件异常)。

此外,根据@Shubham Kumar 的要求,您需要的钩子是process_exception,并且对于实现检查this SO post 和offical docs on how to activate it。 如 Django 文档中所述:

request 是一个 HttpRequest 对象。 exception 是视图函数引发的 Exception 对象。

当视图引发异常时,Django 调用 process_exception()。 process_exception() 应该返回 None 或 HttpResponse 对象。如果它返回一个 HttpResponse 对象,则将应用模板响应和响应中间件,并将结果响应返回给浏览器。否则,将启动默认异常处理。

同样,中间件在响应阶段以相反的顺序运行,其中包括 process_exception。如果异常中间件返回响应,则根本不会调用该中间件之上的中间件类的 process_exception 方法。

意味着您将只能挂钩到 view 函数并捕获所有这些异常。

【讨论】:

以上是关于Django-rest-framework 中的全局异常处理的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 django-rest-framework 的 authtoken 中的现有令牌?

将 django-rest-framework 中的超链接添加到 ModelViewSet

如何从 django-rest-framework 中的文件列表中过滤图像

如何处理 django-rest-framework 中 url 模式中的外键关系

django-rest-framework 序列化器在多个视图中的不同字段

如何使用 django-rest-framework 中的序列化器将相似数据合并到自定义字段中?