hl-api-changelog/changelogs-v2/2026-06/05_任务看板打开弹获取看板X失败toast-前端竞态重复请求被取消-管理后台.md

5.7 KiB

【前端 BUG·管理后台】任务看板打开弹「获取看板详情/任务/成员失败」红 toast = 前端竞态重复发请求 + 取消被误报错

关联: 无工单(前端 bug 走 changelog 通知 mmg 服务: 前端 hl-ui后端零改动| 提报时间: 2026-06-05

存放目录: changelogs-v2/2026-06/ 影响范围: 管理后台「任务看板」/task/boards(看板列表 / 看板详情视图) 类型: 前端竞态 bugmmg 修),后端实测全 200 健康无需改动


⚠️ 关键说明

打开任务看板时弹出红色错误 toast「获取看板详情失败 / 获取看板任务失败 / 获取看板成员失败」,但看板数据其实正常加载出来了(公司看板、各状态列、任务卡片都在)。

根因 = 前端竞态,不是后端故障。 看板组件挂载时对同一个数据接口重复发请求tasks 发 3 次、members 发 2 次、detail 视时序也会重发),多余的在飞请求被前端 AbortController 主动取消(浏览器 net::ERR_ABORTED)。前端 .catch() 没有把「请求被取消」和「请求真失败」区分开,于是把取消也当成失败弹了红 toast。

后端侧:凡是被允许跑完的请求全部返回 200(看板列表/详情/任务/成员/状态 + token refresh,curl 80+ 次 + 真浏览器多轮复现,零服务端失败)。


1. 实证(真浏览器 DevTools Network,刚登录 token 全新,硬刷新复现)

打开 /task/boards(公司看板 2022226454376366081)后的请求序列:

# 请求 结果
1 GET /admin/task/boards(看板列表) 200
2 GET /admin/task/board/{id}(看板详情,含 statuses 200
3 GET /admin/task/board/{id}/tasks FAILED net::ERR_ABORTED
4 GET /admin/task/board/{id}/tasks 200 (同一接口重发,成功)
5 GET /admin/task/board/{id}/members 200
6 GET /admin/task/board/{id}/tasks FAILED net::ERR_ABORTED
7 GET /admin/task/board/{id}/members 200 (同一接口重发)

要点:

  • tasks 接口被触发 3 次2 次被取消、1 次成功);members 触发 2 次detail 偶发重发被取消时就弹「获取看板详情失败」。
  • net::ERR_ABORTED客户端主动取消(不是 4xx/5xx,服务端从没收到失败结果,典型来自 axios cancel / AbortController.abort() / 组件重渲染或重复触发同一 fetch。
  • 浏览器 console 0 个 error(说明取消已被 catch 捕获),但 catch 里仍调用了错误 toast。

后端实测对照(均 200,有数据

GET /admin/task/boards                         -> 200, 看板列表
GET /admin/task/board/2022226454376366081      -> 200, 详情含 4 个 statuses
GET /admin/task/board/2022226454376366081/tasks   -> 200, 任务分组
GET /admin/task/board/2022226454376366081/members -> 200, []
GET /admin/task/board/2022226454376366081/statuses-> 200, 4 条
POST /admin/auth/refresh (真 refreshToken)         -> 200连打 30 次全 200

2. 前端修法mmg

2.1 必修catch 里放过「被取消」的请求,别弹错误 toast

错误处理里先判断是否为取消,是则静默 return,不弹 toast

import axios from 'axios'
// ...
.catch((e) => {
  // 请求被取消(组件重渲染/重复触发抢占)是预期行为,不是错误
  if (axios.isCancel(e) || e?.code === 'ERR_CANCELED' || e?.name === 'CanceledError') return
  ElMessage.error('获取看板任务失败')   // 只有真失败才提示
})

三处都要加:获取看板详情 / 获取看板任务 / 获取看板成员的 catch。

2.2 根治:去掉对同一接口的重复触发

tasks 发 3 次、members 发 2 次,说明同一 fetch 被多个来源同时触发(常见:onMounted 触发一次 + watch(boardId) 触发一次 + 默认「优先级/状态」筛选 radio 又触发一次)。建议:

  • 数据加载只保留单一触发源(推荐由 watch(boardId, { immediate: true }) 统一触发,去掉 onMounted 里的重复拉取);
  • 或对每类请求维护一个 AbortController,重发前先 abort() 旧的——但这种「主动取消」必须配合 §2.1,把取消视为正常、不报错

2.3 注意(与本 bug 无关、但同页常见)

看板有实时通道(/ws/task/info + /admin/task/board/ws-doc)。若 WS 推送后又触发整页重新拉取,也会放大上面的「重复请求 + 取消」现象,一并按 §2.1/§2.2 处理。


3. 后端状态(无需改动)

  • 任务看板全部读接口list / detail / tasks / members / statuses实测 200,数据正确。
  • POST /admin/auth/refresh:网关已在 JwtAuthFilter.SKIP_URLS 白名单放行,带过期 access token + 真 refreshToken 实测 200,20 并发全 200。

3.1 附注:你截图里 refresh 的 502 是「另一桩、瞬时」

你之前截图 Network 里 refresh 显示 502,那是独立的瞬时事件:当时会话 access token 已过期 → 前端自动调 /admin/auth/refresh 续签 → 恰好撞上测试服 user-service双实例 8081/8181部署/重启抖动,网关 LB 轮到正在重启的实例返 502。当前 30+ 次 refresh 全 200,复现不出,不是看板代码缺陷,无需前端改动;若再遇到,刷新页面即恢复。


4. 关联

  • 后端负责人:@wx已实测确认后端健康,无改动
  • 前端对接(本 bug 修复):mmg
  • 复现路径:登录管理后台 → 任务看板(/task/boards)→ 打开「公司看板」即弹失败 toast,但数据正常。