开发者手记:Whois 域名查询接口从请求到返回的完整拆解
什么时候会用到 Whois 查询接手一批存量域名时第一件事往往不是调整解析而是先把每个域名的准备商、到期时间、域名状态摸清楚。域名的创建时间、准备主体、DNS 服务器这些基础信息通常被记录在 Whois 数据库中。除此之外在没有接入准备商接口的情况下想要判断一个未准备域名是否可准备、或是在批量盘点域名资产时快速筛出 30 天内到期的域名Whois 查询都是一个直接可用的数据入口。接口定位能查什么、不能查什么Whois 域名查询接口只做一件事输入一个域名返回该域名当前的准备信息快照。它支持 .com、.cn、.net、.org、.io、.me、.top、.xyz 等主流 TLD覆盖范围以 ICANN 认证后缀为准。接口在进入查询之前会做一次归一化处理传https://www.baidu.com/abc、http://baidu.com:8080甚至www.baidu.com都会被剥离成baidu.com再查询。这意味着调用方不需要在业务层做 URL 解析直接把原始输入传过去即可。值得留意的能力还有三个。第一未准备域名会返回is_availabletrue可用于预准备前的可用性判断第二30 天内到期的域名会返回expiring_soontrue便于前端展示到期高亮第三上游对国内域名会返回中文准备主体例如「极数本源福州科技有限公司」这样的名称省去自行做中文标注的步骤。接口不提供历史 Whois 变更记录也不解析域名下的 DNS 记录内容这些不属于该接口的职责范围。鉴权与请求地址接口是标准的 GET 请求请求地址https://v1.apizero.cn/api/whois请求方法GET鉴权方式请求头携带X-API-Key值为调用方自己的 API KeyQPS 限制5 次/秒超出后需要等待或做本地限速domain是唯一必填参数类型为字符串with_raw是可选布尔参数控制是否返回原始 Whois 文本约 3KB默认关闭建议只在调试时开启。使用 curl 发起第一次查询在终端中先将 API Key 写入环境变量再按下面的方式发起请求export APIZERO_API_KEYyour_api_key_here curl -sS \ -X GET \ -H X-API-Key: $APIZERO_API_KEY \ https://v1.apizero.cn/api/whois?domainbaidu.com返回结果是一个 JSON 数组数组中第一个元素携带example字段里面就是完整的响应体。实际调用时响应体结构为{ code: 0, msg: 成功, data: { domain: baidu.com, is_available: false, registrar: MarkMonitor Information Technology (Shanghai) Co., Ltd., creation_age_text: 26 年 7 个月, expiring_soon: false }, request_id: abc123def456 }code 0表示业务成功request_id可用于排查单次请求的链路问题。使用 Python 跑通一次查询在没有 curl 的环境中用 Python 的requests库也可以快速验证接口import requests resp requests.get( https://v1.apizero.cn/api/whois, params{domain: baidu.com}, headers{X-API-Key: your_api_key_here}, timeout10, ) payload resp.json() if payload[code] 0: data payload[data] print(data[registrar]) print(data[expiration_time]) print(data[expiring_soon]) else: print(payload.get(error, payload.get(msg)))这里刻意使用了payload.get(error, payload.get(msg))的写法原因在后文错误处理部分说明。返回字段逐一拆解响应体中的data对象是核心字段大致分两类。第一类是准备信息字段类型说明domainstring归一化后的域名suffixstring顶级后缀如comregistrarstring准备商名称whois_serverstring该域名的 Whois 服务器creation_timestring创建时间北京时区expiration_timestring到期时间registrantstring准备主体registrant_emailstring准备邮箱name_serversstring[]当前 DNS 服务器列表registrar_abuse_emailstring准备商滥用举报邮箱registrar_abuse_phonestring准备商滥用举报电话registrar_urlstring准备商官网地址第二类是状态与辅助字段字段类型说明domain_statusstring[]域名状态如clientTransferProhibiteddnssecstringDNSSEC 签名状态常见值为unsignedis_availableboolean是否未准备is_expiredboolean是否已过期expiring_soonboolean是否 30 天内到期creation_age_textstring域龄人类可读字符串如「26 年 7 个月」creation_daysnumber创建至今的天数valid_daysnumber距离到期的剩余天数query_timestring本次查询的服务端时间用baidu.com为例响应中registrar为 MarkMonitor Information Technology (Shanghai) Co., Ltd.creation_time为 1999-10-11expiration_time为 2028-10-11expiring_soon为 false。若查询一个不存在的域名is_available会变为 true此时registrar等准备信息字段通常为空。注意registrant和registrant_email在部分 TLD 或隐私保护开启时可能返回空字符串这不代表接口异常。高频异常与排查顺序接入过程中遇到问题建议按下面的顺序排查。第一检查 HTTP 状态码与请求格式。如果返回 4xx优先确认domain参数是否传了、URL 是否拼接正确、X-API-Key头是否携带。请求地址必须以https://开头domain的值不需要做 URL 编码之外的额外处理。第二检查响应体中的业务错误。该接口的业务错误字段是error而不是message。如果只读取msg可能拿不到上游真正返回的错误原因。这就是前面 Python 示例中同时尝试error和msg的原因。第三确认域名状态本身的含义。is_availabletrue是查询成功的一种正常结果不是错误域名可能处于clientHold或clientTransferProhibited状态这些会如实反映在domain_status数组中不影响接口本身的可用性。如果 QPS 超过 5 次/秒服务端可能返回限流错误此时应降低请求频率或增加本地退避而不是盲目重试。工程化落地建议在真实业务中接入该接口有几点建议。第一利用服务端缓存。接口对同一域名全天只调用一次上游并缓存 24 小时客户端不需要为了获取“最新”数据而反复请求同一个域名。域名准备信息是低频变化数据日级刷新完全够用。第二在本地再做一层应用缓存。结合 QPS 5 次/秒的限制批量盘点几千个域名时建议先查本地缓存再对未命中的域名做限速请求避免触发限流。第三把expiring_soon和valid_days用起来。这两个字段可以直接驱动到期告警逻辑不必在业务侧自行计算“今天距离到期还有几天”。第四生产环境不要开启with_raw。原始 Whois 文本约 3KB对多数业务场景无用还会增加响应体积与解析维护复杂度。参考文档接口文档https://apizero.cn/aidocs/whois原始文档https://apizero.cn/aidocs/whois/raw.md