hl-api-changelog/changelogs/2026-05/07_fix_mp_arrival_batch_validation_friendly.md

5.6 KiB

小程序填写返程信息: 校验前置 mp 端 + 错误信息友好化(前端有 BUG 待排查)

服务: hl-mp-service (端口 8085) PR: #1830 (已合并 dev, 待部署 prod) Issue: #1828 (P0-紧急, 正式环境) 日期: 2026-05-07 影响范围: 小程序「填写返程信息」页(自驾/飞机/火车 × 一起返程/分批返程 全部场景) @ 前端: mmg


⚠️ 关键信息

正式环境用户在小程序「填写返程信息」点「确认提交」后弹 toast

batchReplace.reqs[0].travelerIds: 出行人列表不能为空

用户 UI 上已经勾选了「蒋桂龙」乘坐人员,但后端收到的 travelerIds 是空 — 这是一个双重 BUG

  1. 前端 BUGmmg 必修)hl-mini 小程序 _buildTogetherPlan 把勾选的 traveler 的 id 装进请求 body 时,因 ID 字段名漂移导致最终装入的是占位符 order-N 被过滤,致 travelerIds 空数组
  2. 后端友好化(本 PR 修)MpArrivalController.batchReplace@Valid List<...> 不递归到元素,校验穿透到 internal controller 才被 @Validated 触发,错误信息暴露内部参数名 batchReplace.reqs[0]

一、后端变更(本 PR 已合 dev

1.1 接口契约

# 接口 方法 路径 变更类型 说明
1 全量替换返程批次 POST /mp/order/{orderId}/arrival/batch 错误信息变更(不破坏契约) body 形状不变;mp 端前置校验,错误信息中文友好

1.2 新错误码

Code Message 触发条件
620001 请添加至少一批返程信息 body 是空 List 或 null
620002 第 N 批返程信息:请选择至少一位乘坐人员 body[N-1].travelerIds 为 null 或空 List

1.3 旧错误信息部署前vs 新错误信息(部署后)

场景 部署前 部署后
body 空 batchReplace.reqs: 不能为空 请添加至少一批返程信息
首批空 travelerIds batchReplace.reqs[0].travelerIds: 出行人列表不能为空 第 1 批返程信息:请选择至少一位乘坐人员
第二批空 travelerIds batchReplace.reqs[1].travelerIds: 出行人列表不能为空 第 2 批返程信息:请选择至少一位乘坐人员

1.4 服务端日志增强

mp controller 抛出校验失败前会 log.warn

mp/arrival/batch 校验失败 orderId={} userId={} bodySize={} 元素摘要={}

(元素摘要含 direction / transportType / travelerIds.size 协助排查前端实际发出 body

部署后 mmg 可以让运维拉 hl-mp-service WARN 日志看真实 body 形状(每元素含 direction/transportType/travelerIds 是否为空)。


二、前端待处理mmg 必修)

2.1 嫌疑代码位置

hl-mini/packages/trip/arrival/arrival.js

行 88_loadPassengers

id: String(t.orderTravelerId || t.travelerId || t.id || `order-${idx}`)

行 681-686_buildTogetherPlan

const selected = this.data.passengers.filter(p => p.checked && !p._isLocal);
const travelerIds = selected
  .map(p => String(p.id || ''))
  .filter(id => id && !id.startsWith('order-') && !id.startsWith('local-'));

2.2 排查步骤(建议)

  1. _buildTogetherPlan 进入时打日志:
    console.log('[arrival] passengers=', this.data.passengers, 'selected=', selected, 'travelerIds=', travelerIds);
    
  2. 复现「蒋桂龙」场景(正式订单),观察 passenger 对象的 id 字段真实值:
    • 如果是 order-0 这种占位符_loadPassengers 三个候选字段名(orderTravelerId / travelerId / id)都没拿到值,对照后端 getOrderDetail 接口返回的 travelers[] 元素真实字段名与三候选是否对齐
    • 如果是雪花 ID_buildTogetherPlan 的 filter 逻辑是否有别的过滤条件把它排掉
  3. 对照后端 VOhl-mp-serviceMpOrderTravelerVO)确认实际字段名 — 必要时让我贴出来

2.3 separate 模式(多批次返程)

arrival.js L711 _buildSeparatePlansb.travelerIds || [],L717 已有"第 N 批缺少出行人"前置 toast 拦截 — 理论上不会发到后端。但若有路径绕过此 toast,本次后端校验是兜底。


三、数据库行为

只读校验,不写库。校验失败立即抛 BusinessException 不进入 Feign 调 order-v2。


四、边界行为

  • body=null → 620001 "请添加至少一批返程信息"
  • body=[] → 620001
  • body=[{travelerIds:null}] → 620002 "第 1 批..."
  • body=[{travelerIds:[]}] → 620002
  • body=[{travelerIds:[10001]}, {travelerIds:[]}] → 620002 "第 2 批..."
  • body=[{travelerIds:[10001]}, {travelerIds:[10002]}] → 走 Feign 到 internal,正常处理

五、不影响范围

  • POST /mp/order/{orderId}/arrival/batch 一个接口
  • mp create / update / delete / list 接口 0 改动
  • internal controller @Validated 兜底仍在,admin / 其他客户端调 internal 仍受校验
  • API 契约body 形状)不变,前端无需改请求结构

六、测试

  • 单测: MpArrivalControllerTest 9/9 全绿 (5 原有 + 4 新增反例:空 body / null body / 首批空 travelerIds / 第二批空 travelerIds)
  • 测试服 round-trip: 待 dev 部署测试服后由 QA 验证
  • prod 部署: 由运维管理员排期 (本 PR 不动 prod)

七、相关文档