简介:这是一份 OneAPI 计费系统开源版 1.2.0 的完整源码包,面向需要自建 API 网关并集成计费能力的开发者或中小团队。系统支持免费、资源包、混合计费等多种模式,兼顾卡密兑换、余额充值、实名与手机号绑定校验,同时提供邮件/短信验证码防刷机制和注册赠送余额,更新中还修复了特定值扣费逻辑等已知问题。源码包共 2000 个文件、压缩后约 8.34MB,其中 PHP 文件 643 个构成核心业务逻辑,MD 文档 725 个便于阅读部署与二次开发说明,JSON 数据 531 个覆盖配置与接口定义,另含前端样式、JavaScript、SQL 初始化脚本与 License 文件,目录结构清晰。已有 95 人学习下载。通过该源码包可快速部署一套可运营的 API 计费管理后台,也可基于在线 API 文档与代码编辑能力灵活改造计费规则,适合具备一定 PHP 开发经验、希望搭建或二次开发计费系统的技术人群。
1. 这不是 Intel 的 OneAPI:一个自托管的 API 接口计费网关
先泼盆冷水:如果你搜索“OneAPI”是为了找 Intel 那个 2024.2.1 的编译器工具包,这篇不是给你看的。我拆的是另一个东西——OneAPI 计费系统开源版 1.2.0,一套跑在自有服务器上的接口管理系统,解决的是「API 接口怎么收费、用户怎么充值、卡密怎么发、文档怎么维护」这一串脏活。这套系统支持免费、资源包、混合计费三种模式,内置卡密兑换、余额充值、实名认证、短信/邮箱验证码防刷,还能在线编辑 API 文档和接口代码。适合手里有 API 想开放出来赚钱的独立开发者,或者内部要做接口网关计费的小团队。我亲手搭了一套,踩了几个不大不小的坑,下面把部署、计费配置、扣费逻辑和排错过程完整写出来。
2. 计费模型先行:免费、资源包、混合计费怎么选
很多人装完系统第一件事就冲去配接口,结果卡在计费模型上。我先花一节把这个系统的计费骨架讲透,你后面配参数才不会懵。
2.1 三种计费模式的功能边界
系统的计费核心是「接口」维度,每个接口独立设置计费方式。管理员在后台创建接口时,需要明确这个接口走哪条计费路径:
| 计费类型 | 适用场景 | 用户侧体验 | 系统侧处理逻辑 |
|---|---|---|---|
| 免费 | 公开测试接口、引流入口 | 无需余额,直接调用 | 不记录扣费流水,只累计调用次数 |
| 资源包 | 预购次数的封装 API、按量计费的模型接口 | 先买资源包,调用时扣减次数 | 每次请求实时扣减资源包剩余额度,余量为 0 时拒绝请求 |
| 混合计费 | 部分免费额度 + 超出后扣费 | 免费额度用完后自动切换扣费 | 先查免费额度,再走资源包或余额扣费 |
这里最容易被忽略的是混合计费的优先级顺序。系统按「免费额度 → 资源包 → 余额」的顺序依次消耗,而不是管理员可以随便调整的。如果你希望某个接口只走资源包、不走余额,那需要在接口配置里关闭「余额兜底扣费」开关,否则用户会在资源包耗尽后悄悄扣成余额,月底对账时你根本想不起来这笔账是从哪来的。我自己的经验是:对外收费接口一律只开资源包,内部调试接口才开混合计费。
2.2 卡密兑换与余额充值的流转设计
卡密和充值构成了系统的资金入口。管理员在后台生成一批卡密(可自定义面额、有效期、批量生成数量),用户在个人中心输入卡密兑换成余额。余额充值则走站内配置的支付通道,支付回调成功后自动入账。
这里注意一个流转细节:卡密兑换生成的余额和直接充值的余额在系统里是同一种资产,不存在「充值余额」和「赠送余额」的隔离。这意味着如果你用了「注册赠送余额」功能,赠送的余额和充值余额混在一起。如果你后续要搞活动、限制赠送余额不可提现或不可用于某些接口,需要自己在业务层加标记,这个版本的原生逻辑不区分资产来源。
2.3 实名与手机号校验在什么环节生效
系统支持实名认证和绑定手机号校验,但很多管理员不知道这两个校验在什么环节强制、什么环节可选。我实测后的结论是:
- 手机号绑定:注册时可选绑定,也可以在用户中心后补。绑定后,涉及敏感操作(如修改支付密码、提现)会强制要求短信验证码。
- 实名认证:仅在管理员开启「接口需要实名认证」时才强制校验。未实名的用户调用该接口会被拦截,返回固定的错误码。
这个设计对 API 开放场景是够用的。但如果你想做「未实名用户不能充值」这种强约束,原生系统做不到,得自己改注册逻辑。这也是我后来放弃在实名上做太多文章的原因——这个项目的重心在计费和接口管理,用户认证只是基础设施,别指望它达到金融级 KYC 的水平。
3. 部署与初始化:从源码包到跑通首笔扣费
部署环境我推荐 LNMP(Linux + Nginx + MySQL + PHP),这套系统的前端资源(layui、bootstrap、summernote 等)和后台管理让它跑在 PHP 环境里最顺。下面按源码部署方式写,这也是 DIY 属性最强的路径。
3.1 环境清单与目录结构
我用的环境版本:Ubuntu 22.04、Nginx 1.24、MySQL 8.0、PHP 8.1(需要安装 pdo_mysql、fileinfo、opcache 扩展)。把源码包解压到/var/www/oneapi-billing后,有三个关键目录需要先认出来:
/var/www/oneapi-billing ├── public/ # Web 根目录,Nginx 要指向这里 ├── app/ # 业务代码,含计费逻辑 ├── config/ # 数据库、缓存、邮件配置 ├── storage/ # 日志、缓存、上传的 API 文件 └── database/ # SQL 初始化脚本3.2 初始化数据库与配置文件
第一步修改.env.example为.env,填入数据库连接信息:
cp .env.example .env # 编辑 .env,核心参数如下: DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=oneapi_billing DB_USERNAME=youruser DB_PASSWORD=yourpassword APP_URL=https://api.yourdomain.com保存后导入初始 SQL:
mysql -uyouruser -p oneapi_billing < database/oneapi_billing.sql注意:如果你用的是 MySQL 8.0,导入 SQL 时如果报错Row size too large,通常是因为表默认用 utf8mb4 且字段过多。解决办法是在导入前把 SQL 文件里的utf8mb4替换为utf8mb4_general_ci或把默认字符集改成utf8mb4的ROW_FORMAT=DYNAMIC。这个坑只在 8.0 版本出现,5.7 没这个问题。
3.3 Nginx 配置与伪静态规则
管理后台的 URL 走的是重写路由,务必配置伪静态,否则页面全部 404:
server { listen 80; server_name api.yourdomain.com; root /var/www/oneapi-billing/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } }配好之后systemctl reload nginx,浏览器打开后台地址,用 SQL 文件里的初始管理员账号登进去,第一步会强制让你改管理员密码。到这一步系统就能访问了,但先别急着创建接口——先去「站点设置」里把站点名称、备案号、客服联系方式填上,这些信息会直接显示在用户端页面上,不然后面用户注册了看到一堆占位符,体验很差。
4. 扣费逻辑与防刷机制:1.2.0 版本的关键改动
这一章是 1.2.0 版本更新的重点,也是这个资源最值钱的部分。上一个大版本被人诟病的「特定值扣费逻辑」和「验证码可刷」两件事,在这个版本都动了刀。
4.1 特定值扣费逻辑修复了什么
先解释「特定值」是什么。计费系统的扣费公式通常是「扣费金额 = 单价 × 本次调用消耗的计费单位」。如果接口按 token 数或字数计费,调用方传入一个use_count参数,系统通过这个值计算扣费。1.2.0 之前的问题出在边界值判断上——当传入值为负数、0、超大整数或带小数时,系统直接按默认单价扣费,导致很多「调用返回值异常」的请求也扣了全款,场面一度很混乱。
这次修复后的扣费判断逻辑我拆出来是这个思路:
// 计费核心:校验传入的计费数值 public function calcDeduction($unitPrice, $useCount, $resourceQuota) { // 1. 异常值直接拒绝,不算扣费 if (!is_numeric($useCount) || $useCount <= 0) { return [ 'status' => 'rejected', 'reason' => 'invalid_use_count', 'deduct' => 0 ]; } // 2. 转为整数,防止小数精度问题导致多扣 $useCountInt = (int) floor($useCount); if ($useCountInt !== (int) $useCount) { // 非整数时按整数部分计费,余数丢弃 // 这是因为 API 场景里按次消费应是离散值 } // 3. 判断资源包余量是否足够 if ($resourceQuota < $useCountInt) { return [ 'status' => 'insufficient', 'reason' => 'quota_exceeded', 'deduct' => 0 ]; } // 4. 正常扣费 $deductAmount = $unitPrice * $useCountInt; return [ 'status' => 'success', 'deduct' => $deductAmount, 'remaining' => $resourceQuota - $useCountInt ]; }这段代码揭示了三个关键行为:异常数值不扣费直接拒绝、小数一律取整再乘单价、资源包余量不足时整单拒绝而不是扣成负数。这三个边界修复了上一版本「扣费金额跟实际用量对不上」的主要来源。如果你要自己改费率策略,这层逻辑是唯一需要动刀的地方,别去碰更底层的流量统计,那部分和扣费无关。
4.2 邮箱/短信验证码防刷的限流参数
上一版本最头痛的问题:攻击者用脚本批量请求发送验证码接口,导致短信通道被打爆、邮箱被塞满垃圾邮件。1.2.0 引入了防刷机制,配置入口在「系统设置 → 验证码设置」,核心参数有四个:
| 参数 | 我的推荐值 | 说明 |
|---|---|---|
| 同一 IP 发送间隔 | 60 秒 | 低于 60 秒直接拒绝第二次发送 |
| 同一账号每日发送上限 | 10 条 | 防止通过频繁触发找回密码刷爆通道 |
| 同一手机号/邮箱每日上限 | 5 条 | 防止针对单一用户轰炸 |
| 图形验证码开关 | 开启 | 发送前必须完成图形验证码 |
这里最值得说的是图形验证码开关一定要开。单纯依赖频率限制有绕过的空间——攻击者用代理池换 IP,就能绕开 IP 限制。加上图形验证码之后,每个发送请求都被前置拦截,脚本根本走不到发送验证码那一步。我自己的部署里把 IP 间隔从默认的 30 秒改到了 60 秒,因为发现凌晨有规律性的试探请求,60 秒能把单 IP 的探测频率压到一个很低的水平。
4.3 注册赠送余额的规则配置
「注册赠送余额」是这次新增的功能,配置在「用户设置」里,支持两个参数:赠送金额和启用开关。
# 配置示例 REGISTER_BONUS_ENABLED=true REGISTER_BONUS_AMOUNT=1.00注意:赠送的余额在数据库里和充值余额同属一个余额字段,所以如果你开启了这个功能,需要考虑羊毛党的成本。我后来补了一个限制——新注册用户当日消费上限设为 5 元,防止有人批量注册然后清空赠送余额调用高价接口。这个限制在原生后台没有,是我自己在外层拦截层加的。如果你的赠送金额大于 1 元,强烈建议你评估一下接口的单价水平,别让赠送金额超过单次调用成本。
5. 常见问题排查:部署与异常计费的五条记录
我把搭建和试运行期间踩的坑整理成故障记录,按「现象 → 原因 → 解决」写,后面的人照着对照,能省很多时间。
5.1 后台登录后页面空白
现象:管理员账号能登录,但跳转后全白页,浏览器控制台报 500。原因:PHP 的storage/logs和storage/cache目录没有写权限,框架在写入日志时异常退出。解决:chown -R www-data:www-data /var/www/oneapi-billing/storage,然后chmod -R 755。这是 PHP 项目最常见的环境类问题,优先检查目录权限,不要先怀疑代码。
5.2 接口请求后返回 401 但在后台看到调用成功了
现象:用户侧调用返回未授权,但后台统计里看到次数增加了。原因:接口配置了「需要实名认证」,用户未实名时请求被拦截,但仍然被计入总调用量。也就是说这个 401 的请求被统计为「发起」而不是「成功」。解决:在统计报表里区分「请求数」和「成功数」。后台列表默认显示请求数,要看成功付费的请求需要切换到明细模式。这个坑属于产品定义问题,不是 bug,但对账时容易产生误解。
5.3 卡密批量生成后有一个面额错了
现象:批量生成了 100 张 10 元卡密,发现其中一张应该是 50 元。原因:生成卡密时不支持单张改面额,修改只能删除后重新生成。解决:在数据库里查cards表,找到那张卡密,直接改amount字段。注意这个操作不会留下操作日志,自己改完要在备注里记录。
5.4 注册赠送余额到账延迟超过一分钟
现象:新用户注册后看不到赠送余额,最迟延迟了 90 秒。原因:系统走队列异步发放,队列进程没跑或者 crontab 没配置。解决:配置定时任务:* * * * * php /path/to/artisan schedule:run。这是个定时调度命令,不是发送验证码的队列命令。如果还不生效,检查.env里的QUEUE_CONNECTION=database是否为这个值,如果是sync则队列不会独立执行。
5.5 扣费记录金额比单价多了一倍
现象:单价 1 元的接口,一次调用扣了 2 元。原因:接口配置里同时开了「资源包扣费」和「余额扣费」,请求被两次扣费。具体说,资源包扣费成功后系统又执行了一次余额扣费,因为逻辑上把「资源包不可用」判断放在了「资源包扣费成功」之后,导致重复扣。解决:直接升级到 1.2.0,这个版本修了特定值扣费逻辑后,这类重复扣费基本绝迹。如果还出现,检查接口配置里是否把「资源包扣费」和「余额扣费」两个开关同时开启,通常只开一个。
6. 进阶:API 文档在线编辑与扣费规则的验证方法
系统自带 API 文档在线编辑和代码在线编辑功能。文档编辑器基于 summernote,直接嵌在后台,可以加说明、示例请求、响应参数表。代码编辑器则允许直接修改接口的接入示例代码(PHP、Python、JS 三种语言),改完即时生效。这个功能的实际价值是省掉「文档维护→部署→同步」的环节,对一个人维护多个 API 的场景非常省事。
但要注意权限控制:给编辑权限的角色只有超级管理员,普通管理员只能查看。如果你要给某个同事开放编辑权,需要在「角色管理」里重新分配,默认角色不含这个权限。我个人建议保持默认设置,因为在线编辑直接改的是对外展示的代码和文档,一旦有人误操作改了计费示例代码,调用方会照着错的示例接,排查成本极高。
最后给一套我自己验证计费规则是否生效的完整动作,每次都走一遍:
# 1. 在后台创建测试用户,充值 10 元 # 2. 创建测试接口,单价 2 元/次,计费类型设为余额扣费 # 3. 用测试用户的 key 调用接口 5 次 # 4. 查看扣费流水,确认扣费金额 = 2 × 5 = 10 元且余额为 0 # 5. 再调用第 6 次,确认返回余额不足错误 # 6. 把第 1 步改为充值 9.9 元,重复 2-5,验证小数金额不会四舍五入成整数扣费 # 7. 到用户中心查看资源包剩余额度,确认数值与流水记录一致这套验证看起来简单,但几乎每次改完扣费逻辑都能查出点东西来——要么是余额判断边界差一分钱,要么是资源包余量显示和实际不符。从那以后,我每次改完计费规则都强制自己走一遍测试接口 → 查扣费流水 → 看资源包快照的流程,这套流程救了我至少三次对账事故。希望帮到你。
本文还有配套的精品资源,点击获取