全部项目

Case Study

Chrome 插件 Node 服务

连接浏览器插件与业务 API 的中间层:无感登录、实时推送与 Go 重构带来的 85% 性能提升。

-85%

接口耗时(800→120ms)

-60%

高频查询响应

-83%

发布耗时(30→5min)

背景

内部运营团队每天要在多个后台之间复制粘贴数据,团队里一名工程师每天大约浪费 30 分钟在重复操作上。我们做了一个 Chrome 插件承接这些操作,但插件不能直接持有业务系统的凭证:于是需要一层中间服务,负责无感登录、权限校验、数据聚合与实时指令下发。

我的角色

  • 基于 Midway.js + TypeScript 开发中间层服务,作为插件与后端 API 之间的唯一通道。
  • 设计无感登录与凭证托管方案,覆盖 10+ 名团队成员。
  • 用 WebSocket 支撑实时数据推送与指令下发。
  • 针对 JSON 解析瓶颈,用 Go 重写核心模块。

关键设计

1. 无感登录:凭证留在服务端

插件只持有一个短期会话 token,业务系统的凭证由服务端加密保存并在请求时注入。会话过期时服务端自动续期,插件无需感知:

@Provide()
export class SessionService {
  async resolve(userId: string): Promise<Credentials> {
    const cached = await this.redis.get(`session:${userId}`);
    if (cached) return JSON.parse(cached);

    const credential = await this.vault.read(userId);
    const refreshed = await this.refresh(credential);      // 过期则续期
    await this.redis.set(`session:${userId}`, JSON.stringify(refreshed), 'EX', 1800);
    return refreshed;
  }
}

2. 高频查询加缓存,且能失效

商品、订单模板这类查询结果变化不频繁,却占了大部分请求量。加入 Redis 缓存并对写操作打失效标记后,响应时间下降约 60%。关键在于按业务实体维度失效,而不是粗暴的全量清空。

3. WebSocket 做指令通道

轮询在「等待后台任务完成」的场景下体验很差。改为 WebSocket 后,服务端在任务完成时主动推送结果,插件即时刷新,同时减少了大量空轮询请求。

4. Go 重构解析模块

真正的瓶颈出现在一段复杂的 JSON 解析与字段映射逻辑:单次请求 800ms,其中 70% 消耗在深度遍历与正则匹配上。用 Go 重写为独立服务后:

指标 重构前 重构后
平均响应时间 800ms 120ms
P99 响应时间 2.4s 380ms
单机 CPU 占用 高(单核打满) 中等且平稳

保留 Node 作为业务编排层,把 CPU 密集型解析下沉到 Go,是这次最划算的架构选择。

结果

  • 插件覆盖 10+ 名成员,人均每日节省约 30 分钟重复操作。
  • 解析接口响应从 800ms 降至 120ms,降幅约 85%。
  • 结合 PM2 与 GitLab CI/CD,发布耗时从 30 分钟缩短至 5 分钟。

复盘

Node 适合 I/O 密集的业务编排,不适合长时间占用 CPU 的计算。把两者分开之后,服务既保持了迭代速度,也拿到了数量级的性能收益。判断标准很简单:看火焰图里时间花在等 I/O,还是在算。