【python之DRF学习】drf全局异常
1.【python入门之相关语言了解】---开发语言与其他2.【python入门之pycharm篇】--如何安装pycharm以及如何安装python解释器3.【python工具指南】pycharm相关快捷键---windows+mac合集4.【python入门之pip换源问题】---pip换源的方式5.【python小记】---PE8规范简述6.【python入门之虚拟环境与系统环境】---虚拟环境的创建方式及使用7.【python入门之常量与变量】---常量与变量小记8.【python入门之基本数据类型的学习】---基本数据之数字类型9.【python入门之基本数据类型的学习】---基本数据类型(列表、字符串)【二】10.【python入门之基本数据类型】---基本数据类型(字典、布尔)【三】11.【python入门之基本数据类型】---基本数据类型(元组、集合)【四】12.【python入门之程序与用户交互】---程序与用户交互13.【python入门之基本运算符】---基本运算符14.【python入门之流程控制语句】---流程控制语句15.【python入门之垃圾回收机制】---python 垃圾回收机制16.【python入门之文件操作】---文件操作17.【python入门之文字符编码】---字符编码18.【python基础之可变和不可变数据类型】---python之栈的介绍19.【python基础之可变和不可变数据类型】--- python之堆的介绍20.【python基础之可变和不可变数据类型】--- python堆栈的相关应用21.【python基础之数据类型的内置方法】--- 数据类型的内置方法22.【python入门之深浅拷贝】---python 深浅拷贝23.【python入门之异常处理】---python 异常处理24.【python基础之函数】--- 函数入门25.【python基础之命名空间与作用域】---命名空间与作用域26.【python基础之函数对象和闭包】 --- 函数对象与闭包27.【python基础之装饰器】---装饰器28.【python基础之迭代器】 --- 迭代器29.【python基础之三元表达式】--- 三元表达式30.【python基础之列表生成式】---列表生成式31.【python基础之生成器】---生成器32.【python基础之模块介绍】---模块33.【python基础之包介绍】---包34.【python扩展之软件开发目录规范】---软件开发目录规范35.【python常用模块之OS模块简介】---OS模块36.【python常用模块之random模块简介】---random模块37.【python常用模块之time时间模块】---时间模块(time/datetime)38.【python常用模块之subprocess模块】---subprocess模块39.【python常用模块之sys模块】---系统模块(sys)40.【Python常用模块之logging模块】---日志输出功能(示例代码)41.【python--- ATM+SHOPPING】42.【python基础之面向对象介绍】--- 面向对象43.【python基础之面向对象的绑定方法与非绑定方法】--面向对象的绑定方法与非绑定方法44.【python网络编程相关】 ----操作系统相关了解45.【python之DRF学习】DRF入门了解46.【python之DRF学习】三大方法之认证47.【python之接口工具】利用docker-compose搭建Yapi
48.【python之DRF学习】drf全局异常
49.【python之DRF学习】 drf之接口文档介绍及使用50.【python之DRF学习】drf之jwt使用title: 【python之DRF学习】drf全局异常
date: 2024-04-18 15:10:30 星期四
updated: 2024-04-18 15:10:33 星期四
description:
Cover: https://www.jb51.net/article/238484.htm
全局异常
一、前言:
当系统报错时,希望系统进行统一报告,比如常见的:系统繁忙,请稍后再试、服务异常,请稍后再试这种报错。
另外,drf不能处理非drf的异常,比如 list = [1, 2, 3] print(l[5]),这种时候会报错,不会抛异常,有时候我们不希望程序报错,也需要使用全局异常处理。
而且这些异常对于前端来说,最好后端即使报错也统一格式返回到前端,以便处理
二、目标
如果没有 DRF,我们只需要在 Django 中加一个中间件就可以解决全局异常的处理问题,但是 DRF 会帮我们处理一些异常并自动返回到客户端,因此我们要协调两者的异常处理策略。
同时我们希望能使用 Django 的 admin 进行一些后台的数据查看和修改,因此最好要保留 admin 的内部异常处理行为。
具体目标:
保留 Django 自带的 admin 的异常处理行为
拦截 DRF 的异常并进行全局异常行为处理
拦截除 DRF 的异常之外的其他 Django 异常并进行全局异常行为处理
三、drf全局异常拦截的解决思路
首先 DRF 的异常都是继承自 APIException 这个类的,并且 DRF 跑出的异常会被 exception_handler 这个异常处理函数拦截(这个函数的位置在 /python3.10/site-packages/rest_framework/views.py中)。
四、源码:
def exception_handler(exc, context):
if isinstance(exc, Http404):
exc = exceptions.NotFound(*(exc.args))
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied(*(exc.args))
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 会处理所有继承自 APIException 的异常类,并且还会额外的处理 Django 内置的 Http404 和 PermissionDenied 异常,并将这些异常的处理结果返回到前台。
如果不再这些处理范围之内,函数会返回 None,这时候会给 Django 抛出一个 500 的服务器错误异常。
DRF 支持单独配置异常处理函数,因此第一步现在 setting 中指定自定义的异常处理函数的位置:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler'
}
五、自定义异常处理程序
第一步,调用 DRF 自己的异常处理函数
第二步,对 DRF 拦截的异常进行处理
第三步,将其他异常抛给 Django 处理
from rest_framework.views import exception_handler
from rest_framework.response import Response
class PasswordException(Exception):
def __init__(self,msg):
self.msg=msg
def common_exception_handler(exc, context):
# 日志记录放这里即可:请求方式,请求的地址,客户端ip,用户id
request=context.get('request')
view=context.get('view') # 哪个视图类出的错
user_id=request.user.pk or '匿名用户'
print(f'请求方式是:{request.method},请求地址是:{request.get_full_path()},客户端ip:{request.META.get("REMOTE_ADDR")},用户id:{user_id}')
print(type(exc))
# 1 返回 Response:说明是drf的异常 2 返回None:说明不是drf的异常
response = exception_handler(exc, context)
if response:
if isinstance(response.data,dict):
err=response.data.get('detail','系统错误,请联系系统管理员')
elif isinstance(response.data,list):
err = response.data[0]
else:
err ='系统错误,请联系系统管理员'
response = Response({'code': 998, 'msg': f'【drf的异常】:{err}'})
pass
else:
if isinstance(exc,ZeroDivisionError):
response = Response({'code': 991, 'msg': '不能除以0'})
elif isinstance(exc,Exception):
response = Response({'code': 992, 'msg': 'Exception错误'})
else:
# 表明是 非drf的异常
err=str(exc)
response = Response({'code': 999, 'msg': f'【django的异常】:{err}'})
return response
# 无论后端什么情况,前端收到的都是统一的格式
'''
正常响应:{code:100,msg:成功}
不正常响应:{code:101,msg:登录失败}
出了错:{code:999,msg:错误信息} {code:998,msg:错误信息}
六、django异常处理方案
从上一步的结果我们知道,DRF 处理不了的异常我们抛给了 Django,而 Django 支持通过定义中间件进行全局异常处理,因此接下来我们只需要定一个 Django 全局异常处理的中间件,并将中间件配置到 setting 文件中的 MIDDLEWARE 数组即可。
try:
from django.utils.deprecation import MiddlewareMixin # Django 1.10.x
except ImportError:
MiddlewareMixin = object # Django 1.4.x - Django 1.9.x
class ExceptionGlobeMiddleware(MiddlewareMixin):
"""
Below is the global exception handler of django
"""
def process_exception(self, request, exception):
# 直接抛出 django admin 的异常
if str(request.path).startswith('/admin/'):
return None
# 捕获其他异常,直接返回 500
ex_data = {
"msg": "Sorry, we make a mistake (* ̄︶ ̄)!",
"error_code": 1000,
"request": request.path
}
return JsonResponse(data=ex_data, status=500)
值得注意的是,我们可以在中间件的处理函数中拿到 request
对象,因此,我们可以通过这个对象拿到用户请求的 url,这样,我们通过判断 url 就可以得到那些请求是来自 Django 自带的 admin 的。
参考代码
# 直接抛出 django admin 的异常
if str(request.path).startswith('/admin/'):
return None
七、drf定义的异常部分异常
APIException 所有异常的父类
ParseError 解析错误
AuthenticationFailed 认证失败
NotAuthenticated 尚未认证
PermissionDenied 权限决绝
NotFound 未找到
MethodNotAllowed 请求方式不支持
NotAcceptable 要获取的数据格式不支持
Throttled 超过限流次数
ValidationError 校验失败
通过上述的配置,我们可以对完成 Django 结合 DRF 的全局异常处理,并且保留了 Django 自带 admin 的异常处理策略。
本文来自博客园,作者:Unfool,转载请注明原文链接:https://www.cnblogs.com/queryH/p/18143571
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!