
1. 从登录态到 AI 调用一个 Node 学习项目里的两条链路如果你正在用 NodeExpressMongoDBMongoose 写一个带登录注册的练手项目大概率会经历这么几个阶段先跑通路由再连上 MongoDB然后用 Mongoose 建模型接着用 CookieSession 把登录态维护起来。这套链路本身不复杂但当你开始往项目里塞 AI 能力——比如做一个智能问答接口、代码补全、或者给后台加个 AI 助手——就会遇到新的麻烦每个 AI 工具都要单独配 KeyCline、Claude Code、CC Switch 各配一遍环境变量散落在不同文件里本地调试和生产环境还对不上。这篇笔记就聚焦这个场景在一个 NodeExpressMongoDBMongoose 的学习项目里用 CookieSession 维护登录态同时用 TaoToken 的统一 Key 把 AI 调用链路接进来。我会给出可复制的配置骨架、CC Switch/Cline 的配置片段以及验证请求的具体动作。适合已经能跑通 Express 基础路由、想同时把鉴权和 AI 调用打通的同学。核心检索词先摆出来NodeExpressMongoDBMongoose 项目里CookieSession 负责用户登录态TaoToken 负责统一 AI Key 和 API 通道两者互不干扰一个管“你是谁”一个管“你调哪个模型”。2. TaoToken 前置统一 Key 与 API 通道是什么TaoToken 做的事情简单说就是把多个 AI 模型的调用收敛到一个 Key、一个 API 地址上。你不用在 Cline 里填一个 Key、在 Claude Code 里填另一个、在 CC Switch 里再填一个而是统一走同一个入口。官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。在动手之前你需要先拿到 Key。进入控制台创建 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建完之后Key 只在创建时显示一次记得复制保存。如果你还没决定用哪个模型可以先到模型对话页面试试效果地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。这里要区分两个概念CookieSession 是你自己项目里的用户登录态跟 TaoToken 没关系TaoToken 的 Key 是你调用 AI 模型时的凭证。两者在代码里是分开管理的一个存在 MongoDB 的 session 集合里一个存在环境变量或配置文件里。别把 AI 的 Key 写进 session也别把用户密码写进 AI 配置。对于长期编码和 Agent 场景可以了解 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。3. 可复制配置settings.json / config.toml 骨架先给项目装依赖。假设你已经有一个 Express 项目目录结构大概是 app.js、route/、model/、config/ 这样。先补上 CookieSession 和 AI 调用需要的包npm install express-session connect-mongo cookie-parser mongoose axios dotenvexpress-session管会话connect-mongo把 session 持久化到 MongoDBcookie-parser解析 Cookieaxios用来发 AI 请求dotenv读环境变量。3.1 config/default.json 骨架在项目根目录建 config 文件夹放一个 default.json把数据库和 session 的公共配置放进去{ db: { uri: mongodb://localhost:27017/learn_auth }, session: { name: learn.sid, secret: replace-with-your-secret, maxAge: 1800000 }, ai: { baseURL: https://taotoken.net/api, model: gpt-4o-mini } }session.maxAge单位是毫秒1800000 就是 30 分钟。ai.baseURL固定指向 TaoToken 的 API 地址ai.model先填一个你打算用的模型名后面验证时再确认。3.2 custom-environment-variables.json 存敏感信息Key 和 secret 不要写死在 default.json 里。在 config 文件夹再建一个 custom-environment-variables.json{ session: { secret: SESSION_SECRET }, ai: { apiKey: TAOTOKEN_API_KEY } }然后在项目根目录建 .env 文件SESSION_SECRETyour-random-session-secret TAOTOKEN_API_KEYsk-你的TaoTokenKey.env 记得加进 .gitignore。这样 config 模块会自动把环境变量映射到配置项上代码里用config.get(ai.apiKey)就能拿到。3.3 app.js 里的 session 与 AI 客户端初始化const express require(express); const session require(express-session); const MongoStore require(connect-mongo); const cookieParser require(cookie-parser); const config require(config); const axios require(axios); const app express(); app.use(express.json()); app.use(cookieParser()); app.use(session({ name: config.get(session.name), secret: config.get(session.secret), cookie: { httpOnly: true, maxAge: config.get(session.maxAge) }, saveUninitialized: false, resave: false, store: MongoStore.create({ mongoUrl: config.get(db.uri), touchAfter: 24 * 3600 }) })); const aiClient axios.create({ baseURL: config.get(ai.baseURL), headers: { Authorization: Bearer ${config.get(ai.apiKey)}, Content-Type: application/json }, timeout: 30000 }); module.exports { app, aiClient };这里MongoStore.create的写法对应 connect-mongo 4.x 及以上版本如果你用的是旧版写法是new MongoStore({ url: ... })注意区分。aiClient单独抽出来后面所有 AI 调用都走它。3.4 CC Switch / Cline 配置片段如果你在本地用 Cline 或 CC Switch 这类工具调模型配置里填 TaoToken 的地址和 Key。以 Cline 为例在设置里选 OpenAI CompatibleBase URL 填https://taotoken.net/apiAPI Key 填你的 TaoToken KeyModel 填你要用的模型名。CC Switch 的配置类似核心就是三样Base URL、API Key、Model。如果你用的是 Claude Code 相关的接入方式参考文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里的说明ClaudeCodeAnthropic 的配置入口在 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。4. 验证请求登录态与 AI 调用各跑一遍配置写完先验证 CookieSession 能不能正常种下和读取。写一个最简单的登录路由app.post(/login, (req, res) { const { username } req.body; req.session.user { username }; res.json({ ok: true, user: req.session.user }); }); app.get(/me, (req, res) { if (!req.session.user) { return res.status(401).json({ ok: false, msg: 未登录 }); } res.json({ ok: true, user: req.session.user }); });启动服务后用 curl 测curl -c cookies.txt -X POST http://localhost:3000/login \ -H Content-Type: application/json \ -d {username:test} curl -b cookies.txt http://localhost:3000/me第一条命令会把 Set-Cookie 写进 cookies.txt第二条带上 Cookie 请求 /me应该返回{ok:true,user:{username:test}}。如果第二条返回 401说明 session 没存住去检查 MongoStore 的连接和 secret 是否一致。再验证 AI 调用。加一个路由app.post(/ai/chat, async (req, res) { try { const { message } req.body; const resp await aiClient.post(/v1/chat/completions, { model: config.get(ai.model), messages: [{ role: user, content: message }] }); res.json({ ok: true, reply: resp.data.choices[0].message.content }); } catch (err) { res.status(500).json({ ok: false, msg: err.message }); } });用 curl 发一条curl -X POST http://localhost:3000/ai/chat \ -H Content-Type: application/json \ -d {message:用一句话解释什么是 Express 中间件}成功的话会返回一段模型生成的解释。如果返回 401检查 Authorization 头里的 Key 是否正确如果返回 404检查 baseURL 和路径拼接TaoToken 的 API 地址是https://taotoken.net/apichat 接口路径是/v1/chat/completions。5. 本篇常见错排查5.1 session 存不住每次请求都是新的最常见的原因是saveUninitialized: false加上没有真正修改 session。如果你只是读 session 不写Express 不会创建新会话。另一个原因是 MongoStore 连接失败session 回退到内存存储重启就丢。检查 MongoStore 的 mongoUrl 是否和 Mongoose 连的是同一个库。5.2 Cookie 没带上/me 一直 401先看响应头有没有 Set-Cookie。如果没有说明 session 没创建成功。如果有但后续请求没带检查 curl 有没有加-b cookies.txt浏览器里检查 Cookie 的 domain 和 path 是否匹配。httpOnly: true不影响服务端读取但前端 JS 读不到这是正常的。5.3 AI 请求 401 或 403Key 错了或者没带上。检查 .env 里的 TAOTOKEN_API_KEY 是否被正确加载可以在启动时打印config.get(ai.apiKey)的前几位确认。注意不要把 Key 提交到 Git。5.4 AI 请求超时默认 timeout 设了 30 秒如果模型响应慢会超时。可以适当调大或者在 axios 配置里加timeout: 60000。另外检查网络是否能正常访问 TaoToken 的 API 地址。5.5 Mongoose 连接和 session 存储冲突Mongoose 和 connect-mongo 各自建连接是正常的但如果你的 MongoDB 没启动两个都会报错。先确认net start mongodb或本地 mongod 进程在跑。数据库名建议分开比如 Mongoose 用 learn_authsession 也用同一个库但不同集合connect-mongo 默认集合名是 sessions。6. 把两条链路分开管项目才不乱CookieSession 管的是“这个请求是谁发的”TaoToken 管的是“这个请求要调哪个模型”。两者在代码里通过不同的配置项和不同的客户端实例隔离开session 走 express-session connect-mongoAI 调用走 axios TaoToken 的 baseURL。这样你换模型、换 Key 的时候不用动鉴权代码改登录逻辑的时候也不会影响 AI 调用。如果你后面要接更多 AI 工具比如在 Cline 里做代码补全、在 Claude Code 里做 Agent 任务统一用 TaoToken 的 Key 和 API 地址就行。需要看模型列表或试对话效果去 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 要管理 Key 去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 接入细节看文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。长期做编码和 Agent 的话Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。最后提醒一句.env 和 config 里的 secret 别用默认值session secret 换成一串随机字符串TaoToken Key 只在服务端用别暴露到前端。