首页 > 其他分享 >07-全局异常捕获

07-全局异常捕获

时间:2024-04-18 16:56:38浏览次数:20  
标签:exception 07 get 捕获 request self 全局 异常 response

全局异常捕获

回顾:APIView的dispatch的时候--》三大认证,视图类的方法中--》出了异常--》被异常捕获--》都会执行一个函数:
	-dispatch的大约 509 行 response = self.handle_exception(exc)
    -只要出了异常,都会执行response = self.handle_exception(exc)
    -handle_exception 源码分析
     def handle_exception(self, exc):
        # 拿到一个函数内存地址--》配置文件中配置了
        # self.settings.EXCEPTION_HANDLER
        # 拿到这个函数:rest_framework.views.exception_handler
        exception_handler = self.get_exception_handler()
        # 执行这个函数,传入俩参数
        response = exception_handler(exc, context)
        # drf的 Response的对象
        return response
   	-rest_framework.views.exception_handler 逻辑分析
    	-判断异常是不是 drf内 exceptions.APIException的异常
        -如果是--》组装了Response返回了
        -如果不是--》返回了None
        -总结:默认drf只处理了自己的异常,django的异常,它没处理,直接前端能看到
        - APIException,是drf种所有异常的基类

如何使用

# 1. 新建一个模块
# 2. 进入到这个模块,导入drf自带的异常处理模块,以及处理逻辑
# 3. 全局配置异常
# 配置全局异常处理
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
}

获取异常字段

异常 错误类型 如何获取
AuthenticationFailed 列表 response[0]
ValidationError 字典 response.get("detail")

自定义异常

class PasswordException(Exception):
    def __init__(self, msg):
        self.msg = msg
import time
from user_agents import parse
from datetime import datetime
from rest_framework.response import Response
from rest_framework.views import exception_handler


# 自定义异常
class PasswordException(Exception):
    def __init__(self, msg):
        self.msg = msg

# 全局异常捕获
def common_exception_handler(exc, context):
    # exc 就是异常 Exception as exc  简写了
    """
    context 是一个字典 可以通过get获取对应的键,进一步去处理
    
    'view': 错误发生在哪一个视图层
    'args': 不定长位置参数
    'kwargs': 不定长关键字参数
    'request': 这个request,就是正常的request,可以通过这个取到客户的IP地址,哪一个用户等,方便记录日志
    """
    
    # 拿到 request 
    request = context.get("request")
    
    # 拿到视图
    view = context.get("view")
    
    # 拿到IP地址
    ip = request.META.get("REMOTE_ADDR")
    
    # 拿到请求方式
    method = request.method
    
    # 拿到请求路径
    path = request.get_full_path()
    
    # 拿到user_agent
    user_agent = request.META.get("HTTP_USER_AGENT")
    
    # 拿到请求浏览器
    ua = parse(user_agent)
    browser = ua.browser.family
    
    # 获取当前时间
    now = datetime.fromtimestamp(int(time.time()))
    
    # 是否登录用户
    user_type = request.user or "匿名用户"
    
    data = f"[用户]:{user_type} [IP]:{ip} [路径]:{path} [方式]:{method} / {browser} [视图]:{view.__class__} [时间]:{now}"
    print(data)
    
    # 返回response说明是drf的异常
    # 返回的是None说明并不是drf的异常
    # 这个response 就是drf的Response对象
    response = exception_handler(exc, context)
    

    if response:
        if isinstance(response.data, list):
            detail = response.data[0]
        elif isinstance(response.data, dict):
            detail = response.data.get("detail", "系统错误,请联系管理员。")
        else:
            detail = "系统错误,请联系管理员"
        return Response({"code": 900, "msg": detail})
    else:
        err = str(exc)
        return Response({"code": 101, "error": err})
# 视图
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError, AuthenticationFailed, APIException
from .exceptions import PasswordException

class UserView(APIView):
    def get(self, request):
        # 9 / 0
        raise PasswordException("密码错误!")

一些建议

# 只要程序走到了我们自定义的异常模块,就说明程序肯定出错了。

# 统一的返回格式。
	- 因为项目上线后,要关闭调试模式,肯定要有一个统一的返回格式。

    # 网络错误,请稍后再试。
    # 系统错误,请联系管理员。
   
# 使用日志去记录,越详细越好,这样可以更快的去排查错误。
	- 日志放在函数内部最上面就可以了,因为只要进入到这里程序肯定出错了。
	- 一般会记录:请求方式,请求地址,客户端IP,用户角色。。。

标签:exception,07,get,捕获,request,self,全局,异常,response
From: https://www.cnblogs.com/ccsvip/p/18143834

相关文章

  • JTCR-包和接口-07
    包包用于划分类的命名空间,使得不同包中的同名类不会冲突。Java使用文件夹存储包,文件夹名和包名一致。Java运行时系统从当前目录中、CLASSPATH变量定义的值、-classpath指定的值这三种途径寻找包。包和成员访问可访问性private无修饰符protectedpublic同一个......
  • 07_QT时间编程之QT时钟
    QT时间编程之QT时钟这节课我们做一个计时器​ qtime:qt的时间类​ qtimer:qt的定时类代码widget.h#ifndefWIDGET_H#defineWIDGET_H#include<QWidget>#include<QTime>#include<QTimer>namespaceUi{classWidget;}classWidget:publicQWidget{Q_OBJE......
  • LeetCode 面试经典150题---007
    ####13.罗马数字转整数罗马数字包含以下七种字符:I,V,X,L,C,D和M。字符数值I1V5X10L50C100D500M1000例如,罗马数字2写做II,即为两个并列的1。12写做X......
  • .Net6-利用IServiceProvider实现全局依赖注入
    需求背景:自定义类库程序中的类文件引用IService接口对象并实现依赖注入。1.修改应用程序Program.cs文件1varbuilder=WebApplication.CreateBuilder(args);2builder.Services.AddProgramService();345varapp=builder.Build();6InternalApp.ServiceProvider=a......
  • 软件体系架构课堂测试07 –逻辑架构设计
    某大银行的一位银行卡办公室的收账经理Liz遇到了一个问题。她每周都收到一份过期未付款的账户名单。这份报告已经从两年前的250个账户增加到现在的1250个账户。为了确定那些严重拖欠债务的账户,Liz需要通读这份报告。严重拖欠债务的账户由几个不同的规则确定,每个规则都要求Liz检查......
  • 软件体系架构课堂测试07 –逻辑架构设计
    班级:   学号:    姓名:某大银行的一位银行卡办公室的收账经理Liz遇到了一个问题。她每周都收到一份过期未付款的账户名单。这份报告已经从两年前的250个账户增加到现在的1250个账户。为了确定那些严重拖欠债务的账户,Liz需要通读这份报告。严重拖欠债务的账户由几个不同......
  • 在Linux中,如何使用tcpdump和tshark进行实时数据包捕获?
    tcpdump和tshark是两个常用的网络分析工具,它们可以捕获网络接口上的数据包,并提供实时的网络流量分析。tcpdump是一个命令行工具,而tshark是Wireshark的命令行版本,提供了更多的功能和更详细的输出。1.使用tcpdump进行实时数据包捕获安装tcpdump:在大多数Linux发行版中,tcpdump已......
  • MyBatis-07-插件原理
    MyBatis插件MyBatis的插件实际上就是Interceptor,拦截器,拦截并重写SQLInterceptor:拦截器InterceptorChain:拦截器链Invocation:封装Object.method(args),反射调用Plugin:JDK代理处理器InvocationHandler,封装一个Interceptor及其拦截的方法,及拦截对象+拦截方......
  • 重载全局的new和delete
    重载全局的new和delete::operatornew::operatornew[]->不可以被声明与同一个namespace之内new会执行三个动作:->之前的代码提到:new本身会开辟内存空间.所以声明方法需要一个size_tsize的参数inlinevoid*operatornew(size_tsize){}::operatordelete::......
  • canvas 捕获视频帧
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width,initial-scale=1.0"/><title>捕获视频帧</title>......