最近我在开发一款 Chrome 插件 ScraperAI,插件本身可以在浏览器中提取网页可见数据,并导出为 CSV、XLS 或 JSON。为了支持 Pro 版本,我需要接入支付和许可证校验。

一开始我只是想手动部署一个接口,但很快发现:许可证服务涉及 API Key、环境变量、部署版本、回滚和安全隔离。如果每次都手动改代码、手动部署,不仅效率低,也容易出错。

于是我尝试用 Cursor 辅助生成 Cloudflare Worker 许可证服务,并结合 GitOps 的思路,把部署流程标准化:代码提交后自动部署,密钥放在平台环境变量中,Chrome 插件只访问自己的 Worker,不直接暴露支付平台 API Key。

一、为什么 Chrome 插件需要许可证服务

Chrome 插件如果直接把支付平台的 API Key 写在前端代码里,会有明显风险。

因为扩展代码最终会被安装到用户浏览器中,哪怕做了压缩和混淆,也不能认为它是安全的。只要用户有一定技术能力,就可能看到里面的接口地址、请求参数甚至敏感密钥。

所以更合理的结构是:

Chrome Extension

Cloudflare Worker License Server

Payment / License Provider

插件只负责提交用户输入的 License Key,真正的密钥校验由 Worker 完成。

这样有几个好处:API Key 不暴露在插件里;许可证校验逻辑可以独立升级;插件端逻辑更简单;后续如果切换支付平台,只需要改服务端;还可以配合 CI/CD 自动部署,减少手工操作。

二、整体架构设计

这套方案的核心组件有四个:

用户浏览器
└── Chrome 插件 ScraperAI
└── 调用 License API
└── Cloudflare Worker
└── 调用支付平台许可证接口

在这个结构里,Chrome 插件不直接访问支付平台。插件只知道自己的 Worker 地址,例如:

const LICENSE_API_BASE = “https://scraper-ai-license-server.example.workers.dev”;

用户输入 License Key 后,插件向 Worker 发起请求:

await fetch(${LICENSE_API_BASE}/activate, {
method: “POST”,
headers: {
“Content-Type”: “application/json”
},
body: JSON.stringify({
licenseKey,
instanceId
})
});

Worker 接收到请求后,再用服务端环境变量中的 API Key 去校验许可证。

三、用 Cursor 辅助生成 Worker 接口

在这个过程中,Cursor 最有价值的地方不是“替我写几行代码”,而是帮助我把接口边界和异常情况一次性梳理清楚。

我给 Cursor 的需求大概是:

帮我生成一个 Cloudflare Worker,用于 Chrome 插件许可证激活和校验。
要求:

  1. 支持 /activate 和 /verify 两个接口。
  2. 接收 licenseKey 和 instanceId。
  3. 服务端通过环境变量读取支付平台 API Key。
  4. 不能把真实 API Key 暴露给前端。
  5. 返回清晰的 JSON 状态。
  6. 支持 CORS。

Cursor 根据这个需求生成了 Worker 的基础结构,我再根据实际接口进行调整。

示例结构如下:

export default {
async fetch(request, env) {
const url = new URL(request.url);

if (request.method === "OPTIONS") {
  return handleCors();
}

if (url.pathname === "/activate" && request.method === "POST") {
  return activateLicense(request, env);
}

if (url.pathname === "/verify" && request.method === "POST") {
  return verifyLicense(request, env);
}

return jsonResponse({ error: "Not found" }, 404);

}
};

function handleCors() {
return new Response(null, {
headers: corsHeaders()
});
}

function corsHeaders() {
return {
“Access-Control-Allow-Origin”: “*”,
“Access-Control-Allow-Methods”: “POST, OPTIONS”,
“Access-Control-Allow-Headers”: “Content-Type”
};
}

function jsonResponse(data, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: {
“Content-Type”: “application/json”,
…corsHeaders()
}
});
}

这里的重点不是代码多复杂,而是边界清晰:插件只访问 Worker,Worker 读取环境变量,所有响应统一 JSON,OPTIONS 请求单独处理,避免浏览器 CORS 报错。

四、环境变量和密钥管理

许可证服务最容易出问题的地方就是密钥管理。

错误做法是:

const API_KEY = “sk_xxx”;

这种方式绝对不适合生产环境。

正确做法是把密钥放在 Cloudflare Worker 的环境变量中,例如:

CREEM_API_KEY=真实密钥

代码里只通过 env 读取:

const apiKey = env.CREEM_API_KEY;

这样即使代码仓库公开,也不会泄露真实密钥。

如果用 Wrangler,可以在本地配置项目名称:

name = “scraper-ai-license-server”
main = “src/index.js”
compatibility_date = “2026-06-01”

密钥则通过 Cloudflare 后台或命令行设置,不提交到 Git 仓库。

五、用 GitOps 思路管理部署

传统手动部署的问题是:每次改完代码,都要手动执行命令,时间久了很容易忘记步骤。

GitOps 的核心思路是:

Git 仓库就是部署状态的唯一来源

也就是说,只要代码合并到主分支,部署就自动发生。

流程可以设计成:

修改 Worker 代码

提交到 Git 仓库

触发 GitHub Actions

自动执行 wrangler deploy

部署到 Cloudflare Workers

这样做的好处是:每次部署都有 Git 记录;出问题可以回滚到上一个版本;不依赖某个人本地电脑环境;密钥由 GitHub Secrets 和 Cloudflare 管理;部署过程更可重复。

六、GitHub Actions 示例

下面是一个简化版的自动部署配置:

name: Deploy License Worker

on:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest

steps:
  - name: Checkout repository
    uses: actions/checkout@v4

  - name: Install dependencies
    run: npm install

  - name: Deploy to Cloudflare Workers
    run: npx wrangler deploy
    env:
      CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
      CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

需要注意的是,CLOUDFLARE_API_TOKEN 和 CLOUDFLARE_ACCOUNT_ID 不应该写在代码里,而是配置到 GitHub Secrets。

七、插件端如何调用许可证服务

插件端只需要关心两个状态:License Key 是否有效,以及当前浏览器实例是否已经激活。

async function activateLicense(licenseKey) {
const response = await fetch(${LICENSE_API_BASE}/activate, {
method: “POST”,
headers: {
“Content-Type”: “application/json”
},
body: JSON.stringify({
licenseKey,
instanceId: await getInstanceId()
})
});

const result = await response.json();

if (!response.ok || !result.valid) {
throw new Error(result.message || “License activation failed”);
}

await chrome.storage.local.set({
licenseStatus: “pro”,
licenseActivatedAt: Date.now()
});

return result;
}

这样插件侧不需要知道支付平台的具体接口,也不需要保存任何敏感密钥。

八、实践中遇到的问题

这次实践里,我遇到的主要问题有三个。

第一个是 CORS。Chrome 插件调用 Worker 时,如果没有正确处理 OPTIONS 请求,浏览器会直接拦截请求。解决方法是在 Worker 里统一返回 CORS 头。

第二个是 API Key 暴露风险。最开始很容易想把接口 Key 写在插件里,但这在浏览器插件场景下是不安全的。最终改成 Worker 代理校验。

第三个是部署一致性。如果本地手动部署,代码版本和线上版本可能不一致。使用 GitOps 后,每一次线上变更都可以回溯到 Git 提交记录。

九、Cursor 在这个过程中的价值

Cursor 在这次实践里的价值主要体现在三个方面。

第一,它能快速生成基础代码。比如 Worker 路由、CORS、JSON 响应、异常处理这些重复性代码,可以快速完成。

第二,它能帮助检查风险点。比如密钥是否暴露、接口是否缺少错误处理、Chrome 插件是否应该直接请求第三方 API。

第三,它适合做运维脚本和配置文件的辅助编写。像 wrangler.toml、GitHub Actions YAML、接口测试请求,都可以让 Cursor 先生成初稿,再根据实际情况调整。

我认为 Cursor 在 GitOps 场景下最适合承担的角色不是“完全自动替代开发者”,而是作为一个智能协作工具,帮助开发者更快地完成脚本、配置、部署流程和异常处理。

十、总结

这次实践让我更明确地感受到:对于小型独立产品来说,自动化运维并不一定要很复杂。

一个 Chrome 插件、一个 Cloudflare Worker、一个 GitHub Actions 流程,就可以形成一套轻量但实用的 GitOps 部署体系。

最终效果是:

代码提交 = 自动部署
密钥隔离 = 更安全
服务独立 = 更易维护
流程标准化 = 更少手工失误

Cursor 在其中承担了代码生成、配置辅助、风险检查和流程梳理的角色。对于个人开发者或者小团队来说,这种模式可以明显降低从开发到上线的复杂度。

如果后续产品继续扩展,还可以在这个基础上继续增加日志监控、版本回滚、灰度发布和自动化测试,让整个插件服务更加稳定。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐