缘起:一个"查余额"的痛点

事情的起点很朴素——我手上有几个 AI 平台的订阅,每个月有固定的配额。每次想知道还剩多少,都得打开浏览器、登录控制台、点好几个页面才能看到。烦。

更烦的是,有些平台的控制台把用量信息藏在很深的菜单里,手机上根本没法查。作为一个把"自动化一切"当人生信条的人,这事儿忍不了。

于是就有了这个项目——Quota Pulse。名字很直白:像脉搏一样实时跳动,告诉你配额还剩多少。功能也很明确:自动抓取各 AI 平台的 Token Plan 剩余量,集中展示在一个页面上,支持本地和远程访问。

技术选型:为什么是"本地 + 公网"双模

需求很明确,但实现路径有好几条。我最终选了 本地服务 + 公网代理 的混合架构,理由如下:

核心思路: 本地跑采集逻辑(安全、不受限),公网只暴露只读的展示层(不暴露任何凭证和原始接口)。

架构组成:

  • 本地服务:Node.js + Express,定时任务 + 数据缓存
  • 数据采集层:HTTP 直连 + 浏览器自动化兜底
  • 凭证隔离:环境变量注入,零硬编码
  • 公网暴露:内网穿透,轻量页面

爬虫实战:两种采集策略

API 用量数据不是公开的——它需要身份认证。这就意味着爬虫必须模拟登录态去请求平台的后端接口。

我面对的是两类平台,策略也不同:

平台类型 采集方式 难度 风险
提供用量查询 API HTTP 请求直连,携带认证头 低 频率控制、凭证泄露
无公开用量 API 浏览器自动化登录 → 解析页面 → 提取数据 高 验证码、页面结构变更、会话过期

策略一:HTTP 直连

对于有开放用量接口的平台,流程非常简单——发一个带认证头的 GET 请求,解析 JSON 响应,提取剩余量和重置时间。

// 核心逻辑(脱敏后)
const resp = await fetch(USAGE_ENDPOINT, {
  headers: { 'Authorization': `Bearer ${process.env.API_KEY}` }
});
const data = await resp.json();
return {
  remaining: data.remaining_quota,
  resetAt: data.reset_time,
  percentage: data.usage_percentage
};

这里的关键原则:任何凭证(Key、Token、ID)都不出现在代码中,全部通过 .env 文件注入,且 .env 被 .gitignore 排除。代码仓库里零敏感信息。

策略二:浏览器自动化

有些平台没有公开的用量 API,数据嵌在管理后台的页面里。这时候就得祭出无头浏览器了。

流程是:自动打开登录页 → 填入凭证 → 处理可能的验证码(由人工介入)→ 导航到用量页面 → 解析 DOM 提取数据。

⚠️ 安全边界: 验证码环节不尝试自动破解——这是明确的红线。遇到验证码时,程序挂起等待人工处理。自动化不是为了绕过安全机制,而是减少重复劳动。

数据流设计

整个系统的数据流动如下:

定时任务触发 → 采集模块(HTTP / 浏览器)→ 数据清洗 & 脱敏 → 本地缓存(内存 + 文件)→ 展示 API(只读)→ 前端页面

几个设计要点:

  • 采集与展示分离: 采集层有完整凭证权限,展示层只有只读的数据读取权限。两个模块运行在同一个进程里,但代码边界清晰——展示 API 永远不转发请求到外部平台。
  • 缓存降级: 采集失败时不报错,返回上一次成功缓存的数据并标注"数据可能过期"。用户体验不受单次故障影响。
  • 频率控制: 每个平台的采集间隔独立配置(5~30 分钟),避免对上游造成压力或被限流。

安全设计:三道防线

一个要处理 API 凭证、又要暴露到公网的项目,安全不是可选项。我设计了三道防线:

防线 措施 防护目标
第一道:代码层 零硬编码凭证;.env 不入库;日志脱敏(自动替换敏感字段) 防止源码泄露导致凭证外泄
第二道:传输层 HTTPS 强制;内网穿透隧道加密;展示 API 不代理任何外部请求 防止中间人攻击、SSRF
第三道:访问层 展示页面无写入能力;API 仅返回聚合后的只读数据;无原始接口路径暴露 防止通过展示层反推凭证或攻击上游

额外一提:日志系统做了全局脱敏处理——任何匹配到凭证格式(如特定前缀的字符串)的输出,自动替换为 [REDACTED]。这样即使日志不小心被分享出去,也不会泄露敏感信息。

部署方案:内网穿透的正确姿势

本地服务跑在开发机上(Windows),公网访问通过内网穿透实现。选型上对比了几个方案:

方案 优点 缺点 适用场景
frp / ngrok 简单快速,一行命令 依赖第三方服务;稳定性不可控 临时演示
Cloudflare Tunnel 免费、自带 HTTPS、不限流量 需要自有域名;国内延迟偏高 个人长期使用
自有公网服务器 + 反向代理 完全可控、延迟最低 需要服务器成本;运维复杂 生产环境

我最终选了 Cloudflare Tunnel 作为公网通道——零成本、自带证书、配置简单。在本地启动 tunnel 客户端后,一个随机子域名就映射到了本地的 3000 端口。

# 启动隧道(脱敏后)
cloudflared tunnel --url http://localhost:3000

# 输出:
# +--------------------------------------------------------------------------------------------+
# |  Your quick tunnel has been created!                                                        |
# |  https://xxxx-xxxx-xxxx.trycloudflare.com  →  http://localhost:3000                         |
# +--------------------------------------------------------------------------------------------+

公网访问的只是展示页面——一个静态 HTML 配上几个 AJAX 请求,从本地只读 API 拉取缓存的用量数据。公网侧永远接触不到任何外部平台的接口或凭证。

总结与反思

这个项目从构思到上线大概花了一个周末,但从中沉淀的经验远不止一个工具本身:

  1. 爬虫不是"能爬就行"—— 区分"有 API 的平台"和"没有 API 的平台",用不同的策略,能省大量维护成本。HTTP 直连远比浏览器自动化稳定。
  2. 安全的本质是"最小暴露"—— 不是把所有东西锁起来,而是让每一层只接触它需要接触的信息。展示层不需要凭证,那就永远不传给它。
  3. "本地 + 公网"的混合架构在个人工具场景下非常实用—— 享受本地的灵活性和安全性,同时拥有公网的便利性。两全其美。
  4. 验证码是红线—— 自动化可以帮你省时间,但不能帮你突破安全机制。遇到验证码,停下来,人工处理。这是原则问题。

最后,Quota Pulse 这个名字——配额脉搏——恰好概括了这个工具的本质:不复杂、不花哨,但它跳动的时候,你就知道一切都在运转。


本文所有凭证、Key、Token、接口路径均已脱敏处理 · 技术细节仅作架构参考