ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RxDB 错误消息机制详解:RxError 错误码、参数化诊断与 DevMode 插件

RxDB 错误消息机制详解:RxError 错误码、参数化诊断与 DevMode 插件 RxDB 错误消息机制详解RxError 错误码、参数化诊断与 DevMode 插件【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdbRxDB 在抛出异常时不使用普通的 JavaScriptError而是抛出带有code错误码与parameters参数的结构化RxError对象为了让构建体积保持精简生产包默认不含完整的人类可读错误文本需要借助 DevMode 插件在开发期将其解锁。本文将基于当前仓库源码剖析 RxError 的内部结构、错误码的分组命名体系、DevMode 插件如何隧道注入完整消息并给出捕获、定位与处理 RxDB 错误的可运行实战方案。RxDB 为什么默认不打包完整错误消息打开 docs-src/docs/errors.md 可以读到官方对这一设计的解释错误消息文本具有很高的信息熵high entropy压缩率很差如果把它们全部写死在 RxDB 的构建产物里会显著增大包体积。因此 RxDB 的默认行为是——只抛出带有正确错误码code和参数parameters的错误而不包含完整文本。这一行为在 src/overwritable.ts 中有最直接的实现证据。overwritable对象是 RxDB 留给插件覆盖的可覆盖点其中默认的tunnelErrorMessage()实现为tunnelErrorMessage(message: string): string { return RxDB Error-Code: ${message}. Hint: Error messages are not included in RxDB core to reduce build size. To show the full error messages and to ensure that you do not make any mistakes when using RxDB, use the dev-mode plugin when you are in development mode: https://rxdb.info/dev-mode.html?consoleerror ; }也就是说在没有启用任何插件时抛出的错误文本只是一句RxDB Error-Code: XXX加一段提示指引开发者去启用 DevMode 插件。生产环境保持小体积开发环境解锁完整文案这就是 RxDB 错误消息的两段式设计错误码常驻核心代码几乎不占空间错误文案通过插件按需注入。RxError带错误码的结构化错误对象RxError 与 RxTypeError 的定义集中在 src/rx-error.ts 中先看核心类型RxErrorexport class RxError extends Error { public code: RxErrorKey; // 错误码如 COL20、QU4、DB8 public message: string; // 完整消息生产环境默认只有提示文本 public url: string; // 指向错误文档页的锚点链接 public parameters: RxErrorParameters; // 参数化诊断信息 public rxdb: true; // 恒为 true用于识别这是 RxDB 错误 // ... get name(): string { return RxError ( this.code ); } get typeError(): boolean { return false; } }关键字段的语义如下字段类型说明codeRxErrorKey字符串错误码例如COL20、DB8、QU4是全仓库统一的错误标识parametersRxErrorParameters与本次错误相关的上下文数据对象是排查问题的核心线索urlstringhttps://rxdb.info/errors.html?consoleerrors#code形式的锚点文档链接rxdbtrue恒为布尔true是判断错误是否来自 RxDB 的可靠标记messagestring由messageForError()拼接出的文本错误消息 参数打印typeErrorbooleanRxError恒为false用于区分另一类RxTypeError与RxError平行的还有RxTypeError它继承自原生TypeError而不是Error并带有同样的code、url、parameters、rxdb字段区别在于其typeError恒为true。从源码结构看凡是类型用法错误例如把数字传给findOne()会抛出RxTypeError其余运行时错误抛出RxError两者都通过newRxError(code, parameters)/newRxTypeError(code, parameters)这两个工厂函数创建。参数如何被格式化成可读文本RxError构造时会调用messageForError()而参数部分由parametersToString()负责格式化。看 src/rx-error.ts 中parametersToString()的实现它会把参数对象序列化成这样的块-------------------- Parameters: key1: value1 key2: { nested: 1 }其中有一个值得注意的细节当参数里包含errors数组例如复制冲突场景下的多个子错误时会使用JSON.stringify(err, Object.getOwnPropertyNames(err))对每个子错误做全属性序列化避免丢失 Error 实例上不可枚举的stack等属性——这正是为错误里嵌套错误这种诊断场景专门设计的。构造函数与文档锚点newRxError(code, parameters)内部等价于new RxError( code, overwritable.tunnelErrorMessage(code) errorUrlHint(code), parameters );即完整消息 当前可覆盖点提供的消息文本 一段了解更多请访问的 URL 提示。getErrorUrl()生成的锚点形如https://rxdb.info/errors.html?consoleerrors#COL20也就是说每个错误码在官方错误文档页都有一个锚点这正是本仓库 docs-src/docs/errors.md 的作用。如何捕获并识别 RxDB 错误得益于rxdb: true标记识别 RxDB 错误非常简单典型捕获代码如下try { await myCollection.insert(badDocument); } catch (err: any) { if (err.rxdb) { // 一定是 RxDB 抛出的错误 console.log(错误码:, err.code); console.log(诊断参数:, err.parameters); console.log(文档链接:, err.url); if (err.typeError) { // 类型用法错误RxTypeError } } else { // 其他 JavaScript 错误 } }在 src/rx-error.ts 中还可以找到几个常用的判定/转换工具函数isBulkWriteConflictError(err)当底层存储返回status 409时返回冲突错误对象否则返回false用于在批量写入后识别文档写冲突rxStorageWriteErrorToRxError(err)把存储层写入错误转换为COL20错误码的RxError其中存储状态码与消息的映射关系为409 → document write conflict、422 → schema validation error、510 → attachment data missingnewRxFetchError(response, additionalParameters)把失败的fetch()响应转换为FETCH错误码的RxError并在parameters中带上url、status、statusText、errorText等网络诊断信息。错误码的分组命名体系RxDB 的错误码不是随机的而是带有可读前缀的分组体系。文档站渲染完整错误列表的组件 docs-src/src/components/error-messages.tsx 中维护了一份前缀映射表从中可以清楚地看到前缀 → 所属模块的对应关系前缀所属模块前缀所属模块UTutil / configCOLrx-collectionPLpluginsDOCrx-documentQUrx-queryDMdata-migratorMQmqueryATattachmentsDBrx-databaseENencryptionWMCPwebmcpJDjson-dumpCONFLICTrx-collection文档更新冲突LDlocal-documentsRC*replication 系列SCdev-mode check-schemaDVMdev-modeVDvalidateGQLreplication-graphqlCRDTcrdtDXEstorage-dexieSQLstorage-sqliteRMstorage-remoteMGreplication-mongodbRreact 插件GDR/ODRgoogle-drive / onedrive 复制FETCHfetch 网络请求SNHshould never happen 内部哨兵例如看到QU5就知道是查询排序问题sort 字段未定义在 schema 中看到EN2就知道是加密密码长度不足看到RC_COUCHDB_1就知道是 CouchDB 复制 URL 缺少末尾斜杠。这种前缀命名让错误码本身就成为模块级分类标签。每条错误的四要素message / cause / fix / docs每个错误码在 src/plugins/dev-mode/error-messages.ts 中都对应一个对象统一包含四个字段QU5: { message: RxQuery.sort(): does not work because key is not defined in the schema, cause: The field used for sorting is not defined in the schema., fix: Add the field to the schema or sort by a different field., docs: https://rxdb.info/rx-query.html?consoleerrorscodeQU5#sort }message一句话概括错误cause解释为什么会发生fix给出可执行的修复建议docs指向对应功能文档的锚点链接。DevMode 插件会把这四要素全部拼进抛出的错误消息中这也是开发期排错效率高的根本原因。用 DevMode 插件解锁完整错误消息DevMode 插件开发模式插件是解锁完整错误文案的关键。安装方式为引入RxDBDevModePlugin并注册import { RxDBDevModePlugin } from rxdb/plugins/dev-mode; import { addRxPlugin } from rxdb/plugins/core; addRxPlugin(RxDBDevModePlugin);该插件的定义在 src/plugins/dev-mode/index.ts它通过overwritable.tunnelErrorMessage()覆盖默认实现从ERROR_MESSAGES表中取出对应错误码的message、cause、fix、docs拼接成如下格式的完整消息Error message: RxQuery.sort(): does not work because key is not defined in the schema Error code: QU5 Cause: The field used for sorting is not defined in the schema. Fix: Add the field to the schema or sort by a different field. Docs: https://rxdb.info/rx-query.html?consoleerrorscodeQU5#sort值得注意的是DevMode 插件在注册时还会主动校验ERROR_MESSAGES表中是否存在传入的错误码若不存在会直接抛出Error-Code X not known, contact the maintainer——这保证了任何由核心代码抛出的错误码都必然有对应的消息条目完整的 1395 行错误码表见 src/plugins/dev-mode/error-messages.ts。DevMode 插件应在开发环境启用、生产环境禁用官方文档 docs-src/docs/dev-mode.md 给出了几种按环境条件加载的推荐写法Node.js 环境按NODE_ENV条件动态导入async function createDb() { if (process.env.NODE_ENV ! production) { await import(rxdb/plugins/dev-mode).then( module addRxPlugin(module.RxDBDevModePlugin) ); } const db await createRxDatabase( /* ... */ ); }Angular 环境复用 Angular 的isDevMode()import { isDevMode } from angular/core; async function createDb() { if (isDevMode()) { await import(rxdb/plugins/dev-mode).then( module addRxPlugin(module.RxDBDevModePlugin) ); } const db await createRxDatabase( /* ... */ ); }webpack 环境配合DefinePlugin注入的编译期常量// webpack.config.js module.exports { // ... plugins: [ new webpack.DefinePlugin({ MODE: JSON.stringify(production) }) ] };declare var MODE: production | development; async function createDb() { if (MODE development) { await import(rxdb/plugins/dev-mode).then( module addRxPlugin(module.RxDBDevModePlugin) ); } const db await createRxDatabase( /* ... */ ); }动态import() 环境判断的写法可以让打包器在 production 分支下直接 tree-shake 掉整个 DevMode 插件保证生产构建不含这些额外检查与消息文本。关闭 DevMode 的警告与控制台提示DevMode 插件激活时会在控制台打印一段醒目的console.warn()警告提示你确认没有在 production 误用如果你已了解这一点可以调用disableWarnings()关闭它见 src/plugins/dev-mode/index.ts 中disableWarnings()的定义import { disableWarnings } from rxdb/plugins/dev-mode; disableWarnings();另外在 localhost 浏览器环境下插件会向 DOM 注入一个用于统计营销效果的 tracking iframe官方文档说明拥有 premium 权限的开发者可以在创建数据库前调用setPremiumFlag()来禁用该 iframe。DevMode 插件附带的其他开发期检查除了注入完整错误消息DevMode 插件还在 src/plugins/dev-mode/index.ts 中挂载了大量 hooks把开发期校验做成了全链路的Schema 检查preCreateRxSchema→checkSchema校验字段命名、主键、索引、加密字段、默认值、版本号等对应SC1~SC43系列错误码数据库/集合命名检查preCreateRxDatabase、preCreateRxCollectionensureDatabaseNameIsValid()、ensureCollectionNameValid()以及集合名不能以下划线_开头DB2ORM 方法检查createRxCollection→checkOrmMethods校验 statics、methods、attachments 上的自定义方法命名与类型查询检查preCreateRxQuery→checkQuery、prePrepareQuery→checkMangoQuery校验查询字段是否存在于 schema、索引是否合法、findOne().limit()等非法链式调用文档主键检查createRxDocument→ensurePrimaryKeyValid主键不可修改、不可带空白/换行/双引号等DOC18~DOC24存储校验器要求preCreateRxDatabase当 DevMode 开启时存储层必须使用validate-前缀的 schema 校验器如wrappedValidateAjvStorage()否则抛出DVM1因为大部分 RxDB 使用问题都源于写入了不合 schema 的数据对象深度冻结deepFreezeWhenDevMode()会对文档对象做深度Object.freeze()让开发期意外修改只读对象的行为立即报错——源码注释明确说明 deep-freeze 与 deep-clone 性能相当所以这个能力只在 dev-mode 生效。从这些 hooks 可以看出DevMode 不仅是错误消息的开关更是 RxDB 的整套开发期自检系统这也正是官方强调开发期必须使用、生产期禁止使用的原因。高频错误码速查完整的错误码清单以ERROR_MESSAGES对象维护在 src/plugins/dev-mode/error-messages.ts共 1395 行覆盖UT到SNH的全部模块并在文档页以分组列表形式渲染。以下按模块摘录高频错误码便于快速定位问题数据库与集合DB / COL错误码消息要点常见场景DB2集合名不能以下划线_开头addCollections()命名违规DB6另一实例用不同 schema 创建了同名集合修改 schema 后未递增版本号DB8同名的同名storage 数据库已存在重复createRxDatabase()可用ignoreDuplicate仅 dev-mode或closeDuplicatesDB13数据库/集合名含美元符号$命名违规COL1不能插入已存在的文档应用upsert()COL5/COL6find()/findOne()参数错误按 ID 查询应使用findOne(id)COL20存储写入错误底层存储返回 409/422/510COL21集合已被关闭或移除跨 tab 或跨 realm 访问已销毁集合CONFLICT文档更新冲突必须基于上一个 revision 修改多端并发写同一文档查询QU / MQ错误码消息要点常见场景QU4主键字段上不能使用.regex()查询引擎限制QU5sort 字段未定义在 schema 中排序字段拼写错误或未建模QU6findOne()不能调用.limit()非法链式调用QU10throwIfMissing: true但结果为空exec(true)/remove(true)未命中文档QU11查询对象不是合法的 Mango 查询查询键非法QU12使用的 index 不在 schema 中索引未定义QU16$regex必须使用字符串而非 RegExp 实例正则对象不可 JSON 序列化QU17findByIds()上不能链式调用查询方法请改用find()文档DOC错误码消息要点常见场景DOC1数组元素无法被get$观察观察整个数组字段DOC8/DOC19主键不可修改主键不可变需新建文档DOC9final 字段不可修改schema 中final: true的字段DOC16set()只能用于临时文档请改用update()/patch()/modify()DOC18复合主键缺少字段复合主键字段必须齐全DOC20文档缺少主键插入前补全主键DOC24文档数据无法结构化克隆传入了 Date/Function/Proxy 等非纯 JSON 数据SchemaSC错误码消息要点常见场景SC1字段名不匹配正则字段命名违规SC6主键只能定义在顶层主键位置错误SC30schema 必须定义 primaryKeyschema 缺主键SC34用于索引的 string 字段必须设置maxLength索引字段缺约束SC35用于索引的 number 字段必须设置multipleOf索引字段缺约束SC39主键必须设置maxLength主键约束缺失SC42主键/索引字符串的maxLength不能超过 2048过大索引影响性能SC43加密字段不能嵌套在其他加密字段内父路径加密已覆盖子路径复制RC 系列错误码消息要点常见场景RC_PULL/RC_PUSH/RC_STREAM复制 pull/push/流处理器抛错查看.errors可观察对象RC_COUCHDB_1CouchDB URL 必须以/结尾URL 格式错误RC_OUTDATED客户端版本过旧复制被取消客户端需要升级RC_UNAUTHORIZED/RC_FORBIDDEN未授权 / 行为违规被取消检查鉴权 headers 与权限RC_WEBSOCKET_TIMEOUTWebSocket 连接超时检查服务端可达性工具与配置UT / EN / AT / VD 等错误码消息要点常见场景UT1名称必须是非空字符串数据库名传参错误UT5schema 开了 keyCompression 但存储不支持需加 key-compression 插件UT6schema 含加密字段但存储无加密处理器需加 encryption 插件EN2密码长度不足min 12加密密码过短EN3schema 加密但未提供 password创建数据库时缺密码AT1使用附件前需在 schema 中启用附件未开启VD2文档对象不匹配 schema写入了不合 schema 的数据FETCHfetch 请求失败网络/服务端问题SNHThis should never happen内部哨兵错误遇到即应提 issue在仓库源码中定位错误码的抛出点如果想知道某个错误码在哪里被抛出直接在整个src目录下搜索newRxError(CODE或newRxTypeError(CODE即可。例如COL20由 src/rx-error.ts 中的rxStorageWriteErrorToRxError()统一抛出DB2、DB4由 src/plugins/dev-mode/index.ts 的preCreateRxCollectionhook 抛出QU4、QU6等查询类错误码则散布在 src/rx-query.ts 及查询构建相关文件中。错误码→消息→抛出点的三方对照构成了完整的排错链路捕获RxError读取err.code与err.parameters对照本文速查表或 src/plugins/dev-mode/error-messages.ts 中的cause/fix打开err.url指向的文档锚点如需深入在src下搜索newRxError(CODE定位抛出逻辑。小结RxDB 的错误处理是一套为小体积 可诊断双重目标设计的参数化体系生产构建只携带低熵的错误码与结构化参数DevMode 插件则在开发期把四要素message/cause/fix/docs完整注入错误对象并顺带启用 schema、查询、ORM、主键、对象冻结等一整套开发期自检。掌握err.code、err.parameters、err.rxdb与err.typeError这几个字段的用法配合错误码前缀分组与源码搜索即可在生产与开发两种模式下都快速定位并修复 RxDB 相关问题。【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表