- 作者帖子
现象
使用彩虹 DNS 面板 (dnsmgr v2.16,基于 ThinkPHP 6) 的 API 删除或修改 DNS 记录时,始终返回 「域名不存在」 错误,但同一凭据调用查询接口完全正常。
API 路径格式:
POST /api/record/delete/{domain_id},POST body 带id={record_id}。这个问题困扰了好几个会话,期间尝试过:
- 检查签名算法 → 正确 (
md5(uid + timestamp + apikey)) - 检查 domain_id 是否正确 → 正确 (和 list 接口用的同一个)
- 检查权限 → 查询正常,排除权限问题
百思不得其解。
原因分析
最终拿到 dnsmgr 源码才定位到根因。关键在 ThinkPHP 的参数解析机制。
控制器代码 (Domain.php)
// record_delete 方法 public function record_delete($id) { // $id 来自路由 /api/record/delete/:id,是域名的内部 ID $domain = DomainModel::where('id', $id)->find(); // ... $recordid = input('post.recordid'); // 注意:这里取的是 recordid,不是 id // ... }路由定义 (route/app.php)
Route::post('/api/record/delete/:id', 'Domain/record_delete');问题所在
ThinkPHP 的
input('param.id')解析顺序是:路由参数 → GET → POST 。当我们用
POST /api/record/delete/364且 body 带id=2028144566343693312时:- 路由参数
:id= 364(域名 ID)✓ - 但 POST body 也有
id字段,ThinkPHP 的 param 解析会让 POST 的id覆盖路由的:id - 控制器拿到的
$id变成了2028144566343693312(记录 ID) - 拿记录 ID 去域名表查 → 当然查不到 →「域名不存在」
而控制器里取记录 ID 用的是
input('post.recordid')——参数名是 recordid,不是 id 。同样的问题存在于 record_update
public function record_update($id) { $domain = DomainModel::where('id', $id)->find(); $recordid = input('post.recordid'); // 同样是 recordid // ... }解决方案
将所有脚本中 delete 和 update 调用的参数从
&id=改为&recordid=:# 修复前 (错误) _dns_api "/api/record/delete/${domain_id}" "&id=${record_id}" # 修复后 (正确) _dns_api "/api/record/delete/${domain_id}" "&recordid=${record_id}" # update 同理 _dns_api "/api/record/update/${domain_id}" "&recordid=${record_id}&name=..."验证结果
修复后完整测试:添加测试记录 → 查询确认 → 删除 → 再次查询确认已清除,全流程通过。
经验总结
- API 文档不全时读源码是最可靠的排查手段。这个 bug 纯靠黑盒调试很难定位,因为错误信息 「域名不存在」 有误导性——它暗示 domain_id 有问题,但实际是参数名写错导致 domain_id 被覆盖
- ThinkPHP 的 param 解析顺序(路由 → GET → POST) 是个常见坑。 POST body 中的字段名如果和路由参数名撞了,会产生意想不到的覆盖
- 当多个接口用同一个参数名 (
id) 表示不同含义时,容易出歧义。 dnsmgr 的设计是路由用:id表示域名,POST 用recordid表示记录,避开了命名冲突——但如果调用方不知道这个约定,自然会踩坑
- 检查签名算法 → 正确 (
- 作者帖子
Cyberforums · 原文 · Markdown
想回复或继续讨论?请到 Cyberforums 赛博论坛参与。
参与讨论 / 回复