FINTECH 101 — 交易到底是如何运作的
Source: Dev.to
核心思维模型
四大支柱:
- 交易状态
- 回调 / Webhook
- 对账与状态查询
- 重试、冲正与幂等性
如果你误解了其中任何一点,最终会亏钱。
Source: …
交易状态(非响应)
在金融科技领域,我们跟踪 状态,而不仅仅是 HTTP 响应。
规范的交易生命周期
| 状态 | 描述 |
|---|---|
| INITIATED | 请求在内部创建 |
| PROCESSING | 已发送至处理器 |
| PENDING | 处理器已接受但尚未最终确认 |
| SUCCESS | 金额已确认交付 |
| FAILED | 金额未交付 |
| REVERSED | 金额已扣除随后返还 |
| TIMEOUT | 在 SLA 时间内未收到响应 |
这些状态实际代表的含义
| 状态 | 含义 |
|---|---|
| INITIATED | 您的系统已创建该交易 |
| PENDING | 处理器或网络仍在处理中 |
| SUCCESS | 价值已交付(流量、数据、金钱等) |
| FAILED | 价值未交付 |
| REVERSED | 金额已扣除但已退款 |
黄金法则
交易只能以 SUCCESS、FAILED 或 REVERSED(临时)结束。
在金融科技系统中,请求可以在技术上成功,而金融行为本身未完成(例如,余额不足、银行确认待定、合规检查失败)。这些属于正常的业务结果,而非系统错误。
使用 HTTP 响应码来表示技术成功,并使用单独的业务状态来表示交易结果,可避免混淆、防止不安全的重试,并使支付流程更易于理解。
概念 vs. 目的
| 概念 | 目的 |
|---|---|
| Response Code | 技术结果 |
| Status | 业务状态 |
示例
{
"code": "99",
"status": "PENDING",
"message": "Transaction is being processed"
}
HTTP 200 仅表示“我们收到了你的请求”;它 不 表示交易成功。status 字段才是事实的真相。
金额表示
绝不要使用浮点数(float)或双精度(double)来存储金额。
计算机使用二进制(base‑2),而人类使用十进制(base‑10)。一些简单的小数在二进制中无法精确表示,导致四舍五入误差和账本不匹配。
正确做法:最小单位
将金额存储为最小货币单位。
| 错误 | 正确 |
|---|---|
以 100.00(十进制)存储 | 以 10000(整数)存储 |
经验法则
- 数据库:
BIGINT(例如,1050表示 10.50) - 代码: 整数运算(
1050 + 20) - 前端: 仅在显示时转换(例如,
GH₵10.70)
Source: …
回调(Webhooks)
什么是回调?
当交易因网络延迟、银行离线或处理器超时而仍处于待处理状态时,就会发生回调。
典型的回调流程
- 你发送请求。
- 处理器响应 → PENDING。
- 你将交易保存为 PENDING。
- 稍后,处理器调用 your endpoint。
- 你更新交易 → SUCCESS / FAILED。
回调失败
- 网络问题
- 处理器宕机
- 处理器漏洞
由于回调可能会失败,金融科技系统还会使用 status enquiry(拉取)来恢复真实状态。
- Push: 处理器主动通知你(回调)。
- Pull: 你主动向处理器查询(status enquiry)。
幂等性
噩梦情景
- 用户点击 “Pay”。
- 网络故障。
- 用户再次点击。
- 产生两笔收费。
解决方案:幂等键
- 拒绝重复的引用。
- 强制数据库唯一性 (
UNIQUE(reference)).
重试
当出现以下情况时,重试是危险的:
- 无响应(超时)
- 网络错误
在 成功 之后进行重试可能导致重复收费,而在 失败 的业务结果之后进行重试可能是没有必要的。
逆转
当出现以下情况时需要进行逆转:
- 已产生 SUCCESS 借记但交付失败。
- 在 SLA 期限后未收到回调。
逆转流程
- 检测不匹配。
- 调用逆转 API。
- 更新交易 → REVERSED。
- 通知用户。
您的记录永远不可能与处理器的记录完全一致。任何不匹配都应进行调查并予以纠正。
日志要求
- 请求负载
- 响应负载
- 状态转换
- 时间戳
最终思维模型(永远保持)
- 永远不要相信第一次响应。
- 金钱系统最终是一致的。
- Status 是真相,而不是 HTTP 响应码。
- 会计永远占上风。
如果你用这种思维方式构建金融科技,你不仅能通过测试——还能在生产环境中生存下来。