资讯详情

资讯详情

TypeScript 学习笔记(九):TypeScript 与数据库的结合应用——用 TaoToken 统一 Key 打通 TypeORM 与 Mongoose 调试链路

1. 双数据库项目里本地调试为什么总在 Key 上卡住TypeScript 项目里同时接 MySQL 和 MongoDB 并不稀奇订单、账务这类强关系数据放 MySQL日志、配置、内容快照这类半结构化数据放 MongoDB。真正让人头疼的不是写实体和 Schema而是本地调试阶段两条链路各自为政——TypeORM 连一个地址Mongoose 连另一个地址模型调用又要走一层 HTTP 接口Key 散落在.env、ormconfig.json、mongoose.connect()三个地方。改一次环境三处都要动漏一处就报 401 或者连接超时。这篇笔记聚焦一个具体场景你在本地用 TypeScript 同时接入 MySQLTypeORM与 MongoDBMongoose并且模型推理/调试请求需要统一走一个入口。我会给出可复制的tsconfig路径映射、TypeORMDataSource配置、Mongoose 连接片段然后把本地调试请求的 endpoint 与 Base URL 改到 TaoToken用同一把 Key 验证两条数据库链路读写是否正常。适合已经写过 TypeORM 实体、用过 Mongoose Schema但在多模型联调时被 Key 和地址管理搞烦的人。核心检索词先摆出来TypeScript 数据库结合应用、TypeORM 连接 MySQL、Mongoose 连接 MongoDB、TaoToken 统一 Key 调试。这四个词贯穿全文你按顺序跟做即可。先说清楚 TaoToken 在这里的角色它是一个统一的模型调用入口提供兼容常见 SDK 的 Base URL 和 API Key。你不需要在代码里硬编码多个厂商的地址把 Base URL 指向https://taotoken.net/apiKey 用同一把模型 ID 按需切换。数据库本身还是连你本地的 MySQL 和 MongoDBTaoToken 管的是模型调用这条链路两者不冲突。这一点必须先分清否则后面配置会乱。我试过把两条链路的调试请求都收敛到一个.env里配合tsconfig的路径别名改地址只改一行。下面从项目结构开始。2. TaoToken 前置准备Base URL、Key 与模型 ID 三件套在动手改数据库配置之前先把模型调用这条链路的前置条件备齐。TaoToken 的接入只需要三样东西Base URL、API Key、Model ID。这三件套在后续 TypeORM 和 Mongoose 的调试脚本里会反复出现所以先统一放好。Base URL 固定为https://taotoken.net/api注意这里不带任何查询参数直接作为 SDK 的baseURL或base_url使用。API Key 需要你在控制台创建创建入口在 API Keys 页面登录后新建一个 Key复制出来存到本地.env不要提交到 Git。Model ID 取决于你要调用的模型比如做代码补全、结构化抽取、文本润色时选对应的模型标识即可具体可选列表在模型对话页面能看到。这里给一个.env的写法把数据库配置和模型配置放在一起方便统一管理# .env # MySQL DB_HOST127.0.0.1 DB_PORT3306 DB_USERNAMEroot DB_PASSWORDyour_mysql_password DB_DATABASEts_demo # MongoDB MONGO_URImongodb://127.0.0.1:27017/ts_demo # TaoToken 模型调用 TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEYsk-你的Key TAOTOKEN_MODEL_ID你的模型ID注意.env要加进.gitignore。很多 401 报错不是 Key 错了而是 Key 被提交后轮换了本地还是旧值。这个坑后面排障章节会再提。关于 Key 的获取和模型选择你可以直接去控制台操作API Keys 页面创建 Key模型对话页面确认模型 ID。这两个页面是后续所有配置的来源建议先打开确认一遍再往下走。如果你打算长期在这个项目里做编码和 Agent 联调而不是只跑一次验证可以考虑 Coding Plan它更适合持续性的编码场景。但本篇的重点是本地调试链路打通先用按量 Key 验证即可。三件套备齐后进入项目结构配置。这里有个细节TAOTOKEN_BASE_URL我建议写成不带尾部斜杠的形式因为部分 SDK 在拼接/v1/chat/completions时对尾部斜杠处理不一致带斜杠可能出现双斜杠路径导致 404。这个在后面验证请求时会看到实际影响。3. 可复制配置tsconfig 路径映射 TypeORM DataSource Mongoose 连接这一节是全文的核心给出三份可直接复制的配置。先看项目结构我按下面这样组织ts-db-demo/ ├── src/ │ ├── entity/ │ │ └── User.ts │ ├── models/ │ │ └── Log.ts │ ├──>{ compilerOptions: { target: ES2020, module: commonjs, moduleResolution: node, experimentalDecorators: true, emitDecoratorMetadata: true, strict: true, esModuleInterop: true, skipLibCheck: true, outDir: dist, baseUrl: ., paths: { entity/*: [src/entity/*], models/*: [src/models/*], root/*: [src/*] } }, include: [src/**/*.ts] }experimentalDecorators和emitDecoratorMetadata是 TypeORM 实体装饰器必需的缺了会报Unable to resolve signature of class decorator。paths里的baseUrl必须是.否则别名解析不到。如果你用ts-node直接跑还需要在package.json里加ts-node的require配置或者用tsconfig-paths注册否则运行时会找不到别名模块。3.2 TypeORM DataSource 配置TypeORM 0.3 之后推荐用DataSource而不是旧的createConnection。src/data-source.tsimport reflect-metadata; import dotenv/config; import { DataSource } from typeorm; import { User } from entity/User; export const AppDataSource new DataSource({ type: mysql, host: process.env.DB_HOST, port: parseInt(process.env.DB_PORT || 3306, 10), username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, synchronize: true, logging: false, entities: [User], migrations: [], subscribers: [], });entities这里直接写类引用比 glob 字符串更稳尤其在ts-node下 glob 有时匹配不到。synchronize: true只建议本地开发用生产必须关掉否则会改表结构。3.3 Mongoose 连接配置src/mongo.tsimport dotenv/config; import mongoose from mongoose; export async function connectMongo(): Promisetypeof mongoose { const uri process.env.MONGO_URI as string; if (!uri) { throw new Error(MONGO_URI is not defined); } mongoose.set(strictQuery, true); await mongoose.connect(uri, { serverSelectionTimeoutMS: 5000, }); console.log(MongoDB connected); return mongoose; }serverSelectionTimeoutMS设成 5000 是为了本地连不上时快速失败而不是默认 30 秒干等。strictQuery设 true 可以避免查询里带未知字段时静默忽略。3.4 模型调试脚本src/debug-model.ts用同一把 Key 调 TaoToken验证模型链路import dotenv/config; const BASE_URL process.env.TAOTOKEN_BASE_URL as string; const API_KEY process.env.TAOTOKEN_API_KEY as string; const MODEL_ID process.env.TAOTOKEN_MODEL_ID as string; export async function pingModel(prompt: string): Promisestring { const res await fetch(${BASE_URL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY}, }, body: JSON.stringify({ model: MODEL_ID, messages: [{ role: user, content: prompt }], }), }); if (!res.ok) { const text await res.text(); throw new Error(Model request failed: ${res.status} ${text}); } const data (await res.json()) as { choices: Array{ message: { content: string } }; }; return data.choices[0].message.content; }注意BASE_URL后面拼的是/v1/chat/completions所以.env里的TAOTOKEN_BASE_URL不要带尾部斜杠否则会变成//v1/...。这个细节在排障章节会对应到具体报错。三份配置就位后package.json的脚本可以这样写{ scripts: { dev:mysql: ts-node -r tsconfig-paths/register src/run-mysql.ts, dev:mongo: ts-node -r tsconfig-paths/register src/run-mongo.ts, dev:model: ts-node -r tsconfig-paths/register src/run-model.ts } }tsconfig-paths/register是让运行时也认entity/*这类别名的关键少了它ts-node会报Cannot find module entity/User。4. 验证请求同一把 Key 跑通两条数据库链路配置写完接下来是实际验证。验证分三步先确认 MySQL 读写再确认 MongoDB 读写最后确认模型调用链路三者用同一套.env。4.1 验证 TypeORM 读写src/run-mysql.tsimport { AppDataSource } from root/data-source; import { User } from entity/User; async function main() { await AppDataSource.initialize(); console.log(MySQL connected); const repo AppDataSource.getRepository(User); const saved await repo.save( repo.create({ firstName: John, lastName: Doe, age: 25 }) ); console.log(Saved user id:, saved.id); const all await repo.find(); console.log(All users:, all); await AppDataSource.destroy(); } main().catch((err) { console.error(MySQL error:, err); process.exit(1); });运行npm run dev:mysql预期输出MySQL connected Saved user id: 1 All users: [ User { id: 1, firstName: John, lastName: Doe, age: 25 } ]如果Saved user id有值且All users能查到说明 TypeORM 链路正常。4.2 验证 Mongoose 读写src/run-mongo.tsimport { connectMongo } from root/mongo; import Log from models/Log; async function main() { await connectMongo(); const created await Log.create({ level: info, message: mongo write ok, createdAt: new Date(), }); console.log(Saved log id:, created._id.toString()); const logs await Log.find().limit(5); console.log(Recent logs:, logs); } main().catch((err) { console.error(Mongo error:, err); process.exit(1); });运行npm run dev:mongo预期输出里能看到Saved log id和Recent logs数组。两条数据库链路都通了说明本地 MySQL 和 MongoDB 服务正常配置也没问题。4.3 验证模型调用链路src/run-model.tsimport { pingModel } from root/debug-model; async function main() { const reply await pingModel(用一句话说明 TypeScript 的类型收窄); console.log(Model reply:, reply); } main().catch((err) { console.error(Model error:, err); process.exit(1); });运行npm run dev:model。如果返回一段正常文本说明 Base URL、Key、Model ID 三件套都对。如果报 401先查 Key如果报 404先查 Base URL 尾部斜杠如果报reading choices说明响应结构不是预期的 chat completions 格式多半是 Model ID 或路径不对。4.4 把两条链路串起来真正体现「统一 Key」价值的是把数据库写入和模型调用放在一个脚本里。比如写入一条日志后让模型对日志内容做摘要再写回 MongoDBimport { connectMongo } from root/mongo; import Log from models/Log; import { pingModel } from root/debug-model; async function main() { await connectMongo(); const raw 用户登录失败三次IP 归属地异常; const summary await pingModel(请用不超过20字总结${raw}); await Log.create({ level: warn, message: raw, summary }); console.log(Summary saved:, summary); } main().catch((err) { console.error(err); process.exit(1); });这个脚本同时用到 Mongoose 和 TaoTokenKey 只有一把地址只有一处。跑通它说明你的多模型联调链路已经收敛。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来对照每个报错给出定位方法和修复动作。401 Unauthorized。最常见的原因是 Key 没读到或已失效。先确认.env里TAOTOKEN_API_KEY没有多余空格和引号再确认脚本里import dotenv/config在读取process.env之前执行。如果 Key 是从控制台复制的注意不要漏掉前缀。还有一种情况是 Key 被提交到 Git 后轮换了本地还是旧值重新在 API Keys 页面生成一个替换即可。local proxy failed / connect ECONNREFUSED。这个报错通常出现在你本地配了 HTTP 代理但代理进程没起来或者NO_PROXY没排除本地地址。检查系统环境变量里的HTTP_PROXY、HTTPS_PROXY如果不需要代理就清掉如果本地 MySQL/MongoDB 连不上也会报ECONNREFUSED 127.0.0.1:3306或:27017这时先确认数据库服务是否启动端口是否被占用。Cannot read properties of undefined (reading choices)。这个报错说明data.choices是 undefined即响应体不是标准的 chat completions 结构。三种可能Base URL 少了/v1或多了尾部斜杠导致路径错误Model ID 写错导致返回了错误对象请求体里messages格式不对。修复方式是先打印res.status和原始文本确认返回内容再调整。OAuth / token 相关报错。如果你用的是某些 CLI 工具比如 Claude Code 这类它可能走 OAuth 流程而不是 API Key。这种情况下要确认工具支持 API Key 模式并把 Base URL 指向https://taotoken.net/apiKey 用控制台生成的。如果工具只认 OAuth那就换用支持 Key 的调用方式或者参考接入文档里的说明。Cannot find module entity/User。这是路径别名在运行时没生效。确认package.json脚本里带了-r tsconfig-paths/register并且tsconfig.json的baseUrl是.。如果还不行检查include是否覆盖了src/**/*.ts。MongooseServerSelectionError。MongoDB 连不上先确认MONGO_URI里的库名和端口再确认 MongoDB 服务是否允许本地连接。本地开发一般不需要认证如果开了认证要补用户名密码。TypeORM EntityMetadataNotFoundError。实体没被注册。检查data-source.ts的entities数组是否包含对应实体类用类引用而不是字符串 glob 更稳。排障时建议按「先数据库、再模型」的顺序因为数据库报错和模型报错的表现完全不同混在一起排查容易乱。数据库链路用npm run dev:mysql和npm run dev:mongo单独验证模型链路用npm run dev:model单独验证都通过后再跑串联脚本。6. 把 Key 收敛到一处后续联调才不返工走到这里你的项目应该已经能用同一把 Key 跑通 TypeORM 写 MySQL、Mongoose 写 MongoDB、以及模型调用三条链路。回头看真正省事的地方在于把 Base URL 和 Key 收敛到.env一处tsconfig路径映射让导入不再依赖相对层级DataSource和mongoose.connect各自只读环境变量。后续如果你要加更多模型调用比如做结构化抽取、代码补全、日志摘要只需要在debug-model.ts里复用pingModel换 Model ID 即可不用再动数据库配置。如果你要长期在这个项目里做编码和 Agent 联调可以了解 Coding Plan它更适合持续性的编码场景如果只是验证模型效果模型对话页面能直接试。最后留一个实用技巧把TAOTOKEN_BASE_URL、TAOTOKEN_API_KEY、TAOTOKEN_MODEL_ID三个变量在.env.example里留空模板提交到仓库真实.env不提交。这样团队里每个人拉下来只需要填自己的 Key数据库地址和模型地址保持一致联调时不会再出现「你那边能跑我这边 401」的情况。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →