Django-djangorestframework-异常模块-源码及自定义异常
异常模块
为什么要自定义异常模块
- 所有经过 drf APIView 视图类产生的异常,都可以提供异常处理方案(没有继承 APIVIew 的视图函数不会触发)
- drf 默认提供了异常处理方案(
rest_framework.views.exception_handler),但是处理范围有限 - drf 提供的处理方案有两种
- 有对应处理,处理了返回异常信息
- 没有对应处理(处理范围之外),返回 None,直接服务器抛异常给前台
- 自定义异常的目的就是解决 drf 没有处理的异常,让前台得到合理的异常信息返回,后台记录异常具体的信息(方便事后排查)
如果程序报错了,我们应该尽可能的隐藏后台的错误,返回给前台就是服务器错误(你返回给用户用户也看不懂呀,如果是黑客,那可能还会利用报错袭击服务器)
常见的几种异常情况
- 像这种就比较可怕了,甚至连代码文件位置都暴露了

- drf 异常处理模块处理后的异常

- drf 异常处理模块处理后的异常

- 异常信息经汉化后的报错(django 配置了国际化后)

异常模块源码分析
视图函数执行出现异常会自动触发 handle_exception 函数
每个请求都会经历这么一个过程,走到 dispatch 函数
E:/python3-6-4/Lib/site-packages/rest_framework/views.py 源码
# ...
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
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) # 三大认证
# Get the appropriate handler method
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) # 上面 try 代码体内代码出现异常会自动触发这个函数 <---------
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
handle_exception 源码
def handle_exception(self, exc):
"""
Handle any exception that occurs, by returning an appropriate response,
or re-raising the error.
"""
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()
# 异常处理的结果
# 自定义异常就是提供 exception_handler 异常处理函数,处理的目的就是让 response 一定有值
response = exception_handler(exc, context)
if response is None:
self.raise_uncaught_exception(exc) # 乱七八糟的异常就是这里抛出来的
response.exception = True
return response
如何获取异常类?
get_exception_handler_context 源码,异常处理类是从配置中拿来的
def get_exception_handler(self):
"""
Returns the exception handler that this view uses.
"""
return self.settings.EXCEPTION_HANDLER
# API policy implementation methods
E:/python3-6-4/Lib/site-packages/rest_framework/settings.py
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
获取到异常类如何处理?
返回 None 就会触发
handle_exception源码中的报错
E:/python3-6-4/Lib/site-packages/rest_framework/views.py drf 自带的异常处理类
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.
"""
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)
return None # 其他的异常 drf 未处理,返回 None,让其报错(最上面的那种报错)
自定义 drf 异常处理
自定义异常处理模块就是提供
exception_handler异常处理函数,处理的目的就是让 response 一定有值显而易见,我们只需要自定义一个异常处理方法,先调用系统自带的那个异常处理函数,然后把 drf 自带那个异常函数没有处理的情况处理了就好了(处理后返回一个 Response 对象即可,一定要有返回值,否则没多大意义)
歩鄹
- 先将异常处理交给 rest_framework.views 的 exception_handler 去处理
- 判断处理的结果(返回值)response,有值代表 drf 已经处理了,None 需要自己处理
- 可以根据 exc 的类型再细化处理
if isinstance(exc, '哪个异常'): # 再怎么处理
- 可以根据 exc 的类型再细化处理
api/exception.py
记得自己把报错信息记到日志里面去
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.views import Response
from rest_framework import status
def exception_handler(exc, context):
# drf的exception_handler做基础处理
response = drf_exception_handler(exc, context)
# 为空,说明 drf 中没有对应的处理,咱们自定义二次处理
if response is None:
# print(exc)
# # Book matching query does not exist
# print(context)
# # {'view': <api.views.Book object at 0x000001FED29DD860>}, 'args': (), 'kwargs': {'pk': '4'}, 'request': <rest_framework.request.Request object at 0x000001FED2CD9EF0>
# 这里后期应该写成系统日志才对(这只是演示的伪代码)
print('%s - %s - %s' % (context['view'], context['request'].method, exc))
# <api.views.Book object at 0x000002505A2A9A90> - GET - Book matching query does not exits.
return Response({
'detail': '服务器错误'
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True)
return response
配置上,让其生效
dg_proj/settings.py
# 1.确保已注册 drf
INSTALLED_APPS = [
# ...
'api.apps.ApiConfig',
'rest_framework', # 注册 drf
]
# 2.在 restframework 的配置中配置该自定义异常模块
REST_FRAMEWORK = {
# ...
'EXCEPTION_HANDLER': 'api.exception.exception_handler', # 全局配置异常模块
}
Django-djangorestframework-异常模块-源码及自定义异常的更多相关文章
- Django(50)drf异常模块源码分析
异常模块源码入口 APIView类中dispatch方法中的:response = self.handle_exception(exc) 源码分析 我们点击handle_exception跳转,查看该 ...
- Django(49)drf解析模块源码分析
前言 上一篇分析了请求模块的源码,如下: def initialize_request(self, request, *args, **kwargs): """ Retu ...
- Django(51)drf渲染模块源码分析
前言 渲染模块的原理和解析模块是一样,drf默认的渲染有2种方式,一种是json格式,另一种是模板方式. 渲染模块源码入口 入口:APIView类中dispatch方法中的:self.response ...
- 【 js 模块加载 】深入学习模块化加载(node.js 模块源码)
一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须按照一定的格式编写.AMD,CMD,CommonJS 是目前最常用的三种模块化书写规范. 1.AMD(Asy ...
- Django-restframework 之权限源码分析
Django-restframework 之权限源码分析 一 前言 上篇博客分析了 restframework 框架的认证组件的执行了流程并自定义了认证类.这篇博客分析 restframework 的 ...
- 【 js 模块加载 】【源码学习】深入学习模块化加载(node.js 模块源码)
文章提纲: 第一部分:介绍模块规范及之间区别 第二部分:以 node.js 实现模块化规范 源码,深入学习. 一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须 ...
- 【nodejs原理&源码赏析(4)】深度剖析cluster模块源码与node.js多进程(上)
[摘要] 集群管理模块cluster浅析 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 概述 cluster模块是node.js中用于实现和管理 ...
- 【nodejs原理&源码赏析(4)】深度剖析cluster模块源码与node.js多进程(上)
目录 一. 概述 二. 线程与进程 三. cluster模块源码解析 3.1 起步 3.2 入口 3.3 主进程模块master.js 3.4 子进程模块child.js 四. 小结 示例代码托管在: ...
- 分布式事务中间件 Fescar—RM 模块源码解读
前言 在SOA.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上 ...
随机推荐
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- ASP.NET的MVC设计模式
当开发者听到“设计模式”这个词时,他们通常联想到两个场景.一组开发者正在讨论许多创造性意见,正在开会,但是却没有进行编码.另外一组人能制定出正确的计划,保证系统能够开发成功,代码可以重用. 而现实一般 ...
- vue js select下拉框
<template> <ul id="select"> <li> <div class="select-head"&g ...
- qDebug() << currentThreadId();
从 dbzhang800 的博客中转载两篇关于事件循环的文章,放在一起,写作备忘. 再次提到的一点是:事件循环和线程没有必然关系. QThread 的 run() 方法始终是在一个单独线程执行的,但只 ...
- MapReduce On Yarn的配置详解和日常维护
MapReduce On Yarn的配置详解和日常维护 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MapReduce运维概述 MapReduce on YARN的运维主要是 ...
- leetcode 79. Word Search 、212. Word Search II
https://www.cnblogs.com/grandyang/p/4332313.html 在一个矩阵中能不能找到string的一条路径 这个题使用的是dfs.但这个题与number of is ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_3.RabbitMQ研究-工作原理
Producer生产者 Consumer:消费者 组成部分说明如下: Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue. Exchange:消息队列交换机,按一定的规则 ...
- PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)
1018 Public Bike Management (30 分) There is a public bike service in Hangzhou City which provides ...
- swift 第八课 CollectView的 添加 footerView 、headerView
collectView 也是 iOS 很常用的瀑布流展示控件了,虽然使用过很多次,一直没有系统的总结过,尤其是在添加header 和footer view 的时候,很常见,写起来总觉得不是很流畅,这里 ...
- jmeter性能测试的指标分析和定义
通常情况下,性能测试关注被测对象的时间与资源利用特性及稳定性.时间特性,即被测对象实现业务交易过程中所需的处理时间,从用户角度来说,越短越好.资源利用特性,即被测对象的系统资源占用情况,一般web系统 ...