Nodejs 使用 tedious 驱动模块连接 SqlServer:从 config 骨架到连接验证
1. 为什么 Node.js 连 SqlServer 总在第一步卡住很多 Node.js 项目一开始选型时数据库用的是 MySQL 或 MongoDB等到对接企业内网、老系统或者报表平台时才发现对方只给 SqlServer。这时候你打开 npm 搜驱动会看到mssql、tedious、msnodesqlv8好几个包名字都差不多文档又散很容易在第一步就卡住。tedious是微软 SqlServer 的纯 JavaScript TDS 协议实现不依赖 ODBC、不依赖系统驱动装完就能跑特别适合本地开发和测试环境。它也是mssql这个上层封装库的底层依赖所以你把tedious跑通后面换mssql或者接 ORM 都会顺很多。这篇文章就聚焦一件事用tedious从零写出一份能直接复制的 config 骨架再配一段最小验证脚本让你亲眼看到查询结果确认这条链路真的通了。适合谁看如果你正在写 Node.js 后端、需要连一个本地或测试机的 SqlServer或者你之前用mssql但没搞懂底层连接参数这篇都能直接跟做。我会把server、authentication、options这些字段逐个拆开讲再给一段带execSql的验证代码最后把常见的连接报错对照着排一遍。整个过程不需要你装额外驱动npm install tedious就够了。先说清楚一个前提SqlServer 默认走 1433 端口本地开发常用127.0.0.1或localhost。如果你用的是 Docker 起的 SqlServer端口映射和实例名要额外注意这个我在第 5 节排错里会专门讲。下面先从环境准备和依赖安装开始。2. 用 TaoToken 补齐 Node.js 接入 SqlServer 的配置骨架在写代码之前我想先聊一个实际开发里经常被忽略的环节当你把连接脚本写完之后往往还需要一个能快速验证模型输出、生成配置片段或者排查报错的辅助工具。我自己在调tedious的options字段时就习惯开一个对话窗口把报错原文贴进去让它帮我对照参数含义。TaoToken 就是这样一个入口它把模型对话、API Key 管理、接入文档放在了一起适合在写配置和排错时随手查。它的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置的时候直接写这个就行。如果你只是想验证某个模型能不能正常返回可以用模型对话页面如果你要长期跑编码任务或者 Agent可以看 Coding Plan需要生成 Key 就去 API Keys 页面。这几个入口我下面会分别给出链接。为什么在讲tedious的文章里要提这个因为连接 SqlServer 的坑大多不在 SQL 本身而在参数拼装和报错解读。比如options.encrypt设成true还是false、trustServerCertificate要不要开、authentication.type用default还是ntlm这些字段一旦写错报错信息又很含糊。这时候有一个能对话、能查文档的辅助工具效率会高很多。TaoToken 的接入文档在 https://taotoken.net/doc 里面有针对不同场景的配置说明你可以对照着看。具体到操作上你可以先去 API Keys 页面 https://taotoken.net/api-keys 生成一个 Key然后在模型对话页面 https://taotoken.net/chat 里贴一段你的tediousconfig问它「这个 config 连本地 SqlServer 还缺什么字段」。实测下来它对authentication和options的字段解释比较到位能帮你省掉翻官方文档的时间。如果你要接 Claude Code 做编码辅助可以看 https://taotoken.net/claude-code 要跑 Coding Plan 就看 https://taotoken.net/coding-plan 。控制台在 https://taotoken.net/console Key 和用量都在那里管。需要说明的是TaoToken 在这里的角色是辅助你写配置和排错的工具不是替代tedious本身。tedious负责真正的数据库连接TaoToken 负责在你卡住的时候给你一个能问的地方。两者不冲突配合起来用就行。下面进入正题先装依赖、建表再写 config。3. 可复制的 tedious config 骨架与最小验证脚本这一节是全文的核心我会给出完整的package.json依赖、一份config.js骨架、一段app.js验证脚本以及建表 SQL。你按顺序复制就能跑。先初始化项目并安装tediousmkdir node-tedious-demo cd node-tedious-demo npm init -y npm install tedious安装完成后package.json里会出现tedious: ^16.x.x这样的依赖。注意tedious的版本更新比较快16 以上版本对authentication字段的结构有调整老教程里的userName/password顶层写法在新版里会报警告建议统一用authentication对象。接下来建一份config.js这是你要复制的 config 骨架// config.js module.exports { server: 127.0.0.1, // SqlServer 地址本地开发常用 127.0.0.1 port: 1433, // 默认端口Docker 映射时按实际改 authentication: { type: default, // 默认账号密码认证 options: { userName: sa, // 你的登录名 password: YourStrongPassw0rd // 你的密码 } }, options: { database: BigDataTest, // 目标数据库 encrypt: false, // 本地开发通常 false云上或强制加密时 true trustServerCertificate: true, // encrypt 为 true 且自签证书时设为 true rowCollectionOnRequestCompletion: true, // 回调里能拿到完整行集合 requestTimeout: 15000, // 请求超时毫秒 connectTimeout: 15000 // 连接超时毫秒 } };这里几个字段值得单独说。server和port分开写比老版本把端口拼在 server 字符串里更清晰。authentication.type用default表示 SQL Server 身份验证如果你用的是 Windows 域账号才需要改成ntlm并补domain字段。options.encrypt是最容易踩坑的地方本地 SqlServer 如果没配证书encrypt: true会直接报证书错误所以本地开发先设false但如果你连的是云上实例通常要求encrypt: true这时配合trustServerCertificate: true跳过自签证书校验。rowCollectionOnRequestCompletion: true这个选项很关键。默认情况下tedious的execSql回调只给你rowCount不给你行数据行数据要通过request.on(row)事件自己收集。开了这个选项之后回调的第三个参数rows就是完整的结果集验证脚本写起来更短。然后是建表 SQL在 SqlServer 里执行CREATE TABLE [dbo].[Citys]( [id] [int] IDENTITY(1,1) NOT NULL, [name] [nvarchar](100) NULL, [code] [varchar](300) NULL, CONSTRAINT [PK_Citys] PRIMARY KEY CLUSTERED ([id] ASC) ) ON [PRIMARY]; GO INSERT INTO [dbo].[Citys] ([name], [code]) VALUES (N北京, BJ); INSERT INTO [dbo].[Citys] ([name], [code]) VALUES (N上海, SH); INSERT INTO [dbo].[Citys] ([name], [code]) VALUES (N广州, GZ); GO建完表插几条数据方便验证。接着写app.js// app.js const { Connection, Request } require(tedious); const config require(./config); const connection new Connection(config); connection.on(connect, (err) { if (err) { console.error(连接出错:, err.message); process.exit(1); } console.log(连接成功!); getSqlData(); }); connection.connect(); function getSqlData() { const rows []; const request new Request( SELECT id, name, code FROM Citys, (err, rowCount, rowsFromCallback) { if (err) { console.error(查询出错:, err.message); connection.close(); return; } console.log(行数:, rowCount); const result rowsFromCallback || rows; result.forEach((row) { const obj {}; row.forEach((col) { obj[col.metadata.colName] col.value; }); console.log(${obj.id} | ${obj.name} | ${obj.code}); }); connection.close(); } ); request.on(row, (columns) { const row {}; columns.forEach((col) { row[col.metadata.colName] col.value; }); rows.push(row); }); connection.execSql(request); }这段脚本做了三件事建立连接、监听connect事件、执行查询并打印结果。注意connection.connect()要显式调用老版本里new Connection(config)会自动连新版需要手动触发。查询回调里我同时兼容了rowCollectionOnRequestCompletion开启和关闭两种情况开了就用第三个参数没开就用row事件收集的rows。如果你要接 Claude Code 做这类脚本的批量生成可以在 https://taotoken.net/claude-code 看接入方式要跑长期编码任务Coding Plan 在 https://taotoken.net/coding-plan 。这些是辅助入口不影响tedious本身的运行。4. 运行验证请求并确认连接成功配置和脚本都写完之后直接运行node app.js如果一切正常你会看到类似这样的输出连接成功! 行数: 3 1 | 北京 | BJ 2 | 上海 | SH 3 | 广州 | GZ看到这三行数据就说明从 Node.js 到 SqlServer 的链路完全通了。这里有几个细节可以帮你确认「真的成功」而不是「看起来成功」。第一连接成功!这行来自connect事件的回调err为null才会打印。如果连接失败你会看到连接出错:加上具体错误信息脚本会以退出码 1 结束。第二行数: 3来自execSql的回调rowCount是数据库返回的实际行数和表里的数据条数对得上才算真通。第三每行数据都打印了id | name | code说明列名映射和值读取都正常。如果你想进一步验证参数化查询可以把SELECT换成带参数的写法避免 SQL 注入const { TYPES } require(tedious); const request new Request( SELECT id, name, code FROM Citys WHERE code code, (err, rowCount, rows) { if (err) { console.error(查询出错:, err.message); connection.close(); return; } console.log(匹配行数:, rowCount); connection.close(); } ); request.addParameter(code, TYPES.VarChar, BJ); connection.execSql(request);参数化查询是tedious的推荐用法addParameter的第二个参数是类型第三个是值。类型要和数据库列类型匹配code列是varchar(300)所以用TYPES.VarChar如果是nvarchar用TYPES.NVarChar。类型写错有时不会报错但会返回空结果这点要注意。另外如果你在验证过程中想快速确认某个字段的含义可以把config.js的内容贴到模型对话页面 https://taotoken.net/chat 里问一下比翻文档快。API Key 在 https://taotoken.net/api-keys 生成接入文档在 https://taotoken.net/doc 。这些入口在你排错时会比较顺手。跑通之后建议把connection.close()放在回调里避免进程挂起不退出。如果你忘了关连接node app.js会一直停在那里不返回这也是新手常见的一个「以为卡死」的情况。5. 常见连接报错排查对照这一节把tedious连 SqlServer 时最常遇到的几个报错列出来对照着改就行。报错一ConnectionError: Failed to connect to 127.0.0.1:1433 - connect ECONNREFUSED这是最直白的错误意思是端口没人监听。先确认 SqlServer 服务是否启动Windows 上可以在服务管理器里看SQL Server (MSSQLSERVER)是否在运行。如果是 Docker 起的检查端口映射是不是-p 1433:1433以及容器是否还在跑。还有一种情况是 SqlServer 配置了 TCP/IP 协议但没启用需要在 SqlServer 配置管理器里把 TCP/IP 打开并重启服务。报错二ConnectionError: Login failed for user sa账号密码不对或者sa账号被禁用。SqlServer 安装时如果选的是 Windows 身份验证模式sa是禁用的需要改成混合模式再启用sa。另外密码里如果有特殊字符注意在config.js里用引号包好别被转义。报错三ConnectionError: self signed certificate这个错误说明options.encrypt设成了true但服务器用的是自签证书。本地开发直接把encrypt改成false如果必须加密就加trustServerCertificate: true。云上实例通常要求encrypt: true这时trustServerCertificate也要一起开否则证书链校验过不去。报错四ConnectionError: Failed to connect - getaddrinfo ENOTFOUNDserver字段写错了或者 DNS 解析不了。本地开发用127.0.0.1比localhost更稳因为有些环境localhost会解析到 IPv6 的::1而 SqlServer 只监听 IPv4。如果你用的是实例名比如localhost\SQLEXPRESStedious对实例名的支持有限建议直接用serverport的方式。报错五RequestError: Invalid object name Citys连接成功了但表不存在。检查options.database是不是写对了库名以及建表 SQL 是不是在同一个库里执行的。SqlServer 默认库是master如果你建表时没切库表就建到master里去了。报错六TypeError: Cannot read properties of undefined (reading colName)这个通常出现在row事件里columns结构和你预期的不一样。确认tedious版本16 以上版本columns里每项是{ metadata, value }metadata.colName才是列名。如果你从老教程复制代码可能用的是column.metadata.colName之外的写法对照本文第 3 节的脚本改一下。报错七进程不退出命令行一直挂着忘了调connection.close()。tedious的连接是长连接不关的话 Node 进程不会自动结束。把close()放在查询回调的最后或者用process.exit(0)强制退出不推荐生产环境要用close。排错时如果报错信息看不懂可以把原文贴到 https://taotoken.net/chat 里问或者对照 https://taotoken.net/doc 里的接入说明。控制台 https://taotoken.net/console 可以看 Key 的调用情况。这些工具在你反复调试options字段时会省不少时间。6. 把 tedious 接入脚本沉淀成可复用模块跑通第一条链路之后下一步通常是把它封装成项目里能复用的模块而不是每次都在app.js里写一遍。我自己的做法是拆成db.js和query.js两个文件db.js负责连接池和连接生命周期query.js负责把execSql包成 Promise这样在业务代码里就能用await query(SELECT ...)的写法。tedious本身没有内置连接池但可以用ConnectionPool类或者自己维护一个连接数组。对于本地开发和测试环境单连接加close就够了如果 QPS 高一点建议上mssql这个上层库它基于tedious封装了连接池和 Promise 接口配置字段和本文的config.js基本一致迁移成本很低。封装成 Promise 的核心思路是这样function execQuery(sql, params []) { return new Promise((resolve, reject) { const connection new Connection(config); connection.on(connect, (err) { if (err) return reject(err); const rows []; const request new Request(sql, (err, rowCount) { connection.close(); if (err) return reject(err); resolve({ rowCount, rows }); }); request.on(row, (columns) { const row {}; columns.forEach((col) { row[col.metadata.colName] col.value; }); rows.push(row); }); params.forEach((p) request.addParameter(p.name, p.type, p.value)); connection.execSql(request); }); connection.connect(); }); }这样在业务里就能写const { rows } await execQuery(SELECT * FROM Citys)。注意每次查询都新建连接在低频场景没问题高频场景要改成复用连接否则连接建立的开销会拖慢响应。最后提醒一个实际经验tedious的options字段在不同版本间有细微差异升级依赖后最好重新跑一遍本文第 4 节的验证脚本确认encrypt、trustServerCertificate、rowCollectionOnRequestCompletion这几个关键字段的行为没变。把验证脚本留在项目里当冒烟测试比每次手动连数据库靠谱得多。

相关新闻

DeepSeek Harness 插件化架构解析:从 settings.json 到 TaoToken 统一 Key 的配置骨架

DeepSeek Harness 插件化架构解析:从 settings.json 到 TaoToken 统一 Key 的配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 22:47:45 阅读更多 →
LLM、Agent、Skills、MCP:AI开发四大概念,一张图全搞懂!TaoToken 统一 Key 接入实战

LLM、Agent、Skills、MCP:AI开发四大概念,一张图全搞懂!TaoToken 统一 Key 接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 22:47:45 阅读更多 →
RoTBench 实战:用多级基准测出大语言模型工具学习的鲁棒性短板

RoTBench 实战:用多级基准测出大语言模型工具学习的鲁棒性短板

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 22:47:45 阅读更多 →

最新新闻

PLC会中病毒吗?解析恶意代码入侵路径与现场防御策略

PLC会中病毒吗?解析恶意代码入侵路径与现场防御策略

上周接到一个做设备维护的朋友打来的电话:产线上一个工位偶尔会自己多动作一次,时好时坏。换了传感器、查了接线,问题依旧。我让他用编程软件打开在线监视程序,翻了一会儿,发现梯形图里多了一个谁都没印象的计数器逻辑…

2026/9/30 23:46:22 阅读更多 →
从零手写 ClaudeCode:learn-claude-code 项目实战笔记(3)TodoWrite 待办写入与 TaoToken 配置

从零手写 ClaudeCode:learn-claude-code 项目实战笔记(3)TodoWrite 待办写入与 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 23:45:21 阅读更多 →
Python防止SQL注入的有效方法:TaoToken统一Key下的参数化查询与ORM实战

Python防止SQL注入的有效方法:TaoToken统一Key下的参数化查询与ORM实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 23:45:21 阅读更多 →
Augment Code 配 TaoToken:PyCharm 插件 AI 指令与代码生成配置指南

Augment Code 配 TaoToken:PyCharm 插件 AI 指令与代码生成配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 23:45:21 阅读更多 →
PLC也会中病毒?工控系统安全排查与防护实战指南

PLC也会中病毒?工控系统安全排查与防护实战指南

上个月处理一台产线的“怪病”:设备白天运行正常,凌晨三点左右主轴突然反转了几秒,现场工人根本没碰按钮,第二天查监控记录,发现定时器 T37 的设定值从 50 变成了 500。大家的第一反应是触摸屏被误触,可那块…

2026/9/30 23:45:21 阅读更多 →
大模型面试6场实录复盘:TaoToken统一Key打通RAG与Agent实战链路

大模型面试6场实录复盘:TaoToken统一Key打通RAG与Agent实战链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 23:45:21 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/30 13:14:22 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 18:13:06 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/30 13:14:49 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/30 15:27:04 阅读更多 →