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.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上 ...
随机推荐
- speech-to-text-wavenet
docker pull buriburisuri/speech-to-text-wavenet docker run -it buriburisuri/speech-to-text-wavenet p ...
- 下板不动, 上板匀速平板间流动(Crank-Nicolson格式)【转载】
摘自<FLUENT流体工程仿真计算实例与分析>,程序略有修改 两个间距为1cm水平平板,如下图所示: 上板匀速平板间流动(Crank-Nicolson格式)[转载]"> 充 ...
- 关于mysql数据库远程访问
mysql数据库安装默认为只能本地访问,若需远程连接需根据不同的操作系统做一些操作 Windows: 新装的mysql本地无法登录,显示为1045错误 mysql#1045(1045Access de ...
- HearthBuddy Ai 调试实战2 在使用海巨人的时候,少召唤了一个图腾(费用是对的)
问题 游戏面板 8是青玉之爪13是海巨人17是恐狼前锋 64是萨满 66是圣骑士63,99,46,是微型木乃伊[其中99和46都是2血3攻,63是2血1攻]57是鱼人木乃伊 微型木乃伊 "L ...
- flutter中的异步机制 Future
饿补一下Flutter中Http请求的异步操作. Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作.延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到 ...
- C语言包含头文件时用引号和尖括号的区别
用尖括号 #include <>: 一般用于包含标准的库头文件,编译器会去系统配置的库环境变量和者用户配置的路径去搜索,而不会在项目的当前目录去查找 用双引号 #include &q ...
- Spring Boot确保Web应用安全(登陆认证)
Spring Boot官方提供了一个登陆认证的清晰易懂的 例子 , 我们在次以此例展开演示Spring Boot是如何实现登陆认证的. 首先我们去 https://start.spring.io/ 下 ...
- Ubuntu 16.04安装MySQL设置远程访问出现问题的完美解决方案(error:10061)
一.安装mysql 安装mysql过程中,需要设置mysql的root账号的密码,不要忽略了. sudo apt-get install mysql-server apt isntall mysql- ...
- App唤起微信小程序和回调
在同一开放平台账号下的移动应用及小程序无需关联即可完成跳转,非同一开放平台账号下的小程序需与移动应用(APP)成功关联后才支持跳转. 可在“管理中心-移动应用-应用详情-关联小程序信息”,为通过审核的 ...
- json转换成dart类 JSON to Dart
json_to_dart的使用 如果我们得到一个特别复杂的JSON,有时候会无从下手开始写Model,这时候就可以使用一些辅助工具.我认为json_to_dart是比较好用的一个.它可以直接把json ...