Files
012-kaopeilian/知识库/问题修复/文件上传失败问题修复报告.md
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

4.1 KiB
Raw Permalink Blame History

文件上传失败问题修复报告

问题时间

2025-10-16 22:40

问题现象

用户在"编辑课程"页面上传文件时,浏览器控制台报错:

文件上传失败 - uploadRes: {file_url: '/static/uploads/courses/1/20251016224032_bac7a33f.pdf', file_name: '美拉美共建卡销售工具.pdf', file_size: 1458815, file_type: 'pdf'}
上传过程出错: Error: 文件上传失败
错误详情: {message: '文件上传失败', response: undefined, data: undefined}

关键线索

  • 文件已成功上传到服务器有file_url等信息
  • 但uploadRes缺少code字段
  • edit-course.vue:1115 判断 uploadRes.code === 200 失败

根本原因

http.tsupload() 方法存在双重数据提取问题:

  1. **响应拦截器第238行**处理后返回:

    return response.data  // {code: 200, data: {file_url: '...', ...}}
    
  2. **upload方法第392行**又执行了:

    .then((response) => response.data as ResponseData<T>)
    
  3. 最终返回

    {file_url: '...', file_name: '...', file_size: ..., file_type: '...'}
    // 丢失了 code 字段!
    
  4. edit-course.vue 第1115行判断失败

    if (uploadRes.code === 200 && uploadRes.data) {  // code 为 undefined
    

修复措施

1. 修复 http.ts 的 upload 方法

文件/root/aiedu/kaopeilian-frontend/src/utils/http.ts

修改前第392行

}).then((response) => response.data as ResponseData<T>)

修改后

})  // 直接返回响应拦截器处理后的结果

关键响应拦截器已经处理了数据结构upload方法不应再次提取 .data

2. 更新联调经验文档

文件/root/aiedu/考培练系统规划/全链路联调/联调经验汇总.md

  • 更新了第3654行的记录2025-09-29的修复记录
  • 标记为"2025-10-16 彻底修复"
  • 添加了详细的根因分析和修复措施

3. 更新团队基线规范

文件/root/aiedu/考培练系统规划/全链路联调/规范与约定-团队基线.md

  • 更新了"前端网络层返回结构约定"第1285行
  • 更新了"HTTP响应拦截器规范"第1004行
  • 添加了"具体方法实现规范",明确说明不应二次提取数据

验证结果

修复验证

  1. upload方法现在正确返回 { code: 200, data: { file_url, file_type, file_size } }
  2. edit-course.vue 判断 uploadRes.code === 200 能够成功通过
  3. courseApi.addMaterial(...) 能够正常执行
  4. 资料列表能够即时更新

技术要点

响应拦截器与方法封装的关系

核心原则

  1. 响应拦截器负责统一处理所有响应,返回标准的 {code, message, data} 结构
  2. 具体方法只负责构造请求,不再处理响应结构
  3. 保持"单一职责":拦截器处理响应,方法构造请求

常见错误模式

// ❌ 错误:双重数据提取
upload() {
  return this.instance.post(url, data)
    .then(res => res.data)  // 响应拦截器已经返回了 {code, data}
    // 再次提取 .data 会丢失 code 字段
}

正确模式

// ✅ 正确:直接返回响应拦截器处理后的结果
upload() {
  return this.instance.post(url, data)  // 响应拦截器已处理
}

历史记录

  • 2025-09-29:首次记录此问题,但修复不彻底
  • 2025-10-16:彻底修复,更新规范文档

后续建议

  1. 添加单元测试覆盖 upload 方法的返回结构
  2. 每次修改网络层代码后,必须在浏览器中实际测试上传功能
  3. Code Review 时重点检查响应拦截器与方法封装的数据层级关系
  4. 考虑使用 TypeScript 类型检查来预防类似问题

相关文件

  • /root/aiedu/kaopeilian-frontend/src/utils/http.ts - 修复位置
  • /root/aiedu/kaopeilian-frontend/src/views/manager/edit-course.vue - 调用位置
  • /root/aiedu/考培练系统规划/全链路联调/联调经验汇总.md - 经验记录
  • /root/aiedu/考培练系统规划/全链路联调/规范与约定-团队基线.md - 规范文档