ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cursor + GitOps 实战:自动部署 Chrome 插件许可证服务到 Cloudflare Workers | TaoToken 统一 Key 接入

Cursor + GitOps 实战:自动部署 Chrome 插件许可证服务到 Cloudflare Workers | TaoToken 统一 Key 接入 1. 为什么 Chrome 插件许可证服务必须独立部署做 Chrome 插件的人迟早会碰到同一个问题Pro 版本怎么校验。我见过太多插件把支付平台的 API Key 直接写进background.js或者content.js然后打包上传到商店。这种做法在技术上能跑通但安全模型是崩的。扩展代码最终会落到用户浏览器里压缩和混淆只是提高阅读成本不是加密。任何人打开 DevTools 的 Sources 面板或者把 crx 解包都能看到里面的接口地址、请求参数甚至明文密钥。所以正确的结构是三层Chrome 插件只负责收集用户输入的 License Key然后请求你自己的服务端服务端持有真正的支付平台密钥去和许可证提供商校验校验结果再返回给插件。插件永远不接触支付平台的 Key它只知道一个 Worker 地址。这个服务端用 Cloudflare Workers 非常合适。它免费额度够个人产品用冷启动几乎无感全球边缘节点而且天然支持环境变量注入密钥。你不需要维护一台服务器也不需要担心证书和扩容。但光有 Worker 还不够。许可证服务涉及 API Key、环境变量、部署版本、回滚。如果每次改代码都手动wrangler deploy时间一长必然出现「本地代码和线上版本不一致」的问题。这时候就需要 GitOpsGit 仓库是部署状态的唯一来源代码合并到主分支就自动部署每次线上变更都能回溯到某个 commit。这篇内容要解决的就是这条链路用 Cursor 辅助写 Worker 代码和配置文件用 GitHub Actions 做自动部署用 TaoToken 统一管理模型调用凭据最后用 curl 验证许可证接口真的返回了正确结果。适合正在做 Chrome 插件商业化、或者想把小型服务纳入自动化部署的独立开发者。2. TaoToken 统一 Key 接入把模型调用凭据从代码里拿出来在讲 Worker 部署之前先解决一个容易被忽略的问题许可证服务本身可能也要调用大模型。比如你想在激活时做风控判断、或者给用户生成一段个性化的欢迎文案、或者用模型解析支付平台的异常返回。这些调用都需要 API Key。如果每个服务各自维护一套 Key很快就会乱有的写在.env有的塞进 GitHub Secrets有的直接硬编码。更麻烦的是当你同时用多个模型供应商时Key 的格式、Base URL、模型 ID 都不一样切换成本很高。TaoToken 在这里的作用是提供一个统一的 API 通道。你只需要在 TaoToken 控制台创建一个 Key然后所有模型调用都走同一个 Base URL 和同一个 Key模型 ID 在请求体里指定。这样 Worker 的环境变量里只需要放一个TAOTOKEN_API_KEY而不是五六个不同平台的密钥。具体操作路径是这样的先到官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号然后进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建 API Key。创建完成后在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以看到完整的 Key 字符串复制保存好它只会完整显示一次。如果你只是想先验证模型能不能通可以直接用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 发一条消息测试。这个页面不需要写代码适合确认 Key 有效、模型可用。对于长期做编码和 Agent 的场景Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 会更划算它针对高频调用做了额度优化。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各语言的调用示例。API 的基础地址是https://taotoken.net/api注意这个地址不带 UTM 参数是给代码里用的。在 Worker 里调用时请求结构大致是这样const resp await fetch(https://taotoken.net/api/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${env.TAOTOKEN_API_KEY} }, body: JSON.stringify({ model: claude-sonnet-4-20250514, messages: [{ role: user, content: ping }] }) });这里的关键点是TAOTOKEN_API_KEY只存在于 Worker 的环境变量里不出现在代码仓库也不出现在 Chrome 插件里。插件端永远只请求你自己的 Worker 地址。如果你用的是 Claude Code 这类工具TaoToken 也提供了对应的接入方式参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。核心还是三件套Base URL 填https://taotoken.net/apiKey 填你创建的 KeyModel ID 按文档里的可用列表填。3. 可复制配置wrangler.toml、GitHub Actions 与 Worker 代码这一节给出可以直接复制粘贴的配置。整个项目结构建议这样组织scraper-ai-license-server/ ├── src/ │ └── index.js ├── wrangler.toml ├── package.json └── .github/ └── workflows/ └── deploy.yml先看wrangler.toml。这个文件定义 Worker 的名称、入口、兼容日期以及非敏感的环境变量。敏感密钥不写在这里通过 Cloudflare 后台或wrangler secret设置。name scraper-ai-license-server main src/index.js compatibility_date 2026-06-01 [vars] LICENSE_PROVIDER creem TAOTOKEN_BASE_URL https://taotoken.net/api # 敏感变量不写在这里用以下命令设置 # npx wrangler secret put CREEM_API_KEY # npx wrangler secret put TAOTOKEN_API_KEY注意compatibility_date要填一个已经发布的日期不要填未来日期否则 wrangler 会报错。[vars]里只放非敏感配置比如供应商名称和 Base URL。接下来是 Worker 主代码src/index.js。它处理/activate和/verify两个接口统一 CORS统一 JSON 响应密钥全部从env读取。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() } }); } async function activateLicense(request, env) { const { licenseKey, instanceId } await request.json(); if (!licenseKey || !instanceId) { return jsonResponse({ valid: false, message: missing licenseKey or instanceId }, 400); } const providerResp await fetch(https://api.creem.io/v1/licenses/activate, { method: POST, headers: { Content-Type: application/json, x-api-key: env.CREEM_API_KEY }, body: JSON.stringify({ license_key: licenseKey, instance_id: instanceId }) }); const providerData await providerResp.json(); if (!providerResp.ok) { return jsonResponse({ valid: false, message: providerData.message || provider error }, 502); } return jsonResponse({ valid: true, activatedAt: Date.now(), plan: providerData.plan || pro }); } async function verifyLicense(request, env) { const { licenseKey, instanceId } await request.json(); const providerResp await fetch(https://api.creem.io/v1/licenses/validate, { method: POST, headers: { Content-Type: application/json, x-api-key: env.CREEM_API_KEY }, body: JSON.stringify({ license_key: licenseKey, instance_id: instanceId }) }); const providerData await providerResp.json(); return jsonResponse({ valid: providerResp.ok providerData.valid true }); } export default { async fetch(request, env) { const url new URL(request.url); if (request.method OPTIONS) { return new Response(null, { headers: corsHeaders() }); } 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); } };这段代码里env.CREEM_API_KEY和env.TAOTOKEN_API_KEY都来自 Cloudflare 的加密环境变量不会出现在 Git 仓库里。如果你要在激活流程里加模型调用就在activateLicense里用env.TAOTOKEN_API_KEY去请求env.TAOTOKEN_BASE_URL。然后是 GitHub Actions 工作流.github/workflows/deploy.yml。它监听 main 分支的 push安装依赖后执行wrangler deploy。name: Deploy License Worker on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkoutv4 - name: Setup Node uses: actions/setup-nodev4 with: node-version: 20 - 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 仓库的 Settings → Secrets and variables → Actions 里。API Token 在 Cloudflare 后台的 My Profile → API Tokens 创建权限选「Edit Cloudflare Workers」即可。package.json里只需要声明 wrangler 依赖{ name: scraper-ai-license-server, version: 1.0.0, private: true, devDependencies: { wrangler: ^3.80.0 } }这套配置的核心逻辑是代码里没有任何明文密钥所有敏感信息通过 Cloudflare Secrets 和 GitHub Secrets 注入。Git 仓库可以公开也不会泄露。4. 验证请求push 触发部署与 curl 测试许可证接口配置写完之后验证分两步先确认 push 能触发自动部署再确认接口真的返回正确结果。第一步把代码提交到 main 分支git add . git commit -m feat: add license worker with gitops deploy git push origin mainpush 之后打开 GitHub 仓库的 Actions 标签页应该能看到一个名为「Deploy License Worker」的工作流正在运行。点进去可以看到每一步的日志。如果wrangler deploy成功最后会输出类似这样的内容Uploaded scraper-ai-license-server (1.23 sec) Deployed scraper-ai-license-server triggers (0.45 sec) https://scraper-ai-license-server.your-subdomain.workers.dev这个 URL 就是你的许可证服务地址。把它填到 Chrome 插件的LICENSE_API_BASE里。第二步用 curl 验证/activate接口。先测一个明显无效的 Key确认错误处理正常curl -X POST https://scraper-ai-license-server.your-subdomain.workers.dev/activate \ -H Content-Type: application/json \ -d {licenseKey:invalid-key-123,instanceId:test-instance-001}预期返回{valid:false,message:provider error}状态码应该是 502 或 400说明 Worker 正确地把错误透传出来了而不是崩溃或者返回 200。再用一个真实的测试 License Key 验证成功路径curl -X POST https://scraper-ai-license-server.your-subdomain.workers.dev/activate \ -H Content-Type: application/json \ -d {licenseKey:YOUR_REAL_TEST_KEY,instanceId:test-instance-001}预期返回{valid:true,activatedAt:1735689600000,plan:pro}如果看到valid: true说明整条链路是通的curl → Cloudflare Worker → 支付平台许可证接口 → 返回结果。这时候再去 Chrome 插件里调用同一个接口应该也能拿到相同结果。再验证一下 CORS 预检请求curl -X OPTIONS https://scraper-ai-license-server.your-subdomain.workers.dev/activate \ -H Origin: chrome-extension://abcdefg \ -H Access-Control-Request-Method: POST \ -i响应头里应该包含Access-Control-Allow-Origin: *和Access-Control-Allow-Methods: POST, OPTIONS。如果没有这两个头Chrome 插件里的 fetch 会被浏览器拦截。最后验证/verify接口curl -X POST https://scraper-ai-license-server.your-subdomain.workers.dev/verify \ -H Content-Type: application/json \ -d {licenseKey:YOUR_REAL_TEST_KEY,instanceId:test-instance-001}返回{valid:true}就说明校验接口也正常。到这里一次完整的 push 触发部署 curl 验证就完成了。5. 本篇常见错排查401、CORS、wrangler 报错与 OAuth 问题这一节列出实际部署中最容易撞到的几个错误以及对应的排查方向。错误一401 Unauthorized来自支付平台现象是 curl 返回{valid:false,message:provider error}但你去 Cloudflare 后台看日志发现请求确实发出去了只是支付平台返回了 401。这通常说明CREEM_API_KEY没有正确设置或者设置后没有重新部署。排查步骤先在 Cloudflare 后台进入 Workers Pages → 你的 Worker → Settings → Variables and Secrets确认CREEM_API_KEY存在且类型是 Secret。如果刚添加需要重新触发一次部署才能生效。可以用npx wrangler secret list查看当前已设置的 secret 名称。注意wrangler secret put设置的变量不会出现在wrangler.toml里这是正常的。如果你在本地用wrangler dev调试需要在项目根目录建一个.dev.vars文件里面写CREEM_API_KEYxxx但这个文件必须加入.gitignore。错误二local proxy failed或reading choices报错如果你在 Worker 里调用了 TaoToken 的模型接口可能会遇到Cannot read properties of undefined (reading choices)。这通常是因为响应结构和你预期的不一样。先打印原始响应const raw await resp.text(); console.log(raw response:, raw);常见原因是 Base URL 写错了。TaoToken 的 API 地址是https://taotoken.net/api完整的 chat completions 路径是https://taotoken.net/api/v1/chat/completions。如果你只写了https://taotoken.net就会 404返回的就不是 JSON 结构解析choices自然报错。另一个原因是Authorization头格式不对。必须是Bearer 你的Key中间有一个空格。少了空格或者用了Token前缀都会 401。错误三CORS 报错No Access-Control-Allow-Origin headerChrome 插件里 fetch 报这个错说明 Worker 没有正确处理 OPTIONS 预检。检查你的 Worker 代码里是否有这一段if (request.method OPTIONS) { return new Response(null, { headers: corsHeaders() }); }这段必须放在路由判断的最前面。如果你把它放在/activate判断之后OPTIONS 请求会先命中 404 分支就不会返回 CORS 头。另外Access-Control-Allow-Headers要包含Content-Type因为插件发的是 JSON 请求。如果你还传了自定义头比如X-Instance-Id也要加进去。错误四wrangler deploy报OAuth error或Authentication error在 GitHub Actions 里跑wrangler deploy时如果报 OAuth 相关错误通常是因为CLOUDFLARE_API_TOKEN没有设置或者 Token 权限不够。wrangler 在 CI 环境里不会走 OAuth 浏览器登录它只认CLOUDFLARE_API_TOKEN环境变量。排查确认 GitHub Secrets 里有CLOUDFLARE_API_TOKEN和CLOUDFLARE_ACCOUNT_ID。API Token 的权限要包含Workers Scripts:Edit。如果 Token 创建时只给了读权限部署会失败。还有一个容易忽略的点CLOUDFLARE_ACCOUNT_ID不是你的登录邮箱而是 Cloudflare 后台右侧栏显示的 Account ID一串十六进制字符。填错了会报account not found。错误五部署成功但接口 404Actions 显示部署成功但 curl 访问返回 404。先确认你访问的 URL 和部署日志里输出的 URL 完全一致。Workers 的默认域名是worker-name.subdomain.workers.devsubdomain是你在 Cloudflare 注册时设置的不是账号 ID。如果 URL 没错检查wrangler.toml里的main字段是否指向了正确的入口文件。如果main src/index.js但实际文件在src/worker/index.jswrangler 会部署一个空 Worker所有请求都 404。6. 语义一致 CTA把 Key 管理和部署流程固定下来整套流程跑通之后你会发现真正花时间的不是写 Worker 代码而是把密钥管理和部署流程固定成可重复的动作。Cursor 在这里的价值是帮你快速生成wrangler.toml、GitHub Actions YAML 和 Worker 路由代码的初稿但密钥放哪里、怎么注入、怎么验证这些决策还是得自己做。我的建议是把三件事固定下来第一所有模型调用统一走 TaoToken 的 Base URL 和 KeyWorker 环境变量里只保留一个TAOTOKEN_API_KEY第二所有敏感信息通过 Cloudflare Secrets 和 GitHub Secrets 注入代码仓库里不出现任何明文密钥第三每次部署后用 curl 跑一遍/activate和/verify确认返回结构没变。如果你还没创建 TaoToken 的 Key可以从 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 开始。想先确认模型调用能不能通用模型对话 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 发一条消息最快。接入细节和参数说明在文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里。长期做编码和 Agent 的话Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 的额度更适合高频场景。最后一步把 Chrome 插件里的LICENSE_API_BASE改成你的 Worker 地址然后在插件里调用/activate确认chrome.storage.local里写入了licenseStatus: pro。到这一步从 Cursor 写代码到 GitOps 自动部署再到插件端激活整条链路就闭环了。
返回列表