
1. 为什么要把数据库工作台装进浏览器先说个我自己的切身体会。以前做项目排障最烦的就是数据库环境不统一Windows 上装 NavicatmacOS 上装 Sequel ProLinux 服务器上只能靠命令行用着用着发现同一个 SQL 在不同客户端里表现还不一样。更要命的是临时要查线上数据手边没有客户端还得先找安装包、配 SSH 隧道、连跳板机一套流程下来十分钟过去了问题还没定位到。DBViewer 解决的正是这个场景——把数据库工作台直接搬到浏览器里。你打开 Chrome、Edge、Firefox输入地址登录就能看到熟悉的连接管理、SQL 编辑器、结果集浏览、表结构设计这些功能。不需要安装任何原生客户端不需要在每台机器上重复配置环境只要浏览器能上网数据库工作台就随身带着。这个项目适合谁小团队里的后端开发、DBA、数据分析师或者公司内部需要给非技术同事提供“只读查询”入口的运维同学都很对口。我自己最早做这个东西就是想省掉“帮同事装客户端、配连接”这类重复劳动。后来发现它的价值远不止省事还顺带解决了权限管控、操作审计、版本统一这些桌面客户端很难做好的问题。有人可能会问浏览器里跑数据库工具性能行不行安全怎么保证跟原生客户端差距大不大这些问题我后面会逐一展开讲。先给结论对绝大多数日常工作场景浏览器里的数据库工作台完全够用而且在协作、审计、远程访问这些维度上体验反而比桌面客户端好不少。2. 整体设计思路与方案选型2.1 核心架构前端只做界面后端统一代理DBViewer 的架构并不复杂核心思路是“前端不直连数据库所有请求走后端代理”。浏览器里的 JavaScript 没有能力直接跟 MySQL、PostgreSQL 建立原生协议连接所以必须有一个后端服务作为桥接层。我当时的设计是这样后端用 Node.js 实现它对外提供一套 HTTP/WebSocket 接口对内管理多种数据库连接。前端是一个单页应用所有操作都通过接口发给后端由后端去执行 SQL、读取元数据、管理事务再把结果返回给浏览器。这个桥接层的存在让 DBViewer 天然具备了几个桌面客户端没有的能力——连接信息集中管理、操作日志统一记录、权限策略服务端控制。想做审计后端记一行日志就行想收回某个人对某个库的访问权改一下服务端配置就行不用挨个通知客户端。这里有个选型细节值得说为什么用 Node.js 而不是 Python 或 Go没有标准答案但 Node.js 的生态里数据库驱动非常全mysql2、pg、ioredis 这些库都很成熟而且它的异步模型处理大量并发查询请求时表现稳定。如果你更熟悉 Go用 Go 写桥接层也完全没问题核心架构是一样的。2.2 通信协议HTTP 接口为主WebSocket 做结果流式回传前端和后端之间的通信我建议按场景混用两种方式。常规操作比如获取数据库列表、读取表结构、执行 CRUD用 HTTP 接口就够了简单直观方便调试。但有一个场景必须用 WebSocket就是执行大查询、返回大数据集的时候。假如用户执行了一条SELECT * FROM 订单表返回几十万行如果用 HTTP 一次性响应前端等得久、后端内存压力大、网络传输还可能超时。用 WebSocket 做流式回传后端每查出一批数据就推给前端一批前端边收边渲染用户等待首屏的时间从“等全部查完”变成“等第一批数据到达”体感快很多。我在实现时给前端结果集加了一个“流式加载”模式默认每批取 500 行用户滚动到底部自动拉下一批。几千行数据秒开几十万行数据也不会卡死页面这个体验就很接近桌面客户端的“分页取数”了。2.3 多数据源支持让一个工作台管所有库现实中一个团队不可能只用一种数据库。MySQL、PostgreSQL、SQL Server、SQLite、Redis甚至 ClickHouse 这种列式存储都可能出现在不同的项目里。如果做一个只能连 MySQL 的 Web 工作台价值大打折扣。DBViewer 在设计上把“数据源类型”做成了抽象层。每种数据库实现一套适配器对外暴露统一的接口listDatabases()、listTables()、getTableSchema()、executeQuery(sql)。上层业务代码完全不知道底层连的是 MySQL 还是 PostgreSQL只管调接口。好处很明显新增一种数据库支持时不需要动前端和主逻辑只要照着适配器接口写一个实现类就行。我当时跑通 MySQL 和 PostgreSQL 只花了一个周末后面加 SQLite 支持就更快了因为核心逻辑完全复用。2.4 部署形态公司内网部署为主兼顾单机模式数据库工具嘛安全永远是第一位的所以我更推荐“内网部署 账号体系”的模式。把 DBViewer 的服务部署在公司内网的一台服务器上所有用户通过内网地址访问数据库连接串只配置在后端服务里前端永远接触不到真实密码。这样一来即使某个同事的电脑中了木马他浏览器里也拿不到数据库密码风险可控。当然如果是个人开发者自己用或者想在一台临时机器上快速连一下远程数据库单机模式也很有用。我把服务做成了一个可执行文件启动后自动打开浏览器配置一次连接信息就完事跟开一个本地小工具没什么区别。提示无论是哪种部署形态都建议在前面加一层 HTTPS。浏览器对“非 HTTPS 页面里的敏感请求”限制很严格有些接口在 HTTP 下会被浏览器拦截或警告加上 HTTPS 能省掉很多莫名其妙的兼容性问题。3. 核心功能实现与实操细节3.1 连接管理配置、测试、保存与共享连接管理是数据库工作台的入口也是最容易做得难用的地方。我的目标是让“添加一个连接”这件事在两分钟内完成。连接配置表单需要这几个字段连接名称、数据库类型、主机地址、端口、数据库名、用户名、密码。高级选项里可以填 SSL 配置、连接超时时间、是否只读模式。保存之前提供“测试连接”按钮后端拿到配置后尝试建立一条真实连接成功则返回版本号之类的基础信息失败则把错误信息原样返回给前端展示。连接信息存哪里是个关键决策。我建议把连接配置存在后端用配置文件或本地存储都行但密码字段必须加密。我见过把数据库密码明文存在前端 localStorage 里的设计这等于把钥匙挂在门上千万别学。连接共享是个额外加分项。团队里通常有一批“公共连接”比如测试环境数据库、预发环境数据库每个人都要连。与其让每个人各自配一遍不如管理员在后端维护一个公共连接列表所有登录用户都能看到。个人连接还是私有的别人看不到。这个功能上线后团队里让我帮忙配连接的消息少了一大半。3.2 SQL 编辑器不只是能跑 SQL 那么简单一个 Web 版 SQL 编辑器最基础的要求是能写、能跑。但真要当日常主力工具用下面这几个功能缺一不可。语法高亮和自动补全是刚需。写长 SQL 的时候没有高亮很容易看花眼没有补全则容易拼错表名和字段名。自动补全的数据来源是数据库元数据——连接建立后后端异步拉取表结构、字段名、索引信息生成补全词典。监听编辑器里的输入遇到.或空格就触发匹配。我用的 CodeMirror 6 写补全逻辑效果很顺滑。多标签页操作也是必须的。日常工作里经常要同时打开好几段 SQL 来回切换像写代码一样管理多个“文件”。每个标签页独立维护自己的编辑器状态跑完后结果区各自独立互不干扰。这个功能对习惯了 IDE 的开发来说没什么特别的但没有的话真的很难受。执行方式的细节也值得打磨。我支持三种执行模式选中执行、光标所在语句执行、全部执行。很常用的场景是SQL 文件里有 20 条语句我只想跑其中 2 条先选中再点执行而不是把整个文件丢给数据库跑。默认情况下我都建议新手把“执行”按钮绑到选中执行养成习惯后能少踩很多“误跑全量脚本”的坑。3.3 结果集浏览大数据量不卡才是真本事跑一条查询很简单难的是让结果集在浏览器里浏览得舒服。DBViewer 的结果集组件是我投入时间最多的部分之一。先说渲染方案。几千行以内随便渲染表格组件直接用现成的问题不大。但到了几万行、几十万行如果一次性把所有行都渲染成 DOM浏览器必卡。我用了虚拟滚动方案只渲染可视区域内的那几十行滚动时动态替换。这样即使结果集有十万行页面也能保持流畅。实测下来在普通办公电脑上滚动浏览十万行数据帧率依然稳定。再说单元格操作。结果集默认是只读的但开发调试时经常需要直接改几个值。我加了一个“行编辑模式”双击单元格就进入输入态改完点保存后端生成一条 UPDATE 语句并执行。要注意的是更新操作必须依赖主键没有主键的表不允许编辑避免一次误改整行或者改错行。这个限制很重要曾经有人为了图方便允许无主键表编辑结果一条 UPDATE 把整个表的数据都覆盖了教训深刻。导出功能也很常用。查询结果一键导出 CSV 或 Excel这个功能做出来很受欢迎。CSV 导出直接在后端完成按行流式写入不会撑爆内存。Excel 导出用 SheetJS 在前端生成因为涉及到格式设置比如列宽、对齐方式用前端库更灵活。3.4 表结构设计与数据导入导出除了查询数据日常开发也免不了要建表、改表。DBViewer 提供了一套可视化表结构设计器左侧选择表右侧展示字段列表支持增删字段、修改类型、设置默认值、建索引。所有操作都是“生成 DDL 语句”再提交执行方便审核。数据导入导出这块我踩过不少坑。CSV 导入看似简单实则细节很多编码是 UTF-8 还是 GBK第一行是表头还是数据字段分隔符是逗号还是制表符有的字段里本身就含逗号怎么办我的方案是导入前先让用户上传文件后端解析前 20 行做自动探测把猜测的编码、表头、分隔符显示出来让用户确认确认后再执行正式导入。这个“预解析 人工确认”的流程避免了很多导入错误。4. 安全、权限与审计一个都不能少4.1 认证与会话管理既然是 Web 应用账号认证就是第一道门。DBViewer 的登录凭证和数据库凭证是分开的用户表存的是系统账号数据库连接信息里的密码只存在后端配置文件或加密存储中。会话管理用的是 JWT Token登录成功后前端持有 Token每次请求带上。Token 设置了过期时间默认 8 小时过期后需要重新登录。对于公司内部工具这个时间长度比较友好不会像银行 App 那样动不动就让你重新登录。还有一个细节是“登录即验证”。用户登录时后端除了校验账号密码还会测试一下该用户所有已分配连接是否可用。如果某个连接已经失效比如数据库密码被改了登录后立刻能看到告警提示而不是等到点了某个库才报“连接失败”。4.2 细粒度操作权限不是每个登录用户都有权限执行所有操作。我把权限拆成了几层第一层是数据源权限控制用户能看到哪些连接。比如 A 用户只能看到测试环境连接B 用户能看测试和预发只有 C 用户能看生产。第二层是操作类型权限控制用户能做什么。只读用户只有查询权限不能执行 INSERT、UPDATE、DELETE、DDL开发用户能执行 DML 和 DDL但生产库会被额外限制比如禁止 DROP TABLE。第三层是行级限制。这个比较进阶比如只允许查看某张表中包含特定字段的记录或者强制查询加LIMIT 1000。生产环境的连接我建议默认开启这个限制防止有人不小心跑一个全表查询把数据库拖垮。4.3 操作审计日志数据库是公司的核心资产谁在什么时候执行了什么 SQL必须留痕。DBViewer 的审计日志记录了账号、时间、连接的数据库、执行的 SQL 原文、影响行数、执行耗时。对于生产环境的连接审计日志设为不可关闭只能追加不能删除或修改。这个功能上线后很多 DBA 同事反馈特别好因为以前出了问题排查 SQL 靠猜翻各种会话记录现在直接搜日志谁干了什么一清二楚。更重要的是审计日志本身就形成了一种威慑大家知道操作有记录执行高危 SQL 时就更谨慎了。4.4 前端安全检查清单安全不仅指后端权限前端也有不少容易被忽略的坑。XSS 是其中最常见的——数据库里存的数据可能是恶意内容比如用户昵称字段里写了scriptalert(1)/script如果前端渲染结果集时直接拼接 HTML脚本就会执行。我统一用文本节点渲染所有查询结果绝不用innerHTML拼接。CSRF 防护也不可忽视。所有写操作的接口都校验请求头里的自定义字段确认请求来自本站页面。Cookie 设置了SameSiteLax跨站请求不发 Cookie这个配置能挡掉绝大多数 CSRF 攻击。还有一点是 SQL 执行的“二次确认”。凡是检测到 DROP、TRUNCATE、DELETE 不带 WHERE 这类高危操作前端会弹确认框后端还会二次拦截。双重确认虽然多一步操作但能挡住很多“手滑”引发的灾难。5. 实操过程中的常见问题与排查技巧5.1 连接超时与空闲断连Web 工具最常见的报错就是“连接超时”和“连接已断开”。数据库连接默认有一个空闲超时时间通常 8 小时如果用户打开页面长时间不操作后端的数据库连接会被数据库服务端主动断开下次执行 SQL 就报错。解决方案有几个一是后端维护连接池定期发送心跳探测发现连接失效就重连二是前端在执行 SQL 前先发一个 Ping 接口确保连接可用再执行三是在报错信息里给出明确提示“连接已过期请重新连接”而不是让用户面对一堆底层异常信息。我自己遇到最多的情况是早上到公司打开昨晚挂着的页面一跑 SQL 就报“Connection is closed”。后来加了心跳机制这个问题基本绝迹了。5.2 查询大数据量导致浏览器卡死浏览器内存占用问题是所有 Web 数据库工具的宿命。跑了一个超大查询返回了 50 万行数据如果前端把这 50 万行全部装在内存里浏览器直接崩给你看。我的处理方式是三重防护第一后端强制给查询加一个行数上限默认 10 万行超过则截断并提示用户“查询结果已截断建议加 LIMIT 或使用流式加载”第二前端虚拟滚动不渲染不可见行第三导出大数据集时走后端流式导出不走前端内存。这三条叠加之后浏览器内存占用基本能控制在一个合理的范围。如果你自己也在做类似工具建议重点关注结果集组件的内存表现。Chrome 的 DevTools 里 Performance Monitor 可以实时看 JS 堆内存开发阶段多测几种极端场景别等上线了被用户骂了才回来修。5.3 并发操作与事务冲突多人同时操作同一张表时会出现锁等待、死锁、更新丢失等问题。DBViewer 里的事务管控原则是“短事务优先”。界面上给用户提供事务开关开启后执行的 SQL 会在同一个事务里用户可以手动 COMMIT 或 ROLLBACK。但这个功能只推荐给对事务有清晰认识的用户默认事务是关闭的每条 SQL 自动提交。遇到锁冲突时后端会捕获数据库的超时错误翻译成友好提示“表已被其他会话锁定请稍后重试。”前端还有一个“终止当前查询”的按钮可以发送 Kill 指令终止超时查询这个功能在同事误跑大查询时特别好用。5.4 浏览器兼容性与资源占用做 Web 工具绕不开浏览器兼容性。DBViewer 实测下来Chrome 和 Edge 表现最好Firefox 也基本正常Safari 偶尔有些样式小问题。我的建议是直接声明支持 Chrome/Edge 最新两个大版本Firefox 做兼容适配Safari 不做重点投入。与其花大精力兼容所有浏览器不如引导团队用统一浏览器内部工具这是很务实的做法。另外长时间挂着 DBViewer 页面浏览器内存占用会缓慢增长。排查发现是结果集组件的事件监听器没有及时清理旧的 WebSocket 连接未关闭。后来我在组件卸载时统一移除监听器、关闭连接内存泄漏问题解决。如果你用 React 或 Vue 做这类工具记得在useEffect的清理函数里处理这些资源释放。5.5 证书问题与混合内容拦截公司内网部署 HTTPS 时经常用自签名证书。浏览器访问自签名证书的页面会提示“不安全”更麻烦的是如果页面是 HTTPS 的而 API 请求是 HTTP 的浏览器会直接拦截这叫混合内容拦截Mixed Content。具体表现就是页面能打开但所有接口都请求失败。解决方法是统一 HTTPS并在内网 CA 中加入自签名证书让浏览器信任它。如果实在没有正规证书也可以用一些内网穿透工具临时解决但这不是长久之计。最省事的方案是直接申请一个公网域名的免费证书然后通过内网 DNS 解析到内网 IP既能享受 HTTPS 的便利又不会有证书告警。6. 部署上线以及我的一些经验心得部署 DBViewer 其实很简单。我提供了两种方式Docker Compose 一键部署适合团队内网使用直接跑二进制文件适合个人本机调试。Docker 方式就是把前端静态文件、后端 API 服务、配置文件打包在一起docker-compose up -d就完事。配置方面我强烈建议把“数据库连接信息”和“DBViewer 服务配置”分开。连接信息放在一个单独的文件里由运维管理开发环境、测试环境、生产环境的配置各不相同。DBViewer 本身只读这个配置文件不提供图形化修改入口这样避免某些用户通过界面乱改连接设置。灰度上线的时候可以先让几个核心开发试用一周收集反馈再全员推广。不用着急把功能做得很全先把查询、编辑、导出这条主链路打磨顺畅比堆一堆花哨功能有用得多。最后再分享一个我个人的实操体会数据库工作台这类工具用户体验的瓶颈从来不是功能数量而是“查询结果返回得快不快”“大数据量会不会卡”“出错了能不能看懂错误信息”。我的精力分配比例大约是 40% 花在结果集组件上30% 花在连接池和错误处理上剩下的才去完善各种操作功能。顺着这个优先级走做出来的工具团队愿意用、用得住。