4. 支付核心链路高频问题
支付核心链路是面试官判断候选人是否“真做过支付”的分水岭。很多人能背出“收单、路由、风控、渠道网关、回调、重试”这六个词,但一旦被追问“路由失败后订单状态怎么流转”“回调重复到达如何保证幂等”“重试和补偿的边界在哪”,回答就开始发散。本章的目标不是让你背链路名词,而是建立一条可复述、可追问、可落地的回答主线。
面试官问“讲一下支付核心链路”,本质是在考察三件事:你是否理解资金与状态的流转顺序;你是否能说清每个环节的失败处理;你是否知道不同公司在这条链路上的侧重点差异。
一、核心原理:链路是状态机,不是函数调用
支付链路最容易被误解成一条同步调用链:收单调风控,风控调路由,路由调渠道,渠道返回结果。真实系统里,这条链路是“同步请求 + 异步回调 + 定时补偿”三线并行的状态机。任何一步都可能超时、失败、重复,因此核心设计原则是:先落状态,再发请求;以最终状态为准,不以单次返回为准。
- 收单:生成支付单,做参数校验、金额校验、商户校验,写入初始状态(如 INIT)。
- 风控:同步或异步做准入判断,输出通过、拒绝、人工审核三类结果,拒绝要能回写订单。
- 路由:根据渠道成本、成功率、限额、可用性选择渠道,路由结果要可追溯、可降级。
- 渠道网关:负责协议适配、签名、超时控制、请求日志,屏蔽不同渠道差异。
- 回调:接收渠道异步通知,验签、幂等、更新订单,并触发下游业务。
- 重试:对超时和未知状态做查询或补偿,区分“可重试”和“不可重试”。
二、方法流程:一条可复述的回答主线
面试时建议按“正向 + 异常 + 兜底”三段式回答,避免从头到尾平铺直叙。正向讲清楚状态流转,异常讲清楚失败分类,兜底讲清楚如何保证最终一致。
- 收单创建支付单,状态 INIT,记录商户、金额、币种、业务单号。
- 风控准入,通过则进入路由,拒绝则置为 FAIL 并通知业务。
- 路由选渠道,生成渠道请求流水,状态置为 PROCESSING。
- 渠道网关发起请求,记录请求日志和渠道返回码。
- 同步返回成功不等于终态,等待回调或主动查询确认。
- 回调验签、幂等更新订单为 SUCCESS 或 FAIL,通知业务方。
- 超时或未知状态进入重试与补偿,按策略查询渠道终态。
回答时主动说出“同步返回只代表受理,不代表成功”,这句话能立刻体现你对支付终态的理解,是高频加分点。
三、案例与场景:路由失败与回调重复
场景一:路由失败。用户支付时渠道 A 超时,系统不能直接把订单置为失败,因为渠道可能已扣款。正确做法是保留 PROCESSING,触发渠道查询,确认失败后再置 FAIL,或切换渠道 B 重新支付。这里要强调“未知状态”是支付里最危险也最常见的状态。
场景二:回调重复。渠道因网络问题重复推送回调,系统必须用渠道流水号 + 商户单号做唯一键,先查后更或使用数据库唯一索引,保证幂等。更新成功后返回渠道约定的成功标识,避免渠道继续重推。
// 回调幂等伪代码
if (exists(channelNo, merchantOrderNo)) {
return SUCCESS; // 已处理,直接应答
}
try {
insertCallbackLog(channelNo, merchantOrderNo);
updateOrderStatus(merchantOrderNo, SUCCESS);
notifyBusiness(merchantOrderNo);
} catch (DuplicateKeyException e) {
return SUCCESS; // 并发重复,视为已处理
}
return SUCCESS;
四、误区与复盘:别把重试当万能药
最常见的误区是“失败就重试”。支付里必须区分:网络超时可重试,参数错误不可重试,风控拒绝不可重试,渠道明确失败不可重试。盲目重试会造成重复扣款或重复发货。
| 环节 | 高频追问 | 回答要点 |
|---|---|---|
| 收单 | 如何防重复下单 | 业务单号唯一索引 + 幂等键 |
| 风控 | 同步还是异步 | 按拦截时效要求选择,拒绝要回写 |
| 路由 | 如何降级 | 成功率、成本、限额、熔断 |
| 渠道网关 | 超时怎么处理 | 记录未知态,走查询补偿 |
| 回调 | 如何保证幂等 | 唯一键 + 先查后更 + 日志 |
| 重试 | 重试边界 | 只重试可恢复错误,设上限和退避 |
最后是公司侧重点差异:电商支付更关注收单与回调的幂等和履约一致性;金融支付更关注风控、合规与资金安全;聚合支付更关注路由成本与渠道覆盖率;跨境支付更关注汇率、清结算和渠道时区。面试前先判断目标公司属于哪一类,再调整回答重心,比背一套通用答案更有效。