SSL证书检测API的调用限制与用量边界:QPS、缓存与错误处理详解
适用场景
SSL证书检测API适用于以下典型场景:
- 域名证书到期监控:定时检测业务域名的证书有效期,提前预警即将过期的证书,避免服务中断。
- 安全检查与合规审计:自动化检查域名是否启用了SSL/TLS,验证证书链是否完整、签名算法是否符合安全标准。
- 运维告警联动:将检测结果接入告警系统(如Prometheus + Alertmanager),在证书过期前发送通知。
- CDN/云厂商证书管理:批量检测多个域名的证书状态,辅助证书更换或续费决策。
在这些场景中,调用频率、缓存时效、错误容忍度都是影响系统稳定性的关键因素。本文将重点围绕该API的调用限制与用量边界展开,帮助开发者制定合理的请求策略。
接口能力边界
请求方式与地址
- 接口名称:SSL 证书检测
- 请求方法:GET
- 请求地址:
https://v1.apizero.cn/api/ssl - 分类:开发工具
核心限制参数
| 限制类型 | 数值 | 说明 |
|---|---|---|
| QPS(每秒请求数) | 5 | 单个客户端每秒内允许的并发请求上限,超出后可能返回429或连接超时。 |
| 成功响应缓存 | 6小时 | 对于成功获取证书信息的域名,结果会被缓存6小时,同一域名在缓存期内再次请求直接返回缓存数据,不计入QPS?需注意缓存命中仍消耗请求次数(文档未明确),但响应更快。 |
| 失败响应缓存 | 30分钟 | 对于无证书或连接失败的域名,结果缓存30分钟,避免短时间内重复请求无效域名,浪费上游资源。 |
| 匿名调用限额 | 每天30次 | 未携带Authorization头的请求视为匿名调用,每天累计30次。超出后需传入有效API Key才能继续。 |
提示:虽然缓存可以降低上游压力,但每个域名在缓存失效前请求会直接从缓存返回,此时不消耗QPS配额(推测,但建议以实际测试为准)。若需实时检测,可通过添加随机参数绕过缓存(但需注意API服务条款)。
响应三态模型
API针对不同情况返回三种响应结构:
- 有SSL证书:
is_ssl = true,data字段包含完整的证书信息。 - 无SSL或连接失败:
is_ssl = false,其余data内字段均为null(例如域名未部署TLS)。 - 上游异常:HTTP状态码502,
code可能为非0,表示后端服务器无法完成请求(如DNS解析失败、上游超时)。
理解这三态有助于在工程层面区分业务逻辑错误与系统级错误。
请求参数详解
Query 参数
| 参数名 | 必填 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
domain | 是 | string | 待检测的域名。API会自动剥离http(s)://前缀、路径、端口、www.子域,仅保留根域名。长度不得超过253字符,且须符合RFC 1123标签规则。 | apizero.cn |
Header 参数
| 参数名 | 必填 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
Authorization | 否(匿名可用) | string | API Key鉴权头,格式为Bearer sk_live_xxx。匿名调用时省略,但受每日30次限制。 | Bearer sk_live_xxxxxxxxxxxxxx |
注意:素材中的cURL示例使用了
X-API-Key头发送密钥,实际两套鉴权方式可能并存。为减少混淆,下述示例统一使用Authorization: Bearer方式,与官方Header说明一致。如果你正使用X-API-Key,请按原样保留。
cURL示例与代码接入
基础cURL示例(匿名调用)
curl -sS \ -X GET \ "https://v1.apizero.cn/api/ssl?domain=apizero.cn"注意:匿名调用每日仅30次,生产环境请务必添加API Key。
带API Key的cURL示例
curl -sS \ -X GET \ -H "Authorization: Bearer YOUR_API_KEY" \ "https://v1.apizero.cn/api/ssl?domain=apizero.cn"Python接入示例
import requests import json API_URL = "https://v1.apizero.cn/api/ssl" API_KEY = "sk_live_xxxxxxxxxxxxxx" # 替换为实际密钥 def check_ssl(domain: str) -> dict: """检测指定域名的SSL证书信息""" headers = { "Authorization": f"Bearer {API_KEY}" } params = { "domain": domain } resp = requests.get(API_URL, headers=headers, params=params, timeout=10) resp.raise_for_status() # 非2XX抛出异常 return resp.json() # 调用示例 result = check_ssl("apizero.cn") print(json.dumps(result, indent=2, ensure_ascii=False))Java (OkHttp) 示例片段
OkHttpClient client = new OkHttpClient(); String url = "https://v1.apizero.cn/api/ssl?domain=apizero.cn"; Request request = new Request.Builder() .url(url) .addHeader("Authorization", "Bearer sk_live_xxxxxxxxxxxxxx") .build(); try (Response response = client.newCall(request).execute()) { System.out.println(response.body().string()); } catch (IOException e) { e.printStackTrace(); }返回字段解读
成功响应(HTTP 200)的JSON结构如下:
{ "code": 0, "msg": "成功", "request_id": "abc123def456", "data": { "common_name": "*.apizero.cn", "domain": "apizero.cn", "domains": ["*.apizero.cn", "apizero.cn"], "expire_date": "2026-11-07 17:04:59", "expire_days": 184, "fingerprint": "f4633adfd1cb59185ba094dc3edeef5a8ea26889", "is_expired": false, "is_ssl": true, "issuer": "Certum DV TLS G2 R39 CA", "issuing_agency": "Asseco Data Systems S.A.", "life_span_days": 198, "remote_address": "119.36.225.184:443", "signature_algorithm": "RSA-SHA256", "start_date": "2026-04-22 17:05:00" } }字段详解
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 业务状态码,0表示成功;非0表示错误(具体错误码见文档)。 |
msg | string | 与code对应的文字描述。 |
request_id | string | 请求唯一标识,可用于日志追踪。 |
data.common_name | string | 证书的通用名称(Common Name),通常为*.域名或具体域名。 |
data.domain | string | 传入的域名(经过预处理后)。 |
data.domains | string[] | 证书覆盖的所有域名(Subject Alternative Names)。 |
data.expire_date | string | 证书到期时间,格式YYYY-MM-DD HH:mm:ss。 |
data.expire_days | int | 距离到期的天数(从请求时刻计算)。 |
data.fingerprint | string | 证书的SHA-1指纹,40位十六进制。 |
data.is_expired | bool | 是否已过期。 |
data.is_ssl | bool | 是否成功检测到SSL证书。若为false,则data内其他字段均为null。 |
data.issuer | string | 证书颁发机构(CA)。 |
data.issuing_agency | string | 颁发机构实体。 |
data.life_span_days | int | 证书有效期总天数(从start_date到expire_date)。 |
data.remote_address | string | 检测目标IP地址及端口。 |
data.signature_algorithm | string | 签名算法,如RSA-SHA256。 |
data.start_date | string | 证书开始生效时间。 |
当is_ssl=false时,data内的其他字段均为null,例如:
{ "code": 0, "data": { "is_ssl": false, "domain": "nonexistent-ssl.example.com", "common_name": null, "expire_date": null, "expire_days": null, ... (其他字段均为null) } }常见错误与状态码
| HTTP状态码 | 业务code | 说明 | 处理建议 |
|---|---|---|---|
| 200 | 0 | 成功(可能含is_ssl=false) | 正常处理 |
| 400 | 1xxx | 参数错误,如domain缺失或格式非法 | 检查域名是否符合RFC 1123;使用前建议先做本地正则校验 |
| 401 | 2xxx | 鉴权失败,API Key无效或过期 | 检查Authorization头格式是否正确,Key是否有效 |
| 429 | 3xxx | 请求频率超限(QPS > 5) | 实施指数退避重试;控制并发数 |
| 502 | 5xxx | 上游服务器异常(如DNS解析失败、目标服务器不可达) | 该错误通常为瞬时性,可重试2-3次;注意区分与业务无证书的区别 |
注意:具体错误码(如
1001、2002等)以官方文档为准,素材未列出完整错误码表,生产环境建议查阅文档页。
工程化注意事项
1. 缓存策略利用
- 成功缓存6小时:证书信息短期不变,对于监控场景,可以设置为每5小时检测一次,既满足数据新鲜度,又减少请求。
- 失败缓存30分钟:对于无证书的域名,缓存期内无需重复请求。若业务上需要更频繁探测(例如刚部署了证书),可通过添加随机参数(如
_t=timestamp)强制跳过缓存(但需遵守API使用条款)。
2. QPS 并发控制
QPS上限为5,意味着每秒最多发送5个请求。如果业务需要检测大量域名(如100个),应使用限流工具(如Guava RateLimiter、Resilience4j)控制请求速率:
import time import requests from ratelimit import limits, sleep_and_retry @sleep_and_retry @limits(calls=5, period=1) def rate_limited_check(domain): return check_ssl(domain) # 批量检测 domains = ["example1.com", "example2.com", ...] for d in domains: result = rate_limited_check(d) # 处理结果3. 错误重试策略
- 非2XX响应:对于429、502、5xx等错误,建议采用指数退避重试,初始延迟1秒,最大延迟60秒,最多重试3次。
- 连接超时:设置合理的超时时间(建议10秒),避免长时间阻塞。
- 业务逻辑错误:如
code != 0且不是限流错误,可能为参数问题,不应重试,应记录日志并人工介入。
4. 响应数据校验
由于API返回的字段类型可能为null或自动转换(如is_expired为布尔),客户端要做好空值检查:
if result.get("data") and result["data"].get("is_ssl"): expire_days = result["data"]["expire_days"] if expire_days is not None and expire_days < 30: # 发送告警5. 域名预处理
API虽然会自动处理域名,但客户端最好也做初步清洗:去除协议头、路径、端口、www.,并校验合法域名格式。这样可以避免因错误输入导致无效请求浪费QPS额度。
import re def sanitize_domain(raw: str) -> str: # 移除协议、路径、端口 domain = re.sub(r'^(https?://)?(www\.)?', '', raw.split('/')[0].split(':')[0]) if not re.match(r'^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', domain): raise ValueError(f"Invalid domain: {domain}") return domain6. 匿名调用额度管理
匿名调用每日30次,适合开发测试或低频小工具。生产环境应准备API Key,避免因额度耗尽导致服务中断。建议在代码中配置Key,并通过环境变量注入:
export SSL_API_KEY="sk_live_xxxxxxxxxxxxxx"然后在代码中读取:
import os API_KEY = os.getenv("SSL_API_KEY", "")参考文档
- API文档页:https://apizero.cn/aidocs/ssl
- 原始文档(Markdown):https://apizero.cn/aidocs/ssl/raw.md
- 错误码与详细参数请以上述文档为准。
