一个参数取名导致的 DRF 下 GET 方法的行为异常

日前,笔者项目有一个导出JSON和Excel文件的需求,碰到一个很奇怪的现象,排查了两天,终于搞懂了,现在复盘整个过程和解决方法。

一、简要代码

Django-Vue3前后端分离项目,后端采用Django REST Framework (DRF) 框架。 针对导出JSON和Excel文件的需求,我的设计如下: 1、前端接口定义:

typescript 复制代码
export interface InfosExportParams {
  format: "json" | "excel"; // 导出格式
  name?: string; // 按信息名称模糊搜索
  category?: number; // 按信息类别ID精确匹配
}

2、前端网络请求API

csharp 复制代码
export const exportInfos = async (params?: InfosExportParams): Promise<any[]> => {
  return request.get("/infos/export/", {
    params,
    responseType: "json",
  });
};

3、前端导出功能调用

typescript 复制代码
// 导出按钮click函数,传递"json" | "excel"参数
const handleExport = async (formatParams: "json" | "excel") => {
  // 构建导出参数 - 使用当前筛选条件
  const exportParams: InfosExportParams = {
    format: formatParams,
  };
  if (searchForm.name) exportParams.name = searchForm.name;
  if (searchForm.category) exportParams.category = searchForm.category;

  if (formatParams === "json") {
    // 导出JSON格式
    try {
      const flatJSONData = await exportInfos(exportParams);

      // 由前端继续处理flatJSONData数据,导出JSON文件
      // 后续省略
    } catch (error: any) {
      // 省略
    }
  } else if (formatParams === "excel") {
    // 导出Excel格式
    try {
      const flatJSONData = await exportInfos(exportParams);

      // 由前端继续处理flatJSONData数据,导出Excel文件
      // 后续省略
    } catch (error: any) {
      // 省略
    }
  }
};

4、后端采用自定义action:GET /api/infos/export/ 在视图集里定义如下:

python 复制代码
# 自定义 action:GET /api/infos/export/ - 导出扁平化 JSON 数据
    @action(detail=False, methods=["get"], url_path="export")
    def infos_export(self, request):
        print("开始生成扁平化 JSON 数据...")
        // 处理请求,返回响应。省略
        return response

以上这些代码,是我反复排查后,确认的和Bug可能有关的核心代码,移除了无关的业务逻辑。

二、现象描述

  • 1、当参数 format 为 "json"时,可以正常返回数据;
  • 2、当参数 format 为 "excel"时,返回404错误"请求的资源不存在",而且连自定义action infos_export方法都没有进去(第一行print调试语句没有打印)。

以上就是我排查整个前后端功能链路上聚焦的核心关键点。

我一开始以为是后端的权限配置问题,或者url设置问题,但反复测试下来不是。

后来发现,在排除掉无关业务代码后,两种导出功能在前后端的代码几乎一模一样,只有format参数不一样。

这时我还没有怀疑是format参数的问题,总认为format参数是我自定义参数的一个字段,Django/DRF难道能够针对GET方法,自动解析我的参数 format,并根据解析结果产生不同行为?

三、定位分析

这种现象太奇怪了,反复排查,移除无关代码,最后让我不得不怀疑就是format参数的问题,尽管format是我自定义的一个参数。

实际上,DRF为了提供开箱即用的"可浏览API"(Browsable API)功能,内置了一个机制,它会检查请求中的format查询参数,并根据其值来决定使用哪种渲染器(Renderer)来生成响应。

当我使用request.get("/infos/export/", { params: { format: "excel" } }) 发送请求时,DRF在视图函数执行之前,会先处理这个format参数。

而DRF的核心库中并不包含名为 ExcelRenderer 的内置渲染器。DRF 默认只提供了以下几种渲染器:

  • JSONRenderer (默认)
  • BrowsableAPIRenderer
  • AdminRenderer
  • HTMLFormRenderer
  • XMLRenderer

因此,如果我想导出 Excel 文件,DRF无法找到处理 format=excel的方式。因此,它会认为这个请求无效,并直接返回一个404 Not Found响应,我的自定义action infos_export根本没有机会执行。

这就是为什么request.get("/infos/export/", { params: { format: "json" } })成功,request.get("/infos/export/", { params: { format: "excel" } })失败的根本原因。

解决方法也很简单,直接更换参数名,将前端的参数名从 format 改为如 export_format 。

四、大模型AI的作用

整个问题的排查分析,我让AI深度参与,国内trae、千问、deepseek试了个遍,都没有用,认为就是我后端的权限配置或URL设置的问题。

当我指出,很可能是format参数的问题时,依然从权限和url角度排查,要么陷入死循环,要么给出错误结论然后停摆。

最后是我查阅DRF官方文档,看到DRF会对format参数进行自动解析时,AI才接受,后面就顺利了。

相关推荐
我叫黑大帅2 小时前
Go 项目中 Redis 缓存的实用设计与实现(Cache-Aside 模式)
redis·后端·面试
didadida2622 小时前
深度解析:现代单页应用(SPA)中微信授权登录的高可用架构实现
后端
小江的记录本2 小时前
【RAG】RAG检索增强生成(核心架构、全流程、RAG优化方案、常见问题与解决方案)
java·前端·人工智能·后端·python·机器学习·架构
ZC跨境爬虫2 小时前
海南大学交友平台登录页开发实战day6(覆写接口+Flask 本地链接正常访问)
前端·后端·python·flask·html
花椒技术2 小时前
从 1.5 秒到 660ms,直播间首屏秒开是怎么做出来的?
人工智能·后端·全栈
Rust研习社3 小时前
深入 Rust 引用计数智能指针:Rc 与 Arc 从入门到实战
开发语言·后端·rust
树獭叔叔3 小时前
OpenCLI:让任何网站成为你的命令行工具
后端·aigc·openai
峥嵘life3 小时前
Android + Kiro AI软件开发实战教程
android·后端·学习
石榴树下的七彩鱼4 小时前
Python OCR 文字识别 API 接入完整教程
开发语言·人工智能·后端·python·ocr·api·图片识别