1. 为什么要在 Cursor 里写这个 Chrome 插件
如果你经常和运营、测试或者非技术同事打交道,大概率遇到过这种场景:某个后台系统需要登录态才能抓数据,技术人员打开 F12,切到 Application 面板,在 Cookies 里翻半天找到那个关键字段,复制出来贴给对方。对方拿到之后还要自己找地方存、自己拼请求头,交接一次懵一次。
这个流程本身不复杂,但重复次数多了就很烦。更麻烦的是,当这个插件还想顺带调用 AI 能力做点自动化处理时,Key 往哪放、怎么配、怎么保证不把 Key 硬编码进前端代码,就变成了新的问题。我试过把这套东西拆成两部分:Chrome 插件负责一键读取并复制当前站点的 Cookies,AI 请求部分则通过一个统一的 Key 网关来转发,插件本身不接触真实密钥。
这篇就聚焦在 Cursor 里从零把这个插件跑通的完整链路。你会看到manifest.json怎么写、settings.json配置骨架长什么样、TaoToken 的统一 Key 怎么接进来,以及最后怎么在浏览器里验证 Cookies 读取和 AI 请求都通了。适合有基础 JS 能力、想在本地快速搭一个可用插件的开发者。
核心检索词先摆出来:Cursor 写 Chrome 插件、一键获取 Cookies、TaoToken 统一 Key 接入、settings.json 配置骨架。下面按可跟做的顺序展开。
2. TaoToken 前置:统一 Key 与配置骨架
在动手写插件之前,先把 Key 管理这块理清楚。插件里如果直接写死某个模型的 API Key,一旦分发出去就等于泄露,而且换模型、换额度都要重新打包,非常不划算。更合理的做法是让插件请求一个统一的网关地址,由网关去持有真实密钥并做转发。
TaoToken 在这里扮演的就是这个统一入口。你只需要在它那边生成一个 Key,插件里配置这个 Key 和网关地址即可。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基地址是 https://taotoken.net/api ,注意 API 地址后面不加任何 UTM 参数,保持干净。
具体操作上,先进控制台创建 Key。控制台地址带 deep link:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。创建完之后去 API Keys 页面复制:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。如果你后面要接 Claude Code 或者做长期编码 Agent,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。想先验证模型通不通,用模型对话页最快:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。接入细节看文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
拿到 Key 之后,我们要在插件项目里建一个settings.json作为配置骨架。这个文件不放进打包产物,而是作为本地开发时的配置模板,真正的 Key 通过环境变量或者本地存储注入。骨架大概长这样:
{ "apiBase": "https://taotoken.net/api", "apiKey": "YOUR_TAOTOKEN_KEY", "model": "claude-3-5-sonnet", "timeoutMs": 30000, "cookieTargets": [ { "name": "sessionid", "domain": "example.com" }, { "name": "token", "domain": "example.com" } ], "copyFormat": "header" }这里几个字段的作用要说明白。apiBase固定指向 TaoToken 的 API 地址,不要带斜杠结尾。apiKey是占位符,实际运行时从chrome.storage.local读取,避免提交到仓库。model按你实际要用的模型填。cookieTargets是你要抓取的 Cookie 字段名和对应域名,可以配多个。copyFormat决定复制出来的是纯值还是Cookie: xxx这种请求头格式,运营同事一般更喜欢后者,直接能贴。
注意:
settings.json里绝对不要提交真实 Key。建议在.gitignore里加上这个文件,仓库里只保留settings.example.json。
3. 可复制配置:manifest 与插件目录结构
在 Cursor 里新建一个文件夹,比如叫cookie-ai-helper,然后让 Cursor 帮你生成基础结构。不过我更建议手动把关键文件先定下来,避免生成的东西太散。目录结构如下:
cookie-ai-helper/ ├── manifest.json ├── popup.html ├── popup.js ├── background.js ├── settings.example.json └── icons/ └── icon128.pngmanifest.json用 V3 版本,权限声明要精确,不要一上来就<all_urls>。下面这份可以直接复制:
{ "manifest_version": 3, "name": "Cookie AI Helper", "version": "1.0.0", "description": "一键获取当前站点 Cookies 并通过统一 Key 调用 AI", "permissions": ["cookies", "storage", "activeTab", "scripting"], "host_permissions": ["https://taotoken.net/*"], "action": { "default_popup": "popup.html", "default_icon": "icons/icon128.png" }, "background": { "service_worker": "background.js" } }这里cookies权限是读 Cookie 必须的,storage用来存 Key 和配置,activeTab配合scripting用来拿当前标签页信息。host_permissions只放 TaoToken 的域名,不要图省事写通配。background.js作为 service worker 负责发起 AI 请求,这样 Key 不会暴露在页面上下文里。
popup.html保持极简,两个按钮加一个输出区:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> body { width: 320px; padding: 12px; font-family: system-ui; } button { width: 100%; margin: 6px 0; padding: 8px; cursor: pointer; } pre { background: #f5f5f5; padding: 8px; font-size: 12px; white-space: pre-wrap; } </style> </head> <body> <button id="grab">一键获取 Cookies</button> <button id="ask">用 AI 分析</button> <pre id="out">等待操作...</pre> <script src="popup.js"></script> </body> </html>popup.js负责和 background 通信,自己不直接碰 Key:
const out = document.getElementById('out'); document.getElementById('grab').addEventListener('click', async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); const res = await chrome.runtime.sendMessage({ type: 'GRAB_COOKIES', url: tab.url }); out.textContent = res.ok ? res.data : '失败: ' + res.error; }); document.getElementById('ask').addEventListener('click', async () => { const res = await chrome.runtime.sendMessage({ type: 'ASK_AI', prompt: '总结当前站点登录态字段' }); out.textContent = res.ok ? res.data : '失败: ' + res.error; });background.js是核心,负责读 Cookie 和调 AI:
async function getSettings() { const { settings } = await chrome.storage.local.get('settings'); return settings || { apiBase: 'https://taotoken.net/api', apiKey: '', model: 'claude-3-5-sonnet' }; } async function grabCookies(url) { const u = new URL(url); const cookies = await chrome.cookies.getAll({ domain: u.hostname }); return cookies.map(c => `${c.name}=${c.value}`).join('; '); } async function askAI(prompt) { const s = await getSettings(); if (!s.apiKey) throw new Error('未配置 apiKey'); const resp = await fetch(`${s.apiBase}/v1/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': s.apiKey, 'anthropic-version': '2023-06-01' }, body: JSON.stringify({ model: s.model, max_tokens: 512, messages: [{ role: 'user', content: prompt }] }) }); if (!resp.ok) throw new Error('HTTP ' + resp.status); const data = await resp.json(); return data.content?.[0]?.text || JSON.stringify(data); } chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { (async () => { try { if (msg.type === 'GRAB_COOKIES') { sendResponse({ ok: true, data: await grabCookies(msg.url) }); } else if (msg.type === 'ASK_AI') { sendResponse({ ok: true, data: await askAI(msg.prompt) }); } } catch (e) { sendResponse({ ok: false, error: e.message }); } })(); return true; });这段代码里,grabCookies用chrome.cookies.getAll按域名过滤,拼成标准 Cookie 头格式。askAI走 TaoToken 的/v1/messages接口,Key 从 storage 读,不写死在代码里。onMessage里返回true是为了保持异步通道打开,这个坑很多人踩过,不加的话sendResponse会失效。
4. 验证请求:从加载插件到 AI 联通
代码写完,先在 Cursor 里把settings.example.json复制成settings.json,填入你的 TaoToken Key。然后打开 Chrome,地址栏输入chrome://extensions/,右上角打开开发者模式,点「加载已解压的扩展程序」,选中cookie-ai-helper文件夹。加载成功后工具栏会出现插件图标。
第一步验证 Cookies 读取。随便打开一个已登录的站点,点插件图标,点「一键获取 Cookies」。如果输出区出现sessionid=xxx; token=yyy这样的字符串,说明读取链路通了。如果为空,检查manifest.json里cookies权限有没有加,以及当前站点是否真的设置了对应 Cookie。
第二步验证 AI 请求。点「用 AI 分析」,如果返回一段模型生成的文本,说明 TaoToken 的 Key 和网关地址都配对了。如果报HTTP 401,多半是 Key 填错或者没保存到 storage;报HTTP 404,检查apiBase是不是写成了带斜杠的https://taotoken.net/api/,去掉末尾斜杠再试。
想更直观地验证模型本身通不通,可以先用模型对话页发一条消息:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。那边能通,插件这边基本就是配置问题。接入文档里对请求头和参数有更细的说明:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
在 Cursor 里调试的时候,有个小技巧:background 的console.log不会显示在 popup 的控制台里,要去chrome://extensions/找到这个插件,点「Service Worker」那一行的「检查」,才能看到 background 的日志。popup 的日志则在插件弹窗上右键「检查」查看。这两个控制台分开,排查问题时别搞混。
5. 本篇常见错排查
Cookie 读出来是空数组。最常见的原因是域名不匹配。chrome.cookies.getAll({ domain: u.hostname })里的u.hostname是当前标签页的主机名,如果 Cookie 设在子域名或者父域名上,就抓不到。可以改成{ url: tab.url }让 Chrome 自己匹配,或者把cookieTargets里的 domain 配全。
AI 请求报 CORS 错误。Chrome 插件的 background service worker 发请求不受页面 CORS 限制,但前提是host_permissions里声明了目标域名。如果你把apiBase改成了别的地址,记得同步改host_permissions,否则请求会被拦。
Key 存进去读不出来。chrome.storage.local是异步的,get之后要await。另外 popup 和 background 是两个上下文,popup 里存的 Key,background 能读到,但如果你在 popup 里直接chrome.storage.local.set之后立刻发消息,可能有时序问题,建议存完再点按钮。
改了代码没生效。Chrome 插件加载后不会自动热更新,每次改完manifest.json或 background 代码,都要回chrome://extensions/点一下刷新按钮。popup 的 HTML/JS 改完,关掉弹窗重新打开即可。
复制出来的格式不对。copyFormat字段目前只是配置骨架里的占位,实际复制逻辑要自己在grabCookies里根据这个字段拼。想要Cookie: xxx格式,就在返回前加个前缀判断。这个字段留着是为了后面扩展,别以为配了就自动生效。
注意:调试阶段可以把
timeoutMs调小一点,比如 10000,这样请求卡住时能更快看到失败,不用干等。
6. 后续怎么接得更顺
插件跑通之后,如果你打算长期用它做编码辅助或者接 Agent 流程,建议把 Key 管理从本地 storage 再往上提一层。比如用 Coding Plan 统一管理额度和模型切换:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。这样插件里只需要配一个入口,换模型不用重新打包。
另外,settings.json的骨架可以继续扩展,比如加上retry次数、temperature参数、多模型 fallback 列表。但记住一个原则:凡是涉及密钥的字段,都走 storage 注入,仓库里只留 example。Cursor 生成代码很快,但配置安全这块它不会替你把关,得自己盯住。
最后留一个实用习惯:每次改完manifest.json,先在 Cursor 里用 JSON 校验插件过一遍语法,再去 Chrome 加载。我踩过的坑是少了一个逗号,Chrome 只报「无法加载」,不告诉你哪一行错,来回找很费时间。校验通过再加载,能省不少事。