全局异常封装处理
概述:
- 当我们在处理request请求时,前端接受的格式都要统一,无论后端是否出错
- 自内部调用一些函数做一些遗产给处理的时候,还是可能就会出现一些处理不到的错,造成程序不能正常运行,甚至会导致直接将报错返回到前端
- 为了避免这一错误,使我们的后端服务看起来是正常运行的,就算是报错也会返回一个前端一个提示,以及在后端做一些错误信息的日志记录,这里我们引入 全局异常处理
项目在运行的过程中,走到三大认证,视图类的方法只要出现了异常,就会执行一个函数,但是这个函数只能处理drf的异常,这时我们就需要自己重写一个函数,既能处理drf的异常,又能处理django的异常,这样统一返回格式,前端看到的格式也是统一的
使用步骤:
1.utils 文件中新建一个common_exceptions.py
2.写一个函数
项目代码 (下文)
3.配置配置文件,以后只要除了异常就走自己写的函数
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'utils.common_exceptions.exception_handler',
}
4. 以后在写带的时候,不要怕代码报错,程序不会蹦,并且会记录日志,处理成统一的格式
代码:
common_exceptions.py
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.common_logger import logger
# 一般只要走到这个函数,就一定是除了异常,所以需要记录日志
def exception_handler(exc,context):
# 记录日志:IP地址,用户id 访问路径,执行函数,报错信息
request=context.get('request')
view=context.get('view')
ip=request.META.get('REMOTE_ADDR')
user_id=request.user.pk
path=request.get_full_path()
response=drf_exception_handler(exc,context)
if response:
logger.warning('drf出了异常,异常是:%s'%str(exc))
# drf 的异常已经处理了,直接取detail 会有一点小小的问题,(获取出现再解决)
res =Response({'code':1000,'msg':response.data.get('detail','服务器异常,请联系系统管理员')})
else:
# 这是django的异常
logger.error(f'用户{user_id},IP地址{ip},访问 地址{path},执行函数{str(view)},{str(exc)}')
res=Response({'code':1001,'msg':'服务器异常,请联系管理员'})
return res
封装Response
# 本身的drf 是有Response的,但是一般都会规定前端收到的数据格式必须是固定的
{'code':100,'msg':'提示信息',data:{}/[]}
所以我们将Response进行封装,封装过后,code,msg 这些写是可以不用传的,不传的话就使用默认的
使用的步骤:
1.在 utils 下创建common_response.py
2.封装APIResponse
3.导入使用,视图函数的方法,返回时,使用的都是自己的
代码
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self,code=100,msg='成功',status=None,headers=None,**kwargs):
data={'code':code,'msg':msg}
if kwargs:
# 如果有值的话就说明传进来数据,是除了code,msg,status,headers 之外的数据,这些都是要返回给前端的,所以要将它们放在data
data.update(kwargs)
super().__init__(data=data,status=status,headers=headers)
# 配置文件加入
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 总路由中设置
# re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT})
# 访问
http://127.0.0.1:8000/media/icon/default.png
# 以后使用djagno的配置文件都用这个
from django.conf import settings