generated from youfool-project/youfool-prj-springboot3-template
107 lines
4.2 KiB
Markdown
107 lines
4.2 KiB
Markdown
|
|
# LE-2026-05-001 - 前端联调高频错误模式归纳(来自 gz-atms-web 项目)
|
|||
|
|
|
|||
|
|
**日期**:2026-05-21
|
|||
|
|
**模块**:通用
|
|||
|
|
**分类**:前后端数据映射 / 接口参数 / 组件框架 / 数据库SQL
|
|||
|
|
**严重程度**:P1(严重)
|
|||
|
|
|
|||
|
|
## 问题描述
|
|||
|
|
|
|||
|
|
从 gz-atms-web 项目(`D:\chinaweal\gz-atms\gz-atms-web\docs\fix\错题库`)的 12 条错题中,归纳出前后端联调的 8 大高频错误模式。
|
|||
|
|
|
|||
|
|
## 错误模式归纳
|
|||
|
|
|
|||
|
|
### 模式 1:字段名不匹配
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 表格数据为空,prop 与后端返回的 JSON key 不一致 |
|
|||
|
|
| 根因 | 前端 prop 用中文/自定义名,后端返回 Java camelCase 字段名 |
|
|||
|
|
| 修复 | prop 必须与 API 返回的 JSON key 精确一致 |
|
|||
|
|
| 检测 | 对比前端 table column prop 与后端 VO 字段名 |
|
|||
|
|
|
|||
|
|
### 模式 2:rowKey 不匹配
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 翻页后操作列按钮消失、DOM 状态错乱 |
|
|||
|
|
| 根因 | 默认 rowKey='id',但后端主键字段名不同(如 marketId) |
|
|||
|
|
| 修复 | 显式设置 `row-key="实际主键名"` |
|
|||
|
|
| 检测 | 检查 Entity @TableId 的字段名,与前端 row-key 对比 |
|
|||
|
|
|
|||
|
|
### 模式 3:分页字段名(list vs records)
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 列表数据加载不出来 |
|
|||
|
|
| 根因 | MyBatis-Plus 分页返回 `records`,前端误用 `list` |
|
|||
|
|
| 修复 | 统一使用 `res.records` |
|
|||
|
|
| 检测 | 后端返回 `Page<Entity>` 时,前端取列表数据的字段名 |
|
|||
|
|
|
|||
|
|
### 模式 4:JSON 字符串未解析
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 调用 `.map()` 报 TypeError: xxx.map is not a function |
|
|||
|
|
| 根因 | 后端 CLOB/JSON 字段返回 String,前端当数组直接使用 |
|
|||
|
|
| 修复 | `JSON.parse(data)` 或 `Array.isArray(data) ? data : JSON.parse(data)` |
|
|||
|
|
| 检测 | 后端 Entity 中 String 类型但实际存储 JSON 的字段(如 relatedRules、scopeDistricts) |
|
|||
|
|
|
|||
|
|
### 模式 5:数组与单对象混淆
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 访问属性报 undefined,渲染异常 |
|
|||
|
|
| 根因 | 一对多关系后端返回数组,前端当单个对象使用 |
|
|||
|
|
| 修复 | `Array.isArray(data) ? data[0] : data` |
|
|||
|
|
| 检测 | 详情接口返回类型如果是 `List<Entity>` 而非 `Entity` |
|
|||
|
|
|
|||
|
|
### 模式 6:响应拦截器自动解包
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 取 res.data.data 报 undefined |
|
|||
|
|
| 根因 | request.js 拦截器已自动解包 `response.data`,业务代码再解包一次就多了一层 |
|
|||
|
|
| 修复 | 直接使用 `res.list`、`res.total` 等已解包字段 |
|
|||
|
|
| 检测 | 检查前端 request.js 响应拦截器的 return 逻辑 |
|
|||
|
|
|
|||
|
|
### 模式 7:导出接口 responseType 未设 blob
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 文件下载报"业务出错"或下载文件损坏 |
|
|||
|
|
| 根因 | 未设置 `responseType: 'blob'`,二进制数据被当文本处理 |
|
|||
|
|
| 修复 | 请求配置中添加 `responseType: 'blob'` |
|
|||
|
|
| 检测 | 所有文件下载接口的前端请求配置 |
|
|||
|
|
|
|||
|
|
### 模式 8:排序字段驼峰未转下划线
|
|||
|
|
|
|||
|
|
| 维度 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 表现 | 达梦数据库报错"列名无效" |
|
|||
|
|
| 根因 | 前端传驼峰字段名,后端直接拼 SQL,DM8 要求大写下划线列名 |
|
|||
|
|
| 修复 | 后端排序字段先转下划线再拼 SQL,或前端直接传下划线格式 |
|
|||
|
|
| 检测 | 后端 QueryWrapper orderBy 使用了 camelCase 字段名的位置 |
|
|||
|
|
|
|||
|
|
## AI 检测规则
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
CHECK: 对 OARMS 项目进行以下 8 项自动检测
|
|||
|
|
RULE:
|
|||
|
|
1. 前端 table column prop == 后端 VO/Entity 字段名
|
|||
|
|
2. 前端 row-key == 后端 @TableId 字段名
|
|||
|
|
3. 前端分页取数据字段 == "records"(非 "list")
|
|||
|
|
4. 后端 CLOB/String 字段(relatedRules, scopeDistricts 等)前端有 JSON.parse
|
|||
|
|
5. 详情接口返回数组时前端有 Array.isArray 判断
|
|||
|
|
6. 前端 request.js 拦截器解包逻辑与业务代码一致
|
|||
|
|
7. 文件下载接口前端有 responseType:'blob'
|
|||
|
|
8. 后端排序字段名已转下划线
|
|||
|
|
FAIL: 任一规则不满足 → 报告具体位置和修复建议
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 参考
|
|||
|
|
|
|||
|
|
原始错题来源:`D:\chinaweal\gz-atms\gz-atms-web\docs\fix\错题库\`
|
|||
|
|
- 2026-01: 3 条(方法调用错误、拦截器解包、路径错误)
|
|||
|
|
- 2026-05: 9 条(字段映射、分页、JSON解析、导出、排序等)
|