体育博彩页面看上去是静态的:一列比赛,一栏赔率。底下的赔率数据源却是由成千上万次小变化组成的数据流,运营商要做的,就是按正确顺序把每一次变化都应用到位。这篇指南从第一次请求一直讲到注单结算。
1. 数据模型
几乎所有数据源都采用同一套层级:
- 体育项目:足球、网球、电竞。
- 赛事或联赛:英超、ATP 东京站、英雄联盟全球总决赛。
- 比赛:一场具体的比赛,有开赛时间和参赛方。
- 盘口:关于这场比赛的一个问题,例如 1X2、大小 2.5 球或地图让分。
- 选项:一个答案,带赔率和状态(开放、封盘、已结算)。
每个元素都有稳定的标识符。对接中的大多数 bug,都源于把名称当成了标识符:队名的拼写会变,ID 不会。
2. 先快照,后增量
启动时,客户端请求一份快照,也就是完整的当前状态。此后它接收的是增量:一条条小消息,告诉它“这个赔率变了”“这个盘口封了”“这场比赛开始了”。
好的数据源会给增量编号。以 Nocturn Sport 为例,它把自己的数据源描述为完整快照加带版本号的增量。如果客户端手里是 N 版,收到的却是 N+2 版,就知道有一条消息丢了,会重新加载,而不是显示过期赔率。没有版本号的数据源只能让客户端去猜,而盘口挂出昨天的赔率,往往就是这么猜出来的。
3. 推送与拉取
足球滚球的赔率一分钟可能变好几次,所以滚球数据通常通过长连接推送。赛前赔率变化慢,每隔几秒用 HTTP 拉取一次往往就足够。很多运营商两种都用:赛前目录用拉取,滚球用推送。
4. 封盘
封盘就是数据源在说:“现在别接这个的注。”触发原因包括进球、点球、破发、一张地图结束,或者供应商自己的数据源断了。客户端处理封盘必须比处理任何其他消息都快;进球后几秒内接下的投注,是赔钱的经典方式。
赛前盘口也会在开赛前关闭。比如 Nocturn Sport 会在开赛前一分钟关闭赛前盘口。
5. 下注
如果 API 不只是发布赔率,下注通常遵循这样一套流程:
- 客户端发送所选选项、它显示的赔率和投注金额,并附上一个唯一请求 ID。
- 服务器检查赔率是否仍然有效、盘口是否开放。
- 服务器接受、拒绝,或给出新赔率。
- 如果网络中断,客户端用同一个请求 ID 重发,服务器返回最初的结果,而不是再生成一笔注单。
最后这一步就是幂等性,它同时保护玩家余额和运营商的账本。
6. 结算
比赛结束后,数据源按选项发布结果:赢、输、走盘,或者亚洲让分这类拆分盘口的赢一半、输一半。平台据此逐笔结算。结果也会被更正:复核后赛果可能修改,所以结算流程必须能干净地重新结算。
7. 上线前要测什么
- 比赛进行中切断连接,检查恢复过程。
- 乱序重放一条增量,检查客户端能否察觉。
- 用同一个请求 ID 下同一注两次。
- 结算一张其中一关走盘的串关。
能扛过这四项测试的数据源,才算准备好迎接周六下午的流量高峰。
常见问题
快照(snapshot)和增量(delta)有什么区别?
快照是所有赛事、盘口和赔率当前的完整状态;增量只包含某个版本之后发生变化的内容。客户端先加载一次快照,然后按顺序应用增量。
增量为什么要带版本号?
这样客户端才能发现缺口。如果手里是 1,204 版,收到的却是 1,206 版,它就知道 1,205 丢了,必须重新加载,而不是显示一个错误的赔率。
盘口为什么会被封盘?
因为当前赔率已经不安全了:进球、红牌、破发,或者与数据源断开连接。封盘期间拒绝投注,直到以新赔率重新开盘。
赔率数据源负责下注吗?
有的负责,有的不负责。纯数据源只发布赔率;体育博彩API 会加上下注、注单历史和结算,通常每笔投注带一个唯一请求 ID,这样重试不会让投注金额翻倍。
推送还是拉取,哪种传输方式更好?
推送(消息流或 socket)适合滚球,因为赔率按秒变化。拉取(HTTP 轮询)更简单,赛前盘口通常就够用了。