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.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上 ...
随机推荐
- TCP首部的TimeStamp时间戳选项 转载
TCP应该是以太网协议族中被应用最为广泛的协议之中的一个,这里就聊一聊TCP协议中的TimeStamp选项.这个选项是由RFC 1323引入的,该C建议提交于1992年.到今天已经足足有20个年头.只 ...
- vue-导入element-ui
安装 npm install element-ui -S 项目中导入 修改main.js import ElementUI from 'element-ui'; import 'element-ui/ ...
- root of context hierarchy
Spring Boot项目,运行不明中断.日志如下: 2018-11-03 11:03:43.358 INFO [Thread-2][AbstractApplicationContext.java:9 ...
- 哈希表(hash table)基础概念
哈希是什么 引入:我们在学习数组的时候,使用数组元素的下标值即可访问到该元素,所花费的时间是O(1),与数组元素的个数n没有关系,这就是哈希方法的核心思想. 哈希方法:以关键值K为自变量,通过一定的函 ...
- Java微信公众号开发梳理
Java微信公众号开发梳理 现在微信公众平台的开发已经越来越普遍,这次开发需要用到微信公众平台.因此做一个简单的记录,也算是给那些没踩过坑的童鞋一些启示吧.我将分几块来简单的描述一下,之后会做详细的说 ...
- centos7的网络配置参考
<鸟哥的Linux私房菜>中的相关介绍和配置:http://linux.vbird.org/linux_basic/0610hardware.php 修改链接(connection)的名字 ...
- git常用操作方法
在实际开发,测试中,会使用git作为版本控制工具来完成团队协作.因此,对基本的git操作指令进行总结是十分有必要的,本文对一些术语或者理论基础,不重新码字,可以参考廖雪峰老师的博文,本文只对命令做归纳 ...
- Oracle中shrink space命令
shrink_clause: http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_3001.htm#i2192484 ...
- 21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
21.Merge Two Sorted Lists 初始化一个指针作为开头,然后返回这个指针的next class Solution { public: ListNode* mergeTwoLists ...
- SqlServer视图介绍以及创建方式
1.,视图的介绍: (ps:学sqlServer视图是在面试问到之后学的,答不上来太low了,然后就去各种搜索操作对视图也有了自己的理解) 其实视图就是一张表,是一张表中或者多张表中经过某种筛选后显示 ...