ARTICLE DETAIL

资讯详情

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

Node.js基础7:连接mongo数据库上传文件,TaoToken统一Key配置避坑指南

Node.js基础7:连接mongo数据库上传文件,TaoToken统一Key配置避坑指南 1. 从一次「Key 到处贴」的翻车说起Node.js 基础第 7 篇我们做的是连接 mongo 数据库并上传文件用 express-generator 起项目mongoose 连库formidable 收文件bcryptjs 加密密码最后把用户信息和头像地址写进 users 集合。这套流程本身不复杂真正让人头疼的是另一件事——当你在同一个项目里同时用 Cline、Claude Code、CC Switch 这类工具时每个工具都要填一遍 API Key、Base URL、模型名改一次配置要翻四五个文件改漏一个就报 401。我试过把 Key 写死在.env里结果 Cline 读的是 VS Code 的 settings.jsonClaude Code 读的是~/.claude/settings.jsonCC Switch 又有自己的 config.toml三份配置各说各话。后来我把它们统一收敛到 TaoToken 的同一个 Key 和同一个 API 通道上配置只维护一份工具之间切换不再互相打架。这篇就把 mongo 连接、文件上传的完整代码和这套统一 Key 的配置骨架一起交付给你适合正在学 Node.js 全栈、同时又在用 AI 编码工具的同学。核心检索词先摆出来Node.js 连接 mongo 数据库、上传文件、TaoToken 统一 Key 配置。读完你能拿到可复制的 settings.json 与 config.toml 骨架、CC Switch 和 Cline 的接入步骤以及连接 mongo 与文件上传的验证动作。2. TaoToken 前置一个 Key 管住所有工具TaoToken 在这里扮演的角色是「统一入口」你只在它这里拿一次 API Key之后 Cline、Claude Code、CC Switch 都指向同一个 Base URL 和同一个 Key。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址固定为 https://taotoken.net/api 注意 API 地址后面不加任何 UTM 参数填错会导致请求 404。为什么要在写 mongo 项目时先配这个因为你在写routes/users.js的时候大概率会让 AI 帮你补全 formidable 的form.parse回调、bcrypt 的加密强度、mongoose 的findById写法。如果工具 Key 散落你会在「代码写一半 → 工具报鉴权失败 → 去翻配置」之间反复横跳。统一 Key 之后工具层稳定你才能专注在业务代码上。拿 Key 的路径进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建一个 Key复制出来先存到密码管理器。这个 Key 后面会同时出现在 settings.json 和 config.toml 里所以命名建议带项目前缀比如node-mongo-demo方便你日后区分。注意Key 只创建一次就够不要每个工具建一个。多 Key 反而会让「哪个工具用了哪个额度」变得不可追踪。3. 可复制配置settings.json 与 config.toml 骨架先给 ClineVS Code 插件用的 settings.json 骨架。路径通常在 VS Code 的用户设置里或者项目级.vscode/settings.json。关键是apiProvider选 openai 兼容模式baseUrl指向 TaoToken 的 API 地址apiKey填你刚创建的那把。{ cline.apiProvider: openai, cline.openAiBaseUrl: https://taotoken.net/api, cline.openAiApiKey: sk-你的TaoTokenKey, cline.openAiModelId: claude-sonnet-4-5, cline.openAiModelInfo: { maxTokens: 8192, contextWindow: 200000 } }再给 Claude Code / CC Switch 用的 config.toml 骨架。CC Switch 的作用是帮你在多个 API 通道之间切换配置里同样只保留一份 TaoToken 通道[[providers]] name taotoken base_url https://taotoken.net/api api_key sk-你的TaoTokenKey model claude-sonnet-4-5 [settings] default_provider taotoken timeout_seconds 120如果你用的是 Claude Code 原生命令行环境变量方式更直接export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的TaoTokenKey这三份配置的共同点是Base URL 完全一致Key 完全一致只有「工具怎么读」不同。改 Key 的时候三处一起改或者干脆用环境变量注入避免硬编码。CC Switch 的接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各工具的字段对照表填之前对一眼能省很多试错。4. 项目骨架express-generator mongoose formidable配置搞定回到 Node.js 本体。先建项目mkdir mondo-express cd mondo-express npx express-generator npm i npm i mongoose formidable bcryptjs npm i -D nodemon然后把package.json的启动脚本改成 nodemon省得每次手动重启scripts: { start: nodemon ./bin/www }4.1 model/index.js 连接 mongo在model目录下建index.js定义 Schema 并连接数据库。注意 mongoose 7 之后connect返回 Promise建议加.catch兜底const mongoose require(mongoose); mongoose .connect(mongodb://127.0.0.1:27017/runoob) .then(() console.log(mongo connected)) .catch((err) console.error(mongo error:, err.message)); const userSchema new mongoose.Schema({ username: String, password: String, gender: String, tel: String, avatarUrl: String, }); module.exports mongoose.model(runoob, userSchema, users);这里用127.0.0.1而不是localhost是因为部分 Node 版本下 localhost 会先解析 IPv6 的::1而 mongo 默认只监听 IPv4导致连接超时。这个坑我在本地环境踩过换成 127.0.0.1 立刻通。4.2 app.js 挂载连接与路由在app.js顶部引入 model引入即触发连接并挂载 users 路由const createError require(http-errors); const express require(express); const path require(path); const cookieParser require(cookie-parser); const logger require(morgan); require(./model/index); // 引入即连接 mongo const indexRouter require(./routes/index); const usersRouter require(./routes/users); const app express(); app.set(views, path.join(__dirname, views)); app.set(view engine, jade); app.use(logger(dev)); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, public))); app.use(/static, express.static(path.join(__dirname, static))); app.use(/, indexRouter); app.use(/users, usersRouter); app.use(function (req, res, next) { next(createError(404)); }); app.use(function (err, req, res, next) { res.locals.message err.message; res.locals.error req.app.get(env) development ? err : {}; res.status(err.status || 500); res.render(error); }); module.exports app;多了一行app.use(/static, ...)是为了让上传后的头像能通过/static/upload/xxx.png访问到否则前端拿到 avatarUrl 也显示不出来。4.3 routes/users.js 增删改查与文件上传这是核心文件遵循 REST 风格GET 查、POST 增、PUT 改、DELETE 删。上传用 formidable密码用 bcryptjs 加密。const express require(express); const path require(path); const formidable require(formidable); const bcrypt require(bcryptjs); const db require(../model/index); const router express.Router(); // 查找有 _id 查单条没有查全部 router.get(/:_id?, (req, res) { const { _id } req.params; if (_id) { db.findById(_id).then((data) { res.json({ code: 200, status: 1, data }); }); } else { db.find().then((data) { res.json({ code: 200, status: 0, data }); }); } }); // 增加上传头像 密码加密 router.post(/api/upload, (req, res, next) { const form formidable({ multiples: true, uploadDir: path.join(__dirname, ../static/upload), keepExtensions: true, }); form.parse(req, (err, fields, files) { if (err) { next(err); return; } const { name, password, gender, tel } fields; const avatar Array.isArray(files.avatar) ? files.avatar[0] : files.avatar; const avatarUrl /upload/ avatar.newFilename; if (!name || !password) { res.json({ code: 200, status: 1, message: 用户名或密码不能为空 }); return; } db.findOne({ username: name }).then((exist) { if (exist) { res.json({ code: 200, status: 1, message: 用户名已存在 }); return; } const hash bcrypt.hashSync(password, 10); new db({ username: name, password: hash, gender, tel, avatarUrl }) .save() .then((data) { res.json({ code: 200, status: 0, message: data }); }); }); }); }); // 修改 router.put(/:_id, (req, res) { const { _id } req.params; const { username, password, gender, tel, avatarUrl } req.body; db.updateOne({ _id }, { username, password, gender, tel, avatarUrl }).then( () { res.json({ code: 200, status: 0, message: 修改成功 }); } ); }); // 删除 router.delete(/:_id, (req, res) { const { _id } req.params; db.deleteOne({ _id }).then(() { res.send({ code: 200, status: 0, message: 删除成功 }); }); }); module.exports router;formidable 3.x 里files.avatar可能是数组也可能是对象取决于multiples配置所以上面加了一行兼容判断。另外newFilename是 formidable 3 的新字段旧教程里的path已经废弃照抄老代码会拿到 undefined。4.4 上传目录与前端页面建目录mkdir -p static/upload在public/index.html放一个表单注意enctype必须是 multipartform action/users/api/upload methodpost enctypemultipart/form-data input typetext namename placeholder用户名 / input typepassword namepassword placeholder密码 / input typetext namegender placeholder性别 / input typetext nametel placeholder电话 / input typefile nameavatar / button typesubmit提交/button /form5. 验证请求从 curl 到浏览器启动服务npm start看到mongo connected说明数据库连上了。先验证查询接口curl http://127.0.0.1:3000/users返回{code:200,status:0,data:[]}表示路由和数据库都通。再验证上传curl -X POST http://127.0.0.1:3000/users/api/upload \ -F nametestuser \ -F password123456 \ -F gendermale \ -F tel13800000000 \ -F avatar./test.png成功会返回带_id的文档avatarUrl形如/upload/xxxx.png。浏览器打开http://127.0.0.1:3000/static/upload/xxxx.png能显示图片说明静态目录挂载正确。最后再查一次/users能看到新用户且 password 是 bcrypt 哈希串就全链路通了。如果你在验证阶段让 AI 工具帮你读报错记得工具已经指向 TaoToken 统一通道直接问就行不用再切配置。模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 把 curl 的报错贴进去让它分析比来回翻文档快。6. 本篇常见错排查报错一MongooseServerSelectionError: connect ECONNREFUSED ::1:27017原因就是前面说的 IPv6 解析问题。把连接串里的localhost换成127.0.0.1或者启动 mongo 时显式绑定 IPv4。报错二formidable拿到的files.avatar是 undefined检查前端表单有没有写enctypemultipart/form-data以及name属性是不是avatar。formidable 靠字段名匹配名字对不上就拿不到。报错三上传成功但图片 404uploadDir指向static/upload但app.js里没挂/static静态目录或者 avatarUrl 拼的是/upload/而实际访问路径是/static/upload/。两处路径要对齐。报错四AI 工具报 401 或 404401 通常是 Key 填错或带了多余空格404 多半是 Base URL 写成了https://taotoken.net/api/带尾斜杠或者误加了 UTM 参数。API 地址就是https://taotoken.net/api干净利落。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有各工具的字段校验清单对不上时逐项核。报错五bcrypt.hashSync卡住或报错bcryptjs 是纯 JS 实现不需要编译但如果误装了bcrypt原生模块在部分环境会编译失败。确认package.json里是bcryptjs。7. 配置收敛之后把精力留给业务mongo 连接和文件上传这套代码写一遍就熟了真正消耗时间的是环境配置的反复折腾。把 Cline、Claude Code、CC Switch 全部指向 TaoToken 的同一个 Key 和同一个 API 通道之后你改一次配置就能全局生效写routes/users.js时让工具补全 formidable 回调、bcrypt 强度、mongoose 查询链都不会再被鉴权打断。如果你后面要长期在这个项目上做编码和 Agent 任务可以看下 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它更适合持续性的代码生成场景只是偶尔验证模型效果用模型对话页就够了。配置骨架已经给你了接下来把static/upload目录建好跑一遍 curl看到那条带_id的返回这篇的任务就完成了。
返回列表