1. 从一行 wx.request 说起:小程序前端直调 AI 的 Key 暴露面
TaoToken 提醒:在小程序前端直调微信 AI 时,最容易被忽略的不是模型选型,而是wx.request里那行Authorization。TaoToken 的接入入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_intro ,拿 Key 后请求地址统一用 https://taotoken.net/api 。
不少“个人小程序如何被微信 AI 调用”的最小步骤会这样写:在微信开发者工具里发一个 POST,带上Bearer YOUR_API_KEY,收到 JSON 就认为接完了。作为前端安全视角的仿写,本文不这么建议。因为小程序包可被解包,真机调试可看 Network,代理工具能抓请求头;Key 一旦进入前端,就等于对所有能拿到包的人公开。更稳的路径是:前端只调云函数,云函数持有 TaoToken Key,TaoToken 的 Base URL 用 https://taotoken.net/api 。下面给出前端安全对照、后端代理代码、请求示例,以及本地 Claude Code / Codex / CC Switch 的配置边界。
先看一个最常见的错误写法:
// 危险示例:不要在小程序前端这样写 wx.request({ url: 'https://taotoken.net/api/v1/chat/completions', method: 'POST', header: { 'Content-Type': 'application/json', Authorization: 'Bearer YOUR_API_KEY' }, data: { model: 'gpt-4o-mini', messages: [{ role: 'user', content: '你好' }] }, success(res) { console.log(res.data) } })这段代码在开发者工具里能跑通,甚至体验版也能返回内容,但它把 TaoToken Key 直接写进了前端请求头。小程序代码包下载到本地后,JS 文件可被解包阅读;即使做了混淆,字符串常量仍然可能被搜索出来。真机调试时,Network 面板能看到完整请求头;如果用户侧抓包,Authorization: Bearer ...也会暴露。结果就是:别人可以拿着你的 Key 调用模型,消耗你的额度,甚至触发风控。
前端安全的第一条边界是:能进小程序前端的,只有业务参数和短期票据;长期有效的 API Key 必须留在服务端。TaoToken 的 Key 属于账号级凭证,不应该出现在wx.request、wxml、wxss、app.js或任何会被打包的代码里。
下面这张表可以作为前端安全对照:
| 信息项 | 能否放小程序前端 | 原因 | 替代方案 |
|---|---|---|---|
| TaoToken API Key | 不能 | 可被解包、抓包、调试面板看到 | 放云函数/云托管环境变量 |
Base URLhttps://taotoken.net/api | 可以 | 它不是秘密,只是请求地址 | 后端统一配置,前端不必关心 |
| 用户 openid | 谨慎 | 用于身份识别,不要外泄 | 由云函数getWXContext()获取 |
| prompt 用户输入 | 可以 | 业务数据 | 服务端做长度、内容、频率校验 |
| 模型名 | 可以 | 非敏感,但不应让前端随意指定 | 服务端白名单映射 |
| 管理台 Token | 不能 | 权限过大 | 永不下发前端 |
| 云端临时票据 | 可以 | 有有效期和权限范围 | 结合云函数鉴权使用 |
很多个人小程序开发者会问:微信 AI 能力不是可以直接在微信生态里调用吗?这里要区分两件事。微信生态里的身份、登录、云函数、云开发确实可以帮你完成鉴权,但只要你接的是第三方大模型 API,Key 的安全边界就不由微信保证,而由你的后端代理保证。无论你接的是微信对话开放平台、还是自己接大模型做 AI 问答,只要涉及Authorization请求头,前端直调就是高风险动作。
所以,在你确定前端代理方案之前,先做一件事:去 TaoToken 官网创建 Key。链接是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_getkey ,创建后把请求地址记成 https://taotoken.net/api 。这个 Key 只应存在服务端,不应写进小程序前端。接下来从最小步骤开始,把前端直调改成后端代理。
2. 个人小程序接入微信 AI 的最小步骤:前端只留一个云函数名
如果你的目标是“个人小程序如何被微信 AI 调用:接入微信生态最小步骤”,那么最小可用路径不是“前端直调 API”,而是“前端调用云函数,云函数调用 TaoToken”。这样小程序端只需要知道云函数名,例如aiProxy,不需要知道 TaoToken Key,也不需要知道完整上游地址。
最小步骤可以拆成 6 步:
- 在 TaoToken 官网创建账号并生成 API Key:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_getkey 。
- 记录请求地址:
https://taotoken.net/api。注意这个地址不要加 UTM,它是工具配置用的 Base URL。 - 在微信开发者工具里开通云开发,创建云函数
aiProxy。 - 在云函数配置里添加环境变量
TAOTOKEN_API_KEY=YOUR_API_KEY,不要把 Key 写进index.js。 - 部署云函数,小程序端用
wx.cloud.callFunction调用。 - 真机预览,打开调试器 Network,确认小程序发出的请求里没有
Authorization: Bearer ...。
这里的关键点是:小程序前端只留一个云函数名,例如:
wx.cloud.callFunction({ name: 'aiProxy', data: { prompt: '帮我写一段小程序公告' } })前端不知道 TaoToken Key,也不知道https://taotoken.net/api后面拼了什么路径。所有敏感配置都收敛到云函数环境变量里。这样即使小程序包被解包,攻击者也拿不到长期有效的 Key。
如果你还没有云开发环境,也可以在微信开发者工具里先创建云函数目录:
cloudfunctions/ aiProxy/ index.js package.json config.json miniprogram/ pages/ ai/ ai.js ai.wxml ai.wxssconfig.json可以按云函数权限需要配置,个人小程序初期保持默认即可。重点是把aiProxy当成唯一的 AI 出口,所有大模型调用都从这里走。
前端页面逻辑也可以保持简单:输入 prompt,点击按钮,调用云函数,展示结果。下面是一个可参考的小程序端示例:
// miniprogram/pages/ai/ai.js Page({ data: { prompt: '', answer: '', loading: false }, onPromptInput(e) { this.setData({ prompt: e.detail.value }) }, async onAsk() { const prompt = this.data.prompt.trim() if (!prompt) { wx.showToast({ title: '请输入内容', icon: 'none' }) return } this.setData({ loading: true, answer: '' }) try { const { result } = await wx.cloud.callFunction({ name: 'aiProxy', data: { prompt } }) if (!result || !result.ok) { throw new Error((result && result.message) || 'AI 服务暂时不可用') } this.setData({ answer: result.content || '' }) } catch (err) { wx.showToast({ title: err.message || '调用失败', icon: 'none' }) } finally { this.setData({ loading: false }) } } })对应ai.wxml只需要两个区域:输入框和结果展示。这里不再展开样式,因为安全重点是请求链路,不是 UI。
到这一步,你已经完成了“前端不暴露 Key”的最小改造。接下来要写后端代理代码,也就是云函数里如何安全地调用 TaoToken。
3. 后端代理代码:微信云函数调用 TaoToken 的 OpenAI 兼容接口
云函数是个人小程序最省事的安全代理。它运行在服务端,环境变量不会随小程序包下发;同时它能通过cloud.getWXContext()拿到OPENID,天然具备微信身份鉴权能力。下面给出一个可复制的 Node.js 云函数示例。
先看package.json:
{ "name": "aiProxy", "version": "1.0.0", "description": "TaoToken proxy for WeChat mini program", "main": "index.js", "dependencies": { "wx-server-sdk": "latest", "axios": "^1.7.0" } }然后是index.js:
// cloudfunctions/aiProxy/index.js const cloud = require('wx-server-sdk') const axios = require('axios') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const BASE_URL = process.env.TAOTOKEN_BASE_URL || 'https://taotoken.net/api' const API_KEY = process.env.TAOTOKEN_API_KEY exports.main = async (event) => { const { OPENID } = cloud.getWXContext() if (!OPENID) { return { ok: false, code: 'NO_OPENID', message: '未获取到微信身份' } } const prompt = String(event.prompt || '').trim() if (!prompt) { return { ok: false, code: 'EMPTY_PROMPT', message: '请输入内容' } } if (prompt.length > 2000) { return { ok: false, code: 'TOO_LONG', message: '内容过长,请精简后重试' } } if (!API_KEY) { console.error('[aiProxy] missing TAOTOKEN_API_KEY') return { ok: false, code: 'NO_API_KEY', message: '服务端 Key 未配置' } } try { const resp = await axios.post( `${BASE_URL}/v1/chat/completions`, { model: event.model || 'gpt-4o-mini', messages: [ { role: 'user', content: prompt } ], temperature: 0.3, max_tokens: 800 }, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${API_KEY}` }, timeout: 20000 } ) const content = resp.data?.choices?.[0]?.message?.content || '' return { ok: true, content } } catch (err) { const status = err.response?.status const upstreamBody = err.response?.data console.error('[aiProxy] upstream error', { status, body: JSON.stringify(upstreamBody).slice(0, 300) }) return { ok: false, code: status || 'UPSTREAM_ERROR', message: status === 401 ? '服务端 Key 配置错误' : status === 429 ? '请求过于频繁,请稍后再试' : 'AI 服务暂时不可用' } } }这段代码有几个安全细节值得单独说明:
第一,TAOTOKEN_API_KEY来自环境变量,不来自event。小程序端无法通过传参覆盖 Key,避免前端伪造。
第二,OPENID来自cloud.getWXContext(),不是前端传入。这样每个请求都能绑定真实微信用户,后续可以做频率限制。
第三,日志只打印状态码和截断后的上游响应,不打印完整Authorization。很多团队出事不是 Key 写在前端,而是 Key 被打印进云函数日志,然后日志被分享到群里或提交到仓库。
第四,BASE_URL默认是https://taotoken.net/api,最终请求路径由代码拼接为${BASE_URL}/v1/chat/completions。如果你使用的 SDK 会自动拼接/v1,则 Base URL 保持https://taotoken.net/api;如果你手动拼接完整路径,就写https://taotoken.net/api/v1/chat/completions。不要混用,否则容易 404。
在微信云函数控制台配置环境变量时,填写:
TAOTOKEN_API_KEY=YOUR_API_KEY TAOTOKEN_BASE_URL=https://taotoken.net/api注意,TAOTOKEN_BASE_URL不要加 UTM 参数。UTM 只用于官网入口追踪,工具配置里的 Base URL 保持干净。
部署后,可以在云函数控制台用测试参数验证:
{ "prompt": "用一句话解释为什么小程序不能在前端放 API Key" }如果返回ok: true和一段文本,说明代理链路已经通了。如果返回 401,优先检查环境变量里是否真的写入了YOUR_API_KEY对应的真实 Key;如果返回 404,检查 Base URL 和路径拼接是否重复或缺失/v1。
如果你更习惯用 curl 在本地先验证 TaoToken 上游是否可用,可以用下面这个请求示例。注意,这个命令只在本地服务端执行,不要把结果贴到公开 issue:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "用一句话解释小程序为什么要走后端代理" } ], "temperature": 0.3 }'这个 curl 能通,说明 Key 和 Base URL 正确;然后再去排查云函数。不要把 curl 成功截图发到公开社区,因为截图里可能包含完整 Key。
4. 前端安全对照:直调、云函数、云托管、自建后端怎么选
个人小程序做 AI 接入时,常见方案有四种:前端直调、微信云函数、微信云托管、自建后端。它们的安全边界和运维成本不同。下面这张对照表可以作为选型参考:
| 方案 | Key 存放位置 | 优点 | 风险 | 适用阶段 |
|---|---|---|---|---|
| 前端直调 | 小程序包 | 开发最快 | Key 公开、无法限流、无法审计 | 仅本地 demo |
| 微信云函数 | 云函数环境变量 | 免运维、天然微信身份、成本低 | 冷启动、并发限制、日志要脱敏 | 个人小程序最小可用 |
| 微信云托管 | Secret 配置 | 可常驻、易扩容、支持容器 | 配置成本、费用更高 | 有一定流量 |
| 自建后端 | 服务器环境变量 | 完全可控、可做复杂限流 | 需要备案、运维、防攻击 | 企业或长期项目 |
从安全角度看,前端直调只适合本地验证接口是否可用,不适合上线。只要你的小程序发布体验版或正式版,前端直调就相当于把 Key 公开。云函数是个人开发者最平衡的选择:不需要买服务器,不需要自己配 HTTPS,微信云开发天然提供身份上下文,TaoToken Key 放在环境变量里也不会随包下发。
云托管适合请求量更大、需要常驻进程的场景。你可以把上面的aiProxy逻辑迁移到 Express 或 Koa 服务,把TAOTOKEN_API_KEY放在云托管 Secret 里。自建后端则适合需要自定义鉴权、计费、审计、内容安全的中大型项目。
不管选哪种,都要遵守同一条原则:前端只拿结果,不拿 Key。如果你在前端安全对照里发现任何一处出现YOUR_API_KEY,都要把它移到服务端。TaoToken 的 Key 创建入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_proxy ,Base URL 仍然是 https://taotoken.net/api 。
另外,个人小程序还要注意内容安全。AI 返回的内容如果直接展示给用户,建议在云函数里加一层敏感词或内容安全接口校验。微信云开发有内容安全能力,可以在返回前端之前做一次检查。这样即使模型输出不可控,也不会直接把风险内容展示给用户。
5. 请求示例与错误码排查:401、403、429、超时分别怎么查
当前端只调云函数后,排查问题的路径会清晰很多:小程序端只负责展示错误,云函数日志负责记录上游状态。下面用一个表格整理常见错误码和定位方向。
| 错误码 | 常见含义 | 优先检查 | 处理建议 |
|---|---|---|---|
| 401 | 未授权或 Key 错误 | 云函数环境变量TAOTOKEN_API_KEY是否设置 | 重新生成 Key,确认Bearer后没有多余空格 |
| 403 | 无权限或额度/权限限制 | TaoToken 控制台账号状态、Key 权限 | 检查 Key 是否被禁用,确认账号可用 |
| 404 | 路径不对 | Base URL 与/v1/chat/completions拼接 | 确认是https://taotoken.net/api+/v1/chat/completions |
| 400 | 请求参数不合法 | model、messages格式 | 检查 JSON 字段,确保messages是数组 |
| 429 | 请求过于频繁 | 用户调用频率、并发量 | 云函数加限流,前端做防抖 |
| 502/504 | 上游超时或网关错误 | 云函数超时时间、网络 | 缩短 prompt、增加超时、重试一次 |
| 前端无响应 | 云函数未部署或权限不足 | 云函数名称、云开发环境 | 重新部署,检查wx.cloud.init |
排查 401 时,不要在云函数日志里打印完整 Key。可以用“前 6 位 + 后 4 位”的方式确认 Key 是否配置正确:
function maskKey(key) { if (!key) return 'EMPTY' if (key.length <= 10) return '***' return `${key.slice(0, 6)}...${key.slice(-4)}` }如果本地 curl 能通,云函数 401,通常是环境变量没生效或部署后未重新加载。微信云函数修改环境变量后,需要重新部署或重启实例。如果本地 curl 也 401,就去 TaoToken 控制台检查 Key 是否复制完整。注意,YOUR_API_KEY只是占位符,不能直接当真实 Key 使用。
排查 429 时,除了上游限流,也可能是前端按钮被连续点击。可以在小程序端加一个loading状态,在请求期间禁用按钮;在云函数侧按OPENID做简单计数,例如同一用户 10 秒内最多 5 次。个人小程序初期不需要复杂网关,但基本防抖和频率限制能避免大部分误触发。
排查超时时,注意云函数默认超时时间可能较短。如果你的 prompt 很长或模型响应慢,可以在云函数配置里适当调大超时,同时设置axios的timeout。前端也要设置自己的等待提示,避免用户以为小程序卡死。
最后,所有请求示例里的 Key 都必须替换为YOUR_API_KEY,并且只在本地或服务端环境变量中使用。不要把真实 Key 写进文章、截图、仓库、前端代码或聊天记录。
6. Claude Code、Codex、CC Switch:本地工具改 TaoToken 的配置边界
虽然本文主线是小程序前端安全,但很多个人开发者同时会在本地用 Claude Code、Codex 或 CC Switch 做开发。这些工具的配置也有类似的“不要套错”问题。尤其是 Claude Code 使用ANTHROPIC_*环境变量,Codex 使用config.toml,两者不能混用。下面给出可复制配置示例。
Claude Code 可以使用settings.json,核心是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "YOUR_API_KEY" } }注意,这里不要把ANTHROPIC_*写到 Codex 的配置里。Codex 使用config.toml,配置方式不同:
model = "gpt-4o-mini" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api/v1" env_key = "TAOTOKEN_API_KEY" wire_api = "chat"Codex 里使用TAOTOKEN_API_KEY作为环境变量名,不要写ANTHROPIC_API_KEY。如果你在终端里配置,可以这样:
export TAOTOKEN_API_KEY=YOUR_API_KEYCC Switch 这类配置切换工具,核心是“三件套”:Base URL、API Key、默认模型。你可以把它理解成一组供应商配置:
{ "providers": [ { "name": "TaoToken", "base_url": "https://taotoken.net/api", "api_key": "YOUR_API_KEY", "default_model": "gpt-4o-mini" } ] }三件套里,base_url不要带 UTM,api_key只存在本地配置,default_model按你的实际可用模型填写。切换供应商时,不要在不同工具之间复制错误的环境变量名。Claude Code 用ANTHROPIC_*,Codex 用config.toml和TAOTOKEN_API_KEY,CC Switch 用三件套。这样本地工具和线上小程序代理各自独立,不会互相污染。
如果你需要更详细的 Claude Code 配置说明,可以在文末查看 TaoToken 的 Claude Code 文档。小程序侧仍然坚持后端代理,不要把本地工具的 Key 直接搬进小程序前端。
7. 上线前检查清单与下一步 CTA
在小程序发布体验版或正式版之前,建议按下面清单逐项检查:
- 小程序前端代码中搜索
YOUR_API_KEY,确认没有真实 Key。 - 搜索
Authorization,确认请求头只出现在云函数或服务端代码。 - 云函数环境变量已配置
TAOTOKEN_API_KEY,且没有写进index.js。 - Base URL 使用
https://taotoken.net/api,路径拼接正确。 - 云函数日志没有打印完整 Key。
- 小程序端对按钮做了防抖或 loading 限制。
- 云函数对
OPENID做了基本鉴权或频率限制。 - prompt 长度有上限,避免一次消耗过多 token。
- AI 返回内容在展示前做了必要的内容安全校验。
- 真机调试 Network 面板中,小程序发出的请求不包含上游
Authorization。
完成这些检查后,你的个人小程序就具备了“前端不暴露 Key”的最小安全形态。后续如果流量增加,可以把云函数替换为云托管或自建后端,但前端调用方式可以保持不变,仍然是“前端只调自己的服务,服务端持有 TaoToken Key”。
如果你还没有创建 Key,可以先从模型对话页面验证接口能力,再去控制台创建 Key,最后配置本地工具或小程序云函数。推荐路径如下:
- 模型对话体验:https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_cta_chat
- Coding Plan 查看:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_cta_plan
- 创建 API Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_cta_keys
- Claude Code 文档:https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_cta_claude_code
官网入口也可以直接访问:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=mini_program_checklist 。记住,小程序前端直调看起来是最短路径,但安全上不是。把 Key 留在服务端,把请求地址统一成https://taotoken.net/api,前端只调云函数,才是个人小程序接入微信 AI 时更稳的最小步骤。