Django后端相应类设计

news2025/1/12 0:42:25

通用的ApiResponse类:用于生成统一的 API 响应格式。每个响应都包含以下字段(每个接口最终的返回数据格式):

  • status_code:HTTP 状态码(如 200、400、500 等)
  • message:响应的描述信息(如 “Success”、“Resource not found” 等)
  • data:返回的数据(如果有)
  • trace_id:请求的唯一标识符

trace_id的作用:

  • 唯一标识请求:每个请求都有一个唯一的 TraceID
  • 日志关联:在日志中记录 TraceID,便于快速定位问题

ApiResponse类核心方法:
1、success 200 请求成功
2、created 201 创建资源成功
3、bad_request 400 后端必要的参数与前端传递的参数不一致。例如缺少必填字段、参数类型错误(如期望是数字,但传入了字符串)
4、unauthorized 401 用户鉴权问题,例如token失效,没有提供有效的身份验证信息
5、forbidden 403 禁止访问,客户端没有权限访问资源
6、not_found 404 请求的资源不存在,URL 路径错误。访问的 API 路径错误等
7、validation_error 422 请求格式正确,但语义错误,服务器无法处理。例如:邮箱格式不正确、密码长度不符合要求。请求数据不符合业务规则
8、conflict 409 资源冲突,请求与当前资源状态冲突.例如:创建资源时,资源已存在。用户重名等
9、internal_server_error 500 服务器内部错误,无法完成请求。例如:数据库连接失败,代码逻辑错误导致的异常
10、service_unavailable 503 服务不可用,服务器暂时无法处理请求。例如:服务器正在维护,第三方 API 服务失效等

中间件middlewares作用:
Django 中的一个全局异常处理器,它的主要作用是捕获 Django 视图函数或中间件中抛出的异常,并根据异常类型返回统一的错误响应
同时,它还支持 TraceID 的生成和传递,便于追踪请求的完整调用链路。

1、中间件会捕获所有未处理的异常(包括 Django 内置异常和自定义异常),根据异常类型,生成对应的错误响应
2、最终会使用 ApiResponse 类生成统一的错误响应格式(status_code、message、data、trace_id)
3、从请求头中获取 TraceID,如果未提供则自动生成一个新的。将异常信息和 TraceID 记录到日志中,便于后续排查问题

整体说明:
1、使用可参考test.py,接口最终返回的数据,需要经过结果处理类ApiResponse,统一进行处理
2、在视图(接口)中,尽量使用ApiResponse类的10个核心方法,捕捉可能发生的异常
3、中间件会捕捉,代码未处理的异常,最终规范为status_code、message、data、trace_id四个字段(中间键与ApiResponse结果处理类是互补的作用)
4、后端返回的数据,最终会规范为status_code、message、data、trace_id四个字段

class StatusCode:
    # 成功状态码
    SUCCESS = 200  # 请求成功
    CREATED = 201  # 创建资源成功

    # 客户端错误(4XX)
    BAD_REQUEST = 400  # 参数错误
    UNAUTHORIZED = 401  # 未授权
    FORBIDDEN = 403  # 禁止访问
    NOT_FOUND = 404  # 资源未找到
    VALIDATION_ERROR = 422  # 参数校验错误
    CONFLICT = 409  # 资源冲突

    # 服务端错误(5XX)
    SERVER_ERROR = 500  # 服务器内部错误
    SERVICE_UNAVAILABLE = 503  # 服务不可用


class ApiException(Exception):
    """
    基础异常类,所有自定义异常继承此类。
    """

    def __init__(self, message, status_code):
        super().__init__(message)
        self.status_code = status_code
        self.message = message


# 客户端错误(4XX)
class BadRequestException(ApiException):
    """400 Bad Request"""

    def __init__(self, message="Bad request"):
        super().__init__(message, status_code=StatusCode.BAD_REQUEST)


class UnauthorizedException(ApiException):
    """401 Unauthorized"""

    def __init__(self, message="Unauthorized"):
        super().__init__(message, status_code=StatusCode.UNAUTHORIZED)


class ForbiddenException(ApiException):
    """403 Forbidden"""

    def __init__(self, message="Forbidden"):
        super().__init__(message, status_code=StatusCode.FORBIDDEN)


class NotFoundException(ApiException):
    """404 Not Found"""

    def __init__(self, message="Resource not found"):
        super().__init__(message, status_code=StatusCode.NOT_FOUND)


class ValidationErrorException(ApiException):
    """422 Validation Error"""

    def __init__(self, message="Validation error"):
        super().__init__(message, status_code=StatusCode.VALIDATION_ERROR)


class ConflictException(ApiException):
    """409 Conflict"""

    def __init__(self, message="Conflict"):
        super().__init__(message, status_code=StatusCode.CONFLICT)


# 服务端错误(5XX)
class InternalServerErrorException(ApiException):
    """500 Internal Server Error"""

    def __init__(self, message="Internal server error"):
        super().__init__(message, status_code=StatusCode.SERVER_ERROR)


class ServiceUnavailableException(ApiException):
    """503 Service Unavailable"""

    def __init__(self, message="Service unavailable"):
        super().__init__(message, status_code=StatusCode.SERVICE_UNAVAILABLE)

以上为自定义的异常处理类,下述为自定义的中间件

import logging
import uuid

from django.core.exceptions import PermissionDenied
from django.http import Http404

from 响应类设计.exceptions import *
from 响应类设计.response_handler import ApiResponse

logger = logging.getLogger(__name__)


class ExceptionHandlingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 从请求头中获取 Trace ID,如果没有则生成一个新的
        trace_id = request.headers.get('X-Trace-ID', str(uuid.uuid4()))
        request.trace_id = trace_id  # 将 Trace ID 绑定到请求对象

        try:
            response = self.get_response(request)
            return response
        except Exception as e:
            return self.handle_exception(e, trace_id)

    def handle_exception(self, exception, trace_id):
        # 记录异常日志,包含 Trace ID
        logger.error(f"Trace ID: {trace_id}, Error: {str(exception)}", exc_info=True)

        if isinstance(exception, Http404):
            return ApiResponse.not_found(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, PermissionDenied):
            return ApiResponse.forbidden(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, BadRequestException):
            return ApiResponse.bad_request(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, UnauthorizedException):
            return ApiResponse.unauthorized(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, ForbiddenException):
            return ApiResponse.forbidden(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, NotFoundException):
            return ApiResponse.not_found(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, ValidationErrorException):
            return ApiResponse.validation_error(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, ConflictException):
            return ApiResponse.conflict(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, InternalServerErrorException):
            return ApiResponse.internal_server_error(message=str(exception), trace_id=trace_id)
        elif isinstance(exception, ServiceUnavailableException):
            return ApiResponse.service_unavailable(message=str(exception), trace_id=trace_id)
        else:
            # 未知异常,返回 500 状态码
            return ApiResponse.internal_server_error(message="An unexpected error occurred.", trace_id=trace_id)
from django.http import JsonResponse
import uuid

from 响应类设计.exceptions import StatusCode


class ApiResponse:
    """
    通用的 API 响应类,支持 Trace ID 和多种状态码。
    """

    def __init__(self, status_code, message, data=None, trace_id=None):
        self.status_code = status_code
        self.message = message
        self.data = data
        self.trace_id = trace_id or str(uuid.uuid4())  # 生成唯一的 Trace ID

    def to_dict(self):
        """
        将响应数据转换为字典格式。
        """
        return {
            'status_code': self.status_code,
            'message': self.message,
            'data': self.data if self.data is not None else {},
            'trace_id': self.trace_id  # 包含 Trace ID
        }

    def to_json_response(self):
        """
        将响应数据转换为 Django 的 JsonResponse。
        """
        return JsonResponse(self.to_dict(), status=self.status_code)

    # 成功响应
    @staticmethod
    def success(message="Success", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.SUCCESS, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    # 资源创建成功
    @staticmethod
    def created(message="Resource created", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.CREATED, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    # 客户端错误
    @staticmethod
    def bad_request(message="Bad request", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.BAD_REQUEST, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def unauthorized(message="Unauthorized", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.UNAUTHORIZED, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def forbidden(message="Forbidden", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.FORBIDDEN, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def not_found(message="Resource not found", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.NOT_FOUND, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def validation_error(message="Validation error", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.VALIDATION_ERROR, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def conflict(message="Conflict", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.CONFLICT, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    # 服务端错误
    @staticmethod
    def internal_server_error(message="Internal server error", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.SERVER_ERROR, message=message, data=data,
                           trace_id=trace_id).to_json_response()

    @staticmethod
    def service_unavailable(message="Service unavailable", data=None, trace_id=None):
        return ApiResponse(status_code=StatusCode.SERVICE_UNAVAILABLE, message=message, data=data,
                           trace_id=trace_id).to_json_response()

上述为定义的结果处理类,一下为使用说明案例

from django.views import View
import uuid
from .exceptions import BadRequestException, NotFoundException
from .response_handler import ApiResponse


def get_trace_id(request):
    """
    从请求头中获取 Trace ID,如果没有则生成一个新的。
    """
    return request.headers.get('X-Trace-ID', str(uuid.uuid4()))


class MyView(View):
    def get(self, request, *args, **kwargs):
        """
        示例 GET 请求视图,展示如何使用 Trace ID。
        """
        # 获取或生成 Trace ID
        trace_id = get_trace_id(request)

        # 示例:从 URL 参数中获取资源 ID
        resource_id = kwargs.get('resource_id')
        if not resource_id:
            # 如果资源 ID 不存在,返回 400 错误
            raise BadRequestException("Resource ID is required.")

        # 模拟资源查找
        resource = self.get_resource(resource_id)
        if not resource:
            # 如果资源未找到,返回 404 错误
            raise NotFoundException("Resource not found.")

        # 返回成功响应
        return ApiResponse.success(
            message="Resource retrieved successfully",
            data=resource,
            trace_id=trace_id
        )

    def post(self, request, *args, **kwargs):
        """
        示例 POST 请求视图,展示如何使用 Trace ID。
        """
        # 获取或生成 Trace ID
        trace_id = get_trace_id(request)

        # 示例:从请求体中获取数据
        data = request.POST
        if not data.get('name'):
            # 如果名称字段不存在,返回 400 错误
            raise BadRequestException("Name is required.")

        # 模拟创建资源
        resource = self.create_resource(data)
        return ApiResponse.created(
            message="Resource created successfully",
            data=resource,
            trace_id=trace_id
        )

    def get_resource(self, resource_id):
        """
        模拟资源查找逻辑。
        """
        # 这里可以替换为实际的数据库查询逻辑
        if resource_id == "123":
            return {"id": "123", "name": "Example Resource"}
        return None

    def create_resource(self, data):
        """
        模拟资源创建逻辑。
        """
        # 这里可以替换为实际的数据库插入逻辑
        return {"id": str(uuid.uuid4()), "name": data.get('name')}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2275203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

风水算命系统架构与功能分析

系统架构 服务端:Java(最低JDK1.8,支持JDK11以及JDK17)数据库:MySQL数据库(标配5.7版本,支持MySQL8)ORM框架:Mybatis(集成通用tk-mapper,支持myb…

551 灌溉

常规解法&#xff1a; #include<bits/stdc.h> using namespace std; int n,m,k,t; const int N105; bool a[N][N],b[N][N]; int cnt; //设置滚动数组来存贮当前和下一状态的条件 //处理传播扩散问题非常有效int main() {cin>>n>>m>>t;for(int i1;i&l…

HDFS编程 - 使用HDFS Java API进行文件操作

文章目录 前言一、创建hdfs-demo项目1. 在idea上创建maven项目2. 导入hadoop相关依赖 二、常用 HDFS Java API1. 简介2. 获取文件系统实例3. 创建目录4. 创建文件4.1 创建文件并写入数据4.2 创建新空白文件 5. 查看文件内容6. 查看目录下的文件或目录信息6.1 查看指定目录下的文…

Java面试题~~

深拷贝和浅拷贝区别了解吗?什么是引用拷贝? 关于深拷贝和浅拷贝区别&#xff0c;我这里先给结论&#xff1a; 浅拷贝&#xff1a;浅拷贝会在堆上创建一个新的对象&#xff08;区别于引用拷贝的一点&#xff09;&#xff0c;不过&#xff0c;如果原对象内部的属性是引用类型的…

el-table 自定义表头颜色

第一种方法&#xff1a;计算属性 <template><div><el-table:data"formData.detail"border stripehighlight-current-row:cell-style"{ text-align: center }":header-cell-style"headerCellStyle"><el-table-column fixed…

MySQL笔记大总结20250108

Day2 1.where (1)关系运算符 select * from info where id>1; select * from info where id1; select * from info where id>1; select * from info where id!1;(2)逻辑运算符 select * from info where name"吴佩奇" and age19; select * from info wh…

精选2款.NET开源的博客系统

前言 博客系统是一个便于用户创建、管理和分享博客内容的在线平台&#xff0c;今天大姚给大家分享2款.NET开源的博客系统。 StarBlog StarBlog是一个支持Markdown导入的开源博客系统&#xff0c;后端基于最新的.Net6和Asp.Net Core框架&#xff0c;遵循RESTFul接口规范&…

SEO内容优化:如何通过用户需求赢得搜索引擎青睐?

在谷歌SEO优化中&#xff0c;内容一直是最重要的因素之一。但要想让内容真正发挥作用&#xff0c;关键在于满足用户需求&#xff0c;而不是简单地堆砌关键词。谷歌的算法越来越智能化&#xff0c;更注重用户体验和内容的实用性。 了解目标用户的需求。通过工具如Google Trends…

Spring——自动装配

假设一个场景&#xff1a; 一个人&#xff08;Person&#xff09;有一条狗&#xff08;Dog&#xff09;和一只猫(Cat)&#xff0c;狗和猫都会叫&#xff0c;狗叫是“汪汪”&#xff0c;猫叫是“喵喵”&#xff0c;同时人还有一个自己的名字。 将上述场景 抽象出三个实体类&…

计算机网络(三)——局域网和广域网

一、局域网 特点&#xff1a;覆盖较小的地理范围&#xff1b;具有较低的时延和误码率&#xff1b;使用双绞线、同轴电缆、光纤传输&#xff0c;传输效率高&#xff1b;局域网内各节点之间采用以帧为单位的数据传输&#xff1b;支持单播、广播和多播&#xff08;单播指点对点通信…

错误的类文件: *** 类文件具有错误的版本 61.0, 应为 52.0 请删除该文件或确保该文件位于正确的类路径子目录中

一、问题 用maven对一个开源项目打包时&#xff0c;遇到了“错误的类文件: *** 类文件具有错误的版本 61.0, 应为 52.0 请删除该文件或确保该文件位于正确的类路径子目录中。”&#xff1a; 二、原因 原因是当前java环境是Java 8&#xff08;版本52.0&#xff09;&#xff0c;但…

【大模型入门指南 07】量化技术浅析

【大模型入门指南】系列文章&#xff1a; 【大模型入门指南 01】深度学习入门【大模型入门指南 02】LLM大模型基础知识【大模型入门指南 03】提示词工程【大模型入门指南 04】Transformer结构【大模型入门指南 05】LLM技术选型【大模型入门指南 06】LLM数据预处理【大模型入门…

在线工具箱源码优化版

在线工具箱 前言效果图部分源码源码下载部署教程下期更新 前言 来自缤纷彩虹天地优化后的我爱工具网源码&#xff0c;百度基本全站收录&#xff0c;更能基本都比较全&#xff0c;个人使用或是建站都不错&#xff0c;挑过很多工具箱&#xff0c;这个比较简洁&#xff0c;非常实…

@LocalBuilder装饰器: 维持组件父子关系

一、前言 当开发者使用Builder做引用数据传递时&#xff0c;会考虑组件的父子关系&#xff0c;使用了bind(this)之后&#xff0c;组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题&#xff0c;引入LocalBuilder装饰器。…

C 语言内存探秘:数据存储的字节密码

文章目录 一、数据在内存中的存储1、基本数据类型存储2、数组存储3、结构体存储1、基本存储规则2、举例说明3、查看结构体大小和成员偏移量的方法 二、大小端字节序三、字节序的判断 一、数据在内存中的存储 1、基本数据类型存储 整型&#xff1a;如int类型&#xff0c;通常在…

双因素身份验证技术在NPI区域邮件安全管控上的解决思路

在制造业中&#xff0c;NPI&#xff08;New Product Introduction&#xff0c;新产品导入&#xff09;区域是指专门负责新产品从概念到市场推出全过程的部门或团队。NPI 的目标是确保新产品能够高效、高质量地投入生产&#xff0c;并顺利满足市场需求。在支撑企业持续创新和竞争…

浙江安吉成新的分布式光伏发电项目应用

摘 要&#xff1a;分布式光伏发电站是指将光伏发电组件安装在用户的建筑物屋顶、空地或其他适合的场地上&#xff0c;利用太阳能进行发电的一种可再生能源利用方式&#xff0c;与传统的大型集中式光伏电站相比&#xff0c;分布式光伏发电具有更灵活的布局、更低的建设成本和更高…

更新Office后,LabVIEW 可执行程序生成失败

问题描述&#xff1a; 在计算机中&#xff0c;LabVIEW 开发的源程序运行正常&#xff0c;但在生成可执行程序时提示以下错误&#xff1a; ​ A VI broke during the build process from being saved without a block diagram. Either open the build specification to include…

mysql-operator容器化部署mysql8

基础组件容器化 前一段时间容器化了容器的s3和pika。由于已经有开源方案&#xff0c;本次mysql直接以operator容器化。使用的是[presslabs的mysql-operator]https://github.com/presslabs/mysql-operator。 主要特征 presslabs/mysql-operator自动化搭建主从集群。使用XtraBack…

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize&#xff08;&#xff09; 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…