# Midway Framework Documentation > Midway is a future-proof, cloud-native Node.js framework for enterprise applications. - [Midway Framework Documentation](/index.md) ## blog Blog - [Blog](/blog.md): Blog ### archive 历史博文 - [历史博文](/blog/archive.md): 历史博文 ### authors - [作者](/blog/authors.md) ### core-decorator-merge 从 v3.6.0 开始,Midway 在代码层面将 @midwayjs/decorator 中的代码迁移到了 @midwayjs/core 中,未来 @midwayjs/decorator 包将逐步减少使用。 - [core 和 decorator 包合并的影响](/blog/core-decorator-merge.md): 从 v3.6.0 开始,Midway 在代码层面将 @midwayjs/decorator 中的代码迁移到了 @midwayjs/core 中,未来 @midwayjs/decorator 包将逐步减少使用。 ### jest_update 最近由于 axios 组件的升级,可能在单测时会出现下面的报错。 - [Jest v29 更新](/blog/jest_update.md): 最近由于 axios 组件的升级,可能在单测时会出现下面的报错。 ### mwtsc-check 由于 Midway 版本发布规则,@midwayjs/core 和组件有着版本对应关系,即低版本的 @midwayjs/core 无法使用高版本的组件。 - [mwtsc 增加版本检查](/blog/mwtsc-check.md): 由于 Midway 版本发布规则,@midwayjs/core 和组件有着版本对应关系,即低版本的 @midwayjs/core 无法使用高版本的组件。 ### page #### 2 Blog - [Blog](/blog/page/2.md): Blog #### 3 Blog - [Blog](/blog/page/3.md): Blog #### 4 Blog - [Blog](/blog/page/4.md): Blog #### 5 Blog - [Blog](/blog/page/5.md): Blog #### 6 Blog - [Blog](/blog/page/6.md): Blog ### release #### 3.10.0 新年快乐。 - [Release 3.10.0](/blog/release/3.10.0.md): 新年快乐。 #### 3.11.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.11.0](/blog/release/3.11.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.12.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.12.0](/blog/release/3.12.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.13.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.13.0](/blog/release/3.13.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.14.0 2024 新年快乐。 - [Release 3.14.0](/blog/release/3.14.0.md): 2024 新年快乐。 #### 3.15.0 开工大吉。 - [Release 3.15.0](/blog/release/3.15.0.md): 开工大吉。 #### 3.16.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.16.0](/blog/release/3.16.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.17.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.17.0](/blog/release/3.17.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.18.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.18.0](/blog/release/3.18.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.19.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.19.0](/blog/release/3.19.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.20.0 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 - [Release 3.20.0](/blog/release/3.20.0.md): 升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。 #### 3.6.0 v3.6.0 包含一个重大的 重构,我们将 @midwayjs/decorator 包和 @midwayjs/core 包的内容进行了整合,未来所有的 decorator 相关的内容,都会由 @midwayjs/core 导出,@midwayjs/decorator 包仅做代理,保持功能兼容。 - [Release 3.6.0](/blog/release/3.6.0.md): v3.6.0 包含一个重大的 重构,我们将 @midwayjs/decorator 包和 @midwayjs/core 包的内容进行了整合,未来所有的 decorator 相关的内容,都会由 @midwayjs/core 导出,@midwayjs/decorator 包仅做代理,保持功能兼容。 #### 3.7.0 Features - [Release 3.7.0](/blog/release/3.7.0.md): Features #### 3.8.0 v3.8.0 是在经过大促之后的第一个 minor 版本,积攒了很多新的能力。 - [Release 3.8.0](/blog/release/3.8.0.md): v3.8.0 是在经过大促之后的第一个 minor 版本,积攒了很多新的能力。 #### 3.9.0 大促积攒了约两周的需求,统一在 v3.9.0 发布。 - [Release 3.9.0](/blog/release/3.9.0.md): 大促积攒了约两周的需求,统一在 v3.9.0 发布。 #### 4.0.0 今天,我们正式发布 Midway 4.0。 - [Release 4.0.0](/blog/release/4.0.0.md): 今天,我们正式发布 Midway 4.0。 #### 4.0.0-beta.1 这是全新的 Midway 4.0 的变化,这是一个非常重大的版本。 - [Release 4.0.0-beta.1](/blog/release/4.0.0-beta.1.md): 这是全新的 Midway 4.0 的变化,这是一个非常重大的版本。 #### 4.0.0-beta.10 这是 Midway 4.0 的第十个 beta 版本。 - [Release 4.0.0-beta.10](/blog/release/4.0.0-beta.10.md): 这是 Midway 4.0 的第十个 beta 版本。 #### 4.0.0-beta.2 这是全新的 Midway 4.0 的第二个 beta 版本。 - [Release 4.0.0-beta.2](/blog/release/4.0.0-beta.2.md): 这是全新的 Midway 4.0 的第二个 beta 版本。 #### 4.0.0-beta.9 这是 Midway 4.0 的第九个 beta 版本。 - [Release 4.0.0-beta.9](/blog/release/4.0.0-beta.9.md): 这是 Midway 4.0 的第九个 beta 版本。 ### remove-node-14-ci 最近一段时间,我们发现越来越多的库移除了 Node.js v14 的支持。 - [移除 Node.js v14 的 CI 环境](/blog/remove-node-14-ci.md): 最近一段时间,我们发现越来越多的库移除了 Node.js v14 的支持。 ### remove-node-v12 由于最近 node v18 标记为 LTS,社区相关的相关的依赖都移除了 node v12 的支持,导致 Midway 的基建,单测已经无法正常的执行。 - [移除 node v12 相关的依赖](/blog/remove-node-v12.md): 由于最近 node v18 标记为 LTS,社区相关的相关的依赖都移除了 node v12 的支持,导致 Midway 的基建,单测已经无法正常的执行。 ### skill #### midway 我们新增了 @midwayjs/skill-midway。 - [新增 @midwayjs/skill-midway](/blog/skill/midway.md): 我们新增了 @midwayjs/skill-midway。 ### tags - [标签](/blog/tags.md) #### ai - [1 篇博文 含有标签「ai」](/blog/tags/ai.md) #### core - [1 篇博文 含有标签「core」](/blog/tags/core.md) #### decorator - [1 篇博文 含有标签「decorator」](/blog/tags/decorator.md) #### jest - [1 篇博文 含有标签「jest」](/blog/tags/jest.md) #### midway - [1 篇博文 含有标签「midway」](/blog/tags/midway.md) #### mwtsc - [1 篇博文 含有标签「mwtsc」](/blog/tags/mwtsc.md) #### node - [2 篇博文 含有标签「node」](/blog/tags/node.md) #### release - [20 篇博文 含有标签「release」](/blog/tags/release.md) - [20 篇博文 含有标签「release」](/blog/tags/release/page/2.md) - [20 篇博文 含有标签「release」](/blog/tags/release/page/3.md) - [20 篇博文 含有标签「release」](/blog/tags/release/page/4.md) #### skill - [1 篇博文 含有标签「skill」](/blog/tags/skill.md) #### 更新 - [1 篇博文 含有标签「更新」](/blog/tags/更新.md) ## changelog Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog.md): Keep yourself up-to-date about new features in every release ### authors - [作者](/changelog/authors.md) ### page #### 10 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/10.md): Keep yourself up-to-date about new features in every release #### 11 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/11.md): Keep yourself up-to-date about new features in every release #### 12 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/12.md): Keep yourself up-to-date about new features in every release #### 13 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/13.md): Keep yourself up-to-date about new features in every release #### 14 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/14.md): Keep yourself up-to-date about new features in every release #### 15 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/15.md): Keep yourself up-to-date about new features in every release #### 16 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/16.md): Keep yourself up-to-date about new features in every release #### 17 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/17.md): Keep yourself up-to-date about new features in every release #### 18 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/18.md): Keep yourself up-to-date about new features in every release #### 19 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/19.md): Keep yourself up-to-date about new features in every release #### 2 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/2.md): Keep yourself up-to-date about new features in every release #### 20 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/20.md): Keep yourself up-to-date about new features in every release #### 21 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/21.md): Keep yourself up-to-date about new features in every release #### 22 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/22.md): Keep yourself up-to-date about new features in every release #### 23 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/23.md): Keep yourself up-to-date about new features in every release #### 3 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/3.md): Keep yourself up-to-date about new features in every release #### 4 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/4.md): Keep yourself up-to-date about new features in every release #### 5 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/5.md): Keep yourself up-to-date about new features in every release #### 6 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/6.md): Keep yourself up-to-date about new features in every release #### 7 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/7.md): Keep yourself up-to-date about new features in every release #### 8 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/8.md): Keep yourself up-to-date about new features in every release #### 9 Keep yourself up-to-date about new features in every release - [Midway changelog](/changelog/page/9.md): Keep yourself up-to-date about new features in every release ### v0.2.10 Note: Version bump only for package midway - [v0.2.10](/changelog/v0.2.10.md): Note: Version bump only for package midway ### v0.2.5 Bug Fixes - [v0.2.5](/changelog/v0.2.5.md): Bug Fixes ### v0.2.6 Bug Fixes - [v0.2.6](/changelog/v0.2.6.md): Bug Fixes ### v0.2.7 Bug Fixes - [v0.2.7](/changelog/v0.2.7.md): Bug Fixes ### v0.2.8 Bug Fixes - [v0.2.8](/changelog/v0.2.8.md): Bug Fixes ### v0.2.9 Bug Fixes - [v0.2.9](/changelog/v0.2.9.md): Bug Fixes ### v0.4.5 Bug Fixes - [v0.4.5](/changelog/v0.4.5.md): Bug Fixes ### v0.4.6 Bug Fixes - [v0.4.6](/changelog/v0.4.6.md): Bug Fixes ### v0.4.7 Bug Fixes - [v0.4.7](/changelog/v0.4.7.md): Bug Fixes ### v0.5.0 Bug Fixes - [v0.5.0](/changelog/v0.5.0.md): Bug Fixes ### v0.5.1 Bug Fixes - [v0.5.1](/changelog/v0.5.1.md): Bug Fixes ### v0.6.0 Bug Fixes - [v0.6.0](/changelog/v0.6.0.md): Bug Fixes ### v0.6.1 Bug Fixes - [v0.6.1](/changelog/v0.6.1.md): Bug Fixes ### v0.6.2 Bug Fixes - [v0.6.2](/changelog/v0.6.2.md): Bug Fixes ### v0.6.3 Bug Fixes - [v0.6.3](/changelog/v0.6.3.md): Bug Fixes ### v0.6.4 Bug Fixes - [v0.6.4](/changelog/v0.6.4.md): Bug Fixes ### v0.6.5 Note: Version bump only for package midway - [v0.6.5](/changelog/v0.6.5.md): Note: Version bump only for package midway ### v0.7.0 Bug Fixes - [v0.7.0](/changelog/v0.7.0.md): Bug Fixes ### v0.7.1 Bug Fixes - [v0.7.1](/changelog/v0.7.1.md): Bug Fixes ### v1.0.0 Features - [v1.0.0](/changelog/v1.0.0.md): Features ### v1.0.1 Note: Version bump only for package midway - [v1.0.1](/changelog/v1.0.1.md): Note: Version bump only for package midway ### v1.0.2 Note: Version bump only for package midway - [v1.0.2](/changelog/v1.0.2.md): Note: Version bump only for package midway ### v1.0.3 Bug Fixes - [v1.0.3](/changelog/v1.0.3.md): Bug Fixes ### v1.0.4 Note: Version bump only for package midway - [v1.0.4](/changelog/v1.0.4.md): Note: Version bump only for package midway ### v1.0.5 Bug Fixes - [v1.0.5](/changelog/v1.0.5.md): Bug Fixes ### v1.1.0 Bug Fixes - [v1.1.0](/changelog/v1.1.0.md): Bug Fixes ### v1.1.1 Bug Fixes - [v1.1.1](/changelog/v1.1.1.md): Bug Fixes ### v1.1.2 Note: Version bump only for package midway - [v1.1.2](/changelog/v1.1.2.md): Note: Version bump only for package midway ### v1.10.0 Features - [v1.10.0](/changelog/v1.10.0.md): Features ### v1.10.1 Note: Version bump only for package midway - [v1.10.1](/changelog/v1.10.1.md): Note: Version bump only for package midway ### v1.10.2 Note: Version bump only for package midway - [v1.10.2](/changelog/v1.10.2.md): Note: Version bump only for package midway ### v1.10.3 Bug Fixes - [v1.10.3](/changelog/v1.10.3.md): Bug Fixes ### v1.10.4 Bug Fixes - [v1.10.4](/changelog/v1.10.4.md): Bug Fixes ### v1.10.5 Bug Fixes - [v1.10.5](/changelog/v1.10.5.md): Bug Fixes ### v1.10.6 Bug Fixes - [v1.10.6](/changelog/v1.10.6.md): Bug Fixes ### v1.10.7 Bug Fixes - [v1.10.7](/changelog/v1.10.7.md): Bug Fixes ### v1.10.8 Note: Version bump only for package midway - [v1.10.8](/changelog/v1.10.8.md): Note: Version bump only for package midway ### v1.10.9 Bug Fixes - [v1.10.9](/changelog/v1.10.9.md): Bug Fixes ### v1.11.0 Features - [v1.11.0](/changelog/v1.11.0.md): Features ### v1.11.1 Note: Version bump only for package midway - [v1.11.1](/changelog/v1.11.1.md): Note: Version bump only for package midway ### v1.11.2 Note: Version bump only for package midway - [v1.11.2](/changelog/v1.11.2.md): Note: Version bump only for package midway ### v1.11.3 Bug Fixes - [v1.11.3](/changelog/v1.11.3.md): Bug Fixes ### v1.11.4 Note: Version bump only for package midway - [v1.11.4](/changelog/v1.11.4.md): Note: Version bump only for package midway ### v1.11.5 Note: Version bump only for package midway - [v1.11.5](/changelog/v1.11.5.md): Note: Version bump only for package midway ### v1.11.6 Note: Version bump only for package midway - [v1.11.6](/changelog/v1.11.6.md): Note: Version bump only for package midway ### v1.12.0 Features - [v1.12.0](/changelog/v1.12.0.md): Features ### v1.12.1 Bug Fixes - [v1.12.1](/changelog/v1.12.1.md): Bug Fixes ### v1.13.0 Features - [v1.13.0](/changelog/v1.13.0.md): Features ### v1.14.0 Features - [v1.14.0](/changelog/v1.14.0.md): Features ### v1.14.1 Note: Version bump only for package midway - [v1.14.1](/changelog/v1.14.1.md): Note: Version bump only for package midway ### v1.14.2 Note: Version bump only for package midway - [v1.14.2](/changelog/v1.14.2.md): Note: Version bump only for package midway ### v1.14.3 Bug Fixes - [v1.14.3](/changelog/v1.14.3.md): Bug Fixes ### v1.14.4 Bug Fixes - [v1.14.4](/changelog/v1.14.4.md): Bug Fixes ### v1.15.0 Bug Fixes - [v1.15.0](/changelog/v1.15.0.md): Bug Fixes ### v1.15.1 Bug Fixes - [v1.15.1](/changelog/v1.15.1.md): Bug Fixes ### v1.16.0 Note: Version bump only for package midway - [v1.16.0](/changelog/v1.16.0.md): Note: Version bump only for package midway ### v1.16.1 Note: Version bump only for package midway - [v1.16.1](/changelog/v1.16.1.md): Note: Version bump only for package midway ### v1.16.2 Bug Fixes - [v1.16.2](/changelog/v1.16.2.md): Bug Fixes ### v1.16.3 Note: Version bump only for package midway - [v1.16.3](/changelog/v1.16.3.md): Note: Version bump only for package midway ### v1.16.4 Bug Fixes - [v1.16.4](/changelog/v1.16.4.md): Bug Fixes ### v1.17.0 Features - [v1.17.0](/changelog/v1.17.0.md): Features ### v1.17.1 Bug Fixes - [v1.17.1](/changelog/v1.17.1.md): Bug Fixes ### v1.2.0 Bug Fixes - [v1.2.0](/changelog/v1.2.0.md): Bug Fixes ### v1.2.1 Note: Version bump only for package midway - [v1.2.1](/changelog/v1.2.1.md): Note: Version bump only for package midway ### v1.2.2 Bug Fixes - [v1.2.2](/changelog/v1.2.2.md): Bug Fixes ### v1.2.3 Bug Fixes - [v1.2.3](/changelog/v1.2.3.md): Bug Fixes ### v1.2.4 Bug Fixes - [v1.2.4](/changelog/v1.2.4.md): Bug Fixes ### v1.3.0 Bug Fixes - [v1.3.0](/changelog/v1.3.0.md): Bug Fixes ### v1.3.1 Note: Version bump only for package midway - [v1.3.1](/changelog/v1.3.1.md): Note: Version bump only for package midway ### v1.3.2 Note: Version bump only for package midway - [v1.3.2](/changelog/v1.3.2.md): Note: Version bump only for package midway ### v1.4.0 Features - [v1.4.0](/changelog/v1.4.0.md): Features ### v1.4.1 Note: Version bump only for package midway - [v1.4.1](/changelog/v1.4.1.md): Note: Version bump only for package midway ### v1.4.10 Note: Version bump only for package midway - [v1.4.10](/changelog/v1.4.10.md): Note: Version bump only for package midway ### v1.4.2 Note: Version bump only for package midway - [v1.4.2](/changelog/v1.4.2.md): Note: Version bump only for package midway ### v1.4.3 Note: Version bump only for package midway - [v1.4.3](/changelog/v1.4.3.md): Note: Version bump only for package midway ### v1.4.4 Bug Fixes - [v1.4.4](/changelog/v1.4.4.md): Bug Fixes ### v1.4.5 Note: Version bump only for package midway - [v1.4.5](/changelog/v1.4.5.md): Note: Version bump only for package midway ### v1.4.6 Note: Version bump only for package midway - [v1.4.6](/changelog/v1.4.6.md): Note: Version bump only for package midway ### v1.4.7 Note: Version bump only for package midway - [v1.4.7](/changelog/v1.4.7.md): Note: Version bump only for package midway ### v1.4.8 Note: Version bump only for package midway - [v1.4.8](/changelog/v1.4.8.md): Note: Version bump only for package midway ### v1.4.9 Bug Fixes - [v1.4.9](/changelog/v1.4.9.md): Bug Fixes ### v1.5.0 Bug Fixes - [v1.5.0](/changelog/v1.5.0.md): Bug Fixes ### v1.5.1 Note: Version bump only for package midway - [v1.5.1](/changelog/v1.5.1.md): Note: Version bump only for package midway ### v1.5.2 Note: Version bump only for package midway - [v1.5.2](/changelog/v1.5.2.md): Note: Version bump only for package midway ### v1.5.3 Note: Version bump only for package midway - [v1.5.3](/changelog/v1.5.3.md): Note: Version bump only for package midway ### v1.5.4 Note: Version bump only for package midway - [v1.5.4](/changelog/v1.5.4.md): Note: Version bump only for package midway ### v1.5.5 Note: Version bump only for package midway - [v1.5.5](/changelog/v1.5.5.md): Note: Version bump only for package midway ### v1.5.6 Bug Fixes - [v1.5.6](/changelog/v1.5.6.md): Bug Fixes ### v1.6.0 Bug Fixes - [v1.6.0](/changelog/v1.6.0.md): Bug Fixes ### v1.6.1 Note: Version bump only for package midway - [v1.6.1](/changelog/v1.6.1.md): Note: Version bump only for package midway ### v1.6.2 Bug Fixes - [v1.6.2](/changelog/v1.6.2.md): Bug Fixes ### v1.6.3 Note: Version bump only for package midway - [v1.6.3](/changelog/v1.6.3.md): Note: Version bump only for package midway ### v1.7.0 Bug Fixes - [v1.7.0](/changelog/v1.7.0.md): Bug Fixes ### v1.8.0 Bug Fixes - [v1.8.0](/changelog/v1.8.0.md): Bug Fixes ### v1.9.0 Bug Fixes - [v1.9.0](/changelog/v1.9.0.md): Bug Fixes ### v2.0.0 Note: Version bump only for package midway - [v2.0.0](/changelog/v2.0.0.md): Note: Version bump only for package midway ### v2.0.1 Features - [v2.0.1](/changelog/v2.0.1.md): Features ### v2.0.10 Note: Version bump only for package midway - [v2.0.10](/changelog/v2.0.10.md): Note: Version bump only for package midway ### v2.0.11 Bug Fixes - [v2.0.11](/changelog/v2.0.11.md): Bug Fixes ### v2.0.12 Bug Fixes - [v2.0.12](/changelog/v2.0.12.md): Bug Fixes ### v2.0.13 Note: Version bump only for package midway - [v2.0.13](/changelog/v2.0.13.md): Note: Version bump only for package midway ### v2.0.14 Note: Version bump only for package midway - [v2.0.14](/changelog/v2.0.14.md): Note: Version bump only for package midway ### v2.0.15 Bug Fixes - [v2.0.15](/changelog/v2.0.15.md): Bug Fixes ### v2.0.16 Bug Fixes - [v2.0.16](/changelog/v2.0.16.md): Bug Fixes ### v2.0.17 Bug Fixes - [v2.0.17](/changelog/v2.0.17.md): Bug Fixes ### v2.0.2 Bug Fixes - [v2.0.2](/changelog/v2.0.2.md): Bug Fixes ### v2.0.3 Note: Version bump only for package midway - [v2.0.3](/changelog/v2.0.3.md): Note: Version bump only for package midway ### v2.0.4 Bug Fixes - [v2.0.4](/changelog/v2.0.4.md): Bug Fixes ### v2.0.5 Bug Fixes - [v2.0.5](/changelog/v2.0.5.md): Bug Fixes ### v2.0.6 Bug Fixes - [v2.0.6](/changelog/v2.0.6.md): Bug Fixes ### v2.0.7 Note: Version bump only for package midway - [v2.0.7](/changelog/v2.0.7.md): Note: Version bump only for package midway ### v2.0.8 Bug Fixes - [v2.0.8](/changelog/v2.0.8.md): Bug Fixes ### v2.0.9 Bug Fixes - [v2.0.9](/changelog/v2.0.9.md): Bug Fixes ### v2.1.0 Features - [v2.1.0](/changelog/v2.1.0.md): Features ### v2.1.1 Bug Fixes - [v2.1.1](/changelog/v2.1.1.md): Bug Fixes ### v2.1.2 Bug Fixes - [v2.1.2](/changelog/v2.1.2.md): Bug Fixes ### v2.1.3 Bug Fixes - [v2.1.3](/changelog/v2.1.3.md): Bug Fixes ### v2.1.4 Bug Fixes - [v2.1.4](/changelog/v2.1.4.md): Bug Fixes ### v2.10.0 Bug Fixes - [v2.10.0](/changelog/v2.10.0.md): Bug Fixes ### v2.10.1 Bug Fixes - [v2.10.1](/changelog/v2.10.1.md): Bug Fixes ### v2.10.10 Bug Fixes - [v2.10.10](/changelog/v2.10.10.md): Bug Fixes ### v2.10.11 Bug Fixes - [v2.10.11](/changelog/v2.10.11.md): Bug Fixes ### v2.10.12 Bug Fixes - [v2.10.12](/changelog/v2.10.12.md): Bug Fixes ### v2.10.13 Bug Fixes - [v2.10.13](/changelog/v2.10.13.md): Bug Fixes ### v2.10.14 Bug Fixes - [v2.10.14](/changelog/v2.10.14.md): Bug Fixes ### v2.10.15 Bug Fixes - [v2.10.15](/changelog/v2.10.15.md): Bug Fixes ### v2.10.16 Bug Fixes - [v2.10.16](/changelog/v2.10.16.md): Bug Fixes ### v2.10.17 Bug Fixes - [v2.10.17](/changelog/v2.10.17.md): Bug Fixes ### v2.10.18 Bug Fixes - [v2.10.18](/changelog/v2.10.18.md): Bug Fixes ### v2.10.19 Bug Fixes - [v2.10.19](/changelog/v2.10.19.md): Bug Fixes ### v2.10.2 Bug Fixes - [v2.10.2](/changelog/v2.10.2.md): Bug Fixes ### v2.10.3 Bug Fixes - [v2.10.3](/changelog/v2.10.3.md): Bug Fixes ### v2.10.4 Bug Fixes - [v2.10.4](/changelog/v2.10.4.md): Bug Fixes ### v2.10.5 Bug Fixes - [v2.10.5](/changelog/v2.10.5.md): Bug Fixes ### v2.10.6 Bug Fixes - [v2.10.6](/changelog/v2.10.6.md): Bug Fixes ### v2.10.7 Bug Fixes - [v2.10.7](/changelog/v2.10.7.md): Bug Fixes ### v2.10.8 Bug Fixes - [v2.10.8](/changelog/v2.10.8.md): Bug Fixes ### v2.10.9 Bug Fixes - [v2.10.9](/changelog/v2.10.9.md): Bug Fixes ### v2.11.0 Bug Fixes - [v2.11.0](/changelog/v2.11.0.md): Bug Fixes ### v2.11.1 Bug Fixes - [v2.11.1](/changelog/v2.11.1.md): Bug Fixes ### v2.11.2 Bug Fixes - [v2.11.2](/changelog/v2.11.2.md): Bug Fixes ### v2.11.3 Bug Fixes - [v2.11.3](/changelog/v2.11.3.md): Bug Fixes ### v2.11.4 Bug Fixes - [v2.11.4](/changelog/v2.11.4.md): Bug Fixes ### v2.11.5 Bug Fixes - [v2.11.5](/changelog/v2.11.5.md): Bug Fixes ### v2.11.6 Features - [v2.11.6](/changelog/v2.11.6.md): Features ### v2.11.7 Bug Fixes - [v2.11.7](/changelog/v2.11.7.md): Bug Fixes ### v2.12.0 Features - [v2.12.0](/changelog/v2.12.0.md): Features ### v2.12.1 Bug Fixes - [v2.12.1](/changelog/v2.12.1.md): Bug Fixes ### v2.12.2 Bug Fixes - [v2.12.2](/changelog/v2.12.2.md): Bug Fixes ### v2.12.3 Bug Fixes - [v2.12.3](/changelog/v2.12.3.md): Bug Fixes ### v2.12.4 Bug Fixes - [v2.12.4](/changelog/v2.12.4.md): Bug Fixes ### v2.2.0 Features - [v2.2.0](/changelog/v2.2.0.md): Features ### v2.2.1 Bug Fixes - [v2.2.1](/changelog/v2.2.1.md): Bug Fixes ### v2.2.10 Bug Fixes - [v2.2.10](/changelog/v2.2.10.md): Bug Fixes ### v2.2.2 Bug Fixes - [v2.2.2](/changelog/v2.2.2.md): Bug Fixes ### v2.2.3 Bug Fixes - [v2.2.3](/changelog/v2.2.3.md): Bug Fixes ### v2.2.4 Bug Fixes - [v2.2.4](/changelog/v2.2.4.md): Bug Fixes ### v2.2.5 Bug Fixes - [v2.2.5](/changelog/v2.2.5.md): Bug Fixes ### v2.2.6 Features - [v2.2.6](/changelog/v2.2.6.md): Features ### v2.2.7 Bug Fixes - [v2.2.7](/changelog/v2.2.7.md): Bug Fixes ### v2.2.8 Bug Fixes - [v2.2.8](/changelog/v2.2.8.md): Bug Fixes ### v2.2.9 Bug Fixes - [v2.2.9](/changelog/v2.2.9.md): Bug Fixes ### v2.3.0 Features - [v2.3.0](/changelog/v2.3.0.md): Features ### v2.3.1 Bug Fixes - [v2.3.1](/changelog/v2.3.1.md): Bug Fixes ### v2.3.10 Bug Fixes - [v2.3.10](/changelog/v2.3.10.md): Bug Fixes ### v2.3.11 Note: Version bump only for package midway - [v2.3.11](/changelog/v2.3.11.md): Note: Version bump only for package midway ### v2.3.12 Bug Fixes - [v2.3.12](/changelog/v2.3.12.md): Bug Fixes ### v2.3.13 Bug Fixes - [v2.3.13](/changelog/v2.3.13.md): Bug Fixes ### v2.3.14 Note: Version bump only for package midway - [v2.3.14](/changelog/v2.3.14.md): Note: Version bump only for package midway ### v2.3.15 Note: Version bump only for package midway - [v2.3.15](/changelog/v2.3.15.md): Note: Version bump only for package midway ### v2.3.16 Bug Fixes - [v2.3.16](/changelog/v2.3.16.md): Bug Fixes ### v2.3.17 Note: Version bump only for package midway - [v2.3.17](/changelog/v2.3.17.md): Note: Version bump only for package midway ### v2.3.18 Bug Fixes - [v2.3.18](/changelog/v2.3.18.md): Bug Fixes ### v2.3.19 Features - [v2.3.19](/changelog/v2.3.19.md): Features ### v2.3.2 Bug Fixes - [v2.3.2](/changelog/v2.3.2.md): Bug Fixes ### v2.3.20 Bug Fixes - [v2.3.20](/changelog/v2.3.20.md): Bug Fixes ### v2.3.21 Bug Fixes - [v2.3.21](/changelog/v2.3.21.md): Bug Fixes ### v2.3.22 Bug Fixes - [v2.3.22](/changelog/v2.3.22.md): Bug Fixes ### v2.3.23 Bug Fixes - [v2.3.23](/changelog/v2.3.23.md): Bug Fixes ### v2.3.3 Bug Fixes - [v2.3.3](/changelog/v2.3.3.md): Bug Fixes ### v2.3.4 Note: Version bump only for package midway - [v2.3.4](/changelog/v2.3.4.md): Note: Version bump only for package midway ### v2.3.6 Bug Fixes - [v2.3.6](/changelog/v2.3.6.md): Bug Fixes ### v2.3.7 Bug Fixes - [v2.3.7](/changelog/v2.3.7.md): Bug Fixes ### v2.3.8 Bug Fixes - [v2.3.8](/changelog/v2.3.8.md): Bug Fixes ### v2.3.9 Bug Fixes - [v2.3.9](/changelog/v2.3.9.md): Bug Fixes ### v2.4.0 Bug Fixes - [v2.4.0](/changelog/v2.4.0.md): Bug Fixes ### v2.4.1 Bug Fixes - [v2.4.1](/changelog/v2.4.1.md): Bug Fixes ### v2.4.2 Bug Fixes - [v2.4.2](/changelog/v2.4.2.md): Bug Fixes ### v2.4.3 Bug Fixes - [v2.4.3](/changelog/v2.4.3.md): Bug Fixes ### v2.4.4 Bug Fixes - [v2.4.4](/changelog/v2.4.4.md): Bug Fixes ### v2.4.5 Bug Fixes - [v2.4.5](/changelog/v2.4.5.md): Bug Fixes ### v2.4.6 Note: Version bump only for package midway - [v2.4.6](/changelog/v2.4.6.md): Note: Version bump only for package midway ### v2.4.7 Note: Version bump only for package midway - [v2.4.7](/changelog/v2.4.7.md): Note: Version bump only for package midway ### v2.4.8 Bug Fixes - [v2.4.8](/changelog/v2.4.8.md): Bug Fixes ### v2.5.0 Bug Fixes - [v2.5.0](/changelog/v2.5.0.md): Bug Fixes ### v2.5.1 Bug Fixes - [v2.5.1](/changelog/v2.5.1.md): Bug Fixes ### v2.5.2 Bug Fixes - [v2.5.2](/changelog/v2.5.2.md): Bug Fixes ### v2.5.3 Bug Fixes - [v2.5.3](/changelog/v2.5.3.md): Bug Fixes ### v2.5.4 Bug Fixes - [v2.5.4](/changelog/v2.5.4.md): Bug Fixes ### v2.5.5 Bug Fixes - [v2.5.5](/changelog/v2.5.5.md): Bug Fixes ### v2.6.0 Bug Fixes - [v2.6.0](/changelog/v2.6.0.md): Bug Fixes ### v2.6.1 Bug Fixes - [v2.6.1](/changelog/v2.6.1.md): Bug Fixes ### v2.6.10 Bug Fixes - [v2.6.10](/changelog/v2.6.10.md): Bug Fixes ### v2.6.11 Bug Fixes - [v2.6.11](/changelog/v2.6.11.md): Bug Fixes ### v2.6.12 Bug Fixes - [v2.6.12](/changelog/v2.6.12.md): Bug Fixes ### v2.6.13 Bug Fixes - [v2.6.13](/changelog/v2.6.13.md): Bug Fixes ### v2.6.2 Bug Fixes - [v2.6.2](/changelog/v2.6.2.md): Bug Fixes ### v2.6.3 Bug Fixes - [v2.6.3](/changelog/v2.6.3.md): Bug Fixes ### v2.6.4 Bug Fixes - [v2.6.4](/changelog/v2.6.4.md): Bug Fixes ### v2.6.5 Bug Fixes - [v2.6.5](/changelog/v2.6.5.md): Bug Fixes ### v2.6.6 Note: Version bump only for package midway - [v2.6.6](/changelog/v2.6.6.md): Note: Version bump only for package midway ### v2.6.7 Bug Fixes - [v2.6.7](/changelog/v2.6.7.md): Bug Fixes ### v2.6.8 Bug Fixes - [v2.6.8](/changelog/v2.6.8.md): Bug Fixes ### v2.6.9 Bug Fixes - [v2.6.9](/changelog/v2.6.9.md): Bug Fixes ### v2.7.0 Bug Fixes - [v2.7.0](/changelog/v2.7.0.md): Bug Fixes ### v2.7.1 Bug Fixes - [v2.7.1](/changelog/v2.7.1.md): Bug Fixes ### v2.7.2 Bug Fixes - [v2.7.2](/changelog/v2.7.2.md): Bug Fixes ### v2.7.3 Bug Fixes - [v2.7.3](/changelog/v2.7.3.md): Bug Fixes ### v2.7.4 Bug Fixes - [v2.7.4](/changelog/v2.7.4.md): Bug Fixes ### v2.7.5 Bug Fixes - [v2.7.5](/changelog/v2.7.5.md): Bug Fixes ### v2.7.6 Bug Fixes - [v2.7.6](/changelog/v2.7.6.md): Bug Fixes ### v2.7.7 Bug Fixes - [v2.7.7](/changelog/v2.7.7.md): Bug Fixes ### v2.8.0 Features - [v2.8.0](/changelog/v2.8.0.md): Features ### v2.8.10 Bug Fixes - [v2.8.10](/changelog/v2.8.10.md): Bug Fixes ### v2.8.11 Bug Fixes - [v2.8.11](/changelog/v2.8.11.md): Bug Fixes ### v2.8.12 Bug Fixes - [v2.8.12](/changelog/v2.8.12.md): Bug Fixes ### v2.8.13 Bug Fixes - [v2.8.13](/changelog/v2.8.13.md): Bug Fixes ### v2.8.2 Bug Fixes - [v2.8.2](/changelog/v2.8.2.md): Bug Fixes ### v2.8.3 Bug Fixes - [v2.8.3](/changelog/v2.8.3.md): Bug Fixes ### v2.8.4 Bug Fixes - [v2.8.4](/changelog/v2.8.4.md): Bug Fixes ### v2.8.5 Bug Fixes - [v2.8.5](/changelog/v2.8.5.md): Bug Fixes ### v2.8.6 Bug Fixes - [v2.8.6](/changelog/v2.8.6.md): Bug Fixes ### v2.8.7 Bug Fixes - [v2.8.7](/changelog/v2.8.7.md): Bug Fixes ### v2.8.8 Bug Fixes - [v2.8.8](/changelog/v2.8.8.md): Bug Fixes ### v2.8.9 Bug Fixes - [v2.8.9](/changelog/v2.8.9.md): Bug Fixes ### v2.9.0 Bug Fixes - [v2.9.0](/changelog/v2.9.0.md): Bug Fixes ### v2.9.1 Bug Fixes - [v2.9.1](/changelog/v2.9.1.md): Bug Fixes ### v2.9.2 Bug Fixes - [v2.9.2](/changelog/v2.9.2.md): Bug Fixes ### v2.9.3 Bug Fixes - [v2.9.3](/changelog/v2.9.3.md): Bug Fixes ### v3.0.0 Bug Fixes - [v3.0.0](/changelog/v3.0.0.md): Bug Fixes ### v3.0.1 Bug Fixes - [v3.0.1](/changelog/v3.0.1.md): Bug Fixes ### v3.0.10 Bug Fixes - [v3.0.10](/changelog/v3.0.10.md): Bug Fixes ### v3.0.11 Bug Fixes - [v3.0.11](/changelog/v3.0.11.md): Bug Fixes ### v3.0.12 Bug Fixes - [v3.0.12](/changelog/v3.0.12.md): Bug Fixes ### v3.0.13 Bug Fixes - [v3.0.13](/changelog/v3.0.13.md): Bug Fixes ### v3.0.2 Bug Fixes - [v3.0.2](/changelog/v3.0.2.md): Bug Fixes ### v3.0.3 Bug Fixes - [v3.0.3](/changelog/v3.0.3.md): Bug Fixes ### v3.0.4 Bug Fixes - [v3.0.4](/changelog/v3.0.4.md): Bug Fixes ### v3.0.5 Bug Fixes - [v3.0.5](/changelog/v3.0.5.md): Bug Fixes ### v3.0.6 Bug Fixes - [v3.0.6](/changelog/v3.0.6.md): Bug Fixes ### v3.0.7 Bug Fixes - [v3.0.7](/changelog/v3.0.7.md): Bug Fixes ### v3.0.8 Bug Fixes - [v3.0.8](/changelog/v3.0.8.md): Bug Fixes ### v3.0.9 Bug Fixes - [v3.0.9](/changelog/v3.0.9.md): Bug Fixes ### v3.1.0 Bug Fixes - [v3.1.0](/changelog/v3.1.0.md): Bug Fixes ### v3.1.1 Bug Fixes - [v3.1.1](/changelog/v3.1.1.md): Bug Fixes ### v3.1.2 Bug Fixes - [v3.1.2](/changelog/v3.1.2.md): Bug Fixes ### v3.1.3 Bug Fixes - [v3.1.3](/changelog/v3.1.3.md): Bug Fixes ### v3.1.4 Bug Fixes - [v3.1.4](/changelog/v3.1.4.md): Bug Fixes ### v3.1.5 Bug Fixes - [v3.1.5](/changelog/v3.1.5.md): Bug Fixes ### v3.1.6 Bug Fixes - [v3.1.6](/changelog/v3.1.6.md): Bug Fixes ### v3.10.0 Breaking Change - [v3.10.0](/changelog/v3.10.0.md): Breaking Change ### v3.10.1 Bug Fix - [v3.10.1](/changelog/v3.10.1.md): Bug Fix ### v3.10.10 Bug Fix - [v3.10.10](/changelog/v3.10.10.md): Bug Fix ### v3.10.11 Polish - [v3.10.11](/changelog/v3.10.11.md): Polish ### v3.10.12 Bug Fix - [v3.10.12](/changelog/v3.10.12.md): Bug Fix ### v3.10.13 Bug Fix - [v3.10.13](/changelog/v3.10.13.md): Bug Fix ### v3.10.14 Bug Fix - [v3.10.14](/changelog/v3.10.14.md): Bug Fix ### v3.10.15 Bug Fix - [v3.10.15](/changelog/v3.10.15.md): Bug Fix ### v3.10.16 Bug Fix - [v3.10.16](/changelog/v3.10.16.md): Bug Fix ### v3.10.2 Bug Fix - [v3.10.2](/changelog/v3.10.2.md): Bug Fix ### v3.10.3 Bug Fix - [v3.10.3](/changelog/v3.10.3.md): Bug Fix ### v3.10.4 Bug Fix - [v3.10.4](/changelog/v3.10.4.md): Bug Fix ### v3.10.5 Bug Fix - [v3.10.5](/changelog/v3.10.5.md): Bug Fix ### v3.10.6 Bug Fix - [v3.10.6](/changelog/v3.10.6.md): Bug Fix ### v3.10.7 Bug Fix - [v3.10.7](/changelog/v3.10.7.md): Bug Fix ### v3.10.8 Polish - [v3.10.8](/changelog/v3.10.8.md): Polish ### v3.10.9 Bug Fix - [v3.10.9](/changelog/v3.10.9.md): Bug Fix ### v3.11.0 New Feature - [v3.11.0](/changelog/v3.11.0.md): New Feature ### v3.11.1 Bug Fix - [v3.11.1](/changelog/v3.11.1.md): Bug Fix ### v3.11.10 Bug Fix - [v3.11.10](/changelog/v3.11.10.md): Bug Fix ### v3.11.11 Bug Fix - [v3.11.11](/changelog/v3.11.11.md): Bug Fix ### v3.11.12 Documentation - [v3.11.12](/changelog/v3.11.12.md): Documentation ### v3.11.13 Bug Fix - [v3.11.13](/changelog/v3.11.13.md): Bug Fix ### v3.11.14 Bug Fix - [v3.11.14](/changelog/v3.11.14.md): Bug Fix ### v3.11.15 Bug Fix - [v3.11.15](/changelog/v3.11.15.md): Bug Fix ### v3.11.16 Bug Fix - [v3.11.16](/changelog/v3.11.16.md): Bug Fix ### v3.11.17 Bug Fix - [v3.11.17](/changelog/v3.11.17.md): Bug Fix ### v3.11.18 Bug Fix - [v3.11.18](/changelog/v3.11.18.md): Bug Fix ### v3.11.2 Bug Fix - [v3.11.2](/changelog/v3.11.2.md): Bug Fix ### v3.11.3 Bug Fix - [v3.11.3](/changelog/v3.11.3.md): Bug Fix ### v3.11.4 Bug Fix - [v3.11.4](/changelog/v3.11.4.md): Bug Fix ### v3.11.5 Bug Fix - [v3.11.5](/changelog/v3.11.5.md): Bug Fix ### v3.11.6 Polish - [v3.11.6](/changelog/v3.11.6.md): Polish ### v3.11.7 Dependencies - [v3.11.7](/changelog/v3.11.7.md): Dependencies ### v3.11.8 Bug Fix - [v3.11.8](/changelog/v3.11.8.md): Bug Fix ### v3.11.9 Polish - [v3.11.9](/changelog/v3.11.9.md): Polish ### v3.12.0 Breaking Change - [v3.12.0](/changelog/v3.12.0.md): Breaking Change ### v3.12.1 Bug Fix - [v3.12.1](/changelog/v3.12.1.md): Bug Fix ### v3.12.10 Dependencies - [v3.12.10](/changelog/v3.12.10.md): Dependencies ### v3.12.2 Bug Fix - [v3.12.2](/changelog/v3.12.2.md): Bug Fix ### v3.12.3 Bug Fix - [v3.12.3](/changelog/v3.12.3.md): Bug Fix ### v3.12.4 Bug Fix - [v3.12.4](/changelog/v3.12.4.md): Bug Fix ### v3.12.5 Documentation - [v3.12.5](/changelog/v3.12.5.md): Documentation ### v3.12.6 Documentation - [v3.12.6](/changelog/v3.12.6.md): Documentation ### v3.12.7 Bug Fix - [v3.12.7](/changelog/v3.12.7.md): Bug Fix ### v3.12.8 Bug Fix - [v3.12.8](/changelog/v3.12.8.md): Bug Fix ### v3.12.9 Bug Fix - [v3.12.9](/changelog/v3.12.9.md): Bug Fix ### v3.13.0 New Feature - [v3.13.0](/changelog/v3.13.0.md): New Feature ### v3.13.1 Bug Fix - [v3.13.1](/changelog/v3.13.1.md): Bug Fix ### v3.13.2 Bug Fix - [v3.13.2](/changelog/v3.13.2.md): Bug Fix ### v3.13.3 Bug Fix - [v3.13.3](/changelog/v3.13.3.md): Bug Fix ### v3.13.4 Bug Fix - [v3.13.4](/changelog/v3.13.4.md): Bug Fix ### v3.13.5 Polish - [v3.13.5](/changelog/v3.13.5.md): Polish ### v3.13.6 Bug Fix - [v3.13.6](/changelog/v3.13.6.md): Bug Fix ### v3.13.7 Dependencies - [v3.13.7](/changelog/v3.13.7.md): Dependencies ### v3.13.8 Bug Fix - [v3.13.8](/changelog/v3.13.8.md): Bug Fix ### v3.13.9 Bug Fix - [v3.13.9](/changelog/v3.13.9.md): Bug Fix ### v3.14.0 New Feature - [v3.14.0](/changelog/v3.14.0.md): New Feature ### v3.14.1 Bug Fix - [v3.14.1](/changelog/v3.14.1.md): Bug Fix ### v3.14.10 Bug Fix - [v3.14.10](/changelog/v3.14.10.md): Bug Fix ### v3.14.11 Bug Fix - [v3.14.11](/changelog/v3.14.11.md): Bug Fix ### v3.14.12 Bug Fix - [v3.14.12](/changelog/v3.14.12.md): Bug Fix ### v3.14.13 Bug Fix - [v3.14.13](/changelog/v3.14.13.md): Bug Fix ### v3.14.2 Bug Fix - [v3.14.2](/changelog/v3.14.2.md): Bug Fix ### v3.14.3 Polish - [v3.14.3](/changelog/v3.14.3.md): Polish ### v3.14.4 Bug Fix - [v3.14.4](/changelog/v3.14.4.md): Bug Fix ### v3.14.5 Bug Fix - [v3.14.5](/changelog/v3.14.5.md): Bug Fix ### v3.14.6 Bug Fix - [v3.14.6](/changelog/v3.14.6.md): Bug Fix ### v3.14.7 Bug Fix - [v3.14.7](/changelog/v3.14.7.md): Bug Fix ### v3.14.8 Bug Fix - [v3.14.8](/changelog/v3.14.8.md): Bug Fix ### v3.14.9 Polish - [v3.14.9](/changelog/v3.14.9.md): Polish ### v3.15.0 New Feature - [v3.15.0](/changelog/v3.15.0.md): New Feature ### v3.15.1 Polish - [v3.15.1](/changelog/v3.15.1.md): Polish ### v3.15.10 Polish - [v3.15.10](/changelog/v3.15.10.md): Polish ### v3.15.11 Bug Fix - [v3.15.11](/changelog/v3.15.11.md): Bug Fix ### v3.15.2 Polish - [v3.15.2](/changelog/v3.15.2.md): Polish ### v3.15.3 Bug Fix - [v3.15.3](/changelog/v3.15.3.md): Bug Fix ### v3.15.4 Bug Fix - [v3.15.4](/changelog/v3.15.4.md): Bug Fix ### v3.15.5 Bug Fix - [v3.15.5](/changelog/v3.15.5.md): Bug Fix ### v3.15.6 Bug Fix - [v3.15.6](/changelog/v3.15.6.md): Bug Fix ### v3.15.7 Bug Fix - [v3.15.7](/changelog/v3.15.7.md): Bug Fix ### v3.15.8 Bug Fix - [v3.15.8](/changelog/v3.15.8.md): Bug Fix ### v3.15.9 Bug Fix - [v3.15.9](/changelog/v3.15.9.md): Bug Fix ### v3.16.0 New Feature - [v3.16.0](/changelog/v3.16.0.md): New Feature ### v3.16.1 Bug Fix - [v3.16.1](/changelog/v3.16.1.md): Bug Fix ### v3.16.2 Bug Fix - [v3.16.2](/changelog/v3.16.2.md): Bug Fix ### v3.16.3 Bug Fix - [v3.16.3](/changelog/v3.16.3.md): Bug Fix ### v3.16.4 Documentation - [v3.16.4](/changelog/v3.16.4.md): Documentation ### v3.16.5 Documentation - [v3.16.5](/changelog/v3.16.5.md): Documentation ### v3.16.6 Polish - [v3.16.6](/changelog/v3.16.6.md): Polish ### v3.16.7 Bug Fix - [v3.16.7](/changelog/v3.16.7.md): Bug Fix ### v3.16.8 Bug Fix - [v3.16.8](/changelog/v3.16.8.md): Bug Fix ### v3.17.0 New Feature - [v3.17.0](/changelog/v3.17.0.md): New Feature ### v3.17.1 Bug Fix - [v3.17.1](/changelog/v3.17.1.md): Bug Fix ### v3.17.2 Bug Fix - [v3.17.2](/changelog/v3.17.2.md): Bug Fix ### v3.17.3 Bug Fix - [v3.17.3](/changelog/v3.17.3.md): Bug Fix ### v3.18.0 New Feature - [v3.18.0](/changelog/v3.18.0.md): New Feature ### v3.18.1 Bug Fix - [v3.18.1](/changelog/v3.18.1.md): Bug Fix ### v3.18.2 Documentation - [v3.18.2](/changelog/v3.18.2.md): Documentation ### v3.19.0 New Feature - [v3.19.0](/changelog/v3.19.0.md): New Feature ### v3.19.1 Bug Fix - [v3.19.1](/changelog/v3.19.1.md): Bug Fix ### v3.19.2 Polish - [v3.19.2](/changelog/v3.19.2.md): Polish ### v3.19.3 Bug Fix - [v3.19.3](/changelog/v3.19.3.md): Bug Fix ### v3.2.0 Bug Fixes - [v3.2.0](/changelog/v3.2.0.md): Bug Fixes ### v3.2.1 Bug Fixes - [v3.2.1](/changelog/v3.2.1.md): Bug Fixes ### v3.2.2 Bug Fixes - [v3.2.2](/changelog/v3.2.2.md): Bug Fixes ### v3.20.0 Polish - [v3.20.0](/changelog/v3.20.0.md): Polish ### v3.20.1 Bug Fix - [v3.20.1](/changelog/v3.20.1.md): Bug Fix ### v3.20.10 Bug Fix - [v3.20.10](/changelog/v3.20.10.md): Bug Fix ### v3.20.11 Polish - [v3.20.11](/changelog/v3.20.11.md): Polish ### v3.20.12 Polish - [v3.20.12](/changelog/v3.20.12.md): Polish ### v3.20.2 Bug Fix - [v3.20.2](/changelog/v3.20.2.md): Bug Fix ### v3.20.3 Bug Fix - [v3.20.3](/changelog/v3.20.3.md): Bug Fix ### v3.20.4 Polish - [v3.20.4](/changelog/v3.20.4.md): Polish ### v3.20.5 Polish - [v3.20.5](/changelog/v3.20.5.md): Polish ### v3.20.6 Polish - [v3.20.6](/changelog/v3.20.6.md): Polish ### v3.20.7 Bug Fix - [v3.20.7](/changelog/v3.20.7.md): Bug Fix ### v3.20.8 Polish - [v3.20.8](/changelog/v3.20.8.md): Polish ### v3.20.9 Polish - [v3.20.9](/changelog/v3.20.9.md): Polish ### v3.3.0 Bug Fixes - [v3.3.0](/changelog/v3.3.0.md): Bug Fixes ### v3.3.1 Bug Fixes - [v3.3.1](/changelog/v3.3.1.md): Bug Fixes ### v3.3.10 Features - [v3.3.10](/changelog/v3.3.10.md): Features ### v3.3.11 Note: Version bump only for package midway_project - [v3.3.11](/changelog/v3.3.11.md): Note: Version bump only for package midway_project ### v3.3.12 Bug Fixes - [v3.3.12](/changelog/v3.3.12.md): Bug Fixes ### v3.3.13 Bug Fixes - [v3.3.13](/changelog/v3.3.13.md): Bug Fixes ### v3.3.14 Bug Fixes - [v3.3.14](/changelog/v3.3.14.md): Bug Fixes ### v3.3.2 Bug Fixes - [v3.3.2](/changelog/v3.3.2.md): Bug Fixes ### v3.3.3 Bug Fixes - [v3.3.3](/changelog/v3.3.3.md): Bug Fixes ### v3.3.4 Bug Fixes - [v3.3.4](/changelog/v3.3.4.md): Bug Fixes ### v3.3.5 Bug Fixes - [v3.3.5](/changelog/v3.3.5.md): Bug Fixes ### v3.3.6 Bug Fixes - [v3.3.6](/changelog/v3.3.6.md): Bug Fixes ### v3.3.7 Bug Fixes - [v3.3.7](/changelog/v3.3.7.md): Bug Fixes ### v3.3.8 Bug Fixes - [v3.3.8](/changelog/v3.3.8.md): Bug Fixes ### v3.3.9 Bug Fixes - [v3.3.9](/changelog/v3.3.9.md): Bug Fixes ### v3.4.0 Note: Version bump only for package midway_project - [v3.4.0](/changelog/v3.4.0.md): Note: Version bump only for package midway_project ### v3.4.1 Bug Fixes - [v3.4.1](/changelog/v3.4.1.md): Bug Fixes ### v3.4.10 Bug Fixes - [v3.4.10](/changelog/v3.4.10.md): Bug Fixes ### v3.4.11 Bug Fixes - [v3.4.11](/changelog/v3.4.11.md): Bug Fixes ### v3.4.12 Bug Fixes - [v3.4.12](/changelog/v3.4.12.md): Bug Fixes ### v3.4.13 Bug Fixes - [v3.4.13](/changelog/v3.4.13.md): Bug Fixes ### v3.4.2 Bug Fixes - [v3.4.2](/changelog/v3.4.2.md): Bug Fixes ### v3.4.3 Bug Fixes - [v3.4.3](/changelog/v3.4.3.md): Bug Fixes ### v3.4.4 Bug Fixes - [v3.4.4](/changelog/v3.4.4.md): Bug Fixes ### v3.4.5 Bug Fixes - [v3.4.5](/changelog/v3.4.5.md): Bug Fixes ### v3.4.6 Bug Fixes - [v3.4.6](/changelog/v3.4.6.md): Bug Fixes ### v3.4.7 Bug Fixes - [v3.4.7](/changelog/v3.4.7.md): Bug Fixes ### v3.4.8 Performance Improvements - [v3.4.8](/changelog/v3.4.8.md): Performance Improvements ### v3.4.9 Bug Fixes - [v3.4.9](/changelog/v3.4.9.md): Bug Fixes ### v3.5.0 Bug Fixes - [v3.5.0](/changelog/v3.5.0.md): Bug Fixes ### v3.5.1 Bug Fixes - [v3.5.1](/changelog/v3.5.1.md): Bug Fixes ### v3.5.2 Bug Fixes - [v3.5.2](/changelog/v3.5.2.md): Bug Fixes ### v3.5.3 Bug Fixes - [v3.5.3](/changelog/v3.5.3.md): Bug Fixes ### v3.6.0 Bug Fixes - [v3.6.0](/changelog/v3.6.0.md): Bug Fixes ### v3.6.1 Bug Fixes - [v3.6.1](/changelog/v3.6.1.md): Bug Fixes ### v3.7.0 Bug Fixes - [v3.7.0](/changelog/v3.7.0.md): Bug Fixes ### v3.7.1 Bug Fix - [v3.7.1](/changelog/v3.7.1.md): Bug Fix ### v3.7.2 Bug Fix - [v3.7.2](/changelog/v3.7.2.md): Bug Fix ### v3.7.3 Bug Fix - [v3.7.3](/changelog/v3.7.3.md): Bug Fix ### v3.7.4 Bug Fix - [v3.7.4](/changelog/v3.7.4.md): Bug Fix ### v3.8.0 New Feature - [v3.8.0](/changelog/v3.8.0.md): New Feature ### v3.8.1 Bug Fix - [v3.8.1](/changelog/v3.8.1.md): Bug Fix ### v3.8.2 Bug Fix - [v3.8.2](/changelog/v3.8.2.md): Bug Fix ### v3.8.3 Bug Fix - [v3.8.3](/changelog/v3.8.3.md): Bug Fix ### v3.8.4 Bug Fix - [v3.8.4](/changelog/v3.8.4.md): Bug Fix ### v3.9.0 New Feature - [v3.9.0](/changelog/v3.9.0.md): New Feature ### v3.9.1 Polish - [v3.9.1](/changelog/v3.9.1.md): Polish ### v3.9.2 Bug Fix - [v3.9.2](/changelog/v3.9.2.md): Bug Fix ### v3.9.3 Bug Fix - [v3.9.3](/changelog/v3.9.3.md): Bug Fix ### v3.9.4 Bug Fix - [v3.9.4](/changelog/v3.9.4.md): Bug Fix ### v3.9.5 Bug Fix - [v3.9.5](/changelog/v3.9.5.md): Bug Fix ### v3.9.6 Bug Fix - [v3.9.6](/changelog/v3.9.6.md): Bug Fix ### v3.9.7 Bug Fix - [v3.9.7](/changelog/v3.9.7.md): Bug Fix ### v3.9.8 Bug Fix - [v3.9.8](/changelog/v3.9.8.md): Bug Fix ### v3.9.9 Bug Fix - [v3.9.9](/changelog/v3.9.9.md): Bug Fix ### v4.0.0 Dependencies - [v4.0.0](/changelog/v4.0.0.md): Dependencies ### v4.0.0-beta.1 Breaking Change - [v4.0.0-beta.1](/changelog/v4.0.0-beta.1.md): Breaking Change ### v4.0.0-beta.10 New Feature - [v4.0.0-beta.10](/changelog/v4.0.0-beta.10.md): New Feature ### v4.0.0-beta.11 Bug Fix - [v4.0.0-beta.11](/changelog/v4.0.0-beta.11.md): Bug Fix ### v4.0.0-beta.12 Breaking Change - [v4.0.0-beta.12](/changelog/v4.0.0-beta.12.md): Breaking Change ### v4.0.0-beta.13 Bug Fix - [v4.0.0-beta.13](/changelog/v4.0.0-beta.13.md): Bug Fix ### v4.0.0-beta.14 New Feature - [v4.0.0-beta.14](/changelog/v4.0.0-beta.14.md): New Feature ### v4.0.0-beta.15 Bug Fix - [v4.0.0-beta.15](/changelog/v4.0.0-beta.15.md): Bug Fix ### v4.0.0-beta.16 New Feature - [v4.0.0-beta.16](/changelog/v4.0.0-beta.16.md): New Feature ### v4.0.0-beta.17 Bug Fix - [v4.0.0-beta.17](/changelog/v4.0.0-beta.17.md): Bug Fix ### v4.0.0-beta.2 Breaking Change - [v4.0.0-beta.2](/changelog/v4.0.0-beta.2.md): Breaking Change ### v4.0.0-beta.3 New Feature - [v4.0.0-beta.3](/changelog/v4.0.0-beta.3.md): New Feature ### v4.0.0-beta.4 Bug Fix - [v4.0.0-beta.4](/changelog/v4.0.0-beta.4.md): Bug Fix ### v4.0.0-beta.5 Polish - [v4.0.0-beta.5](/changelog/v4.0.0-beta.5.md): Polish ### v4.0.0-beta.6 Bug Fix - [v4.0.0-beta.6](/changelog/v4.0.0-beta.6.md): Bug Fix ### v4.0.0-beta.7 Bug Fix - [v4.0.0-beta.7](/changelog/v4.0.0-beta.7.md): Bug Fix ### v4.0.0-beta.8 Bug Fix - [v4.0.0-beta.8](/changelog/v4.0.0-beta.8.md): Bug Fix ### v4.0.0-beta.9 New Feature - [v4.0.0-beta.9](/changelog/v4.0.0-beta.9.md): New Feature ### v4.0.1 New Feature - [v4.0.1](/changelog/v4.0.1.md): New Feature ### v4.0.2 New Feature - [v4.0.2](/changelog/v4.0.2.md): New Feature ### v4.0.3 Bug Fix - [v4.0.3](/changelog/v4.0.3.md): Bug Fix ## index.layout 来源页面:index.tsx - [首页布局梳理(用于重设计)](/index.layout.md): 来源页面:index.tsx ## search - [在文档中搜索](/search.md) ## test-webcontainer 测试 WebContainer 组件 - [WebContainer 组件测试](/test-webcontainer.md): 测试 WebContainer 组件 ## tutorials 通过交互式教程学习 Midway.js 开发 - [🚧 教程中心 (开发中)](/tutorials.md): 通过交互式教程学习 Midway.js 开发 ### class-syntax 使用 IoC + 装饰器构建优雅的 Node.js 应用架构 - [🚧 Class 语法教程 (开发中)](/tutorials/class-syntax.md): 使用 IoC + 装饰器构建优雅的 Node.js 应用架构 ### function-syntax 使用函数 + Hooks 进行快速全栈应用开发 - [🚧 Function 语法教程 (开发中)](/tutorials/function-syntax.md): 使用函数 + Hooks 进行快速全栈应用开发 ## api - [API](/api.md) ### 3.0.0 - [API](/api/3.0.0.md) #### async-hooks-context-manager - [@midwayjs/async-hooks-context-manager](/api/3.0.0/async-hooks-context-manager.md) - [AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) - [AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) - [createContextManager](/api/3.0.0/async-hooks-context-manager/function/createContextManager.md) - [isSemverGreaterThanOrEqualTo](/api/3.0.0/async-hooks-context-manager/function/isSemverGreaterThanOrEqualTo.md) #### axios - [@midwayjs/axios](/api/3.0.0/axios.md) - [Configuration](/api/3.0.0/axios/class/Configuration.md) - [HttpService](/api/3.0.0/axios/class/HttpService.md) - [HttpServiceFactory](/api/3.0.0/axios/class/HttpServiceFactory.md) - [AxiosRequestConfig ](/api/3.0.0/axios/interface/AxiosRequestConfig.md): Interface for custom axios request config merging. - [AxiosResponse ](/api/3.0.0/axios/interface/AxiosResponse.md) #### bootstrap - [@midwayjs/bootstrap](/api/3.0.0/bootstrap.md) - [abstractAbstractForkManager ](/api/3.0.0/bootstrap/class/AbstractForkManager.md) - [Bootstrap](/api/3.0.0/bootstrap/class/Bootstrap.md) - [BootstrapStarter](/api/3.0.0/bootstrap/class/BootstrapStarter.md) - [ClusterManager](/api/3.0.0/bootstrap/class/ClusterManager.md) - [setupStickyMaster](/api/3.0.0/bootstrap/function/setupStickyMaster.md) - [ForkOptions](/api/3.0.0/bootstrap/interface/ForkOptions.md) - [IForkManager ](/api/3.0.0/bootstrap/interface/IForkManager.md) #### bull - [@midwayjs/bull](/api/3.0.0/bull.md) - [BullQueue](/api/3.0.0/bull/class/BullQueue.md) - [Configuration](/api/3.0.0/bull/class/Configuration.md) - [Framework](/api/3.0.0/bull/class/Framework.md) - [InjectQueue](/api/3.0.0/bull/function/InjectQueue.md) - [Processor](/api/3.0.0/bull/function/Processor.md) - [Application](/api/3.0.0/bull/interface/Application.md) - [Context](/api/3.0.0/bull/interface/Context.md) - [IProcessor](/api/3.0.0/bull/interface/IProcessor.md) - [IQueue ](/api/3.0.0/bull/interface/IQueue.md) - [IQueueManager ](/api/3.0.0/bull/interface/IQueueManager.md) #### bull-board - [@midwayjs/bull-board](/api/3.0.0/bull-board.md) - [BoardMiddleware](/api/3.0.0/bull-board/class/BoardMiddleware.md) - [BullBoardManager](/api/3.0.0/bull-board/class/BullBoardManager.md) - [Configuration](/api/3.0.0/bull-board/class/Configuration.md) - [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - [BullBoardOption](/api/3.0.0/bull-board/interface/BullBoardOption.md) #### captcha - [@midwayjs/captcha](/api/3.0.0/captcha.md) - [CaptchaService](/api/3.0.0/captcha/class/CaptchaService.md) - [Configuration](/api/3.0.0/captcha/class/Configuration.md) - [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md) - [CaptchaOptions](/api/3.0.0/captcha/interface/CaptchaOptions.md) - [FormulaCaptchaOptions](/api/3.0.0/captcha/interface/FormulaCaptchaOptions.md) - [ImageCaptchaOptions](/api/3.0.0/captcha/interface/ImageCaptchaOptions.md) - [TextCaptchaOptions](/api/3.0.0/captcha/interface/TextCaptchaOptions.md) #### casbin - [@midwayjs/casbin](/api/3.0.0/casbin.md) - [AuthGuard](/api/3.0.0/casbin/class/AuthGuard.md) - [abstractBaseAdapter ](/api/3.0.0/casbin/class/BaseAdapter.md) - [CasbinEnforcerService](/api/3.0.0/casbin/class/CasbinEnforcerService.md) - [Configuration](/api/3.0.0/casbin/class/Configuration.md) - [AuthAction](/api/3.0.0/casbin/enum/AuthAction.md) - [AuthActionVerb](/api/3.0.0/casbin/enum/AuthActionVerb.md) - [AuthPossession](/api/3.0.0/casbin/enum/AuthPossession.md) - [UsePermission](/api/3.0.0/casbin/function/UsePermission.md) - [CasbinConfigOptions](/api/3.0.0/casbin/interface/CasbinConfigOptions.md) - [Permission](/api/3.0.0/casbin/interface/Permission.md) #### casbin-redis-adapter - [@midwayjs/casbin-redis-adapter](/api/3.0.0/casbin-redis-adapter.md) - [abstractBaseWatcher ](/api/3.0.0/casbin-redis-adapter/class/BaseWatcher.md) - [NodeRedisAdapter](/api/3.0.0/casbin-redis-adapter/class/NodeRedisAdapter.md) - [NodeRedisWatcher](/api/3.0.0/casbin-redis-adapter/class/NodeRedisWatcher.md) - [createAdapter](/api/3.0.0/casbin-redis-adapter/function/createAdapter.md) - [createWatcher](/api/3.0.0/casbin-redis-adapter/function/createWatcher.md) #### casbin-typeorm-adapter - [@midwayjs/casbin-typeorm-adapter](/api/3.0.0/casbin-typeorm-adapter.md) - [CasbinMongoRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinMongoRule.md) - [CasbinRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinRule.md) - [TypeORMAdapter](/api/3.0.0/casbin-typeorm-adapter/class/TypeORMAdapter.md): TypeORMAdapter represents the TypeORM filtered adapter for policy storage. - [createAdapter](/api/3.0.0/casbin-typeorm-adapter/function/createAdapter.md) #### code-dye - [@midwayjs/code-dye](/api/3.0.0/code-dye.md) - [CodeDyeMW](/api/3.0.0/code-dye/class/CodeDyeMW.md) - [Configuration](/api/3.0.0/code-dye/class/Configuration.md) - [CodeDyeOptions](/api/3.0.0/code-dye/interface/CodeDyeOptions.md) #### consul - [@midwayjs/consul](/api/3.0.0/consul.md) - [BalancerService](/api/3.0.0/consul/class/BalancerService.md) - [Configuration](/api/3.0.0/consul/class/Configuration.md) - [ConsulController](/api/3.0.0/consul/class/ConsulController.md) - [ConsulConfig](/api/3.0.0/consul/interface/ConsulConfig.md) - [IConsulBalancer](/api/3.0.0/consul/interface/IConsulBalancer.md) - [IConsulProviderInfoOptions](/api/3.0.0/consul/interface/IConsulProviderInfoOptions.md) - [IConsulRegisterInfoOptions](/api/3.0.0/consul/interface/IConsulRegisterInfoOptions.md) - [IServiceBalancer](/api/3.0.0/consul/interface/IServiceBalancer.md) #### core - [@midwayjs/core](/api/3.0.0/core.md) - [abstractAbstractFileDetector ](/api/3.0.0/core/class/AbstractFileDetector.md) - [abstractBaseFramework ](/api/3.0.0/core/class/BaseFramework.md) - [CommonJSFileDetector](/api/3.0.0/core/class/CommonJSFileDetector.md): CommonJS module loader - [ContextMiddlewareManager ](/api/3.0.0/core/class/ContextMiddlewareManager.md) - [CustomModuleDetector](/api/3.0.0/core/class/CustomModuleDetector.md) - [abstractDataListener ](/api/3.0.0/core/class/DataListener.md) - [abstractDataSourceManager ](/api/3.0.0/core/class/DataSourceManager.md) - [DecoratorManager](/api/3.0.0/core/class/DecoratorManager.md) - [DefaultConsoleLoggerFactory](/api/3.0.0/core/class/DefaultConsoleLoggerFactory.md) - [ESModuleFileDetector](/api/3.0.0/core/class/ESModuleFileDetector.md): ES module loader - [FilterManager ](/api/3.0.0/core/class/FilterManager.md) - [abstractFrameworkType](/api/3.0.0/core/class/FrameworkType.md) - [FunctionalConfiguration](/api/3.0.0/core/class/FunctionalConfiguration.md) - [HttpClient](/api/3.0.0/core/class/HttpClient.md): A simple http client - [HttpServerResponse ](/api/3.0.0/core/class/HttpServerResponse.md) - [abstractLoggerFactory ](/api/3.0.0/core/class/LoggerFactory.md) - [MidwayApplicationManager](/api/3.0.0/core/class/MidwayApplicationManager.md) - [MidwayAspectService](/api/3.0.0/core/class/MidwayAspectService.md) - [MidwayCodeInvokeTimeoutError](/api/3.0.0/core/class/MidwayCodeInvokeTimeoutError.md) - [MidwayCommonError](/api/3.0.0/core/class/MidwayCommonError.md) - [MidwayConfigMissingError](/api/3.0.0/core/class/MidwayConfigMissingError.md) - [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) - [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md): Abstract Object Factory 对象容器抽象 - [MidwayDecoratorService](/api/3.0.0/core/class/MidwayDecoratorService.md) - [MidwayDefinitionNotFoundError](/api/3.0.0/core/class/MidwayDefinitionNotFoundError.md) - [MidwayDuplicateClassNameError](/api/3.0.0/core/class/MidwayDuplicateClassNameError.md) - [MidwayDuplicateControllerOptionsError](/api/3.0.0/core/class/MidwayDuplicateControllerOptionsError.md) - [MidwayDuplicateRouteError](/api/3.0.0/core/class/MidwayDuplicateRouteError.md) - [MidwayEmptyValueError](/api/3.0.0/core/class/MidwayEmptyValueError.md) - [MidwayEnvironmentService](/api/3.0.0/core/class/MidwayEnvironmentService.md) - [MidwayError](/api/3.0.0/core/class/MidwayError.md) - [MidwayFeatureNoLongerSupportedError](/api/3.0.0/core/class/MidwayFeatureNoLongerSupportedError.md) - [MidwayFeatureNotImplementedError](/api/3.0.0/core/class/MidwayFeatureNotImplementedError.md) - [MidwayFrameworkService](/api/3.0.0/core/class/MidwayFrameworkService.md) - [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) - [MidwayHealthService](/api/3.0.0/core/class/MidwayHealthService.md) - [MidwayHttpError](/api/3.0.0/core/class/MidwayHttpError.md) - [MidwayInconsistentVersionError](/api/3.0.0/core/class/MidwayInconsistentVersionError.md) - [MidwayInformationService](/api/3.0.0/core/class/MidwayInformationService.md) - [MidwayInvalidConfigError](/api/3.0.0/core/class/MidwayInvalidConfigError.md) - [MidwayInvalidConfigPropertyError](/api/3.0.0/core/class/MidwayInvalidConfigPropertyError.md) - [MidwayInvokeForbiddenError](/api/3.0.0/core/class/MidwayInvokeForbiddenError.md) - [MidwayLifeCycleService](/api/3.0.0/core/class/MidwayLifeCycleService.md) - [MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md): 多客户端工厂实现 - [MidwayMainFrameworkMissingError](/api/3.0.0/core/class/MidwayMainFrameworkMissingError.md) - [MidwayMiddlewareService ](/api/3.0.0/core/class/MidwayMiddlewareService.md) - [MidwayMissingImportComponentError](/api/3.0.0/core/class/MidwayMissingImportComponentError.md) - [MidwayMockService](/api/3.0.0/core/class/MidwayMockService.md) - [MidwayParameterError](/api/3.0.0/core/class/MidwayParameterError.md) - [MidwayPerformanceManager](/api/3.0.0/core/class/MidwayPerformanceManager.md) - [MidwayPipelineService](/api/3.0.0/core/class/MidwayPipelineService.md) - [MidwayPriorityManager](/api/3.0.0/core/class/MidwayPriorityManager.md) - [MidwayRequestContainer](/api/3.0.0/core/class/MidwayRequestContainer.md): Abstract Object Factory 对象容器抽象 - [MidwayResolverMissingError](/api/3.0.0/core/class/MidwayResolverMissingError.md) - [MidwayRetryExceededMaxTimesError](/api/3.0.0/core/class/MidwayRetryExceededMaxTimesError.md) - [MidwayServerlessFunctionService](/api/3.0.0/core/class/MidwayServerlessFunctionService.md) - [MidwaySingletonInjectRequestError](/api/3.0.0/core/class/MidwaySingletonInjectRequestError.md) - [MidwayUseWrongMethodError](/api/3.0.0/core/class/MidwayUseWrongMethodError.md) - [MidwayUtilHttpClientTimeoutError](/api/3.0.0/core/class/MidwayUtilHttpClientTimeoutError.md) - [MidwayWebRouterService](/api/3.0.0/core/class/MidwayWebRouterService.md) - [PipelineContext](/api/3.0.0/core/class/PipelineContext.md): 执行pipeline 时当前上下文存储内容 - [ServerResponse ](/api/3.0.0/core/class/ServerResponse.md) - [abstractServiceFactory ](/api/3.0.0/core/class/ServiceFactory.md): 多客户端工厂实现 - [TypedResourceManager ](/api/3.0.0/core/class/TypedResourceManager.md) - [abstractWebControllerGenerator ](/api/3.0.0/core/class/WebControllerGenerator.md) - [WebRouterCollector](/api/3.0.0/core/class/WebRouterCollector.md) - [BaseType](/api/3.0.0/core/enum/BaseType.md) - [GrpcStreamTypeEnum](/api/3.0.0/core/enum/GrpcStreamTypeEnum.md) - [HttpStatus](/api/3.0.0/core/enum/HttpStatus.md) - [InjectModeEnum](/api/3.0.0/core/enum/InjectModeEnum.md) - [MidwayProcessTypeEnum](/api/3.0.0/core/enum/MidwayProcessTypeEnum.md) - [MSListenerType](/api/3.0.0/core/enum/MSListenerType.md) - [MSProviderType](/api/3.0.0/core/enum/MSProviderType.md) - [ObjectLifeCycleEvent](/api/3.0.0/core/enum/ObjectLifeCycleEvent.md) - [RouteParamTypes](/api/3.0.0/core/enum/RouteParamTypes.md) - [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) - [ServerlessTriggerType](/api/3.0.0/core/enum/ServerlessTriggerType.md) - [WSEventTypeEnum](/api/3.0.0/core/enum/WSEventTypeEnum.md) - [All](/api/3.0.0/core/function/All.md) - [App](/api/3.0.0/core/function/App.md) - [ApplicationContext](/api/3.0.0/core/function/ApplicationContext.md) - [Aspect](/api/3.0.0/core/function/Aspect.md) - [attachClassMetadata](/api/3.0.0/core/function/attachClassMetadata.md) - [attachPropertyDataToClass](/api/3.0.0/core/function/attachPropertyDataToClass.md) - [attachPropertyMetadata](/api/3.0.0/core/function/attachPropertyMetadata.md) - [Autoload](/api/3.0.0/core/function/Autoload.md) - [bindContainer](/api/3.0.0/core/function/bindContainer.md) - [Body](/api/3.0.0/core/function/Body.md) - [Catch](/api/3.0.0/core/function/Catch.md) - [clearAllModule](/api/3.0.0/core/function/clearAllModule.md) - [clearBindContainer](/api/3.0.0/core/function/clearBindContainer.md) - [Config](/api/3.0.0/core/function/Config.md) - [Configuration](/api/3.0.0/core/function/Configuration.md) - [Consumer](/api/3.0.0/core/function/Consumer.md) - [ContentType](/api/3.0.0/core/function/ContentType.md) - [Controller](/api/3.0.0/core/function/Controller.md) - [createConfiguration](/api/3.0.0/core/function/createConfiguration.md) - [createCustomMethodDecorator](/api/3.0.0/core/function/createCustomMethodDecorator.md) - [createCustomParamDecorator](/api/3.0.0/core/function/createCustomParamDecorator.md) - [createCustomPropertyDecorator](/api/3.0.0/core/function/createCustomPropertyDecorator.md) - [createMiddleware](/api/3.0.0/core/function/createMiddleware.md) - [createRender](/api/3.0.0/core/function/createRender.md) - [createRequestParamDecorator](/api/3.0.0/core/function/createRequestParamDecorator.md) - [Del](/api/3.0.0/core/function/Del.md) - [delegateTargetAllPrototypeMethod](/api/3.0.0/core/function/delegateTargetAllPrototypeMethod.md) - [delegateTargetMethod](/api/3.0.0/core/function/delegateTargetMethod.md) - [delegateTargetProperties](/api/3.0.0/core/function/delegateTargetProperties.md) - [delegateTargetPrototypeMethod](/api/3.0.0/core/function/delegateTargetPrototypeMethod.md) - [deprecatedOutput](/api/3.0.0/core/function/deprecatedOutput.md) - [Destroy](/api/3.0.0/core/function/Destroy.md) - [destroyGlobalApplicationContext](/api/3.0.0/core/function/destroyGlobalApplicationContext.md) - [DubboMethod](/api/3.0.0/core/function/DubboMethod.md) - [Emit](/api/3.0.0/core/function/Emit.md) - [extend](/api/3.0.0/core/function/extend.md) - [extractExpressLikeValue](/api/3.0.0/core/function/extractExpressLikeValue.md) - [extractKoaLikeValue](/api/3.0.0/core/function/extractKoaLikeValue.md) - [Fields](/api/3.0.0/core/function/Fields.md) - [File](/api/3.0.0/core/function/File.md) - [Files](/api/3.0.0/core/function/Files.md) - [Framework](/api/3.0.0/core/function/Framework.md) - [Get](/api/3.0.0/core/function/Get.md) - [getClassExtendedMetadata](/api/3.0.0/core/function/getClassExtendedMetadata.md) - [getClassMetadata](/api/3.0.0/core/function/getClassMetadata.md) - [getCurrentApplicationContext](/api/3.0.0/core/function/getCurrentApplicationContext.md) - [getCurrentAsyncContextManager](/api/3.0.0/core/function/getCurrentAsyncContextManager.md) - [getCurrentMainApp](/api/3.0.0/core/function/getCurrentMainApp.md) - [getCurrentMainFramework](/api/3.0.0/core/function/getCurrentMainFramework.md) - [getMethodParamTypes](/api/3.0.0/core/function/getMethodParamTypes.md) - [getMethodReturnTypes](/api/3.0.0/core/function/getMethodReturnTypes.md) - [getObjectDefinition](/api/3.0.0/core/function/getObjectDefinition.md) - [getPropertyDataFromClass](/api/3.0.0/core/function/getPropertyDataFromClass.md) - [getPropertyInject](/api/3.0.0/core/function/getPropertyInject.md) - [getPropertyMetadata](/api/3.0.0/core/function/getPropertyMetadata.md) - [getPropertyType](/api/3.0.0/core/function/getPropertyType.md) - [getProviderId](/api/3.0.0/core/function/getProviderId.md) - [getProviderName](/api/3.0.0/core/function/getProviderName.md) - [getProviderUUId](/api/3.0.0/core/function/getProviderUUId.md) - [GrpcMethod](/api/3.0.0/core/function/GrpcMethod.md) - [Guard](/api/3.0.0/core/function/Guard.md) - [Head](/api/3.0.0/core/function/Head.md) - [Headers](/api/3.0.0/core/function/Headers.md) - [HSF](/api/3.0.0/core/function/HSF.md) - [HttpCode](/api/3.0.0/core/function/HttpCode.md) - [Init](/api/3.0.0/core/function/Init.md) - [initializeGlobalApplicationContext](/api/3.0.0/core/function/initializeGlobalApplicationContext.md) - [Inject](/api/3.0.0/core/function/Inject.md) - [InjectClient](/api/3.0.0/core/function/InjectClient.md) - [isProvide](/api/3.0.0/core/function/isProvide.md) - [isTypeScriptEnvironment](/api/3.0.0/core/function/isTypeScriptEnvironment.md) - [KafkaListener](/api/3.0.0/core/function/KafkaListener.md) - [listModule](/api/3.0.0/core/function/listModule.md) - [listPreloadModule](/api/3.0.0/core/function/listPreloadModule.md) - [listPropertyDataFromClass](/api/3.0.0/core/function/listPropertyDataFromClass.md) - [loadModule](/api/3.0.0/core/function/loadModule.md) - [Logger](/api/3.0.0/core/function/Logger.md) - [makeHttpRequest](/api/3.0.0/core/function/makeHttpRequest.md) - [Match](/api/3.0.0/core/function/Match.md) - [Middleware](/api/3.0.0/core/function/Middleware.md) - [Mock](/api/3.0.0/core/function/Mock.md) - [OnConnection](/api/3.0.0/core/function/OnConnection.md) - [OnDisConnection](/api/3.0.0/core/function/OnDisConnection.md) - [OnMessage](/api/3.0.0/core/function/OnMessage.md) - [OnWSConnection](/api/3.0.0/core/function/OnWSConnection.md) - [OnWSDisConnection](/api/3.0.0/core/function/OnWSDisConnection.md) - [OnWSMessage](/api/3.0.0/core/function/OnWSMessage.md) - [Options](/api/3.0.0/core/function/Options.md) - [Param](/api/3.0.0/core/function/Param.md) - [Patch](/api/3.0.0/core/function/Patch.md) - [pathMatching](/api/3.0.0/core/function/pathMatching.md) - [Pipe](/api/3.0.0/core/function/Pipe.md) - [Pipeline](/api/3.0.0/core/function/Pipeline.md) - [Plugin](/api/3.0.0/core/function/Plugin.md) - [Post](/api/3.0.0/core/function/Post.md) - [prepareGlobalApplicationContext](/api/3.0.0/core/function/prepareGlobalApplicationContext.md) - [prepareGlobalApplicationContextAsync](/api/3.0.0/core/function/prepareGlobalApplicationContextAsync.md) - [Provide](/api/3.0.0/core/function/Provide.md) - [Provider](/api/3.0.0/core/function/Provider.md) - [providerWrapper](/api/3.0.0/core/function/providerWrapper.md) - [Put](/api/3.0.0/core/function/Put.md) - [Queries](/api/3.0.0/core/function/Queries.md) - [Query](/api/3.0.0/core/function/Query.md) - [Queue](/api/3.0.0/core/function/Queue.md) - [RabbitMQListener](/api/3.0.0/core/function/RabbitMQListener.md) - [Redirect](/api/3.0.0/core/function/Redirect.md) - [registerErrorCode](/api/3.0.0/core/function/registerErrorCode.md) - [RequestIP](/api/3.0.0/core/function/RequestIP.md) - [RequestMapping](/api/3.0.0/core/function/RequestMapping.md) - [RequestPath](/api/3.0.0/core/function/RequestPath.md) - [resetModule](/api/3.0.0/core/function/resetModule.md) - [retryWith](/api/3.0.0/core/function/retryWith.md) - [retryWithAsync](/api/3.0.0/core/function/retryWithAsync.md) - [safelyGet](/api/3.0.0/core/function/safelyGet.md) - [safeRequire](/api/3.0.0/core/function/safeRequire.md) - [saveClassMetadata](/api/3.0.0/core/function/saveClassMetadata.md) - [saveModule](/api/3.0.0/core/function/saveModule.md) - [saveObjectDefinition](/api/3.0.0/core/function/saveObjectDefinition.md) - [savePreloadModule](/api/3.0.0/core/function/savePreloadModule.md) - [savePropertyDataToClass](/api/3.0.0/core/function/savePropertyDataToClass.md) - [savePropertyInject](/api/3.0.0/core/function/savePropertyInject.md) - [savePropertyMetadata](/api/3.0.0/core/function/savePropertyMetadata.md) - [saveProviderId](/api/3.0.0/core/function/saveProviderId.md) - [Schedule](/api/3.0.0/core/function/Schedule.md) - [Scope](/api/3.0.0/core/function/Scope.md) - [ServerlessFunction](/api/3.0.0/core/function/ServerlessFunction.md) - [ServerlessTrigger](/api/3.0.0/core/function/ServerlessTrigger.md) - [Session](/api/3.0.0/core/function/Session.md) - [SetHeader](/api/3.0.0/core/function/SetHeader.md) - [Singleton](/api/3.0.0/core/function/Singleton.md) - [sleep](/api/3.0.0/core/function/sleep.md) - [Task](/api/3.0.0/core/function/Task.md) - [TaskLocal](/api/3.0.0/core/function/TaskLocal.md) - [transformRequestObjectByType](/api/3.0.0/core/function/transformRequestObjectByType.md) - [transformTypeFromTSDesign](/api/3.0.0/core/function/transformTypeFromTSDesign.md) - [UseGuard](/api/3.0.0/core/function/UseGuard.md) - [wrapAsync](/api/3.0.0/core/function/wrapAsync.md) - [wrapMiddleware](/api/3.0.0/core/function/wrapMiddleware.md) - [WSBroadCast](/api/3.0.0/core/function/WSBroadCast.md) - [WSController](/api/3.0.0/core/function/WSController.md) - [WSEmit](/api/3.0.0/core/function/WSEmit.md) - [AspectMetadata](/api/3.0.0/core/interface/AspectMetadata.md) - [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) - [AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) - [CommonSchedule](/api/3.0.0/core/interface/CommonSchedule.md) - [Context](/api/3.0.0/core/interface/Context.md) - [ControllerOption](/api/3.0.0/core/interface/ControllerOption.md) - [HealthResult](/api/3.0.0/core/interface/HealthResult.md) - [HealthResults](/api/3.0.0/core/interface/HealthResults.md) - [HSFOpts](/api/3.0.0/core/interface/HSFOpts.md) - [HttpClientOptions ](/api/3.0.0/core/interface/HttpClientOptions.md) - [HttpClientResponse ](/api/3.0.0/core/interface/HttpClientResponse.md) - [IComponentInfo](/api/3.0.0/core/interface/IComponentInfo.md) - [IConfigService](/api/3.0.0/core/interface/IConfigService.md) - [IConfigurationOptions](/api/3.0.0/core/interface/IConfigurationOptions.md) - [IEnvironmentService](/api/3.0.0/core/interface/IEnvironmentService.md) - [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md) - [IFilter ](/api/3.0.0/core/interface/IFilter.md): Common Exception Filter definition - [IGuard ](/api/3.0.0/core/interface/IGuard.md): Guard definition - [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) - [IInformationService](/api/3.0.0/core/interface/IInformationService.md) - [ILifeCycle](/api/3.0.0/core/interface/ILifeCycle.md): Lifecycle Definition 生命周期定义 - [ILogger](/api/3.0.0/core/interface/ILogger.md): Logger Options for midway, you can merge this interface in package - [IManagedInstance](/api/3.0.0/core/interface/IManagedInstance.md): 内部管理的属性、json、ref等解析实例存储 - [IManagedResolver](/api/3.0.0/core/interface/IManagedResolver.md): 解析内部管理的属性、json、ref等实例的解析器 同时创建这些对象的实际使用的对象 - [IManagedResolverFactoryCreateOptions](/api/3.0.0/core/interface/IManagedResolverFactoryCreateOptions.md) - [IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md) - [IMiddleware ](/api/3.0.0/core/interface/IMiddleware.md): Common middleware definition - [IMiddlewareManager ](/api/3.0.0/core/interface/IMiddlewareManager.md) - [IMidwayBaseApplication ](/api/3.0.0/core/interface/IMidwayBaseApplication.md) - [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md) - [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md): Abstract Object Factory 对象容器抽象 - [IMidwayFramework ](/api/3.0.0/core/interface/IMidwayFramework.md) - [IModuleStore](/api/3.0.0/core/interface/IModuleStore.md) - [InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md) - [IObjectCreator](/api/3.0.0/core/interface/IObjectCreator.md) - [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md): Object Definition 对象描述定义 - [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md): Object Definition Registry 对象定义存储容器 - [IObjectFactory](/api/3.0.0/core/interface/IObjectFactory.md): Abstract Object Factory 对象容器抽象 - [IObjectLifeCycle](/api/3.0.0/core/interface/IObjectLifeCycle.md): Object Lifecycle 对象生命周期 - [IPipelineContext](/api/3.0.0/core/interface/IPipelineContext.md): 执行pipeline 时当前上下文存储内容 - [IPipelineHandler](/api/3.0.0/core/interface/IPipelineHandler.md) - [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md): pipeline 执行参数 - [IPipelineResult ](/api/3.0.0/core/interface/IPipelineResult.md): pipeline 执行返回结果 - [IProperties](/api/3.0.0/core/interface/IProperties.md): 属性配置抽象 - [IServiceFactory ](/api/3.0.0/core/interface/IServiceFactory.md) - [ISimulation](/api/3.0.0/core/interface/ISimulation.md) - [IValveHandler](/api/3.0.0/core/interface/IValveHandler.md): 每个具体的 valve 需要继承实现该接口 - [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md) - [KafkaListenerOptions](/api/3.0.0/core/interface/KafkaListenerOptions.md) - [MethodDecoratorMetaData ](/api/3.0.0/core/interface/MethodDecoratorMetaData.md) - [MethodDecoratorOptions](/api/3.0.0/core/interface/MethodDecoratorOptions.md) - [MidwayAppInfo](/api/3.0.0/core/interface/MidwayAppInfo.md) - [MidwayConfig](/api/3.0.0/core/interface/MidwayConfig.md): midway global config definition - [MidwayCoreDefaultConfig](/api/3.0.0/core/interface/MidwayCoreDefaultConfig.md) - [MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md): Logger Options for midway, you can merge this interface in package - [ObjectBeforeBindOptions](/api/3.0.0/core/interface/ObjectBeforeBindOptions.md) - [ObjectBeforeCreatedOptions](/api/3.0.0/core/interface/ObjectBeforeCreatedOptions.md) - [ObjectBeforeDestroyOptions](/api/3.0.0/core/interface/ObjectBeforeDestroyOptions.md) - [ObjectCreatedOptions ](/api/3.0.0/core/interface/ObjectCreatedOptions.md) - [ObjectDefinitionOptions](/api/3.0.0/core/interface/ObjectDefinitionOptions.md) - [ObjectInitOptions](/api/3.0.0/core/interface/ObjectInitOptions.md) - [ParamDecoratorOptions](/api/3.0.0/core/interface/ParamDecoratorOptions.md) - [ParameterDecoratorMetaData ](/api/3.0.0/core/interface/ParameterDecoratorMetaData.md) - [PipeTransform ](/api/3.0.0/core/interface/PipeTransform.md) - [RabbitMQListenerOptions](/api/3.0.0/core/interface/RabbitMQListenerOptions.md) - [ReflectResult](/api/3.0.0/core/interface/ReflectResult.md) - [ResolveFilter](/api/3.0.0/core/interface/ResolveFilter.md) - [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md) - [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md) - [RouterOption](/api/3.0.0/core/interface/RouterOption.md) - [RouterParamValue](/api/3.0.0/core/interface/RouterParamValue.md) - [RouterPriority](/api/3.0.0/core/interface/RouterPriority.md) - [ScheduleOpts](/api/3.0.0/core/interface/ScheduleOpts.md) - [ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md) - [ServerSendEventStreamOptions ](/api/3.0.0/core/interface/ServerSendEventStreamOptions.md) - [ServerStreamOptions ](/api/3.0.0/core/interface/ServerStreamOptions.md) - [TagClsMetadata](/api/3.0.0/core/interface/TagClsMetadata.md) - [TagPropsMetadata](/api/3.0.0/core/interface/TagPropsMetadata.md) - [TransformOptions ](/api/3.0.0/core/interface/TransformOptions.md) - [TSDesignType ](/api/3.0.0/core/interface/TSDesignType.md) - [WSControllerOption](/api/3.0.0/core/interface/WSControllerOption.md) - [WSEventInfo](/api/3.0.0/core/interface/WSEventInfo.md) - [ConsumerMetadata](/api/3.0.0/core/namespace/ConsumerMetadata.md) - [FaaSMetadata](/api/3.0.0/core/namespace/FaaSMetadata.md) - [GRPCMetadata](/api/3.0.0/core/namespace/GRPCMetadata.md): grpc decorator metadata format #### cos - [@midwayjs/cos](/api/3.0.0/cos.md) - [Configuration](/api/3.0.0/cos/class/Configuration.md) - [COSService](/api/3.0.0/cos/class/COSService.md) - [COSServiceFactory](/api/3.0.0/cos/class/COSServiceFactory.md) #### cron - [@midwayjs/cron](/api/3.0.0/cron.md) - [Configuration](/api/3.0.0/cron/class/Configuration.md) - [Framework](/api/3.0.0/cron/class/Framework.md) - [InjectJob](/api/3.0.0/cron/function/InjectJob.md) - [Job](/api/3.0.0/cron/function/Job.md) - [Application](/api/3.0.0/cron/interface/Application.md) - [Context](/api/3.0.0/cron/interface/Context.md) - [CronOptions](/api/3.0.0/cron/interface/CronOptions.md) - [IJob](/api/3.0.0/cron/interface/IJob.md) #### cross-domain - [@midwayjs/cross-domain](/api/3.0.0/cross-domain.md) - [Configuration](/api/3.0.0/cross-domain/class/Configuration.md) - [CorsMiddleware](/api/3.0.0/cross-domain/class/CorsMiddleware.md) - [JSONPFilter](/api/3.0.0/cross-domain/class/JSONPFilter.md) - [JSONPMiddleware](/api/3.0.0/cross-domain/class/JSONPMiddleware.md) - [JSONPService](/api/3.0.0/cross-domain/class/JSONPService.md) - [CORSOptions](/api/3.0.0/cross-domain/interface/CORSOptions.md) - [JSONPOptions](/api/3.0.0/cross-domain/interface/JSONPOptions.md) #### decorator - [@midwayjs/decorator](/api/3.0.0/decorator.md) - [DecoratorManager](/api/3.0.0/decorator/class/DecoratorManager.md) - [abstractFrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) - [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) - [BaseType](/api/3.0.0/decorator/enum/BaseType.md) - [GrpcStreamTypeEnum](/api/3.0.0/decorator/enum/GrpcStreamTypeEnum.md) - [InjectModeEnum](/api/3.0.0/decorator/enum/InjectModeEnum.md) - [MSListenerType](/api/3.0.0/decorator/enum/MSListenerType.md) - [MSProviderType](/api/3.0.0/decorator/enum/MSProviderType.md) - [RouteParamTypes](/api/3.0.0/decorator/enum/RouteParamTypes.md) - [ScopeEnum](/api/3.0.0/decorator/enum/ScopeEnum.md) - [ServerlessTriggerType](/api/3.0.0/decorator/enum/ServerlessTriggerType.md) - [WSEventTypeEnum](/api/3.0.0/decorator/enum/WSEventTypeEnum.md) - [All](/api/3.0.0/decorator/function/All.md) - [App](/api/3.0.0/decorator/function/App.md) - [ApplicationContext](/api/3.0.0/decorator/function/ApplicationContext.md) - [Aspect](/api/3.0.0/decorator/function/Aspect.md) - [attachClassMetadata](/api/3.0.0/decorator/function/attachClassMetadata.md) - [attachPropertyDataToClass](/api/3.0.0/decorator/function/attachPropertyDataToClass.md) - [attachPropertyMetadata](/api/3.0.0/decorator/function/attachPropertyMetadata.md) - [Autoload](/api/3.0.0/decorator/function/Autoload.md) - [bindContainer](/api/3.0.0/decorator/function/bindContainer.md) - [Body](/api/3.0.0/decorator/function/Body.md) - [Catch](/api/3.0.0/decorator/function/Catch.md) - [clearAllModule](/api/3.0.0/decorator/function/clearAllModule.md) - [clearBindContainer](/api/3.0.0/decorator/function/clearBindContainer.md) - [Config](/api/3.0.0/decorator/function/Config.md) - [Configuration](/api/3.0.0/decorator/function/Configuration.md) - [Consumer](/api/3.0.0/decorator/function/Consumer.md) - [ContentType](/api/3.0.0/decorator/function/ContentType.md) - [Controller](/api/3.0.0/decorator/function/Controller.md) - [createCustomMethodDecorator](/api/3.0.0/decorator/function/createCustomMethodDecorator.md) - [createCustomParamDecorator](/api/3.0.0/decorator/function/createCustomParamDecorator.md) - [createCustomPropertyDecorator](/api/3.0.0/decorator/function/createCustomPropertyDecorator.md) - [createRender](/api/3.0.0/decorator/function/createRender.md) - [createRequestParamDecorator](/api/3.0.0/decorator/function/createRequestParamDecorator.md) - [Del](/api/3.0.0/decorator/function/Del.md) - [Destroy](/api/3.0.0/decorator/function/Destroy.md) - [DubboMethod](/api/3.0.0/decorator/function/DubboMethod.md) - [Emit](/api/3.0.0/decorator/function/Emit.md) - [Fields](/api/3.0.0/decorator/function/Fields.md) - [File](/api/3.0.0/decorator/function/File.md) - [Files](/api/3.0.0/decorator/function/Files.md) - [Framework](/api/3.0.0/decorator/function/Framework.md) - [Get](/api/3.0.0/decorator/function/Get.md) - [getClassExtendedMetadata](/api/3.0.0/decorator/function/getClassExtendedMetadata.md) - [getClassMetadata](/api/3.0.0/decorator/function/getClassMetadata.md) - [getMethodParamTypes](/api/3.0.0/decorator/function/getMethodParamTypes.md) - [getMethodReturnTypes](/api/3.0.0/decorator/function/getMethodReturnTypes.md) - [getObjectDefinition](/api/3.0.0/decorator/function/getObjectDefinition.md) - [getPropertyDataFromClass](/api/3.0.0/decorator/function/getPropertyDataFromClass.md) - [getPropertyInject](/api/3.0.0/decorator/function/getPropertyInject.md) - [getPropertyMetadata](/api/3.0.0/decorator/function/getPropertyMetadata.md) - [getPropertyType](/api/3.0.0/decorator/function/getPropertyType.md) - [getProviderId](/api/3.0.0/decorator/function/getProviderId.md) - [getProviderName](/api/3.0.0/decorator/function/getProviderName.md) - [getProviderUUId](/api/3.0.0/decorator/function/getProviderUUId.md) - [GrpcMethod](/api/3.0.0/decorator/function/GrpcMethod.md) - [Guard](/api/3.0.0/decorator/function/Guard.md) - [Head](/api/3.0.0/decorator/function/Head.md) - [Headers](/api/3.0.0/decorator/function/Headers.md) - [HSF](/api/3.0.0/decorator/function/HSF.md) - [HttpCode](/api/3.0.0/decorator/function/HttpCode.md) - [Init](/api/3.0.0/decorator/function/Init.md) - [Inject](/api/3.0.0/decorator/function/Inject.md) - [InjectClient](/api/3.0.0/decorator/function/InjectClient.md) - [isProvide](/api/3.0.0/decorator/function/isProvide.md) - [KafkaListener](/api/3.0.0/decorator/function/KafkaListener.md) - [listModule](/api/3.0.0/decorator/function/listModule.md) - [listPreloadModule](/api/3.0.0/decorator/function/listPreloadModule.md) - [listPropertyDataFromClass](/api/3.0.0/decorator/function/listPropertyDataFromClass.md) - [Logger](/api/3.0.0/decorator/function/Logger.md) - [Match](/api/3.0.0/decorator/function/Match.md) - [Middleware](/api/3.0.0/decorator/function/Middleware.md) - [Mock](/api/3.0.0/decorator/function/Mock.md) - [OnConnection](/api/3.0.0/decorator/function/OnConnection.md) - [OnDisConnection](/api/3.0.0/decorator/function/OnDisConnection.md) - [OnMessage](/api/3.0.0/decorator/function/OnMessage.md) - [OnWSConnection](/api/3.0.0/decorator/function/OnWSConnection.md) - [OnWSDisConnection](/api/3.0.0/decorator/function/OnWSDisConnection.md) - [OnWSMessage](/api/3.0.0/decorator/function/OnWSMessage.md) - [Options](/api/3.0.0/decorator/function/Options.md) - [Param](/api/3.0.0/decorator/function/Param.md) - [Patch](/api/3.0.0/decorator/function/Patch.md) - [Pipe](/api/3.0.0/decorator/function/Pipe.md) - [Pipeline](/api/3.0.0/decorator/function/Pipeline.md) - [Plugin](/api/3.0.0/decorator/function/Plugin.md) - [Post](/api/3.0.0/decorator/function/Post.md) - [Provide](/api/3.0.0/decorator/function/Provide.md) - [Provider](/api/3.0.0/decorator/function/Provider.md) - [Put](/api/3.0.0/decorator/function/Put.md) - [Queries](/api/3.0.0/decorator/function/Queries.md) - [Query](/api/3.0.0/decorator/function/Query.md) - [Queue](/api/3.0.0/decorator/function/Queue.md) - [RabbitMQListener](/api/3.0.0/decorator/function/RabbitMQListener.md) - [Redirect](/api/3.0.0/decorator/function/Redirect.md) - [RequestIP](/api/3.0.0/decorator/function/RequestIP.md) - [RequestMapping](/api/3.0.0/decorator/function/RequestMapping.md) - [RequestPath](/api/3.0.0/decorator/function/RequestPath.md) - [resetModule](/api/3.0.0/decorator/function/resetModule.md) - [saveClassMetadata](/api/3.0.0/decorator/function/saveClassMetadata.md) - [saveModule](/api/3.0.0/decorator/function/saveModule.md) - [saveObjectDefinition](/api/3.0.0/decorator/function/saveObjectDefinition.md) - [savePreloadModule](/api/3.0.0/decorator/function/savePreloadModule.md) - [savePropertyDataToClass](/api/3.0.0/decorator/function/savePropertyDataToClass.md) - [savePropertyInject](/api/3.0.0/decorator/function/savePropertyInject.md) - [savePropertyMetadata](/api/3.0.0/decorator/function/savePropertyMetadata.md) - [saveProviderId](/api/3.0.0/decorator/function/saveProviderId.md) - [Schedule](/api/3.0.0/decorator/function/Schedule.md) - [Scope](/api/3.0.0/decorator/function/Scope.md) - [ServerlessFunction](/api/3.0.0/decorator/function/ServerlessFunction.md) - [ServerlessTrigger](/api/3.0.0/decorator/function/ServerlessTrigger.md) - [Session](/api/3.0.0/decorator/function/Session.md) - [SetHeader](/api/3.0.0/decorator/function/SetHeader.md) - [Singleton](/api/3.0.0/decorator/function/Singleton.md) - [sleep](/api/3.0.0/decorator/function/sleep.md) - [Task](/api/3.0.0/decorator/function/Task.md) - [TaskLocal](/api/3.0.0/decorator/function/TaskLocal.md) - [transformTypeFromTSDesign](/api/3.0.0/decorator/function/transformTypeFromTSDesign.md) - [UseGuard](/api/3.0.0/decorator/function/UseGuard.md) - [WSBroadCast](/api/3.0.0/decorator/function/WSBroadCast.md) - [WSController](/api/3.0.0/decorator/function/WSController.md) - [WSEmit](/api/3.0.0/decorator/function/WSEmit.md) - [CommonSchedule](/api/3.0.0/decorator/interface/CommonSchedule.md) - [ControllerOption](/api/3.0.0/decorator/interface/ControllerOption.md) - [HSFOpts](/api/3.0.0/decorator/interface/HSFOpts.md) - [IComponentInfo](/api/3.0.0/decorator/interface/IComponentInfo.md) - [IManagedInstance](/api/3.0.0/decorator/interface/IManagedInstance.md): 内部管理的属性、json、ref等解析实例存储 - [IMethodAspect](/api/3.0.0/decorator/interface/IMethodAspect.md) - [IModuleStore](/api/3.0.0/decorator/interface/IModuleStore.md) - [InjectionConfigurationOptions](/api/3.0.0/decorator/interface/InjectionConfigurationOptions.md) - [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md) - [KafkaListenerOptions](/api/3.0.0/decorator/interface/KafkaListenerOptions.md) - [ObjectDefinitionOptions](/api/3.0.0/decorator/interface/ObjectDefinitionOptions.md) - [RabbitMQListenerOptions](/api/3.0.0/decorator/interface/RabbitMQListenerOptions.md) - [ReflectResult](/api/3.0.0/decorator/interface/ReflectResult.md) - [ResolveFilter](/api/3.0.0/decorator/interface/ResolveFilter.md) - [RouterOption](/api/3.0.0/decorator/interface/RouterOption.md) - [RouterParamValue](/api/3.0.0/decorator/interface/RouterParamValue.md) - [ScheduleOpts](/api/3.0.0/decorator/interface/ScheduleOpts.md) - [TagClsMetadata](/api/3.0.0/decorator/interface/TagClsMetadata.md) - [TagPropsMetadata](/api/3.0.0/decorator/interface/TagPropsMetadata.md) - [WSControllerOption](/api/3.0.0/decorator/interface/WSControllerOption.md) - [WSEventInfo](/api/3.0.0/decorator/interface/WSEventInfo.md) - [ConsumerMetadata](/api/3.0.0/decorator/namespace/ConsumerMetadata.md) - [FaaSMetadata](/api/3.0.0/decorator/namespace/FaaSMetadata.md) - [GRPCMetadata](/api/3.0.0/decorator/namespace/GRPCMetadata.md): grpc decorator metadata format #### etcd - [@midwayjs/etcd](/api/3.0.0/etcd.md) - [Configuration](/api/3.0.0/etcd/class/Configuration.md) - [ETCDService](/api/3.0.0/etcd/class/ETCDService.md) - [ETCDServiceFactory](/api/3.0.0/etcd/class/ETCDServiceFactory.md) #### express-session - [@midwayjs/express-session](/api/3.0.0/express-session.md) - [Configuration](/api/3.0.0/express-session/class/Configuration.md) - [SessionMiddleware](/api/3.0.0/express-session/class/SessionMiddleware.md) - [SessionStoreManager](/api/3.0.0/express-session/class/SessionStoreManager.md) #### faas - [@midwayjs/faas](/api/3.0.0/faas.md) - [abstractAbstractBootstrapStarter](/api/3.0.0/faas/class/AbstractBootstrapStarter.md) - [Configuration](/api/3.0.0/faas/class/Configuration.md) - [Framework](/api/3.0.0/faas/class/Framework.md) - [Event](/api/3.0.0/faas/function/Event.md) - [Application](/api/3.0.0/faas/interface/Application.md) - [Context](/api/3.0.0/faas/interface/Context.md) - [FaaSContext](/api/3.0.0/faas/interface/FaaSContext.md) - [FaaSHTTPContext](/api/3.0.0/faas/interface/FaaSHTTPContext.md) - [FaaSHTTPRequest](/api/3.0.0/faas/interface/FaaSHTTPRequest.md) - [FaaSHTTPResponse](/api/3.0.0/faas/interface/FaaSHTTPResponse.md) - [FormatResponseOptions](/api/3.0.0/faas/interface/FormatResponseOptions.md) - [HandlerOptions](/api/3.0.0/faas/interface/HandlerOptions.md) - [HttpResponseFormat ](/api/3.0.0/faas/interface/HttpResponseFormat.md) - [IFaaSConfigurationOptions](/api/3.0.0/faas/interface/IFaaSConfigurationOptions.md) - [IWebMiddleware](/api/3.0.0/faas/interface/IWebMiddleware.md) - [ServerlessStarterOptions](/api/3.0.0/faas/interface/ServerlessStarterOptions.md) - [State](/api/3.0.0/faas/interface/State.md) - [wrapHttpRequestOptions](/api/3.0.0/faas/interface/wrapHttpRequestOptions.md) #### grpc - [@midwayjs/grpc](/api/3.0.0/grpc.md) - [Clients](/api/3.0.0/grpc/class/Clients.md) - [Configuration](/api/3.0.0/grpc/class/Configuration.md) - [Framework](/api/3.0.0/grpc/class/Framework.md) - [createGRPCConsumer](/api/3.0.0/grpc/function/createGRPCConsumer.md) - [loadProto](/api/3.0.0/grpc/function/loadProto.md) - [Context ](/api/3.0.0/grpc/interface/Context.md) - [DefaultConfig](/api/3.0.0/grpc/interface/DefaultConfig.md) - [IClientDuplexStreamService ](/api/3.0.0/grpc/interface/IClientDuplexStreamService.md) - [IClientOptions](/api/3.0.0/grpc/interface/IClientOptions.md) - [IClientReadableStreamService ](/api/3.0.0/grpc/interface/IClientReadableStreamService.md) - [IClientUnaryService ](/api/3.0.0/grpc/interface/IClientUnaryService.md) - [IClientWritableStreamService ](/api/3.0.0/grpc/interface/IClientWritableStreamService.md) - [IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md) - [IGRPCServiceOptions](/api/3.0.0/grpc/interface/IGRPCServiceOptions.md) - [IMidwayGRPFrameworkOptions](/api/3.0.0/grpc/interface/IMidwayGRPFrameworkOptions.md) #### http-proxy - [@midwayjs/http-proxy](/api/3.0.0/http-proxy.md) - [Configuration](/api/3.0.0/http-proxy/class/Configuration.md) - [HttpProxyMiddleware](/api/3.0.0/http-proxy/class/HttpProxyMiddleware.md) - [HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md) - [HttpProxyStrategy](/api/3.0.0/http-proxy/interface/HttpProxyStrategy.md) #### i18n - [@midwayjs/i18n](/api/3.0.0/i18n.md) - [Configuration](/api/3.0.0/i18n/class/Configuration.md) - [I18nFilter](/api/3.0.0/i18n/class/I18nFilter.md) - [I18nMiddleware](/api/3.0.0/i18n/class/I18nMiddleware.md) - [MidwayI18nService](/api/3.0.0/i18n/class/MidwayI18nService.md) - [MidwayI18nServiceSingleton](/api/3.0.0/i18n/class/MidwayI18nServiceSingleton.md) - [formatLocale](/api/3.0.0/i18n/function/formatLocale.md) - [I18nOptions](/api/3.0.0/i18n/interface/I18nOptions.md) - [RequestResolver](/api/3.0.0/i18n/interface/RequestResolver.md) - [TranslateOptions](/api/3.0.0/i18n/interface/TranslateOptions.md) #### info - [@midwayjs/info](/api/3.0.0/info.md) - [Configuration](/api/3.0.0/info/class/Configuration.md) - [InfoMiddleware](/api/3.0.0/info/class/InfoMiddleware.md) - [InfoService](/api/3.0.0/info/class/InfoService.md) - [InfoType](/api/3.0.0/info/enum/InfoType.md) - [InfoConfigOptions](/api/3.0.0/info/interface/InfoConfigOptions.md) - [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) #### jwt - [@midwayjs/jwt](/api/3.0.0/jwt.md) - [Configuration](/api/3.0.0/jwt/class/Configuration.md) - [JwtService](/api/3.0.0/jwt/class/JwtService.md): @see{@link https://github.com/auth0/node-jsonwebtoken} #### kafka - [@midwayjs/kafka](/api/3.0.0/kafka.md) - [Configuration](/api/3.0.0/kafka/class/Configuration.md) - [Framework](/api/3.0.0/kafka/class/Framework.md) - [KafkaAdminFactory](/api/3.0.0/kafka/class/KafkaAdminFactory.md) - [KafkaProducerFactory](/api/3.0.0/kafka/class/KafkaProducerFactory.md) - [KafkaConsumer](/api/3.0.0/kafka/function/KafkaConsumer.md) - [Context](/api/3.0.0/kafka/interface/Context.md) - [IKafkaApplication](/api/3.0.0/kafka/interface/IKafkaApplication.md) - [IKafkaConsumer](/api/3.0.0/kafka/interface/IKafkaConsumer.md) - [IKafkaConsumerInitOptions](/api/3.0.0/kafka/interface/IKafkaConsumerInitOptions.md): The options for the kafka consumer initialization in midway - [IMidwayConsumerConfig](/api/3.0.0/kafka/interface/IMidwayConsumerConfig.md): 客户端的相关配置,在midwayjs的自定义配置项 - [IMidwayKafkaAdminInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaAdminInitOptions.md): The options for the kafka admin initialization in midway - [IMidwayKafkaConfigurationOptions](/api/3.0.0/kafka/interface/IMidwayKafkaConfigurationOptions.md) - [IMidwayKafkaProducerInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaProducerInitOptions.md): The options for the kafka producer initialization in midway #### mikro - [@midwayjs/mikro](/api/3.0.0/mikro.md) - [Configuration](/api/3.0.0/mikro/class/Configuration.md) - [MikroDataSourceManager](/api/3.0.0/mikro/class/MikroDataSourceManager.md) - [InjectDataSource](/api/3.0.0/mikro/function/InjectDataSource.md) - [InjectEntityManager](/api/3.0.0/mikro/function/InjectEntityManager.md) - [InjectRepository](/api/3.0.0/mikro/function/InjectRepository.md) #### mock - [@midwayjs/mock](/api/3.0.0/mock.md) - [SocketIOWrapperClient](/api/3.0.0/mock/class/SocketIOWrapperClient.md) - [close](/api/3.0.0/mock/function/close.md) - [create](/api/3.0.0/mock/function/create.md) - [createApp](/api/3.0.0/mock/function/createApp.md) - [createBootstrap](/api/3.0.0/mock/function/createBootstrap.md) - [createFunctionApp](/api/3.0.0/mock/function/createFunctionApp.md) - [createHttpRequest](/api/3.0.0/mock/function/createHttpRequest.md) - [createKafkaProducer](/api/3.0.0/mock/function/createKafkaProducer.md) - [createLightApp](/api/3.0.0/mock/function/createLightApp.md) - [createRabbitMQProducer](/api/3.0.0/mock/function/createRabbitMQProducer.md) - [createSocketIOClient](/api/3.0.0/mock/function/createSocketIOClient.md) - [createWebSocketClient](/api/3.0.0/mock/function/createWebSocketClient.md) - [mockClassProperty](/api/3.0.0/mock/function/mockClassProperty.md) - [mockContext](/api/3.0.0/mock/function/mockContext.md) - [mockHeader](/api/3.0.0/mock/function/mockHeader.md) - [mockProperty](/api/3.0.0/mock/function/mockProperty.md) - [mockSession](/api/3.0.0/mock/function/mockSession.md) - [processArgsParser](/api/3.0.0/mock/function/processArgsParser.md) - [restoreAllMocks](/api/3.0.0/mock/function/restoreAllMocks.md) - [restoreMocks](/api/3.0.0/mock/function/restoreMocks.md) - [transformFrameworkToConfiguration](/api/3.0.0/mock/function/transformFrameworkToConfiguration.md) - [MidwaySocketIOClientOptions](/api/3.0.0/mock/interface/MidwaySocketIOClientOptions.md) #### mongoose - [@midwayjs/mongoose](/api/3.0.0/mongoose.md) - [Configuration](/api/3.0.0/mongoose/class/Configuration.md) - [MongooseConnectionService](/api/3.0.0/mongoose/class/MongooseConnectionService.md) - [MongooseConnectionServiceFactory](/api/3.0.0/mongoose/class/MongooseConnectionServiceFactory.md) - [MongooseDataSourceManager](/api/3.0.0/mongoose/class/MongooseDataSourceManager.md) #### otel - [@midwayjs/otel](/api/3.0.0/otel.md) - [Configuration](/api/3.0.0/otel/class/Configuration.md) - [TraceService](/api/3.0.0/otel/class/TraceService.md) - [Trace](/api/3.0.0/otel/function/Trace.md) #### passport - [@midwayjs/passport](/api/3.0.0/passport.md) - [abstractAbstractPassportMiddleware](/api/3.0.0/passport/class/AbstractPassportMiddleware.md) - [Configuration](/api/3.0.0/passport/class/Configuration.md) - [PassportAuthenticator](/api/3.0.0/passport/class/PassportAuthenticator.md) - [CustomStrategy](/api/3.0.0/passport/function/CustomStrategy.md) - [PassportMiddleware](/api/3.0.0/passport/function/PassportMiddleware.md) - [PassportStrategy](/api/3.0.0/passport/function/PassportStrategy.md) - [AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md) - [IPassportMiddleware](/api/3.0.0/passport/interface/IPassportMiddleware.md) - [IPassportStrategy](/api/3.0.0/passport/interface/IPassportStrategy.md) - [StrategyCreatedStatic](/api/3.0.0/passport/interface/StrategyCreatedStatic.md) #### processAgent - [@midwayjs/process-agent](/api/3.0.0/processAgent.md) - [Configuration](/api/3.0.0/processAgent/class/Configuration.md) - [RunInPrimary](/api/3.0.0/processAgent/function/RunInPrimary.md) #### prometheus - [@midwayjs/prometheus](/api/3.0.0/prometheus.md) - [Configuration](/api/3.0.0/prometheus/class/Configuration.md) - [DataService](/api/3.0.0/prometheus/class/DataService.md) #### prometheus-socket-io - [@midwayjs/prometheus-socket-io](/api/3.0.0/prometheus-socket-io.md) - [Configuration](/api/3.0.0/prometheus-socket-io/class/Configuration.md) #### rabbitmq - [@midwayjs/rabbitmq](/api/3.0.0/rabbitmq.md) - [Configuration](/api/3.0.0/rabbitmq/class/Configuration.md) - [Framework](/api/3.0.0/rabbitmq/class/Framework.md) - [Context](/api/3.0.0/rabbitmq/interface/Context.md) - [IMidwayRabbitMQConfigurationOptions](/api/3.0.0/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) - [IRabbitMQApplication](/api/3.0.0/rabbitmq/interface/IRabbitMQApplication.md) - [IRabbitMQExchange](/api/3.0.0/rabbitmq/interface/IRabbitMQExchange.md) #### redis - [@midwayjs/redis](/api/3.0.0/redis.md) - [Configuration](/api/3.0.0/redis/class/Configuration.md) - [RedisService](/api/3.0.0/redis/class/RedisService.md) - [RedisServiceFactory](/api/3.0.0/redis/class/RedisServiceFactory.md) #### security - [@midwayjs/security](/api/3.0.0/security.md) - [Configuration](/api/3.0.0/security/class/Configuration.md) - [CSPMiddleware](/api/3.0.0/security/class/CSPMiddleware.md) - [CsrfMiddleware](/api/3.0.0/security/class/CsrfMiddleware.md) - [HSTSMiddleware](/api/3.0.0/security/class/HSTSMiddleware.md) - [NoOpenMiddleware](/api/3.0.0/security/class/NoOpenMiddleware.md) - [NoSniffMiddleware](/api/3.0.0/security/class/NoSniffMiddleware.md) - [SecurityHelper](/api/3.0.0/security/class/SecurityHelper.md) - [XFrameMiddleware](/api/3.0.0/security/class/XFrameMiddleware.md) - [XSSProtectionMiddleware](/api/3.0.0/security/class/XSSProtectionMiddleware.md) - [SecurityCSPOptions](/api/3.0.0/security/interface/SecurityCSPOptions.md) - [SecurityCSRFOptions](/api/3.0.0/security/interface/SecurityCSRFOptions.md) - [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) - [SecurityHSTSOptions](/api/3.0.0/security/interface/SecurityHSTSOptions.md) - [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) - [SecurityXFrameOptions](/api/3.0.0/security/interface/SecurityXFrameOptions.md) - [SecurityXSSProtectionOptions](/api/3.0.0/security/interface/SecurityXSSProtectionOptions.md) #### sequelize - [@midwayjs/sequelize](/api/3.0.0/sequelize.md) - [Configuration](/api/3.0.0/sequelize/class/Configuration.md) - [SequelizeDataSourceManager](/api/3.0.0/sequelize/class/SequelizeDataSourceManager.md) - [BaseTable](/api/3.0.0/sequelize/function/BaseTable.md) - [InjectDataSource](/api/3.0.0/sequelize/function/InjectDataSource.md) - [InjectRepository](/api/3.0.0/sequelize/function/InjectRepository.md) #### session - [@midwayjs/session](/api/3.0.0/session.md) - [Configuration](/api/3.0.0/session/class/Configuration.md) - [SessionMiddleware](/api/3.0.0/session/class/SessionMiddleware.md) - [abstractSessionStore](/api/3.0.0/session/class/SessionStore.md) - [SessionStoreManager](/api/3.0.0/session/class/SessionStoreManager.md) - [ISession](/api/3.0.0/session/interface/ISession.md) - [SessionOptions](/api/3.0.0/session/interface/SessionOptions.md) #### socketio - [@midwayjs/socketio](/api/3.0.0/socketio.md) - [Configuration](/api/3.0.0/socketio/class/Configuration.md) - [Framework](/api/3.0.0/socketio/class/Framework.md) - [createRedisAdapter](/api/3.0.0/socketio/function/createRedisAdapter.md) #### static-file - [@midwayjs/static-file](/api/3.0.0/static-file.md) - [Configuration](/api/3.0.0/static-file/class/Configuration.md) - [DirectoryNotFoundError](/api/3.0.0/static-file/class/DirectoryNotFoundError.md) - [StaticMiddleware](/api/3.0.0/static-file/class/StaticMiddleware.md) - [StaticFileOption](/api/3.0.0/static-file/interface/StaticFileOption.md) - [StaticFileOptions](/api/3.0.0/static-file/interface/StaticFileOptions.md) #### swagger - [@midwayjs/swagger](/api/3.0.0/swagger.md) - [Configuration](/api/3.0.0/swagger/class/Configuration.md) - [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md) - [SwaggerMiddleware](/api/3.0.0/swagger/class/SwaggerMiddleware.md) - [BodyContentType](/api/3.0.0/swagger/enum/BodyContentType.md) - [ApiAcceptedResponse](/api/3.0.0/swagger/function/ApiAcceptedResponse.md) - [ApiBadGatewayResponse](/api/3.0.0/swagger/function/ApiBadGatewayResponse.md) - [ApiBadRequestResponse](/api/3.0.0/swagger/function/ApiBadRequestResponse.md) - [ApiBasicAuth](/api/3.0.0/swagger/function/ApiBasicAuth.md) - [ApiBearerAuth](/api/3.0.0/swagger/function/ApiBearerAuth.md) - [ApiBody](/api/3.0.0/swagger/function/ApiBody.md) - [ApiConflictResponse](/api/3.0.0/swagger/function/ApiConflictResponse.md) - [ApiCookieAuth](/api/3.0.0/swagger/function/ApiCookieAuth.md) - [ApiCreatedResponse](/api/3.0.0/swagger/function/ApiCreatedResponse.md) - [ApiDefaultResponse](/api/3.0.0/swagger/function/ApiDefaultResponse.md) - [ApiExcludeController](/api/3.0.0/swagger/function/ApiExcludeController.md) - [ApiExcludeEndpoint](/api/3.0.0/swagger/function/ApiExcludeEndpoint.md) - [ApiExcludeSecurity](/api/3.0.0/swagger/function/ApiExcludeSecurity.md) - [ApiExtension](/api/3.0.0/swagger/function/ApiExtension.md) - [ApiExtraModel](/api/3.0.0/swagger/function/ApiExtraModel.md) - [ApiForbiddenResponse](/api/3.0.0/swagger/function/ApiForbiddenResponse.md) - [ApiFoundResponse](/api/3.0.0/swagger/function/ApiFoundResponse.md) - [ApiGatewayTimeoutResponse](/api/3.0.0/swagger/function/ApiGatewayTimeoutResponse.md) - [ApiGoneResponse](/api/3.0.0/swagger/function/ApiGoneResponse.md) - [ApiHeader](/api/3.0.0/swagger/function/ApiHeader.md) - [ApiHeaders](/api/3.0.0/swagger/function/ApiHeaders.md) - [ApiInternalServerErrorResponse](/api/3.0.0/swagger/function/ApiInternalServerErrorResponse.md) - [ApiMethodNotAllowedResponse](/api/3.0.0/swagger/function/ApiMethodNotAllowedResponse.md) - [ApiMovedPermanentlyResponse](/api/3.0.0/swagger/function/ApiMovedPermanentlyResponse.md) - [ApiNoContentResponse](/api/3.0.0/swagger/function/ApiNoContentResponse.md) - [ApiNotAcceptableResponse](/api/3.0.0/swagger/function/ApiNotAcceptableResponse.md) - [ApiNotFoundResponse](/api/3.0.0/swagger/function/ApiNotFoundResponse.md) - [ApiNotImplementedResponse](/api/3.0.0/swagger/function/ApiNotImplementedResponse.md) - [ApiOAuth2](/api/3.0.0/swagger/function/ApiOAuth2.md) - [ApiOkResponse](/api/3.0.0/swagger/function/ApiOkResponse.md) - [ApiOperation](/api/3.0.0/swagger/function/ApiOperation.md) - [ApiParam](/api/3.0.0/swagger/function/ApiParam.md) - [ApiPayloadTooLargeResponse](/api/3.0.0/swagger/function/ApiPayloadTooLargeResponse.md) - [ApiPreconditionFailedResponse](/api/3.0.0/swagger/function/ApiPreconditionFailedResponse.md) - [ApiProperty](/api/3.0.0/swagger/function/ApiProperty.md) - [ApiPropertyOptional](/api/3.0.0/swagger/function/ApiPropertyOptional.md) - [ApiQuery](/api/3.0.0/swagger/function/ApiQuery.md) - [ApiRequestTimeoutResponse](/api/3.0.0/swagger/function/ApiRequestTimeoutResponse.md) - [ApiResponse](/api/3.0.0/swagger/function/ApiResponse.md) - [ApiResponseProperty](/api/3.0.0/swagger/function/ApiResponseProperty.md) - [ApiSecurity](/api/3.0.0/swagger/function/ApiSecurity.md) - [ApiServiceUnavailableResponse](/api/3.0.0/swagger/function/ApiServiceUnavailableResponse.md) - [ApiTags](/api/3.0.0/swagger/function/ApiTags.md) - [ApiTooManyRequestsResponse](/api/3.0.0/swagger/function/ApiTooManyRequestsResponse.md) - [ApiUnauthorizedResponse](/api/3.0.0/swagger/function/ApiUnauthorizedResponse.md) - [ApiUnprocessableEntityResponse](/api/3.0.0/swagger/function/ApiUnprocessableEntityResponse.md) - [ApiUnsupportedMediaTypeResponse](/api/3.0.0/swagger/function/ApiUnsupportedMediaTypeResponse.md) - [getSchemaPath](/api/3.0.0/swagger/function/getSchemaPath.md) - [renderJSON](/api/3.0.0/swagger/function/renderJSON.md) - [renderSwaggerUIDist](/api/3.0.0/swagger/function/renderSwaggerUIDist.md) - [renderSwaggerUIRemote](/api/3.0.0/swagger/function/renderSwaggerUIRemote.md) - [ApiHeaderOptions](/api/3.0.0/swagger/interface/ApiHeaderOptions.md) - [ApiPropertyOptions](/api/3.0.0/swagger/interface/ApiPropertyOptions.md) - [ApiResponseMetadata](/api/3.0.0/swagger/interface/ApiResponseMetadata.md) - [ApiResponseSchemaHost](/api/3.0.0/swagger/interface/ApiResponseSchemaHost.md) - [AuthOptions](/api/3.0.0/swagger/interface/AuthOptions.md): 继承自 https://swagger.io/specification/#security-scheme-object - [BaseParameterObject](/api/3.0.0/swagger/interface/BaseParameterObject.md) - [ComponentsObject](/api/3.0.0/swagger/interface/ComponentsObject.md) - [ContactObject](/api/3.0.0/swagger/interface/ContactObject.md) - [DiscriminatorObject](/api/3.0.0/swagger/interface/DiscriminatorObject.md) - [EncodingPropertyObject](/api/3.0.0/swagger/interface/EncodingPropertyObject.md) - [ExampleObject](/api/3.0.0/swagger/interface/ExampleObject.md) - [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) - [InfoObject](/api/3.0.0/swagger/interface/InfoObject.md) - [LicenseObject](/api/3.0.0/swagger/interface/LicenseObject.md) - [LinkObject](/api/3.0.0/swagger/interface/LinkObject.md) - [MediaTypeObject](/api/3.0.0/swagger/interface/MediaTypeObject.md) - [MixDecoratorMetadata](/api/3.0.0/swagger/interface/MixDecoratorMetadata.md) - [OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) - [OAuthFlowsObject](/api/3.0.0/swagger/interface/OAuthFlowsObject.md) - [OpenAPIObject](/api/3.0.0/swagger/interface/OpenAPIObject.md) - [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) - [ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md) - [PathItemObject](/api/3.0.0/swagger/interface/PathItemObject.md) - [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) - [RequestBodyObject](/api/3.0.0/swagger/interface/RequestBodyObject.md) - [ResponseObject](/api/3.0.0/swagger/interface/ResponseObject.md) - [ResponsesObject](/api/3.0.0/swagger/interface/ResponsesObject.md) - [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) - [SchemaObjectMetadata](/api/3.0.0/swagger/interface/SchemaObjectMetadata.md) - [SecuritySchemeObject](/api/3.0.0/swagger/interface/SecuritySchemeObject.md) - [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md) - [ServerVariableObject](/api/3.0.0/swagger/interface/ServerVariableObject.md) - [SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md): see https://swagger.io/specification/ - [TagObject](/api/3.0.0/swagger/interface/TagObject.md) - [Type ](/api/3.0.0/swagger/interface/Type.md) - [XmlObject](/api/3.0.0/swagger/interface/XmlObject.md) #### tablestore - [@midwayjs/tablestore](/api/3.0.0/tablestore.md) - [CompositeCondition](/api/3.0.0/tablestore/class/CompositeCondition.md) - [Condition](/api/3.0.0/tablestore/class/Condition.md) - [Configuration](/api/3.0.0/tablestore/class/Configuration.md) - [SingleColumnCondition ](/api/3.0.0/tablestore/class/SingleColumnCondition.md) - [TableStoreService](/api/3.0.0/tablestore/class/TableStoreService.md) - [TableStoreServiceFactory](/api/3.0.0/tablestore/class/TableStoreServiceFactory.md) - [ColumnConditionType](/api/3.0.0/tablestore/enum/ColumnConditionType.md) - [ColumnReturnType](/api/3.0.0/tablestore/enum/ColumnReturnType.md) - [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md) - [DefinedColumnType](/api/3.0.0/tablestore/enum/DefinedColumnType.md) - [Direction](/api/3.0.0/tablestore/enum/Direction.md) - [FieldType](/api/3.0.0/tablestore/enum/FieldType.md) - [FilterType](/api/3.0.0/tablestore/enum/FilterType.md) - [GeoDistanceType](/api/3.0.0/tablestore/enum/GeoDistanceType.md) - [IndexOptions](/api/3.0.0/tablestore/enum/IndexOptions.md) - [IndexType](/api/3.0.0/tablestore/enum/IndexType.md) - [IndexUpdateMode](/api/3.0.0/tablestore/enum/IndexUpdateMode.md) - [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md) - [PrimaryKeyOption](/api/3.0.0/tablestore/enum/PrimaryKeyOption.md) - [PrimaryKeyType](/api/3.0.0/tablestore/enum/PrimaryKeyType.md) - [QueryOperator](/api/3.0.0/tablestore/enum/QueryOperator.md) - [QueryType](/api/3.0.0/tablestore/enum/QueryType.md): search - [ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) - [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md): metadata - [ScoreMode](/api/3.0.0/tablestore/enum/ScoreMode.md) - [SortMode](/api/3.0.0/tablestore/enum/SortMode.md) - [SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md) - [UpdateType](/api/3.0.0/tablestore/enum/UpdateType.md) - [formatRow](/api/3.0.0/tablestore/function/formatRow.md) - [formatRows](/api/3.0.0/tablestore/function/formatRows.md) - [BatchGetRowParams](/api/3.0.0/tablestore/interface/BatchGetRowParams.md) - [BatchWriteRowParams](/api/3.0.0/tablestore/interface/BatchWriteRowParams.md) - [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) - [CreateIndexParams](/api/3.0.0/tablestore/interface/CreateIndexParams.md) - [CreateSearchIndexParams](/api/3.0.0/tablestore/interface/CreateSearchIndexParams.md) - [CreateTableParams](/api/3.0.0/tablestore/interface/CreateTableParams.md): params - [DeleteRowParams](/api/3.0.0/tablestore/interface/DeleteRowParams.md) - [DeleteSearchIndexParams](/api/3.0.0/tablestore/interface/DeleteSearchIndexParams.md) - [DeleteTableParams](/api/3.0.0/tablestore/interface/DeleteTableParams.md) - [DescribeSearchIndexParams](/api/3.0.0/tablestore/interface/DescribeSearchIndexParams.md) - [DescribeTableParams](/api/3.0.0/tablestore/interface/DescribeTableParams.md) - [DropIndexParams](/api/3.0.0/tablestore/interface/DropIndexParams.md) - [GetRangeParams](/api/3.0.0/tablestore/interface/GetRangeParams.md) - [GetRowParams](/api/3.0.0/tablestore/interface/GetRowParams.md) - [ListSearchIndexParams](/api/3.0.0/tablestore/interface/ListSearchIndexParams.md) - [PutRowParams](/api/3.0.0/tablestore/interface/PutRowParams.md) - [SearchIndexFieldSchema](/api/3.0.0/tablestore/interface/SearchIndexFieldSchema.md) - [SearchIndexNestedFilter](/api/3.0.0/tablestore/interface/SearchIndexNestedFilter.md) - [SearchIndexSchema](/api/3.0.0/tablestore/interface/SearchIndexSchema.md) - [SearchIndexSetting](/api/3.0.0/tablestore/interface/SearchIndexSetting.md) - [SearchIndexSorter](/api/3.0.0/tablestore/interface/SearchIndexSorter.md) - [SearchParams](/api/3.0.0/tablestore/interface/SearchParams.md) - [SearchQuery](/api/3.0.0/tablestore/interface/SearchQuery.md) - [StartLocalTransactionParams](/api/3.0.0/tablestore/interface/StartLocalTransactionParams.md) - [TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md) - [TableStoreCompositeCondition](/api/3.0.0/tablestore/interface/TableStoreCompositeCondition.md) - [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) - [TableStoreConfig](/api/3.0.0/tablestore/interface/TableStoreConfig.md) - [TableStoreLong](/api/3.0.0/tablestore/interface/TableStoreLong.md) - [TableStoreResult](/api/3.0.0/tablestore/interface/TableStoreResult.md) - [TableStoreSingleColumnCondition ](/api/3.0.0/tablestore/interface/TableStoreSingleColumnCondition.md) - [UpdateRowParams](/api/3.0.0/tablestore/interface/UpdateRowParams.md) - [UpdateTableParams](/api/3.0.0/tablestore/interface/UpdateTableParams.md) #### tags - [@midwayjs/tags](/api/3.0.0/tags.md) - [Configuration](/api/3.0.0/tags/class/Configuration.md) - [abstractITagDialect](/api/3.0.0/tags/class/ITagDialect.md) - [abstractITagDialectInstance](/api/3.0.0/tags/class/ITagDialectInstance.md) - [TagClient](/api/3.0.0/tags/class/TagClient.md) - [TagServiceFactory](/api/3.0.0/tags/class/TagServiceFactory.md) - [MATCH_TYPE](/api/3.0.0/tags/enum/MATCH_TYPE.md) - [TAG_ERROR](/api/3.0.0/tags/enum/TAG_ERROR.md) - [ITagBindOptions](/api/3.0.0/tags/interface/ITagBindOptions.md) - [ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md) - [ITagInstance](/api/3.0.0/tags/interface/ITagInstance.md) - [ITagItem](/api/3.0.0/tags/interface/ITagItem.md) - [ITagListInstanceOptions](/api/3.0.0/tags/interface/ITagListInstanceOptions.md) - [ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md) - [ITagListResult ](/api/3.0.0/tags/interface/ITagListResult.md) - [ITagMysqlDialectOption](/api/3.0.0/tags/interface/ITagMysqlDialectOption.md) - [ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md) - [ITagPages](/api/3.0.0/tags/interface/ITagPages.md) - [ITagSearchOptions](/api/3.0.0/tags/interface/ITagSearchOptions.md) - [ITagServiceInitOptions](/api/3.0.0/tags/interface/ITagServiceInitOptions.md) - [ITagUnBindOptions](/api/3.0.0/tags/interface/ITagUnBindOptions.md) - [ITagUserDialect](/api/3.0.0/tags/interface/ITagUserDialect.md) #### typegoose - [@midwayjs/typegoose](/api/3.0.0/typegoose.md) - [Configuration](/api/3.0.0/typegoose/class/Configuration.md) - [EntityModel](/api/3.0.0/typegoose/function/EntityModel.md) - [InjectEntityModel](/api/3.0.0/typegoose/function/InjectEntityModel.md) #### typeorm - [@midwayjs/typeorm](/api/3.0.0/typeorm.md) - [Configuration](/api/3.0.0/typeorm/class/Configuration.md) - [TypeORMDataSourceManager](/api/3.0.0/typeorm/class/TypeORMDataSourceManager.md) - [EventSubscriberModel](/api/3.0.0/typeorm/function/EventSubscriberModel.md) - [InjectDataSource](/api/3.0.0/typeorm/function/InjectDataSource.md) - [InjectEntityModel](/api/3.0.0/typeorm/function/InjectEntityModel.md) #### upload - [@midwayjs/upload](/api/3.0.0/upload.md) - [Configuration](/api/3.0.0/upload/class/Configuration.md) - [MultipartInvalidFilenameError](/api/3.0.0/upload/class/MultipartInvalidFilenameError.md) - [MultipartInvalidFileTypeError](/api/3.0.0/upload/class/MultipartInvalidFileTypeError.md) - [UploadMiddleware](/api/3.0.0/upload/class/UploadMiddleware.md) - [UploadFileInfo ](/api/3.0.0/upload/interface/UploadFileInfo.md) - [UploadOptions](/api/3.0.0/upload/interface/UploadOptions.md) #### validate - [@midwayjs/validate](/api/3.0.0/validate.md) - [abstractAbstractValidationPipe](/api/3.0.0/validate/class/AbstractValidationPipe.md) - [Configuration](/api/3.0.0/validate/class/Configuration.md) - [DecoratorValidPipe](/api/3.0.0/validate/class/DecoratorValidPipe.md) - [DefaultValuePipe ](/api/3.0.0/validate/class/DefaultValuePipe.md) - [MidwayValidationError](/api/3.0.0/validate/class/MidwayValidationError.md) - [ParseBoolPipe](/api/3.0.0/validate/class/ParseBoolPipe.md) - [ParseFloatPipe](/api/3.0.0/validate/class/ParseFloatPipe.md) - [ParseIntPipe](/api/3.0.0/validate/class/ParseIntPipe.md) - [abstractParsePipe](/api/3.0.0/validate/class/ParsePipe.md) - [ValidateService](/api/3.0.0/validate/class/ValidateService.md) - [ValidationPipe](/api/3.0.0/validate/class/ValidationPipe.md) - [getSchema](/api/3.0.0/validate/function/getSchema.md) - [OmitDto](/api/3.0.0/validate/function/OmitDto.md) - [PickDto](/api/3.0.0/validate/function/PickDto.md) - [Rule](/api/3.0.0/validate/function/Rule.md) - [Valid](/api/3.0.0/validate/function/Valid.md) - [Validate](/api/3.0.0/validate/function/Validate.md) - [Dto ](/api/3.0.0/validate/interface/Dto.md) - [RuleOptions](/api/3.0.0/validate/interface/RuleOptions.md) - [ValidateOptions](/api/3.0.0/validate/interface/ValidateOptions.md) #### view - [@midwayjs/view](/api/3.0.0/view.md) - [Configuration](/api/3.0.0/view/class/Configuration.md) - [ContextView](/api/3.0.0/view/class/ContextView.md): View instance for each request. It will find the view engine, and render it. The view engine should be registered in {@link ViewManager}. - [ViewManager](/api/3.0.0/view/class/ViewManager.md) - [IViewEngine](/api/3.0.0/view/interface/IViewEngine.md) - [RenderOptions](/api/3.0.0/view/interface/RenderOptions.md) #### view-ejs - [@midwayjs/view-ejs](/api/3.0.0/view-ejs.md) - [Configuration](/api/3.0.0/view-ejs/class/Configuration.md) - [EjsView](/api/3.0.0/view-ejs/class/EjsView.md) #### view-nunjucks - [@midwayjs/view-nunjucks](/api/3.0.0/view-nunjucks.md) - [Configuration](/api/3.0.0/view-nunjucks/class/Configuration.md) - [NunjucksEnvironment](/api/3.0.0/view-nunjucks/class/NunjucksEnvironment.md) - [NunjucksView](/api/3.0.0/view-nunjucks/class/NunjucksView.md) #### web - [@midwayjs/web](/api/3.0.0/web.md) - [Agent](/api/3.0.0/web/class/Agent.md) - [Application](/api/3.0.0/web/class/Application.md) - [Configuration](/api/3.0.0/web/class/Configuration.md) - [Framework](/api/3.0.0/web/class/Framework.md) - [AgentApp](/api/3.0.0/web/function/AgentApp.md) - [createAgentWorkerLoader](/api/3.0.0/web/function/createAgentWorkerLoader.md) - [createAppWorkerLoader](/api/3.0.0/web/function/createAppWorkerLoader.md) - [createEggAgent](/api/3.0.0/web/function/createEggAgent.md) - [createEggApplication](/api/3.0.0/web/function/createEggApplication.md) - [RunInEggAgent](/api/3.0.0/web/function/RunInEggAgent.md) - [startCluster](/api/3.0.0/web/function/startCluster.md) - [Context ](/api/3.0.0/web/interface/Context.md) - [IMidwayWebBaseApplication](/api/3.0.0/web/interface/IMidwayWebBaseApplication.md) - [IMidwayWebConfigurationOptions](/api/3.0.0/web/interface/IMidwayWebConfigurationOptions.md) - [IWebMiddleware](/api/3.0.0/web/interface/IWebMiddleware.md) - [State](/api/3.0.0/web/interface/State.md) #### web-express - [@midwayjs/express](/api/3.0.0/web-express.md) - [Configuration](/api/3.0.0/web-express/class/Configuration.md) - [Framework](/api/3.0.0/web-express/class/Framework.md) - [MidwayExpressMiddlewareService](/api/3.0.0/web-express/class/MidwayExpressMiddlewareService.md) - [wrapAsyncHandler](/api/3.0.0/web-express/function/wrapAsyncHandler.md) - [wrapMiddleware](/api/3.0.0/web-express/function/wrapMiddleware.md) - [Context](/api/3.0.0/web-express/interface/Context.md) - [IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md) - [IMidwayExpressConfigurationOptions](/api/3.0.0/web-express/interface/IMidwayExpressConfigurationOptions.md) #### web-koa - [@midwayjs/koa](/api/3.0.0/web-koa.md) - [BodyParserMiddleware](/api/3.0.0/web-koa/class/BodyParserMiddleware.md) - [Configuration](/api/3.0.0/web-koa/class/Configuration.md) - [Framework](/api/3.0.0/web-koa/class/Framework.md) - [SiteFileMiddleware](/api/3.0.0/web-koa/class/SiteFileMiddleware.md) - [BodyParserOptions](/api/3.0.0/web-koa/interface/BodyParserOptions.md) - [Context](/api/3.0.0/web-koa/interface/Context.md) - [IMidwayKoaConfigurationOptions](/api/3.0.0/web-koa/interface/IMidwayKoaConfigurationOptions.md) - [IWebMiddleware](/api/3.0.0/web-koa/interface/IWebMiddleware.md) - [State](/api/3.0.0/web-koa/interface/State.md) #### ws - [@midwayjs/ws](/api/3.0.0/ws.md) - [Configuration](/api/3.0.0/ws/class/Configuration.md) - [Framework](/api/3.0.0/ws/class/Framework.md) - [Context](/api/3.0.0/ws/interface/Context.md) ### axios - [@midwayjs/axios](/api/axios.md) #### class - [Configuration](/api/axios/class/Configuration.md) - [HttpService](/api/axios/class/HttpService.md) - [HttpServiceFactory](/api/axios/class/HttpServiceFactory.md) #### interface - [AxiosRequestConfig ](/api/axios/interface/AxiosRequestConfig.md): Interface for custom axios request config merging. - [AxiosResponse ](/api/axios/interface/AxiosResponse.md) ### bootstrap - [@midwayjs/bootstrap](/api/bootstrap.md) #### class - [abstractAbstractForkManager ](/api/bootstrap/class/AbstractForkManager.md) - [Bootstrap](/api/bootstrap/class/Bootstrap.md) - [BootstrapStarter](/api/bootstrap/class/BootstrapStarter.md) - [ClusterManager](/api/bootstrap/class/ClusterManager.md) #### function - [setupStickyMaster](/api/bootstrap/function/setupStickyMaster.md) #### interface - [ForkOptions](/api/bootstrap/interface/ForkOptions.md) - [IForkManager ](/api/bootstrap/interface/IForkManager.md) ### bull - [@midwayjs/bull](/api/bull.md) #### class - [BullQueue](/api/bull/class/BullQueue.md) - [Configuration](/api/bull/class/Configuration.md) - [Framework](/api/bull/class/Framework.md) #### function - [InjectQueue](/api/bull/function/InjectQueue.md) - [Processor](/api/bull/function/Processor.md) #### interface - [Application](/api/bull/interface/Application.md) - [Context](/api/bull/interface/Context.md) - [IProcessor](/api/bull/interface/IProcessor.md) - [IQueue ](/api/bull/interface/IQueue.md) - [IQueueManager ](/api/bull/interface/IQueueManager.md) ### bull-board - [@midwayjs/bull-board](/api/bull-board.md) #### class - [BoardMiddleware](/api/bull-board/class/BoardMiddleware.md) - [BullBoardManager](/api/bull-board/class/BullBoardManager.md) - [Configuration](/api/bull-board/class/Configuration.md) - [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) #### interface - [BullBoardOption](/api/bull-board/interface/BullBoardOption.md) ### bullmq - [@midwayjs/bullmq](/api/bullmq.md) #### class - [BullMQQueue](/api/bullmq/class/BullMQQueue.md) - [Configuration](/api/bullmq/class/Configuration.md) - [Framework](/api/bullmq/class/Framework.md) #### function - [InjectFlowProducer](/api/bullmq/function/InjectFlowProducer.md) - [InjectQueue](/api/bullmq/function/InjectQueue.md) - [InjectWorker](/api/bullmq/function/InjectWorker.md) - [Processor](/api/bullmq/function/Processor.md) #### interface - [Application](/api/bullmq/interface/Application.md) - [BullMQConfig](/api/bullmq/interface/BullMQConfig.md) - [Context](/api/bullmq/interface/Context.md) - [IProcessor](/api/bullmq/interface/IProcessor.md) ### busboy - [@midwayjs/busboy](/api/busboy.md) #### class - [Configuration](/api/busboy/class/Configuration.md) - [MultipartError](/api/busboy/class/MultipartError.md) - [MultipartFieldsLimitError](/api/busboy/class/MultipartFieldsLimitError.md) - [MultipartFileLimitError](/api/busboy/class/MultipartFileLimitError.md) - [MultipartFileSizeLimitError](/api/busboy/class/MultipartFileSizeLimitError.md) - [MultipartInvalidFilenameError](/api/busboy/class/MultipartInvalidFilenameError.md) - [MultipartInvalidFileTypeError](/api/busboy/class/MultipartInvalidFileTypeError.md) - [MultipartPartsLimitError](/api/busboy/class/MultipartPartsLimitError.md) - [UploadMiddleware](/api/busboy/class/UploadMiddleware.md) #### interface - [UploadFileInfo](/api/busboy/interface/UploadFileInfo.md) - [UploadOptions](/api/busboy/interface/UploadOptions.md) - [UploadStreamFieldInfo](/api/busboy/interface/UploadStreamFieldInfo.md) - [UploadStreamFileInfo](/api/busboy/interface/UploadStreamFileInfo.md) ### cache-manager - [@midwayjs/cache-manager](/api/cache-manager.md) #### class - [CachingFactory](/api/cache-manager/class/CachingFactory.md) - [Configuration](/api/cache-manager/class/Configuration.md) #### function - [Caching](/api/cache-manager/function/Caching.md) - [createRedisStore](/api/cache-manager/function/createRedisStore.md) - [getClassMethodDefaultCacheKey](/api/cache-manager/function/getClassMethodDefaultCacheKey.md) #### interface - [RedisStore](/api/cache-manager/interface/RedisStore.md) #### namespace - [CacheManager](/api/cache-manager/namespace/CacheManager.md) ### captcha - [@midwayjs/captcha](/api/captcha.md) #### class - [CaptchaService](/api/captcha/class/CaptchaService.md) - [Configuration](/api/captcha/class/Configuration.md) #### interface - [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md) - [CaptchaOptions](/api/captcha/interface/CaptchaOptions.md) - [FormulaCaptchaOptions](/api/captcha/interface/FormulaCaptchaOptions.md) - [ImageCaptchaOptions](/api/captcha/interface/ImageCaptchaOptions.md) - [TextCaptchaOptions](/api/captcha/interface/TextCaptchaOptions.md) ### casbin - [@midwayjs/casbin](/api/casbin.md) #### class - [AuthGuard](/api/casbin/class/AuthGuard.md) - [abstractBaseAdapter ](/api/casbin/class/BaseAdapter.md) - [CasbinEnforcerService](/api/casbin/class/CasbinEnforcerService.md) - [Configuration](/api/casbin/class/Configuration.md) #### enum - [AuthAction](/api/casbin/enum/AuthAction.md) - [AuthActionVerb](/api/casbin/enum/AuthActionVerb.md) - [AuthPossession](/api/casbin/enum/AuthPossession.md) #### function - [UsePermission](/api/casbin/function/UsePermission.md) #### interface - [CasbinConfigOptions](/api/casbin/interface/CasbinConfigOptions.md) - [Permission](/api/casbin/interface/Permission.md) ### casbin-redis-adapter - [@midwayjs/casbin-redis-adapter](/api/casbin-redis-adapter.md) #### class - [abstractBaseWatcher ](/api/casbin-redis-adapter/class/BaseWatcher.md) - [NodeRedisAdapter](/api/casbin-redis-adapter/class/NodeRedisAdapter.md) - [NodeRedisWatcher](/api/casbin-redis-adapter/class/NodeRedisWatcher.md) #### function - [createAdapter](/api/casbin-redis-adapter/function/createAdapter.md) - [createWatcher](/api/casbin-redis-adapter/function/createWatcher.md) ### casbin-typeorm-adapter - [@midwayjs/casbin-typeorm-adapter](/api/casbin-typeorm-adapter.md) #### class - [CasbinMongoRule](/api/casbin-typeorm-adapter/class/CasbinMongoRule.md) - [CasbinRule](/api/casbin-typeorm-adapter/class/CasbinRule.md) - [TypeORMAdapter](/api/casbin-typeorm-adapter/class/TypeORMAdapter.md): TypeORMAdapter represents the TypeORM filtered adapter for policy storage. #### function - [createAdapter](/api/casbin-typeorm-adapter/function/createAdapter.md) ### code-dye - [@midwayjs/code-dye](/api/code-dye.md) #### class - [CodeDyeMW](/api/code-dye/class/CodeDyeMW.md) - [Configuration](/api/code-dye/class/Configuration.md) #### interface - [CodeDyeOptions](/api/code-dye/interface/CodeDyeOptions.md) ### consul - [@midwayjs/consul](/api/consul.md) #### class - [Configuration](/api/consul/class/Configuration.md) - [ConsulService](/api/consul/class/ConsulService.md) - [ConsulServiceDiscoverClient](/api/consul/class/ConsulServiceDiscoverClient.md): The adapter for consul service discovery - [ConsulServiceDiscovery](/api/consul/class/ConsulServiceDiscovery.md): The service discovery for consul - [ConsulServiceFactory](/api/consul/class/ConsulServiceFactory.md) #### interface - [ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md) - [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md) - [ConsulServiceDiscoveryOptions](/api/consul/interface/ConsulServiceDiscoveryOptions.md) ### core - [@midwayjs/core](/api/core.md) #### class - [abstractAbstractFileDetector ](/api/core/class/AbstractFileDetector.md) - [abstractBaseFramework ](/api/core/class/BaseFramework.md) - [CommonJSFileDetector](/api/core/class/CommonJSFileDetector.md): CommonJS module loader - [ContextMiddlewareManager ](/api/core/class/ContextMiddlewareManager.md) - [CustomModuleDetector](/api/core/class/CustomModuleDetector.md) - [abstractDataListener ](/api/core/class/DataListener.md) - [abstractDataSourceManager ](/api/core/class/DataSourceManager.md) - [DecoratorManager](/api/core/class/DecoratorManager.md): This class is used to manage the decorator data of the class - [DefaultConsoleLoggerFactory](/api/core/class/DefaultConsoleLoggerFactory.md) - [DynamicMidwayContainer](/api/core/class/DynamicMidwayContainer.md): 尝试用于开发时动态更新的 IoC 容器 - [ESModuleFileDetector](/api/core/class/ESModuleFileDetector.md): ES module loader - [FilterManager ](/api/core/class/FilterManager.md) - [HttpClient](/api/core/class/HttpClient.md): A simple http client - [HttpServerResponse ](/api/core/class/HttpServerResponse.md) - [LoadBalancerFactory](/api/core/class/LoadBalancerFactory.md): 负载均衡工厂 - [abstractLoggerFactory ](/api/core/class/LoggerFactory.md) - [MetadataManager](/api/core/class/MetadataManager.md): A class that manages metadata for classes and properties This class is a simplified version of the Reflect Metadata API Provides a way to retrieve, define, delete and copy metadata - [MidwayApplicationManager](/api/core/class/MidwayApplicationManager.md) - [MidwayAspectService](/api/core/class/MidwayAspectService.md) - [MidwayCodeInvokeTimeoutError](/api/core/class/MidwayCodeInvokeTimeoutError.md) - [MidwayCommonError](/api/core/class/MidwayCommonError.md) - [MidwayConfigMissingError](/api/core/class/MidwayConfigMissingError.md) - [MidwayConfigService](/api/core/class/MidwayConfigService.md) - [MidwayContainer](/api/core/class/MidwayContainer.md): Abstract Object Factory 对象容器抽象 - [MidwayDecoratorService](/api/core/class/MidwayDecoratorService.md) - [MidwayDefinitionNotFoundError](/api/core/class/MidwayDefinitionNotFoundError.md) - [MidwayDuplicateClassNameError](/api/core/class/MidwayDuplicateClassNameError.md) - [MidwayDuplicateControllerOptionsError](/api/core/class/MidwayDuplicateControllerOptionsError.md) - [MidwayDuplicateRouteError](/api/core/class/MidwayDuplicateRouteError.md) - [MidwayEmptyValueError](/api/core/class/MidwayEmptyValueError.md) - [MidwayEnvironmentService](/api/core/class/MidwayEnvironmentService.md) - [MidwayError](/api/core/class/MidwayError.md) - [MidwayFeatureNoLongerSupportedError](/api/core/class/MidwayFeatureNoLongerSupportedError.md) - [MidwayFeatureNotImplementedError](/api/core/class/MidwayFeatureNotImplementedError.md) - [MidwayFrameworkService](/api/core/class/MidwayFrameworkService.md) - [MidwayHealthService](/api/core/class/MidwayHealthService.md) - [MidwayHttpError](/api/core/class/MidwayHttpError.md) - [MidwayInconsistentVersionError](/api/core/class/MidwayInconsistentVersionError.md) - [MidwayInformationService](/api/core/class/MidwayInformationService.md) - [MidwayInvalidConfigError](/api/core/class/MidwayInvalidConfigError.md) - [MidwayInvalidConfigPropertyError](/api/core/class/MidwayInvalidConfigPropertyError.md) - [MidwayInvokeForbiddenError](/api/core/class/MidwayInvokeForbiddenError.md) - [MidwayLifeCycleService](/api/core/class/MidwayLifeCycleService.md) - [MidwayLoggerService](/api/core/class/MidwayLoggerService.md): 多客户端工厂实现 - [MidwayMainFrameworkMissingError](/api/core/class/MidwayMainFrameworkMissingError.md) - [MidwayMiddlewareService ](/api/core/class/MidwayMiddlewareService.md) - [MidwayMissingImportComponentError](/api/core/class/MidwayMissingImportComponentError.md) - [MidwayMockService](/api/core/class/MidwayMockService.md) - [MidwayParameterError](/api/core/class/MidwayParameterError.md) - [MidwayPerformanceManager](/api/core/class/MidwayPerformanceManager.md) - [MidwayPriorityManager](/api/core/class/MidwayPriorityManager.md) - [MidwayRequestContainer](/api/core/class/MidwayRequestContainer.md): Abstract Object Factory 对象容器抽象 - [MidwayRetryExceededMaxTimesError](/api/core/class/MidwayRetryExceededMaxTimesError.md) - [MidwayServerlessFunctionService](/api/core/class/MidwayServerlessFunctionService.md) - [MidwaySingletonInjectRequestError](/api/core/class/MidwaySingletonInjectRequestError.md) - [MidwayTraceService](/api/core/class/MidwayTraceService.md) - [MidwayUseWrongMethodError](/api/core/class/MidwayUseWrongMethodError.md) - [MidwayUtilHttpClientTimeoutError](/api/core/class/MidwayUtilHttpClientTimeoutError.md) - [MidwayWebRouterService](/api/core/class/MidwayWebRouterService.md) - [RandomLoadBalance ](/api/core/class/RandomLoadBalance.md): 随机负载均衡策略 - [RoundRobinLoadBalancer ](/api/core/class/RoundRobinLoadBalancer.md): 轮询负载均衡策略 - [ServerResponse ](/api/core/class/ServerResponse.md) - [abstractServiceDiscovery ](/api/core/class/ServiceDiscovery.md): 服务发现抽象类 - [abstractServiceDiscoveryClient ](/api/core/class/ServiceDiscoveryClient.md) - [abstractServiceFactory ](/api/core/class/ServiceFactory.md): 多客户端工厂实现 - [TypedResourceManager ](/api/core/class/TypedResourceManager.md) - [abstractWebControllerGenerator ](/api/core/class/WebControllerGenerator.md) #### enum - [GrpcStreamTypeEnum](/api/core/enum/GrpcStreamTypeEnum.md) - [HttpStatus](/api/core/enum/HttpStatus.md) - [InjectModeEnum](/api/core/enum/InjectModeEnum.md) - [MidwayProcessTypeEnum](/api/core/enum/MidwayProcessTypeEnum.md) - [MSListenerType](/api/core/enum/MSListenerType.md) - [MSProviderType](/api/core/enum/MSProviderType.md) - [ObjectLifeCycleEvent](/api/core/enum/ObjectLifeCycleEvent.md) - [RouteParamTypes](/api/core/enum/RouteParamTypes.md) - [ScopeEnum](/api/core/enum/ScopeEnum.md) - [ServerlessTriggerType](/api/core/enum/ServerlessTriggerType.md) - [WSEventTypeEnum](/api/core/enum/WSEventTypeEnum.md) #### function - [All](/api/core/function/All.md) - [AllConfig](/api/core/function/AllConfig.md) - [App](/api/core/function/App.md) - [ApplicationContext](/api/core/function/ApplicationContext.md) - [Aspect](/api/core/function/Aspect.md) - [attachClassMetadata](/api/core/function/attachClassMetadata.md) - [attachPropertyDataToClass](/api/core/function/attachPropertyDataToClass.md) - [attachPropertyMetadata](/api/core/function/attachPropertyMetadata.md) - [Autoload](/api/core/function/Autoload.md) - [Body](/api/core/function/Body.md) - [Catch](/api/core/function/Catch.md) - [clearAllModule](/api/core/function/clearAllModule.md) - [Config](/api/core/function/Config.md) - [Configuration](/api/core/function/Configuration.md) - [Consumer](/api/core/function/Consumer.md) - [ContentType](/api/core/function/ContentType.md) - [Controller](/api/core/function/Controller.md) - [createCustomMethodDecorator](/api/core/function/createCustomMethodDecorator.md) - [createCustomParamDecorator](/api/core/function/createCustomParamDecorator.md) - [createCustomPropertyDecorator](/api/core/function/createCustomPropertyDecorator.md) - [createMiddleware](/api/core/function/createMiddleware.md) - [createRender](/api/core/function/createRender.md) - [createRequestParamDecorator](/api/core/function/createRequestParamDecorator.md) - [Del](/api/core/function/Del.md) - [delegateTargetAllPrototypeMethod](/api/core/function/delegateTargetAllPrototypeMethod.md) - [delegateTargetMethod](/api/core/function/delegateTargetMethod.md) - [delegateTargetProperties](/api/core/function/delegateTargetProperties.md) - [delegateTargetPrototypeMethod](/api/core/function/delegateTargetPrototypeMethod.md) - [deprecatedOutput](/api/core/function/deprecatedOutput.md) - [Destroy](/api/core/function/Destroy.md) - [destroyGlobalApplicationContext](/api/core/function/destroyGlobalApplicationContext.md) - [DubboMethod](/api/core/function/DubboMethod.md) - [Emit](/api/core/function/Emit.md) - [extend](/api/core/function/extend.md) - [extractExpressLikeValue](/api/core/function/extractExpressLikeValue.md) - [extractKoaLikeValue](/api/core/function/extractKoaLikeValue.md) - [Fields](/api/core/function/Fields.md) - [File](/api/core/function/File.md) - [Files](/api/core/function/Files.md) - [Framework](/api/core/function/Framework.md) - [Get](/api/core/function/Get.md) - [getClassExtendedMetadata](/api/core/function/getClassExtendedMetadata.md) - [getClassMetadata](/api/core/function/getClassMetadata.md) - [getCurrentApplicationContext](/api/core/function/getCurrentApplicationContext.md) - [getCurrentAsyncContextManager](/api/core/function/getCurrentAsyncContextManager.md) - [getCurrentMainApp](/api/core/function/getCurrentMainApp.md) - [getCurrentMainFramework](/api/core/function/getCurrentMainFramework.md) - [getMethodParamTypes](/api/core/function/getMethodParamTypes.md) - [getObjectDefinition](/api/core/function/getObjectDefinition.md) - [getPropertyDataFromClass](/api/core/function/getPropertyDataFromClass.md) - [getPropertyInject](/api/core/function/getPropertyInject.md) - [getPropertyMetadata](/api/core/function/getPropertyMetadata.md) - [getPropertyType](/api/core/function/getPropertyType.md) - [getProviderId](/api/core/function/getProviderId.md) - [getProviderName](/api/core/function/getProviderName.md) - [getProviderUUId](/api/core/function/getProviderUUId.md) - [GrpcMethod](/api/core/function/GrpcMethod.md) - [Guard](/api/core/function/Guard.md) - [Head](/api/core/function/Head.md) - [Headers](/api/core/function/Headers.md) - [HttpCode](/api/core/function/HttpCode.md) - [Init](/api/core/function/Init.md) - [initializeGlobalApplicationContext](/api/core/function/initializeGlobalApplicationContext.md) - [Inject](/api/core/function/Inject.md) - [InjectClient](/api/core/function/InjectClient.md) - [isProvide](/api/core/function/isProvide.md) - [isTypeScriptEnvironment](/api/core/function/isTypeScriptEnvironment.md) - [KafkaListener](/api/core/function/KafkaListener.md) - [LazyInject](/api/core/function/LazyInject.md) - [listModule](/api/core/function/listModule.md) - [listPreloadModule](/api/core/function/listPreloadModule.md) - [listPropertyDataFromClass](/api/core/function/listPropertyDataFromClass.md) - [loadModule](/api/core/function/loadModule.md) - [Logger](/api/core/function/Logger.md) - [MainApp](/api/core/function/MainApp.md) - [makeHttpRequest](/api/core/function/makeHttpRequest.md) - [Match](/api/core/function/Match.md) - [Middleware](/api/core/function/Middleware.md) - [Mock](/api/core/function/Mock.md) - [OnConnection](/api/core/function/OnConnection.md) - [OnDisConnection](/api/core/function/OnDisConnection.md) - [OnMessage](/api/core/function/OnMessage.md) - [OnWSConnection](/api/core/function/OnWSConnection.md) - [OnWSDisConnection](/api/core/function/OnWSDisConnection.md) - [OnWSMessage](/api/core/function/OnWSMessage.md) - [Options](/api/core/function/Options.md) - [Param](/api/core/function/Param.md) - [Patch](/api/core/function/Patch.md) - [pathMatching](/api/core/function/pathMatching.md) - [Pipe](/api/core/function/Pipe.md) - [Plugin](/api/core/function/Plugin.md) - [Post](/api/core/function/Post.md) - [prepareGlobalApplicationContext](/api/core/function/prepareGlobalApplicationContext.md) - [prepareGlobalApplicationContextAsync](/api/core/function/prepareGlobalApplicationContextAsync.md) - [Provide](/api/core/function/Provide.md) - [Provider](/api/core/function/Provider.md) - [providerWrapper](/api/core/function/providerWrapper.md) - [Put](/api/core/function/Put.md) - [Queries](/api/core/function/Queries.md) - [Query](/api/core/function/Query.md) - [Queue](/api/core/function/Queue.md) - [RabbitMQListener](/api/core/function/RabbitMQListener.md) - [Redirect](/api/core/function/Redirect.md) - [registerErrorCode](/api/core/function/registerErrorCode.md) - [RequestIP](/api/core/function/RequestIP.md) - [RequestMapping](/api/core/function/RequestMapping.md) - [RequestPath](/api/core/function/RequestPath.md) - [resetModule](/api/core/function/resetModule.md) - [retryWith](/api/core/function/retryWith.md) - [retryWithAsync](/api/core/function/retryWithAsync.md) - [safelyGet](/api/core/function/safelyGet.md) - [safeRequire](/api/core/function/safeRequire.md) - [saveClassMetadata](/api/core/function/saveClassMetadata.md) - [saveModule](/api/core/function/saveModule.md) - [saveObjectDefinition](/api/core/function/saveObjectDefinition.md) - [savePreloadModule](/api/core/function/savePreloadModule.md) - [savePropertyDataToClass](/api/core/function/savePropertyDataToClass.md) - [savePropertyInject](/api/core/function/savePropertyInject.md) - [savePropertyMetadata](/api/core/function/savePropertyMetadata.md) - [saveProviderId](/api/core/function/saveProviderId.md) - [Schedule](/api/core/function/Schedule.md) - [Scope](/api/core/function/Scope.md) - [ServerlessFunction](/api/core/function/ServerlessFunction.md) - [ServerlessTrigger](/api/core/function/ServerlessTrigger.md) - [Session](/api/core/function/Session.md) - [SetHeader](/api/core/function/SetHeader.md) - [Singleton](/api/core/function/Singleton.md) - [sleep](/api/core/function/sleep.md) - [Task](/api/core/function/Task.md) - [TaskLocal](/api/core/function/TaskLocal.md) - [Trace](/api/core/function/Trace.md) - [transformRequestObjectByType](/api/core/function/transformRequestObjectByType.md) - [UseGuard](/api/core/function/UseGuard.md) - [wrapAsync](/api/core/function/wrapAsync.md) - [wrapMiddleware](/api/core/function/wrapMiddleware.md) - [WSBroadCast](/api/core/function/WSBroadCast.md) - [WSController](/api/core/function/WSController.md) - [WSEmit](/api/core/function/WSEmit.md) #### interface - [AspectMetadata](/api/core/interface/AspectMetadata.md) - [AsyncContext](/api/core/interface/AsyncContext.md) - [AsyncContextManager](/api/core/interface/AsyncContextManager.md) - [BaseServiceDiscoveryHealthCheckOptions](/api/core/interface/BaseServiceDiscoveryHealthCheckOptions.md): 基础健康检查配置 - [CommonSchedule](/api/core/interface/CommonSchedule.md) - [ConstructorInjectMetadata](/api/core/interface/ConstructorInjectMetadata.md): Metadata when using - [Context](/api/core/interface/Context.md) - [ControllerOption](/api/core/interface/ControllerOption.md) - [DataSourceManagerConfigOption ](/api/core/interface/DataSourceManagerConfigOption.md) - [DefaultInstanceMetadata](/api/core/interface/DefaultInstanceMetadata.md) - [DuplicateRouteErrorEntry](/api/core/interface/DuplicateRouteErrorEntry.md) - [DuplicateRouteErrorPayload](/api/core/interface/DuplicateRouteErrorPayload.md) - [HealthResult](/api/core/interface/HealthResult.md) - [HealthResults](/api/core/interface/HealthResults.md) - [HttpClientOptions ](/api/core/interface/HttpClientOptions.md) - [HttpClientResponse ](/api/core/interface/HttpClientResponse.md) - [HTTPServiceDiscoveryHealthCheckOptions](/api/core/interface/HTTPServiceDiscoveryHealthCheckOptions.md): HTTP 健康检查配置 - [IComponentInfo](/api/core/interface/IComponentInfo.md) - [IConfigService](/api/core/interface/IConfigService.md) - [IConfigurationOptions](/api/core/interface/IConfigurationOptions.md) - [IDataSourceManager ](/api/core/interface/IDataSourceManager.md) - [IEnvironmentService](/api/core/interface/IEnvironmentService.md) - [IFileDetector](/api/core/interface/IFileDetector.md) - [IFilter ](/api/core/interface/IFilter.md): Common Exception Filter definition - [IGuard ](/api/core/interface/IGuard.md): Guard definition - [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) - [IInformationService](/api/core/interface/IInformationService.md) - [ILifeCycle](/api/core/interface/ILifeCycle.md): Lifecycle Definition 生命周期定义 - [ILoadBalancer ](/api/core/interface/ILoadBalancer.md): 负载均衡策略接口 - [ILogger](/api/core/interface/ILogger.md): Logger Options for midway, you can merge this interface in package - [IMethodAspect](/api/core/interface/IMethodAspect.md) - [IMiddleware ](/api/core/interface/IMiddleware.md): Common middleware definition - [IMiddlewareManager ](/api/core/interface/IMiddlewareManager.md) - [IMidwayBaseApplication ](/api/core/interface/IMidwayBaseApplication.md) - [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md) - [IMidwayContainer](/api/core/interface/IMidwayContainer.md): Abstract Object Factory 对象容器抽象 - [IMidwayFramework ](/api/core/interface/IMidwayFramework.md) - [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md): Abstract Object Factory 对象容器抽象 - [IMidwayRequestContainer](/api/core/interface/IMidwayRequestContainer.md): Abstract Object Factory 对象容器抽象 - [InjectionConfigurationOptions](/api/core/interface/InjectionConfigurationOptions.md) - [IObjectCreator](/api/core/interface/IObjectCreator.md) - [IObjectDefinition](/api/core/interface/IObjectDefinition.md): Object Definition 对象描述定义 - [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md): Object Definition Registry 对象定义存储容器 - [IObjectFactory](/api/core/interface/IObjectFactory.md): Abstract Object Factory 对象容器抽象 - [IObjectLifeCycle](/api/core/interface/IObjectLifeCycle.md): Object Lifecycle 对象生命周期 - [IServiceDiscoveryClient ](/api/core/interface/IServiceDiscoveryClient.md) - [IServiceDiscoveryHealthCheck ](/api/core/interface/IServiceDiscoveryHealthCheck.md) - [IServiceFactory ](/api/core/interface/IServiceFactory.md) - [ISimulation](/api/core/interface/ISimulation.md) - [JoinPoint](/api/core/interface/JoinPoint.md) - [KafkaListenerOptions](/api/core/interface/KafkaListenerOptions.md) - [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md) - [MethodDecoratorMetaData ](/api/core/interface/MethodDecoratorMetaData.md) - [MethodDecoratorOptions](/api/core/interface/MethodDecoratorOptions.md) - [MidwayAppInfo](/api/core/interface/MidwayAppInfo.md) - [MidwayConfig](/api/core/interface/MidwayConfig.md): midway global config definition - [MidwayCoreDefaultConfig](/api/core/interface/MidwayCoreDefaultConfig.md) - [MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md): Logger Options for midway, you can merge this interface in package - [ObjectBeforeBindOptions](/api/core/interface/ObjectBeforeBindOptions.md) - [ObjectBeforeCreatedOptions](/api/core/interface/ObjectBeforeCreatedOptions.md) - [ObjectBeforeDestroyOptions](/api/core/interface/ObjectBeforeDestroyOptions.md) - [ObjectCreatedOptions ](/api/core/interface/ObjectCreatedOptions.md) - [ObjectDefinitionOptions](/api/core/interface/ObjectDefinitionOptions.md) - [ObjectInitOptions](/api/core/interface/ObjectInitOptions.md) - [ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md) - [ParameterDecoratorMetaData ](/api/core/interface/ParameterDecoratorMetaData.md) - [PipeTransform ](/api/core/interface/PipeTransform.md) - [PropertyDecoratorOptions](/api/core/interface/PropertyDecoratorOptions.md) - [PropertyInjectMetadata](/api/core/interface/PropertyInjectMetadata.md): Metadata when using - [RabbitMQListenerOptions](/api/core/interface/RabbitMQListenerOptions.md) - [ReflectResult](/api/core/interface/ReflectResult.md) - [RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md) - [RouterInfo](/api/core/interface/RouterInfo.md) - [RouterOption](/api/core/interface/RouterOption.md) - [RouterParamValue](/api/core/interface/RouterParamValue.md) - [RouterPriority](/api/core/interface/RouterPriority.md) - [ScheduleOpts](/api/core/interface/ScheduleOpts.md) - [ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md) - [ServerSendEventStreamOptions ](/api/core/interface/ServerSendEventStreamOptions.md) - [ServerStreamOptions ](/api/core/interface/ServerStreamOptions.md) - [ServiceDiscoveryBaseInstance](/api/core/interface/ServiceDiscoveryBaseInstance.md) - [ServiceDiscoveryHealthCheckResult](/api/core/interface/ServiceDiscoveryHealthCheckResult.md): 健康检查结果 - [ServiceDiscoveryOptions ](/api/core/interface/ServiceDiscoveryOptions.md) - [TagClsMetadata](/api/core/interface/TagClsMetadata.md) - [TagPropsMetadata](/api/core/interface/TagPropsMetadata.md) - [TCPServiceDiscoveryHealthCheckOptions](/api/core/interface/TCPServiceDiscoveryHealthCheckOptions.md): TCP 健康检查配置 - [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md) - [TransformOptions ](/api/core/interface/TransformOptions.md) - [TSDesignType ](/api/core/interface/TSDesignType.md) - [TTLServiceDiscoveryHealthCheckOptions](/api/core/interface/TTLServiceDiscoveryHealthCheckOptions.md): TTL 健康检查配置 - [WSControllerOption](/api/core/interface/WSControllerOption.md) - [WSEventInfo](/api/core/interface/WSEventInfo.md) #### namespace - [ConsumerMetadata](/api/core/namespace/ConsumerMetadata.md) - [FaaSMetadata](/api/core/namespace/FaaSMetadata.md) - [GRPCMetadata](/api/core/namespace/GRPCMetadata.md): grpc decorator metadata format ### cos - [@midwayjs/cos](/api/cos.md) #### class - [Configuration](/api/cos/class/Configuration.md) - [COSService](/api/cos/class/COSService.md) - [COSServiceFactory](/api/cos/class/COSServiceFactory.md) ### cron - [@midwayjs/cron](/api/cron.md) #### class - [Configuration](/api/cron/class/Configuration.md) - [Framework](/api/cron/class/Framework.md) #### function - [InjectJob](/api/cron/function/InjectJob.md) - [Job](/api/cron/function/Job.md) #### interface - [Application](/api/cron/interface/Application.md) - [Context](/api/cron/interface/Context.md) - [CronOptions](/api/cron/interface/CronOptions.md) - [IJob](/api/cron/interface/IJob.md) ### cross-domain - [@midwayjs/cross-domain](/api/cross-domain.md) #### class - [Configuration](/api/cross-domain/class/Configuration.md) - [CorsMiddleware](/api/cross-domain/class/CorsMiddleware.md) - [JSONPFilter](/api/cross-domain/class/JSONPFilter.md) - [JSONPMiddleware](/api/cross-domain/class/JSONPMiddleware.md) - [JSONPService](/api/cross-domain/class/JSONPService.md) #### interface - [CORSOptions](/api/cross-domain/interface/CORSOptions.md) - [JSONPOptions](/api/cross-domain/interface/JSONPOptions.md) ### etcd - [@midwayjs/etcd](/api/etcd.md) #### class - [Configuration](/api/etcd/class/Configuration.md) - [ETCDService](/api/etcd/class/ETCDService.md) - [EtcdServiceDiscoverClient](/api/etcd/class/EtcdServiceDiscoverClient.md) - [EtcdServiceDiscovery](/api/etcd/class/EtcdServiceDiscovery.md) - [ETCDServiceFactory](/api/etcd/class/ETCDServiceFactory.md) ### event-emitter - [@midwayjs/event-emitter](/api/event-emitter.md) #### class - [Configuration](/api/event-emitter/class/Configuration.md) - [EventEmitterService](/api/event-emitter/class/EventEmitterService.md) #### function - [OnEvent](/api/event-emitter/function/OnEvent.md) #### interface - [EventEmitterConfigOptions](/api/event-emitter/interface/EventEmitterConfigOptions.md) ### express-session - [@midwayjs/express-session](/api/express-session.md) #### class - [Configuration](/api/express-session/class/Configuration.md) - [SessionMiddleware](/api/express-session/class/SessionMiddleware.md) - [SessionStoreManager](/api/express-session/class/SessionStoreManager.md) ### faas - [@midwayjs/faas](/api/faas.md) #### class - [abstractAbstractBootstrapStarter](/api/faas/class/AbstractBootstrapStarter.md) - [Configuration](/api/faas/class/Configuration.md) - [Framework](/api/faas/class/Framework.md) #### function - [Event](/api/faas/function/Event.md) #### interface - [Application](/api/faas/interface/Application.md) - [Context](/api/faas/interface/Context.md) - [FaaSContext](/api/faas/interface/FaaSContext.md) - [FaaSHTTPContext](/api/faas/interface/FaaSHTTPContext.md) - [FaaSHTTPRequest](/api/faas/interface/FaaSHTTPRequest.md) - [FaaSHTTPResponse](/api/faas/interface/FaaSHTTPResponse.md) - [FormatResponseOptions](/api/faas/interface/FormatResponseOptions.md) - [HandlerOptions](/api/faas/interface/HandlerOptions.md) - [HttpResponseFormat ](/api/faas/interface/HttpResponseFormat.md) - [IFaaSConfigurationOptions](/api/faas/interface/IFaaSConfigurationOptions.md) - [IWebMiddleware](/api/faas/interface/IWebMiddleware.md) - [ServerlessStarterOptions](/api/faas/interface/ServerlessStarterOptions.md) - [State](/api/faas/interface/State.md) - [wrapHttpRequestOptions](/api/faas/interface/wrapHttpRequestOptions.md) ### grpc - [@midwayjs/grpc](/api/grpc.md) #### class - [Clients](/api/grpc/class/Clients.md) - [Configuration](/api/grpc/class/Configuration.md) - [Framework](/api/grpc/class/Framework.md) #### function - [createGRPCConsumer](/api/grpc/function/createGRPCConsumer.md) - [loadProto](/api/grpc/function/loadProto.md) #### interface - [Context ](/api/grpc/interface/Context.md) - [DefaultConfig](/api/grpc/interface/DefaultConfig.md) - [IClientDuplexStreamService ](/api/grpc/interface/IClientDuplexStreamService.md) - [IClientOptions](/api/grpc/interface/IClientOptions.md) - [IClientReadableStreamService ](/api/grpc/interface/IClientReadableStreamService.md) - [IClientUnaryService ](/api/grpc/interface/IClientUnaryService.md) - [IClientWritableStreamService ](/api/grpc/interface/IClientWritableStreamService.md) - [IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md) - [IGRPCServiceOptions](/api/grpc/interface/IGRPCServiceOptions.md) - [IMidwayGRPFrameworkOptions](/api/grpc/interface/IMidwayGRPFrameworkOptions.md) ### http-proxy - [@midwayjs/http-proxy](/api/http-proxy.md) #### class - [Configuration](/api/http-proxy/class/Configuration.md) - [HttpProxyMiddleware](/api/http-proxy/class/HttpProxyMiddleware.md) #### interface - [HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md) - [HttpProxyStrategy](/api/http-proxy/interface/HttpProxyStrategy.md) ### i18n - [@midwayjs/i18n](/api/i18n.md) #### class - [Configuration](/api/i18n/class/Configuration.md) - [I18nFilter](/api/i18n/class/I18nFilter.md) - [I18nMiddleware](/api/i18n/class/I18nMiddleware.md) - [MidwayI18nService](/api/i18n/class/MidwayI18nService.md) - [MidwayI18nServiceSingleton](/api/i18n/class/MidwayI18nServiceSingleton.md) #### function - [formatLocale](/api/i18n/function/formatLocale.md) #### interface - [I18nOptions](/api/i18n/interface/I18nOptions.md) - [RequestResolver](/api/i18n/interface/RequestResolver.md) - [TranslateOptions](/api/i18n/interface/TranslateOptions.md) ### info - [@midwayjs/info](/api/info.md) #### class - [Configuration](/api/info/class/Configuration.md) - [InfoMiddleware](/api/info/class/InfoMiddleware.md) - [InfoService](/api/info/class/InfoService.md) #### enum - [InfoType](/api/info/enum/InfoType.md) #### interface - [InfoConfigOptions](/api/info/interface/InfoConfigOptions.md) - [TypeInfo](/api/info/interface/TypeInfo.md) ### jwt - [@midwayjs/jwt](/api/jwt.md) #### class - [Configuration](/api/jwt/class/Configuration.md) - [JwtService](/api/jwt/class/JwtService.md): @see{@link https://github.com/auth0/node-jsonwebtoken} ### kafka - [@midwayjs/kafka](/api/kafka.md) #### class - [Configuration](/api/kafka/class/Configuration.md) - [Framework](/api/kafka/class/Framework.md) - [KafkaAdminFactory](/api/kafka/class/KafkaAdminFactory.md) - [KafkaProducerFactory](/api/kafka/class/KafkaProducerFactory.md) #### function - [KafkaConsumer](/api/kafka/function/KafkaConsumer.md) #### interface - [Context](/api/kafka/interface/Context.md) - [IKafkaApplication](/api/kafka/interface/IKafkaApplication.md) - [IKafkaConsumer](/api/kafka/interface/IKafkaConsumer.md) - [IKafkaConsumerInitOptions](/api/kafka/interface/IKafkaConsumerInitOptions.md): The options for the kafka consumer initialization in midway - [IMidwayConsumerConfig](/api/kafka/interface/IMidwayConsumerConfig.md): 客户端的相关配置,在midwayjs的自定义配置项 - [IMidwayKafkaAdminInitOptions](/api/kafka/interface/IMidwayKafkaAdminInitOptions.md): The options for the kafka admin initialization in midway - [IMidwayKafkaConfigurationOptions](/api/kafka/interface/IMidwayKafkaConfigurationOptions.md) - [IMidwayKafkaProducerInitOptions](/api/kafka/interface/IMidwayKafkaProducerInitOptions.md): The options for the kafka producer initialization in midway ### leoric - [@midwayjs/leoric](/api/leoric.md) #### class - [Configuration](/api/leoric/class/Configuration.md) - [LeoricDataSourceManager](/api/leoric/class/LeoricDataSourceManager.md) #### function - [InjectDataSource](/api/leoric/function/InjectDataSource.md) - [InjectModel](/api/leoric/function/InjectModel.md) ### mcp - [@midwayjs/mcp](/api/mcp.md) #### class - [Configuration](/api/mcp/class/Configuration.md) - [MCPAuthInfoMiddleware](/api/mcp/class/MCPAuthInfoMiddleware.md) - [MidwayMCPFramework](/api/mcp/class/MidwayMCPFramework.md) #### function - [Prompt](/api/mcp/function/Prompt.md) - [Resource](/api/mcp/function/Resource.md) - [Tool](/api/mcp/function/Tool.md) #### interface - [Context](/api/mcp/interface/Context.md) - [IMcpPrompt](/api/mcp/interface/IMcpPrompt.md) - [IMcpResource](/api/mcp/interface/IMcpResource.md) - [IMcpTool](/api/mcp/interface/IMcpTool.md) - [IMidwayMCPConfigurationOptions](/api/mcp/interface/IMidwayMCPConfigurationOptions.md) - [IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md) ### mikro - [@midwayjs/mikro](/api/mikro.md) #### class - [Configuration](/api/mikro/class/Configuration.md) - [MikroDataSourceManager](/api/mikro/class/MikroDataSourceManager.md) #### function - [InjectDataSource](/api/mikro/function/InjectDataSource.md) - [InjectEntityManager](/api/mikro/function/InjectEntityManager.md) - [InjectRepository](/api/mikro/function/InjectRepository.md) ### mock - [@midwayjs/mock](/api/mock.md) #### class - [SocketIOWrapperClient](/api/mock/class/SocketIOWrapperClient.md) - [SSEClient](/api/mock/class/SSEClient.md) #### function - [close](/api/mock/function/close.md) - [create](/api/mock/function/create.md) - [createApp](/api/mock/function/createApp.md) - [createBootstrap](/api/mock/function/createBootstrap.md) - [createFunctionApp](/api/mock/function/createFunctionApp.md) - [createHttpRequest](/api/mock/function/createHttpRequest.md) - [createKafkaProducer](/api/mock/function/createKafkaProducer.md) - [createLegacyApp](/api/mock/function/createLegacyApp.md) - [createLegacyFunctionApp](/api/mock/function/createLegacyFunctionApp.md) - [createLegacyLightApp](/api/mock/function/createLegacyLightApp.md) - [createLightApp](/api/mock/function/createLightApp.md) - [createRabbitMQProducer](/api/mock/function/createRabbitMQProducer.md) - [createSocketIOClient](/api/mock/function/createSocketIOClient.md) - [createSSEClient](/api/mock/function/createSSEClient.md) - [createWebSocketClient](/api/mock/function/createWebSocketClient.md) - [mockClassProperty](/api/mock/function/mockClassProperty.md) - [mockContext](/api/mock/function/mockContext.md) - [mockHeader](/api/mock/function/mockHeader.md) - [mockProperty](/api/mock/function/mockProperty.md) - [mockSession](/api/mock/function/mockSession.md) - [processArgsParser](/api/mock/function/processArgsParser.md) - [restoreAllMocks](/api/mock/function/restoreAllMocks.md) - [restoreMocks](/api/mock/function/restoreMocks.md) - [transformFrameworkToConfiguration](/api/mock/function/transformFrameworkToConfiguration.md) #### interface - [MidwaySocketIOClientOptions](/api/mock/interface/MidwaySocketIOClientOptions.md) - [SSEClientOptions](/api/mock/interface/SSEClientOptions.md) ### mongoose - [@midwayjs/mongoose](/api/mongoose.md) #### class - [Configuration](/api/mongoose/class/Configuration.md) - [MongooseConnectionService](/api/mongoose/class/MongooseConnectionService.md) - [MongooseConnectionServiceFactory](/api/mongoose/class/MongooseConnectionServiceFactory.md) - [MongooseDataSourceManager](/api/mongoose/class/MongooseDataSourceManager.md) ### mqtt - [@midwayjs/mqtt](/api/mqtt.md) #### class - [Configuration](/api/mqtt/class/Configuration.md) - [DefaultMqttProducer](/api/mqtt/class/DefaultMqttProducer.md) - [Framework](/api/mqtt/class/Framework.md) - [MqttProducerFactory](/api/mqtt/class/MqttProducerFactory.md) #### function - [MqttSubscriber](/api/mqtt/function/MqttSubscriber.md) #### interface - [Context](/api/mqtt/interface/Context.md) - [IMidwayMQTTConfigurationOptions](/api/mqtt/interface/IMidwayMQTTConfigurationOptions.md) - [IMqttSubscriber](/api/mqtt/interface/IMqttSubscriber.md) - [MqttSubscriberOptions](/api/mqtt/interface/MqttSubscriberOptions.md) ### nextjs - [@midwayjs/nextjs](/api/nextjs.md) #### class - [Configuration](/api/nextjs/class/Configuration.md) - [NextJSMiddleware](/api/nextjs/class/NextJSMiddleware.md) #### function - [createClient](/api/nextjs/function/createClient.md) - [createNextjsApiClient](/api/nextjs/function/createNextjsApiClient.md) - [createNextjsApiClientFromOperations](/api/nextjs/function/createNextjsApiClientFromOperations.md) - [resolveNextjsApiBridgeOptions](/api/nextjs/function/resolveNextjsApiBridgeOptions.md) ### oss - [@midwayjs/oss](/api/oss.md) #### class - [Configuration](/api/oss/class/Configuration.md) - [OSSService](/api/oss/class/OSSService.md) - [OSSServiceFactory ](/api/oss/class/OSSServiceFactory.md) - [OSSSTSService](/api/oss/class/OSSSTSService.md) #### interface - [MWOSSClusterOptions](/api/oss/interface/MWOSSClusterOptions.md) - [MWOSSOptions](/api/oss/interface/MWOSSOptions.md) - [MWOSSSTSOptions](/api/oss/interface/MWOSSSTSOptions.md) ### passport - [@midwayjs/passport](/api/passport.md) #### class - [abstractAbstractPassportMiddleware](/api/passport/class/AbstractPassportMiddleware.md) - [Configuration](/api/passport/class/Configuration.md) - [PassportAuthenticator](/api/passport/class/PassportAuthenticator.md) #### function - [CustomStrategy](/api/passport/function/CustomStrategy.md) - [PassportMiddleware](/api/passport/function/PassportMiddleware.md) - [PassportStrategy](/api/passport/function/PassportStrategy.md) #### interface - [AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md) - [IPassportMiddleware](/api/passport/interface/IPassportMiddleware.md) - [IPassportStrategy](/api/passport/interface/IPassportStrategy.md) - [StrategyCreatedStatic](/api/passport/interface/StrategyCreatedStatic.md) ### prometheus - [@midwayjs/prometheus](/api/prometheus.md) #### class - [Configuration](/api/prometheus/class/Configuration.md) - [DataService](/api/prometheus/class/DataService.md) ### prometheus-socket-io - [@midwayjs/prometheus-socket-io](/api/prometheus-socket-io.md) #### class - [Configuration](/api/prometheus-socket-io/class/Configuration.md) ### rabbitmq - [@midwayjs/rabbitmq](/api/rabbitmq.md) #### class - [Configuration](/api/rabbitmq/class/Configuration.md) - [Framework](/api/rabbitmq/class/Framework.md) #### interface - [Context](/api/rabbitmq/interface/Context.md) - [IMidwayRabbitMQConfigurationOptions](/api/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) - [IRabbitMQApplication](/api/rabbitmq/interface/IRabbitMQApplication.md) - [IRabbitMQExchange](/api/rabbitmq/interface/IRabbitMQExchange.md) ### redis - [@midwayjs/redis](/api/redis.md) #### class - [Configuration](/api/redis/class/Configuration.md) - [RedisService](/api/redis/class/RedisService.md) - [RedisServiceDiscoverClient](/api/redis/class/RedisServiceDiscoverClient.md) - [RedisServiceDiscovery](/api/redis/class/RedisServiceDiscovery.md) - [RedisServiceFactory](/api/redis/class/RedisServiceFactory.md) #### interface - [RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md) - [RedisServiceDiscoveryOptions](/api/redis/interface/RedisServiceDiscoveryOptions.md) ### security - [@midwayjs/security](/api/security.md) #### class - [Configuration](/api/security/class/Configuration.md) - [CSPMiddleware](/api/security/class/CSPMiddleware.md) - [CsrfMiddleware](/api/security/class/CsrfMiddleware.md) - [HSTSMiddleware](/api/security/class/HSTSMiddleware.md) - [NoOpenMiddleware](/api/security/class/NoOpenMiddleware.md) - [NoSniffMiddleware](/api/security/class/NoSniffMiddleware.md) - [SecurityHelper](/api/security/class/SecurityHelper.md) - [XFrameMiddleware](/api/security/class/XFrameMiddleware.md) - [XSSProtectionMiddleware](/api/security/class/XSSProtectionMiddleware.md) #### interface - [SecurityCSPOptions](/api/security/interface/SecurityCSPOptions.md) - [SecurityCSRFOptions](/api/security/interface/SecurityCSRFOptions.md) - [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) - [SecurityHSTSOptions](/api/security/interface/SecurityHSTSOptions.md) - [SecurityOptions](/api/security/interface/SecurityOptions.md) - [SecurityXFrameOptions](/api/security/interface/SecurityXFrameOptions.md) - [SecurityXSSProtectionOptions](/api/security/interface/SecurityXSSProtectionOptions.md) ### sequelize - [@midwayjs/sequelize](/api/sequelize.md) #### class - [Configuration](/api/sequelize/class/Configuration.md) - [SequelizeDataSourceManager](/api/sequelize/class/SequelizeDataSourceManager.md) #### function - [InjectDataSource](/api/sequelize/function/InjectDataSource.md) - [InjectRepository](/api/sequelize/function/InjectRepository.md) ### session - [@midwayjs/session](/api/session.md) #### class - [Configuration](/api/session/class/Configuration.md) - [SessionMiddleware](/api/session/class/SessionMiddleware.md) - [abstractSessionStore](/api/session/class/SessionStore.md) - [SessionStoreManager](/api/session/class/SessionStoreManager.md) #### interface - [ISession](/api/session/interface/ISession.md) - [SessionOptions](/api/session/interface/SessionOptions.md) ### socketio - [@midwayjs/socketio](/api/socketio.md) #### class - [Configuration](/api/socketio/class/Configuration.md) - [Framework](/api/socketio/class/Framework.md) ### static-file - [@midwayjs/static-file](/api/static-file.md) #### class - [Configuration](/api/static-file/class/Configuration.md) - [DirectoryNotFoundError](/api/static-file/class/DirectoryNotFoundError.md) - [StaticMiddleware](/api/static-file/class/StaticMiddleware.md) #### interface - [StaticFileOption](/api/static-file/interface/StaticFileOption.md) - [StaticFileOptions](/api/static-file/interface/StaticFileOptions.md) ### swagger - [@midwayjs/swagger](/api/swagger.md) #### class - [Configuration](/api/swagger/class/Configuration.md) - [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md) - [SwaggerMiddleware](/api/swagger/class/SwaggerMiddleware.md) #### enum - [BodyContentType](/api/swagger/enum/BodyContentType.md) #### function - [ApiAcceptedResponse](/api/swagger/function/ApiAcceptedResponse.md) - [ApiBadGatewayResponse](/api/swagger/function/ApiBadGatewayResponse.md) - [ApiBadRequestResponse](/api/swagger/function/ApiBadRequestResponse.md) - [ApiBasicAuth](/api/swagger/function/ApiBasicAuth.md) - [ApiBearerAuth](/api/swagger/function/ApiBearerAuth.md) - [ApiBody](/api/swagger/function/ApiBody.md) - [ApiConflictResponse](/api/swagger/function/ApiConflictResponse.md) - [ApiCookieAuth](/api/swagger/function/ApiCookieAuth.md) - [ApiCreatedResponse](/api/swagger/function/ApiCreatedResponse.md) - [ApiDefaultResponse](/api/swagger/function/ApiDefaultResponse.md) - [ApiExcludeController](/api/swagger/function/ApiExcludeController.md) - [ApiExcludeEndpoint](/api/swagger/function/ApiExcludeEndpoint.md) - [ApiExcludeSecurity](/api/swagger/function/ApiExcludeSecurity.md) - [ApiExtension](/api/swagger/function/ApiExtension.md) - [ApiExtraModel](/api/swagger/function/ApiExtraModel.md) - [ApiForbiddenResponse](/api/swagger/function/ApiForbiddenResponse.md) - [ApiFoundResponse](/api/swagger/function/ApiFoundResponse.md) - [ApiGatewayTimeoutResponse](/api/swagger/function/ApiGatewayTimeoutResponse.md) - [ApiGoneResponse](/api/swagger/function/ApiGoneResponse.md) - [ApiHeader](/api/swagger/function/ApiHeader.md) - [ApiHeaders](/api/swagger/function/ApiHeaders.md) - [ApiInternalServerErrorResponse](/api/swagger/function/ApiInternalServerErrorResponse.md) - [ApiMethodNotAllowedResponse](/api/swagger/function/ApiMethodNotAllowedResponse.md) - [ApiMovedPermanentlyResponse](/api/swagger/function/ApiMovedPermanentlyResponse.md) - [ApiNoContentResponse](/api/swagger/function/ApiNoContentResponse.md) - [ApiNotAcceptableResponse](/api/swagger/function/ApiNotAcceptableResponse.md) - [ApiNotFoundResponse](/api/swagger/function/ApiNotFoundResponse.md) - [ApiNotImplementedResponse](/api/swagger/function/ApiNotImplementedResponse.md) - [ApiOAuth2](/api/swagger/function/ApiOAuth2.md) - [ApiOkResponse](/api/swagger/function/ApiOkResponse.md) - [ApiOperation](/api/swagger/function/ApiOperation.md) - [ApiParam](/api/swagger/function/ApiParam.md) - [ApiPayloadTooLargeResponse](/api/swagger/function/ApiPayloadTooLargeResponse.md) - [ApiPreconditionFailedResponse](/api/swagger/function/ApiPreconditionFailedResponse.md) - [ApiProperty](/api/swagger/function/ApiProperty.md) - [ApiPropertyOptional](/api/swagger/function/ApiPropertyOptional.md) - [ApiQuery](/api/swagger/function/ApiQuery.md) - [ApiRequestTimeoutResponse](/api/swagger/function/ApiRequestTimeoutResponse.md) - [ApiResponse](/api/swagger/function/ApiResponse.md) - [ApiResponseProperty](/api/swagger/function/ApiResponseProperty.md) - [ApiSecurity](/api/swagger/function/ApiSecurity.md) - [ApiServiceUnavailableResponse](/api/swagger/function/ApiServiceUnavailableResponse.md) - [ApiTags](/api/swagger/function/ApiTags.md) - [ApiTooManyRequestsResponse](/api/swagger/function/ApiTooManyRequestsResponse.md) - [ApiUnauthorizedResponse](/api/swagger/function/ApiUnauthorizedResponse.md) - [ApiUnprocessableEntityResponse](/api/swagger/function/ApiUnprocessableEntityResponse.md) - [ApiUnsupportedMediaTypeResponse](/api/swagger/function/ApiUnsupportedMediaTypeResponse.md) - [getSchemaPath](/api/swagger/function/getSchemaPath.md) - [renderJSON](/api/swagger/function/renderJSON.md) - [renderSwaggerUIDist](/api/swagger/function/renderSwaggerUIDist.md) - [renderSwaggerUIRemote](/api/swagger/function/renderSwaggerUIRemote.md) #### interface - [ApiHeaderOptions](/api/swagger/interface/ApiHeaderOptions.md) - [ApiPropertyOptions](/api/swagger/interface/ApiPropertyOptions.md) - [ApiResponseMetadata](/api/swagger/interface/ApiResponseMetadata.md) - [ApiResponseSchemaHost](/api/swagger/interface/ApiResponseSchemaHost.md) - [AuthOptions](/api/swagger/interface/AuthOptions.md): 继承自 https://swagger.io/specification/#security-scheme-object - [BaseParameterObject](/api/swagger/interface/BaseParameterObject.md) - [ComponentsObject](/api/swagger/interface/ComponentsObject.md) - [ContactObject](/api/swagger/interface/ContactObject.md) - [DiscriminatorObject](/api/swagger/interface/DiscriminatorObject.md) - [EncodingPropertyObject](/api/swagger/interface/EncodingPropertyObject.md) - [ExampleObject](/api/swagger/interface/ExampleObject.md) - [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) - [InfoObject](/api/swagger/interface/InfoObject.md) - [LicenseObject](/api/swagger/interface/LicenseObject.md) - [LinkObject](/api/swagger/interface/LinkObject.md) - [MediaTypeObject](/api/swagger/interface/MediaTypeObject.md) - [MixDecoratorMetadata](/api/swagger/interface/MixDecoratorMetadata.md) - [OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) - [OAuthFlowsObject](/api/swagger/interface/OAuthFlowsObject.md) - [OpenAPIObject](/api/swagger/interface/OpenAPIObject.md) - [OperationObject](/api/swagger/interface/OperationObject.md) - [ParameterObject](/api/swagger/interface/ParameterObject.md) - [PathItemObject](/api/swagger/interface/PathItemObject.md) - [ReferenceObject](/api/swagger/interface/ReferenceObject.md) - [RequestBodyObject](/api/swagger/interface/RequestBodyObject.md) - [ResponseObject](/api/swagger/interface/ResponseObject.md) - [ResponsesObject](/api/swagger/interface/ResponsesObject.md) - [SchemaObject](/api/swagger/interface/SchemaObject.md) - [SchemaObjectMetadata](/api/swagger/interface/SchemaObjectMetadata.md) - [SecuritySchemeObject](/api/swagger/interface/SecuritySchemeObject.md) - [ServerObject](/api/swagger/interface/ServerObject.md) - [ServerVariableObject](/api/swagger/interface/ServerVariableObject.md) - [SwaggerOptions](/api/swagger/interface/SwaggerOptions.md): see https://swagger.io/specification/ - [TagObject](/api/swagger/interface/TagObject.md) - [Type ](/api/swagger/interface/Type.md) - [XmlObject](/api/swagger/interface/XmlObject.md) ### tablestore - [@midwayjs/tablestore](/api/tablestore.md) #### class - [CompositeCondition](/api/tablestore/class/CompositeCondition.md) - [Condition](/api/tablestore/class/Condition.md) - [Configuration](/api/tablestore/class/Configuration.md) - [SingleColumnCondition ](/api/tablestore/class/SingleColumnCondition.md) - [TableStoreService](/api/tablestore/class/TableStoreService.md) - [TableStoreServiceFactory](/api/tablestore/class/TableStoreServiceFactory.md) #### enum - [ColumnConditionType](/api/tablestore/enum/ColumnConditionType.md) - [ColumnReturnType](/api/tablestore/enum/ColumnReturnType.md) - [ComparatorType](/api/tablestore/enum/ComparatorType.md) - [DefinedColumnType](/api/tablestore/enum/DefinedColumnType.md) - [Direction](/api/tablestore/enum/Direction.md) - [FieldType](/api/tablestore/enum/FieldType.md) - [FilterType](/api/tablestore/enum/FilterType.md) - [GeoDistanceType](/api/tablestore/enum/GeoDistanceType.md) - [IndexOptions](/api/tablestore/enum/IndexOptions.md) - [IndexType](/api/tablestore/enum/IndexType.md) - [IndexUpdateMode](/api/tablestore/enum/IndexUpdateMode.md) - [LogicalOperator](/api/tablestore/enum/LogicalOperator.md) - [PrimaryKeyOption](/api/tablestore/enum/PrimaryKeyOption.md) - [PrimaryKeyType](/api/tablestore/enum/PrimaryKeyType.md) - [QueryOperator](/api/tablestore/enum/QueryOperator.md) - [QueryType](/api/tablestore/enum/QueryType.md): search - [ReturnType](/api/tablestore/enum/ReturnType.md) - [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md): metadata - [ScoreMode](/api/tablestore/enum/ScoreMode.md) - [SortMode](/api/tablestore/enum/SortMode.md) - [SortOrder](/api/tablestore/enum/SortOrder.md) - [UpdateType](/api/tablestore/enum/UpdateType.md) #### function - [formatRow](/api/tablestore/function/formatRow.md) - [formatRows](/api/tablestore/function/formatRows.md) #### interface - [BatchGetRowParams](/api/tablestore/interface/BatchGetRowParams.md) - [BatchWriteRowParams](/api/tablestore/interface/BatchWriteRowParams.md) - [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) - [CreateIndexParams](/api/tablestore/interface/CreateIndexParams.md) - [CreateSearchIndexParams](/api/tablestore/interface/CreateSearchIndexParams.md) - [CreateTableParams](/api/tablestore/interface/CreateTableParams.md): params - [DeleteRowParams](/api/tablestore/interface/DeleteRowParams.md) - [DeleteSearchIndexParams](/api/tablestore/interface/DeleteSearchIndexParams.md) - [DeleteTableParams](/api/tablestore/interface/DeleteTableParams.md) - [DescribeSearchIndexParams](/api/tablestore/interface/DescribeSearchIndexParams.md) - [DescribeTableParams](/api/tablestore/interface/DescribeTableParams.md) - [DropIndexParams](/api/tablestore/interface/DropIndexParams.md) - [GetRangeParams](/api/tablestore/interface/GetRangeParams.md) - [GetRowParams](/api/tablestore/interface/GetRowParams.md) - [ListSearchIndexParams](/api/tablestore/interface/ListSearchIndexParams.md) - [PutRowParams](/api/tablestore/interface/PutRowParams.md) - [SearchIndexFieldSchema](/api/tablestore/interface/SearchIndexFieldSchema.md) - [SearchIndexNestedFilter](/api/tablestore/interface/SearchIndexNestedFilter.md) - [SearchIndexSchema](/api/tablestore/interface/SearchIndexSchema.md) - [SearchIndexSetting](/api/tablestore/interface/SearchIndexSetting.md) - [SearchIndexSorter](/api/tablestore/interface/SearchIndexSorter.md) - [SearchParams](/api/tablestore/interface/SearchParams.md) - [SearchQuery](/api/tablestore/interface/SearchQuery.md) - [StartLocalTransactionParams](/api/tablestore/interface/StartLocalTransactionParams.md) - [TableStoreClient](/api/tablestore/interface/TableStoreClient.md) - [TableStoreCompositeCondition](/api/tablestore/interface/TableStoreCompositeCondition.md) - [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) - [TableStoreConfig](/api/tablestore/interface/TableStoreConfig.md) - [TableStoreLong](/api/tablestore/interface/TableStoreLong.md) - [TableStoreResult](/api/tablestore/interface/TableStoreResult.md) - [TableStoreSingleColumnCondition ](/api/tablestore/interface/TableStoreSingleColumnCondition.md) - [UpdateRowParams](/api/tablestore/interface/UpdateRowParams.md) - [UpdateTableParams](/api/tablestore/interface/UpdateTableParams.md) ### tenant - [@midwayjs/tenant](/api/tenant.md) #### class - [Configuration](/api/tenant/class/Configuration.md) - [TenantManager](/api/tenant/class/TenantManager.md) ### typegoose - [@midwayjs/typegoose](/api/typegoose.md) #### class - [Configuration](/api/typegoose/class/Configuration.md) #### function - [EntityModel](/api/typegoose/function/EntityModel.md) - [InjectEntityModel](/api/typegoose/function/InjectEntityModel.md) ### typeorm - [@midwayjs/typeorm](/api/typeorm.md) #### class - [Configuration](/api/typeorm/class/Configuration.md) - [TypeORMDataSourceManager](/api/typeorm/class/TypeORMDataSourceManager.md) #### function - [EventSubscriberModel](/api/typeorm/function/EventSubscriberModel.md) - [InjectDataSource](/api/typeorm/function/InjectDataSource.md) - [InjectEntityModel](/api/typeorm/function/InjectEntityModel.md) ### upload - [@midwayjs/upload](/api/upload.md) #### class - [Configuration](/api/upload/class/Configuration.md) - [MultipartInvalidFilenameError](/api/upload/class/MultipartInvalidFilenameError.md) - [MultipartInvalidFileTypeError](/api/upload/class/MultipartInvalidFileTypeError.md) - [UploadMiddleware](/api/upload/class/UploadMiddleware.md) #### interface - [UploadFileInfo ](/api/upload/interface/UploadFileInfo.md) - [UploadOptions](/api/upload/interface/UploadOptions.md) ### validate - [@midwayjs/validate](/api/validate.md) #### class - [abstractAbstractValidationPipe](/api/validate/class/AbstractValidationPipe.md) - [Configuration](/api/validate/class/Configuration.md) - [DecoratorValidPipe](/api/validate/class/DecoratorValidPipe.md) - [DefaultValuePipe ](/api/validate/class/DefaultValuePipe.md) - [MidwayValidationError](/api/validate/class/MidwayValidationError.md) - [ParseBoolPipe](/api/validate/class/ParseBoolPipe.md) - [ParseFloatPipe](/api/validate/class/ParseFloatPipe.md) - [ParseIntPipe](/api/validate/class/ParseIntPipe.md) - [abstractParsePipe](/api/validate/class/ParsePipe.md) - [ValidateService](/api/validate/class/ValidateService.md) - [ValidationPipe](/api/validate/class/ValidationPipe.md) #### function - [getSchema](/api/validate/function/getSchema.md) - [OmitDto](/api/validate/function/OmitDto.md) - [PickDto](/api/validate/function/PickDto.md) - [Rule](/api/validate/function/Rule.md) - [Valid](/api/validate/function/Valid.md) - [Validate](/api/validate/function/Validate.md) #### interface - [Dto ](/api/validate/interface/Dto.md) - [ValidateOptions](/api/validate/interface/ValidateOptions.md) ### validation - [@midwayjs/validation](/api/validation.md) #### class - [abstractAbstractValidationPipe](/api/validation/class/AbstractValidationPipe.md) - [Configuration](/api/validation/class/Configuration.md) - [DecoratorValidPipe](/api/validation/class/DecoratorValidPipe.md) - [DefaultValuePipe ](/api/validation/class/DefaultValuePipe.md) - [MidwayValidationError](/api/validation/class/MidwayValidationError.md) - [MidwayValidatorNotFoundError](/api/validation/class/MidwayValidatorNotFoundError.md) - [ParseBoolPipe](/api/validation/class/ParseBoolPipe.md) - [ParseFloatPipe](/api/validation/class/ParseFloatPipe.md) - [ParseIntPipe](/api/validation/class/ParseIntPipe.md) - [abstractParsePipe](/api/validation/class/ParsePipe.md) - [ValidationPipe](/api/validation/class/ValidationPipe.md) - [ValidationService](/api/validation/class/ValidationService.md) #### function - [getRuleMeta](/api/validation/function/getRuleMeta.md) - [getSchema](/api/validation/function/getSchema.md) - [OmitDto](/api/validation/function/OmitDto.md) - [PartialDto](/api/validation/function/PartialDto.md) - [PickDto](/api/validation/function/PickDto.md) - [RequiredDto](/api/validation/function/RequiredDto.md) - [Rule](/api/validation/function/Rule.md) - [Valid](/api/validation/function/Valid.md) - [Validate](/api/validation/function/Validate.md) #### interface - [Dto ](/api/validation/interface/Dto.md) - [IValidationService ](/api/validation/interface/IValidationService.md) - [IValidator ](/api/validation/interface/IValidator.md) - [IValidatorModule ](/api/validation/interface/IValidatorModule.md) - [SchemaHelper ](/api/validation/interface/SchemaHelper.md) - [ValidateResult](/api/validation/interface/ValidateResult.md) - [ValidationDecoratorOptions](/api/validation/interface/ValidationDecoratorOptions.md) - [ValidationExtendOptions](/api/validation/interface/ValidationExtendOptions.md) - [ValidationOptions](/api/validation/interface/ValidationOptions.md) ### validation-class-validator - [@midwayjs/validation-class-validator](/api/validation-class-validator.md) #### class - [ClassValidatorService](/api/validation-class-validator/class/ClassValidatorService.md) ### validation-joi - [@midwayjs/validation-joi](/api/validation-joi.md) ### validation-zod - [@midwayjs/validation-zod](/api/validation-zod.md) ### view - [@midwayjs/view](/api/view.md) #### class - [Configuration](/api/view/class/Configuration.md) - [ContextView](/api/view/class/ContextView.md): View instance for each request. It will find the view engine, and render it. The view engine should be registered in {@link ViewManager}. - [ViewManager](/api/view/class/ViewManager.md) #### interface - [IViewEngine](/api/view/interface/IViewEngine.md) - [RenderOptions](/api/view/interface/RenderOptions.md) ### view-ejs - [@midwayjs/view-ejs](/api/view-ejs.md) #### class - [Configuration](/api/view-ejs/class/Configuration.md) - [EjsView](/api/view-ejs/class/EjsView.md) ### view-nunjucks - [@midwayjs/view-nunjucks](/api/view-nunjucks.md) #### class - [Configuration](/api/view-nunjucks/class/Configuration.md) - [NunjucksEnvironment](/api/view-nunjucks/class/NunjucksEnvironment.md) - [NunjucksView](/api/view-nunjucks/class/NunjucksView.md) ### web - [@midwayjs/web](/api/web.md) #### class - [Agent](/api/web/class/Agent.md) - [Application](/api/web/class/Application.md) - [Configuration](/api/web/class/Configuration.md) - [Framework](/api/web/class/Framework.md) #### function - [AgentApp](/api/web/function/AgentApp.md) - [createAgentWorkerLoader](/api/web/function/createAgentWorkerLoader.md) - [createAppWorkerLoader](/api/web/function/createAppWorkerLoader.md) - [createEggAgent](/api/web/function/createEggAgent.md) - [createEggApplication](/api/web/function/createEggApplication.md) - [RunInEggAgent](/api/web/function/RunInEggAgent.md) - [startCluster](/api/web/function/startCluster.md) #### interface - [Context ](/api/web/interface/Context.md) - [IMidwayWebBaseApplication](/api/web/interface/IMidwayWebBaseApplication.md) - [IMidwayWebConfigurationOptions](/api/web/interface/IMidwayWebConfigurationOptions.md) - [IWebMiddleware](/api/web/interface/IWebMiddleware.md) - [State](/api/web/interface/State.md) ### web-express - [@midwayjs/express](/api/web-express.md) #### class - [Configuration](/api/web-express/class/Configuration.md) - [Framework](/api/web-express/class/Framework.md) - [MidwayExpressMiddlewareService](/api/web-express/class/MidwayExpressMiddlewareService.md) #### function - [wrapAsyncHandler](/api/web-express/function/wrapAsyncHandler.md) - [wrapMiddleware](/api/web-express/function/wrapMiddleware.md) #### interface - [Context](/api/web-express/interface/Context.md) - [IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md) - [IMidwayExpressConfigurationOptions](/api/web-express/interface/IMidwayExpressConfigurationOptions.md) ### web-koa - [@midwayjs/koa](/api/web-koa.md) #### class - [BodyParserMiddleware](/api/web-koa/class/BodyParserMiddleware.md) - [Configuration](/api/web-koa/class/Configuration.md) - [Framework](/api/web-koa/class/Framework.md) - [SiteFileMiddleware](/api/web-koa/class/SiteFileMiddleware.md) #### interface - [BodyParserOptions](/api/web-koa/interface/BodyParserOptions.md) - [Context](/api/web-koa/interface/Context.md) - [IMidwayKoaConfigurationOptions](/api/web-koa/interface/IMidwayKoaConfigurationOptions.md) - [IWebMiddleware](/api/web-koa/interface/IWebMiddleware.md) - [State](/api/web-koa/interface/State.md) ### ws - [@midwayjs/ws](/api/ws.md) #### class - [Configuration](/api/ws/class/Configuration.md) - [Framework](/api/ws/class/Framework.md) #### interface - [Context](/api/ws/interface/Context.md) ## docs ### 1.0.0 #### controller midway 使用 koa-router 作为路由的承载者,同时在 ts 的语法上做了一些简化,我们将路由和控制器放在了一起,使用装饰器来标注路由。 - [路由和控制器](/docs/1.0.0/controller.md): midway 使用 koa-router 作为路由的承载者,同时在 ts 的语法上做了一些简化,我们将路由和控制器放在了一起,使用装饰器来标注路由。 #### debug 一个更简单的 Debug 方案,新版本 VSCode 已经支持了 autoAttach。 - [Debug](/docs/1.0.0/debug.md): 一个更简单的 Debug 方案,新版本 VSCode 已经支持了 autoAttach。 #### decorator midway 内部有一套标准的装饰器管理器,用来所有装饰器对接 IoC 容器,扫描和扩展,我们称之为 decoratorManager 。 - [高级装饰器 API](/docs/1.0.0/decorator.md): midway 内部有一套标准的装饰器管理器,用来所有装饰器对接 IoC 容器,扫描和扩展,我们称之为 decoratorManager 。 #### deploy 构建打包 - [部署](/docs/1.0.0/deploy.md): 构建打包 #### docker 在 Docker 中部署,由于 egg 体系会根据 cpu 核数来启动进程,而 Docker 中获取的 cpu 数是错误的,就会导致启动非常多的 worker 进程。 - [Docker 中进程过多](/docs/1.0.0/docker.md): 在 Docker 中部署,由于 egg 体系会根据 cpu 核数来启动进程,而 Docker 中获取的 cpu 数是错误的,就会导致启动非常多的 worker 进程。 #### extensions - [介绍](/docs/1.0.0/extensions/axios.md): 组件扩展功能从 2.0 开始,请访问新版本文档。 #### framework 框架增强注入 - [框架增强](/docs/1.0.0/framework.md): 框架增强注入 #### hooks - [介绍](/docs/1.0.0/hooks/hooks_intro.md): 一体化功能从 2.0 开始,请访问新版本文档。 #### injection Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 - [依赖注入手册](/docs/1.0.0/injection.md): Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 #### intro 介绍 - [基础介绍](/docs/1.0.0/intro.md): 介绍 #### middleware 当前,midway v1 的全局中间件为 egg 提供,使用 egg 写法,和路由中间件有所区别,并且不能使用注入的形式使用。 - [全局中间件](/docs/1.0.0/middleware.md): 当前,midway v1 的全局中间件为 egg 提供,使用 egg 写法,和路由中间件有所区别,并且不能使用注入的形式使用。 #### quickstart 安装 Node 环境 - [快速上手](/docs/1.0.0/quickstart.md): 安装 Node 环境 #### serverless - [介绍](/docs/1.0.0/serverless/serverless_intro.md): Serverless 功能从 2.0 开始,请访问新版本文档。 #### test 经过大量的实践,我们沉淀出了一套标准的测试工具集。 - [应用测试](/docs/1.0.0/test.md): 经过大量的实践,我们沉淀出了一套标准的测试工具集。 #### test_more 测试应用 - [midway 高级测试方案](/docs/1.0.0/test_more.md): 测试应用 #### tool - [midway 工具集](/docs/1.0.0/tool/cli.md): midway-bin #### ts_guide Typescript 和 Javascript 既相似又有着许多不同,以往的 Node.js 应用和模块大多都是 Javascript 写的。 - [TS 新手指南](/docs/1.0.0/ts_guide.md): Typescript 和 Javascript 既相似又有着许多不同,以往的 Node.js 应用和模块大多都是 Javascript 写的。 ### 2.0.0 #### alinode 准备工作 - [接入 Alinode](/docs/2.0.0/alinode.md): 准备工作 #### aspect 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 - [方法拦截器(切面)](/docs/2.0.0/aspect.md): 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 #### body-parser Bodyparser 一般用来对 post 请求的请求体进行解析,是比较常用的 Web 中间件之一。 - [BodyParser](/docs/2.0.0/body-parser.md): Bodyparser 一般用来对 post 请求的请求体进行解析,是比较常用的 Web 中间件之一。 #### cfork 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 - [使用 cfork](/docs/2.0.0/cfork.md): 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 #### change_start_dir 在某些特殊场景下,可以修改源码所在的 src 目录。 - [修改源码目录](/docs/2.0.0/change_start_dir.md): 在某些特殊场景下,可以修改源码所在的 src 目录。 #### component_development 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: - [组件开发](/docs/2.0.0/component_development.md): 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: #### container Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 - [依赖注入](/docs/2.0.0/container.md): Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 #### context_definition 在某些场景下,需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 - [扩展上下文定义](/docs/2.0.0/context_definition.md): 在某些场景下,需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 #### controller 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责解析用户的输入,处理后返回相应的结果。 - [控制器(Controller)](/docs/2.0.0/controller.md): 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责解析用户的输入,处理后返回相应的结果。 #### cookies HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 - [Cookies](/docs/2.0.0/cookies.md): HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 #### cors 跨源资源共享(CORS) (或通俗地译为跨域资源共享)是一种基于HTTP头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),这样浏览器可以访问加载这些资源。 - [跨域 CORS](/docs/2.0.0/cors.md): 跨源资源共享(CORS) (或通俗地译为跨域资源共享)是一种基于HTTP头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),这样浏览器可以访问加载这些资源。 #### custom_eggjs 在 Midway 体系中,我们通过 @midwayjs/web ,支持了 EggJS 作为上层框架,并将 Web 层传统的控制器、服务等分层,以及依赖注入带到了 EggJS 体系。 - [自定义 EggJS 框架接入](/docs/2.0.0/custom_eggjs.md): 在 Midway 体系中,我们通过 @midwayjs/web ,支持了 EggJS 作为上层框架,并将 Web 层传统的控制器、服务等分层,以及依赖注入带到了 EggJS 体系。 #### debugger 在 VSCode 中调试 - [本地调试](/docs/2.0.0/debugger.md): 在 VSCode 中调试 #### decorator_api Midway 内部有一套标准的装饰器管理 API,用来将装饰器对接依赖注入容器,实现扫描和扩展,这些 API 方法我们都从 @midwayjs/decorator  包进行导出。 - [高级装饰器 API](/docs/2.0.0/decorator_api.md): Midway 内部有一套标准的装饰器管理 API,用来将装饰器对接依赖注入容器,实现扫描和扩展,这些 API 方法我们都从 @midwayjs/decorator  包进行导出。 #### decorator_index | | 场景 | 作用 | - [现有装饰器索引](/docs/2.0.0/decorator_index.md): | | 场景 | 作用 | #### deployment Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 - [启动和部署](/docs/2.0.0/deployment.md): Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 #### eggjs Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 - [EggJS](/docs/2.0.0/eggjs.md): Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 #### env_config 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 - [多环境配置](/docs/2.0.0/env_config.md): 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 #### environment Node.js 应用一般通过 NODE_ENV  来获取环境变量,来满足不同环境下的不同需求。比如在 production  环境下,开启缓存,优化性能,而在 development  环境下,会打开所有的日志开关,输出详细的错误信息等等。 - [运行环境](/docs/2.0.0/environment.md): Node.js 应用一般通过 NODE_ENV  来获取环境变量,来满足不同环境下的不同需求。比如在 production  环境下,开启缓存,优化性能,而在 development  环境下,会打开所有的日志开关,输出详细的错误信息等等。 #### express 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 - [Express](/docs/2.0.0/express.md): 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 #### extensions - [HTTP 请求(Axios)](/docs/2.0.0/extensions/axios.md): midway 包裹了 axios 包,使得在代码中可以简单的使用 axios 接口。 - [缓存(Cache)](/docs/2.0.0/extensions/cache.md): Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 - [Consul](/docs/2.0.0/extensions/consul.md): consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 - [对象存储(COS)](/docs/2.0.0/extensions/cos.md): 本文介绍了如何使用 midway 接入腾讯云 COS。 - [GraphQL](/docs/2.0.0/extensions/graphql.md): 概述 - [gRPC](/docs/2.0.0/extensions/grpc.md): gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 - [MongoDB](/docs/2.0.0/extensions/mongo.md): 在这一章节中,我们选择 Typegoose 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 - [Database(TypeORM)](/docs/2.0.0/extensions/orm.md): TypeORM  是  node.js  现有社区最成熟的对象关系映射器(ORM )。Midway 和 TypeORM 搭配,使开发更简单。 - [对象存储(OSS)](/docs/2.0.0/extensions/oss.md): 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 - [Passport](/docs/2.0.0/extensions/passport.md): 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Node.js 中最流行的 Passport 库。 - [进程共享(ProcessAgent)](/docs/2.0.0/extensions/process_agent.md): midway 封装了 @midwayjs/process-agent 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 - [RabbitMQ](/docs/2.0.0/extensions/rabbitmq.md): 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务 A 负责产生消息给消息队列,而服务 B 则负责消费消息队列中的任务。 - [Redis](/docs/2.0.0/extensions/redis.md): 这里介绍如何快速在 Midway 中使用 Redis。 - [模板渲染](/docs/2.0.0/extensions/render.md): 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 - [Sequelize](/docs/2.0.0/extensions/sequelize.md): 使用方法: - [Swagger](/docs/2.0.0/extensions/swagger.md): Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。Swagger 让部署管理和使用功能强大的 API 从未如此简单。 - [TableStore](/docs/2.0.0/extensions/tablestore.md): 本文介绍了如何使用 midway 接入阿里云 TableStore。 - [任务调度(Task)](/docs/2.0.0/extensions/task.md): @midwayjs/task 是为了解决任务系列的模块,例如分布式定时任务、延迟任务调度。例如每日定时报表邮件发送、订单2小时后失效等工作。 #### file_upload 一、使用场景 - [FaaS 文件上传](/docs/2.0.0/file_upload.md): 一、使用场景 #### framework_development Midway 提供了一套可以自定义框架的能力,如果 Midway 没有提供某种上层框架能力,则可以自定义接入。 - [框架扩展](/docs/2.0.0/framework_development.md): Midway 提供了一套可以自定义框架的能力,如果 Midway 没有提供某种上层框架能力,则可以自定义接入。 #### framework_problem 多个 @midwayjs/decorator 警告 - [常见框架错误](/docs/2.0.0/framework_problem.md): 多个 @midwayjs/decorator 警告 #### git_problem 文件名大小写问题 - [常见 git 问题](/docs/2.0.0/git_problem.md): 文件名大小写问题 #### hooks - [非 Serverless 环境使用一体化](/docs/2.0.0/hooks/application_integration.md): 在 Midway Serverless 2.0 中,我们支持了 Web 全栈应用的开发。 - [接口开发 & 前端调用](/docs/2.0.0/hooks/hooks_api.md): “零” API 调用 - [纯接口项目增加 Hooks 支持](/docs/2.0.0/hooks/hooks_bff.md): 如果你之前的项目是 Midway Web 或者 Midway FaaS 的纯接口项目,想在代码中使用纯函数的开发方式,那么可以参考本文档。 - [内置 Hooks](/docs/2.0.0/hooks/hooks_builtin.md): useContext - [运行时配置 & Hooks 组件](/docs/2.0.0/hooks/hooks_component.md): 2.0 版 - [项目初始化](/docs/2.0.0/hooks/hooks_create.md): 创建 - [自定义前端 SDK](/docs/2.0.0/hooks/hooks_custom_request.md): Midway Hooks 默认使用浏览器指定的 fetch 发送请求,为了支持不同场景,开发者可以自定义请求函数。 - [本地调试](/docs/2.0.0/hooks/hooks_debug.md): VSCode - [Web 中间件](/docs/2.0.0/hooks/hooks_middleware.md): 在 2.0 版本中,Midway Hooks 支持三种形式的中间件,用来覆盖不同的使用诉求。 - [小程序一体化](/docs/2.0.0/hooks/hooks_miniprogram.md): 小程序一体化是 Midway.js 团队与 Rax 团队合作的产品,通过 Midway.js 对一体化的支持与 Rax 对小程序的支持,我们可以为小程序带去更好的研发体验。 - [路由](/docs/2.0.0/hooks/hooks_route.md): Midway Hooks 的路由机制是文件路由,我们会根据 目录/文件/导出的方法 来分析出路由配置。同时我们也提供了相应的配置选项。 - [Hooks 语法](/docs/2.0.0/hooks/hooks_syntax.md): Midway Hooks 使用了类似于 React Hooks 的语法,允许开发者通过 Function + Hooks 的方式,获取当前请求数据并提供 Web 服务。 - [介绍](/docs/2.0.0/hooks/intro.md): ✨ 特性 - [OSS 文件上传](/docs/2.0.0/hooks/oss_upload.md): 由于函数网关的问题,文件无法直传至函数,但我们也提供了两种方式来解决文件上传的问题。 #### how_to_install_nodejs 使用场景 - [如何安装 Node.js 环境](/docs/2.0.0/how_to_install_nodejs.md): 使用场景 #### how_to_update_midway midway 项目的依赖使用 lerna 发布,请不要: - [如何更新 Midway](/docs/2.0.0/how_to_update_midway.md): midway 项目的依赖使用 lerna 发布,请不要: #### intro Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架。 - [介绍](/docs/2.0.0/intro.md): Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架。 #### koa Koa 是一个非常轻量易用的 Web 框架。 - [Koa](/docs/2.0.0/koa.md): Koa 是一个非常轻量易用的 Web 框架。 #### lifecycle 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 - [生命周期](/docs/2.0.0/lifecycle.md): 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 #### logger 简介 - [日志](/docs/2.0.0/logger.md): 简介 #### midway_component 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 - [使用组件](/docs/2.0.0/midway_component.md): 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 #### midway_slow_problem Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 - [关于 Midway 启动慢的问题](/docs/2.0.0/midway_slow_problem.md): Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 #### multi_framework_start 所谓的多框架启动,指的是多个能提供服务的上层框架,在一个进程中同时提供服务。 - [多框架研发](/docs/2.0.0/multi_framework_start.md): 所谓的多框架启动,指的是多个能提供服务的上层框架,在一个进程中同时提供服务。 #### npm_problem 1、不希望生成 package-lock.json - [常见 npm 问题](/docs/2.0.0/npm_problem.md): 1、不希望生成 package-lock.json #### pipeline 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 - [代码流程控制](/docs/2.0.0/pipeline.md): 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 #### pm2 PM2 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 - [使用 pm2](/docs/2.0.0/pm2.md): PM2 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 #### prometheus Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 - [接入 Prometheus](/docs/2.0.0/prometheus.md): Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 #### release_schedule | Release | Status | Codename | Initial Release | Active LTS Start | Maintenance LTS Start | End-of-life | - [Midway 维护计划](/docs/2.0.0/release_schedule.md): | Release | Status | Codename | Initial Release | Active LTS Start | Maintenance LTS Start | End-of-life | #### req_res_app Midway 框架会根据不同的场景来启动不同的应用,前文提到,我们默认选用 EggJS 作为我们的 Web 框架,也可以使用 Express 或者 Koa。 - [请求、响应、应用](/docs/2.0.0/req_res_app.md): Midway 框架会根据不同的场景来启动不同的应用,前文提到,我们默认选用 EggJS 作为我们的 Web 框架,也可以使用 Express 或者 Koa。 #### router_table 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 - [Web 路由表](/docs/2.0.0/router_table.md): 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 #### sample 官方示例 - [示例列表](/docs/2.0.0/sample.md): 官方示例 #### serverless - [API 网关](/docs/2.0.0/serverless/aliyun_trigger_apigw.md): API 网关在阿里云函数体系中比较特殊,他类似于创建一个无触发器函数,通过平台网关的绑定到特定的路径上。 - [事件触发器(Event)](/docs/2.0.0/serverless/aliyun_trigger_event.md): 发布不包含触发器的函数,这是最简单的类型,可以直接通过 event 手动触发参数,也可以在平台绑定其他触发器。 - [HTTP 触发器](/docs/2.0.0/serverless/aliyun_trigger_http.md): 阿里云的 HTTP 触发器和其他平台的有所区别,是独立于 API 网关的另一套服务于 HTTP 场景的触发器。相比于 API 网关,该触发器更易于使用和配置。 - [MNS 触发器(消息队列)](/docs/2.0.0/serverless/aliyun_trigger_mns.md): 请务必注意,阿里云消息队列会对 Topic 和 Queue 产生一定的费用。 - [OSS 触发器(对象存储)](/docs/2.0.0/serverless/aliyun_trigger_oss.md): OSS 用于存储一些资源文件,是阿里云的资源存储产品。 当 OSS 中有文件创建,更新,对应的函数就会被触发而执行。 - [Timer 触发器(定时任务)](/docs/2.0.0/serverless/aliyun_trigger_timer.md): 定时任务触发器用于定时执行一个函数。定时有两种方式,时间间隔(every)和 cron 格式。 - [应用迁移方案说明](/docs/2.0.0/serverless/app_deploy_serverless.md): 迁移方案 - [阿里云发布 FAQ](/docs/2.0.0/serverless/deploy_aliyun_faq.md): 包大小问题 - [腾讯云发布 FAQ](/docs/2.0.0/serverless/deploy_tencent_faq.md): 用户鉴权 - [发布到阿里云 FC](/docs/2.0.0/serverless/deploy_to_aliyun.md): 配置 - [发布到腾讯云 SCF](/docs/2.0.0/serverless/deploy_to_tencent.md): 配置 - [Egg/Midway 应用迁移](/docs/2.0.0/serverless/migrate_egg.md): Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 egg/midway 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 - [Express 应用迁移](/docs/2.0.0/serverless/migrate_express.md): Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 express 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 - [应用迁移 FAQ](/docs/2.0.0/serverless/migrate_faq.md): 这套方案和平台的迁移方案有什么区别? - [Koa 应用迁移](/docs/2.0.0/serverless/migrate_koa.md): Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 koa 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 - [静态网站托管](/docs/2.0.0/serverless/migrate_static.md): 此方案适用于纯前端项目(React、vue 等)托管到 Serverless 平台(阿里云,腾讯云等)。 - [聚合部署](/docs/2.0.0/serverless/serverless_aggr.md): Midway 针对 HTTP 场景,提供了一种聚合部署的方式,在开发时和传统 Web 应用类似,在部署时将多个路由部署在同一个函数容器中,可以节省冷启动时间,节省费用。 - [函数上下文](/docs/2.0.0/serverless/serverless_context.md): Event 转换 - [开发函数](/docs/2.0.0/serverless/serverless_dev.md): 初始化代码 - [部署环境](/docs/2.0.0/serverless/serverless_environment.md): 在 Serverless 场景,由于环境和传统的容器不同(平台提供,无法修改),我们在启动时,使用传统的命令透传环境变量,函数是无法正确的读取到的。 - [默认错误行为](/docs/2.0.0/serverless/serverless_error.md): 错误值处理 - [介绍](/docs/2.0.0/serverless/serverless_intro.md): Midway Serverless 能做什么 - [Serverless 触发器 POST 情况差异](/docs/2.0.0/serverless/serverless_post_difference.md): 阿里云 API 网关 - [测试函数](/docs/2.0.0/serverless/serverless_testing.md): HTTP 类的函数 - [Serverless 函数部署为应用](/docs/2.0.0/serverless/serverless_to_app.md): Midway Serverless 在 v1.0 版本已经支持部署到各个 Serverless 云平台,例如阿里云 FC、腾讯云 SCF 等。从 v2.0 版本开始支持已有的 Serverless 函数以应用模式部署在你的私有服务器上。 - [从 Serverless v1 迁移到 v2](/docs/2.0.0/serverless/serverless_v1_upgrade_serverless_v2.md): 本文章介绍如何从 Serverless v1.0 迁移到 Serverless v2.0。 - [f.yml 定义](/docs/2.0.0/serverless/serverless_yml.md): 概述 - [API 网关(HTTP)](/docs/2.0.0/serverless/tencent_trigger_apigw.md): API 网关在腾讯云函数体系中类似于 HTTP 函数,我们通过它将函数发布为 HTTP 服务。 - [CMQ 触发器(消息队列)](/docs/2.0.0/serverless/tencent_trigger_cmq.md): CMQ(mq) 触发器,订阅的是腾讯云的消息队列服务。 - [COS 触发器(对象存储)](/docs/2.0.0/serverless/tencent_trigger_cos.md): COS 是腾讯云用于存储一些资源文件的服务。 - [Timer 触发器(定时任务)](/docs/2.0.0/serverless/tencent_trigger_timer.md): 定时任务触发器用于定时执行一个函数。腾讯云 Timer 触发器目前只支持 cron 格式。 #### service 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 - [服务和注入](/docs/2.0.0/service.md): 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 #### service_factory 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 - [服务工厂](/docs/2.0.0/service_factory.md): 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 #### session Session 在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。 - [Session](/docs/2.0.0/session.md): Session 在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。 #### socketio Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 - [SocketIO](/docs/2.0.0/socketio.md): Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 #### start_app 快速初始化 - [创建第一个应用](/docs/2.0.0/start_app.md): 快速初始化 #### static_file 静态资源一般用来托管前端文件(js/css/html/png)等。 - [静态资源(Static File)](/docs/2.0.0/static_file.md): 静态资源一般用来托管前端文件(js/css/html/png)等。 #### testing 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 - [测试](/docs/2.0.0/testing.md): 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 #### tool - [midwayjs/cli](/docs/2.0.0/tool/cli.md): @midwayjs/cli  是新版本的 Midway 体系工具链,和 Serverless,以及原应用的工具链进行了整合。 - [midwayjs/egg-ts-helper](/docs/2.0.0/tool/egg-ts-helper.md): 针对 midway 支持 Egg.js 的场景,重写了原 egg-ts-helper 包,移除了原有的 TS,AST 分析等大依赖。 - [检查工具](/docs/2.0.0/tool/luckyeye.md): Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。@midwayjs/luckyeye  包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 - [Lint 工具、规则和格式化](/docs/2.0.0/tool/mwts.md): Midway 的框架和业务代码都是由 TypeScript 编写的,默认 Midway 提供了一套默认的 lint、编辑器以及格式化规则,用于更方便的进行开发和测试。 - [TypeORM Model Generator](/docs/2.0.0/tool/typeorm_generator.md): 感谢社区用户 @youtiao66 提供此模块。 #### ts_problem TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 - [常见 TS 问题](/docs/2.0.0/ts_problem.md): TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 #### v1_upgrade_v2 手动迁移步骤 - [从 Midway v1 升级到 v2](/docs/2.0.0/v1_upgrade_v2.md): 手动迁移步骤 #### validate 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 joi ,同时也提供了参数的转换能力,这个能力来自于 class-transformer 。 - [参数校验和转换](/docs/2.0.0/validate.md): 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 joi ,同时也提供了参数的转换能力,这个能力来自于 class-transformer 。 #### web_middleware Web 中间件是在控制器调用  之前  和 之后(部分) 调用的函数。 中间件函数可以访问请求和响应对象。 - [Web 中间件](/docs/2.0.0/web_middleware.md): Web 中间件是在控制器调用  之前  和 之后(部分) 调用的函数。 中间件函数可以访问请求和响应对象。 #### ws ws 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. - [WebSocket](/docs/2.0.0/ws.md): ws 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. ### 3.0.0 #### aspect 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 - [拦截器(AOP)](/docs/3.0.0/aspect.md): 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 #### auto_run 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 - [自执行代码](/docs/3.0.0/auto_run.md): 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 #### awesome_midway 以下列举了与 Midwayjs 相关的优质社区项目 - [Awesome Midway](/docs/3.0.0/awesome_midway.md): 以下列举了与 Midwayjs 相关的优质社区项目 #### built_in_service 在 Midway 中,提供了众多的内置对象,方便用户使用。 - [内置服务](/docs/3.0.0/built_in_service.md): 在 Midway 中,提供了众多的内置对象,方便用户使用。 #### change_start_dir 在某些特殊场景下,可以修改源码所在的 src 目录。 - [修改源码目录](/docs/3.0.0/change_start_dir.md): 在某些特殊场景下,可以修改源码所在的 src 目录。 #### component_development 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: - [自定义组件](/docs/3.0.0/component_development.md): 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: #### container Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 - [依赖注入](/docs/3.0.0/container.md): Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 #### context_definition 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 - [扩展上下文定义](/docs/3.0.0/context_definition.md): 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 #### contributing Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 - [向 Midway 贡献](/docs/3.0.0/contributing.md): Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 #### controller 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 解析用户的输入,处理后返回相应的结果。 - [路由和控制器](/docs/3.0.0/controller.md): 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 解析用户的输入,处理后返回相应的结果。 #### cookie_session HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: - [Cookies 和 Session](/docs/3.0.0/cookie_session.md): HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: #### cusom_response 在大多数正常的逻辑中,返回数据只需要 return 相应的对象。 - [自定义数据响应](/docs/3.0.0/cusom_response.md): 在大多数正常的逻辑中,返回数据只需要 return 相应的对象。 #### custom_decorator 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: - [自定义装饰器](/docs/3.0.0/custom_decorator.md): 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: #### custom_error 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 - [自定义错误](/docs/3.0.0/custom_error.md): 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 #### data_listener 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 - [数据订阅](/docs/3.0.0/data_listener.md): 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 #### data_response 从 v3.17.0 开始,框架添加了 ServerResponse 和 HttpServerResponse 的实现。 - [数据响应](/docs/3.0.0/data_response.md): 从 v3.17.0 开始,框架添加了 ServerResponse 和 HttpServerResponse 的实现。 #### data_source 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 - [数据源管理](/docs/3.0.0/data_source.md): 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 #### debugger 本章节介绍如何在常用编辑器中调试 Midway 项目。 - [调试](/docs/3.0.0/debugger.md): 本章节介绍如何在常用编辑器中调试 Midway 项目。 #### decorator_index Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 - [现有装饰器索引](/docs/3.0.0/decorator_index.md): Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 #### deployment Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 - [启动和部署](/docs/3.0.0/deployment.md): Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 #### env_config 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 - [多环境配置](/docs/3.0.0/env_config.md): 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 #### environment Node.js 应用一般通过 NODE_ENV 来获取环境变量,来满足不同环境下的不同需求。比如在 production 环境下,开启缓存,优化性能,而在 development 环境下,会打开所有的日志开关,输出详细的错误信息等等。 - [运行环境](/docs/3.0.0/environment.md): Node.js 应用一般通过 NODE_ENV 来获取环境变量,来满足不同环境下的不同需求。比如在 production 环境下,开启缓存,优化性能,而在 development 环境下,会打开所有的日志开关,输出详细的错误信息等等。 #### error_code 以下是框架内置的错误,随着时间推移,我们会不断增加。 - [框架错误码](/docs/3.0.0/error_code.md): 以下是框架内置的错误,随着时间推移,我们会不断增加。 #### error_filter Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 - [异常处理](/docs/3.0.0/error_filter.md): Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 #### esm 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 - [ESModule 使用指南](/docs/3.0.0/esm.md): 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 #### extensions - [Alinode](/docs/3.0.0/extensions/alinode.md): 准备工作 - [HTTP 请求](/docs/3.0.0/extensions/axios.md): 简单的 HTTP 请求 - [任务队列](/docs/3.0.0/extensions/bull.md): 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题。 - [任务队列](/docs/3.0.0/extensions/bullmq.md): 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题: - [文件上传](/docs/3.0.0/extensions/busboy.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 - [缓存](/docs/3.0.0/extensions/cache.md): Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 - [缓存](/docs/3.0.0/extensions/caching.md): 缓存是一个伟大而简单的技术,有助于提高你的应用程序的性能。本组件提供了缓存相关的能力,你可以将数据缓存到不同的数据源,也可以针对不同场景建立多级缓存,提高数据访问速度。 - [验证码](/docs/3.0.0/extensions/captcha.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用验证码组件,支持 图片验证码、计算表达式 等类型验证码。 - [角色鉴权](/docs/3.0.0/extensions/casbin.md): Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。 - [cfork](/docs/3.0.0/extensions/cfork.md): 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 - [代码染色](/docs/3.0.0/extensions/code_dye.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的代码染色组件。 - [Consul](/docs/3.0.0/extensions/consul.md): consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 - [腾讯云对象存储(COS)](/docs/3.0.0/extensions/cos.md): 本文介绍了如何使用 midway 接入腾讯云 COS。 - [本地任务](/docs/3.0.0/extensions/cron.md): 和 bull 组件不同,cron 组件提供的是本地任务能力,即在每台机器的每个进程都会执行。如需不同机器或者不同进程之间只执行一次任务,请使用 bull 组件 。 - [跨域](/docs/3.0.0/extensions/cross_domain.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用跨域组件,支持 cors 、jsonp 多种模式。 - [EggJS](/docs/3.0.0/extensions/egg.md): Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 - [ETCD](/docs/3.0.0/extensions/etcd.md): etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中可以作为服务注册于发现,也可以作为 key-value 存储的中间件。 - [Express](/docs/3.0.0/extensions/express.md): 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 - [gRPC](/docs/3.0.0/extensions/grpc.md): gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 - [HTTP 代理](/docs/3.0.0/extensions/http-proxy.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的 HTTP 请求代理组件,支持 GET、POST 等多种请求方法。 - [多语言](/docs/3.0.0/extensions/i18n.md): Midway 提供了多语言组件,让业务可以快速指定不同的语言,展示不同的文案,也可以在 HTTP 场景配合请求参数,请求头等方式来使用。 - [信息查看](/docs/3.0.0/extensions/info.md): Midway 提供了 info 组件,用于展示应用的基本信息,方便排查问题。 - [JWT](/docs/3.0.0/extensions/jwt.md): JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 - [Kafka](/docs/3.0.0/extensions/kafka.md): 在复杂系统的架构中,事件流是很重要的一环,包括从事件源中(数据库、传感器、移动设备等)以事件流的方式去实时捕获数据,持久化事件流方便检索,并实时和回顾操作处理响应事件流。 - [Koa](/docs/3.0.0/extensions/koa.md): Koa 是一个非常轻量易用的 Web 框架。本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 - [MikroORM](/docs/3.0.0/extensions/mikro.md): 本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。 - [MongoDB](/docs/3.0.0/extensions/mongodb.md): 在这一章节中,我们选择 Typegoose 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 - [MQTT](/docs/3.0.0/extensions/mqtt.md): MQTT是用于物联网 (IoT) 的OASIS标准消息传递协议。它被设计为非常轻量级的发布/订阅消息传输,非常适合以较小的代码占用空间和最小的网络带宽连接远程设备。MQTT目前广泛应用于汽车、制造、电信、石油和天然气等行业。 - [TypeORM](/docs/3.0.0/extensions/orm.md): TypeORM 是 node.js 现有社区最成熟的对象关系映射器(ORM )。本文介绍如何在 Midway 中使用 TypeORM 。 - [阿里云对象存储(OSS)](/docs/3.0.0/extensions/oss.md): 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 - [链路追踪](/docs/3.0.0/extensions/otel.md): Midway 采用社区最新的 open-telemetry 方案,其前身是知名的 OpenTracing 和 OpenCensus 规范,现阶段也是 CNCF 的孵化项目,社区许多知名的大公司如 Amazon,Dynatrace,Microsoft,Google,Datadog,Splunk 等都有使用。 - [身份验证](/docs/3.0.0/extensions/passport.md): 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Nodejs 中最流行的 Passport 库。 - [pm2](/docs/3.0.0/extensions/pm2.md): PM2 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 - [进程 Agent](/docs/3.0.0/extensions/process_agent.md): midway 封装了 @midwayjs/process-agent 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 - [Prometheus](/docs/3.0.0/extensions/prometheus.md): Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 - [RabbitMQ](/docs/3.0.0/extensions/rabbitmq.md): 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务A负责产生消息给消息队列,而服务B则负责消费消息队列中的任务。 - [Redis](/docs/3.0.0/extensions/redis.md): 这里介绍如何快速在 Midway 中使用 Redis。 - [模板渲染](/docs/3.0.0/extensions/render.md): 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 - [安全](/docs/3.0.0/extensions/security.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用安全组件,支持 csrf 、xss 等多种安全策略。 - [Sequelize](/docs/3.0.0/extensions/sequelize.md): 本文档介绍如何在 Midway 中使用 Sequelize。 - [SocketIO](/docs/3.0.0/extensions/socketio.md): Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 - [静态文件托管](/docs/3.0.0/extensions/static_file.md): midway 提供了基于 koa-static-cache 模块的静态资源托管组件。 - [Swagger](/docs/3.0.0/extensions/swagger.md): 基于最新的 OpenAPI 3.0.3 实现了新版的 Swagger 组件。 - [TableStore](/docs/3.0.0/extensions/tablestore.md): 本文介绍了如何使用 midway 接入阿里云 TableStore。 - [标签组件](/docs/3.0.0/extensions/tags.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用标签组件。 - [租户](/docs/3.0.0/extensions/tenant.md): 这里介绍如何快速在 Midway 中使用租户组件。 - [文件上传](/docs/3.0.0/extensions/upload.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 - [参数校验](/docs/3.0.0/extensions/validate.md): 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 joi 。 - [WebSocket](/docs/3.0.0/extensions/ws.md): ws 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. #### faq - [关于 Alias Path](/docs/3.0.0/faq/alias_path.md): 我们并不建议使用 Alias Path, Node 和 TS 原生不支持这个功能,即使有,现在也是通过各种 Hack 手段来实现(从 v18 开始,Node.js 已经有 exports 的方案,但是类型还未支持,可以等后续)。 - [常见框架问题](/docs/3.0.0/faq/framework_problem.md): 多个 @midwayjs/core 警告 - [常见 git 问题](/docs/3.0.0/faq/git_problem.md): 文件名大小写问题 - [常见 npm 问题](/docs/3.0.0/faq/npm_problem.md): 1、不希望生成 package-lock.json - [常见 TS 问题](/docs/3.0.0/faq/ts_problem.md): TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 #### guard 从 v3.6.0 开始,Midway 提供守卫能力。 - [守卫](/docs/3.0.0/guard.md): 从 v3.6.0 开始,Midway 提供守卫能力。 #### hooks - [接口开发](/docs/3.0.0/hooks/api.md): 路由 - [Hooks](/docs/3.0.0/hooks/builtin-hooks.md): Midway Hooks 可以通过使用 Hooks 函数来获取运行时上下文。 - [前端请求客户端](/docs/3.0.0/hooks/client.md): 在 Midway Hooks 的全栈应用中,我们使用 @midwayjs/rpc 作为默认的请求客户端。所有生成的接口都会通过 @midwayjs/rpc 来调用服务端。 - [使用 Midway 组件](/docs/3.0.0/hooks/component.md): Midway 提供了一系列的组件,包含 Cache / Http / Redis 等。 - [项目配置](/docs/3.0.0/hooks/config.md): 我们通过项目根目录下的 midway.config.ts 来配置项目,具体的配置项如下。 - [跨域 CORS](/docs/3.0.0/hooks/cors.md): 在 Midway Hooks 中,可以通过 @koa/cors 来配置跨域功能。 - [调试](/docs/3.0.0/hooks/debug.md): 得益于编辑器的支持,我们可以快速的在本地调试应用。 - [部署](/docs/3.0.0/hooks/deploy.md): Midway Hooks 支持 Api Server 与一体化两种模式。 - [简易模式 & 文件系统路由](/docs/3.0.0/hooks/file-route.md): 简易模式 - [全栈套件](/docs/3.0.0/hooks/fullstack.md): 在 Midway Hooks 中,我们提供了 @midwayjs/hooks-kit 来快速开发全栈应用。目前我们提供了以下可直接使用的模版: - [介绍](/docs/3.0.0/hooks/intro.md): 一体化方案将逐步停止维护,已有项目可以继续使用,新建项目请谨慎选择。 - [Web 中间件](/docs/3.0.0/hooks/middleware.md): Midway Hooks 支持通过函数 + useContext() 来定义 Web 中间件。 - [Prisma ORM](/docs/3.0.0/hooks/prisma.md): 在 Midway Hooks 中,我们推荐使用 Prisma 来构建数据库,并实现我们静态类型安全的目标。 - [静态类型安全 + 运行时安全](/docs/3.0.0/hooks/safe.md): 使用 Prisma 和 @midwayjs/hooks 提供的 Validate 校验器,可以实现从前端到后端再到数据库的类型安全 + 运行时安全链路。 - [测试](/docs/3.0.0/hooks/test.md): 在 Midway Hooks 中,我们可以快速的对 Http 接口进行测试。 - [文件上传](/docs/3.0.0/hooks/upload.md): Midway Hooks 提供了 @midwayjs/hooks-upload 并配合 @midwayjs/upload 来实现纯函数 + 一体化项目中的文件上传功能。 - [参数校验](/docs/3.0.0/hooks/validate.md): 校验 #### how_to_install_nodejs 使用场景 - [如何安装 Node.js 环境](/docs/3.0.0/how_to_install_nodejs.md): 使用场景 #### how_to_update_midway 什么时候要更新 Midway - [如何更新 Midway](/docs/3.0.0/how_to_update_midway.md): 什么时候要更新 Midway #### intro Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 - [介绍](/docs/3.0.0/intro.md): Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 #### legacy - [MongoDB](/docs/3.0.0/legacy/mongodb.md): 本文档从 v3.4.0 版本起废弃。 - [TypeORM](/docs/3.0.0/legacy/orm.md): 本文档从 v3.4.0 版本起废弃。 - [Sequelize](/docs/3.0.0/legacy/sequelize.md): 本文档从 v3.4.0 版本起废弃。 - [任务调度](/docs/3.0.0/legacy/task.md): 本文档从 v3.6.0 版本起废弃。 #### lifecycle 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 - [生命周期](/docs/3.0.0/lifecycle.md): 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 #### logger 本文档为 @midwayjs/logger v2.0 版本的文档。 - [日志(v2)](/docs/3.0.0/logger.md): 本文档为 @midwayjs/logger v2.0 版本的文档。 #### logger_v3 Midway 为不同场景提供了一套统一的日志接入方式。通过 @midwayjs/logger 包导出的方法,可以方便的接入不同场景的日志系统。 - [日志](/docs/3.0.0/logger_v3.md): Midway 为不同场景提供了一套统一的日志接入方式。通过 @midwayjs/logger 包导出的方法,可以方便的接入不同场景的日志系统。 #### middleware Web 中间件是在控制器调用 之前 和 之后(部分)调用的函数。 中间件函数可以访问请求和响应对象。 - [Web 中间件](/docs/3.0.0/middleware.md): Web 中间件是在控制器调用 之前 和 之后(部分)调用的函数。 中间件函数可以访问请求和响应对象。 #### midway_component 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 - [使用组件](/docs/3.0.0/midway_component.md): 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 #### midway_slow_problem Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 - [关于 Midway 启动慢的问题](/docs/3.0.0/midway_slow_problem.md): Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 #### mock Midway 提供了内置的在开发和测试时模拟数据的能力。 - [数据模拟](/docs/3.0.0/mock.md): Midway 提供了内置的在开发和测试时模拟数据的能力。 #### ops - [服务器启动失败排查](/docs/3.0.0/ops/ecs_start_err.md): 应用启动失败是非常常见的现象,逻辑错误,编译错误,配置错误,环境问题,都有可能导致你的项目无法启动。 #### pipe 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: - [管道](/docs/3.0.0/pipe.md): 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: #### pipeline 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 - [流程控制](/docs/3.0.0/pipeline.md): 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 #### quick_guide 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 - [快速入门](/docs/3.0.0/quick_guide.md): 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 #### quickstart 技术选型 - [创建第一个应用](/docs/3.0.0/quickstart.md): 技术选型 #### release_schedule 下表是 Midway 整体的维护节奏和计划。 - [Midway 维护计划](/docs/3.0.0/release_schedule.md): 下表是 Midway 整体的维护节奏和计划。 #### req_res_app Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 - [Application 和 Context](/docs/3.0.0/req_res_app.md): Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 #### retry 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 - [重试机制](/docs/3.0.0/retry.md): 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 #### router_table 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 - [Web 路由表](/docs/3.0.0/router_table.md): 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 #### serverless - [部署到阿里云函数计算](/docs/3.0.0/serverless/aliyun_faas.md): 阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。 - [部署到 AWS Lambda](/docs/3.0.0/serverless/aws_lambda.md): AWS Lambda是Amazon Web Services (AWS)提供的无服务器计算服务。它允许您在无需预配或管理服务器的情况下运行代码。您可以为几乎任何类型的应用程序或后端服务运行代码,全部无需管理。 - [函数上下文](/docs/3.0.0/serverless/serverless_context.md): Event 转换 - [开发函数](/docs/3.0.0/serverless/serverless_dev.md): 初始化代码 - [默认错误行为](/docs/3.0.0/serverless/serverless_error.md): 错误值处理 - [介绍](/docs/3.0.0/serverless/serverless_intro.md): Midway Serverless 能做什么 - [Serverless 触发器 POST 情况差异](/docs/3.0.0/serverless/serverless_post_difference.md): 阿里云 API 网关 - [测试函数](/docs/3.0.0/serverless/serverless_testing.md): HTTP 类的函数 - [从 Serverless v2 迁移到 v3](/docs/3.0.0/serverless/serverless_v2_upgrade_serverless_v3.md): 基于 Midway 升级到 v3 的缘故,Serverless 体系也同步升级到了 v3 版本。 #### service 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 - [服务和注入](/docs/3.0.0/service.md): 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 #### service_factory 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 - [服务工厂](/docs/3.0.0/service_factory.md): 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 #### testing 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 - [测试](/docs/3.0.0/testing.md): 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 #### tool - [Midway CLI](/docs/3.0.0/tool/cli.md): 由于 CLI 底层能力都来源于社区现有的模块功能,为了减少过渡封装带来的维护成本和理解成本,CLI 中的各项功能都将逐步变为社区现有的模块,同时 CLI 库将停止继续迭代。 - [脚手架](/docs/3.0.0/tool/create_midway.md): Midway 编写了 create-midway 包,通过 npx 命令,可以方便的使用 npm init midway 命令创建脚手架。 - [egg:ts-helper](/docs/3.0.0/tool/egg-ts-helper.md): 针对 midway 支持 Egg.js 的场景,重写了原 egg-ts-helper 包,移除了原有的 TS,AST 分析等大依赖。 - [规则检查工具](/docs/3.0.0/tool/luckyeye.md): Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。@midwayjs/luckyeye 包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 - [Lint 和格式化](/docs/3.0.0/tool/mwts.md): Midway 的框架和业务代码都是由 TypeScript 编写的,默认 Midway 提供了一套默认的 lint、编辑器以及格式化规则,用于更方便的进行开发和测试。 - [开发工具](/docs/3.0.0/tool/mwtsc.md): 基于标准的 tsc 模块,midway 开发了一个简单的工具,用于本地开发和构建 ts 文件。 - [sequelize-auto-midway](/docs/3.0.0/tool/sequelize_generator.md): forked from sequelize/sequelize-auto - [typeorm:Model Generator](/docs/3.0.0/tool/typeorm_generator.md): 感谢社区用户 @youtiao66 提供此模块。 - [版本检查工具](/docs/3.0.0/tool/version_check.md): 由于依赖安装版本的不确定性,Midway 提供了 midway-version 这一版本检查工具,可以快速检查版本之间的兼容性错误。 #### upgrade_v3 本篇将介绍从 midway v2 升级为 midway v3 的方式。 - [2.x 升级指南](/docs/3.0.0/upgrade_v3.md): 本篇将介绍从 midway v2 升级为 midway v3 的方式。 ### aspect 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 - [拦截器(AOP)](/docs/aspect.md): 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 ### auto_run 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 - [自执行代码](/docs/auto_run.md): 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 ### awesome_midway 以下列举了与 Midwayjs 相关的优质社区项目 - [Awesome Midway](/docs/awesome_midway.md): 以下列举了与 Midwayjs 相关的优质社区项目 ### built_in_service 在 Midway 中,提供了众多的内置对象,方便用户使用。 - [内置服务](/docs/built_in_service.md): 在 Midway 中,提供了众多的内置对象,方便用户使用。 ### change_start_dir 在某些特殊场景下,可以修改源码所在的 src 目录。 - [修改源码目录](/docs/change_start_dir.md): 在某些特殊场景下,可以修改源码所在的 src 目录。 ### component_development 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: - [自定义组件](/docs/component_development.md): 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: ### container Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 - [依赖注入](/docs/container.md): Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 ### context_definition 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 - [扩展上下文定义](/docs/context_definition.md): 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 ### contributing Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 - [向 Midway 贡献](/docs/contributing.md): Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 ### controller 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 解析用户的输入,处理后返回相应的结果。 - [路由和控制器](/docs/controller.md): 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 解析用户的输入,处理后返回相应的结果。 ### cookie_session HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: - [Cookies 和 Session](/docs/cookie_session.md): HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: ### cusom_response 在大多数正常的逻辑中,返回数据只需要 return 相应的对象。 - [自定义数据响应](/docs/cusom_response.md): 在大多数正常的逻辑中,返回数据只需要 return 相应的对象。 ### custom_decorator 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: - [自定义装饰器](/docs/custom_decorator.md): 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: ### custom_error 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 - [自定义错误](/docs/custom_error.md): 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 ### data_listener 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 - [数据订阅](/docs/data_listener.md): 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 ### data_response 从 v3.17.0 开始,框架添加了 ServerResponse 和 HttpServerResponse 的实现。 - [数据响应](/docs/data_response.md): 从 v3.17.0 开始,框架添加了 ServerResponse 和 HttpServerResponse 的实现。 ### data_source 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 - [数据源管理](/docs/data_source.md): 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 ### debugger 本章节介绍如何在常用编辑器中调试 Midway 项目。 - [调试](/docs/debugger.md): 本章节介绍如何在常用编辑器中调试 Midway 项目。 ### decorator_index Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 - [现有装饰器索引](/docs/decorator_index.md): Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 ### deployment Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 - [启动和部署](/docs/deployment.md): Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 ### env_config 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 - [多环境配置](/docs/env_config.md): 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 ### environment Node.js 应用一般通过 NODE_ENV 来获取环境变量,来满足不同环境下的不同需求。比如在 production 环境下,开启缓存,优化性能,而在 development 环境下,会打开所有的日志开关,输出详细的错误信息等等。 - [运行环境](/docs/environment.md): Node.js 应用一般通过 NODE_ENV 来获取环境变量,来满足不同环境下的不同需求。比如在 production 环境下,开启缓存,优化性能,而在 development 环境下,会打开所有的日志开关,输出详细的错误信息等等。 ### error_code 以下是框架内置的错误,随着时间推移,我们会不断增加。 - [框架错误码](/docs/error_code.md): 以下是框架内置的错误,随着时间推移,我们会不断增加。 ### error_filter Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 - [异常处理](/docs/error_filter.md): Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 ### esm 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 - [ESModule 使用指南](/docs/esm.md): 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 ### extensions #### alinode 准备工作 - [Alinode](/docs/extensions/alinode.md): 准备工作 #### axios 简单的 HTTP 请求 - [HTTP 请求](/docs/extensions/axios.md): 简单的 HTTP 请求 #### bull 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题。 - [任务队列](/docs/extensions/bull.md): 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题。 #### bullmq 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题: - [任务队列](/docs/extensions/bullmq.md): 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题: #### busboy 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 - [文件上传](/docs/extensions/busboy.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 #### cache Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 - [缓存](/docs/extensions/cache.md): Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 #### caching 缓存是一个伟大而简单的技术,有助于提高你的应用程序的性能。本组件提供了缓存相关的能力,你可以将数据缓存到不同的数据源,也可以针对不同场景建立多级缓存,提高数据访问速度。 - [缓存](/docs/extensions/caching.md): 缓存是一个伟大而简单的技术,有助于提高你的应用程序的性能。本组件提供了缓存相关的能力,你可以将数据缓存到不同的数据源,也可以针对不同场景建立多级缓存,提高数据访问速度。 #### captcha 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用验证码组件,支持 图片验证码、计算表达式 等类型验证码。 - [验证码](/docs/extensions/captcha.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用验证码组件,支持 图片验证码、计算表达式 等类型验证码。 #### casbin Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。 - [角色鉴权](/docs/extensions/casbin.md): Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。 #### cfork 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 - [cfork](/docs/extensions/cfork.md): 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 #### code_dye 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的代码染色组件。 - [代码染色](/docs/extensions/code_dye.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的代码染色组件。 #### commander @midwayjs/commander 是一个基于 Midway IoC 容器的命令行组件,底层使用 commander.js 做参数解析与 help 输出。你可以用 Midway 熟悉的依赖注入方式组织命令、选项解析与业务逻辑,并将命令拆分为多个 Class。 - [命令行](/docs/extensions/commander.md): @midwayjs/commander 是一个基于 Midway IoC 容器的命令行组件,底层使用 commander.js 做参数解析与 help 输出。你可以用 Midway 熟悉的依赖注入方式组织命令、选项解析与业务逻辑,并将命令拆分为多个 Class。 #### consul consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 - [Consul](/docs/extensions/consul.md): consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 #### cos 本文介绍了如何使用 midway 接入腾讯云 COS。 - [腾讯云对象存储(COS)](/docs/extensions/cos.md): 本文介绍了如何使用 midway 接入腾讯云 COS。 #### cron 和 bull 组件不同,cron 组件提供的是本地任务能力,即在每台机器的每个进程都会执行。如需不同机器或者不同进程之间只执行一次任务,请使用 bull 组件 。 - [本地任务](/docs/extensions/cron.md): 和 bull 组件不同,cron 组件提供的是本地任务能力,即在每台机器的每个进程都会执行。如需不同机器或者不同进程之间只执行一次任务,请使用 bull 组件 。 #### cross_domain 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用跨域组件,支持 cors 、jsonp 多种模式。 - [跨域](/docs/extensions/cross_domain.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用跨域组件,支持 cors 、jsonp 多种模式。 #### crud 本文档介绍如何在 Midway 中使用 @midwayjs/crud。 - [CRUD](/docs/extensions/crud.md): 本文档介绍如何在 Midway 中使用 @midwayjs/crud。 #### egg Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 - [EggJS](/docs/extensions/egg.md): Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 #### etcd etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中可以作为服务注册于发现,也可以作为 key-value 存储的中间件。 - [ETCD](/docs/extensions/etcd.md): etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中可以作为服务注册于发现,也可以作为 key-value 存储的中间件。 #### events 事件组件是基于 eventemitter2 实现的,提供了强大的事件处理能力。 - [事件](/docs/extensions/events.md): 事件组件是基于 eventemitter2 实现的,提供了强大的事件处理能力。 #### express 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 - [Express](/docs/extensions/express.md): 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 #### grpc gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 - [gRPC](/docs/extensions/grpc.md): gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 #### http-proxy 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的 HTTP 请求代理组件,支持 GET、POST 等多种请求方法。 - [HTTP 代理](/docs/extensions/http-proxy.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的 HTTP 请求代理组件,支持 GET、POST 等多种请求方法。 #### i18n Midway 提供了多语言组件,让业务可以快速指定不同的语言,展示不同的文案,也可以在 HTTP 场景配合请求参数,请求头等方式来使用。 - [多语言](/docs/extensions/i18n.md): Midway 提供了多语言组件,让业务可以快速指定不同的语言,展示不同的文案,也可以在 HTTP 场景配合请求参数,请求头等方式来使用。 #### info Midway 提供了 info 组件,用于展示应用的基本信息,方便排查问题。 - [信息查看](/docs/extensions/info.md): Midway 提供了 info 组件,用于展示应用的基本信息,方便排查问题。 #### jwt JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 - [JWT](/docs/extensions/jwt.md): JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 #### kafka 在复杂系统的架构中,事件流是很重要的一环,包括从事件源中(数据库、传感器、移动设备等)以事件流的方式去实时捕获数据,持久化事件流方便检索,并实时和回顾操作处理响应事件流。 - [Kafka](/docs/extensions/kafka.md): 在复杂系统的架构中,事件流是很重要的一环,包括从事件源中(数据库、传感器、移动设备等)以事件流的方式去实时捕获数据,持久化事件流方便检索,并实时和回顾操作处理响应事件流。 #### koa Koa 是一个非常轻量易用的 Web 框架。本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 - [Koa](/docs/extensions/koa.md): Koa 是一个非常轻量易用的 Web 框架。本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 #### mcp MCP (Model Context Protocol) 是由 Anthropic 开发的开放标准协议,用于将 AI 模型与外部数据源和工具安全连接。它允许 AI 应用程序与各种服务进行语义集成,为 AI 模型提供了获取实时信息、执行操作和访问资源的标准化方式。 - [MCP (Model Context Protocol)](/docs/extensions/mcp.md): MCP (Model Context Protocol) 是由 Anthropic 开发的开放标准协议,用于将 AI 模型与外部数据源和工具安全连接。它允许 AI 应用程序与各种服务进行语义集成,为 AI 模型提供了获取实时信息、执行操作和访问资源的标准化方式。 #### mikro 本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。 - [MikroORM](/docs/extensions/mikro.md): 本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。 #### mongodb 在这一章节中,我们选择 Typegoose 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 - [MongoDB](/docs/extensions/mongodb.md): 在这一章节中,我们选择 Typegoose 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 #### mqtt MQTT是用于物联网 (IoT) 的OASIS标准消息传递协议。它被设计为非常轻量级的发布/订阅消息传输,非常适合以较小的代码占用空间和最小的网络带宽连接远程设备。MQTT目前广泛应用于汽车、制造、电信、石油和天然气等行业。 - [MQTT](/docs/extensions/mqtt.md): MQTT是用于物联网 (IoT) 的OASIS标准消息传递协议。它被设计为非常轻量级的发布/订阅消息传输,非常适合以较小的代码占用空间和最小的网络带宽连接远程设备。MQTT目前广泛应用于汽车、制造、电信、石油和天然气等行业。 #### one-shot @midwayjs/one-shot 是一个只提供 Framework 的一次性脚本执行组件,适合用 IoC 容器组织依赖,并在应用内触发一次性的任务逻辑。 - [单次执行](/docs/extensions/one-shot.md): @midwayjs/one-shot 是一个只提供 Framework 的一次性脚本执行组件,适合用 IoC 容器组织依赖,并在应用内触发一次性的任务逻辑。 #### orm TypeORM 是 node.js 现有社区最成熟的对象关系映射器(ORM )。本文介绍如何在 Midway 中使用 TypeORM 。 - [TypeORM](/docs/extensions/orm.md): TypeORM 是 node.js 现有社区最成熟的对象关系映射器(ORM )。本文介绍如何在 Midway 中使用 TypeORM 。 #### oss 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 - [阿里云对象存储(OSS)](/docs/extensions/oss.md): 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 #### passport 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Nodejs 中最流行的 Passport 库。 - [身份验证](/docs/extensions/passport.md): 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Nodejs 中最流行的 Passport 库。 #### piscina 线程池组件 @midwayjs/piscina 基于 Piscina 提供在 Worker 线程池中执行任务的能力,适合 CPU 密集型计算,不会阻塞主线程。 - [线程池](/docs/extensions/piscina.md): 线程池组件 @midwayjs/piscina 基于 Piscina 提供在 Worker 线程池中执行任务的能力,适合 CPU 密集型计算,不会阻塞主线程。 #### pm2 PM2 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 - [pm2](/docs/extensions/pm2.md): PM2 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 #### process_agent midway 封装了 @midwayjs/process-agent 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 - [进程 Agent](/docs/extensions/process_agent.md): midway 封装了 @midwayjs/process-agent 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 #### prometheus Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 - [Prometheus](/docs/extensions/prometheus.md): Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 #### rabbitmq 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务A负责产生消息给消息队列,而服务B则负责消费消息队列中的任务。 - [RabbitMQ](/docs/extensions/rabbitmq.md): 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务A负责产生消息给消息队列,而服务B则负责消费消息队列中的任务。 #### redis 这里介绍如何快速在 Midway 中使用 Redis。 - [Redis](/docs/extensions/redis.md): 这里介绍如何快速在 Midway 中使用 Redis。 #### render 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 - [模板渲染](/docs/extensions/render.md): 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 #### security 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用安全组件,支持 csrf 、xss 等多种安全策略。 - [安全](/docs/extensions/security.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用安全组件,支持 csrf 、xss 等多种安全策略。 #### sequelize 本文档介绍如何在 Midway 中使用 Sequelize。 - [Sequelize](/docs/extensions/sequelize.md): 本文档介绍如何在 Midway 中使用 Sequelize。 #### socketio Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 - [SocketIO](/docs/extensions/socketio.md): Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 #### static_file midway 提供了基于 koa-static-cache 模块的静态资源托管组件。 - [静态文件托管](/docs/extensions/static_file.md): midway 提供了基于 koa-static-cache 模块的静态资源托管组件。 #### swagger 基于最新的 OpenAPI 3.0.3 实现了新版的 Swagger 组件。 - [Swagger](/docs/extensions/swagger.md): 基于最新的 OpenAPI 3.0.3 实现了新版的 Swagger 组件。 #### tablestore 本文介绍了如何使用 midway 接入阿里云 TableStore。 - [TableStore](/docs/extensions/tablestore.md): 本文介绍了如何使用 midway 接入阿里云 TableStore。 #### tags 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用标签组件。 - [标签组件](/docs/extensions/tags.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用标签组件。 #### tenant 这里介绍如何快速在 Midway 中使用租户组件。 - [租户](/docs/extensions/tenant.md): 这里介绍如何快速在 Midway 中使用租户组件。 #### upload 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 - [文件上传](/docs/extensions/upload.md): 适用于 @midwayjs/faas 、@midwayjs/web 、@midwayjs/koa 和 @midwayjs/express 多种框架的通用上传组件,支持 file (服务器临时文件) 和 stream (流)两种模式。 #### validate 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 joi 。 - [参数校验](/docs/extensions/validate.md): 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 joi 。 #### validation 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型。 - [参数校验](/docs/extensions/validation.md): 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型。 #### ws ws 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. - [WebSocket](/docs/extensions/ws.md): ws 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. ### faq #### alias_path 我们并不建议使用 Alias Path, Node 和 TS 原生不支持这个功能,即使有,现在也是通过各种 Hack 手段来实现(从 v18 开始,Node.js 已经有 exports 的方案,但是类型还未支持,可以等后续)。 - [关于 Alias Path](/docs/faq/alias_path.md): 我们并不建议使用 Alias Path, Node 和 TS 原生不支持这个功能,即使有,现在也是通过各种 Hack 手段来实现(从 v18 开始,Node.js 已经有 exports 的方案,但是类型还未支持,可以等后续)。 #### framework_problem 多个 @midwayjs/core 警告 - [常见框架问题](/docs/faq/framework_problem.md): 多个 @midwayjs/core 警告 #### git_problem 文件名大小写问题 - [常见 git 问题](/docs/faq/git_problem.md): 文件名大小写问题 #### npm_problem 1、不希望生成 package-lock.json - [常见 npm 问题](/docs/faq/npm_problem.md): 1、不希望生成 package-lock.json #### ts_problem TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 - [常见 TS 问题](/docs/faq/ts_problem.md): TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 ### functional #### api-reference 本页用于快速查询 @midwayjs/core/functional 当前可用的函数式 API。 - [函数式 API](/docs/functional/api-reference.md): 本页用于快速查询 @midwayjs/core/functional 当前可用的函数式 API。 #### build-deploy Functional 一体化项目的实践建议是:开发一体化,部署分离化。 - [构建部署](/docs/functional/build-deploy.md): Functional 一体化项目的实践建议是:开发一体化,部署分离化。 #### frontend-integration 这一节给出一条可直接落地的路线:把 React/Vue 项目和函数式 Midway 接起来。 - [前端集成](/docs/functional/frontend-integration.md): 这一节给出一条可直接落地的路线:把 React/Vue 项目和函数式 Midway 接起来。 #### fundamentals 这一章回答三个核心问题: - [函数式基础](/docs/functional/fundamentals.md): 这一章回答三个核心问题: #### intro 这套文档的目标只有一个:让你尽快把前后端联调跑起来。 - [概览](/docs/functional/intro.md): 这套文档的目标只有一个:让你尽快把前后端联调跑起来。 #### migration 迁移建议是“渐进式”,不要一次改完。 - [迁移指南](/docs/functional/migration.md): 迁移建议是“渐进式”,不要一次改完。 #### react 本节按“能跑起来”为目标,给出最小接入步骤。 - [React 集成](/docs/functional/react.md): 本节按“能跑起来”为目标,给出最小接入步骤。 #### testing 建议把 Functional API 的测试分成三层:契约层、服务端层、前端调用层。 - [测试](/docs/functional/testing.md): 建议把 Functional API 的测试分成三层:契约层、服务端层、前端调用层。 #### validation 这一节说明 Functional API 里的参数校验方式,以及它和 class + decorator + pipeline 的关系。 - [参数校验](/docs/functional/validation.md): 这一节说明 Functional API 里的参数校验方式,以及它和 class + decorator + pipeline 的关系。 #### vue 这篇和 React 一样,先保证你能快速接通调用链路。 - [Vue 集成](/docs/functional/vue.md): 这篇和 React 一样,先保证你能快速接通调用链路。 #### workspace 这一页解决两个常见问题: - [目录与编辑](/docs/functional/workspace.md): 这一页解决两个常见问题: ### guard 从 v3.6.0 开始,Midway 提供守卫能力。 - [守卫](/docs/guard.md): 从 v3.6.0 开始,Midway 提供守卫能力。 ### hooks #### api 路由 - [接口开发](/docs/hooks/api.md): 路由 #### builtin-hooks Midway Hooks 可以通过使用 Hooks 函数来获取运行时上下文。 - [Hooks](/docs/hooks/builtin-hooks.md): Midway Hooks 可以通过使用 Hooks 函数来获取运行时上下文。 #### client 在 Midway Hooks 的全栈应用中,我们使用 @midwayjs/rpc 作为默认的请求客户端。所有生成的接口都会通过 @midwayjs/rpc 来调用服务端。 - [前端请求客户端](/docs/hooks/client.md): 在 Midway Hooks 的全栈应用中,我们使用 @midwayjs/rpc 作为默认的请求客户端。所有生成的接口都会通过 @midwayjs/rpc 来调用服务端。 #### component Midway 提供了一系列的组件,包含 Cache / Http / Redis 等。 - [使用 Midway 组件](/docs/hooks/component.md): Midway 提供了一系列的组件,包含 Cache / Http / Redis 等。 #### config 我们通过项目根目录下的 midway.config.ts 来配置项目,具体的配置项如下。 - [项目配置](/docs/hooks/config.md): 我们通过项目根目录下的 midway.config.ts 来配置项目,具体的配置项如下。 #### cors 在 Midway Hooks 中,可以通过 @koa/cors 来配置跨域功能。 - [跨域 CORS](/docs/hooks/cors.md): 在 Midway Hooks 中,可以通过 @koa/cors 来配置跨域功能。 #### debug 得益于编辑器的支持,我们可以快速的在本地调试应用。 - [调试](/docs/hooks/debug.md): 得益于编辑器的支持,我们可以快速的在本地调试应用。 #### deploy Midway Hooks 支持 Api Server 与一体化两种模式。 - [部署](/docs/hooks/deploy.md): Midway Hooks 支持 Api Server 与一体化两种模式。 #### file-route 简易模式 - [简易模式 & 文件系统路由](/docs/hooks/file-route.md): 简易模式 #### fullstack 在 Midway Hooks 中,我们提供了 @midwayjs/hooks-kit 来快速开发全栈应用。目前我们提供了以下可直接使用的模版: - [全栈套件](/docs/hooks/fullstack.md): 在 Midway Hooks 中,我们提供了 @midwayjs/hooks-kit 来快速开发全栈应用。目前我们提供了以下可直接使用的模版: #### intro 一体化方案将逐步停止维护,已有项目可以继续使用,新建项目请谨慎选择。 - [介绍](/docs/hooks/intro.md): 一体化方案将逐步停止维护,已有项目可以继续使用,新建项目请谨慎选择。 #### middleware Midway Hooks 支持通过函数 + useContext() 来定义 Web 中间件。 - [Web 中间件](/docs/hooks/middleware.md): Midway Hooks 支持通过函数 + useContext() 来定义 Web 中间件。 #### prisma 在 Midway Hooks 中,我们推荐使用 Prisma 来构建数据库,并实现我们静态类型安全的目标。 - [Prisma ORM](/docs/hooks/prisma.md): 在 Midway Hooks 中,我们推荐使用 Prisma 来构建数据库,并实现我们静态类型安全的目标。 #### safe 使用 Prisma 和 @midwayjs/hooks 提供的 Validate 校验器,可以实现从前端到后端再到数据库的类型安全 + 运行时安全链路。 - [静态类型安全 + 运行时安全](/docs/hooks/safe.md): 使用 Prisma 和 @midwayjs/hooks 提供的 Validate 校验器,可以实现从前端到后端再到数据库的类型安全 + 运行时安全链路。 #### test 在 Midway Hooks 中,我们可以快速的对 Http 接口进行测试。 - [测试](/docs/hooks/test.md): 在 Midway Hooks 中,我们可以快速的对 Http 接口进行测试。 #### upload Midway Hooks 提供了 @midwayjs/hooks-upload 并配合 @midwayjs/upload 来实现纯函数 + 一体化项目中的文件上传功能。 - [文件上传](/docs/hooks/upload.md): Midway Hooks 提供了 @midwayjs/hooks-upload 并配合 @midwayjs/upload 来实现纯函数 + 一体化项目中的文件上传功能。 #### validate 校验 - [参数校验](/docs/hooks/validate.md): 校验 ### how_to_install_nodejs 使用场景 - [如何安装 Node.js 环境](/docs/how_to_install_nodejs.md): 使用场景 ### how_to_update_midway 什么时候要更新 Midway - [如何更新 Midway](/docs/how_to_update_midway.md): 什么时候要更新 Midway ### intro Midway 基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 - [介绍](/docs/intro.md): Midway 基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 ### legacy #### mongodb 本文档从 v3.4.0 版本起废弃。 - [MongoDB](/docs/legacy/mongodb.md): 本文档从 v3.4.0 版本起废弃。 #### orm 本文档从 v3.4.0 版本起废弃。 - [TypeORM](/docs/legacy/orm.md): 本文档从 v3.4.0 版本起废弃。 #### sequelize 本文档从 v3.4.0 版本起废弃。 - [Sequelize](/docs/legacy/sequelize.md): 本文档从 v3.4.0 版本起废弃。 #### task 本文档从 v3.6.0 版本起废弃。 - [任务调度](/docs/legacy/task.md): 本文档从 v3.6.0 版本起废弃。 ### lifecycle 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 - [生命周期](/docs/lifecycle.md): 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 ### logger 本文档为 @midwayjs/logger v2.0 版本的文档。 - [日志(v2)](/docs/logger.md): 本文档为 @midwayjs/logger v2.0 版本的文档。 ### logger_v3 Midway 为不同场景提供了一套统一的日志接入方式。通过 @midwayjs/logger 包导出的方法,可以方便的接入不同场景的日志系统。 - [日志](/docs/logger_v3.md): Midway 为不同场景提供了一套统一的日志接入方式。通过 @midwayjs/logger 包导出的方法,可以方便的接入不同场景的日志系统。 ### middleware Web 中间件是在控制器调用 之前 和 之后(部分) 调用的函数。 中间件函数可以访问请求和响应对象。 - [Web 中间件](/docs/middleware.md): Web 中间件是在控制器调用 之前 和 之后(部分) 调用的函数。 中间件函数可以访问请求和响应对象。 ### midway_component 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 - [使用组件](/docs/midway_component.md): 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 ### midway_slow_problem Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 - [关于 Midway 启动慢的问题](/docs/midway_slow_problem.md): Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 ### mock Midway 提供了内置的在开发和测试时模拟数据的能力。 - [数据模拟](/docs/mock.md): Midway 提供了内置的在开发和测试时模拟数据的能力。 ### ops #### ecs_start_err 应用启动失败是非常常见的现象,逻辑错误,编译错误,配置错误,环境问题,都有可能导致你的项目无法启动。 - [服务器启动失败排查](/docs/ops/ecs_start_err.md): 应用启动失败是非常常见的现象,逻辑错误,编译错误,配置错误,环境问题,都有可能导致你的项目无法启动。 ### pipe 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: - [管道](/docs/pipe.md): 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: ### pipeline 4.0 中,我们移除了该功能。 - [流程控制](/docs/pipeline.md): 4.0 中,我们移除了该功能。 ### quick_guide 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 - [快速入门](/docs/quick_guide.md): 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 ### quickstart 技术选型 - [创建第一个应用](/docs/quickstart.md): 技术选型 ### release_schedule 下表是 Midway 整体的维护节奏和计划。 - [Midway 维护计划](/docs/release_schedule.md): 下表是 Midway 整体的维护节奏和计划。 ### req_res_app Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 - [Application 和 Context](/docs/req_res_app.md): Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 ### retry 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 - [重试机制](/docs/retry.md): 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 ### router_table 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 - [Web 路由表](/docs/router_table.md): 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 ### serverless #### aliyun_faas 阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。 - [部署到阿里云函数计算](/docs/serverless/aliyun_faas.md): 阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。 #### aws_lambda AWS Lambda是Amazon Web Services (AWS)提供的无服务器计算服务。它允许您在无需预配或管理服务器的情况下运行代码。您可以为几乎任何类型的应用程序或后端服务运行代码,全部无需管理。 - [部署到 AWS Lambda](/docs/serverless/aws_lambda.md): AWS Lambda是Amazon Web Services (AWS)提供的无服务器计算服务。它允许您在无需预配或管理服务器的情况下运行代码。您可以为几乎任何类型的应用程序或后端服务运行代码,全部无需管理。 #### serverless_context Event 转换 - [函数上下文](/docs/serverless/serverless_context.md): Event 转换 #### serverless_dev 初始化代码 - [开发函数](/docs/serverless/serverless_dev.md): 初始化代码 #### serverless_error 错误值处理 - [默认错误行为](/docs/serverless/serverless_error.md): 错误值处理 #### serverless_intro Midway Serverless 能做什么 - [介绍](/docs/serverless/serverless_intro.md): Midway Serverless 能做什么 #### serverless_post_difference 阿里云 API 网关 - [Serverless 触发器 POST 情况差异](/docs/serverless/serverless_post_difference.md): 阿里云 API 网关 #### serverless_testing HTTP 类的函数 - [测试函数](/docs/serverless/serverless_testing.md): HTTP 类的函数 #### serverless_v2_upgrade_serverless_v3 基于 Midway 升级到 v3 的缘故,Serverless 体系也同步升级到了 v3 版本。 - [从 Serverless v2 迁移到 v3](/docs/serverless/serverless_v2_upgrade_serverless_v3.md): 基于 Midway 升级到 v3 的缘故,Serverless 体系也同步升级到了 v3 版本。 ### service 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 - [服务和注入](/docs/service.md): 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 ### service_discovery 在分布式架构中,服务发现用于自动注册和发现可用的服务实例,并通过健康检查与负载均衡确保调用的稳定与高可用。Midway 在核心层提供了统一的抽象与基类,并在不同的注册中心上提供了具体实现(Consul、ETCD、Redis),以适配多种使用场景。 - [服务发现(Service Discovery)](/docs/service_discovery.md): 在分布式架构中,服务发现用于自动注册和发现可用的服务实例,并通过健康检查与负载均衡确保调用的稳定与高可用。Midway 在核心层提供了统一的抽象与基类,并在不同的注册中心上提供了具体实现(Consul、ETCD、Redis),以适配多种使用场景。 ### service_factory 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 - [服务工厂](/docs/service_factory.md): 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 ### skill_midway @midwayjs/skill-midway 是 Midway 官方提供的 AI Skill 包。 - [Midway Skill 使用](/docs/skill_midway.md): @midwayjs/skill-midway 是 Midway 官方提供的 AI Skill 包。 ### testing 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 - [测试](/docs/testing.md): 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 ### tool #### cli 由于 CLI 底层能力都来源于社区现有的模块功能,为了减少过渡封装带来的维护成本和理解成本,CLI 中的各项功能都将逐步变为社区现有的模块,同时 CLI 库将停止继续迭代。 - [Midway CLI](/docs/tool/cli.md): 由于 CLI 底层能力都来源于社区现有的模块功能,为了减少过渡封装带来的维护成本和理解成本,CLI 中的各项功能都将逐步变为社区现有的模块,同时 CLI 库将停止继续迭代。 #### create_midway Midway 编写了 create-midway 包,通过 npx 命令,可以方便的使用 npm init midway 命令创建脚手架。 - [脚手架](/docs/tool/create_midway.md): Midway 编写了 create-midway 包,通过 npx 命令,可以方便的使用 npm init midway 命令创建脚手架。 #### egg-ts-helper 针对 midway 支持 Egg.js 的场景,重写了原 egg-ts-helper 包,移除了原有的 TS,AST 分析等大依赖。 - [egg:ts-helper](/docs/tool/egg-ts-helper.md): 针对 midway 支持 Egg.js 的场景,重写了原 egg-ts-helper 包,移除了原有的 TS,AST 分析等大依赖。 #### luckyeye Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。@midwayjs/luckyeye 包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 - [规则检查工具](/docs/tool/luckyeye.md): Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。@midwayjs/luckyeye 包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 #### mwts Midway 的框架和业务代码主要由 TypeScript 编写,默认使用 mwts 统一 lint 和格式化。 - [Lint 和格式化](/docs/tool/mwts.md): Midway 的框架和业务代码主要由 TypeScript 编写,默认使用 mwts 统一 lint 和格式化。 #### mwtsc 基于标准的 tsc 模块,midway 开发了一个简单的工具,用于本地开发和构建 ts 文件。 - [开发工具](/docs/tool/mwtsc.md): 基于标准的 tsc 模块,midway 开发了一个简单的工具,用于本地开发和构建 ts 文件。 #### sequelize_generator forked from sequelize/sequelize-auto - [sequelize-auto-midway](/docs/tool/sequelize_generator.md): forked from sequelize/sequelize-auto #### typeorm_generator 感谢社区用户 @youtiao66 提供此模块。 - [typeorm:Model Generator](/docs/tool/typeorm_generator.md): 感谢社区用户 @youtiao66 提供此模块。 #### version_check 由于依赖安装版本的不确定性,Midway 提供了 midway-version 这一版本检查工具,可以快速检查版本之间的兼容性错误。 - [版本检查工具](/docs/tool/version_check.md): 由于依赖安装版本的不确定性,Midway 提供了 midway-version 这一版本检查工具,可以快速检查版本之间的兼容性错误。 ### tracing 从 Midway v4 开始,框架侧 tracing 能力已合并到 @midwayjs/core,不再需要安装和启用 @midwayjs/otel 组件。 - [链路追踪](/docs/tracing.md): 从 Midway v4 开始,框架侧 tracing 能力已合并到 @midwayjs/core,不再需要安装和启用 @midwayjs/otel 组件。 ### upgrade_v3 本篇将介绍从 midway v2 升级为 midway v3 的方式。 - [2.x 升级指南](/docs/upgrade_v3.md): 本篇将介绍从 midway v2 升级为 midway v3 的方式。 ### upgrade_v4 本篇将介绍从 midway v3 升级为 midway v4 的方式。 - [3.x 升级指南](/docs/upgrade_v4.md): 本篇将介绍从 midway v3 升级为 midway v4 的方式。 ### versioning 在现代 API 开发中,版本化是一个非常重要的话题。当你的 API 需要进行不兼容的更改时,版本化可以确保现有的客户端不会受到影响,同时允许新的客户端使用新的功能。 - [路由版本化](/docs/versioning.md): 在现代 API 开发中,版本化是一个非常重要的话题。当你的 API 需要进行不兼容的更改时,版本化可以确保现有的客户端不会受到影响,同时允许新的客户端使用新的功能。 --- # Full Documentation Content ## [新增 @midwayjs/skill-midway](/blog/skill/midway.md) 2026年4月6日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 我们新增了 `@midwayjs/skill-midway`。 这个包提供两类能力: * 把 Midway Skill 安装到项目里的 AI 工具目录 * 在本地查询 Midway 的文档、API、包信息和 changelog **标签:** * [midway](/blog/tags/midway.md) * [ai](/blog/tags/ai.md) * [skill](/blog/tags/skill.md) [**阅读更多**](/blog/skill/midway.md) --- ### 2026[​](#2026 "2026的直接链接") * [1月3日](/blog/release/4.0.0-beta.9.md) [ - ](/blog/release/4.0.0-beta.9.md) [Release 4.0.0-beta.9](/blog/release/4.0.0-beta.9.md) * [1月11日](/blog/release/4.0.0-beta.10.md) [ - ](/blog/release/4.0.0-beta.10.md) [Release 4.0.0-beta.10](/blog/release/4.0.0-beta.10.md) * [4月2日](/blog/release/4.0.0.md) [ - ](/blog/release/4.0.0.md) [Release 4.0.0](/blog/release/4.0.0.md) * [4月6日](/blog/skill/midway.md) [ - ](/blog/skill/midway.md) [新增 @midwayjs/skill-midway](/blog/skill/midway.md) --- # 作者 * [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) ## [Harry Chen](https://github.com/czy88840616) 26 Maintainer of Midway --- # core 和 decorator 包合并的影响 2022年10月26日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 从 v3.6.0 开始,Midway 在代码层面将 `@midwayjs/decorator` 中的代码迁移到了 `@midwayjs/core` 中,未来 `@midwayjs/decorator` 包将逐步减少使用。 `@midwayjs/decorator` 中的代码全部从 `@midwayjs/core` 中代理出来,代码层面保持向下兼容。 最近发现有些用户会出现类似下面的报错: ![](https://img.alicdn.com/imgextra/i3/O1CN01ZUf1P31oSBRQlBEhv_!!6000000005223-0-tps-3148-554.jpg) 原因有两类: **1、v3 的版本的 core 和组件版本不一致** 在开发时,直接使用 `npm install` 而安装了 latest 版本(>=v3.6.0) 的组件。 由于 core 的版本依旧在 `3.6.0` 以下,但是组件依赖了最新版本 core 的 API,从而报错。 我们在文档 [如何更新 Midway](/docs/how_to_update_midway.md) 中有描述,请不要单独升级某个组件包。 解决方案有两个: * 1、可以使用低版本的组件,比如 `3.6.0` 以下 * 2、或者升级 core 和其他的版本统一到 `3.6.0` 以上 **2、v2 的版本使用了 v3 的组件** 在 v2 版本时,直接使用 `npm install` 而错误安装了 latest 版本(v3) 的组件。 我们为了适配最新的版本正好升级了 v3 的组件,从而暴露了引了错误的版本的这个问题。 现在 v2 和 v3 的组件不保证能完全兼容,所以请在安装时做好区分。 解决方案:使用 v2 版本的组件。 **标签:** * [decorator](/blog/tags/decorator.md) * [core](/blog/tags/core.md) --- # Jest v29 更新 2022年10月29日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 最近由于 axios 组件的升级,可能在单测时会出现下面的报错。 ![](https://img.alicdn.com/imgextra/i2/O1CN01G4Ze0F1qVxwcNwYeF_!!6000000005502-2-tps-2080-1158.png) 原因为脚手架自带的 jest v26 不支持 package.json 中的 `exports` 逻辑。 解决方法: * 1、将 `package.json` 中的 jest 版本从 v26 更新为 v29 * 2、将 `@midwayjs/cli` 的版本升级为 `1.3.16` 版本以上,也可以升级到 `2.0` 示例如下: ``` { "devDependencies": { "@midwayjs/cli": "^2.0.1", "@types/jest": "^29.2.0", "jest": "^29.2.2", "ts-jest": "^29.0.3", // ... } } ``` **标签:** * [更新](/blog/tags/更新.md) * [jest](/blog/tags/jest.md) --- # mwtsc 增加版本检查 2024年7月12日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 由于 Midway 版本发布规则,`@midwayjs/core` 和组件有着版本对应关系,即低版本的 `@midwayjs/core` 无法使用高版本的组件。 比如 `@midwayjs/axios@3.17.0` 可能使用了高版本的 API,是无法在 `@midwayjs/core@3.16.0` 版本上执行的。 由于 npm 等包管理的特性,包安装时不存在联系,`npm i @midwayjs/axios` 时往往只会安装组件最新的版本,非常容易造成兼容性问题。 为此我们提供了 `npx midway-version` 命令,可以快速检查版本之间的兼容性错误。 在推行一阵子之后,我们发现很少有用户主动去执行这样的指令,只会在出错时被动执行,再加上锁包和不锁包的复杂场景,会出现一些很难复现和排查的现象。 为了降低复杂性,在 mwtsc 新版本的启动阶段,我们也加入了检查代码。 ![](https://img.alicdn.com/imgextra/i3/O1CN01ZHQcs51tDb5HrSviC_!!6000000005868-2-tps-1550-420.png) 如果出现不兼容的版本,工具会进行提示。 此外,新增的 `npx midway-version -m` 指令可以让固化版本的用户也享受到更新工具。 和之前的 `-u` 指令不同,`-m` 会使用当前的 `@midwayjs/core` 版本,更新组件到最兼容的版本,而不是最新版本。 结合 `mwtsc` 和 `midway-version` 工具,可以更简单的管理版本,如有问题可以反馈给我们改进。 **标签:** * [mwtsc](/blog/tags/mwtsc.md) --- ## [Release 4.0.0-beta.1](/blog/release/4.0.0-beta.1.md) 2025年8月29日 · 阅读需 4 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 这是全新的 Midway 4.0 的变化,这是一个非常重大的版本。 * 全局变化 * 框架支持从 Node.js >=20 开始 * 默认开启 asyncLocalStorage * 编程范式 * 不再以黑盒方式提供框架启动时的目录文件扫描自动绑定能力,改为显式声明,每个组件都可以有自己的绑定和加载方式 * 组件包查找规范变化,现在会查找 `index.ts`,`configuration.ts`,以及 `package.json` 中 main 定义的路径 * 统一规范函数式的导出路径,为组件包下的 `functional` 路径,如 `@midwayjs/core/functional` * 【core】 * 通用能力 * 由于使用率较低且影响依赖注入容器逻辑,移除了流程控制 `Pipeline` 相关的能力 * 移除之前版本中框架启动时的目录文件扫描自动绑定能力,现在需要显式增加一个 file detector,可以自由配置其需要扫描和忽略的目录或者文件 * 移除了会和 validate 的转换产生歧义的请求参数自动 DTO 转换功能,现在自动转换仅在 `validate` 或者 `validation` 组件开启时生效 * `onReady` 等生命周期现在增加了超时机制,默认 30s * 函数式编程 * 提供与 `@Configuration` 同样功能的 `defineConfiguration` 方法 * 提供内置的 hooks 方法,如 `useContext`, `useLogger`, `useInject`, `useConfig`, `useApp`, `useMainApp` 等 * 提供了函数式方法的导出规范,新开发的 hooks 放在 `functional` 目录中,使用子模块方式导出 * 装饰器部分 * 为了更好的管理元数据,重构了 `DecoratorManager`,增加新的 `MetadataManager`,增加了更加方便的聚合和拷贝元数据的能力 * 明确各种装饰器继承的情况,默认情况下,类装饰器和参数装饰器不继承,属性装饰器和方法装饰器继承 * 使用 `@MainApp()` 代替 `@App()` 空参数 * 使用 `@Config(ALL)` 替换为更为明确的 `@AllConfig()` 装饰器 * 移除 `@Configuration` 中的 `conflictCheck` 和 `detectorOptions`, 这些配置将移动到 `detector` 中 * `DecoratorManager` 中的 `listPrelaodModules` 调整为 `listPreStartModule`,`savePreloadModule` 调整为 `savePreStartModule` ,使其语义更加明确 * 依赖注入 * 移除了 `container.get` 和 `container.getAsync` 的一部分无用的参数 * 优化了循环依赖时展示的依赖链路信息以及 definition 未找到时的输出信息 * 单例对象现在和 `registerObject` 的对象存储的位置一致了 * 增加了一个动态依赖注入容器,用于在开发期动态替换实例,支持 HMR 功能 * 框架机制 * `BaseFramework` 移除了令人疑惑的 container 相关 hook 方法,现在都统一使用 `applicationInitialize` * 移除框架的 `MidwayFrameworkType`,以及对应的 `getFrameworkType()` 方法 * 移除了特定框架下令人疑惑的 `contextLoggerApplyLogger` 和 `contextLoggerFormat` 配置,现在如果要配置框架特定的 logger,使用 `setFrameworkLoggerName` 方法 * `ServiceFactory` 和 `DataSourceManager` 现在启动可以通过 `initClients` 的参数 `concurrent` 支持并发,由组件自行控制是否支持 * `DataSourceManager` 原有的 `cacheInstance` 和 `validateConnection` 选项废弃 * `MidwayConfigServce` 在获取配置时可以增加默认值 * 增加服务发现基础功能,增加了 `consul` 、`redis` 、`etcd` 的实现 * 【decorator】移除,API 都移动到 `@midwayjs/core`,不再单独提供 4.x 版本 * 【async-hooks-context-manager】现在默认开启 async\_local\_storage,代码合并至 core 模块中 * 【axios】移除了废弃的 `axios` 导出 * 【socketio】移除了内置的 `socket.io-redis` * 【validate】 * 由于固化了 Joi 作为验证器,不再更新 * 移除 `@Rule` 作为类装饰器的功能 * 移除属性 `@Rule` 参数传递类本身的功能 * 【validation】新增组件,替代原有 validate 组件 * 支持多种验证器,如 Joi, zod, class-validator,提供内置的 i18n 支持 * 可自定义扩展验证器 * 【mock】 * 由于移除了框架启动的扫描能力,如果有大量历史测试不方便修改,可以使用提供的 `createLegacyApp`,`createLegacyLightApp`,`createLegacyFunctionApp` ,对应之前的 `createApp`,`createLightApp`, `createFunctionApp` * 移除了 `createApp`,`createLightApp`, `createFunctionApp` 方法的最后一个参数,现在额外指定组件可以写到 `options.imports` 中 * 【sequelize】 * 移除老版本配置的兼容代码,以及历史装饰器导出,如 `@BaseTable` * 移除默认启动时数据源连接校验 `validateConnection`,如有需求,可以在配置中单独开启 * 【tags】移除,不再提供 4.x 版本 * 【processAgent】移除,不再提供 4.x 版本 * 【event-emitter] 新增组件,提供事件触发和监听能力支持 **标签:** * [release](/blog/tags/release.md) --- ## [mwtsc 增加版本检查](/blog/mwtsc-check.md) 2024年7月12日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 由于 Midway 版本发布规则,`@midwayjs/core` 和组件有着版本对应关系,即低版本的 `@midwayjs/core` 无法使用高版本的组件。 比如 `@midwayjs/axios@3.17.0` 可能使用了高版本的 API,是无法在 `@midwayjs/core@3.16.0` 版本上执行的。 由于 npm 等包管理的特性,包安装时不存在联系,`npm i @midwayjs/axios` 时往往只会安装组件最新的版本,非常容易造成兼容性问题。 为此我们提供了 `npx midway-version` 命令,可以快速检查版本之间的兼容性错误。 在推行一阵子之后,我们发现很少有用户主动去执行这样的指令,只会在出错时被动执行,再加上锁包和不锁包的复杂场景,会出现一些很难复现和排查的现象。 为了降低复杂性,在 mwtsc 新版本的启动阶段,我们也加入了检查代码。 ![](https://img.alicdn.com/imgextra/i3/O1CN01ZHQcs51tDb5HrSviC_!!6000000005868-2-tps-1550-420.png) 如果出现不兼容的版本,工具会进行提示。 此外,新增的 `npx midway-version -m` 指令可以让固化版本的用户也享受到更新工具。 和之前的 `-u` 指令不同,`-m` 会使用当前的 `@midwayjs/core` 版本,更新组件到最兼容的版本,而不是最新版本。 结合 `mwtsc` 和 `midway-version` 工具,可以更简单的管理版本,如有问题可以反馈给我们改进。 **标签:** * [mwtsc](/blog/tags/mwtsc.md) --- ## [Release 3.12.0](/blog/release/3.12.0.md) 2023年8月14日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 在经过了几个月的努力更新之后,Midway 迎来了 3.12 版本,这是一个改动比较大的版本。 ## Breaking[​](#breaking "Breaking的直接链接") 从 v3.12.0 开始,Midway 移除了 Node.js v14 的 CI,原因请参考 [这里](/blog/remove-node-14-ci.md)。 ## Features[​](#features "Features的直接链接") ### 1、ESM 的支持[​](#1esm-的支持 "1、ESM 的支持的直接链接") 从 v3.12.0 开始,midway 支持创建 ESModule 项目,使用时和传统 CJS 项目会有所不同,由于时间紧迫,我们没有针对所有的组件进行测试,如有兼容性问题,请提交 issue。 此外,由于原有的工具体系已经无法很好的兼容 ESM 环境,为了减少维护成本,我们启用了一套全新的工具链,后续普通 CJS 项目也会统一到这一套上来。 更多细节请查看 [ESM 文档](/docs/esm.md)。 ### 2、FaaS 架构变更[​](#2faas-架构变更 "2、FaaS 架构变更的直接链接") 从 v3.12.0 开始,Midway FaaS 使用全新的一套架构支持现有的 Serverless 平台,这一部分后续将会在文档中体现。 主要的变化: * Midway 不再提供 “应用部署到弹性容器” 的兼容方案,如果平台支持使用传统应用部署 Serverless 容器,可以直接使用标准项目部署 * Midway 不再提供 f.yml 的维护工作,也不再提供部署功能,仅提供将现有函数信息写入平台配置的能力,所有的函数部署将由平台自己的工具进行部署 * 移除了原有通过 `@midwayjs/serverless-app` 启动和开发的模式,作为替代,将使用 `@midwayjs/fc-starter` 来进行开发 ## 其他的一些变化[​](#其他的一些变化 "其他的一些变化的直接链接") * 1、添加了 `ctx.getApp()` 方法,可以从 ctx 拿到自己 app,打通了整条从 framework,到 app 和 ctx 的链路 * 2、core 中的 httpClient 现在支持了所有的 http method * 3、增加了一个内部跳转 URL 的 api,`ctx.forward` * 4、IoC 容器增加了一个获取对象作用域的 API,`container.getInstanceScope(xxx)` ## 依赖更新[​](#依赖更新 "依赖更新的直接链接") 具体可以查看 [Changelog](https://midwayjs.org/changelog/v3.12.0)。 **标签:** * [release](/blog/tags/release.md) --- ## [Release 3.8.0](/blog/release/3.8.0.md) 2022年11月18日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway v3.8.0 是在经过大促之后的第一个 minor 版本,积攒了很多新的能力。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 ## Features[​](#features "Features的直接链接") ### 1、etcd 组件[​](#1etcd-组件 "1、etcd 组件的直接链接") 新增了一个 etcd 组件,方便用户使用,文档稍后提供。 ``` import { ETCDService } from '@midwayjs/etcd'; @Provide() export class UserService { @Inject() etcdService: ETCDService; async invoke() { const fooValue = await this.etcdService.get('foo').string(); console.log('foo was:', fooValue); // ... } } ``` 更多细节请查看 [文档](/docs/extensions/etcd.md)。 ### 2、ServiceFactory 支持设置默认客户端[​](#2servicefactory-支持设置默认客户端 "2、ServiceFactory 支持设置默认客户端的直接链接") ServiceFactory 提供了标准的多客户端能力,在默认的客户端中,我们可以设置非 default 的客户端作为默认客户端来使用。 这项能力支持 ServiceFactory 扩展出来的所有组件,包括 axios/cos/oss/redis/tablestore 等,用户自定义的组件也可以通过简单的适配享受到该能力。 比如,我们定义了多个 redis 客户端。 ``` export default { // ... redis: { clients: { default: { // ... }, default2: { // ... }, }, }, } ``` 默认注入的 `RedisService` 永远为 `default` 指向的客户端,而新版本我们可以通过设置默认的客户端名,来选择默认的客户端。 比如: ``` export default { // ... redis: { clients: { default: { // ... }, default2: { // ... }, }, defaultClientName: 'default2' }, } ``` 那么实际获取的 `redisService` 中是 `default2` 这个实例。 ``` @Provide() export class UserService { @Inject() redisService: RedisService; async invoke() { // this.redisService 中包裹的是 default2 } } ``` ### 3、数据源类型增加 `@InjectDataSource` 装饰器[​](#3数据源类型增加-injectdatasource-装饰器 "3数据源类型增加-injectdatasource-装饰器的直接链接") 为了简化获取数据源的过程,我们提供了一个新的 `@InjectDataSource` 装饰器,支持 mikro/sequelize/typeorm。 比如: ``` import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource, Repository } from 'typeorm'; @Provide() export class UserService { @InjectDataSource() defaultDataSource: DataSource; async invoke() { // ... } } ``` 也可以指定数据源。 ``` import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource, Repository } from 'typeorm'; @Provide() export class UserService { @InjectDataSource('default') defaultDataSource: DataSource; async invoke() { // ... } } ``` ## Bugfix[​](#bugfix "Bugfix的直接链接") * 1、修复 windows 下 entity 通配扫描,之前 windows 下的 entity 如果使用了通配符,会扫描失败,导致 entity 无法正确的加入到数据源中,新版本修复了该问题。 * 2、bull 的 Queue 定义处理问题,现在文档已经做了修改,注入的类型可以由 `IQueue` 变为 `BullQueue`。 ## Performance[​](#performance "Performance的直接链接") 移除了 babel 编译出的 class 的兼容判断,框架整体性能提升约一倍。 **标签:** * [release](/blog/tags/release.md) --- ## [Release 3.6.0](/blog/release/3.6.0.md) 2022年10月12日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway v3.6.0 包含一个重大的 [重构](https://github.com/midwayjs/midway/issues/2258),我们将 @midwayjs/decorator 包和 @midwayjs/core 包的内容进行了整合,未来所有的 decorator 相关的内容,都会由 @midwayjs/core 导出,@midwayjs/decorator 包仅做代理,保持功能兼容。 后续,我们将会在文档上进行 decorator 包的移除操作,在这段时间中,大家还是会看到 decorator 和 core 并存的情况。 ## Features[​](#features "Features的直接链接") ### 1、守卫[​](#1守卫 "1、守卫的直接链接") 从 v3.6.0 版本开始,我们提供了守卫能力,和 middleare,filter 类似,也是一个全框架复用的能力(koa/egg/grpc/rabbitmq/bull 等) ``` import { IMiddleware, Guard, IGuard } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, suppilerClz, methodName: string): Promise { // ... } } ``` 更多细节请查看 [文档](/docs/guard.md)。 ### 2、鉴权[​](#2鉴权 "2、鉴权的直接链接") 基于守卫功能的完成,我们可以自己定义 @Role 装饰器来完成简单的角色鉴权,同时我们也封装了 casbin 这一在社区较为通用的鉴权组件,方便大家使用。 比如,通过装饰器鉴权。 ``` import { Controller, Get, UseGuard } from '@midwayjs/decorator'; import { AuthActionVerb, AuthGuard, AuthPossession, UsePermission } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @UsePermission({ action: AuthActionVerb.READ, resource: Resource.USER_ROLES, possession: AuthPossession.ANY }) @Get('/users') async findAllUsers() { // ... } } ``` casbin 组件目前实现了 redis 和 typeorm 两个可以复用的适配器供大家选择,如有其他需求,可以额外进行适配。 更多细节,可以查看 [文档](/docs/extensions/casbin.md)。 ### 3、bull 组件[​](#3bull-组件 "3、bull 组件的直接链接") 我们新增了 bull 组件用于替代原有的 task 组件。 ``` // invoke const testQueue = this.bullFramework.getQueue('test'); // 立即执行这个任务 await testQueue?.runJob({ aaa: 1, bbb: 2, }); ``` 同时也提供了一个 bull-board 组件用于管理。 ![](https://cdn.nlark.com/yuque/0/2022/png/501408/1665641044268-8ebfc3bb-777b-43f8-a8d9-bfb77f95e47c.png) 更多细节,可以查看 文档。 更多介绍可以查看我们的 [b 站视频](https://www.bilibili.com/video/BV1ZB4y1j7H3/) **标签:** * [release](/blog/tags/release.md) --- # Release 3.10.0 2023年1月30日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 新年快乐。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 这个版本更新了许多东西,请耐心看完。 ## Breaking[​](#breaking "Breaking的直接链接") 首先是 Breaking 的部分,这部分并非是框架本身的 API 变更,而是依赖或者行为可能会影响少部分用户,需要注意的部分。 * 1、 `@midwayjs/consul` 依赖的 `consul` 模块从 `0.x` 升级到 `v1` 正式版,API 可能有更新(`consul.acl` 变更为 `consul.acl.legacy`),具体请查看 [文档](https://github.com/silas/node-consul#acl-legacy) * 2、`@midwayjs/jwt` 依赖的`jsonwebtoken` 模块由于安全性问题,从 `v8` 升级到 `v9`,API 可能有更新,更多情况请查看 [文档](https://github.com/midwayjs/midway/pull/2595) * 3、由于新增的 `@Pipe` 功能,`@midwayjs/validate` 新版本无需使用 `@Validate` 装饰器即可校验,可能会影响一部分之前未编写装饰器但是新版本却被验证的场景,具体请看下面关于 `@Pipe` 的介绍或者相关的文档。 ## New Feature[​](#new-feature "New Feature的直接链接") ### Pipe[​](#pipe "Pipe的直接链接") 新版本新增了一项 Pipe 能力,可以使参数装饰器的能力更进一步。 藉由此能力,新版本的 Validate 组件不再需要 `@Validate` 装饰器,代码会更加简洁。 旧: ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate() async updateUser(@Body() user: UserDTO ) { // user.id } } ``` 新: ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO ) { // user.id } } ``` 针对非 DTO 类型的校验,现在也可以使用 Pipe 进行处理,如果是字符串,会自动转为数字,并进行校验。 ``` @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number ) { // ... } } ``` 当然 Pipe 的功能不仅如此,更多功能请查看 [完整文档](/docs/pipe.md)。 ### TypeORM Logger[​](#typeorm-logger "TypeORM Logger的直接链接") 当 typeorm 组件未配置 logger 属性时,新版本会自动创建一个 `typeormLogger` 用于存储执行的 sql。 默认配置为: ``` midwayLogger: { clients: { typeormLogger: { lazyLoad: true, fileLogName: 'midway-typeorm.log', enableError: false, level: 'info', }, }, } ``` `lazyLoad` 为新增的属性,可以使 logger 在一开始仅保留配置,等实际 getLogger 时才做初始化。 ### @Singleton 装饰器[​](#singleton-装饰器 "@Singleton 装饰器的直接链接") 简化原有的写法: 旧: ``` @Scope(ScopeEnum.Singleton) @Provide() class SingletonService {} ``` 新: ``` @Singleton() class SingletonService {} ``` ### app.getNamespace API[​](#appgetnamespace-api "app.getNamespace API的直接链接") 通过 app 上新增的 `getNamespace` API ,可以获取到当前的 app 归属框架的类型。 比如: ``` import { Application } from '@midwayjs/web'; @Controller() class HomeController { @App() app: Application; async invoke() { // this.app.getNamespace() => 'egg' } } ``` ## 其他的一些变化[​](#其他的一些变化 "其他的一些变化的直接链接") * 1、调整`@midwayjs/core` 默认 logger level 为 info,的 `coreLogger` 在服务器环境继续保留 warn * 2、faas 模块新增一些自定义触发器类型 * 3、在 jest 测试环境下,初始化的报错之前会被 jest 吞掉,新版本会通过 `console.error` 进行输出 * 4、修复 `configuration` 的 stop 生命周期,将以 `imports` 顺序的逆序执行 * 5、修复 `bootstrap` 使用 sticky 模式时,文件上传时的错误 * 6、支持 swager 的属性多类型展示 * 7、在 `midway-bin dev` 下,应用在本地开发时也可以快速使用 `--ssl` 来启动 https 服务 **标签:** * [release](/blog/tags/release.md) --- # Release 3.11.0 2023年3月27日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 很高兴给大家介绍我们的 3.11 新版本。 ## 安全性更新[​](#安全性更新 "安全性更新的直接链接") Upload 组件增加了安全性性能,在 `file` 上传模式下,我们发现在某些情况下文件的后缀和实际内容不匹配,导致可能会在服务器被动执行的安全性漏洞。 新版本我们增加了一个 MIME 配置,可以在上传时检查扩展名之外,额外检查 MIME 的类型,会更加安全。 ``` export default { // ... upload: { // ... // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: { '.jpg': 'image/jpeg', } }, } ``` 更多细节可以查看我们的 [Upload 组件](/docs/extensions/upload.md)。 ## New Feature[​](#new-feature "New Feature的直接链接") ### 精细化的 Mock 能力[​](#精细化的-mock-能力 "精细化的 Mock 能力的直接链接") 基于框架新提供的 `@Mock` 装饰器,可以方便的在不同的阶段进行数据模拟。同时作为逻辑的一部分,这个功能可以在开发和测试期被自动执行,方便用户的开发期模拟数据。 文档请参考 [数据模拟](/docs/mock.md)。 ### 中间件的 Match/Ignore[​](#中间件的-matchignore "中间件的 Match/Ignore的直接链接") Middleware 的功能进一步增强,match 和 ignore 现在可以是 `string` ,`regexp`,`function` 或者他们的数组组合形式。 ### 本地定时任务组件[​](#本地定时任务组件 "本地定时任务组件的直接链接") 之前我们提供了 bull 组件,用于分布式定时任务,在某些场景下,我们依旧需要单机的定时任务来赋值完成一些事项,原有的 task 组件实现了 cron 的部分,我们将其分离为 `cron` 组件,继续提供能力支持。 文档请参考 [cron 组件](/docs/extensions/cron.md)。 ### 标签组件[​](#标签组件 "标签组件的直接链接") 一种抽象化的服务端能力,用于数据筛选和处理。 文档请参考 [标签组件](/docs/extensions/tags.md)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.12.0 2023年8月14日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 在经过了几个月的努力更新之后,Midway 迎来了 3.12 版本,这是一个改动比较大的版本。 ## Breaking[​](#breaking "Breaking的直接链接") 从 v3.12.0 开始,Midway 移除了 Node.js v14 的 CI,原因请参考 [这里](/blog/remove-node-14-ci.md)。 ## Features[​](#features "Features的直接链接") ### 1、ESM 的支持[​](#1esm-的支持 "1、ESM 的支持的直接链接") 从 v3.12.0 开始,midway 支持创建 ESModule 项目,使用时和传统 CJS 项目会有所不同,由于时间紧迫,我们没有针对所有的组件进行测试,如有兼容性问题,请提交 issue。 此外,由于原有的工具体系已经无法很好的兼容 ESM 环境,为了减少维护成本,我们启用了一套全新的工具链,后续普通 CJS 项目也会统一到这一套上来。 更多细节请查看 [ESM 文档](/docs/esm.md)。 ### 2、FaaS 架构变更[​](#2faas-架构变更 "2、FaaS 架构变更的直接链接") 从 v3.12.0 开始,Midway FaaS 使用全新的一套架构支持现有的 Serverless 平台,这一部分后续将会在文档中体现。 主要的变化: * Midway 不再提供 “应用部署到弹性容器” 的兼容方案,如果平台支持使用传统应用部署 Serverless 容器,可以直接使用标准项目部署 * Midway 不再提供 f.yml 的维护工作,也不再提供部署功能,仅提供将现有函数信息写入平台配置的能力,所有的函数部署将由平台自己的工具进行部署 * 移除了原有通过 `@midwayjs/serverless-app` 启动和开发的模式,作为替代,将使用 `@midwayjs/fc-starter` 来进行开发 ## 其他的一些变化[​](#其他的一些变化 "其他的一些变化的直接链接") * 1、添加了 `ctx.getApp()` 方法,可以从 ctx 拿到自己 app,打通了整条从 framework,到 app 和 ctx 的链路 * 2、core 中的 httpClient 现在支持了所有的 http method * 3、增加了一个内部跳转 URL 的 api,`ctx.forward` * 4、IoC 容器增加了一个获取对象作用域的 API,`container.getInstanceScope(xxx)` ## 依赖更新[​](#依赖更新 "依赖更新的直接�链接") 具体可以查看 [Changelog](https://midwayjs.org/changelog/v3.12.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.13.0 2023年11月13日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 在双十一大促之后,Midway 迎来了 3.13 版本。 这个版本主要调整了内置的 logger 模块,使其可以支持 v3 版本的 logger 库。 ## Breaking[​](#breaking "Breaking的直接链接") * 1、未声明 `@midwayjs/logger` 依赖的用户的日志会出现意外错误 * 2、日志的配置定义可能丢失 这两个问题的解法在最后描述。 ## Feature[​](#feature "Feature的直接链接") ### 1、日志库升级到 v3[​](#1日志库升级到-v3 "1、日志库升级到 v3的直接链接") 经过一些时间的重写,Midway 搭配的 logger 库也升级到了 v3 版本,在 v3 版本中,我们移除了 winston 依赖,重写了整个 logger 模块,性能几乎翻了一倍。 从 [bundlephobia](https://bundlephobia.com/package/@midwayjs/logger) 中也能看到很明显的变化,代码的精简,使得运行更高效,代码更受控。 ![](https://img.alicdn.com/imgextra/i2/O1CN01NYSvTT1VZzbFdR9nF_!!6000000002668-2-tps-3474-1726.png) 从这个版本开始,Midway 的日志库可以选择使用 v2 或者 v3 的日志库,注意两者的配置是不同的。 如果你想查看两个版本的变化,可以点击 [这里](https://github.com/midwayjs/logger/blob/main/BREAKING-3.md)。 如果你希望升级到 v3 版本的日志库,我们的 [文档](/docs/logger.md) 也已经准备好了。 提示 注意,大版本升级请谨慎,尽可能验证功能点。 ### 2、内置服务新增 HealthService[​](#2内置服务新增-healthservice "2、内置服务新增 HealthService的直接链接") Midway 一直没有提供内置的健康检查方案,在这一版本,终于 [设计](https://github.com/midwayjs/midway/issues/3370) 了 HealthService 这一内置的检查服务。 HealthService 用于提供检查 API,在不同的情况下可以自行接入检查自定义组件的状态,[文档在此](/docs/built_in_service.md#midwayhealthservice)。 同时,我们的 Configuration 生命周期也增加了一个 `onHealthCheck` 的阶段,用于在每次检查时执行,[文档在此](/docs/lifecycle.md#onhealthcheck)。 这一功能目前还没有组件接入,我们将在后续的版本中逐步完善它。 ## 其他的一些变化[​](#其他的一些变化 "其他的一些变化的直接链接") * 1、jwt 组件的配置提供更多的选项,比如 sign,verify,decode 等选项 * 2、jwt 组件导出了默认的 jwt 实例,你可以从上面获取到一些内置的错误实例,方便过滤器拦截 * 3、http-proxy 组件现在可以通过 enable 配置来关闭了,这样你可以自行引入中间件做更多的自定义处理 * 4、在 web 框架中,context.state 的类型现在也可以自定义了,这在文档中也进行了更新 * 5、修复了 static-file 组件的 namespace 不正确的问题 * 6、修复了 framework 加载时主框架顺序不固定的问题 ## 解决方案[​](#解决方案 "解决方案的直接链接") ### 1、日志库丢失的方案[​](#1日志库丢失的方案 "1、日志库丢失的方案的直接链接") 由于大部分脚手架我们都已经引入了日志库依赖,一般来说不需要处理。 如果未引入日志库,框架会在启动时报错,只需要在 `package.json` 的依赖中写入即可。 ``` "dependencies": { + "@midwayjs/logger": "^2.19.2", }, ``` 注意,只有上述最新版本的日志库才兼容 `v3.13.0` 以上的 `@midwayjs/core`。 ### 2、日志的配置定义丢失[​](#2日志的配置定义丢失 "2、日志的配置定义丢失的直接链接") 由于 ts 类型合并需要在项目中显式声明一次,你需要在 `interface.ts` 中加入下面的代码。 ``` + import type {} from '@midwayjs/logger'; /** * @description User-Service parameters */ export interface IUserOptions { uid: number; } ``` 这样在 `src/config/config.default.ts` 中配置 `midwayLogger` 字段时,日志库的定义会恢复。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.14.0 2024年1月13日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 2024 新年快乐。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.14 版本,重写了 Cache 组件,同时也带来了一些新的特性,我们将一一介绍。 ## 全新的 CacheManager 组件[​](#全新的-cachemanager-组件 "全新的 CacheManager 组件的直接链接") 这一版本,Midway 将底层依赖的 `cache-manager` 模块升级到了 v5 版本,由于存在 Breaking Change,启用了一个新的 `@midwayjs/cache-manager` 组件,原有 `@midwayjs/cache` 组件不再更新。 在新组件中,提供了装饰器 `@Caching` 用于快速缓存函数结果。 比如: ``` @Caching('default', 100) async invokeData(name: string) { return name; } ``` 那么,在多次调用时就会缓存返回值,如果超时,则会返回新的值。 ``` await invokeData('harry'); // => harry await invokeData('harry1'); // => harry await invokeData('harry2'); // => harry await sleep(100); await invokeData('harry3'); // => harry3 ``` 这在一些性能敏感的场景会非常有用。 此外,`@Caching` 装饰器还支持多级缓存,如果一个缓存实例配置了多个 Store,那么它将自动根据缓存的顺序进行处理。 最重要的一点,组件通过新设计器的 `createRedisStore` 方法支持复用 Redis 组件的配置了。 ``` import { createRedisStore } from '@midwayjs/cache-manager'; // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: createRedisStore('default'), // ... }, }, }, redis: { clients: { default: { port: 6379, host: '127.0.0.1', } } } } ``` 这下不再需要配置 Redis 多遍了。 更多功能可以接着查看 [文档](/docs/extensions/caching.md)。 ## Swagger 组件的全新渲染方式[​](#swagger-组件的全新渲染方式 "Swagger 组件的全新渲染方式的直接链接") 由于之前的版本无法传递 `swagger-ui` 参数,这个版本设计了一组新的 UI 渲染方式,尽可能的帮助开发者自定义 UI。 现在,通过 `renderSwaggerUIDist` ,`renderJSON` 和 `renderSwaggerUIRemote` 方法,你可以选择自己喜欢的方式进行渲染。 ``` // src/config/config.default.ts import { renderSwaggerUIRemote } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderSwaggerUIRemote, swaggerUIRenderOptions: { // ... } }, } ``` 只要网络环境允许,即使不再引用 `swagger-ui-dist` 包,也可以通过 CDN 资源加载 UI,进一步减轻服务端压力。 也可以仅输出 `Swagger JSON` 内容,不提供 UI,这都可以根据业务随心配置。 ## 服务工厂实例支持优先级[​](#服务工厂实例支持优先级 "服务工厂实例支持优先级的直接链接") 这一版本可以针对创建出的实例设置不同的实例优先级。 比如: ``` // config.default.ts import { DEFAULT_PRIORITY } from '@midwayjs/core'; export default { redis: { clients: { instance1: { // ... }, instance2: { // ... } }, clientPriority: { instance1: DEFAULT_PRIORITY.L1, instance2: DEFAULT_PRIORITY.L3, } } } ``` 实例优先级不影响实例本身的功能,仅对实现了优先级判断的外部逻辑生效。 比如在健康检查时可以根据优先级进行忽略,低优先级的实例等价于弱依赖,会跳过健康检查。 这一功能目前仅有 `HealthService` 在使用,理论上别的逻辑也可能会用到,我们期待更多的可能性。 ## 更多的变化[​](#更多的变化 "更多的变化的直接链接") * [mikro-orm](https://github.com/mikro-orm/mikro-orm/releases) 于 2024.01.08 日发布了 v6 版本,现在 `@midwayjs/mikro` 组件也可以配合 v6 版本使用了 * `@midwayjs/redis` 增加了基于实例优先级的健康检查逻辑 * 服务工厂增加了 `getClients()` 和 `getClientKeys()` 方法,用于快速迭代实例 * 修复了 swagger 组件 ApiOperation 相关的一些问题 * mwtsc 工具修复了 windows 下开发的问题 * 文档的进一步精简,“其他” 菜单合并到了 “使用文档” 菜单中 此外,还有一大批依赖进行了更新,更多可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.14.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.15.0 2024年2月22日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 开工大吉。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.15 版本,主要新增了 MQTT 组件。 ## 全新的 MQTT 组件[​](#全新的-mqtt-组件 "全新的 MQTT 组件的直接链接") 可以通过配置 `sub` 和 `pub` 创建多个不同的实例,方便满足用户需求。 更多细节可以接着查看 [文档](/docs/extensions/mqtt.md)。 ## Swagger 方法级别的 Security 忽略[​](#swagger-方法级别的-security-忽略 "Swagger 方法级别的 Security 忽略的直接链接") 现在可以通过 `@ApiExcludeSecurity` 来忽略特定的接口。 ## mwtsc 工具支持了 Alias Path 的识别和替换[​](#mwtsc-工具支持了-alias-path-的识别和替换 "mwtsc 工具支持了 Alias Path 的识别和替换��的直接链接") 现在新工具已经可以认识 Alias 路径了。 ## 更多的变化[​](#更多的变化 "更多的变化的直接链接") * @koa/router 升级到了 v12 版本 * 自定义参数装饰器支持抛出异常 此外,还有一大批依赖进行了更新,更多可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.15.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.16.0 2024年5月7日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.16 版本,重构了 Swagger 组件,新增了一个租户组件。 ## Tenant[​](#tenant "Tenant的直接链接") 新增组件,提供 `TenantManager` 跨作用域管理租户信息。 比如: ``` import { TenantManager } from '@midwayjs/tenant'; import { Middleware, Inject, Singleton } from '@midwayjs/core'; // 请求链路中设置,中间件或者 Controller @Middleware() class TenantMiddleware { @Inject() tenantManager: tenant.TenantManager; resolve() { return async(ctx, next) => { this.tenantManager.setCurrentTenant({ id: '123', name: '我的租户' }); } } } // 服务中 @Singleton() class TenantService { @Inject() tenantManager: tenant.TenantManager; async getTenantInfo() { const tenantInfo = await this.tenantManager.getCurrentTenant(); console.log(tenantInfo.name); // 我的租户 } } ``` ## MQTT[​](#mqtt "MQTT的直接链接") 增加一个动态添加 mqtt 的方法。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as mqtt from '@midwayjs/mqtt'; @Configuration({ // ... }) class MainConfiguration { @Inject() mqttFramework: mqtt.Framework; async onReady() { await this.mqttFramework.createSubscriber({ host: 'test.mosquitto.org', port: 1883, }, { topicObject: 'test_midway_dynamic', }, TestSubscriber, 'test'); } } ``` ## Swagger[​](#swagger "Swagger的直接链接") 代码重构,支持了 oneof 等特殊用法,增加几十个用例确保输出和 openapi 3.0 一致。 比如: ``` import { ApiProperty } from '@midwayjs/swagger'; class Album { @ApiProperty() id: number; @ApiProperty() name: string; } class Photo { @ApiProperty({ oneOf: [ { type: 'string' }, { type: 'array', items: { type: 'string', }, }, ], }) name: string | string[]; @ApiProperty({ oneOf: [ { type: Album }, { type: 'array', items: { type: () => Album, }, }, ], }) album: Album | Album[]; } ``` ## koa[​](#koa "koa的直接链接") 提供了 query 的 parse 相关配置。 ## mwtsc 工具[​](#mwtsc-工具 "mwtsc 工具的直接链接") 切换回 tsc 自带的监听,稳定性更好。 ## 更多的变化[​](#更多的变化 "更多的变化的直接链接") * 修复了一个健康检查服务丢失 this 的问题 * 参数装饰器增加了一个当前实例的参数 以及一大批依赖进行了更新,可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.16.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.17.0 2024年8月29日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.17 版本,我们增加了一些新的特性,以及修复了一些问题,主要有: * 1、使用 替换原有的上传组件 * 2、`busboy` 上传的数据中的 `filedName`,在流式模式下不再提供 * 3、增加了一个新的服务端响应格式 * 4、class 中间件现在可以复用了 下面是更为细节的描述。 ## 定制服务端响应格式[​](#定制服务端响应格式 "定制服务端响应格式的直接链接") 在 3.17 版本中,我们增加了一个新的特性,可以定制服务端的响应的通用格式。 在之前的版本中,我们依靠中间件和过滤器来实现这个功能,但是这种方式有一些局限性,代码也会分散在不同的地方。 如果由一个统一的可调整的返回逻辑,可能更为合理,为此,添加了 `ServerResponse` 和 `HttpServerResponse` 的实现。 ``` import { ServerResponse, HttpServerResponse } from '@midwayjs/core'; @Controller() export class HomeController { @Inject() ctx: Context; @Get('/') async index() { return new HttpServerResponse(this.ctx).json({ success: true, data: 'hello world', }); } } ``` `HttpServerResponse` 是 `ServerResponse` 的一个 Http 实现,提供了一些常用的方法。 最为特殊的是他可以针对不同的数据格式,设置成功和失败的模版。 比如针对 JSON 数据,框架提供了以下的默认结构。 ``` HttpServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { return { success: 'true', data, }; } else { return { success: 'false', message: data || 'fail', }; } }; ``` 这样,当返回 JSON 格式时,就会按照这个模版进行返回。 ``` // 失败的返回 return new HttpServerResponse(this.ctx).fail().json('hello world'); ``` 就会获取到以下的数据。 ``` { success: 'false', message: 'hello world', } ``` 此外,基于这个模式,也同时实现了 SSE 的响应返回,也有其他的一些数据结构的返回,更多的内容,请参考 [细节文档](/docs/data_response.md)。 ## 上传组件[​](#上传组件 "上传组件的直接链接") 由于在小文件场景下上传碰到一些问题,从 v3.17 开始,基于 [busboy](https://github.com/mscdex/busboy) 实现了一个新的上传组件,替换原有的 `@midwayjs/upload`。 和原有的组件比有一些不同。 * 1、不再默认加载中间件,因为上传只是少部分接口的特殊逻辑,不需要全局加载 * 2、配置的 key 为了避免冲突,从 `upload` 变为 `busboy` 其余的使用方式和原有的上传组件一致, 更多细节请访问 [文档](/docs/extensions/busboy.md)。 ## 类中间件复用[​](#类中间件复用 "类中间件复用的直接链接") 在之前,如果需要复用中间件,只能使用函数中间件。 ``` const mw = (ctx, next) => { // ... } @Controller(/**/) export class HomeController { @Get('/', { middleware: [mw]}) async home() {} @Get('/api', { middleware: [mw]}) async api() {} } ``` 但是如果希望用上继承,或者 `match` 和 `ignore` 功能的,则是类的行为更为方便。 这个版本框架提供了 `createMiddleware` 功能,保留原有的逻辑同时,可以创建出一个新的中间件实例。 ``` @Middleware() export class ReportMiddleware implements IMiddleware { // ... } @Controller(/**/) export class HomeController { @Get('/', { middleware: [createMiddleware(ReportMiddleware, {}, 'name1')]}) async home() {} @Get('/api', { middleware: [createMiddleware(ReportMiddleware, {}, 'name2')]}) async api() {} } ``` 通过向 `createMiddleware` 传递不同的参数,以及中间件名字,就可以引用到不同的逻辑。 更多的细节,请查看 [Web中间件](/docs/middleware.md) 文档。 ## 更多的变化[​](#更多的变化 "更多的变化的直接链接") * 修复了一个多语言匹配 key 的问题 * 一些不合理类型定义的调整 以及一大批依赖进行了更新,可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.17.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.18.0 2024年9月22日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.18 版本,主要修复了新的 busboy 组件的一些遗留问题,以及新增了一种上传模式。 下面是更为细节的描述。 ## 异步迭代器上传模式[​](#异步迭代器上传模式 "异步迭代器上传模式的直接链接") 为了支持单次多个文件的流式上传,新版本使用了异步迭代器模型转换了上传流,这个新的模式用于替代原有的流式模式。 ``` // src/config/config.default.ts export default { // ... busboy: { mode: 'asyncIterator', }, } ``` 装饰器的入参也已经变成了异步迭代器。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload( @Files() fileIterator: AsyncGenerator, @Fields() fieldIterator: AsyncGenerator ) { // ... } } ``` 我们可以通过循环迭代器获取到每个上传的文件。 ``` for await (const file of fileIterator) { const { filename, data } = file; // ... } ``` 进而可以方便的做后续处理。 更多的内容,请参考 [细节文档](/docs/extensions/busboy.md)。 ## 此外还有更多的变化[​](#此外还有更多的变化 "此外还有更多的变化的直接链接") * 流式上传时的 `fieldName` 字段现在恢复了 * httpClient 现在默认的配置不再会被单次请求覆盖 * 数据源的优先级 NPE 报错现在已经修复了 * 业务中的 https 配置现在在 dev 的输出提示中也变得正常了 以及一大批依赖进行了更新,可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.18.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.19.0 2024年11月8日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.19 版本,主要引入了 Kafka 组件的重构,以及一些性能优化和 bug 修复。 下面是更为细节的描述。 ## Kafka 组件重构[​](#kafka-组件重构 "Kafka 组件重构的直接链接") 从 v3.19 开始,Kafka 组件进行了重构,配置和使用方法与之前有较大差异。虽然原有的使用方式仍然兼容,但文档不再保留。新的 Kafka 组件提供了更灵活的配置和更强大的功能。 ``` // src/config/config.default.ts export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, consumerOptions: { groupId: 'groupId-test-1', }, subscribeOptions: { topics: ['topic-test-1'], } }, }, producer: { clients: { pub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, producerOptions: { // ... } } } } } } ``` 更多的内容,请参考 [Kafka 组件文档](/docs/extensions/kafka.md)。 ## Mock 功能分组[​](#mock-功能分组 "Mock 功能分组的直接链接") 从 `3.19.0` 开始,Midway 的 mock 功能支持通过分组来管理不同的 mock 数据。你可以在创建 mock 时指定一个分组名称,这样可以在需要时单独恢复或清理某个分组的 mock 数据。 ``` import { mockContext, restoreMocks } from '@midwayjs/mock'; it('should test mock with groups', async () => { const app = await createApp(); // 创建普通对象的 mock const a = {}; mockProperty(a, 'getUser', async () => { return 'midway'; }, 'group1'); // 创建上下文的 mock mockContext(app, 'user', 'midway', 'group1'); mockContext(app, 'role', 'admin', 'group2'); // 恢复单个分组 restoreMocks('group1'); // 恢复所有分组 restoreAllMocks(); }); ``` 通过分组,你可以更灵活地管理和控制 mock 数据,特别是在复杂的测试场景中。 ## 新增了一个启动性能分析的命令[​](#新增了一个启动性能分析的命令 "新增了一个启动性能分析的命令的直接链接") 在开发环境下,新增了一个 `perf-init` 命令,用于在启动时初始化性能分析,需要配合最新的 `mwtsc` 一同使用。 ``` { "scripts": { "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js --perf-init" } } ``` ## 其他更新[​](#其他更新 "其他更新的直接链接") * 更新了一些依赖库以提高安全性和稳定性。 更多的更新内容和详细信息,请参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.19.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.20.0 2025年1月14日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.20 版本,主要引入了全新的 BullMQ 组件,作为 Bull 组件的升级替代,提供了更好的性能和更多的功能。 下面是更为细节的描述。 ## BullMQ 组件[​](#bullmq-组件 "BullMQ 组件的直接链接") 从 v3.20 开始,我们引入了全新的 BullMQ 组件,作为 Bull 组件的下一代实现。BullMQ 提供了更好的性能和更丰富的功能,包括: * 更好的类型支持 * 更强大的任务流(Flow Producer)功能 * 更完善的事件系统 * 更灵活的任务处理机制 基础使用示例: ``` // 定义任务处理器 @Processor('test') export class TestProcessor implements IProcessor { async execute(data: any) { // 处理任务逻辑 console.log('processing job:', data); } } // 执行任务 const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.runJob({ name: 'harry' }); ``` 任务流示例: ``` // 创建任务流 const flowProducer = bullmqFramework.createFlowProducer({}, 'test-flow'); await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', data: { value: 1 }, children: [ { name: 'child-job', queueName: 'flow-queue-2', data: { value: 2 } } ] }); ``` 更多的内容,请参考 [BullMQ 组件文档](/docs/extensions/bullmq.md)。 ## Bull 组件迁移提示[​](#bull-组件迁移提示 "Bull 组件迁移提示的直接链接") 从 v3.20 开始,我们推荐使用 BullMQ 组件替代原有的 Bull 组件。虽然 Bull 组件仍然可用,但我们建议在新项目中使用 BullMQ,并逐步将现有项目迁移到 BullMQ。 主要的变化包括: 1. 配置方式的调整 ``` // Bull export default { bull: { defaultQueueOptions: { redis: { port: 6379, host: '127.0.0.1', }, } }, } // BullMQ export default { bullmq: { defaultConnection: { port: 6379, host: '127.0.0.1', }, }, } ``` 2. Worker 和事件处理 ``` // BullMQ 新增了独立的 Worker 和 QueueEvents const worker = bullmqFramework.createWorker( 'queueName', async (job) => { // 处理任务 } ); const queueEvents = queue.createQueueEvents(); queueEvents.on('completed', ({ jobId }) => { console.log(`Job ${jobId} completed!`); }); ``` 3. 任务流支持 ``` // BullMQ 支持创建任务依赖关系 const flowProducer = bullmqFramework.createFlowProducer(); await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', children: [/* 子任务 */] }); ``` 4. 队列操作的增强 ``` // BullMQ 提供了更多队列操作方法 const queue = bullmqFramework.createQueue('test'); await queue.runJob(data); // 执行任务 await queue.createQueueEvents(); // 创建事件监听 await queue.createQueueEventsProducer(); // 创建事件生产者 ``` ## 其他更新[​](#其他更新 "其他更新的直接链接") * typeorm 组件现在可以指定自定义的 DataSource 了,以支持一些自定义数据源的场景 * 更新了一些依赖库以提高安全性和稳定性 更多的更新内容和详细信息,请参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.20.0)。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.6.0 2022年10月12日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway v3.6.0 包含一个重大的 [重构](https://github.com/midwayjs/midway/issues/2258),我们将 @midwayjs/decorator 包和 @midwayjs/core 包的内容进行了整合,未来所有的 decorator 相关的内容,都会由 @midwayjs/core 导出,@midwayjs/decorator 包仅做代理,保持功能兼容。 后续,我们将会在文档上进行 decorator 包的移除操作,在这段时间中,大家还是会看到 decorator 和 core 并存的情况。 ## Features[​](#features "Features的直接链接") ### 1、守卫[​](#1守卫 "1、守卫的直接链接") 从 v3.6.0 版本开始,我们提供了守卫能力,和 middleare,filter 类似,也是一个全框架复用的能力(koa/egg/grpc/rabbitmq/bull 等) ``` import { IMiddleware, Guard, IGuard } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, suppilerClz, methodName: string): Promise { // ... } } ``` 更多细节请查看 [文档](/docs/guard.md)。 ### 2、鉴权[​](#2鉴权 "2、鉴权的直接链接") 基于守卫功能的完成,我们可以自己定义 @Role 装饰器来完成简单的角色鉴权,同时我们也封装了 casbin 这一在社区较为通用的鉴权组件,方便大家使用。 比如,通过装饰器鉴权。 ``` import { Controller, Get, UseGuard } from '@midwayjs/decorator'; import { AuthActionVerb, AuthGuard, AuthPossession, UsePermission } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @UsePermission({ action: AuthActionVerb.READ, resource: Resource.USER_ROLES, possession: AuthPossession.ANY }) @Get('/users') async findAllUsers() { // ... } } ``` casbin 组件目前实现了 redis 和 typeorm 两个可以复用的适配器供大家选择,如有其他需求,可以额外进行适配。 更多细节,可以查看 [文档](/docs/extensions/casbin.md)。 ### 3、bull 组件[​](#3bull-组件 "3、bull 组件的直接链接") 我们新增了 bull 组件用于替代原有的 task 组件。 ``` // invoke const testQueue = this.bullFramework.getQueue('test'); // 立即执行这个任务 await testQueue?.runJob({ aaa: 1, bbb: 2, }); ``` 同时也提供了一个 bull-board 组件用于管理。 ![](https://cdn.nlark.com/yuque/0/2022/png/501408/1665641044268-8ebfc3bb-777b-43f8-a8d9-bfb77f95e47c.png) 更多细节,可以查看 文档。 更多介绍可以查看我们的 [b 站视频](https://www.bilibili.com/video/BV1ZB4y1j7H3/) **标签:** * [release](/blog/tags/release.md) --- # Release 3.7.0 2022年10月29日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway ## Features[​](#features "Features的直接链接") ### 1、支持了自定义的 web 参数装饰器[​](#1支持了自定义的-web-参数装饰器 "1、支持了自定义的 web 参数装饰器的直接链接") 在 Web 场景下,我们已经有 `@Query`,`@Body` 等参数装饰器,但是用于依旧有自定义的需求,如果这个时候通过现有的参数装饰器去定义会较为繁琐。 新版本提供了一个快速定义装饰器的能力,从而可以快速获取 ctx 属性。 ``` import { createRequestParamDecorator } from '@midwayjs/core'; // 实现装饰器 export const Token = createRequestParamDecorator(ctx => { return ctx.headers.token; }); // 使用装饰器 export class UserController { async invoke(@Token() token: string) { console.log(token); } } ``` ### 2、koa 组件新增 `serverTimeout` 配置[​](#2koa-组件新增-servertimeout-配置 "2koa-组件新增-servertimeout-配置的直接链接") 通过配置 `serverTimeout` 的值,可以定义服务端超时时间。 比如 1s 超时。 ``` export const koa = { serverTimeout: 1000, } ``` ### 3、多数据源时提供一个默认数据源的选项[​](#3多数据源时提供一个默认数据源的选项 "3、多数据源时提供一个默认数据源的选项的直接链接") 原有 typeorm 等数据库,如果指定了多个数据源,会默认以最后一个配置的数据源作为默认数据源。 默认数据源在 `InjectEntityModel` 时可以不指定名字。 新版本可以通过显式的配置默认数据源,使得这个行为更可控。 比如: ``` // config.default.ts export const typeorm = { dataSource: { abc: {}, bcd: {} }, defaultDataSourceName: 'bcd', } ``` 这样在使用时,如果不指定 `InjectEntityModel` 的第二个参数,则会在 `bcd` 这个 dataSource 中查询 Entity。 ### 3、新增了验证码组件[​](#3新增了验证码组件 "3、新增了验证码组件的直接链接") 通过新增的验证码组件,可以生成在登录中常见的图片,计算表达式等类型的验证码。 效果如下: ![](https://gw.alicdn.com/imgextra/i4/O1CN014cEzLH23vEniOgoyp_!!6000000007317-2-tps-120-40.png) ## Bugfix[​](#bugfix "Bugfix的直接链接") 修复了一个 import 顺序不一致,导致主框架获取错误的情况。 比如: ``` import * as bull from '@midwayjs/bull'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa, bull] }) export class MainConfiguration {} ``` 由于内部初始化是使用 require 的属性,即使 imports 的顺序固定,实际 bull 的 application 还是会变为 mainApp,这个时候去引入中间件,都会加到 bull 上,而不是 koa 上。 ## 其他的更新[​](#其他的更新 "其他的更新的直接链接") * **prometheus** 支持用户定义 Histogram * **faas** 调整了 `triggerFunction` 方法的参数 * 常态化依赖升级 **标签:** * [release](/blog/tags/release.md) --- # Release 3.8.0 2022年11月18日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway v3.8.0 是在经过大促之后的第一个 minor 版本,积攒了很多新的能力。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 ## Features[​](#features "Features的直接链接") ### 1、etcd 组件[​](#1etcd-组件 "1、etcd 组件的直接链接") 新增了一个 etcd 组件,方便用户使用,文档稍后提供。 ``` import { ETCDService } from '@midwayjs/etcd'; @Provide() export class UserService { @Inject() etcdService: ETCDService; async invoke() { const fooValue = await this.etcdService.get('foo').string(); console.log('foo was:', fooValue); // ... } } ``` 更多细节请查看 [文档](/docs/extensions/etcd.md)。 ### 2、ServiceFactory 支持设置默认客户端[​](#2servicefactory-支持设置默认客户端 "2、ServiceFactory 支持设置默认客户端的直接链接") ServiceFactory 提供了标准的多客户端能力,在默认的客户端中,我们可以设置非 default 的客户端作为默认客户端来使用。 这项能力支持 ServiceFactory 扩展出来的所有组件,包括 axios/cos/oss/redis/tablestore 等,用户自定义的组件也可以通过简单的适配享受到该能力。 比如,我们定义了多个 redis 客户端。 ``` export default { // ... redis: { clients: { default: { // ... }, default2: { // ... }, }, }, } ``` 默认注入的 `RedisService` 永远为 `default` 指向的客户端,而新版本我们可以通过设置默认的客户端名,来选择默认的客户端。 比如: ``` export default { // ... redis: { clients: { default: { // ... }, default2: { // ... }, }, defaultClientName: 'default2' }, } ``` 那么实际获取的 `redisService` 中是 `default2` 这个实例。 ``` @Provide() export class UserService { @Inject() redisService: RedisService; async invoke() { // this.redisService 中包裹的是 default2 } } ``` ### 3、数据源类型增加 `@InjectDataSource` 装饰器[​](#3数据源类型增加-injectdatasource-装饰器 "3数据源类型增加-injectdatasource-装饰器的直接链接") 为了简化获取数据源的过程,我们提供了一个新的 `@InjectDataSource` 装饰器,支持 mikro/sequelize/typeorm。 比如: ``` import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource, Repository } from 'typeorm'; @Provide() export class UserService { @InjectDataSource() defaultDataSource: DataSource; async invoke() { // ... } } ``` 也可以指定数据源。 ``` import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource, Repository } from 'typeorm'; @Provide() export class UserService { @InjectDataSource('default') defaultDataSource: DataSource; async invoke() { // ... } } ``` ## Bugfix[​](#bugfix "Bugfix的直接链接") * 1、修复 windows 下 entity 通配扫描,之前 windows 下的 entity 如果使用了通配符,会扫描失败,导致 entity 无法正确的加入到数据源中,新版本修复了该问题。 * 2、bull 的 Queue 定义处理问题,现在文档已经做了修改,注入的类型可以由 `IQueue` 变为 `BullQueue`。 ## Performance[​](#performance "Performance的直接链�接") 移除了 babel 编译出的 class 的兼容判断,框架整体性能提升约一倍。 **标签:** * [release](/blog/tags/release.md) --- # Release 3.9.0 2022年12月13日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 大促积攒了约两周的需求,统一在 v3.9.0 发布。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 ## Breaking[​](#breaking "Breaking的直接链接") 从 v3.9.0 开始,Midway 仅支持 Node.js `>=12.11.0` 版本。 ## Features[​](#features "Features的直接链接") ### 1、bootstrap 新增进程模型[​](#1bootstrap-新增进程模型 "1、bootstrap 新增进程模型的直接链接") 从 v3.9.0 开始,为了应对 socket.io 在 pm2 场景下的粘性会话,我们新增一种 master-worker 模型支持。简单来说,将由 pm2 来启动 midway 的 master,在 master 启动 worker,这样可以相对自由的定制 master 中的逻辑。 原有的 `Bootstrap` 之外,新增了一个 `ClusterManager` 来处理进程,示例如下: ``` const { ClusterManager, Bootstrap } = require('@midwayjs/bootstrap'); const clusterManager = new ClusterManager({ // 执行的子进程文件 exec: __filename, // 进程数 count: 2, }); if (clusterManager.isPrimary()) { // 启动主进程 clusterManager.start(); } else { // 原有子进程执行 Bootstrap.run(); } ``` 关于 socket.io 的粘性会话,我们将在 socket.io 组件中介绍更多。 ### 2、增加 @InjectClient 支持[​](#2增加-injectclient-支持 "2、增加 @InjectClient 支持的直接链接") 为 ServiceFactory 类型添加一个 `@InjectClient` 装饰器,方便在多客户端的的时候选择注入。 比如使用多个 redis 组件的时候。 原来: ``` import { RedisServiceFactory } from '@midwayjs/redis'; import { join } from 'path'; @Provide() export class UserService { @Inject() redisServiceFactory: RedisServiceFactory; async save() { const redis1 = this.redisServiceFactory.get('instance1'); const redis2 = this.redisServiceFactory.get('instance2'); //... } } ``` 现在可以通过注入来简化。 ``` import { RedisServiceFactory } from '@midwayjs/redis'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(RedisServiceFactory, 'instance1') redis1: RedisService; @InjectClient(RedisServiceFactory, 'instance2') redis2: RedisService; async save() { // this.redis1.set(...) // this.redis2.set(...) } } ``` 注意,所有继承于 ServiceFactory 的多实例组件都可以使用上述方法。 ### 3、casbin 支持 watcher 抽象[​](#3casbin-支持-watcher--抽象 "3、casbin 支持 watcher 抽象的直接链接") 除了社区的 casbin-redis-watcher,我们也提供了复用 redis 连接的 watcher,为了减少包,后续所有的 casbin/redis 相关的功能都将复用 `casbin-redis-adapter` 包。 使用示例: ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { createAdapter, createWatcher } from '@midwayjs/casbin-redis-adapter'; export default (appInfo: MidwayAppInfo) => { return { keys: '123456', redis: { clients: { 'node-casbin-official': { host: '127.0.0.1', port: 6379, password: '', db: '0', }, 'node-casbin-sub': { host: '127.0.0.1', port: 6379, password: '', db: '0', } } }, casbin: { // ... policyAdapter: createAdapter({ clientName: 'node-casbin-official' }), policyWatcher: createWatcher({ pubClientName: 'node-casbin-official', subClientName: 'node-casbin-sub', }) }, }; } ``` 由于 pub/sub 连接需要不同,这里定义了两个客户端,和 adapter 存储复用其中一个连接。 ### 4、DataSource 的不同路径支持[​](#4datasource-的不同路径支持 "4、DataSource 的不同路径支持的直接链接") 为了解决不同用户的使用习惯,我们支持了大多数可能的通配形式,现在你可以在 DataSource 中使用很多以前的格式。 比如: ``` export default { mysql: { dataSource: { dataSource1: { // ... entities: [ 'entity', // 特定目录 '**/abc/**', // 仅获取包含 abc 字符的目录下的文件 'abc/**/*.ts', // 特定目录 + 通配 'abc/*.entity.ts', // 匹配后缀 '**/*.entity.ts', // 通配加后缀匹配 '**/*.{j,t}s', // 后缀匹配 ] }, // ... // ... } } } ``` **标签:** * [release](/blog/tags/release.md) --- # Release 4.0.0 2026年4月2日 · 阅读需 6 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 今天,我们正式发布 Midway 4.0。 这是一次跨度很大的版本升级。它不是一次“把版本号从 3 改成 4”的常规发布,而是一次面向未来几年 Node.js 服务研发方式的重新整理:更清晰的启动机制、更统一的函数式能力、更明确的组件边界,以及更适合现代全栈协作的开发体验。 从 3.x 走到 4.0,我们做了很多克制但关键的调整。很多历史能力被重新审视,保留下来的是长期稳定、可维护、可组合的部分;新增的能力,也尽量围绕一个目标展开:让 Midway 在大型应用、组件体系、函数式接口、一体化开发这些场景下更顺手,也更可预期。 ## 为什么是 4.0[​](#为什么是-40 "为什么是 4.0的直接链接") Midway 过去这些年一直在同时面对几类需求: * 传统 Node.js 服务端应用要稳定 * 组件体系要可复用、可扩展 * 函数式写法要真正可落地,而不只是“能写” * 一体化开发要从概念走向工程化 * 框架内部机制要更透明,减少黑盒行为 在 3.x 时代,这些能力已经逐步成型;到了 4.0,我们决定把很多“约定优先但不够显式”的能力重新收束,换成更清楚、更稳定的框架边界。 所以 4.0 的关键词不是“更多功能”,而是: * 更显式 * 更统一 * 更现代 * 更适合长期维护 ## 4.0 的几个核心变化[​](#40-的几个核心变化 "4.0 的几个核心变化的直接链接") ### 1. Node.js 基线升级到 20+[​](#1-nodejs-基线升级到-20 "1. Node.js 基线升级到 20+的直接链接") Midway 4.0 从 Node.js 20 开始支持。 这意味着我们可以更放心地使用现代运行时能力,也意味着框架内部许多基础设施终于可以建立在一个更稳定的底座之上。对用户来说,这会减少很多历史兼容负担;对框架来说,这让后续演进空间明显变大。 ### 2. 启动机制从“隐式扫描”转向“显式声明”[​](#2-启动机制从隐式扫描转向显式声明 "2. 启动机制从“隐式扫描”转向“显式声明”的直接链接") 这是 4.0 最重要的变化之一。 过去,框架会在启动时做很多目录扫描、自动绑定、隐式发现。它在小项目里看起来很方便,但在大型工程、复杂组件、调试排查、测试隔离这些场景里,黑盒成本会越来越高。 4.0 改成了更显式的方式: * 需要扫描什么,由用户或组件明确声明 * 组件自己的加载边界更清楚 * 启动行为更可预测 * 测试和调试更容易定位问题 这个变化会让刚上手时多写一点配置,但长期看,它会让项目结构、工程边界和认知成本都更健康。 ### 3. 函数式能力正式走向统一[​](#3-函数式能力正式走向统一 "3. 函数式能力正式走向统一的直接链接") 4.0 不再把函数式能力当成一条旁支路线,而是把它整理成了清晰的一套主干能力。 现在统一推荐通过 `@midwayjs/core/functional` 使用函数式 API,比如: * `defineConfiguration` * `defineApi` * `useContext` * `useInject` * `useConfig` * `useLogger` 这意味着: * 函数式接口的入口统一了 * 组件提供 functional 能力的方式统一了 * 前后端共享契约、一体化协作更顺了 * 文档、教程、样例都可以围绕同一套模型展开 如果说过去函数式写法更像“一个实验方向”,那么在 4.0,它已经成为 Midway 的正式能力之一。 ### 4. 验证能力升级为新的 `validation` 体系[​](#4-验证能力升级为新的-validation-体系 "4-验证能力升级为新的-validation-体系的直接链接") 4.0 中我们新增了 `@midwayjs/validation`,用来替代原有的 `validate` 思路。 新的验证体系支持: * Joi * zod * class-validator 并且提供了更统一的扩展方式和更好的 i18n 支持。 这背后的考虑也很明确:验证器生态已经变化了,框架不应该继续把能力绑定在单一实现上。Midway 更适合做统一抽象层,把选择权和扩展能力交还给用户。 ### 5. 组件边界更清楚,内部机制更稳定[​](#5-组件边界更清楚内部机制更稳定 "5. 组件边界更清楚,内部机制更稳定的直接链接") 4.0 对核心容器、元数据管理、装饰器继承规则、生命周期、框架 hook、服务工厂等基础能力都做了系统整理。 这一部分不一定是最“显眼”的升级,但它对长期维护最关键。 包括但不限于: * 元数据管理机制重构 * 装饰器继承规则更明确 * 生命周期增加超时机制 * 依赖注入和循环依赖提示更清晰 * 默认开启 `asyncLocalStorage` * 一些历史遗留但语义不清的 API 被移除或重命名 这些改动共同指向一件事:让框架的内部行为和外部表现尽量一致,尽量减少“能跑但说不清为什么”的状态。 ## 这一版也意味着一次取舍[​](#这一版也意味着一次取舍 "这一版也意味着一次取舍的直接链接") 4.0 不是只做加法。 为了让整体模型更干净,我们也移除了或收缩了一部分历史能力,比如: * `@midwayjs/decorator` 独立包不再继续提供 4.x 版本 * 一部分历史兼容 API 被清理 * 部分低使用率、长期维护价值不高的组件退出 4.x 主线 * 一些容易制造歧义的隐式能力被移除 这类调整一定会带来迁移成本,但我们更希望把 4.0 建立在一个能继续往前走很多年的基础上,而不是把旧负担不断往后拖。 ## 对不同用户意味着什么[​](#对不同用户意味着什么 "对不同用户意味着什么的直接链接") ### 如果你是 3.x 用户[​](#如果你是-3x-用户 "如果你是 3.x 用户的直接链接") 你会感受到两件事: * 一开始需要适应一些显式配置和新约定 * 适应之后,项目边界会更清楚 迁移到 4.0 的重点,不只是把依赖版本改掉,而是理解新的启动方式、函数式导出路径、验证体系和部分核心 API 的变化。我们也会继续补充升级文档、教程和示例,帮助大家更平滑地完成迁移。 ### 如果你是新用户[​](#如果你是新用户 "如果你是新用户的直接链接") 4.0 会是一个更合适的起点。 你接触到的 Midway 将是一个更统一的版本: * 当前文档以 4.0 为主 * 教程会同时覆盖 Class 和 Functional * 一体化能力会围绕真实工程方式展开 * 新样例和新组件都优先按 4.0 设计 这会让学习路径更连贯,也更接近我们真正推荐的用法。 ## 接下来我们会继续做什么[​](#接下来我们会继续做什么 "接下来我们会继续做什么的直接链接") 4.0 正式发布,不代表演进结束;相反,它意味着很多事情终于可以在一个稳定基础上继续推进。 接下来我们会持续投入在这些方向: * 继续完善 4.0 文档与升级指南 * 补齐 Class / Functional 双教程 * 完善一体化开发、前端协作、Web Bridge 相关体验 * 持续整理组件生态的 4.0 支持情况 * 让 CLI、脚手架、官网和文档口径继续统一 ## 感谢[​](#感谢 "感谢的直接链接") Midway 能走到 4.0,不是一两次重构,也不是一两个月冲刺的结果。 这是过去很多年里,框架、组件、文档、样例、社区反馈、线上实践一点点积累出来的版本。感谢所有提交过 issue、PR、示例、建议和反馈的朋友,也感谢所有在线上项目里真正使用 Midway、给我们带来真实问题的人。 框架真正的价值,从来不在发布日志里,而在一个个项目能不能更稳地上线、能不能更清楚地维护、能不能让团队协作少一些摩擦。 Midway 4.0,正式发布。 欢迎升级,欢迎继续给我们反馈。 **标签:** * [release](/blog/tags/release.md) --- # Release 4.0.0-beta.1 2025年8月29日 · 阅读需 4 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 这是全新的 Midway 4.0 的变化,这是一个非常重大的版本。 * 全局变化 * 框架支持从 Node.js >=20 开始 * 默认开启 asyncLocalStorage * 编程范式 * 不再以黑盒方式提供框架启动时的目录文件扫描自动绑定能力,改为显式声明,每个组件都可以有自己的绑定和加载方式 * 组件包查找规范变化,现在会查找 `index.ts`,`configuration.ts`,以及 `package.json` 中 main 定义的路径 * 统一规范函数式的导出路径,为组件包下的 `functional` 路径,如 `@midwayjs/core/functional` * 【core】 * 通用能力 * 由于使用率较低且影响依赖注入容器逻辑,移除了流程控制 `Pipeline` 相关的能力 * 移除之前版本中框架启动时的目录文件扫描自动绑定能力,现在需要显式增加一个 file detector,可以自由配置其需要扫描和忽略的目录或者文件 * 移除了会和 validate 的转换产生歧义的请求参数自动 DTO 转换功能,现在自动转换仅在 `validate` 或者 `validation` 组件开启时生效 * `onReady` 等生命周期现在增加了超时机制,默认 30s * 函数式编程 * 提供与 `@Configuration` 同样功能的 `defineConfiguration` 方法 * 提供内置的 hooks 方法,如 `useContext`, `useLogger`, `useInject`, `useConfig`, `useApp`, `useMainApp` 等 * 提供了函数式方法的导出规范,新开发的 hooks 放在 `functional` 目录中,使用子模块方式导出 * 装饰器部分 * 为了更好的管理元数据,重构了 `DecoratorManager`,增加新的 `MetadataManager`,增加了更加方便的聚合和拷贝元数据的能力 * 明确各种装饰器继承的情况,默认情况下,类装饰器和参数装饰器不继承,属性装饰器和方法装饰器继承 * 使用 `@MainApp()` 代替 `@App()` 空参数 * 使用 `@Config(ALL)` 替换为更为明确的 `@AllConfig()` 装饰器 * 移除 `@Configuration` 中的 `conflictCheck` 和 `detectorOptions`, 这些配置将移动到 `detector` 中 * `DecoratorManager` 中的 `listPrelaodModules` 调整为 `listPreStartModule`,`savePreloadModule` 调整为 `savePreStartModule` ,使其语义更加明确 * 依赖注入 * 移除了 `container.get` 和 `container.getAsync` 的一部分无用的参数 * 优化了循环依赖时展示的依赖链路信息以及 definition 未找到时的输出信息 * 单例对象现在和 `registerObject` 的对象存储的位置一致了 * 增加了一个动态依赖注入容器,用于在开发期动态替换实例,支持 HMR 功能 * 框架机制 * `BaseFramework` 移除了令人疑惑的 container 相关 hook 方法,现在都统一使用 `applicationInitialize` * 移除框架的 `MidwayFrameworkType`,以及对应的 `getFrameworkType()` 方法 * 移除了特定框架下令人疑惑的 `contextLoggerApplyLogger` 和 `contextLoggerFormat` 配置,现在如果要配置框架特定的 logger,使用 `setFrameworkLoggerName` 方法 * `ServiceFactory` 和 `DataSourceManager` 现在启动可以通过 `initClients` 的参数 `concurrent` 支持并发,由组件自行控制是否支持 * `DataSourceManager` 原有的 `cacheInstance` 和 `validateConnection` 选项废弃 * `MidwayConfigServce` 在获取配置时可以增加默认值 * 增加服务发现基础功能,增加了 `consul` 、`redis` 、`etcd` 的实现 * 【decorator】移除,API 都移动到 `@midwayjs/core`,不再单独提供 4.x 版本 * 【async-hooks-context-manager】现在默认开启 async\_local\_storage,代码合并至 core 模块中 * 【axios】移除了废弃的 `axios` 导出 * 【socketio】移除了内置的 `socket.io-redis` * 【validate】 * 由于固化了 Joi 作为验证器,不再更新 * 移除 `@Rule` 作为类装饰器的功能 * 移除属性 `@Rule` 参数传递类本身的功能 * 【validation】新增组件,替代原有 validate 组件 * 支持多种验证器,如 Joi, zod, class-validator,提供内置的 i18n 支持 * 可自定义扩展验证器 * 【mock】 * 由于移除了框架启动的扫描能力,如果有大量历史测试不方便修改,可以使用提供的 `createLegacyApp`,`createLegacyLightApp`,`createLegacyFunctionApp` ,对应之前的 `createApp`,`createLightApp`, `createFunctionApp` * 移除了 `createApp`,`createLightApp`, `createFunctionApp` 方法的最后一个参数,现在额外指定组件可以写到 `options.imports` 中 * 【sequelize】 * 移除老版本配置的兼容代码,以及历史装饰器导出,如 `@BaseTable` * 移除默认启动时数据源连接校验 `validateConnection`,如有需求,可以在配置中单独开启 * 【tags】移除,不再提供 4.x 版本 * 【processAgent】移除,不再提供 4.x 版本 * 【event-emitter] 新增组件,提供事件触发和监听能力支持 **标签:** * [release](/blog/tags/release.md) --- # Release 4.0.0-beta.10 2026年1月11日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 这是 Midway 4.0 的第十个 beta 版本。 本次版本新增一次性脚本执行组件与 commander 命令行组件,并补充了相关文档说明。 ## 🚀 主要新增功能[​](#-主要新增功能 "🚀 主要新增功能的直接链接") ### 单次执行组件(One-shot)[​](#单次执行组件one-shot "单次执行组件(One-shot)的直接链接") 新增 `@midwayjs/one-shot` 组件,用于在应用启动后执行一次性脚本逻辑,支持在 `onServerReady` 生命周期中触发。 示例: ``` import { Configuration, Inject } from '@midwayjs/core'; import * as oneShot from '@midwayjs/one-shot'; import { Framework } from '@midwayjs/one-shot'; import { SyncUserScript } from './script/syncUser'; @Configuration({ imports: [oneShot], }) export class MainConfiguration { @Inject() framework: Framework; async onServerReady() { await this.framework.runScript(SyncUserScript, { id: 42 }); } } ``` 更多说明请参考 [单次执行组件文档](/docs/next/extensions/one-shot)。 ### Commander 命令行组件[​](#commander-命令行组件 "Commander 命令行组件的直接链接") 新增 `@midwayjs/commander` 命令行组件,提供命令注册、参数解析、上下文创建与中间件链支持,并内置基于 enquirer 的交互式提问能力。 示例: ``` import { Command, CommandRunner } from '@midwayjs/commander'; @Command({ name: 'hello', arguments: '' }) export class HelloCommand implements CommandRunner { async run([name]: string[]) { return `hello ${name}`; } } ``` 更多说明请参考 [Commander 组件文档](/docs/next/extensions/commander)。 ## 🐛 修复与改进[​](#-修复与改进 "🐛 修复与改进的直接链接") * 文档更新:validation 组件升级说明、one-shot 组件文档、commander 目录结构示例 **标签:** * [release](/blog/tags/release.md) --- # Release 4.0.0-beta.2 2025年10月5日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 这是全新的 Midway 4.0 的第二个 beta 版本。 在这个版本中,我们带来了一些重要的新功能和改进,主要包括 MCP 组件的全面支持以及 mock 组件的测试体验优化。 ## 🚀 主要新增功能[​](#-主要新增功能 "🚀 主要新增功能的直接链接") ### MCP (Model Context Protocol) 支持[​](#mcp-model-context-protocol-支持 "MCP (Model Context Protocol) 支持的直接链接") 我们正式加入了对 MCP 的完整支持。MCP 是由 Anthropic 开发的开放标准协议,用于将 AI 模型与外部数据源和工具安全连接。 Midway 现在提供了: * 完整的 MCP 服务器框架封装 * 支持多种传输方式:stdio、stream-http、sse * 基于装饰器的开发体验 * 与现有 HTTP 框架(Express、Koa、Egg.js)的无缝集成 使用 Midway 可以快速创建 MCP 服务,为 AI 应用程序提供标准化的数据访问和工具调用接口。 ``` import { Tool, IMcpTool } from '@midwayjs/mcp'; import { z } from 'zod'; @Tool('databaes-tool', { description: 'A tool to query user information from the database', inputSchema: { name: z.string().describe('name to query'), } }) export class DatabaseTool implements IMcpTool { async execute(args: { name: string }) { // 模拟数据库查询 return { content: [{ type: 'text', text: [{ id: 1, name: args.name }] }], } } } ``` 更多关于 MCP 的详细使用方法和配置选项,请参考 [MCP 组件文档](/docs/next/extensions/mcp)。 ### Mock 组件测试改进[​](#mock-组件测试改进 "Mock 组件测试改进的直接链接") 针对开发者测试体验的优化,我们为 mock 组件的 `createApp` 方法增加了完整的生命周期支持: * 新增 `onReady`、`onStop`、`onConfigLoad`、`onServerReady`、`onHealthCheck` 等生命周期钩子 这些改进让测试代码能够更准确地反映真实运行环境的行为,提升测试的可靠性。 ``` const app = await createApp(join(__dirname, 'fixtures', 'base-app'), { onReady: async () => { console.log('应用准备就绪'); }, onStop: async () => { console.log('应用停止'); } }); ``` **标签:** * [release](/blog/tags/release.md) --- # Release 4.0.0-beta.9 2026年1月3日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 这是 Midway 4.0 的第九个 beta 版本。 在这个版本中,我们新增了基于 `piscina` 的后台任务组件,支持 CPU 密集型任务的处理,同时升级 Zod 至 v4 版本,并修复了 Swagger UI 等问题。 ## 🚀 主要新增功能[​](#-主要新增功能 "🚀 主要新增功能的直接链接") ### Background Task (Piscina) 支持[​](#background-task-piscina-支持 "Background Task (Piscina) 支持的直接链接") 我们新增了 `@midwayjs/piscina` 组件,基于 [piscina](https://github.com/piscinajs/piscina) 封装,提供了多线程后台任务处理能力。这使得 Midway 应用可以轻松处理 CPU 密集型任务,而不会阻塞主线程。 你可以使用装饰器快速定义一个后台任务: ``` import { IPiscinaTask, PiscinaTask } from '@midwayjs/piscina'; /** * 计算任务 */ @PiscinaTask('calculate') export class CalculateTask implements IPiscinaTask { async execute(payload: { a: number; b: number; operation: 'multiply' | 'add' }) { const { a = 0, b = 0, operation = 'multiply' } = payload || {}; if (operation === 'multiply') { return a * b; } else { return a + b; } } } ``` 并在服务中调用它: ``` @Inject() piscinaFramework: PiscinaFramework; // ... const result = await this.piscinaFramework.runTask('calculate', { a: 10, b: 20, operation: 'add' }); ``` 更多详细用法请参考 [Piscina 组件文档](/docs/next/extensions/piscina)。 ### Zod v4 支持[​](#zod-v4-支持 "Zod v4 支持的直接链接") 我们升级了验证组件以支持 Zod v4 版本,现在你可以使用 Zod v4 的新特性来进行参数校验。 ## 🐛 修复与改进[​](#-修复与改进 "🐛 修复与改进的直接链接") * 修复了 Swagger UI `displayOptions` 渲染字符串的问题 * 修复了 View 组件中异步渲染触发时机的问题 * 修复了 Busboy 和 Upload 组件的校验逻辑 * 新增了服务发现 (Service Discovery) 的文档说明 * 依赖更新: * 更新 `bullmq` 至 v5.66.4 * 更新 `express` 至 v4.22.1 * 更新 `grpc-js` 至 v1.14.3 **标签:** * [release](/blog/tags/release.md) --- # 移除 Node.js v14 的 CI 环境 2023年8月13日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 最近一段时间,我们发现越来越多的库移除了 Node.js v14 的支持。 有些库是升级的大版本,有些库仅仅只升级 minor 版本,这使得依赖他们的业务、模块乃至框架都很难信任社区的 SemVer 版本约定了。 为了保持 Midway 的单测正常运行,从 v3.12.0 开始,Midway 移除了 Node.js v14 的 CI,这意味着我们无法测试 Node.js v16 以下社区库的兼容性,只能靠社区库更新的 Changelog 以及我们的经验来保证。 如果我们发现某些库只支持特定版本的 Node.js,我们会在 `package.json` 中进行版本限制,如果你发现某些库的版本更新无法在低版本 Node.js 中运行,且 Midway 的组件没有进行限制,请通知我们。 最后再次提醒,如果没有强需求,请使用 Node.js v16 以上版本。 **标签:** * [node](/blog/tags/node.md) --- # 移除 node v12 相关的依赖 2022年11月4日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 由于最近 node v18 标记为 LTS,社区相关的相关的依赖都移除了 node v12 的支持,导致 Midway 的基建,单测已经无法正常的执行。 虽然 Midway 框架本身支持在 Node v12 下运行,但是例如 jest 等工具的最新版本已经无法执行。经过内部讨论后决定,在 Github Action 中移除 Midway 以及相关库的 Node v12 的单测,为此,相关的依赖会进行调整,包括: * 1、脚手架的变更 * `@midwayjs/cli` 升级为 `^2.0.0` * `jest` ,`@types/jest`,`ts-jest` 升级为 v29 版本 * typescript 升级为 `4.8.x` * 2、Midway 本身 * 移除 node v12 的 github action 执行 * 鉴于部分环境的情况,继续经验支持 node v12 的运行,有 node v12 的问题可以 issue 提问 依赖的变更可以参考: ``` "devDependencies": { "@midwayjs/cli": "^2.0.0", "@types/jest": "^29.2.0", "jest": "^29.2.2", "ts-jest": "^29.0.3", "typescript": "~4.8.0" } ``` **标签:** * [node](/blog/tags/node.md) --- # 新增 @midwayjs/skill-midway 2026年4月6日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 我们新增了 `@midwayjs/skill-midway`。 这个包提供两类能力: * 把 Midway Skill 安装到项目里的 AI 工具目录 * 在本地查询 Midway 的文档、API、包信息和 changelog ## 怎么安装[​](#怎么安装 "怎么安装的直接链接") 先在项目里安装依赖: ``` $ npm i @midwayjs/skill-midway@4 --save-dev ``` 或者: ``` $ pnpm add -D @midwayjs/skill-midway@4 ``` 安装完成后,执行: ``` $ npx midway-skill install ``` 命令会进入交互式选择。 如果你希望直接指定目标,也可以这样执行: ``` $ npx midway-skill install --target codex $ npx midway-skill install --target cursor $ npx midway-skill install --target trae ``` 默认是项目级安装,会把 Skill 写到当前项目目录,而不是全局目录。 目前已经支持多种 AI 工具,包括 Codex、Cursor、Trae、Claude、Windsurf、GitHub Copilot 等。 相关文档可以查看: * [Midway Skill 使用](https://midwayjs.org/docs/skill_midway) **标签:** * [midway](/blog/tags/midway.md) * [ai](/blog/tags/ai.md) * [skill](/blog/tags/skill.md) --- ## A[​](#A "A的直接链接") * [ai1](/blog/tags/ai.md) *** --- ## [新增 @midwayjs/skill-midway](/blog/skill/midway.md) 2026年4月6日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 我们新增了 `@midwayjs/skill-midway`。 这个包提供两类能力: * 把 Midway Skill 安装到项目里的 AI 工具目录 * 在本地查询 Midway 的文档、API、包信息和 changelog **标签:** * [midway](/blog/tags/midway.md) * [ai](/blog/tags/ai.md) * [skill](/blog/tags/skill.md) [**阅读更多**](/blog/skill/midway.md) --- ## [core 和 decorator 包合并的影响](/blog/core-decorator-merge.md) 2022年10月26日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 从 v3.6.0 开始,Midway 在代码层面将 `@midwayjs/decorator` 中的代码迁移到了 `@midwayjs/core` 中,未来 `@midwayjs/decorator` 包将逐步减少使用。 `@midwayjs/decorator` 中的代码全部从 `@midwayjs/core` 中代理出来,代码层面保持向下兼容。 最近发现有些用户会出现类似下面的报错: ![](https://img.alicdn.com/imgextra/i3/O1CN01ZUf1P31oSBRQlBEhv_!!6000000005223-0-tps-3148-554.jpg) 原因有两类: **1、v3 的版本的 core 和组件版本不一致** 在开发时,直接使用 `npm install` 而安装了 latest 版本(>=v3.6.0) 的组件。 由于 core 的版本依旧在 `3.6.0` 以下,但是组件依赖了最新版本 core 的 API,从而报错。 我们在文档 [如何更新 Midway](/docs/how_to_update_midway.md) 中有描述,请不要单独升级某个组件包。 解决方案有两个: * 1、可以使用低版本的组件,比如 `3.6.0` 以下 * 2、或者升级 core 和其他的版本统一到 `3.6.0` 以上 **2、v2 的版本使用了 v3 的组件** 在 v2 版本时,直接使用 `npm install` 而错误安装了 latest 版本(v3) 的组件。 我们为了适配最新的版本正好升级了 v3 的组件,从而暴露了引了错误的版本的这个问题。 现在 v2 和 v3 的组件不保证能完全兼容,所以请在安装时做好区分。 解决方案:使用 v2 版本的组件。 **标签:** * [decorator](/blog/tags/decorator.md) * [core](/blog/tags/core.md) --- ## [core 和 decorator 包合并的影响](/blog/core-decorator-merge.md) 2022年10月26日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 从 v3.6.0 开始,Midway 在代码层面将 `@midwayjs/decorator` 中的代码迁移到了 `@midwayjs/core` 中,未来 `@midwayjs/decorator` 包将逐步减少使用。 `@midwayjs/decorator` 中的代码全部从 `@midwayjs/core` 中代理出来,代码层面保持向下兼容。 最近发现有些用户会出现类似下面的报错: ![](https://img.alicdn.com/imgextra/i3/O1CN01ZUf1P31oSBRQlBEhv_!!6000000005223-0-tps-3148-554.jpg) 原因有两类: **1、v3 的版本的 core 和组件版本不一致** 在开发时,直接使用 `npm install` 而安装了 latest 版本(>=v3.6.0) 的组件。 由于 core 的版本依旧在 `3.6.0` 以下,但是组件依赖了最新版本 core 的 API,从而报错。 我们在文档 [如何更新 Midway](/docs/how_to_update_midway.md) 中有描述,请不要单独升级某个组件包。 解决方案有两个: * 1、可以使用低版本的组件,比如 `3.6.0` 以下 * 2、或者升级 core 和其他的版本统一到 `3.6.0` 以上 **2、v2 的版本使用了 v3 的组件** 在 v2 版本时,直接使用 `npm install` 而错误安装了 latest 版本(v3) 的组件。 我们为了适配最新的版本正好升级了 v3 的组件,从而暴露了引了错误的版本的这个问题。 现在 v2 和 v3 的组件不保证能完全兼容,所以请在安装时做好区分。 解决方案:使用 v2 版本的组件。 **标签:** * [decorator](/blog/tags/decorator.md) * [core](/blog/tags/core.md) --- ## [Jest v29 更新](/blog/jest_update.md) 2022年10月29日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 最近由于 axios 组件的升级,可能在单测时会出现下面的报错。 ![](https://img.alicdn.com/imgextra/i2/O1CN01G4Ze0F1qVxwcNwYeF_!!6000000005502-2-tps-2080-1158.png) 原因为脚手架自带的 jest v26 不支持 package.json 中的 `exports` 逻辑。 解决方法: * 1、将 `package.json` 中的 jest 版本从 v26 更新为 v29 * 2、将 `@midwayjs/cli` 的版本升级为 `1.3.16` 版本以上,也可以升级到 `2.0` 示例如下: ``` { "devDependencies": { "@midwayjs/cli": "^2.0.1", "@types/jest": "^29.2.0", "jest": "^29.2.2", "ts-jest": "^29.0.3", // ... } } ``` **标签:** * [更新](/blog/tags/更新.md) * [jest](/blog/tags/jest.md) --- ## [新增 @midwayjs/skill-midway](/blog/skill/midway.md) 2026年4月6日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 我们新增了 `@midwayjs/skill-midway`。 这个包提供两类能力: * 把 Midway Skill 安装到项目里的 AI 工具目录 * 在本地查询 Midway 的文档、API、包信息和 changelog **标签:** * [midway](/blog/tags/midway.md) * [ai](/blog/tags/ai.md) * [skill](/blog/tags/skill.md) [**阅读更多**](/blog/skill/midway.md) --- ## [mwtsc 增加版本检查](/blog/mwtsc-check.md) 2024年7月12日 · 阅读需 2 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 由于 Midway 版本发布规则,`@midwayjs/core` 和组件有着版本对应关系,即低版本的 `@midwayjs/core` 无法使用高版本的组件。 比如 `@midwayjs/axios@3.17.0` 可能使用了高版本的 API,是无法在 `@midwayjs/core@3.16.0` 版本上执行的。 由于 npm 等包管理的特性,包安装时不存在联系,`npm i @midwayjs/axios` 时往往只会安装组件最新的版本,非常容易造成兼容性问题。 为此我们提供了 `npx midway-version` 命令,可以快速检查版本之间的兼容性错误。 在推行一阵子之后,我们发现很少有用户主动去执行这样的指令,只会在出错时被动执行,再加上锁包和不锁包的复杂场景,会出现一些很难复现和排查的现象。 为了降低复杂性,在 mwtsc 新版本的启动阶段,我们也加入了检查代码。 ![](https://img.alicdn.com/imgextra/i3/O1CN01ZHQcs51tDb5HrSviC_!!6000000005868-2-tps-1550-420.png) 如果出现不兼容的版本,工具会进行提示。 此外,新增的 `npx midway-version -m` 指令可以让固化版本的用户也享受到更新工具。 和之前的 `-u` 指令不同,`-m` 会使用当前的 `@midwayjs/core` 版本,更新组件到最兼容的版本,而不是最新版本。 结合 `mwtsc` 和 `midway-version` 工具,可以更简单的管理版本,如有问题可以反馈给我们改进。 **标签:** * [mwtsc](/blog/tags/mwtsc.md) --- ## [移除 Node.js v14 的 CI 环境](/blog/remove-node-14-ci.md) 2023年8月13日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 最近一段时间,我们发现越来越多的库移除了 Node.js v14 的支持。 有些库是升级的大版本,有些库仅仅只升级 minor 版本,这使得依赖他们的业务、模块乃至框架都很难信任社区的 SemVer 版本约定了。 为了保持 Midway 的单测正常运行,从 v3.12.0 开始,Midway 移除了 Node.js v14 的 CI,这意味着我们无法测试 Node.js v16 以下社区库的兼容性,只能靠社区库更新的 Changelog 以及我们的经验来保证。 如果我们发现某些库只支持特定版本的 Node.js,我们会在 `package.json` 中进行版本限制,如果你发现某些库的版本更新无法在低版本 Node.js 中运行,且 Midway 的组件没有进行限制,请通知我们。 最后再次提醒,如果没有强需求,请使用 Node.js v16 以上版本。 **标签:** * [node](/blog/tags/node.md) --- ## [Release 4.0.0](/blog/release/4.0.0.md) 2026年4月2日 · 阅读需 6 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 今天,我们正式发布 Midway 4.0。 这是一次跨度很大的版本升级。它不是一次“把版本号从 3 改成 4”的常规发布,而是一次面向未来几年 Node.js 服务研发方式的重新整理:更清晰的启动机制、更统一的函数式能力、更明确的组件边界,以及更适合现代全栈协作的开发体验。 **标签:** * [release](/blog/tags/release.md) [**阅读更多**](/blog/release/4.0.0.md) --- ## [Release 3.20.0](/blog/release/3.20.0.md) 2025年1月14日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.20 版本,主要引入了全新的 BullMQ 组件,作为 Bull 组件的升级替代,提供了更好的性能和更多的功能。 下面是更为细节的描述。 ## BullMQ 组件[​](#bullmq-组件 "BullMQ 组件的直接链接") 从 v3.20 开始,我们引入了全新的 BullMQ 组件,作为 Bull 组件的下一代实现。BullMQ 提供了更好的性能和更丰富的功能,包括: * 更好的类型支持 * 更强大的任务流(Flow Producer)功能 * 更完善的事件系统 * 更灵活的任务处理机制 基础使用示例: ``` // 定义任务处理器 @Processor('test') export class TestProcessor implements IProcessor { async execute(data: any) { // 处理任务逻辑 console.log('processing job:', data); } } // 执行任务 const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.runJob({ name: 'harry' }); ``` 任务流示例: ``` // 创建任务流 const flowProducer = bullmqFramework.createFlowProducer({}, 'test-flow'); await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', data: { value: 1 }, children: [ { name: 'child-job', queueName: 'flow-queue-2', data: { value: 2 } } ] }); ``` 更多的内容,请参考 [BullMQ 组件文档](/docs/extensions/bullmq.md)。 ## Bull 组件迁移提示[​](#bull-组件迁移提示 "Bull 组件迁移提示的直接链接") 从 v3.20 开始,我们推荐使用 BullMQ 组件替代原有的 Bull 组件。虽然 Bull 组件仍然可用,但我们建议在新项目中使用 BullMQ,并逐步将现有项目迁移到 BullMQ。 主要的变化包括: 1. 配置方式的调整 ``` // Bull export default { bull: { defaultQueueOptions: { redis: { port: 6379, host: '127.0.0.1', }, } }, } // BullMQ export default { bullmq: { defaultConnection: { port: 6379, host: '127.0.0.1', }, }, } ``` 2. Worker 和事件处理 ``` // BullMQ 新增了独立的 Worker 和 QueueEvents const worker = bullmqFramework.createWorker( 'queueName', async (job) => { // 处理任务 } ); const queueEvents = queue.createQueueEvents(); queueEvents.on('completed', ({ jobId }) => { console.log(`Job ${jobId} completed!`); }); ``` 3. 任务流支持 ``` // BullMQ 支持创建任务依赖关系 const flowProducer = bullmqFramework.createFlowProducer(); await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', children: [/* 子任务 */] }); ``` 4. 队列操作的增强 ``` // BullMQ 提供了更多队列操作方法 const queue = bullmqFramework.createQueue('test'); await queue.runJob(data); // 执行任务 await queue.createQueueEvents(); // 创建事件监听 await queue.createQueueEventsProducer(); // 创建事件生产者 ``` ## 其他更新[​](#��其他更新 "其他更新的直接链接") * typeorm 组件现在可以指定自定义的 DataSource 了,以支持一些自定义数据源的场景 * 更新了一些依赖库以提高安全性和稳定性 更多的更新内容和详细信息,请参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.20.0)。 **标签:** * [release](/blog/tags/release.md) --- ## [Release 3.15.0](/blog/release/3.15.0.md) 2024年2月22日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 开工大吉。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 本次 3.15 版本,主要新增了 MQTT 组件。 ## 全新的 MQTT 组件[​](#全新的-mqtt-组件 "全新的 MQTT 组件的直接链接") 可以通过配置 `sub` 和 `pub` 创建多个不同的实例,方便满足用户需求。 更多细节可以接着查看 [文档](/docs/extensions/mqtt.md)。 ## Swagger 方法级别的 Security 忽略[​](#swagger-方法级别的-security-忽略 "Swagger 方法级别的 Security 忽略的直接链接") 现在可以通过 `@ApiExcludeSecurity` 来忽略特定的接口。 ## mwtsc 工具支持了 Alias Path 的识别和替换[​](#mwtsc-工具支持了-alias-path-的识别和替换 "mwtsc 工具支持了 Alias Path 的识别和替换的直接链接") 现在新工具已经可以认识 Alias 路径了。 ## 更多的变化[​](#更多的变化 "更多的变化的直接链接") * @koa/router 升级到了 v12 版本 * 自定义参数装饰器支持抛出异常 此外,还有一大批依赖进行了更新,更多可以参考我们的 [ChangeLog](https://midwayjs.org/changelog/v3.15.0)。 **标签:** * [release](/blog/tags/release.md) --- ## [Release 3.10.0](/blog/release/3.10.0.md) 2023年1月30日 · 阅读需 3 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 新年快乐。 升级请参考 [如何更新 Midway](/docs/how_to_update_midway.md) 中描述,请不要单独升级某个组件包。 这个版本更新了许多东西,请耐心看完。 ## Breaking[​](#breaking "Breaking的直接链接") 首先是 Breaking 的部分,这部分并非是框架本身的 API 变更,而是依赖或者行为可能会影响少部分用户,需要注意的部分。 * 1、 `@midwayjs/consul` 依赖的 `consul` 模块从 `0.x` 升级到 `v1` 正式版,API 可能有更新(`consul.acl` 变更为 `consul.acl.legacy`),具体请查看 [文档](https://github.com/silas/node-consul#acl-legacy) * 2、`@midwayjs/jwt` 依赖的`jsonwebtoken` 模块由于安全性问题,从 `v8` 升级到 `v9`,API 可能有更新,更多情况请查看 [文档](https://github.com/midwayjs/midway/pull/2595) * 3、由于新增的 `@Pipe` 功能,`@midwayjs/validate` 新版本无需使用 `@Validate` 装饰器即可校验,可能会影响一部分之前未编写装饰器但是新版本却被验证的场景,具体请看下面关于 `@Pipe` 的介绍或者相关的文档。 ## New Feature[​](#new-feature "New Feature的直接链接") ### Pipe[​](#pipe "Pipe的直接链接") 新版本新增了一项 Pipe 能力,可以使参数装饰器的能力更进一步。 藉由此能力,新版本的 Validate 组件不再需要 `@Validate` 装饰器,代码会更加简洁。 旧: ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate() async updateUser(@Body() user: UserDTO ) { // user.id } } ``` 新: ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO ) { // user.id } } ``` 针对非 DTO 类型的校验,现在也可以使用 Pipe 进行处理,如果是字符串,会自动转为数字,并进行校验。 ``` @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number ) { // ... } } ``` 当然 Pipe 的功能不仅如此,更多功能请查看 [完整文档](/docs/pipe.md)。 ### TypeORM Logger[​](#typeorm-logger "TypeORM Logger的直接链接") 当 typeorm 组件未配置 logger 属性时,新版本会自动创建一个 `typeormLogger` 用于存储执行的 sql。 默认配置为: ``` midwayLogger: { clients: { typeormLogger: { lazyLoad: true, fileLogName: 'midway-typeorm.log', enableError: false, level: 'info', }, }, } ``` `lazyLoad` 为新增的属性,可以使 logger 在一开始仅保留配置,等实际 getLogger 时才做初始化。 ### @Singleton 装饰器[​](#singleton-装饰器 "@Singleton 装饰器的直接链接") 简化原有的写法: 旧: ``` @Scope(ScopeEnum.Singleton) @Provide() class SingletonService {} ``` 新: ``` @Singleton() class SingletonService {} ``` ### app.getNamespace API[​](#appgetnamespace-api "app.getNamespace API的直接链接") 通过 app 上新增的 `getNamespace` API ,可以获取到当前的 app 归属框架的类型。 比如: ``` import { Application } from '@midwayjs/web'; @Controller() class HomeController { @App() app: Application; async invoke() { // this.app.getNamespace() => 'egg' } } ``` ## 其他的一些变化[​](#其他的一些变化 "其他的一些变化的直接链接") * 1、调整`@midwayjs/core` 默认 logger level 为 info,的 `coreLogger` 在服务器环境继续保留 warn * 2、faas 模块新增一些自定义触发器类型 * 3、在 jest 测试环境下,初始化的报错之前会被 jest 吞掉,新版本会通过 `console.error` 进行输出 * 4、修复 `configuration` 的 stop 生命周期,将以 `imports` 顺序的逆序执行 * 5、修复 `bootstrap` 使用 sticky 模式时,文件上传时的错误 * 6、支持 swager 的属性多类型展示 * 7、在 `midway-bin dev` 下,应用在本地开发时也可以快速使用 `--ssl` 来启动 https 服务 **标签:** * [release](/blog/tags/release.md) --- ## [新增 @midwayjs/skill-midway](/blog/skill/midway.md) 2026年4月6日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 我们新增了 `@midwayjs/skill-midway`。 这个包提供两类能力: * 把 Midway Skill 安装到项目里的 AI 工具目录 * 在本地查询 Midway 的文档、API、包信息和 changelog **标签:** * [midway](/blog/tags/midway.md) * [ai](/blog/tags/ai.md) * [skill](/blog/tags/skill.md) [**阅读更多**](/blog/skill/midway.md) --- ## [Jest v29 更新](/blog/jest_update.md) 2022年10月29日 · 阅读需 1 分钟 [![Harry Chen](https://avatars.githubusercontent.com/u/418820)](https://github.com/czy88840616) [Harry Chen](https://github.com/czy88840616) Maintainer of Midway 最近由于 axios 组件的升级,可能在单测时会出现下面的报错。 ![](https://img.alicdn.com/imgextra/i2/O1CN01G4Ze0F1qVxwcNwYeF_!!6000000005502-2-tps-2080-1158.png) 原因为脚手架自带的 jest v26 不支持 package.json 中的 `exports` 逻辑。 解决方法: * 1、将 `package.json` 中的 jest 版本从 v26 更新为 v29 * 2、将 `@midwayjs/cli` 的版本升级为 `1.3.16` 版本以上,也可以升级到 `2.0` 示例如下: ``` { "devDependencies": { "@midwayjs/cli": "^2.0.1", "@types/jest": "^29.2.0", "jest": "^29.2.2", "ts-jest": "^29.0.3", // ... } } ``` **标签:** * [更新](/blog/tags/更新.md) * [jest](/blog/tags/jest.md) --- ## [v4.0.3](/changelog/v4.0.3.md) 2026年4月12日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) --- # 作者 * [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## [Harry Chen](https://github.com/czy88840616) 136 * [![nobu121](https://github.com/nobu121.png)](https://github.com/nobu121) ## [nobu121](https://github.com/nobu121) 1 * [![Timon Peng](https://github.com/TimonPeng.png)](https://github.com/TimonPeng) ## [Timon Peng](https://github.com/TimonPeng) 1 * [![yuntian001](https://github.com/yuntian001.png)](https://github.com/yuntian001) ## [yuntian001](https://github.com/yuntian001) 1 * [![Hongcai Deng](https://github.com/denghongcai.png)](https://github.com/denghongcai) ## [Hongcai Deng](https://github.com/denghongcai) 2 * [![He Yongsheng](https://github.com/heyongsheng.png)](https://github.com/heyongsheng) ## [He Yongsheng](https://github.com/heyongsheng) 2 * [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## [142vip.cn](https://github.com/mmdapl) 8 * [![NoKic233](https://github.com/Nokic233.png)](https://github.com/Nokic233) ## [NoKic233](https://github.com/Nokic233) 2 * [![yuuang](https://github.com/zhangyuang.png)](https://github.com/zhangyuang) ## [yuuang](https://github.com/zhangyuang) 1 * [![Ghoster](https://github.com/ghostker.png)](https://github.com/ghostker) ## [Ghoster](https://github.com/ghostker) 2 * [![harperKKK](https://github.com/harperKKK.png)](https://github.com/harperKKK) ## [harperKKK](https://github.com/harperKKK) 3 * [![larry zhuo](https://github.com/larryzhuo.png)](https://github.com/larryzhuo) ## [larry zhuo](https://github.com/larryzhuo) 4 * [![Aaron Liu](https://github.com/liuyuan512.png)](https://github.com/liuyuan512) ## [Aaron Liu](https://github.com/liuyuan512) 2 * [![Mirai Zhao](https://github.com/miraizhao.png)](https://github.com/miraizhao) ## [Mirai Zhao](https://github.com/miraizhao) 2 * [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) ## [Chen Yangjian](https://github.com/cyjake) 4 * [![yanzhifei](https://github.com/bossbaba.png)](https://github.com/bossbaba) ## [yanzhifei](https://github.com/bossbaba) 1 * [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## [waiting](https://github.com/waitingsong) 16 * [![fangjin](https://github.com/lengyuxuan.png)](https://github.com/lengyuxuan) ## [fangjin](https://github.com/lengyuxuan) 1 * [![xlaoyu](https://github.com/Yuliang-Lee.png)](https://github.com/Yuliang-Lee) ## [xlaoyu](https://github.com/Yuliang-Lee) 2 * [![MrDotYan](https://github.com/MrDotYan.png)](https://github.com/MrDotYan) ## [MrDotYan](https://github.com/MrDotYan) 1 * [![拓荒](https://github.com/tuohuang.png)](https://github.com/tuohuang) ## [拓荒](https://github.com/tuohuang) 1 * [![Gavin](https://github.com/wjw-gavin.png)](https://github.com/wjw-gavin) ## [Gavin](https://github.com/wjw-gavin) 1 * [![flyingcrp](https://github.com/flyingcrp.png)](https://github.com/flyingcrp) ## [flyingcrp](https://github.com/flyingcrp) 2 * [![Daniel Xu](https://github.com/DanielXuuuuu.png)](https://github.com/DanielXuuuuu) ## [Daniel Xu](https://github.com/DanielXuuuuu) 1 * [![Bacuuu](https://github.com/Bacuuu.png)](https://github.com/Bacuuu) ## [Bacuuu](https://github.com/Bacuuu) 1 * [![jingmingji](https://github.com/jingmingji.png)](https://github.com/jingmingji) ## [jingmingji](https://github.com/jingmingji) 1 * [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## [odex21](https://github.com/odex21) 5 * [![旧梦](https://github.com/jiumengs.png)](https://github.com/jiumengs) ## [旧梦](https://github.com/jiumengs) 1 * [![易良](https://github.com/yiliang114.png)](https://github.com/yiliang114) ## [易良](https://github.com/yiliang114) 1 * [![wangwei](https://github.com/qingniaotonghua.png)](https://github.com/qingniaotonghua) ## [wangwei](https://github.com/qingniaotonghua) 1 * [![玄道](https://github.com/xuandao.png)](https://github.com/xuandao) ## [玄道](https://github.com/xuandao) 1 * [![tommy.hu](https://github.com/freedomdebug.png)](https://github.com/freedomdebug) ## [tommy.hu](https://github.com/freedomdebug) 1 * [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) ## [Cong Liu](https://github.com/ghostoy) 7 * [![Cong](https://github.com/gucovip.png)](https://github.com/gucovip) ## [Cong](https://github.com/gucovip) 1 * [![ZhengChao](https://github.com/SmartOrange.png)](https://github.com/SmartOrange) ## [ZhengChao](https://github.com/SmartOrange) 1 * [![iNE](https://github.com/Sakuraine.png)](https://github.com/Sakuraine) ## [iNE](https://github.com/Sakuraine) 2 * [![Taosh](https://github.com/taosher.png)](https://github.com/taosher) ## [Taosh](https://github.com/taosher) 1 * [![Ming Ye](https://github.com/ymqy.png)](https://github.com/ymqy) ## [Ming Ye](https://github.com/ymqy) 1 * [![Suel](https://github.com/wakeGISer.png)](https://github.com/wakeGISer) ## [Suel](https://github.com/wakeGISer) 1 * [![leemotive](https://github.com/leemotive.png)](https://github.com/leemotive) ## [leemotive](https://github.com/leemotive) 1 * [![flyingCrp](https://github.com/flyingCrp.png)](https://github.com/flyingCrp) ## [flyingCrp](https://github.com/flyingCrp) 1 * [![sumy](https://github.com/sumy7.png)](https://github.com/sumy7) ## [sumy](https://github.com/sumy7) 2 * [![yemangran](https://github.com/yemangran.png)](https://github.com/yemangran) ## [yemangran](https://github.com/yemangran) 1 * [![林轩](https://github.com/whale2002.png)](https://github.com/whale2002) ## [林轩](https://github.com/whale2002) 1 * [![Joël Galeran](https://github.com/Jolg42.png)](https://github.com/Jolg42) ## [Joël Galeran](https://github.com/Jolg42) 1 * [![Zy](https://github.com/RainManGO.png)](https://github.com/RainManGO) ## [Zy](https://github.com/RainManGO) 1 * [![Steppenwolf1900](https://github.com/Steppenwolf1900.png)](https://github.com/Steppenwolf1900) ## [Steppenwolf1900](https://github.com/Steppenwolf1900) 1 * [![刘宏玺](https://github.com/lhx6538665.png)](https://github.com/lhx6538665) ## [刘宏玺](https://github.com/lhx6538665) 1 * [![DeveloperYvan](https://github.com/developeryvan.png)](https://github.com/developeryvan) ## [DeveloperYvan](https://github.com/developeryvan) 1 * [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## [Gao Yang](https://github.com/echosoar) 11 * [![Thirteen](https://github.com/wangyi12358.png)](https://github.com/wangyi12358) ## [Thirteen](https://github.com/wangyi12358) 1 * [![Umuoy](https://github.com/umuoy1.png)](https://github.com/umuoy1) ## [Umuoy](https://github.com/umuoy1) 1 * [![世新](https://github.com/4xii.png)](https://github.com/4xii) ## [世新](https://github.com/4xii) 1 * [![孺子牛](https://github.com/ddzyan.png)](https://github.com/ddzyan) ## [孺子牛](https://github.com/ddzyan) 1 * [![Frank Zhao](https://github.com/frank-zsy.png)](https://github.com/frank-zsy) ## [Frank Zhao](https://github.com/frank-zsy) 1 * [![huel129](https://github.com/savoygu.png)](https://github.com/savoygu) ## [huel129](https://github.com/savoygu) 1 * [![C](https://github.com/abnerCrack.png)](https://github.com/abnerCrack) ## [C](https://github.com/abnerCrack) 1 * [![下雨就像弹钢琴](https://github.com/luckyscript.png)](https://github.com/luckyscript) ## [下雨就像弹钢琴](https://github.com/luckyscript) 1 * [![imlh.cn](https://github.com/lhcn.png)](https://github.com/lhcn) ## [imlh.cn](https://github.com/lhcn) 1 * [![huangapple](https://github.com/huangapple.png)](https://github.com/huangapple) ## [huangapple](https://github.com/huangapple) 1 * [![xnng](https://github.com/xnng.png)](https://github.com/xnng) ## [xnng](https://github.com/xnng) 1 * [![zhi](https://github.com/yantze.png)](https://github.com/yantze) ## [zhi](https://github.com/yantze) 1 * [![cave-](https://github.com/cave-.png)](https://github.com/cave-) ## [cave-](https://github.com/cave-) 1 * [![Haitao Lee](https://github.com/haitaodesign.png)](https://github.com/haitaodesign) ## [Haitao Lee](https://github.com/haitaodesign) 1 * [![isaced](https://github.com/isaced.png)](https://github.com/isaced) ## [isaced](https://github.com/isaced) 1 * [![酷酷的老猫](https://github.com/kukudelaomao.png)](https://github.com/kukudelaomao) ## [酷酷的老猫](https://github.com/kukudelaomao) 1 * [![zhangbowy](https://github.com/zhangbowy.png)](https://github.com/zhangbowy) ## [zhangbowy](https://github.com/zhangbowy) 1 * [![yc6](https://github.com/zane0904.png)](https://github.com/zane0904) ## [yc6](https://github.com/zane0904) 1 --- ## [v3.3.11](/changelog/v3.3.11.md) 2022年5月27日 --- ## [v3.1.1](/changelog/v3.1.1.md) 2022年3月9日 --- ## [v2.12.0](/changelog/v2.12.0.md) 2021年7月30日 --- ## [v2.10.8](/changelog/v2.10.8.md) 2021年4月21日 --- ## [v2.8.6](/changelog/v2.8.6.md) 2021年3月3日 --- ## [v2.6.7](/changelog/v2.6.7.md) 2021年1月5日 --- ## [v2.4.2](/changelog/v2.4.2.md) 2020年11月13日 --- ## [v2.3.6](/changelog/v2.3.6.md) 2020年10月2日 --- ## [v2.1.1](/changelog/v2.1.1.md) 2020年4月30日 --- ## [v1.17.1](/changelog/v1.17.1.md) 2020年2月17日 --- ## [v3.20.12](/changelog/v3.20.12.md) 2025年8月10日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![He Yongsheng](https://github.com/heyongsheng.png)](https://github.com/heyongsheng) --- ## [v1.11.3](/changelog/v1.11.3.md) 2019年9月6日 --- ## [v1.6.0](/changelog/v1.6.0.md) 2019年6月11日 --- ## [v1.3.1](/changelog/v1.3.1.md) 2019年2月18日 --- ## [v0.6.3](/changelog/v0.6.3.md) 2018年11月20日 --- ## [v3.18.0](/changelog/v3.18.0.md) 2024年9月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) --- ## [v3.15.5](/changelog/v3.15.5.md) 2024年3月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![jingmingji](https://github.com/jingmingji.png)](https://github.com/jingmingji) --- ## [v3.13.9](/changelog/v3.13.9.md) 2023年12月27日 [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) --- ## [v3.12.0](/changelog/v3.12.0.md) 2023年8月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) [![Taosh](https://github.com/taosher.png)](https://github.com/taosher) [![Ming Ye](https://github.com/ymqy.png)](https://github.com/ymqy) --- ## [v3.10.16](/changelog/v3.10.16.md) 2023年3月21日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Umuoy](https://github.com/umuoy1.png)](https://github.com/umuoy1) --- ## [v3.9.6](/changelog/v3.9.6.md) 2022年12月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) --- ## [v3.5.2](/changelog/v3.5.2.md) 2022年9月8日 --- # v0.2.10 2018年8月20日 **Note:** Version bump only for package midway []() --- # v0.2.5 2018年8月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ts-node register twice ([b405159](https://github.com/midwayjs/midway/commit/b405159)) --- # v0.2.6 2018年8月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * publish add bootstrap file ([3593ec5](https://github.com/midwayjs/midway/commit/3593ec5)) * try to export container method ([7921cdb](https://github.com/midwayjs/midway/commit/7921cdb)) []() --- # v0.2.7 2018年8月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * bind method definition missing ([79685db](https://github.com/midwayjs/midway/commit/79685db)) * export bootstrap file ([d2bd919](https://github.com/midwayjs/midway/commit/d2bd919)) * export bootstrap file ([1337926](https://github.com/midwayjs/midway/commit/1337926)) * module name ([c00d20c](https://github.com/midwayjs/midway/commit/c00d20c)) []() --- # v0.2.8 2018年8月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix framework name and support load server options from pkg ([b8b4c7d](https://github.com/midwayjs/midway/commit/b8b4c7d)) * fix template and modify ts register method ([1857c08](https://github.com/midwayjs/midway/commit/1857c08)) * support typescript in dependencies ([b532a90](https://github.com/midwayjs/midway/commit/b532a90)) []() --- # v0.2.9 2018年8月16日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * mock obj ([1d867ed](https://github.com/midwayjs/midway/commit/1d867ed)) * set appDir before setServerEnv ([6b418ca](https://github.com/midwayjs/midway/commit/6b418ca)) []() --- # v0.4.5 2018年11月5日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix app.root ([33d730c](https://github.com/midwayjs/midway/commit/33d730c)) []() --- # v0.4.6 2018年11月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add ts autoload directory ([a6668fb](https://github.com/midwayjs/midway/commit/a6668fb)) * fix dep map generator err in constructor inject ([9d7abe6](https://github.com/midwayjs/midway/commit/9d7abe6)) * fix set app use defineProperty ([d94d5e9](https://github.com/midwayjs/midway/commit/d94d5e9)) * lint & test failed ([0a3fb74](https://github.com/midwayjs/midway/commit/0a3fb74)) --- # v0.4.7 2018年11月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix load dir bug in js mode ([8c148f3](https://github.com/midwayjs/midway/commit/8c148f3)) --- # v0.5.0 2018年11月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * agent not work ([c7cf3a9](https://github.com/midwayjs/midway/commit/c7cf3a9)) * agent startup become compatible between egg\&midway ([05c98aa](https://github.com/midwayjs/midway/commit/05c98aa)) * build not midway-bin ([5b9667f](https://github.com/midwayjs/midway/commit/5b9667f)) * egg-schedule plugin retrieve dir ([8429332](https://github.com/midwayjs/midway/commit/8429332)) * logger & build scripts ([ef1a948](https://github.com/midwayjs/midway/commit/ef1a948)) * run task with wront ctx & fill tests ([30a0741](https://github.com/midwayjs/midway/commit/30a0741)) ### Features[​](#features "Features的直接链接") * init midway-schedule ([82cc9e1](https://github.com/midwayjs/midway/commit/82cc9e1)) --- # v0.5.1 2018年11月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * schedule build file not published ([4150ce2](https://github.com/midwayjs/midway/commit/4150ce2)) --- # v0.6.0 2018年11月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * agent not work ([f43c553](https://github.com/midwayjs/midway/commit/f43c553)) * agent startup become compatible between egg\&midway ([47f46c3](https://github.com/midwayjs/midway/commit/47f46c3)) * build not midway-bin ([f16b9db](https://github.com/midwayjs/midway/commit/f16b9db)) * egg-schedule plugin retrieve dir ([6a94e01](https://github.com/midwayjs/midway/commit/6a94e01)) * logger & build scripts ([c2e29aa](https://github.com/midwayjs/midway/commit/c2e29aa)) * run task with wront ctx & fill tests ([94d95c3](https://github.com/midwayjs/midway/commit/94d95c3)) * schedule build file not published ([e14be5b](https://github.com/midwayjs/midway/commit/e14be5b)) ### Features[​](#features "Features的直接链接") * init midway-schedule ([4442bd1](https://github.com/midwayjs/midway/commit/4442bd1)) --- # v0.6.1 2018年11月19日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix load order and user can cover default dir ([990ddcb](https://github.com/midwayjs/midway/commit/990ddcb)) --- # v0.6.2 2018年11月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * Increase cron and interval and other parameter expansion ([#62](https://github.com/midwayjs/midway/issues/62)) ([ccd0114](https://github.com/midwayjs/midway/commit/ccd0114)) * not only inject properties that declared on the property ([b1fe4e2](https://github.com/midwayjs/midway/commit/b1fe4e2)) --- # v0.6.3 2018年11月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix invoke loadController repeatedly ([8342649](https://github.com/midwayjs/midway/commit/8342649)) --- # v0.6.4 2018年11月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * change default search directory ([ae189df](https://github.com/midwayjs/midway/commit/ae189df)) --- # v0.6.5 2018年11月27日 **Note:** Version bump only for package midway --- # v0.7.0 2018年12月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * Boolean type resolution error in xml ([b3a35e4](https://github.com/midwayjs/midway/commit/b3a35e4)) ### Features[​](#features "Features的直接链接") * Add build specified suffix file ([1752cf9](https://github.com/midwayjs/midway/commit/1752cf9)) * support non-default class for midway-schedule ([74e51e9](https://github.com/midwayjs/midway/commit/74e51e9)) --- # v0.7.1 2018年12月18日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * lock egg-schedule version ([668a4b3](https://github.com/midwayjs/midway/commit/668a4b3)) --- # v1.0.0 2018年12月23日 ### Features[​](#features "Features的直接链接") * Release v1.0.0 --- # v1.0.1 2018年12月23日 **Note:** Version bump only for package midway --- # v1.0.2 2018年12月26日 **Note:** Version bump only for package midway --- # v1.0.3 2018年12月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove pull template from github and add doc for windows ([3ac69ef](https://github.com/midwayjs/midway/commit/3ac69ef)) --- # v1.0.4 2018年12月29日 **Note:** Version bump only for package midway --- # v1.0.5 2019年1月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add appDir in appInfo ([4399aba](https://github.com/midwayjs/midway/commit/4399aba)) * override alinode default path ([f140a18](https://github.com/midwayjs/midway/commit/f140a18)) --- # v1.1.0 2019年1月23日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * check whether methodNames is iterable ([d8c08d7](https://github.com/midwayjs/midway/commit/d8c08d7)) * fix test case ([de70efa](https://github.com/midwayjs/midway/commit/de70efa)) ### Features[​](#features "Features的直接链接") * add tslint rules ([73ff338](https://github.com/midwayjs/midway/commit/73ff338)) * 用户执行 init 时判断环境 ([142e0e2](https://github.com/midwayjs/midway/commit/142e0e2)) --- # v1.1.1 2019年1月23日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove application definition from egg ([218cf3b](https://github.com/midwayjs/midway/commit/218cf3b)) --- # v1.1.2 2019年1月27日 **Note:** Version bump only for package midway --- # v1.10.0 2019年7月16日 ### Features[​](#features "Features的直接链接") * 导出 egg 的 Service 和 Boot 类,以供用户继承 ([6180040](https://github.com/midwayjs/midway/commit/6180040)) --- # v1.10.1 2019年7月18日 **Note:** Version bump only for package midway --- # v1.10.2 2019年7月20日 **Note:** Version bump only for package midway --- # v1.10.3 2019年7月23日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **boilerplate:** sync configurations for all boilerplate ([e73ae35](https://github.com/midwayjs/midway/commit/e73ae35)) * **boilerplate:** update deps @types/mocha for all boilerplate ([d84cde1](https://github.com/midwayjs/midway/commit/d84cde1)) * **boilerplate:** update deps for all boilerplate ([4a015e7](https://github.com/midwayjs/midway/commit/4a015e7)) * **boilerplate:** update nodejs requirement for all boilerplate ([1602d3a](https://github.com/midwayjs/midway/commit/1602d3a)), closes [#279](https://github.com/midwayjs/midway/issues/279) --- # v1.10.4 2019年7月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **boilerplate:** update vscode path match pattern for all boilerplate ([88352e5](https://github.com/midwayjs/midway/commit/88352e5)) --- # v1.10.5 2019年7月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * compatible with midway mock ([d738b7f](https://github.com/midwayjs/midway/commit/d738b7f)) --- # v1.10.6 2019年7月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * @types/mocha has a wrong version: 6.0.0 ([e1a7285](https://github.com/midwayjs/midway/commit/e1a7285)) --- # v1.10.7 2019年8月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **boilerplate:** missing comma in .vscode/settings.json ([62fa953](https://github.com/midwayjs/midway/commit/62fa953)) --- # v1.10.8 2019年8月3日 **Note:** Version bump only for package midway --- # v1.10.9 2019年8月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * app/extend 没有发布到 npm ([73ba51a](https://github.com/midwayjs/midway/commit/73ba51a)) --- # v1.11.0 2019年8月9日 ### Features[​](#features "Features的直接链接") * **boilerplate:** enable source map for stack trace ([77afc3f](https://github.com/midwayjs/midway/commit/77afc3f)) ### Performance Improvements[​](#performance-improvements "Performance Improvements的直接链接") * **web:** use set to avoid duplicate lookup ([21e44f9](https://github.com/midwayjs/midway/commit/21e44f9)) --- # v1.11.1 2019年8月10日 **Note:** Version bump only for package midway --- # v1.11.2 2019年8月30日 **Note:** Version bump only for package midway --- # v1.11.3 2019年9月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * module path under mono repo ([8342487](https://github.com/midwayjs/midway/commit/8342487)), closes [#329](https://github.com/midwayjs/midway/issues/329) * scripts compatibility under windows ([78850d1](https://github.com/midwayjs/midway/commit/78850d1)) --- # v1.11.4 2019年9月6日 **Note:** Version bump only for package midway --- # v1.11.5 2019年9月6日 **Note:** Version bump only for package midway --- # v1.11.6 2019年9月30日 **Note:** Version bump only for package midway --- # v1.12.0 2019年10月11日 ### Features[​](#features "Features的直接链接") * **midway-bin:** add and export functions ([80ef6b8](https://github.com/midwayjs/midway/commit/80ef6b8)) --- # v1.12.1 2019年10月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **midway-bin:** use resolveModule() instead of findFramework() ([#344](https://github.com/midwayjs/midway/issues/344)) ([8c24e2e](https://github.com/midwayjs/midway/commit/8c24e2e)) ### BREAKING CHANGES[​](#breaking-changes "BREAKING CHANGES的直接链接") * **midway-bin:** remove findFramework() --- # v1.13.0 2019年10月16日 ### Features[​](#features "Features的直接链接") * export IBoot and IgnoreOrMatch from egg ([d5abb3d](https://github.com/midwayjs/midway/commit/d5abb3d)) --- # v1.14.0 2019年11月1日 ### Features[​](#features "Features的直接链接") * add egg-init args ([d6c3582](https://github.com/midwayjs/midway/commit/d6c3582)) * support npm registry parameter ([d9adfcf](https://github.com/midwayjs/midway/commit/d9adfcf)) * use new generator for midway-init ([634b748](https://github.com/midwayjs/midway/commit/634b748)) --- # v1.14.1 2019年11月3日 **Note:** Version bump only for package midway --- # v1.14.2 2019年11月10日 **Note:** Version bump only for package midway --- # v1.14.3 2019年11月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * midway-bin include jest config ([20e2a86](https://github.com/midwayjs/midway/commit/20e2a86)) --- # v1.14.4 2019年11月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix lint ([77177fb](https://github.com/midwayjs/midway/commit/77177fb)) --- # v1.15.0 2019年12月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ignore app/extend/\* when loader start ([4db9e9b](https://github.com/midwayjs/midway/commit/4db9e9b)) * **midway-bin:** log message grammar ([30091d0](https://github.com/midwayjs/midway/commit/30091d0)) ### Features[​](#features "Features的直接链接") * **midway-bin:** add bundle support ([9894049](https://github.com/midwayjs/midway/commit/9894049)) * **midway-bin:** use async-await instead of generator ([eed48f1](https://github.com/midwayjs/midway/commit/eed48f1)) --- # v1.15.1 2019年12月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * use co wrap generator for egg-bin run method ([14cdb2d](https://github.com/midwayjs/midway/commit/14cdb2d)) ### Features[​](#features "Features的直接链接") * **midway-bin:** do not populate exec argv to child processes ([f22c858](https://github.com/midwayjs/midway/commit/f22c858)) --- # v1.16.0 2019年12月16日 **Note:** Version bump only for package midway --- # v1.16.1 2019年12月16日 **Note:** Version bump only for package midway --- # v1.16.2 2019年12月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix ts mode value is empty for non-ts items ([ef3b46a](https://github.com/midwayjs/midway/commit/ef3b46a)) * interface scheduleOpts ([2ae0766](https://github.com/midwayjs/midway/commit/2ae0766)) --- # v1.16.3 2019年12月25日 **Note:** Version bump only for package midway --- # v1.16.4 2020年2月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg bin modify setup file rule ([#380](https://github.com/midwayjs/midway/issues/380)) ([4b9461d](https://github.com/midwayjs/midway/commit/4b9461d)) * executing midway-bin build at arbitrary directory ([#384](https://github.com/midwayjs/midway/issues/384)) ([1ace418](https://github.com/midwayjs/midway/commit/1ace418)) --- # v1.17.0 2020年2月17日 ### Features[​](#features "Features的直接链接") * **build:** options to minify all products ([#389](https://github.com/midwayjs/midway/issues/389)) ([86d5279](https://github.com/midwayjs/midway/commit/86d5279)) # [2.0.0-beta.4](https://github.com/midwayjs/midway/compare/v1.16.4...v2.0.0-beta.4) (2020-02-16) ### Features[​](#features-1 "Features的直接链接") * add namespace feature ([#386](https://github.com/midwayjs/midway/issues/386)) ([bb2a8c8](https://github.com/midwayjs/midway/commit/bb2a8c8)) # [2.0.0-beta.3](https://github.com/midwayjs/midway/compare/v2.0.0-beta.2...v2.0.0-beta.3) (2020-02-08) ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix build ([1d5a7c1](https://github.com/midwayjs/midway/commit/1d5a7c1)) # [2.0.0-beta.2](https://github.com/midwayjs/midway/compare/v2.0.0-beta.1...v2.0.0-beta.2) (2020-02-04) ### Bug Fixes[​](#bug-fixes-1 "Bug Fixes的直接链接") * add missing dep module ([04ecc82](https://github.com/midwayjs/midway/commit/04ecc82)) # [2.0.0-beta.1](https://github.com/midwayjs/midway/compare/v1.16.3...v2.0.0-beta.1) (2020-02-04) ### Bug Fixes[​](#bug-fixes-2 "Bug Fixes的直接链接") * fix requestContext load configService ([f2c874f](https://github.com/midwayjs/midway/commit/f2c874f)) ### Features[​](#features-2 "Features的直接链接") * support [@configuration](https://github.com/configuration) decorator ([0584494](https://github.com/midwayjs/midway/commit/0584494)) * support importConfigs and add test case ([753cfb4](https://github.com/midwayjs/midway/commit/753cfb4)) * transfor to new package ([9144b48](https://github.com/midwayjs/midway/commit/9144b48)) # [2.0.0-beta.3](https://github.com/midwayjs/midway/compare/v2.0.0-beta.2...v2.0.0-beta.3) (2020-02-08) ### Bug Fixes[​](#bug-fixes-3 "Bug Fixes的直接链接") * fix build ([1d5a7c1](https://github.com/midwayjs/midway/commit/1d5a7c1)) # [2.0.0-beta.2](https://github.com/midwayjs/midway/compare/v2.0.0-beta.1...v2.0.0-beta.2) (2020-02-04) ### Bug Fixes[​](#bug-fixes-4 "Bug Fixes的直接链接") * add missing dep module ([04ecc82](https://github.com/midwayjs/midway/commit/04ecc82)) # [2.0.0-beta.1](https://github.com/midwayjs/midway/compare/v1.16.3...v2.0.0-beta.1) (2020-02-04) ### Bug Fixes[​](#bug-fixes-5 "Bug Fixes的直接链接") * egg bin modify setup file rule ([#380](https://github.com/midwayjs/midway/issues/380)) ([4b9461d](https://github.com/midwayjs/midway/commit/4b9461d)) * fix requestContext load configService ([f2c874f](https://github.com/midwayjs/midway/commit/f2c874f)) ### Features[​](#features-3 "Features的直接链接") * support [@configuration](https://github.com/configuration) decorator ([0584494](https://github.com/midwayjs/midway/commit/0584494)) * support importConfigs and add test case ([753cfb4](https://github.com/midwayjs/midway/commit/753cfb4)) * transfor to new package ([9144b48](https://github.com/midwayjs/midway/commit/9144b48)) --- # v1.17.1 2020年2月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** add terser to depenencies ([#390](https://github.com/midwayjs/midway/issues/390)) ([e6da77e](https://github.com/midwayjs/midway/commit/e6da77e)) --- # v1.2.0 2019年1月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * app.runSchedule task key ([29249e9](https://github.com/midwayjs/midway/commit/29249e9)) ### Features[​](#features "Features的直接链接") * midway-mock 支持 applicationContext 获取 ctx 依赖注入,支持 mock IoC 容器中的对象方法 ([4f07c6d](https://github.com/midwayjs/midway/commit/4f07c6d)) * transform injection to another github repo ([5f39ea9](https://github.com/midwayjs/midway/commit/5f39ea9)) --- # v1.2.1 2019年1月30日 **Note:** Version bump only for package midway --- # v1.2.2 2019年1月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * import router in base controller ([1a0b890](https://github.com/midwayjs/midway/commit/1a0b890)) * import router to fix core ([71a2f61](https://github.com/midwayjs/midway/commit/71a2f61)) --- # v1.2.3 2019年2月1日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix lint ([d9e1ab9](https://github.com/midwayjs/midway/commit/d9e1ab9)) * fix more lint ([12873dc](https://github.com/midwayjs/midway/commit/12873dc)) --- # v1.2.4 2019年2月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix default logdir for alinode plugin ([1f737f7](https://github.com/midwayjs/midway/commit/1f737f7)) --- # v1.3.0 2019年2月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove inject api generator ([203478e](https://github.com/midwayjs/midway/commit/203478e)) ### Features[​](#features "Features的直接链接") * add new doc command ([972db71](https://github.com/midwayjs/midway/commit/972db71)) * support process.env.PORT in dev command ([0756f0e](https://github.com/midwayjs/midway/commit/0756f0e)) --- # v1.3.1 2019年2月18日 **Note:** Version bump only for package midway --- # v1.3.2 2019年2月22日 **Note:** Version bump only for package midway --- # v1.4.0 2019年2月24日 ### Features[​](#features "Features的直接链接") * add egg definition ([5d28443](https://github.com/midwayjs/midway/commit/5d28443)) --- # v1.4.1 2019年2月27日 **Note:** Version bump only for package midway --- # v1.4.10 2019年3月12日 **Note:** Version bump only for package midway --- # v1.4.2 2019年2月28日 **Note:** Version bump only for package midway --- # v1.4.3 2019年3月1日 **Note:** Version bump only for package midway --- # v1.4.4 2019年3月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix decorator i midway-mock ([60367fb](https://github.com/midwayjs/midway/commit/60367fb)) * js-app-xml test case ([1298195](https://github.com/midwayjs/midway/commit/1298195)) --- # v1.4.5 2019年3月6日 **Note:** Version bump only for package midway --- # v1.4.6 2019年3月7日 **Note:** Version bump only for package midway --- # v1.4.7 2019年3月8日 **Note:** Version bump only for package midway --- # v1.4.8 2019年3月11日 **Note:** Version bump only for package midway --- # v1.4.9 2019年3月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix loadDir default path ([9defd2d](https://github.com/midwayjs/midway/commit/9defd2d)) --- # v1.5.0 2019年4月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix midway-init ci error ([8f32dcb](https://github.com/midwayjs/midway/commit/8f32dcb)) ### Features[​](#features "Features的直接链接") * add project options in midway-bin ([c635057](https://github.com/midwayjs/midway/commit/c635057)) --- # v1.5.1 2019年4月15日 **Note:** Version bump only for package midway --- # v1.5.2 2019年4月29日 **Note:** Version bump only for package midway --- # v1.5.3 2019年5月8日 **Note:** Version bump only for package midway --- # v1.5.4 2019年5月9日 **Note:** Version bump only for package midway --- # v1.5.5 2019年5月13日 **Note:** Version bump only for package midway --- # v1.5.6 2019年5月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * copy files by src dir ([ad7c28d](https://github.com/midwayjs/midway/commit/ad7c28d)) --- # v1.6.0 2019年6月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **types:** duplicate import of the controller ([2b4600a](https://github.com/midwayjs/midway/commit/2b4600a)) ### Features[​](#features "Features的直接链接") * **types:** import and use Context for boilerplate ([d183196](https://github.com/midwayjs/midway/commit/d183196)) * **vscode:** add launch.json for vscode debug ([9741a53](https://github.com/midwayjs/midway/commit/9741a53)) * **vscode:** add settings.json for vscode ([f7d178b](https://github.com/midwayjs/midway/commit/f7d178b)) --- # v1.6.1 2019年6月11日 **Note:** Version bump only for package midway --- # v1.6.2 2019年6月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix tsconfig in template ([1680d29](https://github.com/midwayjs/midway/commit/1680d29)) --- # v1.6.3 2019年6月13日 **Note:** Version bump only for package midway --- # v1.7.0 2019年6月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **webloader:** remove routerArgs concat ([9feb872](https://github.com/midwayjs/midway/commit/9feb872)) ### Features[​](#features "Features的直接链接") * controller opt support sensitive opt ([780f5d7](https://github.com/midwayjs/midway/commit/780f5d7)) --- # v1.8.0 2019年6月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **test:** param controller test add await ([b955427](https://github.com/midwayjs/midway/commit/b955427)) * make routeArgsInfo Optional ([4ed5443](https://github.com/midwayjs/midway/commit/4ed5443)) * package.json restore mkdir package ([c2ec7ba](https://github.com/midwayjs/midway/commit/c2ec7ba)) * **types:** add file/files opt types ([f40b03e](https://github.com/midwayjs/midway/commit/f40b03e)) ### Features[​](#features "Features的直接链接") * support param decorator [@body](https://github.com/body) [@query](https://github.com/query) [@param](https://github.com/param).. ([6278d99](https://github.com/midwayjs/midway/commit/6278d99)) --- # v1.9.0 2019年7月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **build:** filter unnecessary files [#277](https://github.com/midwayjs/midway/issues/277) ([9c1be93](https://github.com/midwayjs/midway/commit/9c1be93)) * **midway-init:** Internal employees can not use the external network midway ([3179434](https://github.com/midwayjs/midway/commit/3179434)) * **midway-web:** path might be numeric string within safelyGet() ([5b48eff](https://github.com/midwayjs/midway/commit/5b48eff)) * **types:** use generic as typeof context within KoaMiddleware ([6c963e5](https://github.com/midwayjs/midway/commit/6c963e5)) ### Features[​](#features "Features的直接链接") * [@config](https://github.com/config)(opt) decorator opt accept dot natation ([4ee1959](https://github.com/midwayjs/midway/commit/4ee1959)) * **boilerplate:** add midway-ts-strict-boilerplate ([8ee325c](https://github.com/midwayjs/midway/commit/8ee325c)) * **boilerplate:** enforce kebabCase style for filenames for midway-ts-strict ([816941b](https://github.com/midwayjs/midway/commit/816941b)) * **boilerplate:** update midway-ts-strict ([c8388f0](https://github.com/midwayjs/midway/commit/c8388f0)), closes [#269](https://github.com/midwayjs/midway/issues/269) * **types:** assign egg\['Context'] to types of parameter of context ([ea511fa](https://github.com/midwayjs/midway/commit/ea511fa)) * **types:** export and use type MiddlewareParamArray ([90b4e28](https://github.com/midwayjs/midway/commit/90b4e28)) * **types:** update types of utils.ts ([c76db38](https://github.com/midwayjs/midway/commit/c76db38)), closes [#258](https://github.com/midwayjs/midway/issues/258) * **types:** update webLoader.ts ([fb534bb](https://github.com/midwayjs/midway/commit/fb534bb)) --- # v2.0.0 2020年3月13日 **Note:** Version bump only for package midway # [2.0.0-beta.16](https://github.com/midwayjs/midway/compare/v2.0.0-beta.15...v2.0.0-beta.16) (2020-03-12) ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * 修复循环引用 bug ([#419](https://github.com/midwayjs/midway/issues/419)) ([8852c6c](https://github.com/midwayjs/midway/commit/8852c6c55de8975aea3df2978bf50425378379e6)) # [2.0.0-beta.15](https://github.com/midwayjs/midway/compare/v2.0.0-beta.14...v2.0.0-beta.15) (2020-03-06) ### Bug Fixes[​](#bug-fixes-1 "Bug Fixes的直接链接") * disable follow symbolic link ([#413](https://github.com/midwayjs/midway/issues/413)) ([99c30d7](https://github.com/midwayjs/midway/commit/99c30d72ae25001c17372ddd9981b6710af3a3a7)) * merge bug ([7f41fc9](https://github.com/midwayjs/midway/commit/7f41fc94adf1fc9e4465c5aefdf94346184e1efc)) * modified configuration load logic ([#415](https://github.com/midwayjs/midway/issues/415)) ([6e77d36](https://github.com/midwayjs/midway/commit/6e77d3624ed407893b8df1937482bef044b1f36b)) ### Features[​](#features "Features的直接链接") * 2.x lifecycle ([#414](https://github.com/midwayjs/midway/issues/414)) ([7313ab8](https://github.com/midwayjs/midway/commit/7313ab804091fd410b1b3118ea41f18cf05fb01f)) * feat(eslint-midway-contrib): add pkg for js and ts ([#397](https://github.com/midwayjs/midway/issues/397)) ([3b404a5](https://github.com/midwayjs/midway/commit/3b404a5ed92e6843766634b78db1aa6f321191d8)) * MidwayRequestContainer 增加泛型标注 ([#407](https://github.com/midwayjs/midway/issues/407)) ([b206035](https://github.com/midwayjs/midway/commit/b20603577a99f31ece9720d5f7893c2af7905887)) # [2.0.0-beta.14](https://github.com/midwayjs/midway/compare/v2.0.0-beta.13...v2.0.0-beta.14) (2020-03-04) ### Features[​](#features-1 "Features的直接链接") * 2.x pipeline ([#406](https://github.com/midwayjs/midway/issues/406)) ([9eb3e10](https://github.com/midwayjs/midway/commit/9eb3e100ebac966cf58713d4d3f021cd44971150)) # [2.0.0-beta.13](https://github.com/midwayjs/midway/compare/v2.0.0-beta.12...v2.0.0-beta.13) (2020-02-26) ### Bug Fixes[​](#bug-fixes-2 "Bug Fixes的直接链接") * configuration load config bug ([#404](https://github.com/midwayjs/midway/issues/404)) ([5e18763](https://github.com/midwayjs/midway/commit/5e187633b58e76b606a95063056d670e234c1d22)) **Note:** Version bump only for package midway # [2.0.0-beta.12](https://github.com/midwayjs/midway/compare/v2.0.0-beta.11...v2.0.0-beta.12) (2020-02-25) ### Bug Fixes[​](#bug-fixes-3 "Bug Fixes的直接链接") * namespace @ bugfix ([#402](https://github.com/midwayjs/midway/issues/402)) ([e546219](https://github.com/midwayjs/midway/commit/e5462191ec293f98db46cfa59efc446124e2e381)) # [2.0.0-beta.11](https://github.com/midwayjs/midway/compare/v2.0.0-beta.10...v2.0.0-beta.11) (2020-02-25) ### Bug Fixes[​](#bug-fixes-4 "Bug Fixes的直接链接") * configuration bugs ([#401](https://github.com/midwayjs/midway/issues/401)) ([a6a18b2](https://github.com/midwayjs/midway/commit/a6a18b200252bb0cfa415cc000bcdd5ec5d85701)) # [2.0.0-beta.10](https://github.com/midwayjs/midway/compare/v2.0.0-beta.9...v2.0.0-beta.10) (2020-02-20) ### Bug Fixes[​](#bug-fixes-5 "Bug Fixes的直接链接") * ts build cwd ([#396](https://github.com/midwayjs/midway/issues/396)) ([83732f9](https://github.com/midwayjs/midway/commit/83732f90c325c646bc6983eac6460a7f65ca1c51)) # [2.0.0-beta.9](https://github.com/midwayjs/midway/compare/v2.0.0-beta.8...v2.0.0-beta.9) (2020-02-20) ### Bug Fixes[​](#bug-fixes-6 "Bug Fixes的直接链接") * build-tsConfig ([#393](https://github.com/midwayjs/midway/issues/393)) ([fb451b4](https://github.com/midwayjs/midway/commit/fb451b419e0780c9fc803901e186eb38607284dc)) # [2.0.0-beta.8](https://github.com/midwayjs/midway/compare/v2.0.0-beta.7...v2.0.0-beta.8) (2020-02-19) ### Features[​](#features-2 "Features的直接链接") * add tsConfig.json to tsc cmd line support ([#392](https://github.com/midwayjs/midway/issues/392)) ([8e368fb](https://github.com/midwayjs/midway/commit/8e368fb7bb0d290817ac0e1d266bf8295a71269c)) # [2.0.0-beta.7](https://github.com/midwayjs/midway/compare/v2.0.0-beta.6...v2.0.0-beta.7) (2020-02-18) **Note:** Version bump only for package midway # [2.0.0-beta.6](https://github.com/midwayjs/midway/compare/v2.0.0-beta.5...v2.0.0-beta.6) (2020-02-17) **Note:** Version bump only for package midway # [2.0.0-beta.5](https://github.com/midwayjs/midway/compare/v2.0.0-beta.4...v2.0.0-beta.5) (2020-02-17) ### Bug Fixes[​](#bug-fixes-7 "Bug Fixes的直接链接") * **deps:** add terser to depenencies ([#390](https://github.com/midwayjs/midway/issues/390)) ([a8de587](https://github.com/midwayjs/midway/commit/a8de587)) ### Features[​](#features-3 "Features的直接链接") * **build:** options to minify all products ([#389](https://github.com/midwayjs/midway/issues/389)) ([d309bdc](https://github.com/midwayjs/midway/commit/d309bdc)) * 2.x namespace ([#388](https://github.com/midwayjs/midway/issues/388)) ([9c90eb1](https://github.com/midwayjs/midway/commit/9c90eb1)) --- # v2.0.1 2020年3月13日 ### Features[​](#features "Features的直接链接") * add hsf decorator ([#421](https://github.com/midwayjs/midway/issues/421)) ([d5afed3](https://github.com/midwayjs/midway/commit/d5afed3ace4e3570b29a2c789b2683f0cd4fd697)) --- # v2.0.10 2020年3月31日 **Note:** Version bump only for package midway --- # v2.0.11 2020年4月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix dfs circular ([#457](https://github.com/midwayjs/midway/issues/457)) ([8b91326](https://github.com/midwayjs/midway/commit/8b9132604df041dad5f1124389d49f75c288aff5)) --- # v2.0.12 2020年4月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * 2.x fix conflicts ([#458](https://github.com/midwayjs/midway/issues/458)) ([2b0f44c](https://github.com/midwayjs/midway/commit/2b0f44c6d4c91154fb8a7779b6789acbb2635b1b)) * 2.x fix conflicts ([#459](https://github.com/midwayjs/midway/issues/459)) ([e9f689c](https://github.com/midwayjs/midway/commit/e9f689c07efec3078c77557f29ea9ecdb5659094)) --- # v2.0.13 2020年4月7日 **Note:** Version bump only for package midway --- # v2.0.14 2020年4月8日 **Note:** Version bump only for package midway --- # v2.0.15 2020年4月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * Fix default env ([#468](https://github.com/midwayjs/midway/issues/468)) ([db9ffcf](https://github.com/midwayjs/midway/commit/db9ffcfcc412bfb7613d46eb3b3b30f44e3b553f)), closes [#450](https://github.com/midwayjs/midway/issues/450) [#454](https://github.com/midwayjs/midway/issues/454) [#379](https://github.com/midwayjs/midway/issues/379) [#455](https://github.com/midwayjs/midway/issues/455) [#463](https://github.com/midwayjs/midway/issues/463) [#464](https://github.com/midwayjs/midway/issues/464) [#466](https://github.com/midwayjs/midway/issues/466) --- # v2.0.16 2020年4月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * Fix cov ([#469](https://github.com/midwayjs/midway/issues/469)) ([1d65da9](https://github.com/midwayjs/midway/commit/1d65da96c34b46fc0e81373c137545613fb1d7b7)) --- # v2.0.17 2020年4月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix export service method ([#477](https://github.com/midwayjs/midway/issues/477)) ([586b0be](https://github.com/midwayjs/midway/commit/586b0be05ee9ef38cef9d312f19de4318c2b1701)) * fun typing ([#467](https://github.com/midwayjs/midway/issues/467)) ([fdf2814](https://github.com/midwayjs/midway/commit/fdf28148da961d20961c95ecea128e92e3bc9819)) --- # v2.0.2 2020年3月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * Add export hsf ([#422](https://github.com/midwayjs/midway/issues/422)) ([55f1e43](https://github.com/midwayjs/midway/commit/55f1e43fbb9bd442939a6bb504aa721297eaf631)) --- # v2.0.3 2020年3月19日 **Note:** Version bump only for package midway --- # v2.0.4 2020年3月19日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * 2.x fix lifecycle bug ([#435](https://github.com/midwayjs/midway/issues/435)) ([22d3e12](https://github.com/midwayjs/midway/commit/22d3e121d98575e994282c93b7522ddcf76942be)) --- # v2.0.5 2020年3月22日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * can midway build when tsconfig.json has comments ([#424](https://github.com/midwayjs/midway/issues/424)) ([f2b2713](https://github.com/midwayjs/midway/commit/f2b27137fe35d1de462adfdc289953d6a405ecd9)) * lazy get default framework ([#430](https://github.com/midwayjs/midway/issues/430)) ([c8c4b49](https://github.com/midwayjs/midway/commit/c8c4b49dd66d197b10bafd24aba55f42672d7d59)) * mock fn ([#439](https://github.com/midwayjs/midway/issues/439)) ([d0a36e4](https://github.com/midwayjs/midway/commit/d0a36e4ff15493603ebb334dc746d64fed300627)) --- # v2.0.6 2020年3月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * configuration with ctx ([4c7ff6a](https://github.com/midwayjs/midway/commit/4c7ff6ade50a1048c465d50145f0aedcb1ec30d3)) --- # v2.0.7 2020年3月30日 **Note:** Version bump only for package midway --- # v2.0.8 2020年3月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * 2.x conflict 能力 ([#449](https://github.com/midwayjs/midway/issues/449)) ([6064ecf](https://github.com/midwayjs/midway/commit/6064ecf0fcf0f79ca9f9f177b06baef6d65ca7ea)) --- # v2.0.9 2020年3月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * @Func return type ([#452](https://github.com/midwayjs/midway/issues/452)) ([9064743](https://github.com/midwayjs/midway/commit/9064743c04713ef77ef246416dabe8f79b97fc79)) --- # v2.1.0 2020年4月29日 ### Features[​](#features "Features的直接链接") * refactor hook & add @App ([#482](https://github.com/midwayjs/midway/issues/482)) ([3bfd300](https://github.com/midwayjs/midway/commit/3bfd300daf21fce96f2ff92be22ecb0f12bdd033)) --- # v2.1.1 2020年4月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add metadata when configuration load controller ([#483](https://github.com/midwayjs/midway/issues/483)) ([e4e3c57](https://github.com/midwayjs/midway/commit/e4e3c5784df844a290a57a3d309a5f4e866e4831)) --- # v2.1.2 2020年5月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix util import ([7d76cbf](https://github.com/midwayjs/midway/commit/7d76cbf4cedc31b141adc76194c89a284e4fe8ee)) * fix wrap app ([c16ea0b](https://github.com/midwayjs/midway/commit/c16ea0b0a0d02539f80586c5a08a027a28ce2d00)) --- # v2.1.3 2020年5月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * configuration use package name ([#485](https://github.com/midwayjs/midway/issues/485)) ([a00cb18](https://github.com/midwayjs/midway/commit/a00cb189b10a7353f6e0545c17837e8c9b10ca2c)) --- # v2.1.4 2020年6月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * 2.x extends bug ([#498](https://github.com/midwayjs/midway/issues/498)) ([19ec029](https://github.com/midwayjs/midway/commit/19ec0292eedd94cb2e40e69af8897703fc8f55c7)) --- # v2.10.0 2021年4月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * directory filter and ignore test pattern ([#957](https://github.com/midwayjs/midway/issues/957)) ([dbd1a5a](https://github.com/midwayjs/midway/commit/dbd1a5a4bc712a5ce14c409a7f2aee96e34eea4f)) ### Features[​](#features "Features的直接链接") * **consul:** register to consul server and lookup service with balancer ([#949](https://github.com/midwayjs/midway/issues/949)) ([d5f9916](https://github.com/midwayjs/midway/commit/d5f99167b63102e0e98ef7e5a92368320ef0e0f2)) * support prometheus client ([#963](https://github.com/midwayjs/midway/issues/963)) ([b0edd42](https://github.com/midwayjs/midway/commit/b0edd428cbda986a472b8fa3055de1bdfb54b146)) * use @ServerlessTrigger replace functions in f.yml ([#919](https://github.com/midwayjs/midway/issues/919)) ([a85af14](https://github.com/midwayjs/midway/commit/a85af14e06231e8cd82eff8755794ffd13c3ad95)) --- # v2.10.1 2021年4月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove MIDWAY\_SERVER\_ENV default value ([#966](https://github.com/midwayjs/midway/issues/966)) ([e9f7165](https://github.com/midwayjs/midway/commit/e9f71653612142204c1160efaedc909b41621c3a)) --- # v2.10.10 2021年4月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * router sort ([#1009](https://github.com/midwayjs/midway/issues/1009)) ([e9bf8ed](https://github.com/midwayjs/midway/commit/e9bf8ed0a6537714e3004a334e417994ea369aa9)) * serverless app support serverless dev ([#1010](https://github.com/midwayjs/midway/issues/1010)) ([bbeeda5](https://github.com/midwayjs/midway/commit/bbeeda5055cfd9dd6988c484354ac701121ae9da)) --- # v2.10.11 2021年4月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * lifecycle missing container when run onStop method ([#1016](https://github.com/midwayjs/midway/issues/1016)) ([3b6303c](https://github.com/midwayjs/midway/commit/3b6303c7bba0d28e821da8062ae71aa4c1029d63)) * load functional config ([#1017](https://github.com/midwayjs/midway/issues/1017)) ([51566c0](https://github.com/midwayjs/midway/commit/51566c08124275798b92d3c931b27a86a48a2ba7)) * logger eol with default value ([#1018](https://github.com/midwayjs/midway/issues/1018)) ([7d3f58d](https://github.com/midwayjs/midway/commit/7d3f58d4841fab12c229591b94f5a488f1841827)) * serverless-app stop need close runtime ([#1015](https://github.com/midwayjs/midway/issues/1015)) ([1bef223](https://github.com/midwayjs/midway/commit/1bef223b5c6bf8225c5ca24f6ff0eeec957d2ac8)) --- # v2.10.12 2021年5月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * change all requestMethod to real method for serverless http request ([#1028](https://github.com/midwayjs/midway/issues/1028)) ([23e2943](https://github.com/midwayjs/midway/commit/23e29436e3a1b3ab10484171f0dfcd5de068f124)) * disable wait event loop in tencent serverless ([#1029](https://github.com/midwayjs/midway/issues/1029)) ([89d5c2e](https://github.com/midwayjs/midway/commit/89d5c2ec9b83f619d72b31cc003a41bc691a1f19)) * output serverless error in some environment ([#1030](https://github.com/midwayjs/midway/issues/1030)) ([b162b89](https://github.com/midwayjs/midway/commit/b162b897812d1a1a5e981328fbbb43aa75eacf10)) * remove winston-daily-rotate-file ([#1032](https://github.com/midwayjs/midway/issues/1032)) ([ae242c1](https://github.com/midwayjs/midway/commit/ae242c10439b035e42634e723af0a0f9b92da239)) * serverless logger close when runtime stop ([#1022](https://github.com/midwayjs/midway/issues/1022)) ([28548da](https://github.com/midwayjs/midway/commit/28548da888005047123523066ca47207f02eb1c8)) * throw error when router duplicate ([#1023](https://github.com/midwayjs/midway/issues/1023)) ([61bc58d](https://github.com/midwayjs/midway/commit/61bc58d29d637f1c9e54fec0a09f24d90c1286c9)) * use egg-logger got empty logger ([#1031](https://github.com/midwayjs/midway/issues/1031)) ([4077c70](https://github.com/midwayjs/midway/commit/4077c70a71507477c7a5fa15449771cc395bc0c0)) --- # v2.10.13 2021年5月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove zlib ([#1035](https://github.com/midwayjs/midway/issues/1035)) ([cc2cd40](https://github.com/midwayjs/midway/commit/cc2cd405a104b3388d93a09d981b59b472fd8ea1)) --- # v2.10.14 2021年5月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * serverless app more method ([#1034](https://github.com/midwayjs/midway/issues/1034)) ([9c44c3f](https://github.com/midwayjs/midway/commit/9c44c3f58930d0c12464d00eceee93cb9e7aaa62)) --- # v2.10.15 2021年5月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * support aliyun fc cors in local env ([#1041](https://github.com/midwayjs/midway/issues/1041)) ([245925a](https://github.com/midwayjs/midway/commit/245925aaf1a2568c3c90a7d03bc1c6df468b8950)) ### Features[​](#features "Features的直接链接") * prometheus qps rt ([#1039](https://github.com/midwayjs/midway/issues/1039)) ([398203e](https://github.com/midwayjs/midway/commit/398203e8f371e74a8c0aeff476c814e764e2b5df)) --- # v2.10.16 2021年5月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **prometheus:** bootstrap for egg ([#1045](https://github.com/midwayjs/midway/issues/1045)) ([aeb0888](https://github.com/midwayjs/midway/commit/aeb0888930d35a3e13a139f30ce4c39710823cfa)) ### Features[​](#features "Features的直接链接") * **task:** add job parameter for task execute ([#1044](https://github.com/midwayjs/midway/issues/1044)) ([314a1f0](https://github.com/midwayjs/midway/commit/314a1f08dea08ca10ac64a4a408997eefa4352f5)) --- # v2.10.17 2021年5月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * serverless app layer ([#1046](https://github.com/midwayjs/midway/issues/1046)) ([0f8dd18](https://github.com/midwayjs/midway/commit/0f8dd18da29eeb76514e203b3ec91cac0928ae15)) --- # v2.10.18 2021年5月26日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * task execute typo ([#1068](https://github.com/midwayjs/midway/issues/1068)) ([20b424d](https://github.com/midwayjs/midway/commit/20b424d9bf7eeca0e9247571000d02d44f342ad9)) ### Features[​](#features "Features的直接链接") * add decorator metadata ([#1072](https://github.com/midwayjs/midway/issues/1072)) ([db4de9c](https://github.com/midwayjs/midway/commit/db4de9cd787bdbe1effca61dfe162f6678ad5d66)) * add zlib logger file ([#1038](https://github.com/midwayjs/midway/issues/1038)) ([2ae9131](https://github.com/midwayjs/midway/commit/2ae9131b8c8745d2840c40a5d50aa2d3f73bafbf)) --- # v2.10.19 2021年5月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * declare definition error in schedule ([#1076](https://github.com/midwayjs/midway/issues/1076)) ([ec8af5a](https://github.com/midwayjs/midway/commit/ec8af5a35a270855c22b8875c11a0c01a0e78188)) --- # v2.10.2 2021年4月5日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * load config once and support load singleton service before framework start ([#970](https://github.com/midwayjs/midway/issues/970)) ([201dd59](https://github.com/midwayjs/midway/commit/201dd5930bd97f62e5717777b2941b47b54d68c6)) * serverless event test ([#967](https://github.com/midwayjs/midway/issues/967)) ([e0c15e3](https://github.com/midwayjs/midway/commit/e0c15e316c2813fd574f38bdf6a16a339bfede18)) --- # v2.10.3 2021年4月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * scf starter name error ([#972](https://github.com/midwayjs/midway/issues/972)) ([4e5de60](https://github.com/midwayjs/midway/commit/4e5de60e73eaf0722c5bc4efad776c55d73077cf)) --- # v2.10.4 2021年4月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * clear container cache when test ([#978](https://github.com/midwayjs/midway/issues/978)) ([a202075](https://github.com/midwayjs/midway/commit/a202075b52d281e06f1ed7c6139e968fafc960f6)) --- # v2.10.5 2021年4月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * configuration file path join on windows ([#984](https://github.com/midwayjs/midway/issues/984)) ([099e76c](https://github.com/midwayjs/midway/commit/099e76ca892decd02b536b97494590f598d140ac)) * delay load without layer and egg-cluster ([#985](https://github.com/midwayjs/midway/issues/985)) ([52ba60d](https://github.com/midwayjs/midway/commit/52ba60d67d6e2df7a53609f72ec067dc083317ce)) * serverless app stop ([#988](https://github.com/midwayjs/midway/issues/988)) ([279a3c5](https://github.com/midwayjs/midway/commit/279a3c5682786be8ec5ec34081c8ef700afa2ec9)) ### Features[​](#features "Features的直接链接") * support getCurrentApplicationContext API ([#981](https://github.com/midwayjs/midway/issues/981)) ([dd6ce11](https://github.com/midwayjs/midway/commit/dd6ce11d6f8eb2884eb1b03b171a069f55aec04f)) --- # v2.10.6 2021年4月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove eol ([#990](https://github.com/midwayjs/midway/issues/990)) ([e97d5de](https://github.com/midwayjs/midway/commit/e97d5ded9b3e4e3995c99b532bf80586a5324e71)) --- # v2.10.7 2021年4月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add event name args ([#986](https://github.com/midwayjs/midway/issues/986)) ([bfd8232](https://github.com/midwayjs/midway/commit/bfd82320aee8600d8fa30bd2821a0e68c80fd755)) * add midway case for egg-layer and add warn for DecoratorManager ([#994](https://github.com/midwayjs/midway/issues/994)) ([3d601aa](https://github.com/midwayjs/midway/commit/3d601aa19104081870eb32ba09170357a9da4d03)) * format ([#997](https://github.com/midwayjs/midway/issues/997)) ([456cc14](https://github.com/midwayjs/midway/commit/456cc14513bdb000d1aa3130e9719caf7a8a803f)) * inject class when use component by import string ([#996](https://github.com/midwayjs/midway/issues/996)) ([8bfda7d](https://github.com/midwayjs/midway/commit/8bfda7da4b4a0d34bf0b0d0291416ef4655fb8a5)) * remove reset bootstrap logger ([#993](https://github.com/midwayjs/midway/issues/993)) ([9dc9596](https://github.com/midwayjs/midway/commit/9dc9596fffb6b76897b28ba51d4a1af3e8c6544c)) * serverless logger rotator error ([#992](https://github.com/midwayjs/midway/issues/992)) ([df681b3](https://github.com/midwayjs/midway/commit/df681b34136e66c8bed0f85711163bc4ffb27867)) ### Features[​](#features "Features的直接链接") * add midway task component ([#995](https://github.com/midwayjs/midway/issues/995)) ([befb81d](https://github.com/midwayjs/midway/commit/befb81dee90f01a20bba2c1835e8685cf85a76e7)) --- # v2.10.8 2021年4月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * serverless app typings missing ([#1001](https://github.com/midwayjs/midway/issues/1001)) ([2500f11](https://github.com/midwayjs/midway/commit/2500f11faf8e2308ff6d2bf55910b98e57b48001)) --- # v2.10.9 2021年4月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * rabbitmq parameter error ([#1002](https://github.com/midwayjs/midway/issues/1002)) ([cdbd5f9](https://github.com/midwayjs/midway/commit/cdbd5f9e5ba3b1d1e2cf26cb59eaec9447514416)) * revert missing code ([#1006](https://github.com/midwayjs/midway/issues/1006)) ([132bdbb](https://github.com/midwayjs/midway/commit/132bdbb96a88b92b7635072840e58c011ebfcb13)) --- # v2.11.0 2021年6月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * rabbitmq reconnection and test ([#1012](https://github.com/midwayjs/midway/issues/1012)) ([c2bea86](https://github.com/midwayjs/midway/commit/c2bea861430a13e53e5b100ea3935f20889c1fff)) * rule required options ([#1000](https://github.com/midwayjs/midway/issues/1000)) ([d76e9f7](https://github.com/midwayjs/midway/commit/d76e9f7473bfe79ff6f07452a2ebad74cce19981)) ### Features[​](#features "Features的直接链接") * add ws support ([#1058](https://github.com/midwayjs/midway/issues/1058)) ([e73cfcb](https://github.com/midwayjs/midway/commit/e73cfcb0ede82244a4eb8fe7c7612adf5586f47d)) * support close consul service check ([#1083](https://github.com/midwayjs/midway/issues/1083)) ([a632bae](https://github.com/midwayjs/midway/commit/a632bae4c87eeed77b448a65cd2164a9d4f59779)) --- # v2.11.1 2021年6月19日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ignore directory with app prefix ([#1100](https://github.com/midwayjs/midway/issues/1100)) ([0911635](https://github.com/midwayjs/midway/commit/09116355bf7f34892d1c7ad975047ed20e65bee5)) * remove emit required parameter ([#1091](https://github.com/midwayjs/midway/issues/1091)) ([54a29d8](https://github.com/midwayjs/midway/commit/54a29d8fe072c15a0b3d1fe9a616d2c84996edc3)) ### Features[​](#features "Features的直接链接") * add date pattern parameter ([#1102](https://github.com/midwayjs/midway/issues/1102)) ([de4c28e](https://github.com/midwayjs/midway/commit/de4c28e62282d72a0815a6e650e63b2f3c3b2341)) * support EventSubscriberModel with provide ([#1095](https://github.com/midwayjs/midway/issues/1095)) ([05431d2](https://github.com/midwayjs/midway/commit/05431d28b9812cf6f658945b3fe7f69801224559)) --- # v2.11.2 2021年6月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add uncaughtException handler ([#1113](https://github.com/midwayjs/midway/issues/1113)) ([8c32165](https://github.com/midwayjs/midway/commit/8c32165daf688a40be5d9b804eb9ebb1bad0fd53)) * logger parameter join output ([#1104](https://github.com/midwayjs/midway/issues/1104)) ([e85e5f1](https://github.com/midwayjs/midway/commit/e85e5f1184e69b0a9aceaabf7f22a4a3df6f0b8f)) * replace ctx.logger in fc serverless environment ([#1112](https://github.com/midwayjs/midway/issues/1112)) ([8ac87b8](https://github.com/midwayjs/midway/commit/8ac87b832154f2ec0fe82df1ec31e283f03b9b2f)) --- # v2.11.3 2021年7月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add origin args ([#1120](https://github.com/midwayjs/midway/issues/1120)) ([fe593fc](https://github.com/midwayjs/midway/commit/fe593fcdbc91f86eb8402f94e12f9ee5d23b1719)) * get complete origin args ([#1130](https://github.com/midwayjs/midway/issues/1130)) ([d652016](https://github.com/midwayjs/midway/commit/d65201666eb4d0326aaecee29e4a91e2f0805245)) * hide real error when user code throw error ([#1128](https://github.com/midwayjs/midway/issues/1128)) ([e728b0b](https://github.com/midwayjs/midway/commit/e728b0b80956c09cfb856ffe082f44fa29cfeb82)) * remove egg dep ([#1118](https://github.com/midwayjs/midway/issues/1118)) ([633cb17](https://github.com/midwayjs/midway/commit/633cb1773dd2133811fe8b500502cabbd3ef0375)) * serverless app invoke args ([#1127](https://github.com/midwayjs/midway/issues/1127)) ([3467b73](https://github.com/midwayjs/midway/commit/3467b73994f755e230e34de36d24b810a65ab854)) * uppercase for header decorator ([#1123](https://github.com/midwayjs/midway/issues/1123)) ([cfcfb1f](https://github.com/midwayjs/midway/commit/cfcfb1fb8860b110e2671e9bff57f6c537f11f90)) * **prometheus:** this.http\_server may undefined onStop ([#1124](https://github.com/midwayjs/midway/issues/1124)) ([300a3ec](https://github.com/midwayjs/midway/commit/300a3ec9d308e4f32b7b266f41370dd920145e0b)) --- # v2.11.4 2021年7月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * @Func decorator with empty metadata ([#1137](https://github.com/midwayjs/midway/issues/1137)) ([621a99a](https://github.com/midwayjs/midway/commit/621a99a9ee77a8f370a28a395363f585057bd054)) * add target parameter ([#1139](https://github.com/midwayjs/midway/issues/1139)) ([5be4757](https://github.com/midwayjs/midway/commit/5be475710ee19e16a99643a355f7f1774f3435bc)) * remove port with other framework ([#1140](https://github.com/midwayjs/midway/issues/1140)) ([88fec38](https://github.com/midwayjs/midway/commit/88fec380ec410bc4c44b30d4d5a751d5341b266f)) * support ignore dsl ([#1133](https://github.com/midwayjs/midway/issues/1133)) ([3ca6c23](https://github.com/midwayjs/midway/commit/3ca6c236d97853fcd7eaed7732fa782b74b45c07)) --- # v2.11.5 2021年7月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add missing arg "groupBy?" at exported attachPropertyDataToClass in decoratorManager ([#1146](https://github.com/midwayjs/midway/issues/1146)) ([f4f7a55](https://github.com/midwayjs/midway/commit/f4f7a55d9329cd9167b5a5aa2b58a29db16e1e23)) * cors and trigger bugs in serverless ([#1156](https://github.com/midwayjs/midway/issues/1156)) ([2df53c2](https://github.com/midwayjs/midway/commit/2df53c277bb33d31b5a86cd3daa04b937caedc48)) * find baseDir in egg ([#1154](https://github.com/midwayjs/midway/issues/1154)) ([2fc9a44](https://github.com/midwayjs/midway/commit/2fc9a44fbf20ee6d4da00555114bf5e9e44eb5df)) ### Features[​](#features "Features的直接链接") * Optimize typeorm to initialize loading entities ([#1150](https://github.com/midwayjs/midway/issues/1150)) ([f0faf2f](https://github.com/midwayjs/midway/commit/f0faf2f1fbdb14f26f157eb554520377c06e6ef8)) --- # v2.11.6 2021年7月16日 ### Features[​](#features "Features的直接链接") * support ssl ([#1160](https://github.com/midwayjs/midway/issues/1160)) ([2e442ae](https://github.com/midwayjs/midway/commit/2e442ae0c67af93df4f8d2f82cb213744befa8d2)) --- # v2.11.7 2021年7月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add generateMiddleware definition for express app ([#1170](https://github.com/midwayjs/midway/issues/1170)) ([246a244](https://github.com/midwayjs/midway/commit/246a244add49cc1f87b8707bc6403dae8a7b5dae)) * socket listen sequelize ([#1175](https://github.com/midwayjs/midway/issues/1175)) ([84f9b68](https://github.com/midwayjs/midway/commit/84f9b68def0761d48242fa73d64f83de03f582ab)) * test error ([#1174](https://github.com/midwayjs/midway/issues/1174)) ([9f47f64](https://github.com/midwayjs/midway/commit/9f47f64fb2a6388d8b3e1b015c0de40949aa3bdc)) --- # v2.12.0 2021年7月30日 ### Features[​](#features "Features的直接链接") * add oss component ([#1181](https://github.com/midwayjs/midway/issues/1181)) ([e83171c](https://github.com/midwayjs/midway/commit/e83171c73cdc1098796f06919dc652a6d83c3af4)) * add support hostname to http-listening ([#1186](https://github.com/midwayjs/midway/issues/1186)) ([6f8356f](https://github.com/midwayjs/midway/commit/6f8356f610c49f87ce8fb9e7d1e60fbd0527d97c)) * add task log ([#1173](https://github.com/midwayjs/midway/issues/1173)) ([00ca5e8](https://github.com/midwayjs/midway/commit/00ca5e8028141db94d8e2ed0ca2729efdc449e75)) * enhance cache for [#1103](https://github.com/midwayjs/midway/issues/1103) ([#1189](https://github.com/midwayjs/midway/issues/1189)) ([562236c](https://github.com/midwayjs/midway/commit/562236cfa5970d47454f26d92c350165d73a63cd)) --- # v2.12.1 2021年8月1日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add preload modules options ([#1194](https://github.com/midwayjs/midway/issues/1194)) ([1681f42](https://github.com/midwayjs/midway/commit/1681f42157ceaa0950ab5d548c0ff5f84dd9908e)) * server hostname args ([#1196](https://github.com/midwayjs/midway/issues/1196)) ([b9d73f0](https://github.com/midwayjs/midway/commit/b9d73f036befd13c1db28f967fb769459237c52e)) ### Features[​](#features "Features的直接链接") * add http client component ([#1098](https://github.com/midwayjs/midway/issues/1098)) ([4e2f90a](https://github.com/midwayjs/midway/commit/4e2f90a9de946fa5abc2af4cd8a0ad9ee4188991)) --- # v2.12.2 2021年8月4日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * change limit for fc ([0546c81](https://github.com/midwayjs/midway/commit/0546c817e8d60a86dfd5dd5703bd96a29e365c27)) --- # v2.12.3 2021年8月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * decorator manager singleton ([#1211](https://github.com/midwayjs/midway/issues/1211)) ([7e9150e](https://github.com/midwayjs/midway/commit/7e9150ef6805389a1a550361f78e3bb997ae9196)) * task redefine context logger ([#1213](https://github.com/midwayjs/midway/issues/1213)) ([f8887c9](https://github.com/midwayjs/midway/commit/f8887c94b234b0156b8b4c6ad728c97a748c5a4f)) ### Features[​](#features "Features的直接链接") * support object config load and async config ([#1212](https://github.com/midwayjs/midway/issues/1212)) ([a035ccb](https://github.com/midwayjs/midway/commit/a035ccbb513b0ba423bd2b48bc228b5e916c89e8)) * vercel starter and trigger ([#1199](https://github.com/midwayjs/midway/issues/1199)) ([7d978a2](https://github.com/midwayjs/midway/commit/7d978a2bd46bf0b96c689ace2a9268e31a2e4acd)) --- # v2.12.4 2021年8月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * post missing data ([#1225](https://github.com/midwayjs/midway/issues/1225)) ([ca99368](https://github.com/midwayjs/midway/commit/ca9936839d407c4c6e1a279eb57338e30a8cbb62)) * update FaasMddleware interface.ts ([#1219](https://github.com/midwayjs/midway/issues/1219)) ([190a729](https://github.com/midwayjs/midway/commit/190a7292d495ebf2af8c66a2257fef41f3362ad1)) --- # v2.2.0 2020年9月13日 ### Features[​](#features "Features的直接链接") * complete 2.x beta ([#630](https://github.com/midwayjs/midway/issues/630)) ([b23cd00](https://github.com/midwayjs/midway/commit/b23cd00fe9cefc9057a2284d38d5419773539206)) * parameters validation ([#451](https://github.com/midwayjs/midway/issues/451)) ([92735b0](https://github.com/midwayjs/midway/commit/92735b009b59ed150b946a387c5ae56893bee53a)) --- # v2.2.1 2020年9月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add missing typing dep ([09a9473](https://github.com/midwayjs/midway/commit/09a9473d0ddc73b7e9e624e1bed1fe58691e36ec)) * fix default logger dir ([ce0e06a](https://github.com/midwayjs/midway/commit/ce0e06ab1cc121074d0b64e35c127982f7b27296)) * fix some problem in 2.x boilerplate ([80608a1](https://github.com/midwayjs/midway/commit/80608a18f5f04798028e1a5c33a264753ee61121)) --- # v2.2.10 2020年9月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * query decorator with empty args ([#646](https://github.com/midwayjs/midway/issues/646)) ([815e230](https://github.com/midwayjs/midway/commit/815e2308e8f40601ee3b94a3ccb2b1567dc03b9f)) --- # v2.2.2 2020年9月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add missing typing dep ([083395f](https://github.com/midwayjs/midway/commit/083395f76709e4b5e8c32e7a9f89d839d8e16b5f)) --- # v2.2.3 2020年9月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove midway-bin dep ([632bd96](https://github.com/midwayjs/midway/commit/632bd96d105b554b8523fd7d24af60f00e67f01d)) --- # v2.2.4 2020年9月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * support midway global middleware use id ([8dc9ae3](https://github.com/midwayjs/midway/commit/8dc9ae33acd559d74f144a75f08fc039037fa45b)) ### Features[​](#features "Features的直接链接") * type extension bootstrap ([71f9358](https://github.com/midwayjs/midway/commit/71f9358b736b9e5f7f8c604be38ca53582863e1e)) --- # v2.2.5 2020年9月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * move @types/joi to dependencies ([#638](https://github.com/midwayjs/midway/issues/638)) ([7c31164](https://github.com/midwayjs/midway/commit/7c31164ae8959b00213527c7fb384a07929790b9)) ### Features[​](#features "Features的直接链接") * add generateMiddleware for express and faas ([bfcfc9a](https://github.com/midwayjs/midway/commit/bfcfc9a377f01026a459aaed35a3f0fdf0530f26)) * add property for web params ([5c19644](https://github.com/midwayjs/midway/commit/5c1964482b4c8efe0ac23c3c1feb1f48ce5b7889)) * use midway cli replace egg-bin ([#639](https://github.com/midwayjs/midway/issues/639)) ([62bbf38](https://github.com/midwayjs/midway/commit/62bbf3852899476600a0b594cb7dc274b05e29ec)) --- # v2.2.6 2020年9月18日 ### Features[​](#features "Features的直接链接") * add aop ([#640](https://github.com/midwayjs/midway/issues/640)) ([c3e15b3](https://github.com/midwayjs/midway/commit/c3e15b328c184318e364bf40d32fa4df6be2a30a)) --- # v2.2.7 2020年9月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * WebMiddleare to IWebMiddleware ([e69cf28](https://github.com/midwayjs/midway/commit/e69cf286fa76ab3144404806c5cbbe8642cdcd61)) --- # v2.2.8 2020年9月23日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix validate error ([e6e58d3](https://github.com/midwayjs/midway/commit/e6e58d371cbc52ddf51a7d03de48ef44b020aaa9)) --- # v2.2.9 2020年9月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove sourcemap and src in dist ([#645](https://github.com/midwayjs/midway/issues/645)) ([e561a88](https://github.com/midwayjs/midway/commit/e561a88f4a70af15d4be3d5fe0bd39487677d4ce)) --- # v2.3.0 2020年9月27日 ### Features[​](#features "Features的直接链接") * add rabbitmq ([#647](https://github.com/midwayjs/midway/issues/647)) ([2c03eb4](https://github.com/midwayjs/midway/commit/2c03eb4f5e979d309048a11f17f7579a1d299ba1)) --- # v2.3.1 2020年9月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix debugger logger create in every request ([#648](https://github.com/midwayjs/midway/issues/648)) ([8e70fb0](https://github.com/midwayjs/midway/commit/8e70fb0b57241bb6e0b2fcca5c4fa2b26fc2eb5e)) --- # v2.3.10 2020年10月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * component inject global object and add case ([#663](https://github.com/midwayjs/midway/issues/663)) ([e768ee8](https://github.com/midwayjs/midway/commit/e768ee872ed9855252346920318a32133328c0fe)) ### Features[​](#features "Features的直接链接") * replace configuration.imports to object directly and deprecated string ([#657](https://github.com/midwayjs/midway/issues/657)) ([f1b42a1](https://github.com/midwayjs/midway/commit/f1b42a1b338a69cdfaf63e2d951a65333e4f3007)) --- # v2.3.11 2020年10月8日 **Note:** Version bump only for package midway --- # v2.3.12 2020年10月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg framework support ignore and match ([#666](https://github.com/midwayjs/midway/issues/666)) ([b541dc0](https://github.com/midwayjs/midway/commit/b541dc0a5437c172d835d215022096bbb2a4889e)) --- # v2.3.13 2020年10月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * [@plugin](https://github.com/plugin) inject undefined in web middleware ([#667](https://github.com/midwayjs/midway/issues/667)) ([cacb2fa](https://github.com/midwayjs/midway/commit/cacb2faa61258172ef445db0a86e45c3f19014a6)) * when middleware config options is undefined, options.match ([#670](https://github.com/midwayjs/midway/issues/670)) ([1893049](https://github.com/midwayjs/midway/commit/18930498434d8bc0254fa1db013346443a96e9f5)) * when middleware config options is undefined. options.enable expr… ([#668](https://github.com/midwayjs/midway/issues/668)) ([3378ea4](https://github.com/midwayjs/midway/commit/3378ea41d0715e4451fb1cda3e72612d458582b0)) --- # v2.3.14 2020年10月15日 **Note:** Version bump only for package midway --- # v2.3.15 2020年10月15日 **Note:** Version bump only for package midway --- # v2.3.16 2020年10月16日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * use new ctx bind req and res in express ([#674](https://github.com/midwayjs/midway/issues/674)) ([1d26396](https://github.com/midwayjs/midway/commit/1d2639698e8e292fe12506a6e530a6d032f46d7e)) --- # v2.3.17 2020年10月22日 **Note:** Version bump only for package midway --- # v2.3.18 2020年10月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * configuration inject plugin and more in production environment ([#680](https://github.com/midwayjs/midway/issues/680)) ([41bce5d](https://github.com/midwayjs/midway/commit/41bce5d8a60a6fde61ff62794612eecff2e260ed)) --- # v2.3.19 2020年10月28日 ### Features[​](#features "Features的直接链接") * add swagger description meta for swagger --- # v2.3.2 2020年9月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * component get config and merge egg config ([#649](https://github.com/midwayjs/midway/issues/649)) ([aa95a3e](https://github.com/midwayjs/midway/commit/aa95a3eb9ff70d691c2420e58b357e2889d03ebb)) --- # v2.3.20 2020年10月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * missing router options ([#689](https://github.com/midwayjs/midway/issues/689)) ([b1693b8](https://github.com/midwayjs/midway/commit/b1693b885a0804f4924616bf0bdafd98b4698d4e)) --- # v2.3.21 2020年10月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * setHeader loop with array ([#691](https://github.com/midwayjs/midway/issues/691)) ([9ed5acc](https://github.com/midwayjs/midway/commit/9ed5acc0f136a2dc6d013b1fd0ee0ab9b7546eab)) --- # v2.3.22 2020年10月31日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * aspect bind missing ctx ([#694](https://github.com/midwayjs/midway/issues/694)) ([871ea80](https://github.com/midwayjs/midway/commit/871ea80b8090e28f02dc74405de5da3969ccf5c4)) --- # v2.3.23 2020年11月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * delay loader.load after midway bootstrap init ([#699](https://github.com/midwayjs/midway/issues/699)) ([2d12a55](https://github.com/midwayjs/midway/commit/2d12a551707099e0fc7ea188466190e63d02a29a)) * trigger lifecycle after egg load ([#701](https://github.com/midwayjs/midway/issues/701)) ([4d63e3a](https://github.com/midwayjs/midway/commit/4d63e3ae38f9d8492894353b1794f1b571790e9d)) --- # v2.3.3 2020年9月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg definition ([#650](https://github.com/midwayjs/midway/issues/650)) ([3e2f1e9](https://github.com/midwayjs/midway/commit/3e2f1e9d65d37acf1f80ece022a7471d09975b30)) --- # v2.3.4 2020年9月28日 **Note:** Version bump only for package midway --- # v2.3.6 2020年10月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fix core pkg name ([#656](https://github.com/midwayjs/midway/issues/656)) ([2d26b0d](https://github.com/midwayjs/midway/commit/2d26b0d3cd6bb541295deb2b5b5c13d955f8587d)) * implement optional dep for amqplib in mock package ([#654](https://github.com/midwayjs/midway/issues/654)) ([3319872](https://github.com/midwayjs/midway/commit/33198727855ff042db7d96723992b49c632aa25d)) ### Features[​](#features "Features的直接链接") * add request path and ip decorator ([#655](https://github.com/midwayjs/midway/issues/655)) ([3354c26](https://github.com/midwayjs/midway/commit/3354c263c92957fd68b90c383c33afc6ad9ae967)) --- # v2.3.7 2020年10月4日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * transform type after validate ([#659](https://github.com/midwayjs/midway/issues/659)) ([2b30ba7](https://github.com/midwayjs/midway/commit/2b30ba77d0c897d84d8a6f3222b60c083ec3e869)) --- # v2.3.8 2020年10月5日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * schedule case ([#660](https://github.com/midwayjs/midway/issues/660)) ([c9fb3fb](https://github.com/midwayjs/midway/commit/c9fb3fbe5e4edff5e89e11bfbe19c5fcc3515883)) --- # v2.3.9 2020年10月5日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * include files ([#661](https://github.com/midwayjs/midway/issues/661)) ([d48e145](https://github.com/midwayjs/midway/commit/d48e145198939cb5bb2a396edbd438cbd531ca3c)) --- # v2.4.0 2020年11月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * mock method missing ([#710](https://github.com/midwayjs/midway/issues/710)) ([0088cb2](https://github.com/midwayjs/midway/commit/0088cb2253f4f99dc945a5fc99b580bfa4d4a594)) ### Features[​](#features "Features的直接链接") * support define custom egg framework ([#709](https://github.com/midwayjs/midway/issues/709)) ([f5baba1](https://github.com/midwayjs/midway/commit/f5baba18d10e3dc91ba9651effadd00b8f66cf8b)) * **hooks:** use app hooks ([#708](https://github.com/midwayjs/midway/issues/708)) ([faf05c5](https://github.com/midwayjs/midway/commit/faf05c5cdba3e743568db74720f4927374c15f19)) --- # v2.4.1 2020年11月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * first schedule ignore stop other schedule ([#715](https://github.com/midwayjs/midway/issues/715)) ([d296636](https://github.com/midwayjs/midway/commit/d2966361cbaf33bc8f53c30c097bbbd3e64a139f)) * load ignore node\_modules ([#714](https://github.com/midwayjs/midway/issues/714)) ([ad13f13](https://github.com/midwayjs/midway/commit/ad13f1357263fad143ad18527a3c04bd4a629798)) --- # v2.4.2 2020年11月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * error pattern for ignore node\_modules ([#717](https://github.com/midwayjs/midway/issues/717)) ([16f1292](https://github.com/midwayjs/midway/commit/16f1292359b8c65548eea3926de8eaaa13133538)) --- # v2.4.3 2020年11月16日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * aspect mapping npe ([#722](https://github.com/midwayjs/midway/issues/722)) ([1954eed](https://github.com/midwayjs/midway/commit/1954eed145cbb8fc929394f6cb0c1bc8cb80c823)) * fc egg app body parse ([#719](https://github.com/midwayjs/midway/issues/719)) ([18c0aad](https://github.com/midwayjs/midway/commit/18c0aad1d9a187d59da6d9f11940ef82b2770ff0)) --- # v2.4.4 2020年11月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove error process env branch ([#723](https://github.com/midwayjs/midway/issues/723)) ([53ddc4c](https://github.com/midwayjs/midway/commit/53ddc4caec322162889e50f21b50aef96907a607)) --- # v2.4.5 2020年11月19日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * core middleware load ([#724](https://github.com/midwayjs/midway/issues/724)) ([9697834](https://github.com/midwayjs/midway/commit/96978348412284b421adff4be1bdacc1a539fc64)) * get function args error ([#725](https://github.com/midwayjs/midway/issues/725)) ([7ec5317](https://github.com/midwayjs/midway/commit/7ec531776efc65a84d60a7c55dc29ad4e08d999a)) --- # v2.4.6 2020年11月19日 **Note:** Version bump only for package midway --- # v2.4.7 2020年11月23日 **Note:** Version bump only for package midway --- # v2.4.8 2020年11月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * use egg-layer load framework circular reference ([#730](https://github.com/midwayjs/midway/issues/730)) ([f012d78](https://github.com/midwayjs/midway/commit/f012d78599fa0f877937cdb0caaec04da518b917)) --- # v2.5.0 2020年11月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * got egg env from serverEnv ([#735](https://github.com/midwayjs/midway/issues/735)) ([ac19c94](https://github.com/midwayjs/midway/commit/ac19c94a708cb6c5798ae43b04c7e5e5a8382b6c)) * koa response 204 ([#733](https://github.com/midwayjs/midway/issues/733)) ([2463d77](https://github.com/midwayjs/midway/commit/2463d77cf2d9b03216acff901839816be45c5e73)) ### Features[​](#features "Features的直接链接") * add getFunctionName() and functionSerivceName() method to runtime and faas framework ([#734](https://github.com/midwayjs/midway/issues/734)) ([f0bc5aa](https://github.com/midwayjs/midway/commit/f0bc5aadd224e6ec85691b9c82cc7993cbc32cdb)) --- # v2.5.1 2020年11月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * return ctx.body and set header after send ([#738](https://github.com/midwayjs/midway/issues/738)) ([4c8e740](https://github.com/midwayjs/midway/commit/4c8e740865ece6a62176144a877863c1d5317d65)) --- # v2.5.2 2020年12月4日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * definition for getAsync and get ([#740](https://github.com/midwayjs/midway/issues/740)) ([d40de78](https://github.com/midwayjs/midway/commit/d40de7899f3b816c61229dce463d9b2de6842259)) * ignore set body after user set status ([#741](https://github.com/midwayjs/midway/issues/741)) ([4fdb2a6](https://github.com/midwayjs/midway/commit/4fdb2a62c0ff694aa0b6bffaec3386a36d4334c9)) --- # v2.5.3 2020年12月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * runtime mock support initHandler ([#749](https://github.com/midwayjs/midway/issues/749)) ([0b993be](https://github.com/midwayjs/midway/commit/0b993beff72ef648dc438dda4d0214f4e3b13954)) * support eggjs in monorepo ([#751](https://github.com/midwayjs/midway/issues/751)) ([18c32b9](https://github.com/midwayjs/midway/commit/18c32b980167dd9a3547b0a930a043f9c37f86ad)) --- # v2.5.4 2020年12月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * monorepo use different cwd ([#752](https://github.com/midwayjs/midway/issues/752)) ([cb3ba35](https://github.com/midwayjs/midway/commit/cb3ba35343101c1cb34cc10bdd31237c226266bb)) --- # v2.5.5 2020年12月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * aspect wrapper requestContext instance ([#755](https://github.com/midwayjs/midway/issues/755)) ([84193a0](https://github.com/midwayjs/midway/commit/84193a0a50483a0ec8e25b25a17654d4fc77ed1d)) --- # v2.6.0 2020年12月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg layer x forwarded for ([#768](https://github.com/midwayjs/midway/issues/768)) ([568379f](https://github.com/midwayjs/midway/commit/568379fca58744410b273cc6fdb40cec83700d08)) * ouput console in serverless environment ([#759](https://github.com/midwayjs/midway/issues/759)) ([bad20d7](https://github.com/midwayjs/midway/commit/bad20d7950d1ed96a0448aedfac5ae8f909a7960)) * parse http is type ([#763](https://github.com/midwayjs/midway/issues/763)) ([ee77af5](https://github.com/midwayjs/midway/commit/ee77af5e32b36807ddc5d05555826b8562ec6769)) ### Features[​](#features "Features的直接链接") * add midway logger ([#743](https://github.com/midwayjs/midway/issues/743)) ([13e8cc7](https://github.com/midwayjs/midway/commit/13e8cc753d994e6f9f073688e22527f75d39984a)) * support https config for web/koa/express ([#742](https://github.com/midwayjs/midway/issues/742)) ([a0c07b9](https://github.com/midwayjs/midway/commit/a0c07b9e3cc2eec7e88e49085f1e66242fa1ec50)) --- # v2.6.1 2020年12月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * logger build ([#779](https://github.com/midwayjs/midway/issues/779)) ([ee3589e](https://github.com/midwayjs/midway/commit/ee3589e0bed5d79fade9c2067de1452eeb718da4)) --- # v2.6.10 2021年1月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * bootstrap missing create logger ([#797](https://github.com/midwayjs/midway/issues/797)) ([f7aac5f](https://github.com/midwayjs/midway/commit/f7aac5fcd9a59a3a36856af58c17ee1d0c9dfca4)) * disable logrotator and avoid file exists error ([#798](https://github.com/midwayjs/midway/issues/798)) ([64ac85c](https://github.com/midwayjs/midway/commit/64ac85c68bf479e9474de9ac8f22c491d8bfce39)) --- # v2.6.11 2021年1月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * missing originContext property in http trigger ([#799](https://github.com/midwayjs/midway/issues/799)) ([5cd96a0](https://github.com/midwayjs/midway/commit/5cd96a00bdbd733d89dbcb50e460e4a9392679d5)) --- # v2.6.12 2021年1月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * express router missing ([#804](https://github.com/midwayjs/midway/issues/804)) ([30cd26c](https://github.com/midwayjs/midway/commit/30cd26cc505ea91fb7d0796c59238962c5045b3d)) * mockClassFunction missing ([#807](https://github.com/midwayjs/midway/issues/807)) ([88fa763](https://github.com/midwayjs/midway/commit/88fa7636dbfaba89fb420b70f96cd904630e687c)) * rabbitmq client mock ([#801](https://github.com/midwayjs/midway/issues/801)) ([18d0fcd](https://github.com/midwayjs/midway/commit/18d0fcd24df722ec5a58775fd4d795f22c4e4725)) --- # v2.6.13 2021年1月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * fc runtime default ctx ([#813](https://github.com/midwayjs/midway/issues/813)) ([23ad9a2](https://github.com/midwayjs/midway/commit/23ad9a281cbba0e37e3356b15151d8bf08937662)) * file transport context formatter missing ([#815](https://github.com/midwayjs/midway/issues/815)) ([45bd3d5](https://github.com/midwayjs/midway/commit/45bd3d58104e859805f0d7feb84ff17c136966c9)) * optional options ([#811](https://github.com/midwayjs/midway/issues/811)) ([ed3f659](https://github.com/midwayjs/midway/commit/ed3f6594efc32cf2bc9930a687836ae014cb7d90)) * winston-transport build error when enable esModuleInterop ([#814](https://github.com/midwayjs/midway/issues/814)) ([da6e762](https://github.com/midwayjs/midway/commit/da6e762fe32df37307c4f805a38a79f84c36af16)) --- # v2.6.2 2020年12月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * output logs dir when development env ([#780](https://github.com/midwayjs/midway/issues/780)) ([557d874](https://github.com/midwayjs/midway/commit/557d8743cf5183740b25a987b1a1135ea09c9d28)) --- # v2.6.3 2020年12月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add more args for egg transport ([#782](https://github.com/midwayjs/midway/issues/782)) ([adbbfc9](https://github.com/midwayjs/midway/commit/adbbfc9f98c0e9d5617e37232113e7f1e2f92a15)) --- # v2.6.4 2021年1月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * definition fix for getLogger and getCoreLogger ([#783](https://github.com/midwayjs/midway/issues/783)) ([264b481](https://github.com/midwayjs/midway/commit/264b4819f8f96dccabd1e5cd6ad2c7b3b8277136)) --- # v2.6.5 2021年1月4日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg logger definition ([#788](https://github.com/midwayjs/midway/issues/788)) ([a5464f4](https://github.com/midwayjs/midway/commit/a5464f48f5e7f7aee71fadf8e26b187b5802fe24)) --- # v2.6.6 2021年1月4日 **Note:** Version bump only for package midway --- # v2.6.7 2021年1月5日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * can't throw error in faas ([#790](https://github.com/midwayjs/midway/issues/790)) ([e740cda](https://github.com/midwayjs/midway/commit/e740cdaec5fbae0c4addb1eefbb428ea0a50d3eb)) * remove error and symbol link in windows ([#792](https://github.com/midwayjs/midway/issues/792)) ([7434724](https://github.com/midwayjs/midway/commit/7434724a2cf422724ea143032ecb6ccb601d7d7f)) * remove log method in ILogger definition ([#791](https://github.com/midwayjs/midway/issues/791)) ([e716349](https://github.com/midwayjs/midway/commit/e71634957c3e3f183c3f7c03e32db27e9ac82017)) --- # v2.6.8 2021年1月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * force add logger ([#793](https://github.com/midwayjs/midway/issues/793)) ([f095543](https://github.com/midwayjs/midway/commit/f0955438ba5645daf62b107700f2b01537ecf827)) --- # v2.6.9 2021年1月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove array type for label and remove verbose level ([#795](https://github.com/midwayjs/midway/issues/795)) ([622163c](https://github.com/midwayjs/midway/commit/622163c30bd3bf89423850caa39ea58433f18df3)) --- # v2.7.0 2021年1月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add info level for core logger in local env ([#826](https://github.com/midwayjs/midway/issues/826)) ([8e8fc59](https://github.com/midwayjs/midway/commit/8e8fc59435bd77c917d7ce7bdf4e486492455a61)) * date string error in ISO pattern ([#817](https://github.com/midwayjs/midway/issues/817)) ([6557e95](https://github.com/midwayjs/midway/commit/6557e95f70517900df113aa44d1dc42ee1435e9b)) * midway logger and mixin egg logger will be missing log ([#823](https://github.com/midwayjs/midway/issues/823)) ([ac33af2](https://github.com/midwayjs/midway/commit/ac33af217f59a4b06224cb5d6f7eead007a4da41)) ### Features[​](#features "Features的直接链接") * add component mongoose ([#805](https://github.com/midwayjs/midway/issues/805)) ([0092831](https://github.com/midwayjs/midway/commit/0092831858d469ebfbd1a678d665aa956ef1f2fa)) * add midway gRPC framework ([#786](https://github.com/midwayjs/midway/issues/786)) ([d90362c](https://github.com/midwayjs/midway/commit/d90362c6bf15c00621ffc2981f19842f216395f8)) * rabbitmq component ([#802](https://github.com/midwayjs/midway/issues/802)) ([d40197a](https://github.com/midwayjs/midway/commit/d40197a66cdff4a49ad16c6cd1a3467003c9a0a1)) * support entry file in bootstrap ([#819](https://github.com/midwayjs/midway/issues/819)) ([49a5ff6](https://github.com/midwayjs/midway/commit/49a5ff662134bdd42dc3a80738b44a05138f8f7c)) --- # v2.7.1 2021年1月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * disable coreLogger info console output in local env ([#829](https://github.com/midwayjs/midway/issues/829)) ([adaaaea](https://github.com/midwayjs/midway/commit/adaaaeaa9694c072de709c6643c0d7cffbdf3065)) --- # v2.7.2 2021年1月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * mock empty options ([#831](https://github.com/midwayjs/midway/issues/831)) ([7668461](https://github.com/midwayjs/midway/commit/7668461c6ba6097cba9f132fc868f180c66b57d8)) --- # v2.7.3 2021年2月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * context logger mixin ([#836](https://github.com/midwayjs/midway/issues/836)) ([21c78c2](https://github.com/midwayjs/midway/commit/21c78c2a6d3d313d5e504394abdf2d4e91b71b24)) * egg socket io missing session middleware ([#835](https://github.com/midwayjs/midway/issues/835)) ([6e605a1](https://github.com/midwayjs/midway/commit/6e605a15b64bf51182b393b68d66d0867c571b94)) --- # v2.7.4 2021年2月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * http parser get body ([#837](https://github.com/midwayjs/midway/issues/837)) ([9afdbbb](https://github.com/midwayjs/midway/commit/9afdbbbd201834ec989f45a4d54cb26883d812e6)) --- # v2.7.5 2021年2月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ctx logger overwrite in egg extend ([#846](https://github.com/midwayjs/midway/issues/846)) ([a9d7a0d](https://github.com/midwayjs/midway/commit/a9d7a0dab8db24c970fe6528deb62afcf24c11b0)) * load ready after super.load ([#840](https://github.com/midwayjs/midway/issues/840)) ([e329333](https://github.com/midwayjs/midway/commit/e3293338514909179da31847027f46f23cdc1759)) * stack missing in context logger ([#841](https://github.com/midwayjs/midway/issues/841)) ([7b27145](https://github.com/midwayjs/midway/commit/7b27145ec49c1f89740f8d6f811a00308e90e498)) ### Features[​](#features "Features的直接链接") * add configuration functional support ([#843](https://github.com/midwayjs/midway/issues/843)) ([bfaa0aa](https://github.com/midwayjs/midway/commit/bfaa0aad9e8ce667a4bb98af60f1c706e09e7810)) * add enable method ([#847](https://github.com/midwayjs/midway/issues/847)) ([a85b99d](https://github.com/midwayjs/midway/commit/a85b99dd775b9cf69dec3a7fa78248d4d82ad814)) * add logger.write method ([#844](https://github.com/midwayjs/midway/issues/844)) ([0051d07](https://github.com/midwayjs/midway/commit/0051d07d22e9cf88828b723861925d75b00a985f)) --- # v2.7.6 2021年2月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * loggers with egg logger instance and invoke disableConsole method ([#849](https://github.com/midwayjs/midway/issues/849)) ([b5d18e2](https://github.com/midwayjs/midway/commit/b5d18e22764b06b0a9f95e924c475678e78f6b42)) --- # v2.7.7 2021年2月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add request secure ([#854](https://github.com/midwayjs/midway/issues/854)) ([800d30b](https://github.com/midwayjs/midway/commit/800d30bc0374b208434f328efeeb0c9239063520)) * bootstrap in dev ([#851](https://github.com/midwayjs/midway/issues/851)) ([0e616da](https://github.com/midwayjs/midway/commit/0e616da5a20a1ac5da68d5086b3e0309ce1fdd18)) --- # v2.8.0 2021年2月24日 ### Features[​](#features "Features的直接链接") * add router collector and export router table ([#852](https://github.com/midwayjs/midway/issues/852)) ([3641ac9](https://github.com/midwayjs/midway/commit/3641ac9c78ed9888525ce0c87415b961d4602fa8)) * move context logger to @midwayjs/logger and add createFileL… ([#859](https://github.com/midwayjs/midway/issues/859)) ([49f568f](https://github.com/midwayjs/midway/commit/49f568f372b610494d59fa415f4f241c400c7db0)) * support gRPC stream API ([#855](https://github.com/midwayjs/midway/issues/855)) ([bd51c46](https://github.com/midwayjs/midway/commit/bd51c46a1986d9a0666d6af2a1f053ad74560dcc)) * support inject by class ([#832](https://github.com/midwayjs/midway/issues/832)) ([ba5364f](https://github.com/midwayjs/midway/commit/ba5364fcdf9b83c5f778bb7e18d48b821be8f25b)) * support queries decorator ([#858](https://github.com/midwayjs/midway/issues/858)) ([ddb080b](https://github.com/midwayjs/midway/commit/ddb080bbba0b24a4c1f826d8552966275f31ebeb)) --- # v2.8.10 2021年3月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * serverless app layers support ([#892](https://github.com/midwayjs/midway/issues/892)) ([45cd7fe](https://github.com/midwayjs/midway/commit/45cd7fee07223ebb00cf5132cf5b98f372dcdf91)) --- # v2.8.11 2021年3月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * load egg router before midway container ready ([#909](https://github.com/midwayjs/midway/issues/909)) ([4640674](https://github.com/midwayjs/midway/commit/4640674c752122ef4706282b55cff2deb097867e)) * validator class extends ([#896](https://github.com/midwayjs/midway/issues/896)) ([ea2edfe](https://github.com/midwayjs/midway/commit/ea2edfe86f19de983dc634c2e53d750feec906ee)) ### Features[​](#features "Features的直接链接") * add logger dynamic change info method ([#897](https://github.com/midwayjs/midway/issues/897)) ([5a11374](https://github.com/midwayjs/midway/commit/5a113744da64ca31c5e0a1eb18af2fd5739f4c43)) * compatible read config.prod and config.unittest ([#899](https://github.com/midwayjs/midway/issues/899)) ([f90cfe3](https://github.com/midwayjs/midway/commit/f90cfe3a28912ad43f371aff66d4a52e9efa3a68)) * complete static-layer ([#908](https://github.com/midwayjs/midway/issues/908)) ([75033b5](https://github.com/midwayjs/midway/commit/75033b51c89e51e573c0789ec2466447918bcd61)) --- # v2.8.12 2021年3月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * multi package name in grpc client ([#917](https://github.com/midwayjs/midway/issues/917)) ([9e08c93](https://github.com/midwayjs/midway/commit/9e08c938988ee965685d751f33730989893a291c)) * serverless app layers ([#903](https://github.com/midwayjs/midway/issues/903)) ([73cd61a](https://github.com/midwayjs/midway/commit/73cd61aa3d847a1a61322eaf7950f01cd0c77a2d)) --- # v2.8.13 2021年3月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add missing typings ([#924](https://github.com/midwayjs/midway/issues/924)) ([a17c8d8](https://github.com/midwayjs/midway/commit/a17c8d8655d3f7a93469b922529b7a1aba212c10)) --- # v2.8.2 2021年2月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove file options ([#869](https://github.com/midwayjs/midway/issues/869)) ([2287e00](https://github.com/midwayjs/midway/commit/2287e00f617b365ac28b6b2d01d3cf89d0935f9b)) ### Features[​](#features "Features的直接链接") * support fun router ([#867](https://github.com/midwayjs/midway/issues/867)) ([01e673f](https://github.com/midwayjs/midway/commit/01e673f50d48d302e449ab88c2e419bcaeab1458)) --- # v2.8.3 2021年3月1日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * inject definition bug ([#878](https://github.com/midwayjs/midway/issues/878)) ([e11a057](https://github.com/midwayjs/midway/commit/e11a057d25f5205f3641f89e9c8ecd201a2bfdc7)) * router sort with param ([#877](https://github.com/midwayjs/midway/issues/877)) ([7405745](https://github.com/midwayjs/midway/commit/7405745330cbeedc74829bc7683686866d91b633)) --- # v2.8.4 2021年3月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * case ([df2efb6](https://github.com/midwayjs/midway/commit/df2efb6837ee1bdb877825bc7869b82d9e220fb1)) * check case ([4df51ed](https://github.com/midwayjs/midway/commit/4df51ed64157a7b3f76bc050825cf2b59182cc07)) * get singleton from shared context ([3ebcf13](https://github.com/midwayjs/midway/commit/3ebcf13ab0f4151e507b51cda219682859f648d3)) * koa-router support wildcard ([#881](https://github.com/midwayjs/midway/issues/881)) ([0321497](https://github.com/midwayjs/midway/commit/0321497421de648dc791ceb60316c78026dc3cf9)) * multi framework run configuration ([44abb6c](https://github.com/midwayjs/midway/commit/44abb6c710e044d9256325c721cdeb8d9a7e0a7a)) * multi framework run configuration ([db98d6a](https://github.com/midwayjs/midway/commit/db98d6aba820aa86982b491835bb4167b3a1b6b2)) * property decorator and class decorator extends ([#845](https://github.com/midwayjs/midway/issues/845)) ([8d0227d](https://github.com/midwayjs/midway/commit/8d0227dfe946af6fefa832d574cdcfe976ed8ce2)) * serverless support ts ([#879](https://github.com/midwayjs/midway/issues/879)) ([8aea51d](https://github.com/midwayjs/midway/commit/8aea51d3e5a25edb81e269c6ca67050411d4bc74)) ### Features[​](#features "Features的直接链接") * add conflictCheck ([2e08976](https://github.com/midwayjs/midway/commit/2e0897671fd4cb4b36ab351b626347e2f17ace56)) * add conflictCheck ([a892223](https://github.com/midwayjs/midway/commit/a8922234abb2c585d59e37aaa443b14d73a14b2f)) --- # v2.8.5 2021年3月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * empty framework ready ([#882](https://github.com/midwayjs/midway/issues/882)) ([a2dc36f](https://github.com/midwayjs/midway/commit/a2dc36f8dd785e7dce3a5499f5774b990dfd33c4)) --- # v2.8.6 2021年3月3日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * load custom framework in midwayjs/web ([#883](https://github.com/midwayjs/midway/issues/883)) ([7a11cac](https://github.com/midwayjs/midway/commit/7a11cac1cea753e781ac358a75277400f8aa87bf)) --- # v2.8.7 2021年3月4日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * exports missing ([#884](https://github.com/midwayjs/midway/issues/884)) ([a360a0e](https://github.com/midwayjs/midway/commit/a360a0e645a9551cb9d90ceaf7871f3e0ab5b4d3)) --- # v2.8.8 2021年3月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * app proxy ([#886](https://github.com/midwayjs/midway/issues/886)) ([e8fba77](https://github.com/midwayjs/midway/commit/e8fba77ea9920a9bc0b48011f85d77717cab77fd)) * handler ([#885](https://github.com/midwayjs/midway/issues/885)) ([89c6b53](https://github.com/midwayjs/midway/commit/89c6b53d2de8601394d1799c914dbf8177d37f5b)) --- # v2.8.9 2021年3月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * delete method parse body and form body ([#891](https://github.com/midwayjs/midway/issues/891)) ([f5c1e70](https://github.com/midwayjs/midway/commit/f5c1e7042ed85656e323563421391a719999979e)) --- # v2.9.0 2021年3月22日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * create log dir in serverless environment ([#935](https://github.com/midwayjs/midway/issues/935)) ([8a15f69](https://github.com/midwayjs/midway/commit/8a15f694a19a6274bce5172f1dce716ef3d8c0a8)) * lint ([8a34e92](https://github.com/midwayjs/midway/commit/8a34e925ea31910596bd03326f582ad9d4bb72e2)) * lint ([467a03b](https://github.com/midwayjs/midway/commit/467a03bebf7499ce6f9f7002043eae2fc83730da)) * providerWrapper get empty object in component ([#926](https://github.com/midwayjs/midway/issues/926)) ([5e46d19](https://github.com/midwayjs/midway/commit/5e46d19386ae91820e9df71a02a3de7b3f54d3dc)) ### Features[​](#features "Features的直接链接") * add midway cache ([#911](https://github.com/midwayjs/midway/issues/911)) ([cc49eee](https://github.com/midwayjs/midway/commit/cc49eee739ba6d2c37b9270b6cf5239afde4a912)) * add socket.io-redis support ([#874](https://github.com/midwayjs/midway/issues/874)) ([2818920](https://github.com/midwayjs/midway/commit/2818920b9d3391c81666c5b8587a899b9b237d9e)) * run multi framework in one process ([#925](https://github.com/midwayjs/midway/issues/925)) ([330555f](https://github.com/midwayjs/midway/commit/330555f93b9af2a783771edd58bb9431a325938f)) * support bootstrap load config first ([#931](https://github.com/midwayjs/midway/issues/931)) ([ae9ed26](https://github.com/midwayjs/midway/commit/ae9ed261aacdb483d3a9a612be79fff384503bcc)) --- # v2.9.1 2021年3月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * /user/ => /user ([#941](https://github.com/midwayjs/midway/issues/941)) ([6883400](https://github.com/midwayjs/midway/commit/688340021d145c9ce07a05fdda0c1ad8788959df)) * npe for faas ([#943](https://github.com/midwayjs/midway/issues/943)) ([8c062f9](https://github.com/midwayjs/midway/commit/8c062f994b89a129a710586e517003f9e6524c31)) --- # v2.9.2 2021年3月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * framework find and sort ([#946](https://github.com/midwayjs/midway/issues/946)) ([2aac414](https://github.com/midwayjs/midway/commit/2aac4142178417ccd0a60a1007e8ce8b53ed4d4f)) * interface in serverless-app ([#947](https://github.com/midwayjs/midway/issues/947)) ([0b56648](https://github.com/midwayjs/midway/commit/0b566483d92d0ddac516e49dccc9218e05019220)) * missing namespace requestContainer ([#942](https://github.com/midwayjs/midway/issues/942)) ([92e4ee6](https://github.com/midwayjs/midway/commit/92e4ee638d657677b1295bb71c033471b850990b)) --- # v2.9.3 2021年3月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * bootstrap cache error framework ([#955](https://github.com/midwayjs/midway/issues/955)) ([59ec100](https://github.com/midwayjs/midway/commit/59ec10096418fd1e7be2dbce8f254bce1073e931)) * client ip proxy to real server ([#956](https://github.com/midwayjs/midway/issues/956)) ([fa6d53c](https://github.com/midwayjs/midway/commit/fa6d53cde0f8bcbca875cf69faa08a708746c0bc)) * set error logger key ([#953](https://github.com/midwayjs/midway/issues/953)) ([25b4302](https://github.com/midwayjs/midway/commit/25b4302b16431031aa2c20304848db9a14a8babb)) --- # v3.0.0 2022年1月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency supertest to v6.2.2 ([#1599](https://github.com/midwayjs/midway/issues/1599)) ([982d888](https://github.com/midwayjs/midway/commit/982d88816e90e43785f4c429608ce8eafed4da81)) ### Features[​](#features "Features的直接链接") * add favicon middleware and remove koa-onerror ([#1601](https://github.com/midwayjs/midway/issues/1601)) ([2956174](https://github.com/midwayjs/midway/commit/295617498c099982b1c2b3f192ffefb7adbf6b38)) * add hooks doc ([#1606](https://github.com/midwayjs/midway/issues/1606)) ([dd29231](https://github.com/midwayjs/midway/commit/dd29231d9a8093cd2fbb14257b43994307d286be)) # [3.0.0-beta.17](https://github.com/midwayjs/midway/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2022-01-18) ### Bug Fixes[​](#bug-fixes-1 "Bug Fixes的直接链接") * **deps:** update dependency axios to ^0.25.0 ([#1596](https://github.com/midwayjs/midway/issues/1596)) ([b30f1ae](https://github.com/midwayjs/midway/commit/b30f1aecc66755972f0572692918eb3408e22be2)) * **deps:** update dependency supertest to v6.2.1 ([#1561](https://github.com/midwayjs/midway/issues/1561)) ([0bcde23](https://github.com/midwayjs/midway/commit/0bcde231d562d2daedcbefcdaaa8ddcf5bb9ad58)) * move koa-session and definition ([#1572](https://github.com/midwayjs/midway/issues/1572)) ([95743c1](https://github.com/midwayjs/midway/commit/95743c11917507ccf4c218f5353e1b88917237a5)) * move register to on server ready ([#1576](https://github.com/midwayjs/midway/issues/1576)) ([b5f8256](https://github.com/midwayjs/midway/commit/b5f8256d8cab103e3b9c7f22d5fc66bd5fa6c525)) * remove bodyParser typings ([#1579](https://github.com/midwayjs/midway/issues/1579)) ([a967fdf](https://github.com/midwayjs/midway/commit/a967fdf2cba305804ce2355f7fcdb23db1f09ab2)) ### Features[​](#features-1 "Features的直接链接") * add static file ([#1597](https://github.com/midwayjs/midway/issues/1597)) ([2e6baae](https://github.com/midwayjs/midway/commit/2e6baae852f338023e39c72801e6c89319dd2e2e)) * Allows the user to provide the response after authentication fa… ([#1567](https://github.com/midwayjs/midway/issues/1567)) ([57efdee](https://github.com/midwayjs/midway/commit/57efdee91ba81d02be6d0e0e0c2566ba30577386)) * security ([#1569](https://github.com/midwayjs/midway/issues/1569)) ([30762cc](https://github.com/midwayjs/midway/commit/30762cc84ed0df090086841f5470c00dfcbebe51)) * support multi root ([#1584](https://github.com/midwayjs/midway/issues/1584)) ([b23dda2](https://github.com/midwayjs/midway/commit/b23dda258563fba143f23c8779680df3ab8ec3d5)) * throw error when singleton invoke request scope ([#1589](https://github.com/midwayjs/midway/issues/1589)) ([e71bfa8](https://github.com/midwayjs/midway/commit/e71bfa8cc43317989adebd4a2f7b6a24a74e36be)) # [3.0.0-beta.16](https://github.com/midwayjs/midway/compare/v3.0.0-beta.15...v3.0.0-beta.16) (2022-01-11) ### Bug Fixes[​](#bug-fixes-2 "Bug Fixes的直接链接") * @File/@Files schema no type bug ([#1532](https://github.com/midwayjs/midway/issues/1532)) ([a776b3d](https://github.com/midwayjs/midway/commit/a776b3d890ab1faeb3164a42e1dcc953415f8f89)) * **deps:** update dependency amqp-connection-manager to v4 ([#1534](https://github.com/midwayjs/midway/issues/1534)) ([78612e1](https://github.com/midwayjs/midway/commit/78612e13211332112f28e868404473b9fe5a7b75)) * **deps:** update dependency sequelize to \~6.13.0 ([#1554](https://github.com/midwayjs/midway/issues/1554)) ([0a82a2c](https://github.com/midwayjs/midway/commit/0a82a2c698f9b85debf3d09850fb9d350b27bba7)) * **deps:** update dependency supertest to v6.2.0 ([#1555](https://github.com/midwayjs/midway/issues/1555)) ([4ff0e03](https://github.com/midwayjs/midway/commit/4ff0e03e833825b7a79c530665b4ab27b5d25294)) * typings ([4afffe6](https://github.com/midwayjs/midway/commit/4afffe62ddfa97346863691a24065f5820bb9531)) ### Features[​](#features-2 "Features的直接链接") * swagger tags support ascii order ([#1548](https://github.com/midwayjs/midway/issues/1548)) ([f60438f](https://github.com/midwayjs/midway/commit/f60438f4dcf56538de0a1f0978fde8053660ec4c)) # [3.0.0-beta.15](https://github.com/midwayjs/midway/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2022-01-07) ### Bug Fixes[​](#bug-fixes-3 "Bug Fixes的直接链接") * **deps:** update socket.io packages to v4.4.1 ([#1528](https://github.com/midwayjs/midway/issues/1528)) ([14b27ea](https://github.com/midwayjs/midway/commit/14b27eaa0eeb479a80d171ede3af3ebda689ec46)) * serverless app run ([#1523](https://github.com/midwayjs/midway/issues/1523)) ([5a25eb7](https://github.com/midwayjs/midway/commit/5a25eb7ebb17bf9b0e2ba4feee5bc1649f70d56f)) ### Features[​](#features-3 "Features的直接链接") * add data listener ([#1525](https://github.com/midwayjs/midway/issues/1525)) ([0bd0db8](https://github.com/midwayjs/midway/commit/0bd0db8c7f3338c754ae852619bbbb4f2336cc16)) * add info middleware ([#1530](https://github.com/midwayjs/midway/issues/1530)) ([7077f1d](https://github.com/midwayjs/midway/commit/7077f1d84355633a1c2fced35bfcc2152f42a7ac)) * add secret filter ([#1531](https://github.com/midwayjs/midway/issues/1531)) ([ce77e48](https://github.com/midwayjs/midway/commit/ce77e4804aaffc18a0a091d3726e36d7ec1514b2)) * compatible with @File/@Files/@Fields ([#1527](https://github.com/midwayjs/midway/issues/1527)) ([3fe983f](https://github.com/midwayjs/midway/commit/3fe983f2a67c366af370c41df98510adf5dab289)) * cross domain component ([#1493](https://github.com/midwayjs/midway/issues/1493)) ([ca81b2f](https://github.com/midwayjs/midway/commit/ca81b2fa2824fbddc7870a971fa23274c86d05df)) * support hooks 3 ([#1524](https://github.com/midwayjs/midway/issues/1524)) ([1cf446d](https://github.com/midwayjs/midway/commit/1cf446d99ac8bff252820beb7cf7dd036215a864)) # [3.0.0-beta.14](https://github.com/midwayjs/midway/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2022-01-04) ### Bug Fixes[​](#bug-fixes-4 "Bug Fixes的直接链接") * cos config definition & 3.x doc update ([#1515](https://github.com/midwayjs/midway/issues/1515)) ([0ac7ac5](https://github.com/midwayjs/midway/commit/0ac7ac5805b7ab8873f8792fc1712a74e3223172)) * **deps:** update dependency @grpc/proto-loader to ^0.6.0 ([#1505](https://github.com/midwayjs/midway/issues/1505)) ([67eaee7](https://github.com/midwayjs/midway/commit/67eaee791878908ccad8a1fdaac39ac6786e889e)) * **deps:** update dependency axios to ^0.24.0 ([#1506](https://github.com/midwayjs/midway/issues/1506)) ([d2a7dab](https://github.com/midwayjs/midway/commit/d2a7dab55e6f96528e6087ae503f6328013088fb)) * **deps:** update dependency bull to v4 ([#1511](https://github.com/midwayjs/midway/issues/1511)) ([9100d21](https://github.com/midwayjs/midway/commit/9100d21d0cd29ff948981f1c5616dd996929f6e3)) * **deps:** update dependency cookie-session to v2 ([#1483](https://github.com/midwayjs/midway/issues/1483)) ([ef1c1d1](https://github.com/midwayjs/midway/commit/ef1c1d1b8fd7dd297761e7ed3666c6bc0d496fc2)) * **deps:** update dependency http-errors to v2 ([#1512](https://github.com/midwayjs/midway/issues/1512)) ([f3580e1](https://github.com/midwayjs/midway/commit/f3580e14c55cb3ddbc09c75694c2adc45765d7ad)) * **deps:** update dependency prom-client to v14 ([#1486](https://github.com/midwayjs/midway/issues/1486)) ([87b6678](https://github.com/midwayjs/midway/commit/87b6678b179e239f8dbe5d0adb935df2c713d94b)) * **deps:** update dependency sequelize to \~6.12.0 ([#1509](https://github.com/midwayjs/midway/issues/1509)) ([6f96bf7](https://github.com/midwayjs/midway/commit/6f96bf745761c849c94a8977436dc2955f3d9a3c)) * **deps:** update dependency statuses to v2 ([#1487](https://github.com/midwayjs/midway/issues/1487)) ([5f99204](https://github.com/midwayjs/midway/commit/5f99204f7ca28fbf9c8048bcbba0d9d1eb49d2aa)) * **deps:** update dependency ws to v8 ([#1488](https://github.com/midwayjs/midway/issues/1488)) ([7e71bb4](https://github.com/midwayjs/midway/commit/7e71bb4eeb731d3bf91f0caf06bc9d9acb6297ca)) * upload support auto clean and whitelist ([#1484](https://github.com/midwayjs/midway/issues/1484)) ([7daa037](https://github.com/midwayjs/midway/commit/7daa0371f4a3e79cd4789959d8427fc5b6c91d08)) # [3.0.0-beta.13](https://github.com/midwayjs/midway/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-12-30) ### Features[​](#features-4 "Features的直接链接") * 404 error ([#1465](https://github.com/midwayjs/midway/issues/1465)) ([e7e8a9d](https://github.com/midwayjs/midway/commit/e7e8a9dedfa7198ac05b161b41024c2871f93965)) * add custom decorator filter ([#1477](https://github.com/midwayjs/midway/issues/1477)) ([97501a9](https://github.com/midwayjs/midway/commit/97501a989abc211b0c7400b1df45e050bb237c6a)) # [3.0.0-beta.12](https://github.com/midwayjs/midway/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2021-12-28) ### Bug Fixes[​](#bug-fixes-5 "Bug Fixes的直接链接") * 3.x copy all properties ([#1444](https://github.com/midwayjs/midway/issues/1444)) ([21ec8b6](https://github.com/midwayjs/midway/commit/21ec8b6a85b6ba3f4fbff0c8a571484aaa078788)) ### Features[​](#features-5 "Features的直接链接") * add fileupload support ([#1439](https://github.com/midwayjs/midway/issues/1439)) ([0a81e72](https://github.com/midwayjs/midway/commit/0a81e720f525ddab0718301f44f80fce376f9bfe)) * custom error code & add @Files/@Fields ([#1438](https://github.com/midwayjs/midway/issues/1438)) ([b0032af](https://github.com/midwayjs/midway/commit/b0032afd2fa9ea0416fe69f4bd0c1a58bea5314e)) * support throw err status ([#1440](https://github.com/midwayjs/midway/issues/1440)) ([7b98110](https://github.com/midwayjs/midway/commit/7b98110d65c5287a8fcb3eb5356dea2d7a32cee9)) # [3.0.0-beta.11](https://github.com/midwayjs/midway/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2021-12-21) **Note:** Version bump only for package midway\_project # [3.0.0-beta.10](https://github.com/midwayjs/midway/compare/v3.0.0-beta.9...v3.0.0-beta.10) (2021-12-20) ### Features[​](#features-6 "Features的直接链接") * 3.x swagger ([#1409](https://github.com/midwayjs/midway/issues/1409)) ([e00fbbf](https://github.com/midwayjs/midway/commit/e00fbbf7a494f300a53f3bd8635966364cfd96a9)) * 3.x upload ([#1422](https://github.com/midwayjs/midway/issues/1422)) ([cbd8e33](https://github.com/midwayjs/midway/commit/cbd8e334a918222f526552859401f0cf222737b6)) * add swagger doc & fix bug ([#1427](https://github.com/midwayjs/midway/issues/1427)) ([82dc6f1](https://github.com/midwayjs/midway/commit/82dc6f10f7244a75f58922edda1b0625fc6cb90e)) * default add session & bodyparser support for koa/express/faas ([#1420](https://github.com/midwayjs/midway/issues/1420)) ([cdaff31](https://github.com/midwayjs/midway/commit/cdaff317c3e862a95494a167995a28280af639bf)) * implement i18n for validate ([#1426](https://github.com/midwayjs/midway/issues/1426)) ([4c7ed2f](https://github.com/midwayjs/midway/commit/4c7ed2ff2e7ccf10f88f62abad230f92f5e76b97)) * support express ([61e73db](https://github.com/midwayjs/midway/commit/61e73db509bfea21c8251855fccb02a4ce09988f)) # [3.0.0-beta.9](https://github.com/midwayjs/midway/compare/v3.0.0-beta.8...v3.0.0-beta.9) (2021-12-09) ### Bug Fixes[​](#bug-fixes-6 "Bug Fixes的直接链接") * faas missing config in framework ([#1413](https://github.com/midwayjs/midway/issues/1413)) ([7ab16a2](https://github.com/midwayjs/midway/commit/7ab16a24b29d5254a762bfffcdf18385effdf639)) # [3.0.0-beta.8](https://github.com/midwayjs/midway/compare/v3.0.0-beta.7...v3.0.0-beta.8) (2021-12-08) ### Bug Fixes[​](#bug-fixes-7 "Bug Fixes的直接链接") * express routing middleware takes effect at the controller level ([#1364](https://github.com/midwayjs/midway/issues/1364)) ([b9272e0](https://github.com/midwayjs/midway/commit/b9272e0971003443304b0c53815be31a0061b4bd)) * mongoose remote config bug ([#1399](https://github.com/midwayjs/midway/issues/1399)) ([e37602d](https://github.com/midwayjs/midway/commit/e37602d54ae503aeee48afa320709aae3d18b329)) * passport missing proxy file ([#1405](https://github.com/midwayjs/midway/issues/1405)) ([5c9bdae](https://github.com/midwayjs/midway/commit/5c9bdae8323b41ead72c3d3f867aa11150bb3e78)) * typeorm EntityView missing connectionName ([#1403](https://github.com/midwayjs/midway/issues/1403)) ([30b2b37](https://github.com/midwayjs/midway/commit/30b2b3711db485cb85d825d56aeabf53b1374cae)) ### Features[​](#features-7 "Features的直接链接") * passport add presetProperty ([#1358](https://github.com/midwayjs/midway/issues/1358)) ([4db8eda](https://github.com/midwayjs/midway/commit/4db8eda592c0486898edabcacbc9a69eb2d87004)) * support passport and jwt ([#1343](https://github.com/midwayjs/midway/issues/1343)) ([f26af4f](https://github.com/midwayjs/midway/commit/f26af4f3e16507d6f3ffe0467f8f5be69e6306d7)) # [3.0.0-beta.7](https://github.com/midwayjs/midway/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-12-03) ### Bug Fixes[​](#bug-fixes-8 "Bug Fixes的直接链接") * add app.keys ([#1395](https://github.com/midwayjs/midway/issues/1395)) ([c44afc6](https://github.com/midwayjs/midway/commit/c44afc6cc6764a959d1fa7ae04d60099282d156a)) * middleware with ctx.body ([#1389](https://github.com/midwayjs/midway/issues/1389)) ([77af5c0](https://github.com/midwayjs/midway/commit/77af5c0b456f1843f4dcfd3dbfd2c0aa244c51bd)) * validate typing and config ([#1388](https://github.com/midwayjs/midway/issues/1388)) ([0883569](https://github.com/midwayjs/midway/commit/08835691942183e972359cbaa076db06b6bf85ef)) # [3.0.0-beta.6](https://github.com/midwayjs/midway/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2021-11-26) ### Bug Fixes[​](#bug-fixes-9 "Bug Fixes的直接链接") * class transformer method missing ([#1387](https://github.com/midwayjs/midway/issues/1387)) ([074e839](https://github.com/midwayjs/midway/commit/074e8393598dc95e2742f735df75a2191c5fe25d)) # [3.0.0-beta.5](https://github.com/midwayjs/midway/compare/v3.0.0-beta.4...v3.0.0-beta.5) (2021-11-25) ### Bug Fixes[​](#bug-fixes-10 "Bug Fixes的直接链接") * [@match](https://github.com/match) empty args ([#1384](https://github.com/midwayjs/midway/issues/1384)) ([6f90fc9](https://github.com/midwayjs/midway/commit/6f90fc993ff01e078288ff664833c61c02dede51)) * router sort ([#1383](https://github.com/midwayjs/midway/issues/1383)) ([f253887](https://github.com/midwayjs/midway/commit/f2538876d3eaf7dec55173d86b5b9caeeeb7be64)) # [3.0.0-beta.4](https://github.com/midwayjs/midway/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-11-24) ### Bug Fixes[​](#bug-fixes-11 "Bug Fixes的直接链接") * logger close before bootstrap close ([#1370](https://github.com/midwayjs/midway/issues/1370)) ([6cc2720](https://github.com/midwayjs/midway/commit/6cc2720ed3445e8ffccc96d124b80ed7e2517f08)) ### Features[​](#features-8 "Features的直接链接") * add i18n ([#1375](https://github.com/midwayjs/midway/issues/1375)) ([bffefe0](https://github.com/midwayjs/midway/commit/bffefe07afe45777d49b5a76b9ab17fc2b9d9a55)) * auto transform args to type ([#1372](https://github.com/midwayjs/midway/issues/1372)) ([bb3f7d2](https://github.com/midwayjs/midway/commit/bb3f7d2028a034e1926d9df554849332354c3762)) * support global prefix url ([#1371](https://github.com/midwayjs/midway/issues/1371)) ([cc5fe44](https://github.com/midwayjs/midway/commit/cc5fe44e1d221590562dc71e1f33ae96093e0da7)) # [3.0.0-beta.3](https://github.com/midwayjs/midway/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-11-18) ### Features[​](#features-9 "Features的直接链接") * add component and framework config definition ([#1367](https://github.com/midwayjs/midway/issues/1367)) ([b2fe615](https://github.com/midwayjs/midway/commit/b2fe6157f99659471ff1333eca0b86bb889f61a3)) # [3.0.0-beta.2](https://github.com/midwayjs/midway/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-11-16) ### Bug Fixes[​](#bug-fixes-12 "Bug Fixes的直接链接") * middleware decorator missing ([#1366](https://github.com/midwayjs/midway/issues/1366)) ([5f9a8c1](https://github.com/midwayjs/midway/commit/5f9a8c1f7cdd940f785f6c9871fb67b9738de940)) # [3.0.0-beta.1](https://github.com/midwayjs/midway/compare/v2.12.4...v3.0.0-beta.1) (2021-11-14) ### Bug Fixes[​](#bug-fixes-13 "Bug Fixes的直接链接") * add log for 'Internal Server Error' ([#1282](https://github.com/midwayjs/midway/issues/1282)) ([f333466](https://github.com/midwayjs/midway/commit/f333466d138a319b417964cdb9cb065f2b955722)) * ci、build and type error with rabbitmq ([#1253](https://github.com/midwayjs/midway/issues/1253)) ([80ae991](https://github.com/midwayjs/midway/commit/80ae9919e1c21c9e326b5f186f891d14d43495a5)) * circular inject for provide uuid ([#1285](https://github.com/midwayjs/midway/issues/1285)) ([34533bf](https://github.com/midwayjs/midway/commit/34533bfe9bf1c4acdffb1360ab24c716b5196de8)) * component env filter ([#1234](https://github.com/midwayjs/midway/issues/1234)) ([1ad365f](https://github.com/midwayjs/midway/commit/1ad365fd8ef5e0e7dae3d08a2427a2300038290a)) * correct aspect chain bug ([#1204](https://github.com/midwayjs/midway/issues/1204)) ([5de5284](https://github.com/midwayjs/midway/commit/5de5284c70b44acc73eaaad651fd2edc72d54f28)) * disable performance marking for invoke handlers ([#1299](https://github.com/midwayjs/midway/issues/1299)) ([2de9221](https://github.com/midwayjs/midway/commit/2de92214542b8df3abb57b618befde5e161de79e)) * empty options in default ([#1241](https://github.com/midwayjs/midway/issues/1241)) ([802109d](https://github.com/midwayjs/midway/commit/802109ddd098afb04d6d540bff509e0aee85b806)) * encode request path in serverless ([#1230](https://github.com/midwayjs/midway/issues/1230)) ([c826e68](https://github.com/midwayjs/midway/commit/c826e6899c884af9f3365ab77b95449a68889afe)) * find egg plugin in cwd ([#1236](https://github.com/midwayjs/midway/issues/1236)) ([d9ac0ff](https://github.com/midwayjs/midway/commit/d9ac0ff6d4e7a58a8924636806d3894acf94fcd8)) * form-data for egg-layer ([#1097](https://github.com/midwayjs/midway/issues/1097)) ([66057e8](https://github.com/midwayjs/midway/commit/66057e8910c00db0ae2b2ea801cdd94aa063fe84)) * functional configuration load async code ([#1300](https://github.com/midwayjs/midway/issues/1300)) ([32bcf03](https://github.com/midwayjs/midway/commit/32bcf030ed1ab04482dc557f8b0c6904e47b31e1)) * getCustomRepository bug ([#1309](https://github.com/midwayjs/midway/issues/1309)) ([04487a8](https://github.com/midwayjs/midway/commit/04487a8029ac42ed8001ed11a13eb29b846460d8)) * load component with enabledEnvironment ([#1329](https://github.com/midwayjs/midway/issues/1329)) ([3182271](https://github.com/midwayjs/midway/commit/3182271a1eab931e2bf872bff6e2725ebb906ad0)) * node v16 typings ([#1269](https://github.com/midwayjs/midway/issues/1269)) ([e3443b5](https://github.com/midwayjs/midway/commit/e3443b58fc1faddadf1e95dd03a2f319410941bb)) * remove connection key ([#1337](https://github.com/midwayjs/midway/issues/1337)) ([6ac219e](https://github.com/midwayjs/midway/commit/6ac219e786792b32d19a364bffbe9e6318c2f9e1)) * serverless app support applicationContext ([#1281](https://github.com/midwayjs/midway/issues/1281)) ([b692001](https://github.com/midwayjs/midway/commit/b692001c451b17a10d26cb6778a8566d5fa569c5)) * serverless local dev bodyparser limit ([#1245](https://github.com/midwayjs/midway/issues/1245)) ([6bdf378](https://github.com/midwayjs/midway/commit/6bdf37841260b1f77e20d913ee85a45ae41ca559)) * static prefix ([#1321](https://github.com/midwayjs/midway/issues/1321)) ([31fe961](https://github.com/midwayjs/midway/commit/31fe961931fed7656a144b1682ee4c4bb25fdff5)) * winston rotate log size limit in cluster mode ([#1268](https://github.com/midwayjs/midway/issues/1268)) ([09f9d81](https://github.com/midwayjs/midway/commit/09f9d81ac80f660907c5d8a97c897e375bde8ecc)) ### Features[​](#features-10 "Features的直接链接") * add a process agent component ([#1278](https://github.com/midwayjs/midway/issues/1278)) ([e630fb1](https://github.com/midwayjs/midway/commit/e630fb143ba14eed64436612e9a86afc0d46b42d)) * add cos component ([#1271](https://github.com/midwayjs/midway/issues/1271)) ([c18e597](https://github.com/midwayjs/midway/commit/c18e597d55a6452188cc7daecd0062bf161028cc)) * add ctx.throw for serverless app ([#1262](https://github.com/midwayjs/midway/issues/1262)) ([70008b3](https://github.com/midwayjs/midway/commit/70008b32157286708ec01390b0bf8233ba5a84dd)) * add http2 support ([#1242](https://github.com/midwayjs/midway/issues/1242)) ([6cda27e](https://github.com/midwayjs/midway/commit/6cda27e9e22689e46ace543326b43ae21b134911)) * add mongoose component and support multi-instance for typegoose ([#1334](https://github.com/midwayjs/midway/issues/1334)) ([ca0b73f](https://github.com/midwayjs/midway/commit/ca0b73fec77e8871e4001b4c9d3e45397ce32450)) * add prometheus-socket-io ([#1275](https://github.com/midwayjs/midway/issues/1275)) ([55e2b53](https://github.com/midwayjs/midway/commit/55e2b53e83f9b6756df0ffac2e2d7d791aa2154f)) * add redis component ([#1270](https://github.com/midwayjs/midway/issues/1270)) ([09c993a](https://github.com/midwayjs/midway/commit/09c993ac308d26fa9c742a659471c3f4cf5c5782)) * add sequelize component ([#1283](https://github.com/midwayjs/midway/issues/1283)) ([9ad91d1](https://github.com/midwayjs/midway/commit/9ad91d1e3ef3cf4cd799a1f8ef3d57b7efae60cf)) * add setDiff ([#1263](https://github.com/midwayjs/midway/issues/1263)) ([9dd1a08](https://github.com/midwayjs/midway/commit/9dd1a08326540da52abf79cf31182d4e63b7f4d9)) * add tablestore component and typescript definition ([#1302](https://github.com/midwayjs/midway/issues/1302)) ([aaa4877](https://github.com/midwayjs/midway/commit/aaa4877dc2e6a148346e130dcc6f5401c470eb4c)) * add view, view-ejs and view-nunjucks ([#1308](https://github.com/midwayjs/midway/issues/1308)) ([a00f44b](https://github.com/midwayjs/midway/commit/a00f44bd769052245cd49d49ab417d621bb89caa)) * merge DTO Helper for [#1250](https://github.com/midwayjs/midway/issues/1250) ([#1288](https://github.com/midwayjs/midway/issues/1288)) ([3f8f937](https://github.com/midwayjs/midway/commit/3f8f93765a66f49940565231d50405a7dbd593c7)) * queue support concurrency config ([#1231](https://github.com/midwayjs/midway/issues/1231)) ([67bb7f5](https://github.com/midwayjs/midway/commit/67bb7f50b3dcf80439d1b4b4b9c06f930a8b4468)) * serverless-worker-starter ([#1171](https://github.com/midwayjs/midway/issues/1171)) ([081a3ec](https://github.com/midwayjs/midway/commit/081a3ec360af4f0d771bd4cc5a39b185c87c0307)) --- # v3.0.1 2022年1月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * [#1610](https://github.com/midwayjs/midway/issues/1610) use origin args when parameter decorator throw error ([#1613](https://github.com/midwayjs/midway/issues/1613)) ([797ece6](https://github.com/midwayjs/midway/commit/797ece6364b1b512d64aeb82f51ddcb97ef42c0f)) * add missing maxAge ([#1612](https://github.com/midwayjs/midway/issues/1612)) ([5f21909](https://github.com/midwayjs/midway/commit/5f21909104db650e96f1e3445bbbfceadf536c06)) * config key required ([#1615](https://github.com/midwayjs/midway/issues/1615)) ([fb2188e](https://github.com/midwayjs/midway/commit/fb2188eaf5c24ffc9972f73323773a5899825037)) * **deps:** update dependency ws to v8.4.2 ([#1570](https://github.com/midwayjs/midway/issues/1570)) ([932b034](https://github.com/midwayjs/midway/commit/932b034d6fa98dc149ab876df05d081b855ce2bb)) * **serverless-app:** fix findNpmModule in pnp ([#1605](https://github.com/midwayjs/midway/issues/1605)) ([37f46e0](https://github.com/midwayjs/midway/commit/37f46e08811ae43d983e2076a33d16f5f57c795c)) * tablestore ref ([#1616](https://github.com/midwayjs/midway/issues/1616)) ([6b31f4f](https://github.com/midwayjs/midway/commit/6b31f4f00042bed3fb7575b1fff53161e31da243)) ### Reverts[​](#reverts "Reverts的直接链接") * Revert "chore: update ci yml to sync api" ([1ab4994](https://github.com/midwayjs/midway/commit/1ab4994688b55253414f6b8b1478e050ec5940b1)) --- # v3.0.10 2022年2月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency raw-body to v2.5.0 ([#1731](https://github.com/midwayjs/midway/issues/1731)) ([6caec96](https://github.com/midwayjs/midway/commit/6caec96b976b9dce1a8cda4d3f809efd346ceaf5)) * missing express cookie parser typings ([#1735](https://github.com/midwayjs/midway/issues/1735)) ([965e850](https://github.com/midwayjs/midway/commit/965e850e004f39870e8d371be573ecfc754e4627)) * remove configuration resolve handler and add detectorOptions ([#1740](https://github.com/midwayjs/midway/issues/1740)) ([7af24e8](https://github.com/midwayjs/midway/commit/7af24e8cc55f0ba798b4d774084ace4069a8a54c)) --- # v3.0.11 2022年2月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency tablestore to v5.1.1 ([#1743](https://github.com/midwayjs/midway/issues/1743)) ([5087e7d](https://github.com/midwayjs/midway/commit/5087e7d58bf70f903aed7f0b384e70551bffd8d7)) * none level ([#1744](https://github.com/midwayjs/midway/issues/1744)) ([dccb726](https://github.com/midwayjs/midway/commit/dccb7260ad98f9e702392deea6984a65b9bef985)) --- # v3.0.12 2022年2月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * remove winston logger compatibility code ([#1749](https://github.com/midwayjs/midway/issues/1749)) ([3b4c67c](https://github.com/midwayjs/midway/commit/3b4c67cc11ead3923ba060aa9369406fbb16c187)) --- # v3.0.13 2022年3月1日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency raw-body to v2.5.1 ([#1754](https://github.com/midwayjs/midway/issues/1754)) ([6d9d819](https://github.com/midwayjs/midway/commit/6d9d819a3628ac8ecf91e75120a73f0533ba4bc9)) * **deps:** update dependency sequelize to \~6.17.0 ([#1750](https://github.com/midwayjs/midway/issues/1750)) ([5176df9](https://github.com/midwayjs/midway/commit/5176df979528fd41e648771847c32236f19e2baf)) * rabbitmq config key ([#1758](https://github.com/midwayjs/midway/issues/1758)) ([b667011](https://github.com/midwayjs/midway/commit/b667011df4c2604a8eaccc40bce7ae75e0330514)) --- # v3.0.2 2022年1月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * i18n cookie set ([#1621](https://github.com/midwayjs/midway/issues/1621)) ([582dd97](https://github.com/midwayjs/midway/commit/582dd97d35b91837481e7fca558f68f123210027)) * singleton invoke request scope not valid ([#1622](https://github.com/midwayjs/midway/issues/1622)) ([f97c063](https://github.com/midwayjs/midway/commit/f97c0632107b47cf357d17774a4e4bb5233bba57)) --- # v3.0.3 2022年1月28日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * crc error in ncc bundle ([#1636](https://github.com/midwayjs/midway/issues/1636)) ([8f1dc91](https://github.com/midwayjs/midway/commit/8f1dc918e914bc30024181466b42f383d98369f2)) * **deps:** update dependency sequelize to \~6.14.0 ([#1617](https://github.com/midwayjs/midway/issues/1617)) ([f29fc0f](https://github.com/midwayjs/midway/commit/f29fc0fb166cafa09e8cfd7e801417ea7731d437)) --- # v3.0.4 2022年2月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * createFunctionApp ([#1628](https://github.com/midwayjs/midway/issues/1628)) ([8d6f6e8](https://github.com/midwayjs/midway/commit/8d6f6e89786ece993dc3c71cb5cd2e1da69b2732)) * **deps:** update dependency amqp-connection-manager to v4.1.0 ([#1653](https://github.com/midwayjs/midway/issues/1653)) ([9221a49](https://github.com/midwayjs/midway/commit/9221a49f086956d8fd5f8e232a8ea8cbd4cee4b9)) * **deps:** update dependency amqp-connection-manager to v4.1.1 ([#1663](https://github.com/midwayjs/midway/issues/1663)) ([8508913](https://github.com/midwayjs/midway/commit/85089131cdace9e47ec2c46e6d99be9b3c327ecf)) * **deps:** update dependency sequelize to \~6.15.0 ([#1644](https://github.com/midwayjs/midway/issues/1644)) ([eb241f2](https://github.com/midwayjs/midway/commit/eb241f2a3f7aea5c70d28ae1dca265ddf2a78b5a)) * **deps:** update dependency sequelize to \~6.16.0 ([#1677](https://github.com/midwayjs/midway/issues/1677)) ([bf84760](https://github.com/midwayjs/midway/commit/bf8476078801eb34551df242b56345cd2621c6ff)) * **deps:** update dependency ws to v8.5.0 ([#1668](https://github.com/midwayjs/midway/issues/1668)) ([5326c43](https://github.com/midwayjs/midway/commit/5326c43ebf0641a745be1e772c2a5a527dfcb688)) * run in egg cluster mode ([#1645](https://github.com/midwayjs/midway/issues/1645)) ([d6146cc](https://github.com/midwayjs/midway/commit/d6146cccb4ffa9158d87c1f64199bce9f408b43c)) * supertest typings and createFunctionApp ([#1642](https://github.com/midwayjs/midway/issues/1642)) ([484f4f4](https://github.com/midwayjs/midway/commit/484f4f41b3b9e889d4d285f4871a0b37fa51e73f)) * swagger not support more than one @Body ([#1662](https://github.com/midwayjs/midway/issues/1662)) ([a13ec48](https://github.com/midwayjs/midway/commit/a13ec48fa4b3f97f013dc73be409631b4ce2e24e)) * swagger support globalprefix ([#1670](https://github.com/midwayjs/midway/issues/1670)) ([75e83f9](https://github.com/midwayjs/midway/commit/75e83f9fbedb7acbcc20ffac15cb4afaf4513957)) * task typings ([#1678](https://github.com/midwayjs/midway/issues/1678)) ([02aeef6](https://github.com/midwayjs/midway/commit/02aeef69a472709fba97e8250757b6136f859a84)) ### Features[​](#features "Features的直接链接") * move context format to user config ([#1673](https://github.com/midwayjs/midway/issues/1673)) ([db53b8e](https://github.com/midwayjs/midway/commit/db53b8eaf22b50df61945ff11086e1eb7aec99a1)) --- # v3.0.5 2022年2月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * mock options ([#1681](https://github.com/midwayjs/midway/issues/1681)) ([9680929](https://github.com/midwayjs/midway/commit/9680929b9b4e4e991970879c4925b513969453d2)) * swagger query/param bug ([#1682](https://github.com/midwayjs/midway/issues/1682)) ([c05df75](https://github.com/midwayjs/midway/commit/c05df757bc8fd15d893d0dcf7455fc1b6a12d171)) --- # v3.0.6 2022年2月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * [#1692](https://github.com/midwayjs/midway/issues/1692) ([#1696](https://github.com/midwayjs/midway/issues/1696)) ([a3ac74a](https://github.com/midwayjs/midway/commit/a3ac74ab1152e8762ab6ae7d6bfa513255de4a56)) * add missing dep ([#1684](https://github.com/midwayjs/midway/issues/1684)) ([fbd02e2](https://github.com/midwayjs/midway/commit/fbd02e2097ba0bbd774c012ebad647608b588e28)) * missing import component will be throw error ([#1694](https://github.com/midwayjs/midway/issues/1694)) ([c17f049](https://github.com/midwayjs/midway/commit/c17f049ef698ba55509e4ef5ea915668345dc50f)) * not found after no router set. ([#1698](https://github.com/midwayjs/midway/issues/1698)) ([c7f466f](https://github.com/midwayjs/midway/commit/c7f466f118008bf001c17f1145deba5fbf2a7827)) * queue service scope ([#1699](https://github.com/midwayjs/midway/issues/1699)) ([d2e46e5](https://github.com/midwayjs/midway/commit/d2e46e5d4ef8af8016a4153bf132fed32770f06f)) * **web:** check type of variable this.app.middleware ([#1688](https://github.com/midwayjs/midway/issues/1688)) ([f69fb5a](https://github.com/midwayjs/midway/commit/f69fb5a59dac41d4457a48a591dc15df8dce36e0)) --- # v3.0.7 2022年2月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * benchmark ([#1719](https://github.com/midwayjs/midway/issues/1719)) ([088e306](https://github.com/midwayjs/midway/commit/088e3066962b5ad9c5ecae3ba602a3ca5b215f5d)) * **deps:** update dependency body-parser to v1.19.2 ([#1708](https://github.com/midwayjs/midway/issues/1708)) ([01626e8](https://github.com/midwayjs/midway/commit/01626e882710108cc9bede8c6f2adcfd142f72f0)) * **deps:** update dependency express to v4.17.3 ([#1713](https://github.com/midwayjs/midway/issues/1713)) ([c781eca](https://github.com/midwayjs/midway/commit/c781eca27586b1d07cf672e71776ad9a521e149f)) * **deps:** update dependency nanoid to v3.3.1 ([#1704](https://github.com/midwayjs/midway/issues/1704)) ([7e31d41](https://github.com/midwayjs/midway/commit/7e31d41d9d66a3667b21c5c6aa7fedc675ed38aa)) * **deps:** update dependency raw-body to v2.4.3 ([#1705](https://github.com/midwayjs/midway/issues/1705)) ([d4a6b8c](https://github.com/midwayjs/midway/commit/d4a6b8c0a17d5187ac21afd72e8dbf86424fb14f)) * export asyncWrapper from runtime-engine ([#1717](https://github.com/midwayjs/midway/issues/1717)) ([f40d0b9](https://github.com/midwayjs/midway/commit/f40d0b9bbd05025f0472ae0a0e62fd9accb84937)) * passport middleware definition ([#1701](https://github.com/midwayjs/midway/issues/1701)) ([bca3860](https://github.com/midwayjs/midway/commit/bca38603437f7645603feba3cd47ad9b696f8db7)) --- # v3.0.8 2022年2月19日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * cookies definition in koa ([#1720](https://github.com/midwayjs/midway/issues/1720)) ([91adc35](https://github.com/midwayjs/midway/commit/91adc35f1dbcc1b362419b501ffa86be2f1050bc)) * update koa ctx.app definition ([#1721](https://github.com/midwayjs/midway/issues/1721)) ([2b3aced](https://github.com/midwayjs/midway/commit/2b3aced49bb3ca6dfc7652f4df668f6fa171238b)) --- # v3.0.9 2022年2月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg missing setAttr and getAttr ([#1730](https://github.com/midwayjs/midway/issues/1730)) ([7c6de3f](https://github.com/midwayjs/midway/commit/7c6de3ffa437e23f717efa0065ba60e482b3d225)) * missing getLocalTask method ([#1728](https://github.com/midwayjs/midway/issues/1728)) ([1c916e9](https://github.com/midwayjs/midway/commit/1c916e9f6bb8de6ea8b64f45f8043ca315396d62)) * redis on method missing ([#1729](https://github.com/midwayjs/midway/issues/1729)) ([61fde02](https://github.com/midwayjs/midway/commit/61fde024324b9774d51dd9ebd805883207f783b5)) --- # v3.1.0 2022年3月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * egg logger create context logger case ([#1760](https://github.com/midwayjs/midway/issues/1760)) ([f9bebf1](https://github.com/midwayjs/midway/commit/f9bebf18cffbced4bd596d1ab39b585ea4d6a229)) * express use router and middleware ([#1777](https://github.com/midwayjs/midway/issues/1777)) ([21a69bb](https://github.com/midwayjs/midway/commit/21a69bbfc5535aaafcb3751f4c0c54ffcf109e9d)) * koa default onerrror now returns json correctly ([#1779](https://github.com/midwayjs/midway/issues/1779)) ([0b2be53](https://github.com/midwayjs/midway/commit/0b2be5329e11b3ea30fb6b748b23ed310b620394)) * not transform when RouteParam got undefined ([#1762](https://github.com/midwayjs/midway/issues/1762)) ([d714e31](https://github.com/midwayjs/midway/commit/d714e317aec771c8971bf6093c767eba9bccc976)) * nunjucks local cache ([#1774](https://github.com/midwayjs/midway/issues/1774)) ([413ec44](https://github.com/midwayjs/midway/commit/413ec44ea309077ce482fe55db3819aaab45894a)) * use hook to load egg application ([#1782](https://github.com/midwayjs/midway/issues/1782)) ([b47f27b](https://github.com/midwayjs/midway/commit/b47f27bf441431ddb1d0d35d5ee0ae80ae56fce8)) ### Features[​](#features "Features的直接链接") * starter for node.js and serverless-worker environment ([#1768](https://github.com/midwayjs/midway/issues/1768)) ([0c48b73](https://github.com/midwayjs/midway/commit/0c48b739e54be4e18aeff4c989fd3b96e955805c)) * support event for worker starter ([#1788](https://github.com/midwayjs/midway/issues/1788)) ([2d97dc7](https://github.com/midwayjs/midway/commit/2d97dc7908b0a76245d8a8e3089b9756fb579394)) --- # v3.1.1 2022年3月9日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * default error dir and loadMidwayController ([#1791](https://github.com/midwayjs/midway/issues/1791)) ([4fd6b64](https://github.com/midwayjs/midway/commit/4fd6b643d683b85335f4bd314a9574ef8501a3f6)) * preload module position ([#1794](https://github.com/midwayjs/midway/issues/1794)) ([1456a83](https://github.com/midwayjs/midway/commit/1456a83fd2bd2afc1b3d92b4d1315ad6af7650df)) --- # v3.1.2 2022年3月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add a inject for [@inject](https://github.com/inject) logger in singleton scope ([#1816](https://github.com/midwayjs/midway/issues/1816)) ([4e9cf96](https://github.com/midwayjs/midway/commit/4e9cf96793acff829a2a8ca6598081cc331d6d25)) * agent load config ([#1815](https://github.com/midwayjs/midway/issues/1815)) ([95a6505](https://github.com/midwayjs/midway/commit/95a650544b921d6285c1beb97c7df7a0917ea4fb)) * consule config definition ([#1804](https://github.com/midwayjs/midway/issues/1804)) ([2a0d57c](https://github.com/midwayjs/midway/commit/2a0d57c183f3fad22fe878f538a26182291b7b44)) * remove swagger validator url ([#1813](https://github.com/midwayjs/midway/issues/1813)) ([ded291a](https://github.com/midwayjs/midway/commit/ded291a308f81961f9f3c2a9c21b5862d7d73ca6)) * worker starter origin context ([#1814](https://github.com/midwayjs/midway/issues/1814)) ([0168bcc](https://github.com/midwayjs/midway/commit/0168bcceef0f7cf39a8f0d903c24496f5f4f056f)) ### Features[​](#features "Features的直接链接") * add otel component ([#1808](https://github.com/midwayjs/midway/issues/1808)) ([8fda71e](https://github.com/midwayjs/midway/commit/8fda71e82cedfcf05e590780c55fbff10c4132cb)) * security helper ([#1795](https://github.com/midwayjs/midway/issues/1795)) ([cc8a148](https://github.com/midwayjs/midway/commit/cc8a148bf7a2ea1351d3912084de2ad755c465e7)) --- # v3.1.3 2022年3月15日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add midway method to agent ([#1819](https://github.com/midwayjs/midway/issues/1819)) ([e9fa48b](https://github.com/midwayjs/midway/commit/e9fa48bf4d5347dc38f9190228820c8169270f89)) * EggAppConfig with PowerPartial ([#1818](https://github.com/midwayjs/midway/issues/1818)) ([6e2d1dd](https://github.com/midwayjs/midway/commit/6e2d1ddbbf67e7d77d6e316c76b535d5cbedabec)) --- # v3.1.4 2022年3月16日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * invoke method after agent overwrite method ([#1822](https://github.com/midwayjs/midway/issues/1822)) ([63f53cc](https://github.com/midwayjs/midway/commit/63f53cce66e4c8172b11e006ab3ab1a2e8491bdc)) --- # v3.1.5 2022年3月18日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency @midwayjs/cookies to v1.0.2 ([#1834](https://github.com/midwayjs/midway/issues/1834)) ([e99a5fa](https://github.com/midwayjs/midway/commit/e99a5fad0b9e0a7021d3b0158eafe7809e90b652)) * missing appDir value with egg-scripts cluster mode ([#1828](https://github.com/midwayjs/midway/issues/1828)) ([dc333ef](https://github.com/midwayjs/midway/commit/dc333ef4928d34c2c4ca061ce9331e676467c52e)) --- # v3.1.6 2022年3月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * otel test ([#1837](https://github.com/midwayjs/midway/issues/1837)) ([36fa998](https://github.com/midwayjs/midway/commit/36fa998c077551e3ce9e0f0fda89d8bf1a3f0be7)) --- # v3.10.0 2023年1月30日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![iNE](https://github.com/Sakuraine.png)](https://github.com/Sakuraine) ## 💥 Breaking Change[​](#boom-breaking-change "💥 Breaking Change的直接链接") * `consul`, `core` * [#2688](https://github.com/midwayjs/midway/pull/2688) fix(deps): update dependency consul to v1 ([@czy88840616](https://github.com/czy88840616)) * `bull`, `core`, `decorator`, `faas`, `info`, `validate`, `web-express`, `web-koa`, `web` * [#2656](https://github.com/midwayjs/midway/pull/2656) feat: add pipes for parameter decorator ([@czy88840616](https://github.com/czy88840616)) * `jwt` * [#2595](https://github.com/midwayjs/midway/pull/2595) fix(deps): update dependency jsonwebtoken to v9 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2642](https://github.com/midwayjs/midway/pull/2642) chore(deps): update dependency @typegoose/typegoose to v10 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core` * [#2687](https://github.com/midwayjs/midway/pull/2687) feat: add simulator ([@czy88840616](https://github.com/czy88840616)) * [#2654](https://github.com/midwayjs/midway/pull/2654) feat: add @Singleton and get namespace api ([@czy88840616](https://github.com/czy88840616)) * `core`, `typeorm` * [#2591](https://github.com/midwayjs/midway/pull/2591) feat: add typeorm logger and logger lazy create ([@czy88840616](https://github.com/czy88840616)) * `kafka`, `mock` * [#2679](https://github.com/midwayjs/midway/pull/2679) feat: support app enable ssl in dev mode ([@czy88840616](https://github.com/czy88840616)) * `bull`, `core`, `decorator`, `faas`, `info`, `validate`, `web-express`, `web-koa`, `web` * [#2656](https://github.com/midwayjs/midway/pull/2656) feat: add pipes for parameter decorator ([@czy88840616](https://github.com/czy88840616)) * `faas`, `mock` * [#2672](https://github.com/midwayjs/midway/pull/2672) feat: add custom response args ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2626](https://github.com/midwayjs/midway/pull/2626) fix: run stop lifecycle with reverse ([@czy88840616](https://github.com/czy88840616)) * `bootstrap` * [#2644](https://github.com/midwayjs/midway/pull/2644) fix: sticky post ([@echosoar](https://github.com/echosoar)) * `swagger`, `validate` * [#2640](https://github.com/midwayjs/midway/pull/2640) fix: swagger one of with type ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#2646](https://github.com/midwayjs/midway/pull/2646) chore: change level for default logger level ([@czy88840616](https://github.com/czy88840616)) * `core`, `faas`, `mock` * [#2606](https://github.com/midwayjs/midway/pull/2606) feat: add ssr and custom trigger ([@czy88840616](https://github.com/czy88840616)) * `mock` * [#2643](https://github.com/midwayjs/midway/pull/2643) fix: output error when running test in jest environment ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2653](https://github.com/midwayjs/midway/pull/2653) docs(site): update guard.md ([@Sakuraine](https://github.com/Sakuraine)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `consul`, `core` * [#2688](https://github.com/midwayjs/midway/pull/2688) fix(deps): update dependency consul to v1 ([@czy88840616](https://github.com/czy88840616)) * `jwt` * [#2685](https://github.com/midwayjs/midway/pull/2685) fix(deps): update dependency @types/jsonwebtoken to v9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2595](https://github.com/midwayjs/midway/pull/2595) fix(deps): update dependency jsonwebtoken to v9 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2683](https://github.com/midwayjs/midway/pull/2683) chore(deps): update dependency madge to v6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2680](https://github.com/midwayjs/midway/pull/2680) chore(deps): update jest monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2678](https://github.com/midwayjs/midway/pull/2678) chore(deps): update dependency madge to v5.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2673](https://github.com/midwayjs/midway/pull/2673) chore(deps): update dependency @vercel/ncc to v0.36.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2662](https://github.com/midwayjs/midway/pull/2662) chore(deps): update dependency ts-jest to v29.0.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2659](https://github.com/midwayjs/midway/pull/2659) chore(deps): update dependency @types/jest to v29.2.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2660](https://github.com/midwayjs/midway/pull/2660) chore(deps): update dependency lerna to v6.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2649](https://github.com/midwayjs/midway/pull/2649) chore(deps): update dependency @midwayjs/jest-environment-service-worker to v0.1.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2647](https://github.com/midwayjs/midway/pull/2647) chore(deps): update dependency typedoc to v0.23.24 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2650](https://github.com/midwayjs/midway/pull/2650) chore(deps): update dependency @midwayjs/jsdom-service-worker to v0.1.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2639](https://github.com/midwayjs/midway/pull/2639) chore(deps): update dependency @types/node to v18 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2641](https://github.com/midwayjs/midway/pull/2641) chore(deps): update dependency lerna to v6.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core` * [#2684](https://github.com/midwayjs/midway/pull/2684) chore(deps): update dependency sinon to v15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `redis` * [#2681](https://github.com/midwayjs/midway/pull/2681) fix(deps): update dependency ioredis to v5.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2667](https://github.com/midwayjs/midway/pull/2667) fix(deps): update dependency ioredis to v5.2.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2676](https://github.com/midwayjs/midway/pull/2676) chore(deps): update dependency @typegoose/typegoose to v10.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2642](https://github.com/midwayjs/midway/pull/2642) chore(deps): update dependency @typegoose/typegoose to v10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#2675](https://github.com/midwayjs/midway/pull/2675) fix(deps): update dependency axios to v1.2.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2665](https://github.com/midwayjs/midway/pull/2665) fix(deps): update dependency axios to v1.2.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2677](https://github.com/midwayjs/midway/pull/2677) chore(deps): update dependency mongoose to v6.9.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2661](https://github.com/midwayjs/midway/pull/2661) chore(deps): update dependency mongoose to v6.8.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2652](https://github.com/midwayjs/midway/pull/2652) chore(deps): update dependency mongoose to v6.8.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#2670](https://github.com/midwayjs/midway/pull/2670) chore(deps): update dependency @types/express to v4.17.16 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2671](https://github.com/midwayjs/midway/pull/2671) chore(deps): update mikro-orm monorepo to v5.6.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2663](https://github.com/midwayjs/midway/pull/2663) chore(deps): update mikro-orm monorepo to v5.6.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2648](https://github.com/midwayjs/midway/pull/2648) chore(deps): update mikro-orm monorepo to v5.6.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2674](https://github.com/midwayjs/midway/pull/2674) fix(deps): update dependency @grpc/grpc-js to v1.8.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2664](https://github.com/midwayjs/midway/pull/2664) fix(deps): update dependency @grpc/grpc-js to v1.8.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `consul` * [#2668](https://github.com/midwayjs/midway/pull/2668) chore(deps): update dependency nock to v13.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#2669](https://github.com/midwayjs/midway/pull/2669) fix(deps): update dependency ws to v8.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#2666](https://github.com/midwayjs/midway/pull/2666) fix(deps): update dependency casbin to v5.21.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `passport` * [#2651](https://github.com/midwayjs/midway/pull/2651) chore(deps): update dependency @types/passport-local to v1.0.35 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * iNE ([@Sakuraine](https://github.com/Sakuraine)) --- # v3.10.1 2023年1月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2689](https://github.com/midwayjs/midway/pull/2689) fix: logger async and egg will be start error with cluster mode ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.10 2023年2月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `web` * [#2734](https://github.com/midwayjs/midway/pull/2734) fix: function meta name ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.11 2023年2月16日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `faas`, `http-proxy`, `mock` * [#2738](https://github.com/midwayjs/midway/pull/2738) feat: support stream response ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.12 2023年2月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cross-domain`, `faas` * [#2739](https://github.com/midwayjs/midway/pull/2739) fix: cross domain with options request ([@echosoar](https://github.com/echosoar)) * `http-proxy` * [#2748](https://github.com/midwayjs/midway/pull/2748) fix: wrong proxy namespace ([@czy88840616](https://github.com/czy88840616)) * `validate` * [#2747](https://github.com/midwayjs/midway/pull/2747) fix: joi version for node 12/14 ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `http-proxy` * [#2749](https://github.com/midwayjs/midway/pull/2749) fix(deps): update dependency axios to v1.3.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2754](https://github.com/midwayjs/midway/pull/2754) fix(deps): update dependency @grpc/proto-loader to v0.7.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2753](https://github.com/midwayjs/midway/pull/2753) fix(deps): update dependency @grpc/grpc-js to v1.8.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2752](https://github.com/midwayjs/midway/pull/2752) chore(deps): update mikro-orm monorepo to v5.6.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2751](https://github.com/midwayjs/midway/pull/2751) chore(deps): update dependency typedoc to v0.23.25 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2711](https://github.com/midwayjs/midway/pull/2711) chore(deps): update dependency @types/node to v18.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2744](https://github.com/midwayjs/midway/pull/2744) chore(deps): update dependency jest to v29.4.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `redis` * [#2750](https://github.com/midwayjs/midway/pull/2750) fix(deps): update dependency ioredis to v5.3.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2745](https://github.com/midwayjs/midway/pull/2745) chore(deps): update dependency mongoose to v6.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session` * [#2743](https://github.com/midwayjs/midway/pull/2743) chore(deps): update dependency @types/express-session to v1.17.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.13 2023年2月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * Other * [#2758](https://github.com/midwayjs/midway/pull/2758) chore: add context.streaming api for streaming api ([@czy88840616](https://github.com/czy88840616)) * `mock` * [#2757](https://github.com/midwayjs/midway/pull/2757) fix: mock buffer base64 response ([@echosoar](https://github.com/echosoar)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.14 2023年2月23日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * [#2759](https://github.com/midwayjs/midway/pull/2759) fix: set streaming property first ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接��链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.15 2023年3月10日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2764](https://github.com/midwayjs/midway/pull/2764) fix: mock service inited will be before lifecycle ([@czy88840616](https://github.com/czy88840616)) * [#2765](https://github.com/midwayjs/midway/pull/2765) fix: content-type set by headers options ([@czy88840616](https://github.com/czy88840616)) * [#2793](https://github.com/midwayjs/midway/pull/2793) fix: wrong handler name with decorator ([@czy88840616](https://github.com/czy88840616)) * `faas` * [#2761](https://github.com/midwayjs/midway/pull/2761) fix: faas content length ([@echosoar](https://github.com/echosoar)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2773](https://github.com/midwayjs/midway/pull/2773) docs(site): update validate.md ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#2791](https://github.com/midwayjs/midway/pull/2791) chore(deps): update dependency @types/node to v18.15.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2792](https://github.com/midwayjs/midway/pull/2792) chore(deps): update dependency jest to v29.5.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2785](https://github.com/midwayjs/midway/pull/2785) chore(deps): update dependency lerna to v6.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2762](https://github.com/midwayjs/midway/pull/2762) chore(deps): update dependency @types/node to v18.14.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2778](https://github.com/midwayjs/midway/pull/2778) chore(deps): update dependency typedoc to v0.23.26 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2772](https://github.com/midwayjs/midway/pull/2772) fix(deps): update dependency cron to v2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2789](https://github.com/midwayjs/midway/pull/2789) chore(deps): update dependency mongoose to v6.10.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2786](https://github.com/midwayjs/midway/pull/2786) chore(deps): update dependency mongoose to v6.10.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `sequelize` * [#2790](https://github.com/midwayjs/midway/pull/2790) chore(deps): update dependency sequelize to v6.29.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2760](https://github.com/midwayjs/midway/pull/2760) chore(deps): update dependency sequelize to v6.29.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2767](https://github.com/midwayjs/midway/pull/2767) fix(deps): update dependency @grpc/grpc-js to v1.8.12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2763](https://github.com/midwayjs/midway/pull/2763) fix(deps): update dependency @grpc/grpc-js to v1.8.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2784](https://github.com/midwayjs/midway/pull/2784) chore(deps): update dependency @typegoose/typegoose to v10.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2779](https://github.com/midwayjs/midway/pull/2779) chore(deps): update mikro-orm monorepo to v5.6.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `mock`, `upload` * [#2781](https://github.com/midwayjs/midway/pull/2781) fix(deps): update dependency raw-body to v2.5.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#2783](https://github.com/midwayjs/midway/pull/2783) fix(deps): update socket.io packages to v4.6.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#2782](https://github.com/midwayjs/midway/pull/2782) fix(deps): update dependency ws to v8.12.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `kafka`, `mock` * [#2777](https://github.com/midwayjs/midway/pull/2777) chore(deps): update dependency kafkajs to v2.2.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `rabbitmq` * [#2768](https://github.com/midwayjs/midway/pull/2768) fix(deps): update dependency amqp-connection-manager to v4.1.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#2769](https://github.com/midwayjs/midway/pull/2769) fix(deps): update dependency axios to v1.3.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#2770](https://github.com/midwayjs/midway/pull/2770) fix(deps): update dependency body-parser to v1.20.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.10.16 2023年3月21日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Umuoy](https://github.com/umuoy1.png)](https://github.com/umuoy1) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#2807](https://github.com/midwayjs/midway/pull/2807) fix: egg missing export decorator ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `typegoose` * [#2798](https://github.com/midwayjs/midway/pull/2798) chore(deps): update dependency @typegoose/typegoose to v10.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `mikro`, `sequelize`, `typeorm` * [#2795](https://github.com/midwayjs/midway/pull/2795) chore(deps): update dependency sqlite3 to v5.1.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2801](https://github.com/midwayjs/midway/pull/2801) chore(deps): update dependency mongoose to v6.10.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `sequelize` * [#2802](https://github.com/midwayjs/midway/pull/2802) chore(deps): update dependency sequelize to v6.29.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Umuoy ([@umuoy1](https://github.com/umuoy1)) --- # v3.10.2 2023年1月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `typeorm` * [#2690](https://github.com/midwayjs/midway/pull/2690) fix: create default logger when typeorm logger set undefined ([@czy88840616](https://github.com/czy88840616)) * `http-proxy`, `upload` * [#2563](https://github.com/midwayjs/midway/pull/2563) fix: remove content-length when proxy stream ([@echosoar](https://github.com/echosoar)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * [#2622](https://github.com/midwayjs/midway/pull/2622) chore(deps): update dependency typescript to v4.9.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.3 2023年1月31日 [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2691](https://github.com/midwayjs/midway/pull/2691) fix(core): variable options may undefined when use custom decorator ([@waitingsong](https://github.com/waitingsong)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.10.4 2023年1月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `mock` * [#2694](https://github.com/midwayjs/midway/pull/2694) fix: missing pipes args in web param ([@czy88840616](https://github.com/czy88840616)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * `core` * [#2693](https://github.com/midwayjs/midway/pull/2693) chore(core): add type DecoratorMetaData for custom decorator ([@waitingsong](https://github.com/waitingsong)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.10.5 2023年1月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `decorator`, `validate` * [#2695](https://github.com/midwayjs/midway/pull/2695) fix: web param set wrong pipe position ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.6 2023年2月2日 [![C](https://github.com/abnerCrack.png)](https://github.com/abnerCrack) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![下雨就像弹钢琴](https://github.com/luckyscript.png)](https://github.com/luckyscript) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2697](https://github.com/midwayjs/midway/pull/2697) fix: RouterService match router method all ([@luckyscript](https://github.com/luckyscript)) * `core`, `validate` * [#2703](https://github.com/midwayjs/midway/pull/2703) fix: @valid with other decorator ([@czy88840616](https://github.com/czy88840616)) * `typeorm` * [#2704](https://github.com/midwayjs/midway/pull/2704) fix: typeorm logging property ([@czy88840616](https://github.com/czy88840616)) * `cross-domain` * [#2699](https://github.com/midwayjs/midway/pull/2699) fix: repair the impact of JSONP on normal requests(#2692) ([@abnerCrack](https://github.com/abnerCrack)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `otel` * [#2701](https://github.com/midwayjs/midway/pull/2701) feat: add ctx.traceId ([@czy88840616](https://github.com/czy88840616)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * C ([@abnerCrack](https://github.com/abnerCrack)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 下雨就像弹钢琴 ([@luckyscript](https://github.com/luckyscript)) --- # v3.10.7 2023年2月7日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Frank Zhao](https://github.com/frank-zsy.png)](https://github.com/frank-zsy) [![huel129](https://github.com/savoygu.png)](https://github.com/savoygu) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `validate` * [#2714](https://github.com/midwayjs/midway/pull/2714) fix(validate): export ParsePipe from pipe.ts ([@savoygu](https://github.com/savoygu)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core`, `decorator`, `faas`, `validate` * [#2708](https://github.com/midwayjs/midway/pull/2708) feat: add web param optional ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#2715](https://github.com/midwayjs/midway/pull/2715) docs(site): update validate.md ([@savoygu](https://github.com/savoygu)) * `bull` * [#2712](https://github.com/midwayjs/midway/pull/2712) fix(deps): update dependency bull to v4.10.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2709](https://github.com/midwayjs/midway/pull/2709) chore(deps): update dependency @typegoose/typegoose to v10.1.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#2710](https://github.com/midwayjs/midway/pull/2710) chore(deps): update dependency @types/express to v4.17.17 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#2705](https://github.com/midwayjs/midway/pull/2705) fix(deps): update dependency axios to v1.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#2706](https://github.com/midwayjs/midway/pull/2706) fix(deps): update dependency casbin to v5.23.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Frank Zhao ([@frank-zsy](https://github.com/frank-zsy)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * huel129 ([@savoygu](https://github.com/savoygu)) --- # v3.10.8 2023年2月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `cross-domain` * [#2713](https://github.com/midwayjs/midway/pull/2713) fix: add ctx.jsonp for cross-domain ([@echosoar](https://github.com/echosoar)) * `faas` * [#2717](https://github.com/midwayjs/midway/pull/2717) feat: support buffer response ([@czy88840616](https://github.com/czy88840616)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.10.9 2023年2月13日 [![世新](https://github.com/4xii.png)](https://github.com/4xii) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![孺子牛](https://github.com/ddzyan.png)](https://github.com/ddzyan) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull` * [#2720](https://github.com/midwayjs/midway/pull/2720) fix: bull add default job options in decorator will be overriding args ([@czy88840616](https://github.com/czy88840616)) * `core`, `faas` * [#2732](https://github.com/midwayjs/midway/pull/2732) fix: func name set ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `code-dye` * [#2728](https://github.com/midwayjs/midway/pull/2728) chore: update codedye ([@echosoar](https://github.com/echosoar)) * `core` * [#2733](https://github.com/midwayjs/midway/pull/2733) chore: add generalization type ([@czy88840616](https://github.com/czy88840616)) * `mock` * [#2719](https://github.com/midwayjs/midway/pull/2719) fix: node 12 fs promise ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2731](https://github.com/midwayjs/midway/pull/2731) docs: fix pipe valid ([@ddzyan](https://github.com/ddzyan)) * [#2727](https://github.com/midwayjs/midway/pull/2727) doc:custom\_error.md fix import ([@4xii](https://github.com/4xii)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#2730](https://github.com/midwayjs/midway/pull/2730) chore(deps): update mikro-orm monorepo to v5.6.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2729](https://github.com/midwayjs/midway/pull/2729) chore(deps): update supercharge/mongodb-github-action action to v1.9.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2721](https://github.com/midwayjs/midway/pull/2721) chore(deps): update dependency jest to v29.4.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `typeorm` * [#2723](https://github.com/midwayjs/midway/pull/2723) chore(deps): update dependency typeorm to v0.3.12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2724](https://github.com/midwayjs/midway/pull/2724) fix(deps): update dependency @grpc/grpc-js to v1.8.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#2725](https://github.com/midwayjs/midway/pull/2725) fix(deps): update dependency bull to v4.10.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#2726](https://github.com/midwayjs/midway/pull/2726) fix(deps): update socket.io packages to v4.6.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2722](https://github.com/midwayjs/midway/pull/2722) chore(deps): update dependency mongoose to v6.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 世新 ([@4xii](https://github.com/4xii)) * 孺子牛 ([@ddzyan](https://github.com/ddzyan)) --- # v3.11.0 2023年3月27日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `tags`, `upload` * [#2740](https://github.com/midwayjs/midway/pull/2740) feat: tags component ([@echosoar](https://github.com/echosoar)) * `cron` * [#2771](https://github.com/midwayjs/midway/pull/2771) feat: add cron component ([@czy88840616](https://github.com/czy88840616)) * `core` * [#2805](https://github.com/midwayjs/midway/pull/2805) feat: support match and ignore property with array ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cron` * [#2831](https://github.com/midwayjs/midway/pull/2831) fix(deps): update dependency cron to v2.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#2832](https://github.com/midwayjs/midway/pull/2832) fix(deps): update dependency joi to v17.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#2833](https://github.com/midwayjs/midway/pull/2833) fix(deps): update dependency koa-bodyparser to v4.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `captcha`, `security` * [#2828](https://github.com/midwayjs/midway/pull/2828) fix(deps): update dependency nanoid to v3.3.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `tablestore` * [#2829](https://github.com/midwayjs/midway/pull/2829) fix(deps): update dependency tablestore to v5.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board`, `view-ejs` * [#2827](https://github.com/midwayjs/midway/pull/2827) fix(deps): update dependency ejs to v3.1.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#2830](https://github.com/midwayjs/midway/pull/2830) fix(deps): update dependency ws to v8.13.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2823](https://github.com/midwayjs/midway/pull/2823) fix(deps): update dependency @grpc/grpc-js to v1.8.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2824](https://github.com/midwayjs/midway/pull/2824) fix(deps): update dependency @grpc/proto-loader to v0.7.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `sequelize` * [#2819](https://github.com/midwayjs/midway/pull/2819) chore(deps): update dependency sequelize to v6.30.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#2820](https://github.com/midwayjs/midway/pull/2820) chore(deps): update dependency swagger-ui-dist to v4.18.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2817](https://github.com/midwayjs/midway/pull/2817) chore(deps): update mikro-orm monorepo to v5.6.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2818](https://github.com/midwayjs/midway/pull/2818) chore(deps): update dependency @types/jest to v29.5.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2816](https://github.com/midwayjs/midway/pull/2816) chore(deps): update dependency typedoc to v0.23.28 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2799](https://github.com/midwayjs/midway/pull/2799) chore(deps): update dependency @types/node to v18.15.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2810](https://github.com/midwayjs/midway/pull/2810) chore(deps): update dependency @typegoose/typegoose to v10.3.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `mikro`, `sequelize`, `typeorm` * [#2815](https://github.com/midwayjs/midway/pull/2815) chore(deps): update dependency sqlite3 to v5.1.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session` * [#2811](https://github.com/midwayjs/midway/pull/2811) chore(deps): update dependency @types/express-session to v1.17.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2812](https://github.com/midwayjs/midway/pull/2812) chore(deps): update dependency mongoose to v6.10.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core` * [#2813](https://github.com/midwayjs/midway/pull/2813) chore(deps): update dependency sinon to v15.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.11.1 2023年4月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![DeveloperYvan](https://github.com/developeryvan.png)](https://github.com/developeryvan) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) [![Thirteen](https://github.com/wangyi12358.png)](https://github.com/wangyi12358) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `socketio` * [#2850](https://github.com/midwayjs/midway/pull/2850) fix: fixed missing initial messages (#2847) ([@ghostoy](https://github.com/ghostoy)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull` * [#2842](https://github.com/midwayjs/midway/pull/2842) feat: add queueOptions to the @Processor decorator ([@developeryvan](https://github.com/developeryvan)) * `core` * [#2841](https://github.com/midwayjs/midway/pull/2841) chore(core): add boolean property JoinPoint\['proceedIsAsyncFunction'] ([@waitingsong](https://github.com/waitingsong)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * Other * [#2840](https://github.com/midwayjs/midway/pull/2840) docs: update kafka disconnect ([@wangyi12358](https://github.com/wangyi12358)) * `otel` * [#2826](https://github.com/midwayjs/midway/pull/2826) chore(otel): bump and clean dependencies ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `otel` * [#2848](https://github.com/midwayjs/midway/pull/2848) chore(deps): update dependency @opentelemetry/sdk-node to ^0.37.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2826](https://github.com/midwayjs/midway/pull/2826) chore(otel): bump and clean dependencies ([@waitingsong](https://github.com/waitingsong)) * `swagger` * [#2844](https://github.com/midwayjs/midway/pull/2844) chore(deps): update dependency swagger-ui-dist to v4.18.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 6[​](#committers-6 "Committers: 6的直接链接") * Cong Liu ([@ghostoy](https://github.com/ghostoy)) * DeveloperYvan ([@developeryvan](https://github.com/developeryvan)) * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Thirteen ([@wangyi12358](https://github.com/wangyi12358)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.11.10 2023年5月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock` * [#3000](https://github.com/midwayjs/midway/pull/3000) fix: bootstrap close entry ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.11 2023年6月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![sumy](https://github.com/sumy7.png)](https://github.com/sumy7) [![林轩](https://github.com/whale2002.png)](https://github.com/whale2002) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3025](https://github.com/midwayjs/midway/pull/3025) fix: listener init data typings ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `code-dye` * [#3021](https://github.com/midwayjs/midway/pull/3021) feat(code-dye): outputType-html support show not end async call ([@sumy7](https://github.com/sumy7)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3024](https://github.com/midwayjs/midway/pull/3024) docs: update quick\_guide.md ([@whale2002](https://github.com/whale2002)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `oss` * [#2974](https://github.com/midwayjs/midway/pull/2974) fix(deps): update dependency @types/ali-oss to v6.16.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3020](https://github.com/midwayjs/midway/pull/3020) chore(deps): update dependency mongoose to v7.2.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3018](https://github.com/midwayjs/midway/pull/3018) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.12.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3017](https://github.com/midwayjs/midway/pull/3017) fix(deps): update dependency @grpc/grpc-js to v1.8.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#3006](https://github.com/midwayjs/midway/pull/3006) fix(deps): update socket.io packages to v4.6.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3009](https://github.com/midwayjs/midway/pull/3009) chore(deps): update dependency madge to v6.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#3008](https://github.com/midwayjs/midway/pull/3008) chore(deps): update dependency dayjs to v1.11.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3007](https://github.com/midwayjs/midway/pull/3007) fix(deps): update dependency axios to v1.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * sumy ([@sumy7](https://github.com/sumy7)) * 林轩 ([@whale2002](https://github.com/whale2002)) --- # v3.11.12 2023年7月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![sumy](https://github.com/sumy7.png)](https://github.com/sumy7) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) [![yemangran](https://github.com/yemangran.png)](https://github.com/yemangran) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3058](https://github.com/midwayjs/midway/pull/3058) docs(site): update how\_to\_install\_nodejs.md ([@waitingsong](https://github.com/waitingsong)) * [#3051](https://github.com/midwayjs/midway/pull/3051) docs: update quickstart.md ([@yemangran](https://github.com/yemangran)) * [#3034](https://github.com/midwayjs/midway/pull/3034) docs: change cron logger default fileLogName ([@sumy7](https://github.com/sumy7)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `info`, `mock` * [#3070](https://github.com/midwayjs/midway/pull/3070) chore: update lerna to v7 ([@czy88840616](https://github.com/czy88840616)) * `jwt` * [#3067](https://github.com/midwayjs/midway/pull/3067) fix(deps): update dependency jsonwebtoken to v9.0.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3046](https://github.com/midwayjs/midway/pull/3046) fix(deps): update dependency @grpc/grpc-js to v1.8.17 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#3053](https://github.com/midwayjs/midway/pull/3053) fix(deps): update socket.io packages to v4.7.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3033](https://github.com/midwayjs/midway/pull/3033) chore(deps): update mongoose monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#3036](https://github.com/midwayjs/midway/pull/3036) chore(deps): update dependency fs-extra to v11 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@yemangran](https://github.com/yemangran) * sumy ([@sumy7](https://github.com/sumy7)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.11.13 2023年7月10日 [![flyingCrp](https://github.com/flyingCrp.png)](https://github.com/flyingCrp) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `consul` * [#3069](https://github.com/midwayjs/midway/pull/3069) fix(consul): Adjust the application registration logic to obtain consul instances when client does not register ([@flyingCrp](https://github.com/flyingCrp)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * flyingCrp ([@flyingCrp](https://github.com/flyingCrp)) --- # v3.11.14 2023年7月12日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull` * [#3077](https://github.com/midwayjs/midway/pull/3077) fix: bull typings in interop mode ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.15 2023年7月16日 [![leemotive](https://github.com/leemotive.png)](https://github.com/leemotive) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3076](https://github.com/midwayjs/midway/pull/3076) fix: makeHttpRequest failed when post with custom headers ([@leemotive](https://github.com/leemotive)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa` * [#3047](https://github.com/midwayjs/midway/pull/3047) fix(deps): update dependency koa-bodyparser to v4.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3082](https://github.com/midwayjs/midway/pull/3082) fix(deps): update dependency @grpc/grpc-js to v1.8.18 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3083](https://github.com/midwayjs/midway/pull/3083) fix(deps): update dependency @grpc/proto-loader to v0.7.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * [@leemotive](https://github.com/leemotive) --- # v3.11.16 2023年8月1日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3126](https://github.com/midwayjs/midway/pull/3126) fix: swagger @ApiHeader @ApiHeaders only read one header ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `swagger` * [#3122](https://github.com/midwayjs/midway/pull/3122) feat: add swagger operationId ([@odex21](https://github.com/odex21)) * `axios` * [#3127](https://github.com/midwayjs/midway/pull/3127) feat: expose more APIs from axios ([@ghostoy](https://github.com/ghostoy)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Cong Liu ([@ghostoy](https://github.com/ghostoy)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@odex21](https://github.com/odex21) --- # v3.11.17 2023年8月1日 [![Suel](https://github.com/wakeGISer.png)](https://github.com/wakeGISer) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `http-proxy` * [#3130](https://github.com/midwayjs/midway/pull/3130) fix(http-proxy): readableStream.pipe(res) and res.on('finish') ([@wakeGISer](https://github.com/wakeGISer)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Suel ([@wakeGISer](https://github.com/wakeGISer)) --- # v3.11.18 2023年8月5日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull`, `cron` * [#3144](https://github.com/midwayjs/midway/pull/3144) fix: bull logger typo ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `mikro` * [#3114](https://github.com/midwayjs/midway/pull/3114) feat: add InjectEntityManager decorator for MikroORM and upgrade document ([@ghostoy](https://github.com/ghostoy)) * `oss` * [#3132](https://github.com/midwayjs/midway/pull/3132) feat: expose native OSS from package ([@ghostoy](https://github.com/ghostoy)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#3141](https://github.com/midwayjs/midway/pull/3141) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.12.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#3140](https://github.com/midwayjs/midway/pull/3140) fix(deps): update dependency casbin to v5.26.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3143](https://github.com/midwayjs/midway/pull/3143) chore(deps): update dependency autocannon to v7.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3139](https://github.com/midwayjs/midway/pull/3139) chore(deps): update dependency @types/node to v18.17.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Cong Liu ([@ghostoy](https://github.com/ghostoy)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.2 2023年4月3日 [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `socketio` * [#2854](https://github.com/midwayjs/midway/pull/2854) fix: fixed duplicated OnWSConnection ([@ghostoy](https://github.com/ghostoy)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mongoose`, `typegoose` * [#2856](https://github.com/midwayjs/midway/pull/2856) chore(deps): update mongoose monorepo (major) ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Cong Liu ([@ghostoy](https://github.com/ghostoy)) --- # v3.11.3 2023年4月3日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock` * [#2857](https://github.com/midwayjs/midway/pull/2857) fix: change for support worker ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2858](https://github.com/midwayjs/midway/pull/2858) docs(site): update awesome\_midway.md ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#2859](https://github.com/midwayjs/midway/pull/2859) fix(deps): update dependency casbin to v5.26.1 ([@czy88840616](https://github.com/czy88840616)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.11.4 2023年4月18日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![刘宏玺](https://github.com/lhx6538665.png)](https://github.com/lhx6538665) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bootstrap`, `core`, `otel` * [#2885](https://github.com/midwayjs/midway/pull/2885) fix: bootstrap test case ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `cache`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `decorator`, `etcd`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mikro`, `mock`, `mongoose`, `oss`, `otel`, `passport`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#2887](https://github.com/midwayjs/midway/pull/2887) feat: support options for custom request decorator ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `cache`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `decorator`, `etcd`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mikro`, `mock`, `mongoose`, `oss`, `otel`, `passport`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#2887](https://github.com/midwayjs/midway/pull/2887) feat: support options for custom request decorator ([@czy88840616](https://github.com/czy88840616)) * Other * [#2867](https://github.com/midwayjs/midway/pull/2867) docs(site): update quickstart.md ([@lhx6538665](https://github.com/lhx6538665)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#2876](https://github.com/midwayjs/midway/pull/2876) fix(deps): update dependency @grpc/grpc-js to v1.8.14 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `rabbitmq` * [#2877](https://github.com/midwayjs/midway/pull/2877) fix(deps): update dependency amqp-connection-manager to v4.1.12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `cache`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `decorator`, `etcd`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mikro`, `mock`, `mongoose`, `oss`, `otel`, `passport`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#2887](https://github.com/midwayjs/midway/pull/2887) feat: support options for custom request decorator ([@czy88840616](https://github.com/czy88840616)) * `sequelize` * [#2869](https://github.com/midwayjs/midway/pull/2869) chore(deps): update dependency sequelize to v6.31.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2866](https://github.com/midwayjs/midway/pull/2866) chore(deps): update dependency typedoc to v0.24.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2882](https://github.com/midwayjs/midway/pull/2882) chore(deps): update dependency @typegoose/typegoose to v11.0.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 刘宏玺 ([@lhx6538665](https://github.com/lhx6538665)) --- # v3.11.5 2023年4月25日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Steppenwolf1900](https://github.com/Steppenwolf1900.png)](https://github.com/Steppenwolf1900) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock` * [#2905](https://github.com/midwayjs/midway/pull/2905) fix: createServerlessApp baseDir with undefined ([@czy88840616](https://github.com/czy88840616)) * `casbin-typeorm-adapter`, `typeorm` * [#2907](https://github.com/midwayjs/midway/pull/2907) fix: compatible typeorm objectId changes ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * [#2899](https://github.com/midwayjs/midway/pull/2899) feat: support app enable ssl custom certificate in dev mode ([@Steppenwolf1900](https://github.com/Steppenwolf1900)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@Steppenwolf1900](https://github.com/Steppenwolf1900) --- # v3.11.6 2023年4月29日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#2915](https://github.com/midwayjs/midway/pull/2915) chore: support serverless function options any ([@czy88840616](https://github.com/czy88840616)) * [#2906](https://github.com/midwayjs/midway/pull/2906) feat: add more http options ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `typegoose` * [#2926](https://github.com/midwayjs/midway/pull/2926) chore(deps): update dependency @typegoose/typegoose to v11.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#2921](https://github.com/midwayjs/midway/pull/2921) fix(deps): update dependency @types/jsonwebtoken to v9.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2919](https://github.com/midwayjs/midway/pull/2919) chore(deps): update nrwl monorepo to v15.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.7 2023年5月13日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `rabbitmq` * [#2935](https://github.com/midwayjs/midway/pull/2935) fix(deps): update dependency amqp-connection-manager to v4.1.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#2952](https://github.com/midwayjs/midway/pull/2952) fix(deps): update dependency joi to v17.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `redis` * [#2951](https://github.com/midwayjs/midway/pull/2951) fix(deps): update dependency ioredis to v5.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2931](https://github.com/midwayjs/midway/pull/2931) chore(deps): update mikro-orm monorepo to v5.7.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2932](https://github.com/midwayjs/midway/pull/2932) chore(deps): update dependency autocannon to v7.11.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.8 2023年5月15日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `typeorm` * [#2964](https://github.com/midwayjs/midway/pull/2964) fix: model get different repository by type ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `consul` * [#2960](https://github.com/midwayjs/midway/pull/2960) chore(deps): update dependency @types/sinon to v10.0.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#2959](https://github.com/midwayjs/midway/pull/2959) chore(deps): update mikro-orm monorepo to v5.7.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2958](https://github.com/midwayjs/midway/pull/2958) chore(deps): update dependency @types/node to v18.16.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.11.9 2023年5月30日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Joël Galeran](https://github.com/Jolg42.png)](https://github.com/Jolg42) [![Zy](https://github.com/RainManGO.png)](https://github.com/RainManGO) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `faas`, `mock` * [#2996](https://github.com/midwayjs/midway/pull/2996) feat: support new faas v3 entry ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2986](https://github.com/midwayjs/midway/pull/2986) docs: fix validate.md defaultValuePipe variable name error ([@RainManGO](https://github.com/RainManGO)) * [#2983](https://github.com/midwayjs/midway/pull/2983) docs: update Prisma env var for downloading engines ([@Jolg42](https://github.com/Jolg42)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#2934](https://github.com/midwayjs/midway/pull/2934) fix(deps): update dependency @grpc/proto-loader to v0.7.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cron` * [#2992](https://github.com/midwayjs/midway/pull/2992) fix(deps): update dependency cron to v2.3.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Joël Galeran ([@Jolg42](https://github.com/Jolg42)) * Zy ([@RainManGO](https://github.com/RainManGO)) --- # v3.12.0 2023年8月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) [![Taosh](https://github.com/taosher.png)](https://github.com/taosher) [![Ming Ye](https://github.com/ymqy.png)](https://github.com/ymqy) ## 💥 Breaking Change[​](#boom-breaking-change "💥 Breaking Change的直接链接") * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `cache`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `decorator`, `etcd`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mikro`, `mock`, `mongoose`, `oss`, `otel`, `passport`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#3045](https://github.com/midwayjs/midway/pull/3045) feat: support esm file loader ([@czy88840616](https://github.com/czy88840616)) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core`, `leoric` * [#3087](https://github.com/midwayjs/midway/pull/3087) feat(deps): support leoric as model layer ([@czy88840616](https://github.com/czy88840616)) * `core` * [#2961](https://github.com/midwayjs/midway/pull/2961) feat: add getApp and getScope api ([@czy88840616](https://github.com/czy88840616)) * [#3110](https://github.com/midwayjs/midway/pull/3110) feat: support all http methods ([@ghostoy](https://github.com/ghostoy)) * `bull-board` * [#3085](https://github.com/midwayjs/midway/pull/3085) feat: upgrade bull-board v5.6.0 ([@czy88840616](https://github.com/czy88840616)) * `web-koa`, `web` * [#3133](https://github.com/midwayjs/midway/pull/3133) feat: add ctx.forward api ([@czy88840616](https://github.com/czy88840616)) * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `cache`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `decorator`, `etcd`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mikro`, `mock`, `mongoose`, `oss`, `otel`, `passport`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#3045](https://github.com/midwayjs/midway/pull/3045) feat: support esm file loader ([@czy88840616](https://github.com/czy88840616)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * `core` * [#3164](https://github.com/midwayjs/midway/pull/3164) chore(decorator): opt code in serverlessTrigger ([@taosher](https://github.com/taosher)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `etcd` * [#3142](https://github.com/midwayjs/midway/pull/3142) fix(deps): update dependency etcd3 to v1.1.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board`, `bull` * [#2993](https://github.com/midwayjs/midway/pull/2993) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3155](https://github.com/midwayjs/midway/pull/3155) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.12.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3085](https://github.com/midwayjs/midway/pull/3085) feat: upgrade bull-board v5.6.0 ([@czy88840616](https://github.com/czy88840616)) * Other * [#3161](https://github.com/midwayjs/midway/pull/3161) chore(deps): update dependency @types/node to v18.17.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3157](https://github.com/midwayjs/midway/pull/3157) chore(deps): update supercharge/mongodb-github-action action to v1.10.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3162](https://github.com/midwayjs/midway/pull/3162) chore(deps): update dependency mongoose to v7.4.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#3156](https://github.com/midwayjs/midway/pull/3156) fix(deps): update socket.io packages to v4.7.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Cong Liu ([@ghostoy](https://github.com/ghostoy)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Ming Ye ([@ymqy](https://github.com/ymqy)) * Taosh ([@taosher](https://github.com/taosher)) --- # v3.12.1 2023年8月16日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3168](https://github.com/midwayjs/midway/pull/3168) fix: import json not support under node v16 ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.10 2023年11月5日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `http-proxy` * [#3400](https://github.com/midwayjs/midway/pull/3400) fix(deps): update dependency axios to v1.6.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3398](https://github.com/midwayjs/midway/pull/3398) chore(deps): update actions/checkout action to v4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3399](https://github.com/midwayjs/midway/pull/3399) chore(deps): update actions/setup-node action to v4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board`, `bull` * [#3397](https://github.com/midwayjs/midway/pull/3397) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#3395](https://github.com/midwayjs/midway/pull/3395) fix(deps): update dependency ws to v8.14.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#3392](https://github.com/midwayjs/midway/pull/3392) fix(deps): update dependency casbin to v5.27.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#3396](https://github.com/midwayjs/midway/pull/3396) fix(deps): update dependency leoric to v2.11.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cron` * [#3393](https://github.com/midwayjs/midway/pull/3393) fix(deps): update dependency cron to v2.4.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3394](https://github.com/midwayjs/midway/pull/3394) fix(deps): update dependency joi to v17.11.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#3384](https://github.com/midwayjs/midway/pull/3384) fix(deps): update dependency @types/jsonwebtoken to v9.0.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3385](https://github.com/midwayjs/midway/pull/3385) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.12.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.2 2023年8月17日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `web` * [#3175](https://github.com/midwayjs/midway/pull/3175) fix: use original method name ([@czy88840616](https://github.com/czy88840616)) * `core` * [#3171](https://github.com/midwayjs/midway/pull/3171) fix: load file missing file prefix under windows ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.3 2023年8月24日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3191](https://github.com/midwayjs/midway/pull/3191) fix: add glob load model args ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3181](https://github.com/midwayjs/midway/pull/3181) docs(site): \_\_filename, \_\_dirname under ESM ([@waitingsong](https://github.com/waitingsong)) * [#3166](https://github.com/midwayjs/midway/pull/3166) docs: add document for esm version ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#3193](https://github.com/midwayjs/midway/pull/3193) chore(deps): update dependency jest to v29.6.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3183](https://github.com/midwayjs/midway/pull/3183) chore(deps): update dependency jest to v29.6.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3186](https://github.com/midwayjs/midway/pull/3186) chore(deps): update dependency @types/node to v18.17.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3177](https://github.com/midwayjs/midway/pull/3177) fix(deps): update dependency accepts to v1.3.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3187](https://github.com/midwayjs/midway/pull/3187) chore(deps): update dependency mongoose to v7.4.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.12.4 2023年8月29日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3209](https://github.com/midwayjs/midway/pull/3209) fix: swagger revert require ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#3195](https://github.com/midwayjs/midway/pull/3195) fix(deps): update dependency @grpc/proto-loader to v0.7.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.5 2023年9月25日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * `faas` * [#3235](https://github.com/midwayjs/midway/pull/3235) docs: faas upgrade ([@czy88840616](https://github.com/czy88840616)) * Other * [#3219](https://github.com/midwayjs/midway/pull/3219) docs: for faas change ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board` * [#3273](https://github.com/midwayjs/midway/pull/3273) fix(deps): update bull monorepo to v5.8.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3251](https://github.com/midwayjs/midway/pull/3251) fix(deps): update bull monorepo to v5.8.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3229](https://github.com/midwayjs/midway/pull/3229) fix(deps): update bull monorepo to v5.8.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3274](https://github.com/midwayjs/midway/pull/3274) fix(deps): update dependency @grpc/proto-loader to v0.7.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3252](https://github.com/midwayjs/midway/pull/3252) fix(deps): update dependency @grpc/grpc-js to v1.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3230](https://github.com/midwayjs/midway/pull/3230) fix(deps): update dependency @grpc/grpc-js to v1.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#3266](https://github.com/midwayjs/midway/pull/3266) chore(deps): update dependency dayjs to v1.11.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#3254](https://github.com/midwayjs/midway/pull/3254) fix(deps): update dependency @opentelemetry/api to v1.6.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#3253](https://github.com/midwayjs/midway/pull/3253) fix(deps): update dependency ali-oss to v6.18.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3232](https://github.com/midwayjs/midway/pull/3232) fix(deps): update dependency ali-oss to v6.18.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#3249](https://github.com/midwayjs/midway/pull/3249) chore(deps): update dependency @types/koa-router to v7.4.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3241](https://github.com/midwayjs/midway/pull/3241) chore(deps): update dependency mongoose to v7.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3196](https://github.com/midwayjs/midway/pull/3196) fix(deps): update dependency statuses to v2.0.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3237](https://github.com/midwayjs/midway/pull/3237) fix: remove querystring module ([@czy88840616](https://github.com/czy88840616)) * [#3084](https://github.com/midwayjs/midway/pull/3084) chore(deps): update dependency lerna to v7.2.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3234](https://github.com/midwayjs/midway/pull/3234) chore(deps): update dependency @types/node to v18.17.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3093](https://github.com/midwayjs/midway/pull/3093) chore(deps): update dependency @nrwl/tao to v16 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap` * [#3236](https://github.com/midwayjs/midway/pull/3236) fix(deps): update dependency @midwayjs/event-bus to v1.9.4 ([@czy88840616](https://github.com/czy88840616)) * `leoric` * [#3216](https://github.com/midwayjs/midway/pull/3216) fix(deps): update dependency leoric to v2.11.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#3215](https://github.com/midwayjs/midway/pull/3215) fix(deps): update dependency jsonwebtoken to v9.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.6 2023年10月1日 [![iNE](https://github.com/Sakuraine.png)](https://github.com/Sakuraine) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3297](https://github.com/midwayjs/midway/pull/3297) docs(site): update passport.md ([@Sakuraine](https://github.com/Sakuraine)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `oss` * [#3295](https://github.com/midwayjs/midway/pull/3295) fix(deps): update dependency @types/ali-oss to v6.16.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3294](https://github.com/midwayjs/midway/pull/3294) fix(deps): update dependency @grpc/grpc-js to v1.9.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3288](https://github.com/midwayjs/midway/pull/3288) chore(deps): update dependency @types/node to v18.18.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * iNE ([@Sakuraine](https://github.com/Sakuraine)) --- # v3.12.7 2023年10月11日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3320](https://github.com/midwayjs/midway/pull/3320) fix: swagger type missing with multi-extends ([@czy88840616](https://github.com/czy88840616)) * `passport` * [#3314](https://github.com/midwayjs/midway/pull/3314) fix: passport validate resolve is not executed under concurrency ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mongoose`, `typegoose` * [#3308](https://github.com/midwayjs/midway/pull/3308) chore(deps): update mongoose monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3318](https://github.com/midwayjs/midway/pull/3318) chore(deps): update dependency lerna to v7.3.1 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `consul` * [#3319](https://github.com/midwayjs/midway/pull/3319) chore(deps): update dependency nock to v13.3.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3306](https://github.com/midwayjs/midway/pull/3306) fix(deps): update dependency @grpc/grpc-js to v1.9.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#3307](https://github.com/midwayjs/midway/pull/3307) fix(deps): update dependency @types/jsonwebtoken to v9.0.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.12.8 2023年10月25日 [![ZhengChao](https://github.com/SmartOrange.png)](https://github.com/SmartOrange) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#3351](https://github.com/midwayjs/midway/pull/3351) fix: use qs to replace querystring to solve #2162 issue ([@SmartOrange](https://github.com/SmartOrange)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `http-proxy` * [#3326](https://github.com/midwayjs/midway/pull/3326) fix(deps): update dependency axios to v1.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock` * [#3325](https://github.com/midwayjs/midway/pull/3325) fix(deps): update dependency @types/supertest to v2.0.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3327](https://github.com/midwayjs/midway/pull/3327) chore(deps): update dependency mongoose to v7.6.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3345](https://github.com/midwayjs/midway/pull/3345) chore(deps): update dependency @vercel/ncc to v0.38.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3332](https://github.com/midwayjs/midway/pull/3332) chore(deps): update dependency lerna to v7.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `consul` * [#3346](https://github.com/midwayjs/midway/pull/3346) chore(deps): update dependency nock to v13.3.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#3336](https://github.com/midwayjs/midway/pull/3336) chore(deps): update dependency @types/body-parser to v1.19.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3330](https://github.com/midwayjs/midway/pull/3330) chore(deps): update mikro-orm monorepo to v5.8.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * ZhengChao ([@SmartOrange](https://github.com/SmartOrange)) --- # v3.12.9 2023年11月2日 [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3382](https://github.com/midwayjs/midway/pull/3382) fix(swagger): api property should support $ref ([@odex21](https://github.com/odex21)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `consul` * [#3373](https://github.com/midwayjs/midway/pull/3373) chore(deps): update dependency nock to v13.3.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3375](https://github.com/midwayjs/midway/pull/3375) chore(deps): update dependency mongoose to v7.6.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#3364](https://github.com/midwayjs/midway/pull/3364) fix(deps): update dependency @types/ali-oss to v6.16.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * [@odex21](https://github.com/odex21) --- # v3.13.0 2023年11月13日 [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `bootstrap`, `bull`, `core`, `cron`, `faas`, `grpc`, `kafka`, `mock`, `rabbitmq`, `socketio`, `typeorm`, `web-express`, `web-koa`, `web`, `ws` * [#3328](https://github.com/midwayjs/midway/pull/3328) feat: support v3 logger ([@czy88840616](https://github.com/czy88840616)) * `jwt` * [#3261](https://github.com/midwayjs/midway/pull/3261) feat: config separated options for verify & decode and bug fixes ([@ghostoy](https://github.com/ghostoy)) * `core`, `info` * [#3381](https://github.com/midwayjs/midway/pull/3381) feat: add build-in healthService ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3247](https://github.com/midwayjs/midway/pull/3247) fix: sort with imports sequence before framework run ([@czy88840616](https://github.com/czy88840616)) * `static-file` * [#3422](https://github.com/midwayjs/midway/pull/3422) fix: static file component namespace ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `jwt` * [#3425](https://github.com/midwayjs/midway/pull/3425) chore: export default jwt instance ([@czy88840616](https://github.com/czy88840616)) * `http-proxy` * [#3391](https://github.com/midwayjs/midway/pull/3391) feat: add enable config for http-proxy ([@czy88840616](https://github.com/czy88840616)) * `faas`, `passport`, `web-koa`, `web` * [#3402](https://github.com/midwayjs/midway/pull/3402) fix: context.state property override when context typings merge ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3417](https://github.com/midwayjs/midway/pull/3417) docs(session): Supplementary explanation on SameSite = None ([@cyjake](https://github.com/cyjake)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `core`, `web-koa` * [#2975](https://github.com/midwayjs/midway/pull/2975) fix(deps): update dependency koa to v2.14.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock` * [#3420](https://github.com/midwayjs/midway/pull/3420) fix(deps): update dependency @types/supertest to v2.0.16 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3421](https://github.com/midwayjs/midway/pull/3421) fix(deps): update dependency axios to v1.6.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#3418](https://github.com/midwayjs/midway/pull/3418) fix(deps): update dependency @types/ali-oss to v6.16.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#3419](https://github.com/midwayjs/midway/pull/3419) fix(deps): update dependency @types/jsonwebtoken to v9.0.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#3410](https://github.com/midwayjs/midway/pull/3410) chore(deps): update dependency @opentelemetry/sdk-node to v0.45.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3408](https://github.com/midwayjs/midway/pull/3408) chore(deps): update mikro-orm monorepo to v5.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Chen Yangjian ([@cyjake](https://github.com/cyjake)) * Cong Liu ([@ghostoy](https://github.com/ghostoy)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.1 2023年11月13日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#3427](https://github.com/midwayjs/midway/pull/3427) fix: missing default logger dir when cluster mode ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.2 2023年11月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#3428](https://github.com/midwayjs/midway/pull/3428) fix: core logger missing file log name ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.3 2023年11月23日 [![Cong Liu](https://github.com/ghostoy.png)](https://github.com/ghostoy) [![Cong](https://github.com/gucovip.png)](https://github.com/gucovip) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#3448](https://github.com/midwayjs/midway/pull/3448) fix: parsing array of size > 20 in query (#3447) ([@ghostoy](https://github.com/ghostoy)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3443](https://github.com/midwayjs/midway/pull/3443) docs(jwt): Fix a bug in the documentation example where `jwtService` is not retrieved from `this`. ([@gucovip](https://github.com/gucovip)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#3451](https://github.com/midwayjs/midway/pull/3451) chore(deps): update dependency autocannon to v7.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#3441](https://github.com/midwayjs/midway/pull/3441) chore(deps): update dependency @types/koa to v2.13.12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3434](https://github.com/midwayjs/midway/pull/3434) fix(deps): update dependency axios to v1.6.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#3435](https://github.com/midwayjs/midway/pull/3435) fix(deps): update dependency bull to v4.11.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Cong ([@gucovip](https://github.com/gucovip)) * Cong Liu ([@ghostoy](https://github.com/ghostoy)) --- # v3.13.4 2023年12月3日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull`, `cron`, `typeorm`, `web` * [#3474](https://github.com/midwayjs/midway/pull/3474) fix: remove logger v3 compatible ([@czy88840616](https://github.com/czy88840616)) * `web` * [#3456](https://github.com/midwayjs/midway/pull/3456) fix: web default config ([@czy88840616](https://github.com/czy88840616)) * [#3455](https://github.com/midwayjs/midway/pull/3455) fix(web): default app logger name error in cluster mode ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board` * [#3468](https://github.com/midwayjs/midway/pull/3468) fix(deps): update bull monorepo to v5.10.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#3469](https://github.com/midwayjs/midway/pull/3469) fix(deps): update dependency casbin to v5.28.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `captcha`, `security` * [#3452](https://github.com/midwayjs/midway/pull/3452) fix(deps): update dependency nanoid to v3.3.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#3453](https://github.com/midwayjs/midway/pull/3453) fix(deps): update dependency @opentelemetry/api to v1.7.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.5 2023年12月5日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bootstrap`, `core` * [#3462](https://github.com/midwayjs/midway/pull/3462) feat: add main framework missing error ([@czy88840616](https://github.com/czy88840616)) * `core` * [#3478](https://github.com/midwayjs/midway/pull/3478) feat: export http client options typings ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.6 2023年12月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![tommy.hu](https://github.com/freedomdebug.png)](https://github.com/freedomdebug) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `session` * [#3499](https://github.com/midwayjs/midway/pull/3499) fix: add regenerate method for session security ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3490](https://github.com/midwayjs/midway/pull/3490) docs: update validate.md ([@freedomdebug](https://github.com/freedomdebug)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `sequelize` * [#3493](https://github.com/midwayjs/midway/pull/3493) chore(deps): update dependency sequelize to v6.35.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3487](https://github.com/midwayjs/midway/pull/3487) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.12.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3486](https://github.com/midwayjs/midway/pull/3486) fix(deps): update bull monorepo to v5.10.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * tommy.hu ([@freedomdebug](https://github.com/freedomdebug)) --- # v3.13.7 2023年12月15日 ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `leoric` * [#3501](https://github.com/midwayjs/midway/pull/3501) fix(deps): update dependency leoric to v2.12.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core` * [#3502](https://github.com/midwayjs/midway/pull/3502) fix(deps): update dependency reflect-metadata to v0.2.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) --- # v3.13.8 2023年12月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web` * [#3507](https://github.com/midwayjs/midway/pull/3507) fix: wrong agent logger ([@czy88840616](https://github.com/czy88840616)) * `mock` * [#3512](https://github.com/midwayjs/midway/pull/3512) fix: serverless catch error when throw error ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `oss` * [#3515](https://github.com/midwayjs/midway/pull/3515) fix(deps): update dependency ali-oss to v6.19.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#3516](https://github.com/midwayjs/midway/pull/3516) fix(deps): update dependency bull to v4.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.13.9 2023年12月27日 [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock` * [#3521](https://github.com/midwayjs/midway/pull/3521) fix: wrong protocol get in local ([@czy88840616](https://github.com/czy88840616)) * [#3519](https://github.com/midwayjs/midway/pull/3519) fix: support custom args pass through ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `leoric` * [#3509](https://github.com/midwayjs/midway/pull/3509) feat: inject ctx and app to leoric models ([@cyjake](https://github.com/cyjake)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#3363](https://github.com/midwayjs/midway/pull/3363) fix(deps): update dependency @grpc/grpc-js to v1.9.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Chen Yangjian ([@cyjake](https://github.com/cyjake)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.0 2024年1月13日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![flyingcrp](https://github.com/flyingcrp.png)](https://github.com/flyingcrp) [![wangwei](https://github.com/qingniaotonghua.png)](https://github.com/qingniaotonghua) [![玄道](https://github.com/xuandao.png)](https://github.com/xuandao) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `cache-manager-redis`, `cache-manager`, `core`, `mikro`, `redis`, `swagger` * [#3556](https://github.com/midwayjs/midway/pull/3556) feat: Release/3.14.0 ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * Other * [#2741](https://github.com/midwayjs/midway/pull/2741) fix: normal return will be close stream ([@czy88840616](https://github.com/czy88840616)) * `swagger` * [#3555](https://github.com/midwayjs/midway/pull/3555) fix: Swagger tags are duplicate, deprecated field in ApiOperation is … ([@qingniaotonghua](https://github.com/qingniaotonghua)) * `redis` * [#3533](https://github.com/midwayjs/midway/pull/3533) fix(redis): Check the status of the redis client before closing redis ([@flyingcrp](https://github.com/flyingcrp)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#3557](https://github.com/midwayjs/midway/pull/3557) chore(deps): update mikro-orm monorepo to v6.0.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3551](https://github.com/midwayjs/midway/pull/3551) fix(deps): update dependency axios to v1.6.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3535](https://github.com/midwayjs/midway/pull/3535) fix(deps): update dependency axios to v1.6.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3523](https://github.com/midwayjs/midway/pull/3523) fix(deps): update dependency axios to v1.6.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#3552](https://github.com/midwayjs/midway/pull/3552) fix(deps): update socket.io packages to v4.7.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3534](https://github.com/midwayjs/midway/pull/3534) fix(deps): update bull monorepo to v5.10.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `typeorm` * [#3532](https://github.com/midwayjs/midway/pull/3532) chore(deps): update dependency typeorm to v0.3.19 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#3524](https://github.com/midwayjs/midway/pull/3524) fix(deps): update dependency ws to v8.16.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * flyingcrp ([@flyingcrp](https://github.com/flyingcrp)) * wangwei ([@qingniaotonghua](https://github.com/qingniaotonghua)) * 玄道 ([@xuandao](https://github.com/xuandao)) --- # v3.14.1 2024年1月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3559](https://github.com/midwayjs/midway/pull/3559) fix: swagger-ui-dist require missing ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.10 2024年2月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![旧梦](https://github.com/jiumengs.png)](https://github.com/jiumengs) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `passport` * [#3617](https://github.com/midwayjs/midway/pull/3617) fix: isAuthenticated missing this ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3605](https://github.com/midwayjs/midway/pull/3605) docs: update http-proxy.md ([@jiumengs](https://github.com/jiumengs)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#3616](https://github.com/midwayjs/midway/pull/3616) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.13.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#3615](https://github.com/midwayjs/midway/pull/3615) fix(deps): update dependency ali-oss to v6.20.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session`, `passport` * [#3604](https://github.com/midwayjs/midway/pull/3604) chore(deps): update dependency express-session to v1.18.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 旧梦 ([@jiumengs](https://github.com/jiumengs)) --- # v3.14.11 2024年2月7日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3630](https://github.com/midwayjs/midway/pull/3630) fix: ignore custom param decorator in swagger ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#3627](https://github.com/midwayjs/midway/pull/3627) chore(deps): update mikro-orm monorepo to v6.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#3623](https://github.com/midwayjs/midway/pull/3623) chore(deps): update dependency swagger-ui-dist to v5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `consul`, `core` * [#3622](https://github.com/midwayjs/midway/pull/3622) chore(deps): update dependency sinon to v17 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#3035](https://github.com/midwayjs/midway/pull/3035) chore(deps): update dependency egg-logger to v3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3618](https://github.com/midwayjs/midway/pull/3618) fix(deps): update dependency joi to v17.12.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3614](https://github.com/midwayjs/midway/pull/3614) chore(deps): update dependency @types/node to v18.19.14 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3620](https://github.com/midwayjs/midway/pull/3620) chore(deps): update codecov/codecov-action action to v4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#3619](https://github.com/midwayjs/midway/pull/3619) fix(deps): update dependency koa to v2.15.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.12 2024年2月17日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#3648](https://github.com/midwayjs/midway/pull/3648) fix: ctx get logger with custom logger ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `swagger` * [#3631](https://github.com/midwayjs/midway/pull/3631) chore(deps): update dependency swagger-ui-dist to v5.11.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.13 2024年2月18日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3652](https://github.com/midwayjs/midway/pull/3652) fix: missing swagger ui render options ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.2 2024年1月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3560](https://github.com/midwayjs/midway/pull/3560) fix: swagger render json not match path ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.3 2024年1月16日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `captcha`, `mock` * [#3570](https://github.com/midwayjs/midway/pull/3570) feat: captcha use newest cacheManager component ([@czy88840616](https://github.com/czy88840616)) * `cache-manager-redis`, `cache-manager`, `core`, `mongoose` * [#3569](https://github.com/midwayjs/midway/pull/3569) feat: export health service and support mongoose health check ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.4 2024年1月18日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cache-manager`, `captcha`, `web-koa` * [#3572](https://github.com/midwayjs/midway/pull/3572) fix: captcha time use seconds ([@czy88840616](https://github.com/czy88840616)) * `core` * [#3573](https://github.com/midwayjs/midway/pull/3573) fix: lifecycle inject fail in configuration ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.5 2024年1月18日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mikro` * [#3574](https://github.com/midwayjs/midway/pull/3574) fix: entityManager chaos under multiple instances ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.6 2024年1月19日 [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3578](https://github.com/midwayjs/midway/pull/3578) swagger-UI not show exception after fixing global configuration ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#3576](https://github.com/midwayjs/midway/pull/3576) fix(deps): update dependency @grpc/grpc-js to v1.9.14 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) --- # v3.14.7 2024年1月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock` * [#3579](https://github.com/midwayjs/midway/pull/3579) fix: app throw initialize error when invoke close method ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `ws` * [#3582](https://github.com/midwayjs/midway/pull/3582) feat: support heartbeat for ws ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos`, `oss` * [#3581](https://github.com/midwayjs/midway/pull/3581) chore(deps): update dependency dotenv to v16.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.14.8 2024年1月22日 [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3583](https://github.com/midwayjs/midway/pull/3583) fix(swagger): Updated test cases to fix duplicate interface addresses… ([@mmdapl](https://github.com/mmdapl)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) --- # v3.14.9 2024年1月28日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) [![易良](https://github.com/yiliang114.png)](https://github.com/yiliang114) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `swagger`, `ws` * [#3601](https://github.com/midwayjs/midway/pull/3601) feat: custom Ignore swagger endpoint ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3588](https://github.com/midwayjs/midway/pull/3588) docs: update egg.md ([@yiliang114](https://github.com/yiliang114)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board`, `bull` * [#3593](https://github.com/midwayjs/midway/pull/3593) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3592](https://github.com/midwayjs/midway/pull/3592) fix(deps): update dependency axios to v1.6.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos`, `oss` * [#3589](https://github.com/midwayjs/midway/pull/3589) chore(deps): update dependency dotenv to v16.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `typeorm` * [#3597](https://github.com/midwayjs/midway/pull/3597) chore(deps): update dependency typeorm to v0.3.20 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) * 易良 ([@yiliang114](https://github.com/yiliang114)) --- # v3.15.0 2024年2月21日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `swagger` * [#3659](https://github.com/midwayjs/midway/pull/3659) feat: add ApiExcludeSecurity decorator ([@czy88840616](https://github.com/czy88840616)) * `core`, `kafka`, `mqtt`, `rabbitmq` * [#3658](https://github.com/midwayjs/midway/pull/3658) feat: add mqtt module ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#3655](https://github.com/midwayjs/midway/pull/3655) feat: support custom param decorator throw error ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board` * [#3645](https://github.com/midwayjs/midway/pull/3645) fix(deps): update bull monorepo to v5.14.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#3624](https://github.com/midwayjs/midway/pull/3624) fix(deps): update dependency @koa/router to v12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3634](https://github.com/midwayjs/midway/pull/3634) fix(deps): update dependency @grpc/grpc-js to v1.10.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#3643](https://github.com/midwayjs/midway/pull/3643) chore(deps): update dependency swagger-ui-dist to v5.11.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos`, `oss` * [#3657](https://github.com/midwayjs/midway/pull/3657) chore(deps): update dependency dotenv to v16.4.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.1 2024年2月27日 [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull` * [#3671](https://github.com/midwayjs/midway/pull/3671) fix: use bull logger when queue emit error ([@czy88840616](https://github.com/czy88840616)) * `passport` * [#3669](https://github.com/midwayjs/midway/pull/3669) fix: passport missing ctx.setHeader ([@odex21](https://github.com/odex21)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3666](https://github.com/midwayjs/midway/pull/3666) docs: bull incompatibility with aliyun redis proxy mode ([@cyjake](https://github.com/cyjake)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `consul` * [#3668](https://github.com/midwayjs/midway/pull/3668) chore(deps): update dependency nock to v13.5.4 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session` * [#3670](https://github.com/midwayjs/midway/pull/3670) chore(deps): update dependency @types/express-session to v1.18.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3660](https://github.com/midwayjs/midway/pull/3660) chore(deps): update mikro-orm monorepo to v6.1.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#3664](https://github.com/midwayjs/midway/pull/3664) chore(deps): update dependency swagger-ui-dist to v5.11.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#3663](https://github.com/midwayjs/midway/pull/3663) fix(deps): update dependency @types/koa to v2.15.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3662](https://github.com/midwayjs/midway/pull/3662) fix(deps): update dependency joi to v17.12.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Chen Yangjian ([@cyjake](https://github.com/cyjake)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@odex21](https://github.com/odex21) --- # v3.15.10 2024年4月19日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Daniel Xu](https://github.com/DanielXuuuuu.png)](https://github.com/DanielXuuuuu) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull-board` * [#3798](https://github.com/midwayjs/midway/pull/3798) refactor: add the bullBoardManager class along with documentation ([@czy88840616](https://github.com/czy88840616)) * [#3791](https://github.com/midwayjs/midway/pull/3791) feat(bull-board): save the result of createBullBoard ([@DanielXuuuuu](https://github.com/DanielXuuuuu)) * `web-express`, `web-koa`, `web` * [#3797](https://github.com/midwayjs/midway/pull/3797) feat Support http server opts ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3788](https://github.com/midwayjs/midway/pull/3788) fix(docs): typo ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board`, `view-ejs` * [#3792](https://github.com/midwayjs/midway/pull/3792) fix(deps): update dependency ejs to v3.1.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#3793](https://github.com/midwayjs/midway/pull/3793) fix(deps): update dependency leoric to v2.12.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Daniel Xu ([@DanielXuuuuu](https://github.com/DanielXuuuuu)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.15.11 2024年4月25日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `express-session`, `web-express`, `web-koa`, `web` * [#3807](https://github.com/midwayjs/midway/pull/3807) fix: certificate error in web scene ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `otel` * [#3805](https://github.com/midwayjs/midway/pull/3805) chore(deps): update dependency @opentelemetry/sdk-node to v0.51.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3806](https://github.com/midwayjs/midway/pull/3806) chore(deps): update mikro-orm monorepo to v6.2.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.2 2024年3月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `axios` * [#3680](https://github.com/midwayjs/midway/pull/3680) chore: use Axios for interface export ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `swagger` * [#3690](https://github.com/midwayjs/midway/pull/3690) chore(deps): update dependency swagger-ui-dist to v5.11.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3685](https://github.com/midwayjs/midway/pull/3685) chore(deps): update dependency swagger-ui-dist to v5.11.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3693](https://github.com/midwayjs/midway/pull/3693) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.13.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#3694](https://github.com/midwayjs/midway/pull/3694) fix(deps): update dependency express to v4.18.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3686](https://github.com/midwayjs/midway/pull/3686) chore(deps): update mikro-orm monorepo to v6.1.7 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#3678](https://github.com/midwayjs/midway/pull/3678) fix(deps): update dependency @types/jsonwebtoken to v9.0.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#3676](https://github.com/midwayjs/midway/pull/3676) chore(deps): update dependency @opentelemetry/sdk-node to v0.49.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3677](https://github.com/midwayjs/midway/pull/3677) fix(deps): update bull monorepo to v5.14.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.3 2024年3月16日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull` * [#3707](https://github.com/midwayjs/midway/pull/3707) fix: bullLogger with undefined value when emit error ([@czy88840616](https://github.com/czy88840616)) * `mikro` * [#3704](https://github.com/midwayjs/midway/pull/3704) fix(mikro): RequestContext middleware ([@odex21](https://github.com/odex21)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `mikro` * [#3708](https://github.com/midwayjs/midway/pull/3708) chore: update request content middleware and use default source name … ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#3702](https://github.com/midwayjs/midway/pull/3702) fix(deps): update dependency @grpc/grpc-js to v1.10.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `security` * [#3703](https://github.com/midwayjs/midway/pull/3703) fix(deps): update dependency xss to v1.0.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@odex21](https://github.com/odex21) --- # v3.15.4 2024年3月18日 [![odex21](https://github.com/odex21.png)](https://github.com/odex21) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mikro` * [#3709](https://github.com/midwayjs/midway/pull/3709) fix(mikro): Ensure dataSourceName/contextName used in InjectRepository ([@odex21](https://github.com/odex21)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * [@odex21](https://github.com/odex21) --- # v3.15.5 2024年3月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![jingmingji](https://github.com/jingmingji.png)](https://github.com/jingmingji) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cache-manager` * [#3715](https://github.com/midwayjs/midway/pull/3715) fix: cache manager cache key overwrite when use custom logic ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3714](https://github.com/midwayjs/midway/pull/3714) the dosc fix of extension casbin ([@jingmingji](https://github.com/jingmingji)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#3711](https://github.com/midwayjs/midway/pull/3711) chore(deps): update mikro-orm monorepo to v6.1.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@jingmingji](https://github.com/jingmingji) --- # v3.15.6 2024年3月24日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `faas` * [#3722](https://github.com/midwayjs/midway/pull/3722) fix: enable console transport in serverless env ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `core`, `web-koa` * [#3718](https://github.com/midwayjs/midway/pull/3718) fix(deps): update dependency koa to v2.15.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3717](https://github.com/midwayjs/midway/pull/3717) fix(deps): update dependency axios to v1.6.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.7 2024年4月1日 [![Bacuuu](https://github.com/Bacuuu.png)](https://github.com/Bacuuu) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `upload` * [#3734](https://github.com/midwayjs/midway/pull/3734) fix(upload):parameter "whitelist" supports the function type ([@Bacuuu](https://github.com/Bacuuu)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `upload` * [#3741](https://github.com/midwayjs/midway/pull/3741) feat: support upload mime type white list using function type ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#3729](https://github.com/midwayjs/midway/pull/3729) fix(deps): update dependency @grpc/proto-loader to v0.7.12 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3728](https://github.com/midwayjs/midway/pull/3728) fix(deps): update dependency @grpc/grpc-js to v1.10.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `sequelize` * [#3736](https://github.com/midwayjs/midway/pull/3736) chore(deps): update dependency sequelize to v6.37.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#3724](https://github.com/midwayjs/midway/pull/3724) fix(deps): update dependency express to v4.19.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Bacuuu ([@Bacuuu](https://github.com/Bacuuu)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.8 2024年4月12日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `socketio` * [#3764](https://github.com/midwayjs/midway/pull/3764) fix: socket with regexp namespace ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#3780](https://github.com/midwayjs/midway/pull/3780) chore(deps): update dessant/lock-threads action to v5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#3769](https://github.com/midwayjs/midway/pull/3769) fix(deps): update socket.io packages to v4.7.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#3777](https://github.com/midwayjs/midway/pull/3777) fix(deps): update dependency qs to v6.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `static-file` * [#3778](https://github.com/midwayjs/midway/pull/3778) fix(deps): update dependency ylru to v1.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#3776](https://github.com/midwayjs/midway/pull/3776) fix(deps): update dependency @opentelemetry/api to v1.8.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `tablestore` * [#3774](https://github.com/midwayjs/midway/pull/3774) fix(deps): update dependency tablestore to v5.5.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3773](https://github.com/midwayjs/midway/pull/3773) fix(deps): update dependency mqtt to v5.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#3772](https://github.com/midwayjs/midway/pull/3772) fix(deps): update dependency casbin to v5.29.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cron` * [#3771](https://github.com/midwayjs/midway/pull/3771) fix(deps): update dependency @types/cron to v2.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3770](https://github.com/midwayjs/midway/pull/3770) fix(deps): update bull monorepo to v5.15.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3767](https://github.com/midwayjs/midway/pull/3767) fix(deps): update dependency joi to v17.12.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#3768](https://github.com/midwayjs/midway/pull/3768) fix(deps): update dependency koa to v2.15.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3747](https://github.com/midwayjs/midway/pull/3747) fix(deps): update dependency @grpc/grpc-js to v1.10.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3748](https://github.com/midwayjs/midway/pull/3748) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.13.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.15.9 2024年4月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cron` * [#3786](https://github.com/midwayjs/midway/pull/3786) fix: remove typings from the cron module since it includes its own types ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.16.0 2024年5月6日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `web-koa` * [#3751](https://github.com/midwayjs/midway/pull/3751) feat: parse array query by qs ([@czy88840616](https://github.com/czy88840616)) * `core`, `tenant` * [#3762](https://github.com/midwayjs/midway/pull/3762) feat: add tenant component with tenant manager ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3756](https://github.com/midwayjs/midway/pull/3756) refactor: Refactor swagger module ([@czy88840616](https://github.com/czy88840616)) * `core` * [#3700](https://github.com/midwayjs/midway/pull/3700) fix: health check missing this resolver ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#3710](https://github.com/midwayjs/midway/pull/3710) feat: add instance args for parameter decorator options ([@czy88840616](https://github.com/czy88840616)) * `mock`, `mqtt` * [#3699](https://github.com/midwayjs/midway/pull/3699) feat: support dynamic create mqtt consumer ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `casbin-redis-adapter`, `redis` * [#3827](https://github.com/midwayjs/midway/pull/3827) fix(deps): update dependency ioredis to v5.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3825](https://github.com/midwayjs/midway/pull/3825) fix(deps): update bull monorepo to v5.17.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#3811](https://github.com/midwayjs/midway/pull/3811) fix(deps): update dependency qs to v6.12.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `tablestore` * [#3824](https://github.com/midwayjs/midway/pull/3824) fix(deps): update dependency tablestore to v5.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3823](https://github.com/midwayjs/midway/pull/3823) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.13.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#3829](https://github.com/midwayjs/midway/pull/3829) fix(deps): update dependency ws to v8.17.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3828](https://github.com/midwayjs/midway/pull/3828) fix(deps): update dependency joi to v17.13.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#3826](https://github.com/midwayjs/midway/pull/3826) fix(deps): update dependency casbin to v5.30.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core` * [#3775](https://github.com/midwayjs/midway/pull/3775) fix(deps): update dependency reflect-metadata to v0.2.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3818](https://github.com/midwayjs/midway/pull/3818) fix(deps): update dependency @grpc/proto-loader to v0.7.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3817](https://github.com/midwayjs/midway/pull/3817) fix(deps): update dependency @grpc/grpc-js to v1.10.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#3822](https://github.com/midwayjs/midway/pull/3822) chore(deps): update dependency swagger-ui-dist to v5.17.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3819](https://github.com/midwayjs/midway/pull/3819) chore(deps): update mikro-orm monorepo to v6.2.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3810](https://github.com/midwayjs/midway/pull/3810) fix(deps): update dependency mqtt to v5.5.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.16.1 2024年5月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![flyingcrp](https://github.com/flyingcrp.png)](https://github.com/flyingcrp) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `tenant` * [#3840](https://github.com/midwayjs/midway/pull/3840) fix: export named error for tenant component ([@czy88840616](https://github.com/czy88840616)) * `web-koa` * [#3842](https://github.com/midwayjs/midway/pull/3842) fix: make request.query writeable ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3833](https://github.com/midwayjs/midway/pull/3833) docs: update orm.md ([@flyingcrp](https://github.com/flyingcrp)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 陈十一 ([@flyingcrp](https://github.com/flyingcrp)) --- # v3.16.2 2024年6月1日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![拓荒](https://github.com/tuohuang.png)](https://github.com/tuohuang) [![Gavin](https://github.com/wjw-gavin.png)](https://github.com/wjw-gavin) [![xlaoyu](https://github.com/Yuliang-Lee.png)](https://github.com/Yuliang-Lee) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#3886](https://github.com/midwayjs/midway/pull/3886) fix(swagger): miss dto required from schema ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3871](https://github.com/midwayjs/midway/pull/3871) docs: update release schedule docs, mark v2 as EOL ([@Yuliang-Lee](https://github.com/Yuliang-Lee)) * [#3854](https://github.com/midwayjs/midway/pull/3854) docs: fix typo in mock.md ([@wjw-gavin](https://github.com/wjw-gavin)) * [#3849](https://github.com/midwayjs/midway/pull/3849) docs: update en version tenant.md ([@tuohuang](https://github.com/tuohuang)) * [#3848](https://github.com/midwayjs/midway/pull/3848) docs: update tenant.md ([@tuohuang](https://github.com/tuohuang)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull-board`, `bull` * [#3881](https://github.com/midwayjs/midway/pull/3881) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3844](https://github.com/midwayjs/midway/pull/3844) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3882](https://github.com/midwayjs/midway/pull/3882) fix(deps): update dependency axios to v1.7.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#3874](https://github.com/midwayjs/midway/pull/3874) chore(deps): update dependency swagger-ui-dist to v5.17.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3869](https://github.com/midwayjs/midway/pull/3869) fix(deps): update dependency @grpc/grpc-js to v1.10.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3870](https://github.com/midwayjs/midway/pull/3870) chore(deps): update supercharge/mongodb-github-action action to v1.11.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3860](https://github.com/midwayjs/midway/pull/3860) chore(deps): update dependency ts-jest to v29.1.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#3781](https://github.com/midwayjs/midway/pull/3781) chore(deps): update mongoose monorepo (major) ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#3856](https://github.com/midwayjs/midway/pull/3856) chore(deps): update mikro-orm monorepo to v6.2.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Gavin ([@wjw-gavin](https://github.com/wjw-gavin)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * xlaoyu ([@Yuliang-Lee](https://github.com/Yuliang-Lee)) * 拓荒 ([@tuohuang](https://github.com/tuohuang)) --- # v3.16.3 2024年6月6日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cache-manager` * [#3889](https://github.com/midwayjs/midway/pull/3889) fix: get origin value from redis store ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `otel` * [#3894](https://github.com/midwayjs/midway/pull/3894) fix(deps): update dependency @opentelemetry/api to v1.9.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3895](https://github.com/midwayjs/midway/pull/3895) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3893](https://github.com/midwayjs/midway/pull/3893) fix(deps): update bull monorepo to v5.20.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3896](https://github.com/midwayjs/midway/pull/3896) fix(deps): update dependency mqtt to v5.7.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3845](https://github.com/midwayjs/midway/pull/3845) chore(deps): update dependency @types/node to v20 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.16.4 2024年6月29日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3899](https://github.com/midwayjs/midway/pull/3899) docs(site): update awesome\_midway.md ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mqtt` * [#3928](https://github.com/midwayjs/midway/pull/3928) fix(deps): update dependency mqtt to v5.7.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validate` * [#3918](https://github.com/midwayjs/midway/pull/3918) fix(deps): update dependency joi to v17.13.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#3912](https://github.com/midwayjs/midway/pull/3912) fix(deps): update dependency ws to v8.17.1 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3924](https://github.com/midwayjs/midway/pull/3924) fix(deps): update dependency @grpc/grpc-js to v1.10.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3901](https://github.com/midwayjs/midway/pull/3901) fix(deps): update dependency @grpc/grpc-js to v1.10.9 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board`, `bull` * [#3917](https://github.com/midwayjs/midway/pull/3917) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#3925](https://github.com/midwayjs/midway/pull/3925) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#3904](https://github.com/midwayjs/midway/pull/3904) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#3905](https://github.com/midwayjs/midway/pull/3905) fix(deps): update dependency bull to v4.13.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cache-manager` * [#3897](https://github.com/midwayjs/midway/pull/3897) chore(deps): update dependency cache-manager-ioredis-yet to v2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#3898](https://github.com/midwayjs/midway/pull/3898) chore(deps): update dependency egg-scripts to v3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.16.5 2024年7月15日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![MrDotYan](https://github.com/MrDotYan.png)](https://github.com/MrDotYan) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#3929](https://github.com/midwayjs/midway/pull/3929) docs: update awesome\_midway.md ([@MrDotYan](https://github.com/MrDotYan)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#3948](https://github.com/midwayjs/midway/pull/3948) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3947](https://github.com/midwayjs/midway/pull/3947) fix(deps): update dependency @grpc/grpc-js to v1.10.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#3939](https://github.com/midwayjs/midway/pull/3939) chore(deps): update dependency why-is-node-running to v2.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3937](https://github.com/midwayjs/midway/pull/3937) fix(deps): update dependency mqtt to v5.8.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#3938](https://github.com/midwayjs/midway/pull/3938) fix(deps): update dependency ws to v8.18.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#3932](https://github.com/midwayjs/midway/pull/3932) fix(deps): update dependency qs to v6.12.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#3933](https://github.com/midwayjs/midway/pull/3933) fix(deps): update dependency bull to v4.15.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@MrDotYan](https://github.com/MrDotYan) --- # v3.16.6 2024年7月26日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `upload` * [#3971](https://github.com/midwayjs/midway/pull/3971) feat: add allowFieldsDuplication options ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa`, `web` * [#3974](https://github.com/midwayjs/midway/pull/3974) fix(deps): update dependency qs to v6.12.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#3975](https://github.com/midwayjs/midway/pull/3975) fix(deps): update bull monorepo to v5.21.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap` * [#3977](https://github.com/midwayjs/midway/pull/3977) fix(deps): update dependency @midwayjs/event-bus to v1.10.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#3976](https://github.com/midwayjs/midway/pull/3976) fix(deps): update dependency @grpc/grpc-js to v1.11.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `ws` * [#3958](https://github.com/midwayjs/midway/pull/3958) fix(deps): update dependency @types/ws to v8.5.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3959](https://github.com/midwayjs/midway/pull/3959) fix(deps): update dependency mqtt to v5.8.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.16.7 2024年7月26日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `upload` * [#3981](https://github.com/midwayjs/midway/pull/3981) fix: single field when allowFieldsDuplication enabled ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#3973](https://github.com/midwayjs/midway/pull/3973) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.16.8 2024年8月3日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `sequelize` * [#3993](https://github.com/midwayjs/midway/pull/3993) fix: remove authenticate when create data source ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa`, `web` * [#3995](https://github.com/midwayjs/midway/pull/3995) fix(deps): update dependency qs to v6.13.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `ws` * [#3988](https://github.com/midwayjs/midway/pull/3988) fix(deps): update dependency @types/ws to v8.5.12 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#3990](https://github.com/midwayjs/midway/pull/3990) fix(deps): update dependency bull to v4.16.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#3991](https://github.com/midwayjs/midway/pull/3991) fix(deps): update dependency mqtt to v5.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#3989](https://github.com/midwayjs/midway/pull/3989) fix(deps): update dependency axios to v1.7.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.17.0 2024年8月29日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![NoKic233](https://github.com/Nokic233.png)](https://github.com/Nokic233) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core` * [#3982](https://github.com/midwayjs/midway/pull/3982) feat: support response helper and sse util ([@czy88840616](https://github.com/czy88840616)) * `busboy`, `core` * [#3875](https://github.com/midwayjs/midway/pull/3875) refactor: upload component use busboy ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `i18n` * [#3931](https://github.com/midwayjs/midway/pull/3931) fix: Incorrect group format is used in i18n component ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#4013](https://github.com/midwayjs/midway/pull/4013) fix(core): DataSourceManagerConfigOption generic OPTIONS now no changes by PowerPartial ([@waitingsong](https://github.com/waitingsong)) * `busboy`, `core` * [#3875](https://github.com/midwayjs/midway/pull/3875) refactor: upload component use busboy ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4018](https://github.com/midwayjs/midway/pull/4018) docs(awesome\_midway): add @mwcp/pgmq ([@waitingsong](https://github.com/waitingsong)) * [#4008](https://github.com/midwayjs/midway/pull/4008) docs: extensions koa typo ([@Nokic233](https://github.com/Nokic233)) * [#4007](https://github.com/midwayjs/midway/pull/4007) docs: fix typo ([@Nokic233](https://github.com/Nokic233)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#4036](https://github.com/midwayjs/midway/pull/4036) chore(deps): update dependency @types/node to v20.16.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#4011](https://github.com/midwayjs/midway/pull/4011) fix(deps): update dependency axios to v1.7.4 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#4015](https://github.com/midwayjs/midway/pull/4015) fix(deps): update bull monorepo to v5.21.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4005](https://github.com/midwayjs/midway/pull/4005) fix(deps): update bull monorepo to v5.21.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#4016](https://github.com/midwayjs/midway/pull/4016) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4030](https://github.com/midwayjs/midway/pull/4030) fix(deps): update dependency ali-oss to v6.21.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4031](https://github.com/midwayjs/midway/pull/4031) fix(deps): update dependency mqtt to v5.10.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * NoKic233 ([@Nokic233](https://github.com/Nokic233)) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.17.1 2024年9月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![xlaoyu](https://github.com/Yuliang-Lee.png)](https://github.com/Yuliang-Lee) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `kafka` * [#4046](https://github.com/midwayjs/midway/pull/4046) fix(kafkajs): Fix the issue where the consumer method of the kafkajs component returns true to trigger a commit parameter error. ([@Yuliang-Lee](https://github.com/Yuliang-Lee)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#4047](https://github.com/midwayjs/midway/pull/4047) feat: add ctx for the static tpl of response ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios`, `http-proxy` * [#4040](https://github.com/midwayjs/midway/pull/4040) fix(deps): update dependency axios to v1.7.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#4041](https://github.com/midwayjs/midway/pull/4041) fix(deps): update dependency bull to v4.16.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * xlaoyu ([@Yuliang-Lee](https://github.com/Yuliang-Lee)) --- # v3.17.2 2024年9月5日 [![fangjin](https://github.com/lengyuxuan.png)](https://github.com/lengyuxuan) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#4050](https://github.com/midwayjs/midway/pull/4050) fix(swagger): miss dto description from schema ([@lengyuxuan](https://github.com/lengyuxuan)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * fangjin ([@lengyuxuan](https://github.com/lengyuxuan)) --- # v3.17.3 2024年9月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#4075](https://github.com/midwayjs/midway/pull/4075) fix: swagger body array type ([@czy88840616](https://github.com/czy88840616)) * [#4062](https://github.com/midwayjs/midway/pull/4062) fix: swagger api tag for router ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#4073](https://github.com/midwayjs/midway/pull/4073) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4067](https://github.com/midwayjs/midway/pull/4067) fix(deps): update dependency express to v4.20.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4066](https://github.com/midwayjs/midway/pull/4066) fix(deps): update dependency body-parser to v1.20.3 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board`, `bull` * [#4072](https://github.com/midwayjs/midway/pull/4072) fix(deps): update bull monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4059](https://github.com/midwayjs/midway/pull/4059) fix(deps): update dependency @grpc/grpc-js to v1.11.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#4060](https://github.com/midwayjs/midway/pull/4060) fix(deps): update dependency axios to v1.7.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.18.0 2024年9月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `busboy`, `core` * [#4074](https://github.com/midwayjs/midway/pull/4074) feat: busboy support async generator mode ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mock`, `web-express`, `web-koa`, `web` * [#4082](https://github.com/midwayjs/midway/pull/4082) fix: showcase of ssl with mwtsc ([@czy88840616](https://github.com/czy88840616)) * `core` * [#4058](https://github.com/midwayjs/midway/pull/4058) fix: http client will be override default options ([@czy88840616](https://github.com/czy88840616)) * `core`, `mongoose` * [#4061](https://github.com/midwayjs/midway/pull/4061) fix: dataSourcePriority missing default value ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4079](https://github.com/midwayjs/midway/pull/4079) fix(deps): update dependency @grpc/grpc-js to v1.11.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4080](https://github.com/midwayjs/midway/pull/4080) fix(deps): update dependency @types/jsonwebtoken to v9.0.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.18.1 2024年9月23日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cache-manager`, `swagger` * [#4083](https://github.com/midwayjs/midway/pull/4083) fix: ensure compatibility with Swagger response schema and fix the parsing of enum types ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.18.2 2024年10月13日 [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4096](https://github.com/midwayjs/midway/pull/4096) docs(awesome\_midway.md): update @mwcp/pgmq ([@waitingsong](https://github.com/waitingsong)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `leoric` * [#4117](https://github.com/midwayjs/midway/pull/4117) fix(deps): update dependency leoric to v2.13.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#4118](https://github.com/midwayjs/midway/pull/4118) fix(deps): update socket.io packages to v4.8.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4116](https://github.com/midwayjs/midway/pull/4116) fix(deps): update dependency express to v4.21.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#4115](https://github.com/midwayjs/midway/pull/4115) fix(deps): update dependency casbin to v5.31.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4105](https://github.com/midwayjs/midway/pull/4105) fix(deps): update dependency @grpc/grpc-js to v1.12.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session`, `passport` * [#4111](https://github.com/midwayjs/midway/pull/4111) chore(deps): update dependency express-session to v1.18.1 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull-board` * [#4104](https://github.com/midwayjs/midway/pull/4104) fix(deps): update bull monorepo to v5.23.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4093](https://github.com/midwayjs/midway/pull/4093) fix(deps): update dependency mqtt to v5.10.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#4092](https://github.com/midwayjs/midway/pull/4092) fix(deps): update dependency @types/qs to v6.9.16 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4086](https://github.com/midwayjs/midway/pull/4086) chore(deps): update dependency @types/node to v20.16.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.19.0 2024年11月8日 [![yanzhifei](https://github.com/bossbaba.png)](https://github.com/bossbaba) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core`, `mock` * [#4151](https://github.com/midwayjs/midway/pull/4151) feat: add grouping for mock data ([@czy88840616](https://github.com/czy88840616)) * `grpc` * [#4159](https://github.com/midwayjs/midway/pull/4159) feat(grpc): GRPCClients.createClient() supports multi services in one .proto file and returns void insted of T ([@waitingsong](https://github.com/waitingsong)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `static-file` * [#4180](https://github.com/midwayjs/midway/pull/4180) fix: static file path handling in pkg environment ([@czy88840616](https://github.com/czy88840616)) * `core` * [#4176](https://github.com/midwayjs/midway/pull/4176) fix: wrong object format for sse response ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core`, `kafka` * [#4154](https://github.com/midwayjs/midway/pull/4154) feat(kafka): refactor framework and add factory service for producer and admin ([@czy88840616](https://github.com/czy88840616)) * `core`, `mock` * [#4150](https://github.com/midwayjs/midway/pull/4150) feat: add performance manager ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4155](https://github.com/midwayjs/midway/pull/4155) docs(awesome\_midway.md): update @mwcp/otel ([@waitingsong](https://github.com/waitingsong)) * [#4131](https://github.com/midwayjs/midway/pull/4131) docs(awesome\_midway.md): add @mwcp/paradedb ([@waitingsong](https://github.com/waitingsong)) * [#4127](https://github.com/midwayjs/midway/pull/4127) docs: update awesome\_midway.md ([@bossbaba](https://github.com/bossbaba)) * [#4124](https://github.com/midwayjs/midway/pull/4124) docs: update awesome\_midway.md ([@bossbaba](https://github.com/bossbaba)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa` * [#4181](https://github.com/midwayjs/midway/pull/4181) fix(deps): update dependency @types/qs to v6.9.17 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `ws` * [#4182](https://github.com/midwayjs/midway/pull/4182) fix(deps): update dependency @types/ws to v8.5.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#4179](https://github.com/midwayjs/midway/pull/4179) chore(deps): update dependency swagger-ui-dist to v5.18.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#4178](https://github.com/midwayjs/midway/pull/4178) chore(deps): update dependency @opentelemetry/sdk-node to v0.54.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#4164](https://github.com/midwayjs/midway/pull/4164) chore(deps): update mongoose monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#4162](https://github.com/midwayjs/midway/pull/4162) fix(deps): update socket.io packages to v4.8.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4163](https://github.com/midwayjs/midway/pull/4163) chore(deps): update dependency @types/node to v22 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#4145](https://github.com/midwayjs/midway/pull/4145) fix(deps): update dependency casbin to v5.32.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * waiting ([@waitingsong](https://github.com/waitingsong)) * yanzhifei ([@bossbaba](https://github.com/bossbaba)) --- # v3.19.1 2024年11月18日 [![Chen Yangjian](https://github.com/cyjake.png)](https://github.com/cyjake) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `leoric` * [#4192](https://github.com/midwayjs/midway/pull/4192) fix(leoric): keep multiple datasources from conflicting base model ([@cyjake](https://github.com/cyjake)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `otel` * [#4193](https://github.com/midwayjs/midway/pull/4193) chore(deps): update dependency @opentelemetry/sdk-node to v0.55.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4191](https://github.com/midwayjs/midway/pull/4191) chore(deps): update dependency @vercel/ncc to v0.38.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4190](https://github.com/midwayjs/midway/pull/4190) fix(deps): update dependency mqtt to v5.10.2 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#4189](https://github.com/midwayjs/midway/pull/4189) fix(deps): update dependency bull to v4.16.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#4185](https://github.com/midwayjs/midway/pull/4185) chore(deps): update dependency mongoose to v8.8.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#4188](https://github.com/midwayjs/midway/pull/4188) chore(deps): update mikro-orm monorepo to v6.4.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `consul` * [#4187](https://github.com/midwayjs/midway/pull/4187) chore(deps): update dependency nock to v13.5.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Chen Yangjian ([@cyjake](https://github.com/cyjake)) --- # v3.19.2 2024年12月15日 [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `info` * [#4220](https://github.com/midwayjs/midway/pull/4220) refactor: add InfoType enumeration to supplement the missing ts syntax type ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#4223](https://github.com/midwayjs/midway/pull/4223) chore(deps): update mikro-orm monorepo to v6.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4227](https://github.com/midwayjs/midway/pull/4227) chore(deps): update dependency @types/node to v22.10.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4214](https://github.com/midwayjs/midway/pull/4214) chore(deps): update dependency typedoc to ^0.27.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4209](https://github.com/midwayjs/midway/pull/4209) chore(deps): update dependency @types/node to v22.10.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4202](https://github.com/midwayjs/midway/pull/4202) chore(deps): update dependency @types/node to v22.10.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4201](https://github.com/midwayjs/midway/pull/4201) chore(deps): update dependency @types/node to v22.9.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4199](https://github.com/midwayjs/midway/pull/4199) chore(deps): update dependency @types/node to v22.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4198](https://github.com/midwayjs/midway/pull/4198) chore(deps): update dependency @types/node to v22.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4195](https://github.com/midwayjs/midway/pull/4195) chore(deps): update dependency @types/node to v22.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4225](https://github.com/midwayjs/midway/pull/4225) fix(deps): update dependency express to v4.21.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#4224](https://github.com/midwayjs/midway/pull/4224) fix(deps): update dependency axios to v1.7.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4226](https://github.com/midwayjs/midway/pull/4226) fix(deps): update dependency mqtt to v5.10.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#4208](https://github.com/midwayjs/midway/pull/4208) chore(deps): update dependency mongoose to v8.8.3 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4194](https://github.com/midwayjs/midway/pull/4194) chore(deps): update dependency mongoose to v8.8.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4215](https://github.com/midwayjs/midway/pull/4215) fix(deps): update dependency @grpc/grpc-js to v1.12.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `captcha`, `security` * [#4222](https://github.com/midwayjs/midway/pull/4222) fix(deps): update dependency nanoid to v3.3.8 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#4213](https://github.com/midwayjs/midway/pull/4213) chore(deps): update dependency egg-logger to v3.6.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#4212](https://github.com/midwayjs/midway/pull/4212) chore(deps): update dependency @opentelemetry/sdk-node to v0.56.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos`, `oss` * [#4211](https://github.com/midwayjs/midway/pull/4211) chore(deps): update dependency dotenv to v16.4.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `rabbitmq` * [#4210](https://github.com/midwayjs/midway/pull/4210) chore(deps): update dependency @types/amqplib to v0.10.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4200](https://github.com/midwayjs/midway/pull/4200) chore(deps): update dependency amqplib to v0.10.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `express-session` * [#4203](https://github.com/midwayjs/midway/pull/4203) chore(deps): update dependency @types/express-session to v1.18.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#4197](https://github.com/midwayjs/midway/pull/4197) fix(deps): update dependency qs to v6.13.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#4196](https://github.com/midwayjs/midway/pull/4196) chore(deps): update dependency @typegoose/typegoose to v12.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) --- # v3.19.3 2024年12月29日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `captcha` * [#4242](https://github.com/midwayjs/midway/pull/4242) fix: use security svg-captcha and add more options ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * `async-hooks-context-manager`, `axios`, `bootstrap`, `bull-board`, `bull`, `busboy`, `cache-manager`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `decorator`, `etcd`, `grpc`, `i18n`, `info`, `kafka`, `leoric`, `mikro`, `mock`, `mongoose`, `mqtt`, `oss`, `otel`, `rabbitmq`, `redis`, `sequelize`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `tenant`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#4232](https://github.com/midwayjs/midway/pull/4232) docs: use https for github domains ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bootstrap` * [#4248](https://github.com/midwayjs/midway/pull/4248) fix(deps): update dependency @midwayjs/event-bus to v1.11.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#4247](https://github.com/midwayjs/midway/pull/4247) chore(deps): update mikro-orm monorepo to v6.4.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#4243](https://github.com/midwayjs/midway/pull/4243) fix(deps): update dependency bull to v4.16.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4245](https://github.com/midwayjs/midway/pull/4245) fix(deps): update dependency ali-oss to v6.22.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#4246](https://github.com/midwayjs/midway/pull/4246) fix(deps): update dependency casbin to v5.36.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `redis` * [#4244](https://github.com/midwayjs/midway/pull/4244) fix(deps): update dependency ioredis to v5.4.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#4240](https://github.com/midwayjs/midway/pull/4240) chore(deps): update dependency egg-logger to v3.6.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4228](https://github.com/midwayjs/midway/pull/4228) chore(deps): update dependency egg-scripts to v3.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4239](https://github.com/midwayjs/midway/pull/4239) fix(deps): update dependency @grpc/grpc-js to v1.12.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#4238](https://github.com/midwayjs/midway/pull/4238) chore(deps): update dependency mongoose to v8.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4233](https://github.com/midwayjs/midway/pull/4233) chore(deps): update dependency mongoose to v8.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4230](https://github.com/midwayjs/midway/pull/4230) chore(deps): update mongoose monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#4235](https://github.com/midwayjs/midway/pull/4235) chore(deps): update dependency @opentelemetry/sdk-node to v0.57.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.2.0 2022年3月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add lock file for site ([ef2bd57](https://github.com/midwayjs/midway/commit/ef2bd5772d49efb4d0b6865670303a5be776d383)) * fix ts build error (orm) ([#1859](https://github.com/midwayjs/midway/issues/1859)) ([c44e18d](https://github.com/midwayjs/midway/commit/c44e18d00f966792e46238c7d8807d5b3c543873)) * logger create failed cause file size too large to create V8 string ([#1854](https://github.com/midwayjs/midway/issues/1854)) ([8a10d03](https://github.com/midwayjs/midway/commit/8a10d033063ef46bb80f1252bfb6815281a940d8)) * swagger getSchemaPath bug ([#1850](https://github.com/midwayjs/midway/issues/1850)) ([e3adda0](https://github.com/midwayjs/midway/commit/e3adda0e4f5c470d44d66b11e2e5b39a7ecc6bea)) * throw error when cluster exec ([#1848](https://github.com/midwayjs/midway/issues/1848)) ([bf0e209](https://github.com/midwayjs/midway/commit/bf0e209ec724ab41b5bc9b43b08d7c44d3b77e3b)) * upload file support more http method ([#1846](https://github.com/midwayjs/midway/issues/1846)) ([7587898](https://github.com/midwayjs/midway/commit/75878986ba69c41f58de1165d07938f094ce9ab2)) ### Features[​](#features "Features的直接链接") * add http proxy component ([#1843](https://github.com/midwayjs/midway/issues/1843)) ([5281e31](https://github.com/midwayjs/midway/commit/5281e316220591b84a0200c6cdf1572680f6e2f6)) --- # v3.2.1 2022年3月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * swagger ui replace json path ([#1860](https://github.com/midwayjs/midway/issues/1860)) ([0f3728d](https://github.com/midwayjs/midway/commit/0f3728daccba12923f23f5b498c7dda13ced36d7)) --- # v3.2.2 2022年3月30日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * match and ignore method missing this ([#1868](https://github.com/midwayjs/midway/issues/1868)) ([4a3800a](https://github.com/midwayjs/midway/commit/4a3800a05a827b2beebc2e22d12ca8b16ffe0548)) * output error ([#1869](https://github.com/midwayjs/midway/issues/1869)) ([e804fc0](https://github.com/midwayjs/midway/commit/e804fc07e4eb07c49e28c8cd2d995401dee71dda)) * typings missing ([#1863](https://github.com/midwayjs/midway/issues/1863)) ([7d684a0](https://github.com/midwayjs/midway/commit/7d684a0b58c2598b3f242343a5c3797e47ba7efd)) --- # v3.20.0 2025年1月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![harperKKK](https://github.com/harperKKK.png)](https://github.com/harperKKK) [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull-board`, `bullmq` * [#4261](https://github.com/midwayjs/midway/pull/4261) refactor: bullmq ([@czy88840616](https://github.com/czy88840616)) * `core`, `typeorm` * [#4262](https://github.com/midwayjs/midway/pull/4262) feat: support custom data source ([@czy88840616](https://github.com/czy88840616)) * `bull`, `bullmq` * [#4257](https://github.com/midwayjs/midway/pull/4257) feat: add package bullmq ([@harperKKK](https://github.com/harperKKK)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * `axios` * [#4231](https://github.com/midwayjs/midway/pull/4231) refactor: axios component ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mongoose`, `typegoose` * [#4253](https://github.com/midwayjs/midway/pull/4253) chore(deps): update dependency mongoose to v8.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@harperKKK](https://github.com/harperKKK) --- # v3.20.1 2025年1月17日 [![Ghoster](https://github.com/ghostker.png)](https://github.com/ghostker) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#4263](https://github.com/midwayjs/midway/pull/4263) fix(swagger): correct typo from 'text/plan' to 'text/plain' ([@ghostker](https://github.com/ghostker)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mongoose`, `typegoose` * [#4264](https://github.com/midwayjs/midway/pull/4264) chore(deps): update dependency mongoose to v8.9.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4256](https://github.com/midwayjs/midway/pull/4256) chore(deps): update dependency @types/node to v22.10.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#4260](https://github.com/midwayjs/midway/pull/4260) chore(deps): update mikro-orm monorepo to v6.4.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Ghoster ([@ghostker](https://github.com/ghostker)) --- # v3.20.10 2025年7月27日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Hongcai Deng](https://github.com/denghongcai.png)](https://github.com/denghongcai) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `ws` * [#4364](https://github.com/midwayjs/midway/pull/4364) fix: heartbeat does not take effect in koa scenario ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `cron` * [#4361](https://github.com/midwayjs/midway/pull/4361) breaking: upgrade cron to 3.5.0, support waitForComplete ([@denghongcai](https://github.com/denghongcai)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * [#4362](https://github.com/midwayjs/midway/pull/4362) fix(deps): update dependency statuses to v2.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Hongcai Deng ([@denghongcai](https://github.com/denghongcai)) --- # v3.20.11 2025年8月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `typeorm` * [#4369](https://github.com/midwayjs/midway/pull/4369) feat: add config allow typeorm migrations ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `core`, `web-koa` * [#4366](https://github.com/midwayjs/midway/pull/4366) fix(deps): update dependency koa to v2.16.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.20.12 2025年8月10日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![He Yongsheng](https://github.com/heyongsheng.png)](https://github.com/heyongsheng) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `web-express`, `web-koa`, `web` * [#4371](https://github.com/midwayjs/midway/pull/4371) feat: add random free port ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4372](https://github.com/midwayjs/midway/pull/4372) docs: update static\_file.md for static directory not found ([@heyongsheng](https://github.com/heyongsheng)) * [#4370](https://github.com/midwayjs/midway/pull/4370) docs: update static\_file.md for static directory not found ([@heyongsheng](https://github.com/heyongsheng)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4355](https://github.com/midwayjs/midway/pull/4355) fix(deps): update dependency @grpc/grpc-js to v1.13.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4373](https://github.com/midwayjs/midway/pull/4373) chore(deps): update mongo docker tag to v4.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * He Yongsheng ([@heyongsheng](https://github.com/heyongsheng)) --- # v3.20.2 2025年1月31日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `kafka` * [#4271](https://github.com/midwayjs/midway/pull/4271) fix: KafkaProducerFactory not init from decorator ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `axios`, `mqtt` * [#4278](https://github.com/midwayjs/midway/pull/4278) feat: add custom axios config typings merge ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa`, `web` * [#4276](https://github.com/midwayjs/midway/pull/4276) fix(deps): update dependency qs to v6.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#4279](https://github.com/midwayjs/midway/pull/4279) chore(deps): update dependency swagger-ui-dist to v5.18.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4281](https://github.com/midwayjs/midway/pull/4281) fix(deps): update dependency @types/jsonwebtoken to v9.0.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4282](https://github.com/midwayjs/midway/pull/4282) chore(deps): update dependency @types/node to v22.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4283](https://github.com/midwayjs/midway/pull/4283) fix(deps): update dependency bullmq to v5.39.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4275](https://github.com/midwayjs/midway/pull/4275) fix(deps): update dependency bullmq to v5.37.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#4284](https://github.com/midwayjs/midway/pull/4284) fix(deps): update dependency casbin to v5.38.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#4280](https://github.com/midwayjs/midway/pull/4280) chore(deps): update mikro-orm monorepo to v6.4.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4273](https://github.com/midwayjs/midway/pull/4273) fix(deps): update dependency leoric to v2.13.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `ws` * [#4272](https://github.com/midwayjs/midway/pull/4272) fix(deps): update dependency @types/ws to v8.5.14 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#4265](https://github.com/midwayjs/midway/pull/4265) chore(deps): update dependency @opentelemetry/sdk-node to v0.57.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4266](https://github.com/midwayjs/midway/pull/4266) chore(deps): update dependency fs-extra to v11.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.20.3 2025年3月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![harperKKK](https://github.com/harperKKK.png)](https://github.com/harperKKK) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull-board`, `bull`, `bullmq`, `busboy`, `core`, `cron`, `validate` * [#4290](https://github.com/midwayjs/midway/pull/4290) fix: #4295 #4293 #4299 #4294 ([@czy88840616](https://github.com/czy88840616)) * `bull-board`, `bullmq` * [#4286](https://github.com/midwayjs/midway/pull/4286) fix(bull-board): init bull board in resolve ([@harperKKK](https://github.com/harperKKK)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#4274](https://github.com/midwayjs/midway/pull/4274) chore(deps): update supercharge/mongodb-github-action action to v1.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4289](https://github.com/midwayjs/midway/pull/4289) fix(deps): update dependency @grpc/grpc-js to v1.12.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#4291](https://github.com/midwayjs/midway/pull/4291) fix(deps): update dependency koa to v2.15.4 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@harperKKK](https://github.com/harperKKK) --- # v3.20.4 2025年4月10日 [![Aaron Liu](https://github.com/liuyuan512.png)](https://github.com/liuyuan512) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `core` * [#4311](https://github.com/midwayjs/midway/pull/4311) chore: add TooManyRequestsError to http error ([@liuyuan512](https://github.com/liuyuan512)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `core`, `web-koa` * [#4322](https://github.com/midwayjs/midway/pull/4322) fix(deps): update dependency koa to v2.16.1 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#4310](https://github.com/midwayjs/midway/pull/4310) fix(deps): update dependency axios to v1.8.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4307](https://github.com/midwayjs/midway/pull/4307) fix(deps): update dependency axios to v1.8.3 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4305](https://github.com/midwayjs/midway/pull/4305) fix(deps): update dependency axios to v1.8.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `captcha`, `security` * [#4319](https://github.com/midwayjs/midway/pull/4319) fix(deps): update dependency nanoid to v3.3.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#4318](https://github.com/midwayjs/midway/pull/4318) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4308](https://github.com/midwayjs/midway/pull/4308) fix(deps): update dependency mqtt to v5.10.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4302](https://github.com/midwayjs/midway/pull/4302) fix(deps): update dependency @types/jsonwebtoken to v9.0.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4303](https://github.com/midwayjs/midway/pull/4303) fix(deps): update dependency leoric to v2.13.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Aaron Liu ([@liuyuan512](https://github.com/liuyuan512)) --- # v3.20.5 2025年4月27日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![larry zhuo](https://github.com/larryzhuo.png)](https://github.com/larryzhuo) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull-board`, `bullmq`, `web-koa` * [#4330](https://github.com/midwayjs/midway/pull/4330) chore: upgrade bullmq version and update cookie extra options ([@czy88840616](https://github.com/czy88840616)) * `session`, `web-koa` * [#4329](https://github.com/midwayjs/midway/pull/4329) feat: support new cookies options ([@czy88840616](https://github.com/czy88840616)) * `rabbitmq` * [#4326](https://github.com/midwayjs/midway/pull/4326) feat(rabbitmq): add msg into rabbitmq ctx ([@larryzhuo](https://github.com/larryzhuo)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4324](https://github.com/midwayjs/midway/pull/4324) fix(deps): update dependency @grpc/grpc-js to v1.13.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * larry zhuo ([@larryzhuo](https://github.com/larryzhuo)) --- # v3.20.6 2025年6月17日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Mirai Zhao](https://github.com/miraizhao.png)](https://github.com/miraizhao) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `passport`, `swagger` * [#4350](https://github.com/midwayjs/midway/pull/4350) feat: Add global security requirements ([@czy88840616](https://github.com/czy88840616)) * `bull-board` * [#4346](https://github.com/midwayjs/midway/pull/4346) feat: create board manager on server ready ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4343](https://github.com/midwayjs/midway/pull/4343) docs: update mqtt.md ([@miraizhao](https://github.com/miraizhao)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4337](https://github.com/midwayjs/midway/pull/4337) fix(deps): update dependency @grpc/proto-loader to v0.7.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4338](https://github.com/midwayjs/midway/pull/4338) fix(deps): update dependency ali-oss to v6.23.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Mirai Zhao ([@miraizhao](https://github.com/miraizhao)) --- # v3.20.7 2025年6月18日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull-board` * [#4351](https://github.com/midwayjs/midway/pull/4351) fix: bull-board missing export adapter ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.20.8 2025年6月25日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `ws` * [#4354](https://github.com/midwayjs/midway/pull/4354) feat: add request to ws context ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.20.9 2025年7月13日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `ws` * [#4360](https://github.com/midwayjs/midway/pull/4360) feat: add ws upgrade handler ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4359](https://github.com/midwayjs/midway/pull/4359) docs: update the wrong spelling of DefaultConfig ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `jwt` * [#4356](https://github.com/midwayjs/midway/pull/4356) fix(deps): update dependency @types/jsonwebtoken to v9.0.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.3.0 2022年4月7日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * mapping prod and test config in object mode ([#1886](https://github.com/midwayjs/midway/issues/1886)) ([d00f622](https://github.com/midwayjs/midway/commit/d00f622f2a2dc095c8e829b862f2ac155a8e6c91)) * mock when app not start ([#1876](https://github.com/midwayjs/midway/issues/1876)) ([bd32f3e](https://github.com/midwayjs/midway/commit/bd32f3e3e366f5f81c05bfa2b00530ea5ec95744)) ### Features[​](#features "Features的直接链接") * add ApiExtraModel && fix items bug ([#1873](https://github.com/midwayjs/midway/issues/1873)) ([40cce3b](https://github.com/midwayjs/midway/commit/40cce3be1d8ebd5b2723aff2e6d6d488024c5a56)) * add koa init options ([#1885](https://github.com/midwayjs/midway/issues/1885)) ([93d4aed](https://github.com/midwayjs/midway/commit/93d4aed45bc45c2742ceb2bfb990edeaa59d7187)) * upgrade ioredis to v5 ([#1893](https://github.com/midwayjs/midway/issues/1893)) ([42b3dc7](https://github.com/midwayjs/midway/commit/42b3dc723cd291d37f7fd40da90cf031a45f6d78)) --- # v3.3.1 2022年4月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * cookies and BodyParserOptions definition in Koa after [#1856](https://github.com/midwayjs/midway/issues/1856) ([#1899](https://github.com/midwayjs/midway/issues/1899)) ([02fa026](https://github.com/midwayjs/midway/commit/02fa0262ccc2a44fb7e4482ed780cda9026a9a6c)) * swagger\_extend\_bug ([#1894](https://github.com/midwayjs/midway/issues/1894)) ([b918ef8](https://github.com/midwayjs/midway/commit/b918ef871f6daf43a1bf3754e705b7c3e12bf3cd)) --- # v3.3.10 2022年5月26日 ### Features[​](#features "Features的直接链接") * add grpc server options ([#2005](https://github.com/midwayjs/midway/issues/2005)) ([a35d94b](https://github.com/midwayjs/midway/commit/a35d94b37e3134e12d0ec7ff2f4751fc0d7e9d73)) --- # v3.3.11 2022年5月27日 **Note:** Version bump only for package midway\_project --- # v3.3.12 2022年6月2日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add duplicate check for task ([#2019](https://github.com/midwayjs/midway/issues/2019)) ([0b42b56](https://github.com/midwayjs/midway/commit/0b42b560c11d6ff718493b752e2c32cb2c44eb59)) * cache typings ([#2018](https://github.com/midwayjs/midway/issues/2018)) ([8db4e69](https://github.com/midwayjs/midway/commit/8db4e698e534da3eb7b4a37eeb7485b4fe34b977)) --- # v3.3.13 2022年6月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * swagger items assign bug ([#2025](https://github.com/midwayjs/midway/issues/2025)) ([e81a79f](https://github.com/midwayjs/midway/commit/e81a79fd9f88af56d5e1da7421548388d118b2ec)) --- # v3.3.14 2022年6月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * swagger delete example when extends ([#2041](https://github.com/midwayjs/midway/issues/2041)) ([47b62b8](https://github.com/midwayjs/midway/commit/47b62b8ebfb4a5ad4fe9ca0ba0038bb324711404)) * throw error when task run fail and add task to fail queue ([#2044](https://github.com/midwayjs/midway/issues/2044)) ([3c6cd0f](https://github.com/midwayjs/midway/commit/3c6cd0f69bb3c934c56ab5d1e30a333bac6b3e1a)) --- # v3.3.2 2022年4月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * main framework found ([#1903](https://github.com/midwayjs/midway/issues/1903)) ([8a22267](https://github.com/midwayjs/midway/commit/8a22267db744e2269e41089a27fd8e935c1f69e3)) --- # v3.3.3 2022年4月14日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ctx.getLogger does not overwrite success ([#1908](https://github.com/midwayjs/midway/issues/1908)) ([5fcb1c6](https://github.com/midwayjs/midway/commit/5fcb1c6273675c5a1123a94bdaae057781eb217f)) --- # v3.3.4 2022年4月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * close logger before egg app close ([#1928](https://github.com/midwayjs/midway/issues/1928)) ([d30d21f](https://github.com/midwayjs/midway/commit/d30d21f7b2727a2891ac3810dc8dbcbc5276abd7)) * is express method got error result ([#1919](https://github.com/midwayjs/midway/issues/1919)) ([7ca9359](https://github.com/midwayjs/midway/commit/7ca9359c8421f77f1f410c56730cb8babaf65a8c)) * register app before framework init ([#1925](https://github.com/midwayjs/midway/issues/1925)) ([e2fd742](https://github.com/midwayjs/midway/commit/e2fd7425983e30b5ff61fe27db4215b05d33b778)) * typings for app decorator ([#1929](https://github.com/midwayjs/midway/issues/1929)) ([c508458](https://github.com/midwayjs/midway/commit/c508458f9f7505185e676330b3668d38701c6137)) ### Features[​](#features "Features的直接链接") * add recommend extension for site ([#1922](https://github.com/midwayjs/midway/issues/1922)) ([290179c](https://github.com/midwayjs/midway/commit/290179ce47c287f2b39599e609a349c14907cccc)) --- # v3.3.5 2022年4月27日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add original url proxy from url ([#1936](https://github.com/midwayjs/midway/issues/1936)) ([402ad24](https://github.com/midwayjs/midway/commit/402ad249d10f5e9a30d68ee58bc57dc33d7b3107)) * cluster compatible ([#1942](https://github.com/midwayjs/midway/issues/1942)) ([3891150](https://github.com/midwayjs/midway/commit/3891150deec98c9f09edee0973ca8f52d79c66f5)) * oss cluster typings ([#1924](https://github.com/midwayjs/midway/issues/1924)) ([ab2e2be](https://github.com/midwayjs/midway/commit/ab2e2beb9cadb80885ffeb3406da1fb78530f7ef)) * throw error if config is invalid ([#1939](https://github.com/midwayjs/midway/issues/1939)) ([cc5fc1e](https://github.com/midwayjs/midway/commit/cc5fc1e0500554e52853246b90655c05f481fe6c)) --- # v3.3.6 2022年5月11日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency ejs to v3.1.7 \[security] ([#1949](https://github.com/midwayjs/midway/issues/1949)) ([ef8e3fc](https://github.com/midwayjs/midway/commit/ef8e3fcc005b76196ac120dbb0f36e07b6fe6d91)) * egg missing session definition ([#1969](https://github.com/midwayjs/midway/issues/1969)) ([9ded02a](https://github.com/midwayjs/midway/commit/9ded02adce74c59f8644a5f92e5a437deb0d1d8c)) * session maxAge definition ([#1968](https://github.com/midwayjs/midway/issues/1968)) ([3e93254](https://github.com/midwayjs/midway/commit/3e93254b54b30215ddeb3ad6d60469bdb42e284c)) --- # v3.3.7 2022年5月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * koa pipe ([#1973](https://github.com/midwayjs/midway/issues/1973)) ([5cebb76](https://github.com/midwayjs/midway/commit/5cebb76e793abd75bc34dd328d9c1db3d430b58a)) --- # v3.3.8 2022年5月17日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * compatible date type ([#1979](https://github.com/midwayjs/midway/issues/1979)) ([24140f1](https://github.com/midwayjs/midway/commit/24140f1c2b93e8c3a10b996e0f135b260abfbf86)) --- # v3.3.9 2022年5月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * i18 resolver and task typing ([#2003](https://github.com/midwayjs/midway/issues/2003)) ([c7b8ad1](https://github.com/midwayjs/midway/commit/c7b8ad1a86eb680059ab685e1f84ffe046a59292)) --- # v3.4.0 2022年7月20日 **Note:** Version bump only for package midway\_project # [3.4.0-beta.12](https://github.com/midwayjs/midway/compare/v3.4.0-beta.11...v3.4.0-beta.12) (2022-07-20) ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * passport compatible code ([#2133](https://github.com/midwayjs/midway/issues/2133)) ([2975e4f](https://github.com/midwayjs/midway/commit/2975e4f5b6cf8cbcd42cbfb8ce3e08633dbba383)) # [3.4.0-beta.11](https://github.com/midwayjs/midway/compare/v3.4.0-beta.10...v3.4.0-beta.11) (2022-07-19) ### Bug Fixes[​](#bug-fixes-1 "Bug Fixes的直接链接") * async context manager key ([099e4a0](https://github.com/midwayjs/midway/commit/099e4a0a03465b258671b2de48e64df6109b08a5)) * **deps:** update dependency sequelize to v6.21.3 ([#2124](https://github.com/midwayjs/midway/issues/2124)) ([ef05883](https://github.com/midwayjs/midway/commit/ef05883d698f2dc4797fdff75d05cec7790120b0)) * throw error when rabbitmq connect fail ([#2130](https://github.com/midwayjs/midway/issues/2130)) ([e7f55a8](https://github.com/midwayjs/midway/commit/e7f55a863583a3c641b2467799e1d80b1761ecce)) # [3.4.0-beta.10](https://github.com/midwayjs/midway/compare/v3.4.0-beta.9...v3.4.0-beta.10) (2022-07-18) ### Bug Fixes[​](#bug-fixes-2 "Bug Fixes的直接链接") * **deps:** update dependency ws to v8.8.1 ([#2125](https://github.com/midwayjs/midway/issues/2125)) ([fabf2a4](https://github.com/midwayjs/midway/commit/fabf2a4b773c3c132043592c5e1ec7cb57f7dae0)) ### Features[​](#features "Features的直接链接") * add get current context manager global method ([#2129](https://github.com/midwayjs/midway/issues/2129)) ([2ac829f](https://github.com/midwayjs/midway/commit/2ac829fe4cb26851a21a211d17d9bfc2195beab6)) # [3.4.0-beta.9](https://github.com/midwayjs/midway/compare/v3.4.0-beta.8...v3.4.0-beta.9) (2022-07-14) ### Bug Fixes[​](#bug-fixes-3 "Bug Fixes的直接链接") * **deps:** update dependency @koa/router to v11 ([#2111](https://github.com/midwayjs/midway/issues/2111)) ([0f6b34e](https://github.com/midwayjs/midway/commit/0f6b34e964a1bfc98ddf020878b43af99557291d)) * faas close server ([#2113](https://github.com/midwayjs/midway/issues/2113)) ([f627f27](https://github.com/midwayjs/midway/commit/f627f27c0a6afb6f1e4a04a68ae96ef6d579ed3f)) * ignore middleware can't return in resolve ([#2112](https://github.com/midwayjs/midway/issues/2112)) ([ec018a3](https://github.com/midwayjs/midway/commit/ec018a3365b06c1cc809e014afede0a24ce1dd74)) * use redis client before it's ready, most likely to occur during unit test ([#2102](https://github.com/midwayjs/midway/issues/2102)) ([3f4f0cd](https://github.com/midwayjs/midway/commit/3f4f0cdd5d74c5b7f6c39edfeb453accd6ec0fa3)) * when `resolve` return null, the current loop should end, otherwi… ([#2114](https://github.com/midwayjs/midway/issues/2114)) ([cae3c8b](https://github.com/midwayjs/midway/commit/cae3c8b325d57b1da982eec55216eceaf4596cf9)) ### Features[​](#features-1 "Features的直接链接") * add context manager with middleware ([#2116](https://github.com/midwayjs/midway/issues/2116)) ([99ba506](https://github.com/midwayjs/midway/commit/99ba506b82b1061af26bf333892ae90b654a7b31)) # [3.4.0-beta.8](https://github.com/midwayjs/midway/compare/v3.4.0-beta.7...v3.4.0-beta.8) (2022-07-12) ### Bug Fixes[​](#bug-fixes-4 "Bug Fixes的直接链接") * ssl ([be82dcb](https://github.com/midwayjs/midway/commit/be82dcb3c0992f138969ac57a67c67e9dc1727d9)) # [3.4.0-beta.7](https://github.com/midwayjs/midway/compare/v3.4.0-beta.6...v3.4.0-beta.7) (2022-07-12) ### Bug Fixes[​](#bug-fixes-5 "Bug Fixes的直接链接") * egg default custom logger level ([#2099](https://github.com/midwayjs/midway/issues/2099)) ([7b8c4ba](https://github.com/midwayjs/midway/commit/7b8c4ba14d3233777366e643dbd91d1aaca07101)) * regexp for root path match ([#2105](https://github.com/midwayjs/midway/issues/2105)) ([97ccc03](https://github.com/midwayjs/midway/commit/97ccc0391cd1436ef5106a7e35f0d81dca4477dd)) ### Features[​](#features-2 "Features的直接链接") * add display options and fix array bug ([#2103](https://github.com/midwayjs/midway/issues/2103)) ([4f8e06d](https://github.com/midwayjs/midway/commit/4f8e06d98e1c14f4403b87ccddf90a2bb81b4862)) * support socket connection and message middleware ([#1984](https://github.com/midwayjs/midway/issues/1984)) ([886d0bf](https://github.com/midwayjs/midway/commit/886d0bf6b47aecf870df15853d4ba82256c08858)) # [3.4.0-beta.6](https://github.com/midwayjs/midway/compare/v3.4.0-beta.5...v3.4.0-beta.6) (2022-07-07) ### Features[​](#features-3 "Features的直接链接") * add matched method in router service ([#2098](https://github.com/midwayjs/midway/issues/2098)) ([6c00665](https://github.com/midwayjs/midway/commit/6c006656d06587deee808160d536d785412f0c6d)) # [3.4.0-beta.5](https://github.com/midwayjs/midway/compare/v3.4.0-beta.4...v3.4.0-beta.5) (2022-07-07) ### Bug Fixes[​](#bug-fixes-6 "Bug Fixes的直接链接") * koa dynamic router case ([#2094](https://github.com/midwayjs/midway/issues/2094)) ([646ee6e](https://github.com/midwayjs/midway/commit/646ee6e95995136b7795c1f821a7b6e74ffdbbcd)) * replace onReady to onServerReady ([#2092](https://github.com/midwayjs/midway/issues/2092)) ([b3a2804](https://github.com/midwayjs/midway/commit/b3a2804820bc651366c1c3f83118262cd8947884)) # [3.4.0-beta.4](https://github.com/midwayjs/midway/compare/v3.4.0-beta.3...v3.4.0-beta.4) (2022-07-04) ### Bug Fixes[​](#bug-fixes-7 "Bug Fixes的直接链接") * config export default case ([#2089](https://github.com/midwayjs/midway/issues/2089)) ([15c66d8](https://github.com/midwayjs/midway/commit/15c66d894e42bf488e3cb74084a1ecb17a42752b)) * missing client options in grpc ([#2087](https://github.com/midwayjs/midway/issues/2087)) ([be99f10](https://github.com/midwayjs/midway/commit/be99f10f20084932663f76e34e3fb9e55ebaa71e)) * return buffer in serverless environment ([#2085](https://github.com/midwayjs/midway/issues/2085)) ([ef4f70a](https://github.com/midwayjs/midway/commit/ef4f70ac20f8c7dc05165947114349aa991eda56)) ### Features[​](#features-4 "Features的直接链接") * add kafka ([#2062](https://github.com/midwayjs/midway/issues/2062)) ([a83003b](https://github.com/midwayjs/midway/commit/a83003bf0db86d640b60e45ee6cbf71e656008a0)) * code dye ([#2078](https://github.com/midwayjs/midway/issues/2078)) ([a9cf1c5](https://github.com/midwayjs/midway/commit/a9cf1c50199b5bad1e3d6024a87d1c4761370fde)) --- # v3.4.1 2022年7月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * class name and controller prefix conflict ([#2137](https://github.com/midwayjs/midway/issues/2137)) ([f6607ca](https://github.com/midwayjs/midway/commit/f6607cac43ff19cf669f03978817f13cc1da00fd)) --- # v3.4.10 2022年8月12日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * catch kafaka start error ([#2230](https://github.com/midwayjs/midway/issues/2230)) ([60c7c41](https://github.com/midwayjs/midway/commit/60c7c41eaaaa062bf63ca1f938dd2cbd15bd2f7d)) * **deps:** update dependency @grpc/grpc-js to v1.6.9 ([#2223](https://github.com/midwayjs/midway/issues/2223)) ([e0c6d4d](https://github.com/midwayjs/midway/commit/e0c6d4d78410d38149d4347a3bfb270498ae5f14)) * **deps:** update dependency amqp-connection-manager to v4.1.6 ([#2225](https://github.com/midwayjs/midway/issues/2225)) ([ff7506a](https://github.com/midwayjs/midway/commit/ff7506a7bb986409e8c9a85ea55a23a3d935bdf5)) * revert node 14 supported ([#2219](https://github.com/midwayjs/midway/issues/2219)) ([08e4152](https://github.com/midwayjs/midway/commit/08e4152bb9530b699de4150c2494f04795348719)) * stop duplicate invoke ([#2221](https://github.com/midwayjs/midway/issues/2221)) ([6bd3f57](https://github.com/midwayjs/midway/commit/6bd3f57dbd68742c5b789335b46e929b7f71c6c4)) --- # v3.4.11 2022年8月16日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * IMiddleware interface ([#2242](https://github.com/midwayjs/midway/issues/2242)) ([1b435fb](https://github.com/midwayjs/midway/commit/1b435fb86f1ae141f2906b64c236fb8926c4c380)) ### Features[​](#features "Features的直接链接") * **kafka:** update kafka framework & add test demo ([#2236](https://github.com/midwayjs/midway/issues/2236)) ([5eae117](https://github.com/midwayjs/midway/commit/5eae117dc302d1bd56d15564970441e1cd17b185)) --- # v3.4.12 2022年8月20日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * grpc context typings ([#2259](https://github.com/midwayjs/midway/issues/2259)) ([9449097](https://github.com/midwayjs/midway/commit/944909705413cebdfe0ae11301e8fd0e536c1edd)) * service factory client & clients merge ([#2248](https://github.com/midwayjs/midway/issues/2248)) ([cfdee64](https://github.com/midwayjs/midway/commit/cfdee6449cb2770bc238e74fd754b783c331b822)) --- # v3.4.13 2022年8月24日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * passport strategy this missing ([#2264](https://github.com/midwayjs/midway/issues/2264)) ([2e5467a](https://github.com/midwayjs/midway/commit/2e5467a7c1cd4b7aa5574ddab624861dea54346b)) --- # v3.4.2 2022年7月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * export server credentials class & lock version ([#2138](https://github.com/midwayjs/midway/issues/2138)) ([5f48299](https://github.com/midwayjs/midway/commit/5f4829903de744b4b9343e8bc441b373d78d78ed)) --- # v3.4.3 2022年7月21日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * sequelize typings and filter empty metadata([#2140](https://github.com/midwayjs/midway/issues/2140)) ([eaa360c](https://github.com/midwayjs/midway/commit/eaa360c028dca67d0df79efa61eed605d784c58d)) * throw error when authenticate ([#2141](https://github.com/midwayjs/midway/issues/2141)) ([730a282](https://github.com/midwayjs/midway/commit/730a28209162bb18b989cb783b54936a4bb747e0)) --- # v3.4.4 2022年7月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add config filter and modify sequelize & mongoose config ([#2150](https://github.com/midwayjs/midway/issues/2150)) ([5db3b9b](https://github.com/midwayjs/midway/commit/5db3b9b56b6eac393820acf9f089e6f8cdd6a8b6)) * add createBootstrap export ([#2145](https://github.com/midwayjs/midway/issues/2145)) ([8bd9491](https://github.com/midwayjs/midway/commit/8bd94910af98496d17966d44f7a88ec28ecc9b95)) * some passport strategy verify callback arguments length ([#2151](https://github.com/midwayjs/midway/issues/2151)) ([65c9025](https://github.com/midwayjs/midway/commit/65c9025a3b399d9d7e5061cecb30ad4943d337cd)) * **view-nunjucks:** add autoescape config && add ts interface ([#2148](https://github.com/midwayjs/midway/issues/2148)) ([8d39739](https://github.com/midwayjs/midway/commit/8d39739eb99d9baa2d6da229352d90f18bf072d5)) --- # v3.4.5 2022年7月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add getSchema method for validate ([#2155](https://github.com/midwayjs/midway/issues/2155)) ([aee9353](https://github.com/midwayjs/midway/commit/aee9353fb2c39f4996dff97b901a7b6d99f7cb9f)) * rabbit mq disconnect ([#2152](https://github.com/midwayjs/midway/issues/2152)) ([a98f37d](https://github.com/midwayjs/midway/commit/a98f37de69ee0b05ee027bdc8ff6b5cfcc485920)) --- # v3.4.6 2022年7月31日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency @grpc/grpc-js to v1.6.8 ([#2177](https://github.com/midwayjs/midway/issues/2177)) ([a8a8693](https://github.com/midwayjs/midway/commit/a8a86934ffe815458d2c4140d60589b3ef36b97e)) * **deps:** update dependency tablestore to v5.2.0 ([#2179](https://github.com/midwayjs/midway/issues/2179)) ([17e7f9b](https://github.com/midwayjs/midway/commit/17e7f9b0707584a0ad10f593c4ec7f52f598cf54)) * sls metadata npe ([#2167](https://github.com/midwayjs/midway/issues/2167)) ([98bf8b5](https://github.com/midwayjs/midway/commit/98bf8b5ec4d47f69dd8e53dae9a702a9c550a9b1)) * **task:** createClient config missing ([#2163](https://github.com/midwayjs/midway/issues/2163)) ([129ce16](https://github.com/midwayjs/midway/commit/129ce1643201b36d10eac08a97dd6d99e35026aa)) ### Performance Improvements[​](#performance-improvements "Performance Improvements的直接链接") * **core:** destroy connection concurrently within DataSourceManager.… ([#2169](https://github.com/midwayjs/midway/issues/2169)) ([53bcf65](https://github.com/midwayjs/midway/commit/53bcf65dc2699857a41a6400b4c04e0c46b30948)) --- # v3.4.7 2022年8月1日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * middleware disable in express ([#2187](https://github.com/midwayjs/midway/issues/2187)) ([8cad157](https://github.com/midwayjs/midway/commit/8cad157c84bf808763afa2d648c502fdd4264a54)) * unexpected token 'export' in load \*\*.d.ts file in prod mode ([#2185](https://github.com/midwayjs/midway/issues/2185)) ([6d634ce](https://github.com/midwayjs/midway/commit/6d634ce9361dd319e9d710118702e5543e42d4f0)) --- # v3.4.8 2022年8月2日 ### Performance Improvements[​](#performance-improvements "Performance Improvements的直接链接") * add ctx attach hook ([#2189](https://github.com/midwayjs/midway/issues/2189)) ([04a5b3f](https://github.com/midwayjs/midway/commit/04a5b3f6e0cbfc251c115a486948b0c3401ba4df)) --- # v3.4.9 2022年8月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency amqp-connection-manager to v4.1.4 ([#2206](https://github.com/midwayjs/midway/issues/2206)) ([c80e85f](https://github.com/midwayjs/midway/commit/c80e85f47288b3dfff93a29404187a9b15e8963e)) * **deps:** update dependency tablestore to v5.2.1 ([#2197](https://github.com/midwayjs/midway/issues/2197)) ([7b6f3b5](https://github.com/midwayjs/midway/commit/7b6f3b587dc2bdf429c1f50f6af723b2d5b2431b)) * **grpc:** 🐞 Uncaught TypeError: Cannot read properties… ([#2201](https://github.com/midwayjs/midway/issues/2201)) ([f5c993f](https://github.com/midwayjs/midway/commit/f5c993f29a788d0df30f41398cfbc71b5c41defa)) * middleware repeat execute in request ([#2210](https://github.com/midwayjs/midway/issues/2210)) ([0466046](https://github.com/midwayjs/midway/commit/0466046a8843168459bcd5dedee4d17bad83301d)) * query parser with array ([#2207](https://github.com/midwayjs/midway/issues/2207)) ([94ddd69](https://github.com/midwayjs/midway/commit/94ddd691e2c0a8e06d88704d4e85a39443deef52)) * super agent typings ([#2204](https://github.com/midwayjs/midway/issues/2204)) ([87572a6](https://github.com/midwayjs/midway/commit/87572a63ba8226c2380bfdd3252c271336f6bfeb)) * support mikro-orm multi entities manager in request context ([#2193](https://github.com/midwayjs/midway/issues/2193)) ([60f65b2](https://github.com/midwayjs/midway/commit/60f65b2caa77b6770af65d7a24fa8023f1bc2085)) * typeorm config typings key ([#2192](https://github.com/midwayjs/midway/issues/2192)) ([6533942](https://github.com/midwayjs/midway/commit/6533942d88234234a3c7e5bcd877eb8c2200c7be)) ### Features[​](#features "Features的直接链接") * **core:** createInstance() accepts 3rd param cacheInstance (default true) ([#2208](https://github.com/midwayjs/midway/issues/2208)) ([a9149c2](https://github.com/midwayjs/midway/commit/a9149c2ae49a60085c910d8daaf2224aeef92c67)) ### Performance Improvements[​](#performance-improvements "Performance Improvements的直接链接") * move body patch without middleware ([#2209](https://github.com/midwayjs/midway/issues/2209)) ([97c9301](https://github.com/midwayjs/midway/commit/97c930107c6fa93d8209516b15348c988848ca3d)) --- # v3.5.0 2022年8月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **axios:** fix @midway/axios more configuration instance problems ([#2273](https://github.com/midwayjs/midway/issues/2273)) ([edf9377](https://github.com/midwayjs/midway/commit/edf937753a1b290de77bea334a052b22adbb9684)) * oss config typings ([#2277](https://github.com/midwayjs/midway/issues/2277)) ([f62e42a](https://github.com/midwayjs/midway/commit/f62e42abf18ff4df3b6d2f23189ec0a46db72c11)) ### Features[​](#features "Features的直接链接") * add retry wrapper for invoke some remote data ([#2271](https://github.com/midwayjs/midway/issues/2271)) ([1c47338](https://github.com/midwayjs/midway/commit/1c473386937293104369cc8e5727c5330de4f85c)) * **core:** config option for validating database connection during initialization ([#2234](https://github.com/midwayjs/midway/issues/2234)) ([cf5d360](https://github.com/midwayjs/midway/commit/cf5d360d7300db12f12cc3e1ce67806ad082a7b1)) --- # v3.5.1 2022年9月6日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * glob with pattern ([#2293](https://github.com/midwayjs/midway/issues/2293)) ([1e05d41](https://github.com/midwayjs/midway/commit/1e05d41240094b0849caef53f10ef53a54e752ab)) ### Features[​](#features "Features的直接链接") * support add locals and add case ([#2289](https://github.com/midwayjs/midway/issues/2289)) ([fc373d9](https://github.com/midwayjs/midway/commit/fc373d9ac4d2ae82c90cd476292012fae2f5fc2d)) * support receiver to bind this ([#2292](https://github.com/midwayjs/midway/issues/2292)) ([159184c](https://github.com/midwayjs/midway/commit/159184c87087cf9f76bc55a5cda46f90771bf7db)) --- # v3.5.2 2022年9月8日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * ctx.locals missing in faas ([#2302](https://github.com/midwayjs/midway/issues/2302)) ([a0a5903](https://github.com/midwayjs/midway/commit/a0a59036e0a0e8b5f92b17829af3f79191c1ee91)) * example missing in swagger ([#2305](https://github.com/midwayjs/midway/issues/2305)) ([8bc8fcc](https://github.com/midwayjs/midway/commit/8bc8fcc9467bcee1f7cd1cf609c93b918c96bc5a)) --- # v3.5.3 2022年9月25日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** update dependency @grpc/grpc-js to v1.7.1 ([#2331](https://github.com/midwayjs/midway/issues/2331)) ([4a962dc](https://github.com/midwayjs/midway/commit/4a962dce8f3d2990fc3a2668b7e009b670f99166)) * **deps:** update dependency @grpc/proto-loader to v0.7.3 ([#2327](https://github.com/midwayjs/midway/issues/2327)) ([d05dab5](https://github.com/midwayjs/midway/commit/d05dab5e9c2f73fc14d2bb82f61fb8e6bd52416f)) * **deps:** update dependency sequelize to v6.23.1 ([#2332](https://github.com/midwayjs/midway/issues/2332)) ([2a5c6eb](https://github.com/midwayjs/midway/commit/2a5c6eb82394c4b1427e936da3525d999d459b4e)) * **deps:** update dependency ws to v8.9.0 ([#2333](https://github.com/midwayjs/midway/issues/2333)) ([8a84a10](https://github.com/midwayjs/midway/commit/8a84a109b0a304c3f75db6cfb6dcf11e6d3edd78)) * make addAspect public ([#2317](https://github.com/midwayjs/midway/issues/2317)) ([ded7a07](https://github.com/midwayjs/midway/commit/ded7a0798b4f94936f851b202e2406d6dd3902e6)) * path parameters set ([#2314](https://github.com/midwayjs/midway/issues/2314)) ([cf1b441](https://github.com/midwayjs/midway/commit/cf1b441fa1d80894e69ea6ac3bd159f04a0c6ba5)) * scripts in `benchmark/` ([#2310](https://github.com/midwayjs/midway/issues/2310)) ([a039d3d](https://github.com/midwayjs/midway/commit/a039d3d269311e42cbc15c4431508219351bb521)) * **view:** fix setLocals ([#2321](https://github.com/midwayjs/midway/issues/2321)) ([72789a1](https://github.com/midwayjs/midway/commit/72789a114b1142674c1a8141c7af382538d92400)) ### Features[​](#features "Features的直接链接") * add proxyTimeout for httpProxy ([#2308](https://github.com/midwayjs/midway/issues/2308)) ([fb14118](https://github.com/midwayjs/midway/commit/fb141183223098534a075ab20bd3e2c366e40d4a)) --- # v3.6.0 2022年10月10日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * add default generic type to MikroConfigOptions ([#2342](https://github.com/midwayjs/midway/issues/2342)) ([d5fbab6](https://github.com/midwayjs/midway/commit/d5fbab666dabbae6fad0e0946b733ea73ac1a9d5)) * **deps:** update dependency amqp-connection-manager to v4.1.7 ([#2354](https://github.com/midwayjs/midway/issues/2354)) ([79d4d5b](https://github.com/midwayjs/midway/commit/79d4d5bede926be2c00e21250f8edffca747d932)) * **deps:** update dependency body-parser to v1.20.1 ([#2355](https://github.com/midwayjs/midway/issues/2355)) ([4cf6bda](https://github.com/midwayjs/midway/commit/4cf6bdaa8b10b4ae40598305e1df9ad29dd701ed)) * **deps:** update dependency sequelize to v6.24.0 ([#2356](https://github.com/midwayjs/midway/issues/2356)) ([ecc43d0](https://github.com/midwayjs/midway/commit/ecc43d0b96ad7fcc6766831b6db0cb8ca204580c)) ### Features[​](#features "Features的直接链接") * add casbin module ([#2358](https://github.com/midwayjs/midway/issues/2358)) ([a7d2786](https://github.com/midwayjs/midway/commit/a7d27863b756dcf81abc4d7dedaf35c517c2c1e3)) * add filter params for add controller ([#2359](https://github.com/midwayjs/midway/issues/2359)) ([1805011](https://github.com/midwayjs/midway/commit/1805011d3b2d86f04d6a887f4a86afb093a2a75f)) * add guard ([#2345](https://github.com/midwayjs/midway/issues/2345)) ([1b952a1](https://github.com/midwayjs/midway/commit/1b952a1b09adbb88ff3cff9a2974eb1e37ce53a5)) * add new bull component ([#2275](https://github.com/midwayjs/midway/issues/2275)) ([0a37b49](https://github.com/midwayjs/midway/commit/0a37b491720c5d5f0b98e9e42835ba263dd8b975)) --- # v3.6.1 2022年10月13日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * [#2309](https://github.com/midwayjs/midway/issues/2309) ([#2371](https://github.com/midwayjs/midway/issues/2371)) ([919242d](https://github.com/midwayjs/midway/commit/919242d1d7228caa0d450960113396627ce359db)) * fix axios typings and upgrade to v1 ([#2379](https://github.com/midwayjs/midway/issues/2379)) ([f0666f0](https://github.com/midwayjs/midway/commit/f0666f03c1404b7d11e8b3e8da7082a35432fe48)) --- # v3.7.0 2022年10月29日 ### Bug Fixes[​](#bug-fixes "Bug Fixes的直接链接") * **deps:** pin dependency cron to v1.8.2 ([#2426](https://github.com/midwayjs/midway/issues/2426)) ([9873e13](https://github.com/midwayjs/midway/commit/9873e13224e4b935697fdc22ecca97d43f809083)) * **deps:** update dependency @bull-board/api to v4.6.0 ([#2415](https://github.com/midwayjs/midway/issues/2415)) ([bc7f83e](https://github.com/midwayjs/midway/commit/bc7f83ec7d586e847fa70a5974e28e2a79ac4b40)) * **deps:** update dependency @bull-board/api to v4.6.1 ([#2448](https://github.com/midwayjs/midway/issues/2448)) ([aaf7116](https://github.com/midwayjs/midway/commit/aaf7116385c4bd92b338e519afa15f9da402b5be)) * **deps:** update dependency @bull-board/ui to v4.6.0 ([#2416](https://github.com/midwayjs/midway/issues/2416)) ([ccb6d2b](https://github.com/midwayjs/midway/commit/ccb6d2bb95088261504d623cae6885cc24953b1c)) * **deps:** update dependency @bull-board/ui to v4.6.1 ([#2449](https://github.com/midwayjs/midway/issues/2449)) ([0a84692](https://github.com/midwayjs/midway/commit/0a846920c58868e5801db9d8e85edddad4074d2d)) * **deps:** update dependency @grpc/grpc-js to v1.7.2 ([#2411](https://github.com/midwayjs/midway/issues/2411)) ([5f433a1](https://github.com/midwayjs/midway/commit/5f433a16afcb4f031310811608eaa8fdd5968ed8)) * **deps:** update dependency @grpc/grpc-js to v1.7.3 ([#2433](https://github.com/midwayjs/midway/issues/2433)) ([07c7acc](https://github.com/midwayjs/midway/commit/07c7accb4294a98d0726bc53b8bcec33038dd794)) * **deps:** update dependency amqp-connection-manager to v4.1.9 ([#2450](https://github.com/midwayjs/midway/issues/2450)) ([f0a4ccc](https://github.com/midwayjs/midway/commit/f0a4ccceba4a9fc8ef76c28b1e7cbca453d15a20)) * **deps:** update dependency bull to v4.10.1 ([#2412](https://github.com/midwayjs/midway/issues/2412)) ([992ee59](https://github.com/midwayjs/midway/commit/992ee59b4ab9cb82ad390f819f8cee73a2514684)) * **deps:** update dependency express to v4.18.2 ([#2413](https://github.com/midwayjs/midway/issues/2413)) ([ace153b](https://github.com/midwayjs/midway/commit/ace153b796a8b962d307ee1568634869f727431a)) * **deps:** update dependency sequelize to v6.25.3 ([#2417](https://github.com/midwayjs/midway/issues/2417)) ([0289fe9](https://github.com/midwayjs/midway/commit/0289fe93136980b897d6d1de38557680e4f08840)) * **deps:** update dependency supertest to v6.3.0 ([#2435](https://github.com/midwayjs/midway/issues/2435)) ([6342e1d](https://github.com/midwayjs/midway/commit/6342e1d2a5301f3bd512d7c58b90482bca390898)) * **deps:** update dependency tablestore to v5.3.0 ([#2418](https://github.com/midwayjs/midway/issues/2418)) ([c7f0f56](https://github.com/midwayjs/midway/commit/c7f0f56b736acd710efea03ccc4cffcec630d065)) * **deps:** update socket.io packages to v4.5.3 ([#2414](https://github.com/midwayjs/midway/issues/2414)) ([3bc64d6](https://github.com/midwayjs/midway/commit/3bc64d60d1648e18304259f1b957349f8d8e9ac6)) * framework loaded by import sequence ([#2394](https://github.com/midwayjs/midway/issues/2394)) ([c87f125](https://github.com/midwayjs/midway/commit/c87f1253c8ae217940f24efb7f97fe6fe61d20e4)) * init context missing when dev test ([#2423](https://github.com/midwayjs/midway/issues/2423)) ([fd26d92](https://github.com/midwayjs/midway/commit/fd26d92b5dea068e4f86e6d60ab0dfa47eaa55c9)) * upload whitelist set null ([#2431](https://github.com/midwayjs/midway/issues/2431)) ([06a765e](https://github.com/midwayjs/midway/commit/06a765ecfb6e4e16c982c9b39408f420d0c27be5)) ### Features[​](#features "Features的直接链接") * add server timeout config ([#2395](https://github.com/midwayjs/midway/issues/2395)) ([52f63b6](https://github.com/midwayjs/midway/commit/52f63b6726e6d5177ff018579be616c221379625)) * **core:** add custom route param decorator ([#2400](https://github.com/midwayjs/midway/issues/2400)) ([#2441](https://github.com/midwayjs/midway/issues/2441)) ([d5895bf](https://github.com/midwayjs/midway/commit/d5895bf09f454b34345fc11b642e4529a555b19b)) * support default data source name ([#2430](https://github.com/midwayjs/midway/issues/2430)) ([b953a15](https://github.com/midwayjs/midway/commit/b953a153bf09869a0ad3ff5e9617ca6a3db5bf77)) * support user to observe histogram value ([#2401](https://github.com/midwayjs/midway/issues/2401)) ([1d8c9ad](https://github.com/midwayjs/midway/commit/1d8c9ad1cad4f8863b1b6fd899388e554deb807e)) * verification code ([#2402](https://github.com/midwayjs/midway/issues/2402)) ([e96cf0a](https://github.com/midwayjs/midway/commit/e96cf0aa2de21b15cc69009df371834b3db22d47)) ### Performance Improvements[​](#performance-improvements "Performance Improvements的直接链接") * update triggerFunction args ([#2404](https://github.com/midwayjs/midway/issues/2404)) ([7ae42eb](https://github.com/midwayjs/midway/commit/7ae42ebe23c2c1a88f43e4516f7fabb22a2914c9)) --- # v3.7.1 2022年10月30日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![yc6](https://github.com/zane0904.png)](https://github.com/zane0904) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `validate` * [#2459](https://github.com/midwayjs/midway/pull/2459) fix: validate with custom options will override global config ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `sequelize` * [#2458](https://github.com/midwayjs/midway/pull/2458) fix: add config sync options ([@czy88840616](https://github.com/czy88840616)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * yc6 ([@zane0904](https://github.com/zane0904)) --- # v3.7.2 2022年11月2日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![zhangbowy](https://github.com/zhangbowy.png)](https://github.com/zhangbowy) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#2466](https://github.com/midwayjs/midway/pull/2466) fix: type property replace ts type ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2465](https://github.com/midwayjs/midway/pull/2465) docs: Add grafana to docker-compose.yml ([@zhangbowy](https://github.com/zhangbowy)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * zhangbowy ([@zhangbowy](https://github.com/zhangbowy)) --- # v3.7.3 2022年11月3日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![酷酷的老猫](https://github.com/kukudelaomao.png)](https://github.com/kukudelaomao) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#2469](https://github.com/midwayjs/midway/pull/2469) fix: swagger ui favicon output ([@czy88840616](https://github.com/czy88840616)) * `faas`, `mock` * [#2464](https://github.com/midwayjs/midway/pull/2464) fix: getServerlessInstance add ctx hook ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2470](https://github.com/midwayjs/midway/pull/2470) docs: update deployment.md ([@kukudelaomao](https://github.com/kukudelaomao)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * 酷酷的老猫 ([@kukudelaomao](https://github.com/kukudelaomao)) --- # v3.7.4 2022年11月8日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![isaced](https://github.com/isaced.png)](https://github.com/isaced) [![larry zhuo](https://github.com/larryzhuo.png)](https://github.com/larryzhuo) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `captcha` * [#2483](https://github.com/midwayjs/midway/pull/2483) fix: noise and size support ([@echosoar](https://github.com/echosoar)) * `casbin` * [#2486](https://github.com/midwayjs/midway/pull/2486) fix: policyAdapter promise typings ([@czy88840616](https://github.com/czy88840616)) * `typegoose` * [#2477](https://github.com/midwayjs/midway/pull/2477) fix: duplicate mongoose import ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bull` * [#2485](https://github.com/midwayjs/midway/pull/2485) chore: add job typings export ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2487](https://github.com/midwayjs/midway/pull/2487) docs(site): add a throttler like @nestjs/throttler to awesome\_midway.md ([@larryzhuo](https://github.com/larryzhuo)) * [#2479](https://github.com/midwayjs/midway/pull/2479) docs(orm): add OrmConnectionHook example for legacy orm.md ([@larryzhuo](https://github.com/larryzhuo)) * [#2478](https://github.com/midwayjs/midway/pull/2478) docs: fix serverless\_yml link path ([@isaced](https://github.com/isaced)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * isaced ([@isaced](https://github.com/isaced)) * larry zhuo ([@larryzhuo](https://github.com/larryzhuo)) --- # v3.8.0 2022年11月18日 [![cave-](https://github.com/cave-.png)](https://github.com/cave-) [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Haitao Lee](https://github.com/haitaodesign.png)](https://github.com/haitaodesign) [![larry zhuo](https://github.com/larryzhuo.png)](https://github.com/larryzhuo) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `etcd` * [#2481](https://github.com/midwayjs/midway/pull/2481) feat: add etcd component ([@czy88840616](https://github.com/czy88840616)) * `axios`, `core`, `cos`, `oss`, `redis`, `tablestore` * [#2482](https://github.com/midwayjs/midway/pull/2482) feat: serviceFactory support default client name ([@czy88840616](https://github.com/czy88840616)) * `core`, `mikro`, `sequelize`, `typeorm` * [#2498](https://github.com/midwayjs/midway/pull/2498) feat: add injectDataSource for mikro/typeorm/sequelize ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2505](https://github.com/midwayjs/midway/pull/2505) fix: windows entity glob and Closes [#2488](https://github.com/midwayjs/midway/issues/2488) ([@czy88840616](https://github.com/czy88840616)) * [#2504](https://github.com/midwayjs/midway/pull/2504) fix: remove router cache and fix issue #2319 ([@czy88840616](https://github.com/czy88840616)) * `bull` * [#2493](https://github.com/midwayjs/midway/pull/2493) fix: bull exports and typings ([@czy88840616](https://github.com/czy88840616)) ## :running: Performance[​](#running-performance ":running: Performance的直接链接") * `core` * [#2506](https://github.com/midwayjs/midway/pull/2506) perf: remove babel isClass check ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2502](https://github.com/midwayjs/midway/pull/2502) docs: fix remoteConfig in Life Cycle ([@haitaodesign](https://github.com/haitaodesign)) * [#2491](https://github.com/midwayjs/midway/pull/2491) docs(site): update auto\_run.md ([@cave-](https://github.com/cave-)) * [#2489](https://github.com/midwayjs/midway/pull/2489) docs(site): fix midway-throttler url link in awesome\_midway.md ([@larryzhuo](https://github.com/larryzhuo)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Haitao Lee ([@haitaodesign](https://github.com/haitaodesign)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@cave-](https://github.com/cave-) * larry zhuo ([@larryzhuo](https://github.com/larryzhuo)) --- # v3.8.1 2022年11月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `etcd` * [#2512](https://github.com/midwayjs/midway/pull/2512) fix: etcd support default instance name ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.8.2 2022年11月26日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) [![xnng](https://github.com/xnng.png)](https://github.com/xnng) [![zhi](https://github.com/yantze.png)](https://github.com/yantze) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `sequelize` * [#2525](https://github.com/midwayjs/midway/pull/2525) fix: sequelize inject data source forgot to export ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `swagger` * [#2518](https://github.com/midwayjs/midway/pull/2518) fix: swagger global prefix without path ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2516](https://github.com/midwayjs/midway/pull/2516) docs: update the configuration description of AccessKey ([@yantze](https://github.com/yantze)) * [#2515](https://github.com/midwayjs/midway/pull/2515) docs(site): update awesome\_midway.md ([@waitingsong](https://github.com/waitingsong)) * [#2514](https://github.com/midwayjs/midway/pull/2514) doc(consul.md): fix port type error ([@xnng](https://github.com/xnng)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@xnng](https://github.com/xnng) * waiting ([@waitingsong](https://github.com/waitingsong)) * zhi ([@yantze](https://github.com/yantze)) --- # v3.8.3 2022年11月28日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mikro`, `sequelize`, `typeorm` * [#2538](https://github.com/midwayjs/midway/pull/2538) fix: data source find sequence ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.8.4 2022年12月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Gao Yang](https://github.com/echosoar.png)](https://github.com/echosoar) [![huangapple](https://github.com/huangapple.png)](https://github.com/huangapple) [![waiting](https://github.com/waitingsong.png)](https://github.com/waitingsong) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `captcha` * [#2566](https://github.com/midwayjs/midway/pull/2566) fix: captcha store prefix ([@echosoar](https://github.com/echosoar)) * `bull` * [#2526](https://github.com/midwayjs/midway/pull/2526) fix: add default job options when create queue ([@czy88840616](https://github.com/czy88840616)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#2557](https://github.com/midwayjs/midway/pull/2557) docs: update docker deploy ([@huangapple](https://github.com/huangapple)) * [#2549](https://github.com/midwayjs/midway/pull/2549) docs(site): update awesome\_midway.md ([@waitingsong](https://github.com/waitingsong)) ## Committers: 4[​](#committers-4 "Committers: 4的直接链接") * Gao Yang ([@echosoar](https://github.com/echosoar)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@huangapple](https://github.com/huangapple) * waiting ([@waitingsong](https://github.com/waitingsong)) --- # v3.9.0 2022年12月13日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `bootstrap` * [#2551](https://github.com/midwayjs/midway/pull/2551) feat: support socket.io sticky session ([@czy88840616](https://github.com/czy88840616)) * `casbin-redis-adapter`, `casbin`, `core`, `redis` * [#2560](https://github.com/midwayjs/midway/pull/2560) feat: support casbin watcher ([@czy88840616](https://github.com/czy88840616)) * `core` * [#2574](https://github.com/midwayjs/midway/pull/2574) feat: add @injectClient for service factory ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#2533](https://github.com/midwayjs/midway/pull/2533) fix: glob support more wildcard string ([@czy88840616](https://github.com/czy88840616)) * `web` * [#2573](https://github.com/midwayjs/midway/pull/2573) fix: ignore backup egg logger error ([@czy88840616](https://github.com/czy88840616)) * `faas`, `mock` * [#2576](https://github.com/midwayjs/midway/pull/2576) fix: event not format in faas ([@czy88840616](https://github.com/czy88840616)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * `core` * [#2534](https://github.com/midwayjs/midway/pull/2534) chore: sync code from [https://github.com/midwayjs/fork-dep-monitor/pu…](https://github.com/midwayjs/fork-dep-monitor/pu%E2%80%A6) ([@czy88840616](https://github.com/czy88840616)) * `web-koa` * [#2535](https://github.com/midwayjs/midway/pull/2535) chore: sync code from [https://github.com/midwayjs/fork-dep-monitor/pu…](https://github.com/midwayjs/fork-dep-monitor/pu%E2%80%A6) ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.1 2022年12月14日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `bootstrap` * [#2580](https://github.com/midwayjs/midway/pull/2580) chore: add cluster exit binding ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.2 2022年12月15日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull` * [#2582](https://github.com/midwayjs/midway/pull/2582) fix: merge queue options and job options ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.3 2022年12月19日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![imlh.cn](https://github.com/lhcn.png)](https://github.com/lhcn) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#2547](https://github.com/midwayjs/midway/pull/2547) fix: swagger query object ([@lhcn](https://github.com/lhcn)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `axios`, `typeorm` * [#2587](https://github.com/midwayjs/midway/pull/2587) feat: support typeorm migrate cli ([@czy88840616](https://github.com/czy88840616)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * imlh.cn ([@lhcn](https://github.com/lhcn)) --- # v3.9.4 2022年12月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `typeorm` * [#2588](https://github.com/midwayjs/midway/pull/2588) fix: add ts-node run in migrate ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.5 2022年12月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `typeorm` * [#2590](https://github.com/midwayjs/midway/pull/2590) fix: ignore migrate options for typeorm running ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.6 2022年12月20日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `cross-domain`, `http-proxy`, `static-file` * [#2592](https://github.com/midwayjs/midway/pull/2592) fix: static with cors ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.7 2022年12月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull` * [#2594](https://github.com/midwayjs/midway/pull/2594) fix: bull read new config after config load ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.8 2022年12月27日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `swagger` * [#2602](https://github.com/midwayjs/midway/pull/2602) fix: use lazy function to provide type ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bull` * [#2598](https://github.com/midwayjs/midway/pull/2598) fix(deps): update dependency bull to v4.10.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cache` * [#2597](https://github.com/midwayjs/midway/pull/2597) fix(deps): update dependency @types/cache-manager to v3.4.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#2599](https://github.com/midwayjs/midway/pull/2599) fix(deps): update dependency casbin to v5.19.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v3.9.9 2023年1月5日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web-express`, `web-koa`, `web` * [#2629](https://github.com/midwayjs/midway/pull/2629) fix: use ctx.traceId with otel ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mikro` * [#2638](https://github.com/midwayjs/midway/pull/2638) chore(deps): update mikro-orm monorepo to v5.6.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2613](https://github.com/midwayjs/midway/pull/2613) chore(deps): update mikro-orm monorepo to v5.6.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#2633](https://github.com/midwayjs/midway/pull/2633) chore(deps): update dependency @types/jest to v29.2.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2616](https://github.com/midwayjs/midway/pull/2616) chore(deps): update dependency @types/node to v16.18.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2619](https://github.com/midwayjs/midway/pull/2619) chore(deps): update dependency lerna to v6.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#2617](https://github.com/midwayjs/midway/pull/2617) chore(deps): update dependency @vercel/ncc to v0.36.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#2635](https://github.com/midwayjs/midway/pull/2635) fix(deps): update dependency @grpc/grpc-js to v1.8.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#2636](https://github.com/midwayjs/midway/pull/2636) fix(deps): update dependency koa to v2.14.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `rabbitmq` * [#2634](https://github.com/midwayjs/midway/pull/2634) fix(deps): update dependency amqp-connection-manager to v4.1.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `ws` * [#2637](https://github.com/midwayjs/midway/pull/2637) fix(deps): update dependency ws to v8.11.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#2632](https://github.com/midwayjs/midway/pull/2632) fix(deps): update dependency casbin to v5.20.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc`, `mock`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#2618](https://github.com/midwayjs/midway/pull/2618) chore(deps): update dependency fs-extra to v10.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `rabbitmq` * [#2615](https://github.com/midwayjs/midway/pull/2615) chore(deps): update dependency @types/amqplib to v0.10.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap`, `mock`, `socketio` * [#2612](https://github.com/midwayjs/midway/pull/2612) fix(deps): update socket.io packages to v4.5.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#2620](https://github.com/midwayjs/midway/pull/2620) chore(deps): update dependency mongoose to v6.8.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `sequelize` * [#2621](https://github.com/midwayjs/midway/pull/2621) chore(deps): update dependency sequelize to v6.28.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `typegoose` * [#2614](https://github.com/midwayjs/midway/pull/2614) chore(deps): update dependency @typegoose/typegoose to v9.13.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock` * [#2610](https://github.com/midwayjs/midway/pull/2610) fix(deps): update dependency supertest to v6.3.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `tablestore` * [#2611](https://github.com/midwayjs/midway/pull/2611) fix(deps): update dependency tablestore to v5.3.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#2609](https://github.com/midwayjs/midway/pull/2609) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.11.19 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `passport` * [#2608](https://github.com/midwayjs/midway/pull/2608) chore(deps): update dependency passport-jwt to v4.0.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#2604](https://github.com/midwayjs/midway/pull/2604) fix(deps): update dependency axios to v1.2.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0 2026年3月26日 ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#4531](https://github.com/midwayjs/midway/pull/4531) chore(deps): update dependency @types/node to v20.19.37 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#4530](https://github.com/midwayjs/midway/pull/4530) chore(deps): update dependency axios to v1.13.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) --- # v4.0.0-beta.1 2025年7月6日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Ghoster](https://github.com/ghostker.png)](https://github.com/ghostker) [![harperKKK](https://github.com/harperKKK.png)](https://github.com/harperKKK) [![larry zhuo](https://github.com/larryzhuo.png)](https://github.com/larryzhuo) [![Aaron Liu](https://github.com/liuyuan512.png)](https://github.com/liuyuan512) [![Mirai Zhao](https://github.com/miraizhao.png)](https://github.com/miraizhao) [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) ## 💥 Breaking Change[​](#boom-breaking-change "💥 Breaking Change的直接链接") * `bullmq`, `consul`, `core`, `etcd`, `mcp`, `mock`, `redis`, `swagger`, `web-express`, `web-koa`, `web` * [#4313](https://github.com/midwayjs/midway/pull/4313) feat: support service discovery ([@czy88840616](https://github.com/czy88840616)) * `core`, `i18n`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation` * [#4287](https://github.com/midwayjs/midway/pull/4287) feat: support zod ([@czy88840616](https://github.com/czy88840616)) * `bull`, `core`, `cron`, `grpc`, `kafka`, `mqtt`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4236](https://github.com/midwayjs/midway/pull/4236) feat: Unification framework logger ([@czy88840616](https://github.com/czy88840616)) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `bullmq`, `consul`, `core`, `etcd`, `mcp`, `mock`, `redis`, `swagger`, `web-express`, `web-koa`, `web` * [#4313](https://github.com/midwayjs/midway/pull/4313) feat: support service discovery ([@czy88840616](https://github.com/czy88840616)) * `core`, `i18n`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation` * [#4287](https://github.com/midwayjs/midway/pull/4287) feat: support zod ([@czy88840616](https://github.com/czy88840616)) * `core`, `event-emitter` * [#4285](https://github.com/midwayjs/midway/pull/4285) feat: add events component ([@czy88840616](https://github.com/czy88840616)) * `core`, `mock` * [#4258](https://github.com/midwayjs/midway/pull/4258) feat: try to support HMR ([@czy88840616](https://github.com/czy88840616)) * `core` * [#4250](https://github.com/midwayjs/midway/pull/4250) feat: add lifecycle timeout options ([@czy88840616](https://github.com/czy88840616)) * `bull`, `core`, `cron`, `grpc`, `kafka`, `mqtt`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4236](https://github.com/midwayjs/midway/pull/4236) feat: Unification framework logger ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `bull-board`, `bull`, `bullmq`, `busboy`, `core`, `cron`, `validate` * [#4290](https://github.com/midwayjs/midway/pull/4290) fix: #4295 #4293 #4299 #4294 ([@czy88840616](https://github.com/czy88840616)) * `bull-board`, `bullmq` * [#4286](https://github.com/midwayjs/midway/pull/4286) fix(bull-board): init bull board in resolve ([@harperKKK](https://github.com/harperKKK)) * `kafka` * [#4271](https://github.com/midwayjs/midway/pull/4271) fix: KafkaProducerFactory not init from decorator ([@czy88840616](https://github.com/czy88840616)) * `swagger` * [#4263](https://github.com/midwayjs/midway/pull/4263) fix(swagger): correct typo from 'text/plan' to 'text/plain' ([@ghostker](https://github.com/ghostker)) * `captcha` * [#4242](https://github.com/midwayjs/midway/pull/4242) fix: use security svg-captcha and add more options ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `passport`, `swagger` * [#4350](https://github.com/midwayjs/midway/pull/4350) feat: Add global security requirements ([@czy88840616](https://github.com/czy88840616)) * `bull-board` * [#4346](https://github.com/midwayjs/midway/pull/4346) feat: create board manager on server ready ([@czy88840616](https://github.com/czy88840616)) * `bull-board`, `bullmq`, `web-koa` * [#4330](https://github.com/midwayjs/midway/pull/4330) chore: upgrade bullmq version and update cookie extra options ([@czy88840616](https://github.com/czy88840616)) * `session`, `web-koa` * [#4329](https://github.com/midwayjs/midway/pull/4329) feat: support new cookies options ([@czy88840616](https://github.com/czy88840616)) * `rabbitmq` * [#4326](https://github.com/midwayjs/midway/pull/4326) feat(rabbitmq): add msg into rabbitmq ctx ([@larryzhuo](https://github.com/larryzhuo)) * `core` * [#4311](https://github.com/midwayjs/midway/pull/4311) chore: add TooManyRequestsError to http error ([@liuyuan512](https://github.com/liuyuan512)) * `axios`, `bullmq` * [#4278](https://github.com/midwayjs/midway/pull/4278) feat: add custom axios config typings merge ([@czy88840616](https://github.com/czy88840616)) * `bull-board`, `bullmq` * [#4261](https://github.com/midwayjs/midway/pull/4261) refactor: bullmq ([@czy88840616](https://github.com/czy88840616)) * `core`, `typeorm` * [#4262](https://github.com/midwayjs/midway/pull/4262) feat: support custom data source ([@czy88840616](https://github.com/czy88840616)) * `bull`, `bullmq` * [#4257](https://github.com/midwayjs/midway/pull/4257) feat: add package bullmq ([@harperKKK](https://github.com/harperKKK)) * `info` * [#4220](https://github.com/midwayjs/midway/pull/4220) refactor: add InfoType enumeration to supplement the missing ts syntax type ([@mmdapl](https://github.com/mmdapl)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * Other * [#4343](https://github.com/midwayjs/midway/pull/4343) docs: update mqtt.md ([@miraizhao](https://github.com/miraizhao)) * `axios`, `bootstrap`, `bull-board`, `bull`, `busboy`, `cache-manager`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `etcd`, `grpc`, `i18n`, `info`, `kafka`, `leoric`, `mikro`, `mock`, `mongoose`, `mqtt`, `nextjs`, `oss`, `otel`, `rabbitmq`, `redis`, `sequelize`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `tenant`, `validate`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#4232](https://github.com/midwayjs/midway/pull/4232) docs: use https for github domains ([@mmdapl](https://github.com/mmdapl)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * `axios` * [#4231](https://github.com/midwayjs/midway/pull/4231) refactor: axios component ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4337](https://github.com/midwayjs/midway/pull/4337) fix(deps): update dependency @grpc/proto-loader to v0.7.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4324](https://github.com/midwayjs/midway/pull/4324) fix(deps): update dependency @grpc/grpc-js to v1.13.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4289](https://github.com/midwayjs/midway/pull/4289) fix(deps): update dependency @grpc/grpc-js to v1.12.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4239](https://github.com/midwayjs/midway/pull/4239) fix(deps): update dependency @grpc/grpc-js to v1.12.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4338](https://github.com/midwayjs/midway/pull/4338) fix(deps): update dependency ali-oss to v6.23.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4245](https://github.com/midwayjs/midway/pull/4245) fix(deps): update dependency ali-oss to v6.22.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#4322](https://github.com/midwayjs/midway/pull/4322) fix(deps): update dependency koa to v2.16.1 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy` * [#4310](https://github.com/midwayjs/midway/pull/4310) fix(deps): update dependency axios to v1.8.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4307](https://github.com/midwayjs/midway/pull/4307) fix(deps): update dependency axios to v1.8.3 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4305](https://github.com/midwayjs/midway/pull/4305) fix(deps): update dependency axios to v1.8.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `captcha`, `security` * [#4319](https://github.com/midwayjs/midway/pull/4319) fix(deps): update dependency nanoid to v3.3.11 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `cos` * [#4318](https://github.com/midwayjs/midway/pull/4318) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.14.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4308](https://github.com/midwayjs/midway/pull/4308) fix(deps): update dependency mqtt to v5.10.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4302](https://github.com/midwayjs/midway/pull/4302) fix(deps): update dependency @types/jsonwebtoken to v9.0.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4281](https://github.com/midwayjs/midway/pull/4281) fix(deps): update dependency @types/jsonwebtoken to v9.0.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4303](https://github.com/midwayjs/midway/pull/4303) fix(deps): update dependency leoric to v2.13.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4273](https://github.com/midwayjs/midway/pull/4273) fix(deps): update dependency leoric to v2.13.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4274](https://github.com/midwayjs/midway/pull/4274) chore(deps): update supercharge/mongodb-github-action action to v1.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4282](https://github.com/midwayjs/midway/pull/4282) chore(deps): update dependency @types/node to v22.12.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4256](https://github.com/midwayjs/midway/pull/4256) chore(deps): update dependency @types/node to v22.10.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4227](https://github.com/midwayjs/midway/pull/4227) chore(deps): update dependency @types/node to v22.10.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa` * [#4291](https://github.com/midwayjs/midway/pull/4291) fix(deps): update dependency koa to v2.15.4 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#4276](https://github.com/midwayjs/midway/pull/4276) fix(deps): update dependency qs to v6.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `swagger` * [#4279](https://github.com/midwayjs/midway/pull/4279) chore(deps): update dependency swagger-ui-dist to v5.18.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4283](https://github.com/midwayjs/midway/pull/4283) fix(deps): update dependency bullmq to v5.39.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4275](https://github.com/midwayjs/midway/pull/4275) fix(deps): update dependency bullmq to v5.37.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin` * [#4284](https://github.com/midwayjs/midway/pull/4284) fix(deps): update dependency casbin to v5.38.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4246](https://github.com/midwayjs/midway/pull/4246) fix(deps): update dependency casbin to v5.36.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mikro` * [#4280](https://github.com/midwayjs/midway/pull/4280) chore(deps): update mikro-orm monorepo to v6.4.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4260](https://github.com/midwayjs/midway/pull/4260) chore(deps): update mikro-orm monorepo to v6.4.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4247](https://github.com/midwayjs/midway/pull/4247) chore(deps): update mikro-orm monorepo to v6.4.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4223](https://github.com/midwayjs/midway/pull/4223) chore(deps): update mikro-orm monorepo to v6.4.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `ws` * [#4272](https://github.com/midwayjs/midway/pull/4272) fix(deps): update dependency @types/ws to v8.5.14 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `otel` * [#4265](https://github.com/midwayjs/midway/pull/4265) chore(deps): update dependency @opentelemetry/sdk-node to v0.57.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4235](https://github.com/midwayjs/midway/pull/4235) chore(deps): update dependency @opentelemetry/sdk-node to v0.57.0 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4266](https://github.com/midwayjs/midway/pull/4266) chore(deps): update dependency fs-extra to v11.3.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mongoose`, `typegoose` * [#4264](https://github.com/midwayjs/midway/pull/4264) chore(deps): update dependency mongoose to v8.9.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4253](https://github.com/midwayjs/midway/pull/4253) chore(deps): update dependency mongoose to v8.9.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4238](https://github.com/midwayjs/midway/pull/4238) chore(deps): update dependency mongoose to v8.9.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4233](https://github.com/midwayjs/midway/pull/4233) chore(deps): update dependency mongoose to v8.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4230](https://github.com/midwayjs/midway/pull/4230) chore(deps): update mongoose monorepo ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bootstrap` * [#4248](https://github.com/midwayjs/midway/pull/4248) fix(deps): update dependency @midwayjs/event-bus to v1.11.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bull` * [#4243](https://github.com/midwayjs/midway/pull/4243) fix(deps): update dependency bull to v4.16.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-redis-adapter`, `redis` * [#4244](https://github.com/midwayjs/midway/pull/4244) fix(deps): update dependency ioredis to v5.4.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#4240](https://github.com/midwayjs/midway/pull/4240) chore(deps): update dependency egg-logger to v3.6.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4228](https://github.com/midwayjs/midway/pull/4228) chore(deps): update dependency egg-scripts to v3.1.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 7[​](#committers-7 "Committers: 7的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) * Aaron Liu ([@liuyuan512](https://github.com/liuyuan512)) * Ghoster ([@ghostker](https://github.com/ghostker)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Mirai Zhao ([@miraizhao](https://github.com/miraizhao)) * [@harperKKK](https://github.com/harperKKK) * larryzz ([@larryzhuo](https://github.com/larryzhuo)) --- # v4.0.0-beta.10 2026年1月11日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `one-shot` * [#4484](https://github.com/midwayjs/midway/pull/4484) feat: add one-shot component ([@czy88840616](https://github.com/czy88840616)) * `commander` * [#4478](https://github.com/midwayjs/midway/pull/4478) feat: add commander component ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `busboy`, `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4477](https://github.com/midwayjs/midway/pull/4477) chore(deps): update dependency fs-extra to v11.3.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4482](https://github.com/midwayjs/midway/pull/4482) fix(deps): update dependency body-parser to v2.2.2 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4483](https://github.com/midwayjs/midway/pull/4483) fix(deps): update dependency @types/ali-oss to v6.23.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.11 2026年1月25日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![nobu121](https://github.com/nobu121.png)](https://github.com/nobu121) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4` * [#4492](https://github.com/midwayjs/midway/pull/4492) fix: add OpenSpec instructions and fix joi tsup package ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `oss` * [#4490](https://github.com/midwayjs/midway/pull/4490) fix(deps): update dependency @types/ali-oss to v6.23.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4488](https://github.com/midwayjs/midway/pull/4488) fix(deps): update dependency bullmq to v5.66.5 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4489](https://github.com/midwayjs/midway/pull/4489) fix(deps): update dependency leoric to v2.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 2[​](#committers-2 "Committers: 2的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * [@nobu121](https://github.com/nobu121) --- # v4.0.0-beta.12 2026年2月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💥 Breaking Change[​](#boom-breaking-change "💥 Breaking Change的直接链接") * `axios`, `bull`, `bullmq`, `cache-manager`, `commander`, `consul`, `core`, `cos`, `cron`, `etcd`, `faas`, `grpc`, `info`, `kafka`, `mcp`, `mqtt`, `one-shot`, `oss`, `otel`, `piscina`, `rabbitmq`, `redis`, `socketio`, `tablestore`, `web-express`, `web-koa`, `ws` * [#4507](https://github.com/midwayjs/midway/pull/4507) feat: add request entry async tracing ([@czy88840616](https://github.com/czy88840616)) * `api-bridge`, `axios`, `bootstrap`, `bull-board`, `bull`, `bullmq`, `busboy`, `cache-manager`, `captcha`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `commander`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `etcd`, `event-emitter`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `leoric`, `mcp`, `mikro`, `mock`, `mongoose`, `mqtt`, `nextjs`, `one-shot`, `oss`, `passport`, `piscina`, `processAgent`, `prometheus`, `rabbitmq`, `react`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `validation`, `version`, `view-nunjucks`, `view`, `vue`, `web-bridge`, `web-express`, `web-koa`, `web`, `ws` * [#4504](https://github.com/midwayjs/midway/pull/4504) feat: implement integration code ([@czy88840616](https://github.com/czy88840616)) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `axios`, `bull`, `bullmq`, `cache-manager`, `commander`, `consul`, `core`, `cos`, `cron`, `etcd`, `faas`, `grpc`, `info`, `kafka`, `mcp`, `mqtt`, `one-shot`, `oss`, `otel`, `piscina`, `rabbitmq`, `redis`, `socketio`, `tablestore`, `web-express`, `web-koa`, `ws` * [#4507](https://github.com/midwayjs/midway/pull/4507) feat: add request entry async tracing ([@czy88840616](https://github.com/czy88840616)) * `api-bridge`, `axios`, `bootstrap`, `bull-board`, `bull`, `bullmq`, `busboy`, `cache-manager`, `captcha`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `commander`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `etcd`, `event-emitter`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `leoric`, `mcp`, `mikro`, `mock`, `mongoose`, `mqtt`, `nextjs`, `one-shot`, `oss`, `passport`, `piscina`, `processAgent`, `prometheus`, `rabbitmq`, `react`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `typegoose`, `typeorm`, `upload`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `validation`, `version`, `view-nunjucks`, `view`, `vue`, `web-bridge`, `web-express`, `web-koa`, `web`, `ws` * [#4504](https://github.com/midwayjs/midway/pull/4504) feat: implement integration code ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `mqtt` * [#4503](https://github.com/midwayjs/midway/pull/4503) fix(deps): update dependency mqtt to v5.15.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4505](https://github.com/midwayjs/midway/pull/4505) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.8 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#4502](https://github.com/midwayjs/midway/pull/4502) fix(deps): update dependency qs to v6.14.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `commander` * [#4499](https://github.com/midwayjs/midway/pull/4499) fix(deps): update dependency commander to v14.0.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4491](https://github.com/midwayjs/midway/pull/4491) fix(deps): update dependency bullmq to v5.67.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `nextjs` * [#4494](https://github.com/midwayjs/midway/pull/4494) chore(deps): update dependency next to v16 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4496](https://github.com/midwayjs/midway/pull/4496) fix(deps): update dependency @types/ali-oss to v6.23.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.13 2026年2月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `api-bridge`, `core`, `mock` * [#4509](https://github.com/midwayjs/midway/pull/4509) fix: mock rspack dev runtime ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `bullmq` * [#4498](https://github.com/midwayjs/midway/pull/4498) fix(deps): update dependency bullmq to v5.70.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.14 2026年2月24日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `swagger`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `validation` * [#4510](https://github.com/midwayjs/midway/pull/4510) feat: add swagger validation dto reuse ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `mock` * [#4511](https://github.com/midwayjs/midway/pull/4511) fix: mock app exports ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `nextjs` * [#4497](https://github.com/midwayjs/midway/pull/4497) chore(deps): update dependency next to \~16.1.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.15 2026年2月24日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `api-bridge`, `react`, `validation-class-validator`, `validation-zod`, `validation-zod4`, `vue`, `web-bridge` * [#4512](https://github.com/midwayjs/midway/pull/4512) fix: strengthen esm dist runtime coverage ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.16 2026年3月8日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `crud` * [#4516](https://github.com/midwayjs/midway/pull/4516) feat: add crud component ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core` * [#4522](https://github.com/midwayjs/midway/pull/4522) fix: decorator option naming ([@czy88840616](https://github.com/czy88840616)) * `swagger` * [#4521](https://github.com/midwayjs/midway/pull/4521) fix: Swagger documentation for ApiOperation passthrough ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `oss` * [#4506](https://github.com/midwayjs/midway/pull/4506) fix(deps): update dependency @types/ali-oss to v6.23.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4518](https://github.com/midwayjs/midway/pull/4518) chore(deps): update dependency axios to v1.13.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4495](https://github.com/midwayjs/midway/pull/4495) chore(deps): update hashicorp/consul docker tag to v1.22.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4514](https://github.com/midwayjs/midway/pull/4514) fix(deps): update dependency bullmq to v5.70.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.17 2026年3月22日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `passport`, `validation`, `view-ejs`, `web-express`, `web-koa` * [#4528](https://github.com/midwayjs/midway/pull/4528) fix: align config typings with runtime ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `axios` * [#4529](https://github.com/midwayjs/midway/pull/4529) fix(deps): update dependency axios to v1.13.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `http-proxy` * [#4527](https://github.com/midwayjs/midway/pull/4527) fix(deps): update dependency axios to v1.13.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mcp` * [#4456](https://github.com/midwayjs/midway/pull/4456) chore(deps): update dependency @modelcontextprotocol/sdk to v1.26.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4513](https://github.com/midwayjs/midway/pull/4513) chore(deps): update redis docker tag to v7.4.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4523](https://github.com/midwayjs/midway/pull/4523) fix(deps): update dependency bullmq to v5.71.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4519](https://github.com/midwayjs/midway/pull/4519) fix(deps): update dependency bullmq to v5.70.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-koa`, `web` * [#4524](https://github.com/midwayjs/midway/pull/4524) fix(deps): update dependency qs to v6.15.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `tablestore` * [#4525](https://github.com/midwayjs/midway/pull/4525) fix(deps): update dependency tablestore to v5.6.3 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validation-zod` * [#4526](https://github.com/midwayjs/midway/pull/4526) fix(deps): update dependency zod-validation-error to v3.5.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.2 2025年10月6日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Hongcai Deng](https://github.com/denghongcai.png)](https://github.com/denghongcai) [![He Yongsheng](https://github.com/heyongsheng.png)](https://github.com/heyongsheng) [![142vip.cn](https://github.com/mmdapl.png)](https://github.com/mmdapl) [![NoKic233](https://github.com/Nokic233.png)](https://github.com/Nokic233) [![yuuang](https://github.com/zhangyuang.png)](https://github.com/zhangyuang) ## 💥 Breaking Change[​](#boom-breaking-change "💥 Breaking Change的直接链接") * `web-koa` * [#4396](https://github.com/midwayjs/midway/pull/4396) feat: upgrade koa to v3 ([@czy88840616](https://github.com/czy88840616)) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `axios`, `bootstrap`, `bull-board`, `bull`, `bullmq`, `busboy`, `cache-manager`, `captcha`, `casbin-redis-adapter`, `casbin-typeorm-adapter`, `casbin`, `code-dye`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `etcd`, `event-emitter`, `express-session`, `faas`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `mcp`, `mikro`, `mock`, `mongoose`, `mqtt`, `nextjs`, `oss`, `otel`, `processAgent`, `prometheus-socket-io`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `tablestore`, `tags`, `tenant`, `typegoose`, `typeorm`, `upload`, `validate`, `validation-joi`, `validation-zod`, `validation`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#4404](https://github.com/midwayjs/midway/pull/4404) feat: support mcp ([@czy88840616](https://github.com/czy88840616)) * `web-koa` * [#4396](https://github.com/midwayjs/midway/pull/4396) feat: upgrade koa to v3 ([@czy88840616](https://github.com/czy88840616)) * `bull-board`, `web-koa` * [#4380](https://github.com/midwayjs/midway/pull/4380) feat: add new v4 main page ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `ws` * [#4364](https://github.com/midwayjs/midway/pull/4364) fix: heartbeat does not take effect in koa scenario ([@czy88840616](https://github.com/czy88840616)) * `bull-board` * [#4351](https://github.com/midwayjs/midway/pull/4351) fix: bull-board missing export adapter ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `web-express`, `web-koa`, `web` * [#4371](https://github.com/midwayjs/midway/pull/4371) feat: add random free port ([@czy88840616](https://github.com/czy88840616)) * `typeorm` * [#4369](https://github.com/midwayjs/midway/pull/4369) feat: add config allow typeorm migrations ([@czy88840616](https://github.com/czy88840616)) * `ws` * [#4361](https://github.com/midwayjs/midway/pull/4361) breaking: upgrade cron to 3.5.0, support waitForComplete ([@denghongcai](https://github.com/denghongcai)) * [#4360](https://github.com/midwayjs/midway/pull/4360) feat: add ws upgrade handler ([@czy88840616](https://github.com/czy88840616)) * [#4354](https://github.com/midwayjs/midway/pull/4354) feat: add request to ws context ([@czy88840616](https://github.com/czy88840616)) * `cron` * [#4361](https://github.com/midwayjs/midway/pull/4361) breaking: upgrade cron to 3.5.0, support waitForComplete ([@denghongcai](https://github.com/denghongcai)) ## 📝 Documentation[​](#memo-documentation "📝 Documentation的直接链接") * [#4397](https://github.com/midwayjs/midway/pull/4397) docs: add api docs ([@czy88840616](https://github.com/czy88840616)) * [#4394](https://github.com/midwayjs/midway/pull/4394) docs: Update guard.md ([@Nokic233](https://github.com/Nokic233)) * [#4372](https://github.com/midwayjs/midway/pull/4372) docs: update static\_file.md for static directory not found ([@heyongsheng](https://github.com/heyongsheng)) * [#4370](https://github.com/midwayjs/midway/pull/4370) docs: update static\_file.md for static directory not found ([@heyongsheng](https://github.com/heyongsheng)) * [#4359](https://github.com/midwayjs/midway/pull/4359) docs: update the wrong spelling of DefaultConfig ([@mmdapl](https://github.com/mmdapl)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `grpc` * [#4403](https://github.com/midwayjs/midway/pull/4403) fix(deps): update dependency @grpc/grpc-js to v1.14.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4355](https://github.com/midwayjs/midway/pull/4355) fix(deps): update dependency @grpc/grpc-js to v1.13.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4395](https://github.com/midwayjs/midway/pull/4395) chore(deps): update dependency @types/express to v4.17.23 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4400](https://github.com/midwayjs/midway/pull/4400) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4401](https://github.com/midwayjs/midway/pull/4401) chore(deps): update hashicorp/consul docker tag to v1.21.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4381](https://github.com/midwayjs/midway/pull/4381) fix(deps): update dependency cookie-session to v2.1.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4393](https://github.com/midwayjs/midway/pull/4393) chore(deps): update redis docker tag to v7.4.5 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4389](https://github.com/midwayjs/midway/pull/4389) chore(deps): update hashicorp/consul docker tag to v1.21.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4388](https://github.com/midwayjs/midway/pull/4388) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4373](https://github.com/midwayjs/midway/pull/4373) chore(deps): update mongo docker tag to v4.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4362](https://github.com/midwayjs/midway/pull/4362) fix(deps): update dependency statuses to v2.0.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4392](https://github.com/midwayjs/midway/pull/4392) fix(deps): update dependency leoric to v2.13.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `axios`, `http-proxy`, `web-koa` * [#4391](https://github.com/midwayjs/midway/pull/4391) fix(deps): update dependency axios to v1.12.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `validation-zod` * [#4382](https://github.com/midwayjs/midway/pull/4382) fix(deps): update dependency i18next to v24.2.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `nextjs` * [#4385](https://github.com/midwayjs/midway/pull/4385) chore(deps): update dependency next to \~15.4.0 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4377](https://github.com/midwayjs/midway/pull/4377) fix(deps): update dependency next \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#4366](https://github.com/midwayjs/midway/pull/4366) fix(deps): update dependency koa to v2.16.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4356](https://github.com/midwayjs/midway/pull/4356) fix(deps): update dependency @types/jsonwebtoken to v9.0.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 6[​](#committers-6 "Committers: 6的直接链接") * 142vip.cn ([@mmdapl](https://github.com/mmdapl)) * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * He Yongsheng ([@heyongsheng](https://github.com/heyongsheng)) * Hongcai Deng ([@denghongcai](https://github.com/denghongcai)) * NoKic233 ([@Nokic233](https://github.com/Nokic233)) * yuuang ([@zhangyuang](https://github.com/zhangyuang)) --- # v4.0.0-beta.3 2025年10月10日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core`, `mcp`, `web-express`, `web-koa`, `web` * [#4407](https://github.com/midwayjs/midway/pull/4407) feat: support route version for http ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `busboy`, `upload` * [#4405](https://github.com/midwayjs/midway/pull/4405) fix: special in filename when upload file ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-express` * [#4378](https://github.com/midwayjs/midway/pull/4378) chore(deps): update dependency @types/body-parser to v1.19.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `rabbitmq` * [#4402](https://github.com/midwayjs/midway/pull/4402) fix(deps): update dependency amqp-connection-manager to v4.1.15 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4408](https://github.com/midwayjs/midway/pull/4408) chore(deps): update redis docker tag to v7.4.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4409](https://github.com/midwayjs/midway/pull/4409) fix(deps): update dependency bullmq to v5.61.0 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.4 2025年10月12日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `mcp` * [#4413](https://github.com/midwayjs/midway/pull/4413) fix: missing mcp logger config ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `prometheus` * [#4411](https://github.com/midwayjs/midway/pull/4411) chore(deps): update dependency @types/request to v2.48.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4410](https://github.com/midwayjs/midway/pull/4410) chore(deps): update dependency @types/jest to v29.5.14 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.5 2025年10月19日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `mcp`, `mock` * [#4420](https://github.com/midwayjs/midway/pull/4420) feat: support mcp auth ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `cos` * [#4418](https://github.com/midwayjs/midway/pull/4418) fix(deps): update dependency cos-nodejs-sdk-v5 to v2.15.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4419](https://github.com/midwayjs/midway/pull/4419) fix(deps): update dependency mqtt to v5.14.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.6 2025年10月26日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `validation-class-validator`, `validation-joi`, `validation-zod`, `web-koa` * [#4425](https://github.com/midwayjs/midway/pull/4425) fix: esm metadata support ([@czy88840616](https://github.com/czy88840616)) * `web-koa` * [#4422](https://github.com/midwayjs/midway/pull/4422) fix: add missing app property ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-express` * [#4426](https://github.com/midwayjs/midway/pull/4426) chore(deps): update dependency @types/express to v4.17.24 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4421](https://github.com/midwayjs/midway/pull/4421) chore(deps): update dependency @vercel/ncc to v0.38.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `consul` * [#4415](https://github.com/midwayjs/midway/pull/4415) chore(deps): update dependency @types/sinon to v17.0.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.7 2025年10月26日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `validation-class-validator`, `validation-joi`, `validation-zod` * [#4428](https://github.com/midwayjs/midway/pull/4428) fix: esm pkg will exclude internal package ([@czy88840616](https://github.com/czy88840616)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.8 2025年11月9日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `faas`, `grpc`, `leoric`, `mcp`, `mqtt`, `rabbitmq`, `socketio`, `validate`, `validation-joi`, `validation-zod`, `web-express`, `web`, `ws` * [#4433](https://github.com/midwayjs/midway/pull/4433) fix: load zod json error under esm environment ([@czy88840616](https://github.com/czy88840616)) ## 💅 Polish[​](#nail_care-polish "💅 Polish的直接链接") * `i18n` * [#4414](https://github.com/midwayjs/midway/pull/4414) feat: support i18n missing key handler ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `web-koa` * [#4427](https://github.com/midwayjs/midway/pull/4427) chore(deps): update dependency @types/koa-router to v7.4.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * Other * [#4435](https://github.com/midwayjs/midway/pull/4435) chore(deps): update redis docker tag to v7.4.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `leoric` * [#4436](https://github.com/midwayjs/midway/pull/4436) fix(deps): update dependency leoric to v2.13.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `casbin-typeorm-adapter`, `typeorm` * [#4432](https://github.com/midwayjs/midway/pull/4432) chore(deps): update dependency typeorm to v0.3.26 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.0-beta.9 2026年1月3日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) [![Timon Peng](https://github.com/TimonPeng.png)](https://github.com/TimonPeng) [![yuntian001](https://github.com/yuntian001.png)](https://github.com/yuntian001) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `core`, `mcp`, `redis`, `socketio`, `validation-zod`, `validation-zod4` * [#4472](https://github.com/midwayjs/midway/pull/4472) feat: support zod v4 ([@czy88840616](https://github.com/czy88840616)) * `bootstrap`, `core`, `faas`, `mock`, `piscina`, `web` * [#4459](https://github.com/midwayjs/midway/pull/4459) feat: add background task component ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `web-koa`, `web` * [#4476](https://github.com/midwayjs/midway/pull/4476) fix: qs module parse in first value ([@czy88840616](https://github.com/czy88840616)) * `busboy`, `core`, `validate`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `validation` * [#4473](https://github.com/midwayjs/midway/pull/4473) fix: validation in busboy and upload ([@czy88840616](https://github.com/czy88840616)) * `swagger` * [#4451](https://github.com/midwayjs/midway/pull/4451) fix: swagger ui displayOptions render string ([@TimonPeng](https://github.com/TimonPeng)) * `view` * [#4431](https://github.com/midwayjs/midway/pull/4431) fix: the async render trigger timing in the view component ([@yuntian001](https://github.com/yuntian001)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#4463](https://github.com/midwayjs/midway/pull/4463) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.7 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4469](https://github.com/midwayjs/midway/pull/4469) chore(deps): update hashicorp/consul docker tag to v1.22.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4470](https://github.com/midwayjs/midway/pull/4470) chore(deps): update dependency next to v15.4.9 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4461](https://github.com/midwayjs/midway/pull/4461) chore(deps): update dependency next to v15.4.9 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4458](https://github.com/midwayjs/midway/pull/4458) chore(deps): update dependency next to v15.4.8 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4452](https://github.com/midwayjs/midway/pull/4452) chore(deps): update dependency class-validator to v0.14.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4450](https://github.com/midwayjs/midway/pull/4450) fix(deps): update dependency http-errors to v2.0.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4445](https://github.com/midwayjs/midway/pull/4445) chore(deps): update dependency zx to v8.8.5 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4443](https://github.com/midwayjs/midway/pull/4443) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `bullmq` * [#4474](https://github.com/midwayjs/midway/pull/4474) fix(deps): update dependency bullmq to v5.66.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web-express` * [#4475](https://github.com/midwayjs/midway/pull/4475) fix(deps): update dependency express to v4.22.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4447](https://github.com/midwayjs/midway/pull/4447) fix(deps): update dependency body-parser to v2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4437](https://github.com/midwayjs/midway/pull/4437) chore(deps): update dependency @types/express to v4.17.25 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `grpc` * [#4464](https://github.com/midwayjs/midway/pull/4464) fix(deps): update dependency @grpc/grpc-js to v1.14.3 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4444](https://github.com/midwayjs/midway/pull/4444) fix(deps): update dependency @grpc/grpc-js to v1.14.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `jwt` * [#4468](https://github.com/midwayjs/midway/pull/4468) fix(deps): update dependency jsonwebtoken to v9.0.3 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `http-proxy` * [#4453](https://github.com/midwayjs/midway/pull/4453) chore(deps): update dependency nock to v13.5.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `busboy`, `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4446](https://github.com/midwayjs/midway/pull/4446) chore(deps): update dependency fs-extra to v11.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `oss` * [#4449](https://github.com/midwayjs/midway/pull/4449) fix(deps): update dependency @types/ali-oss to v6.16.13 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#4440](https://github.com/midwayjs/midway/pull/4440) chore(deps): update dependency dayjs to v1.11.19 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock` * [#4442](https://github.com/midwayjs/midway/pull/4442) fix(deps): update dependency js-yaml to v4.1.1 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mock`, `rabbitmq` * [#4438](https://github.com/midwayjs/midway/pull/4438) chore(deps): update dependency amqplib to v0.10.9 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 3[​](#committers-3 "Committers: 3的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) * Timon Peng ([@TimonPeng](https://github.com/TimonPeng)) * yuntian001 ([@yuntian001](https://github.com/yuntian001)) --- # v4.0.1 2026年4月5日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * [#4533](https://github.com/midwayjs/midway/pull/4533) feat: new site ([@czy88840616](https://github.com/czy88840616)) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `react`, `vue` * [#4545](https://github.com/midwayjs/midway/pull/4545) fix(core): Improve the type derivation document and example of the functional API input schema ([@czy88840616](https://github.com/czy88840616)) * `axios`, `bull-board`, `bull`, `bullmq`, `busboy`, `cache-manager`, `captcha`, `casbin`, `code-dye`, `commander`, `consul`, `core`, `cos`, `cron`, `cross-domain`, `etcd`, `event-emitter`, `express-session`, `grpc`, `http-proxy`, `i18n`, `info`, `jwt`, `kafka`, `leoric`, `mcp`, `mikro`, `mongoose`, `mqtt`, `nextjs`, `one-shot`, `oss`, `passport`, `piscina`, `prometheus`, `rabbitmq`, `redis`, `security`, `sequelize`, `session`, `socketio`, `static-file`, `swagger`, `tablestore`, `tags`, `tenant`, `typeorm`, `upload`, `validate`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `validation`, `view-ejs`, `view-nunjucks`, `view`, `web-express`, `web-koa`, `web`, `ws` * [#4537](https://github.com/midwayjs/midway/pull/4537) fix: use public core typing entrypoints ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * Other * [#4543](https://github.com/midwayjs/midway/pull/4543) chore(deps): update dependency @types/node to v20.19.39 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4535](https://github.com/midwayjs/midway/pull/4535) chore(deps): update gcr.io/etcd-development/etcd docker tag to v3.6.10 ([@renovate\[bot\]](https://github.com/apps/renovate)) * [#4539](https://github.com/midwayjs/midway/pull/4539) chore(deps): update hashicorp/consul docker tag to v1.22.6 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `web` * [#4532](https://github.com/midwayjs/midway/pull/4532) chore(deps): update dependency dayjs to v1.11.20 - autoclosed ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core` * [#4540](https://github.com/midwayjs/midway/pull/4540) fix(deps): update dependency @opentelemetry/api to v1.9.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `web-koa` * [#4542](https://github.com/midwayjs/midway/pull/4542) fix(deps): update dependency koa to v3.1.2 \[security] ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.2 2026年4月6日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🚀 New Feature[​](#rocket-new-feature "🚀 New Feature的直接链接") * `commander`, `skill-midway` * [#4549](https://github.com/midwayjs/midway/pull/4549) feat: add skill-midway package and installers ([@czy88840616](https://github.com/czy88840616)) ## 🔧 Maintenance[​](#wrench-maintenance "🔧 Maintenance的直接链接") * [#4547](https://github.com/midwayjs/midway/pull/4547) fix: execa sync scripts ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `busboy`, `grpc`, `rabbitmq`, `socketio`, `web-express`, `web-koa`, `web`, `ws` * [#4546](https://github.com/midwayjs/midway/pull/4546) chore(deps): update dependency fs-extra to v11.3.4 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # v4.0.3 2026年4月12日 [![Harry Chen](https://github.com/czy88840616.png)](https://github.com/czy88840616) ## 🐛 Bug Fix[​](#bug-bug-fix "🐛 Bug Fix的直接链接") * `core`, `mock` * [#4557](https://github.com/midwayjs/midway/pull/4557) fix: Node 20 ESM fallback for TypeScript module graphs ([@czy88840616](https://github.com/czy88840616)) ## 📦 Dependencies[​](#package-dependencies "📦 Dependencies的直接链接") * `casbin-typeorm-adapter`, `crud`, `typeorm` * [#4559](https://github.com/midwayjs/midway/pull/4559) chore(deps): update dependency typeorm to v0.3.28 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `api-bridge`, `react`, `validation-class-validator`, `validation-joi`, `validation-zod`, `validation-zod4`, `vue`, `web-bridge` * [#4558](https://github.com/midwayjs/midway/pull/4558) chore(deps): update dependency tsup to v8.5.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `mqtt` * [#4554](https://github.com/midwayjs/midway/pull/4554) fix(deps): update dependency mqtt to v5.15.1 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `core`, `i18n`, `info`, `security` * [#4555](https://github.com/midwayjs/midway/pull/4555) fix(deps): update dependency picomatch to v2.3.2 ([@renovate\[bot\]](https://github.com/apps/renovate)) * `crud`, `sequelize` * [#4548](https://github.com/midwayjs/midway/pull/4548) chore(deps): update dependency sequelize to v6.37.8 ([@renovate\[bot\]](https://github.com/apps/renovate)) ## Committers: 1[​](#committers-1 "Committers: 1的直接链接") * Harry Chen ([@czy88840616](https://github.com/czy88840616)) --- # 首页布局梳理(用于重设计) 来源页面:[index.tsx](file:///Users/harry/project/open-midway-v3/site/src/pages/index.tsx) ## 顶层布局[​](#顶层布局 "顶层布局的直接链接") * 外层:Docusaurus `Layout` * 内容容器:首屏先隐藏,页面挂载后显示(用 `visibility: hidden/visible` 控制) * 页面结构:由多个纵向堆叠的“全宽区块”组成;多数区块内容区域为居中容器(最大宽度约 1200px),两侧留白,移动端改为单列堆叠 ## 区块顺序(从上到下)[​](#区块顺序从上到下 "区块顺序(从上到下)的直接链接") 1. 区块一:首屏 Hero(全屏) 2. 区块二:核心特性(3 张卡片) 3. 区块三:交互式教程预览(左右双卡) 4. 区块四:核心组件(图标 + 文案列表网格) 5. 区块五:应用案例(图片矩阵) 6. 区块六:推荐项目(推荐卡片) 7. 区块七:信任我们的团队(品牌跑马灯) 8. 区块八:底部收尾(Footer) ## 区块一:首屏 Hero(全屏居中 + 动态文本)[​](#区块一首屏-hero全屏居中--动态文本 "区块一:首屏 Hero(全屏居中 + 动态文本)的直接链接") * **布局** * 全宽、最小高度占满一屏(接近 100vh) * 主要内容水平居中、垂直居中偏上,整体为“标题 + 副标题 + 入口按钮 + GitHub Star”纵向排列 * 背景为主题色 + 径向渐变叠加,叠加大量装饰元素(气泡、几何图形、粒子)做浮动/旋转动画 * **内容/文本** * 主标题:`Midway` * 副标题固定前缀:`Node.js Framework For` * 副标题动态内容:在引号内循环切换(打字效果),候选词: * `Web / Fullstack / Architecture / API / Production / Microservice / Serverless / Speed / Efficiency / Developer / Experience` * 文档入口(两枚胶囊按钮): * `📖 稳定版文档 (v3.x)` → `/docs/intro` * `🚧 Beta 版文档 (v4)` → `/docs/next/intro` * GitHub Star:嵌入 iframe(midwayjs/midway) * `https://ghbtns.com/github-btn.html?user=midwayjs&repo=midway&type=star&count=true&size=large` ## 区块二:核心特性(居中标题 + 三列卡片)[​](#区块二核心特性居中标题--三列卡片 "区块二:核心特性(居中标题 + 三列卡片)的直接链接") * **布局** * 全宽区块,浅色强调背景(带径向渐变) * 顶部为居中标题区(标题 + 副标题) * 下方为卡片网格:桌面端 3 列,移动端单列堆叠 * 中间卡片在视觉上更突出(略放大/更醒目) * **内容/文本** * 区块标题:`核心特性` * 区块副标题:`专为现代 Node.js 应用设计,提供企业级的开发体验和性能表现` * 三张卡片(每张:图标 + 英文标题 + 描述): 1. `Reliable & Fast` * `Class + IoC = 更优雅的架构` * `Function + Hooks = 更高的研发效率` 2. `API & Fullstack` * `不仅支持开发 API 服务,也提供业界首创的一体化全栈开发模式` 3. `Progressive` * `渐进式设计,提供从基础到入门再到企业级的升级方案,解决应用维护与拓展性难题` ## 区块三:交互式教程预览(居中标题 + 左右双卡)[​](#区块三交互式教程预览居中标题--左右双卡 "区块三:交互式教程预览(居中标题 + 左右双卡)的直接链接") * **布局** * 全宽区块,浅色背景(带径向渐变) * 顶部为居中标题区(标题 + 副标题) * 下方为左右双列两张卡片;移动端变为上下堆叠 * **内容/文本** * 区块标题:`🚧 交互式教程 (开发中)` * 区块副标题:`WebContainer 功能正在开发中,即将提供真实的开发环境体验,边学边练,快速掌握 Midway.js` * 左卡:`Class 语法教程` * 描述:`学习如何使用 Class 语法开发 Midway.js 应用` * 列表文案: * `基于装饰器的路由定义` * `依赖注入与服务管理` * `TypeORM 数据库集成` * `组件化开发模式` * 底部按钮:`🚧 即将开放`(不可点击状态) * 右卡:`Function 语法教程` * 描述:`学习如何使用 Function 语法开发 Midway.js 应用` * 列表文案: * `前后端一体化开发` * `函数式 API 设计` * `React Hooks 后端开发` * `零 API 调用模式` * 底部按钮:`🚧 即将开放`(不可点击状态) * 预期入口链接(当前为不可点击状态,仅记录原计划): * Class:`/tutorials/class-syntax` * Function:`/tutorials/function-syntax` ## 区块四:核心组件(居中标题 + 列表网格)[​](#区块四核心组件居中标题--列表网格 "区块四:核心组件(居中标题 + 列表网格)的直接链接") * **布局** * 全宽区块,浅色背景 * 顶部为居中标题区(标题 + 副标题) * 下方为卡片列表网格:每张卡片为“左图标 + 右侧标题/描述”的横向排版 * 桌面端为双列/多列自适应(最小列宽较大,整体偏大卡片);移动端单列 * **内容/文本** * 区块标题:`核心组件` * 区块副标题:`提供丰富的企业级组件,满足各种开发需求,让开发更加高效` * 卡片(标题 / 描述 / 点击跳转链接): * `ORM` / `TypeORM-based database SDK` → `/docs/extensions/orm` * `Redis` / `In-memory database for midway.js` → `/docs/extensions/redis` * `Swagger` / `Generate API documentation` → `/docs/extensions/swagger` * `Mongodb` / `NoSQL Database` → `/docs/extensions/mongodb` * `Cache` / `Memory cache support` → `/docs/extensions/cache` * `OSS` / `Aliyun OSS Support` → `/docs/extensions/oss` ## 区块五:应用案例(深色背景 + 图片矩阵)[​](#区块五应用案例深色背景--图片矩阵 "区块五:应用案例(深色背景 + 图片矩阵)的直接链接") * **布局** * 全宽区块,深色渐变背景 * 顶部为居中标题区(标题 + 副标题) * 下方为图片矩阵(自适应多列),每个图片项可点击打开新窗口 * **内容/文本** * 区块标题:`应用案例` * 区块副标题:`探索 Midway.js 在各种场景下的应用,了解其强大的适应性和灵活性` * 点击跳转:默认打开 `http://demo.midwayjs.org/` * 图片列表(15 张): * `//gw.alicdn.com/imgextra/i4/19999999999999/O1CN01PEPPo02NjasvUe8cc_!!19999999999999-2-tps.png` * `//gw.alicdn.com/tfs/TB1Cdu2UYr1gK0jSZFDXXb9yVXa-1200-669.png` * `//gw.alicdn.com/tfs/TB18DKdjCR26e4jSZFEXXbwuXXa-1200-669.png` * `//gw.alicdn.com/tfs/TB11mzgg0Tfau8jSZFwXXX1mVXa-1200-669.png` * `//gw.alicdn.com/imgextra/i3/19999999999999/O1CN01HLo3Pi2NjasqFIZbi_!!19999999999999-2-tps.png` * `//gw.alicdn.com/imgextra/i2/19999999999999/O1CN01LggSYp2NjassPrZeZ_!!19999999999999-2-tps.png` * `//gw.alicdn.com/tfs/TB1l2LaU1L2gK0jSZFmXXc7iXXa-1200-669.png` * `//gw.alicdn.com/tfs/TB12AhMjcVl614jSZKPXXaGjpXa-1200-669.png` * `//gw.alicdn.com/tfs/TB1NtHPh5pE_u4jSZKbXXbCUVXa-1200-669.png` * `//gw.alicdn.com/tfs/TB1bonEgsieb18jSZFvXXaI3FXa-1200-669.png` * `//gw.alicdn.com/tfs/TB1Fh51U.Y1gK0jSZFMXXaWcVXa-1200-669.png` * `//gw.alicdn.com/tfs/TB1Ro.miMgP7K4jSZFqXXamhVXa-1200-669.png` * `//gw.alicdn.com/imgextra/i1/19999999999999/O1CN01FDOJdG2NjasvEbjxX_!!19999999999999-2-tps.png` * `//gw.alicdn.com/tfs/TB1MM_aU8r0gK0jSZFnXXbRRXXa-1200-669.png` * `//gw.alicdn.com/tfs/TB1Fuy3UYr1gK0jSZFDXXb9yVXa-1200-669.png` ## 区块六:推荐项目(浅色背景 + 推荐卡片)[​](#区块六推荐项目浅色背景--推荐卡片 "区块六:推荐项目(浅色背景 + 推荐卡片)的直接链接") * **布局** * 全宽区块,浅色渐变背景 * 顶部为居中标题区(标题 + 副标题) * 下方为推荐卡片(当前只有一项);卡片为“整图展示”,hover 时出现覆盖层与标题 * **内容/文本** * 区块标题:`推荐项目` * 区块副标题:`来自开源社区的优秀扩展和项目,与 Midway.js 完美配合` * 推荐项: * `Cool js, 面向未来的后台开发框架` * 链接:`https://cool-js.com/` * 图片:`https://img.alicdn.com/imgextra/i3/O1CN01IZJkEY1bJrCKViAAc_!!6000000003445-2-tps-600-200.png` ## 区块七:信任我们的团队(浅色背景 + 横向跑马灯)[​](#区块七信任我们的团队浅色背景--横向跑马灯 "区块七:信任我们的团队(浅色背景 + 横向跑马灯)的直接链接") * **布局** * 全宽区块,浅色强调背景(带径向渐变),背景叠加少量浮动装饰元素 * 顶部为居中标题区(标题 + 副标题) * 下方为品牌 Logo 的横向跑马灯(持续滚动),hover 时更清晰/更亮 * **内容/文本** * 区块标题:`信任我们的团队` * 区块副标题:`来自各大互联网公司的优秀团队都在使用 Midway.js,共同构建更好的应用` * Logo 列表: * iconfont(类名): * `icon-tianmaotmall` * `icon-gaodeditu-quan` * `icon-feizhulogo` * `icon-credit_taobao_icon` * `icon-zijietiaodong` * `icon-dcaadaacdcabasvg` * `icon-is-aliyun_logo` * `icon-vivo` * 图片 URL: * `https://img.alicdn.com/imgextra/i3/O1CN015RbnOy1GX2fWWaBbs_!!6000000000631-2-tps-614-200.png` * `https://img.alicdn.com/imgextra/i4/O1CN01RpFMeb1LiYexaZIcP_!!6000000001333-2-tps-320-150.png` * `https://img.alicdn.com/imgextra/i3/O1CN010wn80L1UR01GSABXa_!!6000000002513-2-tps-277-121.png` * `https://img.alicdn.com/imgextra/i3/O1CN01vsbUzd1T9J6X9VBg7_!!6000000002339-2-tps-400-400.png` * `https://img.alicdn.com/imgextra/i1/O1CN01zw2fMc2266tFQCFQr_!!6000000007070-2-tps-704-255.png` * `https://img.alicdn.com/imgextra/i4/O1CN01RiM9ex1hyycitrJHV_!!6000000004347-2-tps-890-310.png` ## 区块八:底部收尾(深色背景 + 居中文案)[​](#区块八底部收尾深色背景--居中文案 "区块八:底部收尾(深色背景 + 居中文案)的直接链接") * **布局** * 全宽 footer,深色渐变背景,居中对齐 * 文案为“标题 + 一句话”纵向排列,背景有轻微装饰浮动元素 * **内容/文本** * 链接区(四列): * Learn * `Introduction` → `docs/intro` * `Quick Start` → `docs/quick_guide` * `Migration from v2 to v3` → `docs/upgrade_v3` * Community * `Bilibili` → `https://space.bilibili.com/1746017680` * `Zhihu` → `https://zhuanlan.zhihu.com/midwayjs` * More * `Blog` → `blog` * `Changelog` → `/changelog` * `GitHub Issue` → `https://github.com/midwayjs/midway` * Link * `Taobao FED` → `https://fed.taobao.org/` * `ICE` → `https://ice.work/` * `CNode` → `https://cnodejs.org/` * 版权信息:`Copyright © {current year} MidwayJS. Built with Docusaurus.` --- [跳到主要内容](#__docusaurus_skipToContent_fallback) [![midway logo](/img/logo.svg)![midway logo](/img/logo.svg)](/index.md) [**Midway**](/index.md)[使用文档](/docs/intro.md)[组件](/docs/extensions/axios.md)[API](/api.md)[Blog](/blog.md) [4.0.0](/docs/intro.md) * [4.0.0](/docs/intro.md) * [3.0.0](/docs/3.0.0/intro.md) * [2.0.0](/docs/2.0.0/intro.md) * [1.0.0](/docs/1.0.0/intro.md) [中文(中国)](#) * [中文(中国)](/search.md) * [English](/en/search) [社区活动](#) * [线下沙龙](https://subway.midwayjs.org/) [](https://github.com/midwayjs/midway) 搜索 # 在文档中搜索 在此输入搜索词 4.0.0 (current) 由 Algolia 提供[](https://www.algolia.com/) Learn * [Introduction](/docs/intro.md) * [Quick Start](/docs/quick_guide.md) * [Migration from v2 to v3](/docs/upgrade_v3.md) Community * [Bilibili](https://space.bilibili.com/1746017680) * [Zhihu](https://zhuanlan.zhihu.com/midwayjs) More * [Blog](/blog.md) * [Changelog](/changelog.md) * [GitHub Issue](https://github.com/midwayjs/midway) Link * [Taobao FED](https://fed.taobao.org/) * [ICE](https://ice.work/) * [CNode](https://cnodejs.org/) Copyright © 2026 MidwayJS. Built with Docusaurus. --- [跳到主要内容](#__docusaurus_skipToContent_fallback) [![midway logo](/img/logo.svg)![midway logo](/img/logo.svg)](/index.md) [**Midway**](/index.md)[使用文档](/docs/intro.md)[组件](/docs/extensions/axios.md)[API](/api.md)[Blog](/blog.md) [4.0.0](/docs/intro.md) * [4.0.0](/docs/intro.md) * [3.0.0](/docs/3.0.0/intro.md) * [2.0.0](/docs/2.0.0/intro.md) * [1.0.0](/docs/1.0.0/intro.md) [中文(中国)](#) * [中文(中国)](/test-webcontainer.md) * [English](/en/test-webcontainer) [社区活动](#) * [线下沙龙](https://subway.midwayjs.org/) [](https://github.com/midwayjs/midway) 搜索 # WebContainer 组件测试 这个页面用于测试 WebContainer 组件是否正常工作。 ### 📁 项目文件 📄package.json ▶src 📘index.ts 📝README.md ### 📝 代码编辑器 👆 请从左侧文件树中选择一个文件进行编辑 ### 🌐 预览 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 ### 💻 终端 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 Learn * [Introduction](/docs/intro.md) * [Quick Start](/docs/quick_guide.md) * [Migration from v2 to v3](/docs/upgrade_v3.md) Community * [Bilibili](https://space.bilibili.com/1746017680) * [Zhihu](https://zhuanlan.zhihu.com/midwayjs) More * [Blog](/blog.md) * [Changelog](/changelog.md) * [GitHub Issue](https://github.com/midwayjs/midway) Link * [Taobao FED](https://fed.taobao.org/) * [ICE](https://ice.work/) * [CNode](https://cnodejs.org/) Copyright © 2026 MidwayJS. Built with Docusaurus. --- [跳到主要内容](#__docusaurus_skipToContent_fallback) [![midway logo](/img/logo.svg)![midway logo](/img/logo.svg)](/index.md) [**Midway**](/index.md)[使用文档](/docs/intro.md)[组件](/docs/extensions/axios.md)[API](/api.md)[Blog](/blog.md) [4.0.0](/docs/intro.md) * [4.0.0](/docs/intro.md) * [3.0.0](/docs/3.0.0/intro.md) * [2.0.0](/docs/2.0.0/intro.md) * [1.0.0](/docs/1.0.0/intro.md) [中文(中国)](#) * [中文(中国)](/tutorials/.md) * [English](/en/tutorials/) [社区活动](#) * [线下沙龙](https://subway.midwayjs.org/) [](https://github.com/midwayjs/midway) 搜索 # 🚧 教程中心 (开发中) WebContainer 功能正在开发中,即将通过浏览器中的真实开发环境提供交互式学习体验 ** ### Class 语法教程 使用 IoC + 装饰器构建优雅的 Node.js 应用架构 * 基于装饰器的路由定义 * 依赖注入与服务管理 * TypeORM 数据库集成 * 组件化开发模式 难度: 中级时长: 2-3 小时 🚧 即将开放 ** ### Function 语法教程 使用函数 + Hooks 进行快速全栈应用开发 * 前后端一体化开发 * 函数式 API 设计 * React Hooks 后端开发 * 零 API 调用模式 难度: 初级时长: 1-2 小时 🚧 即将开放 Learn * [Introduction](/docs/intro.md) * [Quick Start](/docs/quick_guide.md) * [Migration from v2 to v3](/docs/upgrade_v3.md) Community * [Bilibili](https://space.bilibili.com/1746017680) * [Zhihu](https://zhuanlan.zhihu.com/midwayjs) More * [Blog](/blog.md) * [Changelog](/changelog.md) * [GitHub Issue](https://github.com/midwayjs/midway) Link * [Taobao FED](https://fed.taobao.org/) * [ICE](https://ice.work/) * [CNode](https://cnodejs.org/) Copyright © 2026 MidwayJS. Built with Docusaurus. --- [跳到主要内容](#__docusaurus_skipToContent_fallback) [![midway logo](/img/logo.svg)![midway logo](/img/logo.svg)](/index.md) [**Midway**](/index.md)[使用文档](/docs/intro.md)[组件](/docs/extensions/axios.md)[API](/api.md)[Blog](/blog.md) [4.0.0](/docs/intro.md) * [4.0.0](/docs/intro.md) * [3.0.0](/docs/3.0.0/intro.md) * [2.0.0](/docs/2.0.0/intro.md) * [1.0.0](/docs/1.0.0/intro.md) [中文(中国)](#) * [中文(中国)](/tutorials/class-syntax.md) * [English](/en/tutorials/class-syntax) [社区活动](#) * [线下沙龙](https://subway.midwayjs.org/) [](https://github.com/midwayjs/midway) 搜索 # 🚧 Class 语法教程 (开发中) WebContainer 功能正在开发中,即将提供使用 IoC + 装饰器构建优雅的 Node.js 应用架构的交互式学习体验 1 ### 项目初始化 使用 Midway CLI 创建新的 Class 语法项目,配置 TypeScript 和依赖注入 2 ### 控制器定义 使用装饰器定义路由和控制器,实现 RESTful API 接口 3 ### 服务层开发 创建 Service 类,使用依赖注入管理业务逻辑和数据处理 4 ### 数据模型 集成 TypeORM,定义实体模型,实现数据库操作 5 ### 中间件配置 配置全局中间件,处理跨域、认证、日志等功能 ## 🚀 交互式开发环境 在右侧的 WebContainer 环境中,你可以:
• 浏览项目文件结构
• 实时编辑代码
• 运行和调试应用
• 查看实时预览 ### 📁 项目文件 📄package.json 📄tsconfig.json ▶src 📘configuration.ts ▶controller 📘home.ts ▶service 📘home.ts ▶entity 📘user.ts ▶middleware 📘cors.ts ▶config 📘config.default.ts 📗bootstrap.js ### 📝 代码编辑器 👆 请从左侧文件树中选择一个文件进行编辑 ### 🌐 预览 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 ### 💻 终端 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 Learn * [Introduction](/docs/intro.md) * [Quick Start](/docs/quick_guide.md) * [Migration from v2 to v3](/docs/upgrade_v3.md) Community * [Bilibili](https://space.bilibili.com/1746017680) * [Zhihu](https://zhuanlan.zhihu.com/midwayjs) More * [Blog](/blog.md) * [Changelog](/changelog.md) * [GitHub Issue](https://github.com/midwayjs/midway) Link * [Taobao FED](https://fed.taobao.org/) * [ICE](https://ice.work/) * [CNode](https://cnodejs.org/) Copyright © 2026 MidwayJS. Built with Docusaurus. --- [跳到主要内容](#__docusaurus_skipToContent_fallback) [![midway logo](/img/logo.svg)![midway logo](/img/logo.svg)](/index.md) [**Midway**](/index.md)[使用文档](/docs/intro.md)[组件](/docs/extensions/axios.md)[API](/api.md)[Blog](/blog.md) [4.0.0](/docs/intro.md) * [4.0.0](/docs/intro.md) * [3.0.0](/docs/3.0.0/intro.md) * [2.0.0](/docs/2.0.0/intro.md) * [1.0.0](/docs/1.0.0/intro.md) [中文(中国)](#) * [中文(中国)](/tutorials/function-syntax.md) * [English](/en/tutorials/function-syntax) [社区活动](#) * [线下沙龙](https://subway.midwayjs.org/) [](https://github.com/midwayjs/midway) 搜索 # 🚧 Function 语法教程 (开发中) WebContainer 功能正在开发中,即将提供使用函数 + Hooks 进行快速全栈应用开发的交互式学习体验 1 ### 全栈项目创建 使用 Midway CLI 创建前后端一体化的全栈项目,支持 React + Node.js 开发 2 ### 函数式 API 使用函数定义 API 接口,无需类装饰器,代码更简洁直观 3 ### Hooks 开发 在后端使用类似 React Hooks 的模式,管理状态和副作用 4 ### 零 API 调用 直接从后端导入函数,无需手动发起 HTTP 请求,开发体验更佳 5 ### 部署和扩展 支持 Serverless 部署,轻松扩展到云环境 ## 🚀 交互式开发环境 在右侧的 WebContainer 环境中,你可以:
• 浏览项目文件结构
• 实时编辑代码
• 运行和调试应用
• 查看实时预览 ### 📁 项目文件 📄package.json 📄tsconfig.json ▶src 📘App.tsx ▶apis ▶lambda ▶services 📘user.ts 📘configuration.ts ▶config 📘config.default.ts 📗bootstrap.js ### 📝 代码编辑器 👆 请从左侧文件树中选择一个文件进行编辑 ### 🌐 预览 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 ### 💻 终端 🚧 WebContainer 功能开发中 当前仅支持文件浏览和编辑 Learn * [Introduction](/docs/intro.md) * [Quick Start](/docs/quick_guide.md) * [Migration from v2 to v3](/docs/upgrade_v3.md) Community * [Bilibili](https://space.bilibili.com/1746017680) * [Zhihu](https://zhuanlan.zhihu.com/midwayjs) More * [Blog](/blog.md) * [Changelog](/changelog.md) * [GitHub Issue](https://github.com/midwayjs/midway) Link * [Taobao FED](https://fed.taobao.org/) * [ICE](https://ice.work/) * [CNode](https://cnodejs.org/) Copyright © 2026 MidwayJS. Built with Docusaurus. --- # API ### Packages * [v](/api/3.0.0/async-hooks-context-manager.md) [3.20.11 @midwayjs/async-hooks-context-manager](/api/3.0.0/async-hooks-context-manager.md) * [v](/api/3.0.0/axios.md) [3.20.11 @midwayjs/axios](/api/3.0.0/axios.md) * [v](/api/3.0.0/bootstrap.md) [3.20.11 @midwayjs/bootstrap](/api/3.0.0/bootstrap.md) * [v](/api/3.0.0/bull.md) [3.20.11 @midwayjs/bull](/api/3.0.0/bull.md) * [v](/api/3.0.0/bull-board.md) [3.20.13 @midwayjs/bull-board](/api/3.0.0/bull-board.md) * [v](/api/3.0.0/captcha.md) [3.20.13 @midwayjs/captcha](/api/3.0.0/captcha.md) * [v](/api/3.0.0/casbin.md) [3.20.13 @midwayjs/casbin](/api/3.0.0/casbin.md) * [v](/api/3.0.0/casbin-redis-adapter.md) [3.20.13 @midwayjs/casbin-redis-adapter](/api/3.0.0/casbin-redis-adapter.md) * [v](/api/3.0.0/casbin-typeorm-adapter.md) [3.20.13 @midwayjs/casbin-typeorm-adapter](/api/3.0.0/casbin-typeorm-adapter.md) * [v](/api/3.0.0/code-dye.md) [3.20.13 @midwayjs/code-dye](/api/3.0.0/code-dye.md) * [v](/api/3.0.0/consul.md) [3.20.13 @midwayjs/consul](/api/3.0.0/consul.md) * [v](/api/3.0.0/core.md) [3.20.11 @midwayjs/core](/api/3.0.0/core.md) * [v](/api/3.0.0/cos.md) [3.20.11 @midwayjs/cos](/api/3.0.0/cos.md) * [v](/api/3.0.0/cron.md) [3.20.11 @midwayjs/cron](/api/3.0.0/cron.md) * [v](/api/3.0.0/cross-domain.md) [3.20.13 @midwayjs/cross-domain](/api/3.0.0/cross-domain.md) * [v](/api/3.0.0/decorator.md) [3.20.11 @midwayjs/decorator](/api/3.0.0/decorator.md) * [v](/api/3.0.0/etcd.md) [3.20.11 @midwayjs/etcd](/api/3.0.0/etcd.md) * [v](/api/3.0.0/web-express.md) [3.20.12 @midwayjs/express](/api/3.0.0/web-express.md) * [v](/api/3.0.0/express-session.md) [3.20.11 @midwayjs/express-session](/api/3.0.0/express-session.md) * [v](/api/3.0.0/faas.md) [3.20.11 @midwayjs/faas](/api/3.0.0/faas.md) * [v](/api/3.0.0/grpc.md) [3.20.12 @midwayjs/grpc](/api/3.0.0/grpc.md) * [v](/api/3.0.0/http-proxy.md) [3.20.13 @midwayjs/http-proxy](/api/3.0.0/http-proxy.md) * [v](/api/3.0.0/i18n.md) [3.20.13 @midwayjs/i18n](/api/3.0.0/i18n.md) * [v](/api/3.0.0/info.md) [3.20.13 @midwayjs/info](/api/3.0.0/info.md) * [v](/api/3.0.0/jwt.md) [3.20.13 @midwayjs/jwt](/api/3.0.0/jwt.md) * [v](/api/3.0.0/kafka.md) [3.20.11 @midwayjs/kafka](/api/3.0.0/kafka.md) * [v](/api/3.0.0/web-koa.md) [3.20.13 @midwayjs/koa](/api/3.0.0/web-koa.md) * [v](/api/3.0.0/mikro.md) [3.20.13 @midwayjs/mikro](/api/3.0.0/mikro.md) * [v](/api/3.0.0/mock.md) [3.20.11 @midwayjs/mock](/api/3.0.0/mock.md) * [v](/api/3.0.0/mongoose.md) [3.20.11 @midwayjs/mongoose](/api/3.0.0/mongoose.md) * [v](/api/3.0.0/otel.md) [3.20.13 @midwayjs/otel](/api/3.0.0/otel.md) * [v](/api/3.0.0/passport.md) [3.20.13 @midwayjs/passport](/api/3.0.0/passport.md) * [v](/api/3.0.0/processAgent.md) [3.20.13 @midwayjs/process-agent](/api/3.0.0/processAgent.md) * [v](/api/3.0.0/prometheus.md) [3.20.13 @midwayjs/prometheus](/api/3.0.0/prometheus.md) * [v](/api/3.0.0/prometheus-socket-io.md) [3.20.13 @midwayjs/prometheus-socket-io](/api/3.0.0/prometheus-socket-io.md) * [v](/api/3.0.0/rabbitmq.md) [3.20.11 @midwayjs/rabbitmq](/api/3.0.0/rabbitmq.md) * [v](/api/3.0.0/redis.md) [3.20.11 @midwayjs/redis](/api/3.0.0/redis.md) * [v](/api/3.0.0/security.md) [3.20.13 @midwayjs/security](/api/3.0.0/security.md) * [v](/api/3.0.0/sequelize.md) [3.20.13 @midwayjs/sequelize](/api/3.0.0/sequelize.md) * [v](/api/3.0.0/session.md) [3.20.11 @midwayjs/session](/api/3.0.0/session.md) * [v](/api/3.0.0/socketio.md) [3.20.11 @midwayjs/socketio](/api/3.0.0/socketio.md) * [v](/api/3.0.0/static-file.md) [3.20.13 @midwayjs/static-file](/api/3.0.0/static-file.md) * [v](/api/3.0.0/swagger.md) [3.20.13 @midwayjs/swagger](/api/3.0.0/swagger.md) * [v](/api/3.0.0/tablestore.md) [3.20.11 @midwayjs/tablestore](/api/3.0.0/tablestore.md) * [v](/api/3.0.0/tags.md) [3.20.13 @midwayjs/tags](/api/3.0.0/tags.md) * [v](/api/3.0.0/typegoose.md) [3.20.11 @midwayjs/typegoose](/api/3.0.0/typegoose.md) * [v](/api/3.0.0/typeorm.md) [3.20.11 @midwayjs/typeorm](/api/3.0.0/typeorm.md) * [v](/api/3.0.0/upload.md) [3.20.13 @midwayjs/upload](/api/3.0.0/upload.md) * [v](/api/3.0.0/validate.md) [3.20.13 @midwayjs/validate](/api/3.0.0/validate.md) * [v](/api/3.0.0/view.md) [3.20.13 @midwayjs/view](/api/3.0.0/view.md) * [v](/api/3.0.0/view-ejs.md) [3.20.13 @midwayjs/view-ejs](/api/3.0.0/view-ejs.md) * [v](/api/3.0.0/view-nunjucks.md) [3.20.13 @midwayjs/view-nunjucks](/api/3.0.0/view-nunjucks.md) * [v](/api/3.0.0/web.md) [3.20.12 @midwayjs/web](/api/3.0.0/web.md) * [v](/api/3.0.0/ws.md) [3.20.13 @midwayjs/ws](/api/3.0.0/ws.md) Powered by [docusaurus-plugin-typedoc-api](https://github.com/milesj/docusaurus-plugin-typedoc-api) and [TypeDoc](https://typedoc.org/) --- # @midwayjs/async-hooks-context-manager ## Index[**](#Index) ### Classes * [**AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) * [**AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) ### Functions * [**createContextManager](/api/3.0.0/async-hooks-context-manager/function/createContextManager.md) * [**isSemverGreaterThanOrEqualTo](/api/3.0.0/async-hooks-context-manager/function/isSemverGreaterThanOrEqualTo.md) --- # AsyncHooksContextManager ### Implements * AsyncContextManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**active](#active) * [**bind](#bind) * [**disable](#disable) * [**enable](#enable) * [**with](#with) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L29)constructor * **new AsyncHooksContextManager(): [AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) ## Methods[**](#Methods) ### [**](#active)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L39)active * **active(): AsyncContext - Implementation of AsyncContextManager.active ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L135)bind * **bind\(context: AsyncContext, target: T): T - Implementation of AsyncContextManager.bind Binds a the certain context or the active one to the target function and then returns the target *** #### Type parameters * **T** ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L62)disable * **disable(): [AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) - Implementation of AsyncContextManager.disable ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L57)enable * **enable(): [AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) - Implementation of AsyncContextManager.enable ### [**](#with)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncHooksContextManager.ts#L43)with * **with\(context: AsyncContext, fn: F, thisArg? : ThisParameterType\, ...args: A): ReturnType\ - Implementation of AsyncContextManager.with #### Type parameters * **A**: unknown\[] * **F**: (...args: A) => ReturnType\ --- # AsyncLocalStorageContextManager ### Implements * AsyncContextManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**active](#active) * [**bind](#bind) * [**disable](#disable) * [**enable](#enable) * [**with](#with) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L27)constructor * **new AsyncLocalStorageContextManager(): [AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) ## Methods[**](#Methods) ### [**](#active)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L31)active * **active(): AsyncContext - Implementation of AsyncContextManager.active ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L60)bind * **bind\(context: AsyncContext, target: T): T - Implementation of AsyncContextManager.bind Binds a the certain context or the active one to the target function and then returns the target *** #### Type parameters * **T** ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L49)disable * **disable(): [AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) - Implementation of AsyncContextManager.disable ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L45)enable * **enable(): [AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) - Implementation of AsyncContextManager.enable ### [**](#with)[**](https://github.com/midwayjs/midway/blob/main/packages/async-hooks-context-manager/src/asyncLocalStorageContextManager.ts#L35)with * **with\(context: AsyncContext, fn: F, thisArg? : ThisParameterType\, ...args: A): ReturnType\ - Implementation of AsyncContextManager.with #### Type parameters * **A**: unknown\[] * **F**: (...args: A) => ReturnType\ --- # createContextManager ### Callable * **createContextManager(): [AsyncLocalStorageContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncLocalStorageContextManager.md) | [AsyncHooksContextManager](/api/3.0.0/async-hooks-context-manager/class/AsyncHooksContextManager.md) --- # isSemverGreaterThanOrEqualTo ### Callable * **isSemverGreaterThanOrEqualTo(currentVersion: string, targetVersion: string): boolean --- # @midwayjs/axios ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/axios/class/Configuration.md) * [**HttpService](/api/3.0.0/axios/class/HttpService.md) * [**HttpServiceFactory](/api/3.0.0/axios/class/HttpServiceFactory.md) ### Interfaces * [**AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md) * [**AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [AxiosConfiguration](/api/3.0.0/axios/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/configuration.ts#L33)publiconReady * **onReady(container: IMidwayContainer): Promise\ --- # HttpService ### Implements * Axios ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**defaults](#defaults) * [**interceptors](#interceptors) ### Methods * [**delete](#delete) * [**get](#get) * [**getUri](#getUri) * [**head](#head) * [**options](#options) * [**patch](#patch) * [**patchForm](#patchForm) * [**post](#post) * [**postForm](#postForm) * [**put](#put) * [**putForm](#putForm) * [**request](#request) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpService(): [HttpService](/api/3.0.0/axios/class/HttpService.md) ## Accessors[**](#Accessors) ### [**](#defaults)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L30)defaults * **get defaults(): Omit\, headers> & {} - Implementation of Axios.defaults ### [**](#interceptors)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L34)interceptors * **get interceptors(): {} - Implementation of Axios.interceptors ## Methods[**](#Methods) ### [**](#delete)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L55)delete * **delete\(url: string, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.delete #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L48)get * **get\(url: string, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.get #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#getUri)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L38)getUri * **getUri(config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): string - Implementation of Axios.getUri ### [**](#head)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L62)head * **head\(url: string, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.head #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L69)options * **options\(url: string, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.options #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#patch)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L92)patch * **patch\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.patch #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#patchForm)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L116)patchForm * **patchForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.patchForm #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#post)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L76)post * **post\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.post #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#postForm)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L100)postForm * **postForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.postForm #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#put)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L84)put * **put\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.put #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#putForm)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L108)putForm * **putForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.putForm #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.ts#L42)request * **request\(config: [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\): Promise\ - Implementation of Axios.request #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/3.0.0/axios/interface/AxiosResponse.md)\ * **D** = any --- # HttpServiceFactory ### Hierarchy * ServiceFactory\ * *HttpServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**axiosConfig](#axiosConfig) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpServiceFactory(): [HttpServiceFactory](/api/3.0.0/axios/class/HttpServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#axiosConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.factory.ts#L15)axiosConfig **axiosConfig: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = AxiosInstance ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.factory.ts#L30)publicgetName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/http-service.factory.ts#L18)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # AxiosRequestConfig \ Interface for custom axios request config merging. ### Hierarchy * AxiosRequestConfig\ * *AxiosRequestConfig* --- # AxiosResponse \ ### Hierarchy * AxiosResponse\ * *AxiosResponse* ## Index[**](#Index) ### Properties * [**config](#config) ## Properties[**](#Properties) ### [**](#config)[**](https://github.com/midwayjs/midway/blob/main/packages/axios/src/interface.ts#L12)config **config: [AxiosRequestConfig](/api/3.0.0/axios/interface/AxiosRequestConfig.md)\ & { headers: AxiosRequestHeaders } Overrides OriginAxiosResponse.config --- # @midwayjs/bootstrap ## Index[**](#Index) ### Classes * [**AbstractForkManager](/api/3.0.0/bootstrap/class/AbstractForkManager.md) * [**Bootstrap](/api/3.0.0/bootstrap/class/Bootstrap.md) * [**BootstrapStarter](/api/3.0.0/bootstrap/class/BootstrapStarter.md) * [**ClusterManager](/api/3.0.0/bootstrap/class/ClusterManager.md) ### Functions * [**setupStickyMaster](/api/3.0.0/bootstrap/function/setupStickyMaster.md) ### Interfaces * [**ForkOptions](/api/3.0.0/bootstrap/interface/ForkOptions.md) * [**IForkManager](/api/3.0.0/bootstrap/interface/IForkManager.md) ### Type Aliases * [**ClusterOptions](/api/3.0.0/bootstrap.md#ClusterOptions) * [**ThreadOptions](/api/3.0.0/bootstrap.md#ThreadOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#ClusterOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L44)ClusterOptions **ClusterOptions: [ForkOptions](/api/3.0.0/bootstrap/interface/ForkOptions.md) & ClusterSettings & { sticky? : boolean; stickyLoadBalancingMethod? : random | round-robin | least-connection } ### [**](#ThreadOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L49)ThreadOptions **ThreadOptions: [ForkOptions](/api/3.0.0/bootstrap/interface/ForkOptions.md) & WorkerOptions --- # abstractAbstractForkManager \ ### Hierarchy * *AbstractForkManager* * [ClusterManager](/api/3.0.0/bootstrap/class/ClusterManager.md) ## Index[**](#Index) ### Properties * [**options](#options) ### Methods * [**bindWorkerDisconnect](#bindWorkerDisconnect) * [**bindWorkerExit](#bindWorkerExit) * [**closeWorker](#closeWorker) * [**createEventBus](#createEventBus) * [**createWorker](#createWorker) * [**getWorker](#getWorker) * [**getWorkerId](#getWorkerId) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**onStop](#onStop) * [**start](#start) * [**stop](#stop) ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L24)readonlyoptions **options: ClusterOptions ## Methods[**](#Methods) ### [**](#bindWorkerDisconnect)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L343)abstractbindWorkerDisconnect * **bindWorkerDisconnect(listener: (worker: Worker) => void): void ### [**](#bindWorkerExit)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L344)abstractbindWorkerExit * **bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void ### [**](#closeWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L349)abstractcloseWorker * **closeWorker(worker: Worker): any ### [**](#createEventBus)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L350)abstractcreateEventBus * **createEventBus(eventBusOptions: EventBusOptions\): IEventBus\ ### [**](#createWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L342)abstractcreateWorker * **createWorker(oldWorker? : Worker): Worker ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L289)publicgetWorker * **getWorker(workerId: string): Worker ### [**](#getWorkerId)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L347)abstractgetWorkerId * **getWorkerId(worker: Worker): string ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L293)publicgetWorkerIds * **getWorkerIds(): string\[] ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L285)publichasWorker * **hasWorker(workerId: string): boolean ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L353)abstractisPrimary * **isPrimary(): boolean ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L348)abstractisWorkerDead * **isWorkerDead(worker: Worker): boolean ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L297)publiconStop * **onStop(exitListener: any): void ### [**](#start)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L36)publicstart * **start(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L271)publicstop * **stop(timeout? : number): Promise\ --- # Bootstrap ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**configure](#configure) * [**getApplicationContext](#getApplicationContext) * [**getStarter](#getStarter) * [**reset](#reset) * [**run](#run) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Bootstrap(): [Bootstrap](/api/3.0.0/bootstrap/class/Bootstrap.md) ## Methods[**](#Methods) ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L127)staticconfigure * **configure(configuration? : IMidwayBootstrapOptions): typeof [Bootstrap](/api/3.0.0/bootstrap/class/Bootstrap.md) - set global configuration for midway ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L267)staticgetApplicationContext * **getApplicationContext(): IMidwayContainer ### [**](#getStarter)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L158)staticgetStarter * **getStarter(): [BootstrapStarter](/api/3.0.0/bootstrap/class/BootstrapStarter.md) ### [**](#reset)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L210)staticreset * **reset(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L165)staticrun * **run(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L199)staticstop * **stop(): Promise\ --- # BootstrapStarter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**configure](#configure) * [**getApplicationContext](#getApplicationContext) * [**init](#init) * [**run](#run) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BootstrapStarter(): [BootstrapStarter](/api/3.0.0/bootstrap/class/BootstrapStarter.md) ## Methods[**](#Methods) ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L30)publicconfigure * **configure(options? : IMidwayBootstrapOptions): [BootstrapStarter](/api/3.0.0/bootstrap/class/BootstrapStarter.md) ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L101)publicgetApplicationContext * **getApplicationContext(): IMidwayContainer ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L35)publicinit * **init(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L70)publicrun * **run(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/bootstrap.ts#L92)publicstop * **stop(): Promise\ --- # ClusterManager ### Hierarchy * [AbstractForkManager](/api/3.0.0/bootstrap/class/AbstractForkManager.md)\ * *ClusterManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**bindWorkerDisconnect](#bindWorkerDisconnect) * [**bindWorkerExit](#bindWorkerExit) * [**closeWorker](#closeWorker) * [**createEventBus](#createEventBus) * [**createWorker](#createWorker) * [**getWorker](#getWorker) * [**getWorkerId](#getWorkerId) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**onStop](#onStop) * [**start](#start) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L15)constructor * **new ClusterManager(options? : [ClusterOptions](/api/3.0.0/bootstrap.md#ClusterOptions)): [ClusterManager](/api/3.0.0/bootstrap/class/ClusterManager.md) - Overrides AbstractForkManager< Worker, ClusterOptions >.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L15)readonlyoptions **options: [ClusterOptions](/api/3.0.0/bootstrap.md#ClusterOptions) = {} Inherited from AbstractForkManager.options ## Methods[**](#Methods) ### [**](#bindWorkerDisconnect)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L36)bindWorkerDisconnect * **bindWorkerDisconnect(listener: (worker: Worker) => void): void - Overrides AbstractForkManager.bindWorkerDisconnect ### [**](#bindWorkerExit)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L41)bindWorkerExit * **bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void - Overrides AbstractForkManager.bindWorkerExit ### [**](#closeWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L54)closeWorker * **closeWorker(worker: Worker): void - Overrides AbstractForkManager.closeWorker ### [**](#createEventBus)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L58)createEventBus * **createEventBus(options: any): any - Overrides AbstractForkManager.createEventBus ### [**](#createWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L23)createWorker * **createWorker(): any - Overrides AbstractForkManager.createWorker ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L289)publicgetWorker * **getWorker(workerId: string): Worker - Inherited from AbstractForkManager.getWorker ### [**](#getWorkerId)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L46)getWorkerId * **getWorkerId(worker: Worker): string - Overrides AbstractForkManager.getWorkerId ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L293)publicgetWorkerIds * **getWorkerIds(): string\[] - Inherited from AbstractForkManager.getWorkerIds ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L285)publichasWorker * **hasWorker(workerId: string): boolean - Inherited from AbstractForkManager.hasWorker ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L62)isPrimary * **isPrimary(): boolean - Overrides AbstractForkManager.isPrimary ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/cp.ts#L50)isWorkerDead * **isWorkerDead(worker: Worker): boolean - Overrides AbstractForkManager.isWorkerDead ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L297)publiconStop * **onStop(exitListener: any): void - Inherited from AbstractForkManager.onStop ### [**](#start)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L36)publicstart * **start(): Promise\ - Inherited from AbstractForkManager.start ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/manager/base.ts#L271)publicstop * **stop(timeout? : number): Promise\ - Inherited from AbstractForkManager.stop --- # setupStickyMaster ### Callable * **setupStickyMaster(httpServer: any, opts? : {}): void --- # ForkOptions ## Index[**](#Index) ### Properties * [**count](#count) * [**duration](#duration) * [**env](#env) * [**exec](#exec) * [**limit](#limit) * [**logger](#logger) * [**refork](#refork) * [**workerInitTimeout](#workerInitTimeout) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L10)optionalcount **count? : number worker num, default is `os.cpus().length` ### [**](#duration)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L20)optionalduration **duration? : number ### [**](#env)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L26)optionalenv **env? : Record\ Some environments set to worker ### [**](#exec)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L6)optionalexec **exec? : string ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L18)optionallimit **limit? : number restart limit, default is `60` ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L22)optionallogger **logger? : MidwayLogger | Console ### [**](#refork)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L14)optionalrefork **refork? : boolean refork when disconect and unexpected exit, default is `true` ### [**](#workerInitTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L31)optionalworkerInitTimeout **workerInitTimeout? : number Worker init Timeout, default is 30s, --- # IForkManager \ ## Index[**](#Index) ### Methods * [**close](#close) * [**getWorker](#getWorker) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**start](#start) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L36)close * **close(): any ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L38)getWorker * **getWorker(workerId: string): T ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L39)getWorkerIds * **getWorkerIds(): string\[] ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L37)hasWorker * **hasWorker(workerId: string): boolean ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L41)isPrimary * **isPrimary(): boolean ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L40)isWorkerDead * **isWorkerDead(worker: T): boolean ### [**](#start)[**](https://github.com/midwayjs/midway/blob/main/packages/bootstrap/src/interface.ts#L35)start * **start(): any --- # @midwayjs/bull ## Index[**](#Index) ### Classes * [**BullQueue](/api/3.0.0/bull/class/BullQueue.md) * [**Configuration](/api/3.0.0/bull/class/Configuration.md) * [**Framework](/api/3.0.0/bull/class/Framework.md) ### Functions * [**InjectQueue](/api/3.0.0/bull/function/InjectQueue.md) * [**Processor](/api/3.0.0/bull/function/Processor.md) ### Interfaces * [**Application](/api/3.0.0/bull/interface/Application.md) * [**Context](/api/3.0.0/bull/interface/Context.md) * [**IProcessor](/api/3.0.0/bull/interface/IProcessor.md) * [**IQueue](/api/3.0.0/bull/interface/IQueue.md) * [**IQueueManager](/api/3.0.0/bull/interface/IQueueManager.md) ### Type Aliases * [**NextFunction](/api/3.0.0/bull.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L30)NextFunction **NextFunction: BaseNextFunction --- # @midwayjs/bull-board ## Index[**](#Index) ### Classes * [**BoardMiddleware](/api/3.0.0/bull-board/class/BoardMiddleware.md) * [**BullBoardManager](/api/3.0.0/bull-board/class/BullBoardManager.md) * [**Configuration](/api/3.0.0/bull-board/class/Configuration.md) * [**MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) ### Interfaces * [**BullBoardOption](/api/3.0.0/bull-board/interface/BullBoardOption.md) --- # BoardMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BoardMiddleware(): [BoardMiddleware](/api/3.0.0/bull-board/class/BoardMiddleware.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.middleware.ts#L51)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.middleware.ts#L148)staticgetName * **getName(): string --- # BullBoardManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addQueue](#addQueue) * [**getBasePath](#getBasePath) * [**getBullBoardOrigin](#getBullBoardOrigin) * [**getServerAdapter](#getServerAdapter) * [**removeQueue](#removeQueue) * [**replaceQueues](#replaceQueues) * [**setBullBoard](#setBullBoard) * [**setQueues](#setQueues) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BullBoardManager(): [BullBoardManager](/api/3.0.0/bull-board/class/BullBoardManager.md) ## Methods[**](#Methods) ### [**](#addQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L86)publicaddQueue * **addQueue(queue: BaseAdapter): void ### [**](#getBasePath)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L70)publicgetBasePath * **getBasePath(): string ### [**](#getBullBoardOrigin)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L82)publicgetBullBoardOrigin * **getBullBoardOrigin(): {} ### [**](#getServerAdapter)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L74)publicgetServerAdapter * **getServerAdapter(): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) ### [**](#removeQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L90)publicremoveQueue * **removeQueue(queueOrName: string | BaseAdapter): void ### [**](#replaceQueues)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L94)publicreplaceQueues * **replaceQueues(newBullQueues: readonly BaseAdapter\[]): void ### [**](#setBullBoard)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L78)publicsetBullBoard * **setBullBoard(bullBoard: {}): void ### [**](#setQueues)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/board.manager.ts#L98)publicsetQueues * **setQueues(newBullQueues: readonly BaseAdapter\[]): void --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) * [**onServerReady](#onServerReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BullBoardConfiguration](/api/3.0.0/bull-board/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/configuration.ts#L29)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/configuration.ts#L32)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/configuration.ts#L34)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/configuration.ts#L52)onServerReady * **onServerReady(container: IMidwayContainer): Promise\ --- # MidwayAdapter ### Implements * IServerAdapter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getEntryRoute](#getEntryRoute) * [**getStaticRoutes](#getStaticRoutes) * [**getViewRoutes](#getViewRoutes) * [**matchApiRoutes](#matchApiRoutes) * [**renderStatic](#renderStatic) * [**renderView](#renderView) * [**runAPI](#runAPI) * [**setApiRoutes](#setApiRoutes) * [**setBasePath](#setBasePath) * [**setEntryRoute](#setEntryRoute) * [**setErrorHandler](#setErrorHandler) * [**setQueues](#setQueues) * [**setStaticPath](#setStaticPath) * [**setUIConfig](#setUIConfig) * [**setViewsPath](#setViewsPath) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayAdapter(): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) ## Methods[**](#Methods) ### [**](#getEntryRoute)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L70)publicgetEntryRoute * **getEntryRoute(): AppViewRoute ### [**](#getStaticRoutes)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L99)publicgetStaticRoutes * **getStaticRoutes(): string ### [**](#getViewRoutes)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L79)publicgetViewRoutes * **getViewRoutes(): string\[] ### [**](#matchApiRoutes)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L84)publicmatchApiRoutes * **matchApiRoutes(method: string, url: string): AppControllerRoute ### [**](#renderStatic)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L103)publicrenderStatic * **renderStatic(filename: any): Promise\ ### [**](#renderView)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L118)publicrenderView * **renderView(filename: any, params? : {}): Promise\ ### [**](#runAPI)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L144)publicrunAPI * **runAPI(route: any, query: any): Promise\ ### [**](#setApiRoutes)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L55)publicsetApiRoutes * **setApiRoutes(routes: AppControllerRoute\[]): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setApiRoutes ### [**](#setBasePath)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L24)publicsetBasePath * **setBasePath(path: string): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) ### [**](#setEntryRoute)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L65)publicsetEntryRoute * **setEntryRoute(routeDef: AppViewRoute): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setEntryRoute ### [**](#setErrorHandler)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L48)publicsetErrorHandler * **setErrorHandler(handler: (error: Error) => ControllerHandlerReturnType): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setErrorHandler ### [**](#setQueues)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L74)publicsetQueues * **setQueues(bullBoardQueues: BullBoardQueues): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setQueues ### [**](#setStaticPath)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L34)publicsetStaticPath * **setStaticPath(staticsRoute: string, staticsPath: string): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setStaticPath ### [**](#setUIConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L29)publicsetUIConfig * **setUIConfig(config: Partial<{}>): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setUIConfig ### [**](#setViewsPath)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/adapter.ts#L43)publicsetViewsPath * **setViewsPath(viewPath: string): [MidwayAdapter](/api/3.0.0/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setViewsPath --- # BullBoardOption ## Index[**](#Index) ### Properties * [**adapterOptions](#adapterOptions) * [**basePath](#basePath) * [**uiConfig](#uiConfig) ## Properties[**](#Properties) ### [**](#adapterOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/interface.ts#L6)optionaladapterOptions **adapterOptions? : QueueAdapterOptions ### [**](#basePath)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/interface.ts#L4)optionalbasePath **basePath? : string ### [**](#uiConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/bull-board/src/interface.ts#L5)optionaluiConfig **uiConfig? : Partial<{}> --- # BullQueue ### Hierarchy * Bull * *BullQueue* ### Implements * [IQueue](/api/3.0.0/bull/interface/IQueue.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addJobToQueue](#addJobToQueue) * [**getQueueName](#getQueueName) * [**runJob](#runJob) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L25)constructor * **new BullQueue(queueName: string, queueOptions: QueueOptions): [BullQueue](/api/3.0.0/bull/class/BullQueue.md) - Overrides Bull.constructor ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L29)publicaddJobToQueue * **addJobToQueue(data: any, options? : JobOptions): Promise\> - Implementation of IQueue.addJobToQueue ### [**](#getQueueName)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L40)publicgetQueueName * **getQueueName(): string - Implementation of IQueue.getQueueName ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L36)publicrunJob * **runJob(data: any, options? : JobOptions): Promise\> - Implementation of IQueue.runJob * **@deprecated** use addJobToQueue instead --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BullConfiguration](/api/3.0.0/bull/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/configuration.ts#L24)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/configuration.ts#L21)framework **framework: [BullFramework](/api/3.0.0/bull/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/configuration.ts#L27)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/configuration.ts#L41)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/3.0.0/bull/interface/Application.md), [Context](/api/3.0.0/bull/interface/Context.md), any> * *Framework* ### Implements * [IQueueManager](/api/3.0.0/bull/interface/IQueueManager.md)<[BullQueue](/api/3.0.0/bull/class/BullQueue.md), Job> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**addJobToQueue](#addJobToQueue) * [**addProcessor](#addProcessor) * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**createQueue](#createQueue) * [**ensureQueue](#ensureQueue) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getJob](#getJob) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getQueue](#getQueue) * [**getQueueList](#getQueueList) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadConfig](#loadConfig) * [**run](#run) * [**runGuard](#runGuard) * [**runJob](#runJob) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [BullFramework](/api/3.0.0/bull/class/Framework.md) - Inherited from BaseFramework\.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/3.0.0/bull/interface/Application.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/bull/interface/Context.md), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L192)publicaddJobToQueue * **addJobToQueue(queueName: string, jobData: any, options? : JobOptions): Promise\> - Implementation of IQueueManager.addJobToQueue ### [**](#addProcessor)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L146)publicaddProcessor * **addProcessor(processor: new (...args: any\[]) => [IProcessor](/api/3.0.0/bull/interface/IProcessor.md), queueName: string | [BullQueue](/api/3.0.0/bull/class/BullQueue.md), concurrency? : number): Promise\ ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L58)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/bull/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L74)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#createQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L119)publiccreateQueue * **createQueue(name: string, queueOptions? : QueueOptions): [BullQueue](/api/3.0.0/bull/class/BullQueue.md) - Implementation of IQueueManager.createQueue ### [**](#ensureQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L135)publicensureQueue * **ensureQueue(name: string, queueOptions? : QueueOptions): [BullQueue](/api/3.0.0/bull/class/BullQueue.md) ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [Application](/api/3.0.0/bull/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L78)getFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L214)publicgetJob * **getJob(queueName: string, jobName: string): Promise\> - Implementation of IQueueManager.getJob ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/bull/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L131)publicgetQueue * **getQueue(name: string): [BullQueue](/api/3.0.0/bull/class/BullQueue.md) - Implementation of IQueueManager.getQueue ### [**](#getQueueList)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L142)publicgetQueueList * **getQueueList(): [BullQueue](/api/3.0.0/bull/class/BullQueue.md)\[] ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[BullFramework](/api/3.0.0/bull/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L62)publicloadConfig * **loadConfig(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L82)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/bull/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/framework.ts#L206)publicrunJob * **runJob(queueName: string, jobData: any, options? : JobOptions): Promise\> - Implementation of IQueueManager.runJob * **@deprecated** use addJob instead ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/bull/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/bull/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/bull/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # InjectQueue ### Callable * **InjectQueue(queueName: string): PropertyDecorator --- # Processor ### Callable * **Processor(queueName: string, jobOptions? : JobOptions, queueOptions? : QueueOptions): ClassDecorator * **Processor(queueName: string, concurrency? : number, jobOptions? : JobOptions, queueOptions? : QueueOptions): ClassDecorator --- # Application ### Hierarchy * IMidwayApplication<[Context](/api/3.0.0/bull/interface/Context.md)> * *Application* ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L840)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L830)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/3.0.0/bull/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L821)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L780)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L801)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L851)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L776)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L806)getConfig * **getConfig(key? : string): any - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L815)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L784)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L788)getFramework * **getFramework(): IMidwayFramework<[Application](/api/3.0.0/bull/interface/Application.md), [Context](/api/3.0.0/bull/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getFrameworkType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L793)getFrameworkType * **getFrameworkType(): [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) - Inherited from IMidwayApplication.getFrameworkType * **@deprecated** Get current framework type in MidwayFrameworkType enum ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L811)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L860)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/3.0.0/bull/interface/Context.md), R, N> - Inherited from IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L874)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L797)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L825)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L846)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L835)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L865)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/3.0.0/bull/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L870)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/3.0.0/bull/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L856)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/bull/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * IMidwayContext * *Context* ## Index[**](#Index) ### Properties * [**from](#from) * [**job](#job) * [**jobId](#jobId) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#from)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L35)from **from: new (...args: any\[]) => [IProcessor](/api/3.0.0/bull/interface/IProcessor.md) ### [**](#job)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L34)job **job: Job\ ### [**](#jobId)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L33)jobId **jobId: JobId ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayContext.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # IProcessor ## Index[**](#Index) ### Methods * [**execute](#execute) ## Methods[**](#Methods) ### [**](#execute)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L5)execute * **execute(data: any): any --- # IQueue \ ### Implemented by * [BullQueue](/api/3.0.0/bull/class/BullQueue.md) ## Index[**](#Index) ### Methods * [**addJobToQueue](#addJobToQueue) * [**getJob](#getJob) * [**getQueueName](#getQueueName) * [**runJob](#runJob) ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L13)addJobToQueue * **addJobToQueue(data: Record\, options? : unknown): Promise\ ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L14)getJob * **getJob(name: string): Promise\ ### [**](#getQueueName)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L15)getQueueName * **getQueueName(): string ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L12)runJob * **runJob(data: Record\, options? : unknown): Promise\ - - **@deprecated** use addJobToQueue instead --- # IQueueManager \ ### Implemented by * [Framework](/api/3.0.0/bull/class/Framework.md) ## Index[**](#Index) ### Methods * [**addJobToQueue](#addJobToQueue) * [**createQueue](#createQueue) * [**getJob](#getJob) * [**getQueue](#getQueue) * [**runJob](#runJob) ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L19)addJobToQueue * **addJobToQueue(queueName: string, jobData: any, options? : unknown): Promise\ ### [**](#createQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L25)createQueue * **createQueue(queueName: string, queueOptions? : unknown): Queue ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L24)getJob * **getJob(queueName: string, jobName: string): Promise\ ### [**](#getQueue)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L26)getQueue * **getQueue(queueName: string): Queue ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/main/packages/bull/src/interface.ts#L23)runJob * **runJob(queueName: string, jobData: any, options? : unknown): Promise\ - - **@deprecated** use addJobToQueue instead --- # @midwayjs/captcha ## Index[**](#Index) ### Classes * [**CaptchaService](/api/3.0.0/captcha/class/CaptchaService.md) * [**Configuration](/api/3.0.0/captcha/class/Configuration.md) ### Interfaces * [**CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md) * [**CaptchaOptions](/api/3.0.0/captcha/interface/CaptchaOptions.md) * [**FormulaCaptchaOptions](/api/3.0.0/captcha/interface/FormulaCaptchaOptions.md) * [**ImageCaptchaOptions](/api/3.0.0/captcha/interface/ImageCaptchaOptions.md) * [**TextCaptchaOptions](/api/3.0.0/captcha/interface/TextCaptchaOptions.md) --- # CaptchaService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**check](#check) * [**formula](#formula) * [**image](#image) * [**set](#set) * [**text](#text) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CaptchaService(): [CaptchaService](/api/3.0.0/captcha/class/CaptchaService.md) ## Methods[**](#Methods) ### [**](#check)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/service.ts#L120)check * **check(id: string, value: string, cacheOptions? : [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md)): Promise\ ### [**](#formula)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/service.ts#L58)formula * **formula(options? : [FormulaCaptchaOptions](/api/3.0.0/captcha/interface/FormulaCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; imageBase64: string }> ### [**](#image)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/service.ts#L35)image * **image(options? : [ImageCaptchaOptions](/api/3.0.0/captcha/interface/ImageCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; imageBase64: string }> ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/service.ts#L110)set * **set(text: string, cacheOptions? : [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md)): Promise\ ### [**](#text)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/service.ts#L77)text * **text(options? : [TextCaptchaOptions](/api/3.0.0/captcha/interface/TextCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; text: string }> --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CaptchaConfiguration](/api/3.0.0/captcha/class/Configuration.md) --- # CaptchaCacheOptions ### Hierarchy * *CaptchaCacheOptions* * [CaptchaOptions](/api/3.0.0/captcha/interface/CaptchaOptions.md) ## Index[**](#Index) ### Properties * [**expirationTime](#expirationTime) * [**idPrefix](#idPrefix) ## Properties[**](#Properties) ### [**](#expirationTime)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L5)optionalexpirationTime **expirationTime? : number ### [**](#idPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L7)optionalidPrefix **idPrefix? : string --- # CaptchaOptions ### Hierarchy * [CaptchaCacheOptions](/api/3.0.0/captcha/interface/CaptchaCacheOptions.md) * *CaptchaOptions* ## Index[**](#Index) ### Properties * [**default](#default) * [**expirationTime](#expirationTime) * [**formula](#formula) * [**idPrefix](#idPrefix) * [**image](#image) * [**text](#text) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L11)optionaldefault **default? : ConfigObject ### [**](#expirationTime)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L5)optionalexpirationTime **expirationTime? : number Inherited from CaptchaCacheOptions.expirationTime ### [**](#formula)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L13)optionalformula **formula? : [FormulaCaptchaOptions](/api/3.0.0/captcha/interface/FormulaCaptchaOptions.md) ### [**](#idPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L7)optionalidPrefix **idPrefix? : string Inherited from CaptchaCacheOptions.idPrefix ### [**](#image)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L12)optionalimage **image? : [ImageCaptchaOptions](/api/3.0.0/captcha/interface/ImageCaptchaOptions.md) ### [**](#text)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L14)optionaltext **text? : [TextCaptchaOptions](/api/3.0.0/captcha/interface/TextCaptchaOptions.md) --- # FormulaCaptchaOptions ### Hierarchy * ConfigObject * *FormulaCaptchaOptions* --- # ImageCaptchaOptions ### Hierarchy * ConfigObject * *ImageCaptchaOptions* ## Index[**](#Index) ### Properties * [**type](#type) ## Properties[**](#Properties) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L18)optionaltype **type? : number | letter | mixed --- # TextCaptchaOptions ## Index[**](#Index) ### Properties * [**size](#size) * [**type](#type) ## Properties[**](#Properties) ### [**](#size)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L24)optionalsize **size? : number ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/captcha/src/interface.ts#L25)optionaltype **type? : number | letter | mixed --- # @midwayjs/casbin ## Index[**](#Index) ### Classes * [**AuthGuard](/api/3.0.0/casbin/class/AuthGuard.md) * [**BaseAdapter](/api/3.0.0/casbin/class/BaseAdapter.md) * [**CasbinEnforcerService](/api/3.0.0/casbin/class/CasbinEnforcerService.md) * [**Configuration](/api/3.0.0/casbin/class/Configuration.md) ### Enumerations * [**AuthAction](/api/3.0.0/casbin/enum/AuthAction.md) * [**AuthActionVerb](/api/3.0.0/casbin/enum/AuthActionVerb.md) * [**AuthPossession](/api/3.0.0/casbin/enum/AuthPossession.md) ### Functions * [**UsePermission](/api/3.0.0/casbin/function/UsePermission.md) ### Interfaces * [**CasbinConfigOptions](/api/3.0.0/casbin/interface/CasbinConfigOptions.md) * [**Permission](/api/3.0.0/casbin/interface/Permission.md) ### Type Aliases * [**CustomAuthActionVerb](/api/3.0.0/casbin.md#CustomAuthActionVerb) ### Variables * [**PERMISSIONS\_METADATA\_KEY](/api/3.0.0/casbin.md#PERMISSIONS_METADATA_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#CustomAuthActionVerb)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L19)CustomAuthActionVerb **CustomAuthActionVerb: string ## Variables[**](#Variables) ### [**](#PERMISSIONS_METADATA_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L1)constPERMISSIONS\_METADATA\_KEY **PERMISSIONS\_METADATA\_KEY: casbin:permission\_metadata = 'casbin:permission\_metadata' --- # @midwayjs/casbin-redis-adapter ## Index[**](#Index) ### Classes * [**BaseWatcher](/api/3.0.0/casbin-redis-adapter/class/BaseWatcher.md) * [**NodeRedisAdapter](/api/3.0.0/casbin-redis-adapter/class/NodeRedisAdapter.md) * [**NodeRedisWatcher](/api/3.0.0/casbin-redis-adapter/class/NodeRedisWatcher.md) ### Functions * [**createAdapter](/api/3.0.0/casbin-redis-adapter/function/createAdapter.md) * [**createWatcher](/api/3.0.0/casbin-redis-adapter/function/createWatcher.md) --- # abstractBaseWatcher \ ### Hierarchy * *BaseWatcher* * [NodeRedisWatcher](/api/3.0.0/casbin-redis-adapter/class/NodeRedisWatcher.md) ### Implements * Watcher ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getDefaultSubscribeKeyName](#getDefaultSubscribeKeyName) * [**publishData](#publishData) * [**setUpdateCallback](#setUpdateCallback) * [**subscribeData](#subscribeData) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L7)constructor * **new BaseWatcher\(options: { pubClient? : Client; subClient: Client; subscribeKeyName? : string }): [BaseWatcher](/api/3.0.0/casbin-redis-adapter/class/BaseWatcher.md)\ - #### Type parameters * **Client** ## Methods[**](#Methods) ### [**](#getDefaultSubscribeKeyName)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L42)getDefaultSubscribeKeyName * **getDefaultSubscribeKeyName(): string ### [**](#publishData)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L38)abstractpublishData * **publishData(): any ### [**](#setUpdateCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L26)setUpdateCallback * **setUpdateCallback(callback: () => void): void - Implementation of Watcher.setUpdateCallback ### [**](#subscribeData)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L39)abstractsubscribeData * **subscribeData(callback: any): any ### [**](#update)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L29)update * **update(): Promise\ - Implementation of Watcher.update --- # NodeRedisAdapter ### Hierarchy * BaseAdapter\ * *NodeRedisAdapter* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/adapter.ts#L17)constructor * **new NodeRedisAdapter(redisInstance: any): [NodeRedisAdapter](/api/3.0.0/casbin-redis-adapter/class/NodeRedisAdapter.md) - Overrides BaseAdapter\.constructor ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L17)addPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.addPolicy ### [**](#isFiltered)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L14)isFiltered * **isFiltered(): boolean - Inherited from BaseAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L19)loadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Inherited from BaseAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L15)loadPolicy * **loadPolicy(model: Model): Promise\ - Inherited from BaseAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L20)removeFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Inherited from BaseAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L18)removePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.removePolicy ### [**](#savePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L16)savePolicy * **savePolicy(model: Model): Promise\ - Inherited from BaseAdapter.savePolicy --- # NodeRedisWatcher ### Hierarchy * [BaseWatcher](/api/3.0.0/casbin-redis-adapter/class/BaseWatcher.md)\ * *NodeRedisWatcher* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getDefaultSubscribeKeyName](#getDefaultSubscribeKeyName) * [**publishData](#publishData) * [**setUpdateCallback](#setUpdateCallback) * [**subscribeData](#subscribeData) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L7)constructor * **new NodeRedisWatcher(options: { pubClient? : Redis; subClient: Redis; subscribeKeyName? : string }): [NodeRedisWatcher](/api/3.0.0/casbin-redis-adapter/class/NodeRedisWatcher.md) - Inherited from BaseWatcher.constructor ## Methods[**](#Methods) ### [**](#getDefaultSubscribeKeyName)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L42)getDefaultSubscribeKeyName * **getDefaultSubscribeKeyName(): string - Inherited from BaseWatcher.getDefaultSubscribeKeyName ### [**](#publishData)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L48)publishData * **publishData(): Promise\ - Overrides BaseWatcher.publishData ### [**](#setUpdateCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L26)setUpdateCallback * **setUpdateCallback(callback: () => void): void - Inherited from BaseWatcher.setUpdateCallback ### [**](#subscribeData)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L55)subscribeData * **subscribeData(callback: any): Promise\ - Overrides BaseWatcher.subscribeData ### [**](#update)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-redis-adapter/src/watcher.ts#L29)update * **update(): Promise\ - Inherited from BaseWatcher.update --- # createAdapter ### Callable * **createAdapter(options: { clientName: string }): (container: IMidwayContainer) => Promise<[NodeRedisAdapter](/api/3.0.0/casbin-redis-adapter/class/NodeRedisAdapter.md)> --- # createWatcher ### Callable * **createWatcher(options: { keyName? : string; pubClientName: string; subClientName: string }): (container: IMidwayContainer) => Promise<[NodeRedisWatcher](/api/3.0.0/casbin-redis-adapter/class/NodeRedisWatcher.md)> --- # @midwayjs/casbin-typeorm-adapter ## Index[**](#Index) ### Classes * [**CasbinMongoRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinMongoRule.md) * [**CasbinRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinRule.md) * [**TypeORMAdapter](/api/3.0.0/casbin-typeorm-adapter/class/TypeORMAdapter.md) ### Functions * [**createAdapter](/api/3.0.0/casbin-typeorm-adapter/function/createAdapter.md) --- # CasbinMongoRule ### Hierarchy * BaseEntity * *CasbinMongoRule* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**id](#id) * [**ptype](#ptype) * [**v0](#v0) * [**v1](#v1) * [**v2](#v2) * [**v3](#v3) * [**v4](#v4) * [**v5](#v5) * [**v6](#v6) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinMongoRule(): [CasbinMongoRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinMongoRule.md) - Inherited from BaseEntity.constructor ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L21)publicid **id: typeof ObjectId ### [**](#ptype)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L26)publicptype **ptype: string ### [**](#v0)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L31)publicv0 **v0: string ### [**](#v1)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L36)publicv1 **v1: string ### [**](#v2)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L41)publicv2 **v2: string ### [**](#v3)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L46)publicv3 **v3: string ### [**](#v4)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L51)publicv4 **v4: string ### [**](#v5)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L56)publicv5 **v5: string ### [**](#v6)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L61)publicv6 **v6: string --- # CasbinRule ### Hierarchy * BaseEntity * *CasbinRule* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**id](#id) * [**ptype](#ptype) * [**v0](#v0) * [**v1](#v1) * [**v2](#v2) * [**v3](#v3) * [**v4](#v4) * [**v5](#v5) * [**v6](#v6) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinRule(): [CasbinRule](/api/3.0.0/casbin-typeorm-adapter/class/CasbinRule.md) - Inherited from BaseEntity.constructor ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L6)publicid **id: number ### [**](#ptype)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L11)publicptype **ptype: string ### [**](#v0)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L16)publicv0 **v0: string ### [**](#v1)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L21)publicv1 **v1: string ### [**](#v2)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L26)publicv2 **v2: string ### [**](#v3)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L31)publicv3 **v3: string ### [**](#v4)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L36)publicv4 **v4: string ### [**](#v5)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L41)publicv5 **v5: string ### [**](#v6)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/casbinRule.ts#L46)publicv6 **v6: string --- # TypeORMAdapter TypeORMAdapter represents the TypeORM filtered adapter for policy storage. ### Hierarchy * BaseAdapter\ * *TypeORMAdapter* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin-typeorm-adapter/src/adapter.ts#L18)constructor * **new TypeORMAdapter(dataSource: DataSource, options: TypeORMAdapterConfig): [TypeORMAdapter](/api/3.0.0/casbin-typeorm-adapter/class/TypeORMAdapter.md) - Overrides BaseAdapter\.constructor ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L17)addPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.addPolicy ### [**](#isFiltered)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L14)isFiltered * **isFiltered(): boolean - Inherited from BaseAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L19)loadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Inherited from BaseAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L15)loadPolicy * **loadPolicy(model: Model): Promise\ - Inherited from BaseAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L20)removeFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Inherited from BaseAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L18)removePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.removePolicy ### [**](#savePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L16)savePolicy * **savePolicy(model: Model): Promise\ - Inherited from BaseAdapter.savePolicy --- # createAdapter ### Callable * **createAdapter(options: TypeORMAdapterConfig): (container: IMidwayContainer) => Promise<[TypeORMAdapter](/api/3.0.0/casbin-typeorm-adapter/class/TypeORMAdapter.md)> --- # AuthGuard ### Implements * IGuard ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**casbinConfig](#casbinConfig) * [**enforcer](#enforcer) ### Methods * [**canActivate](#canActivate) * [**asyncEvery](#asyncEvery) * [**asyncSome](#asyncSome) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AuthGuard(): [AuthGuard](/api/3.0.0/casbin/class/AuthGuard.md) ## Properties[**](#Properties) ### [**](#casbinConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/auth.guard.ts#L19)casbinConfig **casbinConfig: [CasbinConfigOptions](/api/3.0.0/casbin/interface/CasbinConfigOptions.md) ### [**](#enforcer)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/auth.guard.ts#L16)enforcer **enforcer: [CasbinEnforcerService](/api/3.0.0/casbin/class/CasbinEnforcerService.md) ## Methods[**](#Methods) ### [**](#canActivate)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/auth.guard.ts#L21)canActivate * **canActivate(context: Context, supplierClz: any, methodName: string): Promise\ - Implementation of IGuard.canActivate ### [**](#asyncEvery)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/auth.guard.ts#L84)staticasyncEvery * **asyncEvery\(array: T\[], callback: (value: T, index: number, a: T\[]) => Promise\): Promise\ - #### Type parameters * **T** ### [**](#asyncSome)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/auth.guard.ts#L70)staticasyncSome * **asyncSome\(array: T\[], callback: (value: T, index: number, a: T\[]) => Promise\): Promise\ - #### Type parameters * **T** --- # abstractBaseAdapter \ ### Implements * FilteredAdapter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BaseAdapter\(): [BaseAdapter](/api/3.0.0/casbin/class/BaseAdapter.md)\ - #### Type parameters * **AdapterLine**: Line ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L49)publicaddPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Implementation of FilteredAdapter.addPolicy ### [**](#isFiltered)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L19)publicisFiltered * **isFiltered(): boolean - Implementation of FilteredAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L92)publicloadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Implementation of FilteredAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L23)publicloadPolicy * **loadPolicy(model: Model): Promise\ - Implementation of FilteredAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L101)publicremoveFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Implementation of FilteredAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L59)publicremovePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Implementation of FilteredAdapter.removePolicy ### [**](#savePolicy)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/adapter.ts#L31)publicsavePolicy * **savePolicy(model: Model): Promise\ - Implementation of FilteredAdapter.savePolicy --- # CasbinEnforcerService ### Hierarchy * Enforcer * *CasbinEnforcerService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**getEnforcer](#getEnforcer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinEnforcerService(): [CasbinEnforcerService](/api/3.0.0/casbin/class/CasbinEnforcerService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/enforcer.service.ts#L23)applicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#getEnforcer)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/enforcer.service.ts#L49)publicgetEnforcer * **getEnforcer(): Enforcer --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CasbinConfiguration](/api/3.0.0/casbin/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/configuration.ts#L15)onReady * **onReady(container: any): Promise\ --- # AuthAction ## Index[**](#Index) ### Enumeration Members * [**CREATE\_ANY](#CREATE_ANY) * [**CREATE\_OWN](#CREATE_OWN) * [**DELETE\_ANY](#DELETE_ANY) * [**DELETE\_OWN](#DELETE_OWN) * [**READ\_ANY](#READ_ANY) * [**READ\_OWN](#READ_OWN) * [**UPDATE\_ANY](#UPDATE_ANY) * [**UPDATE\_OWN](#UPDATE_OWN) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#CREATE_ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L17)CREATE\_ANY **CREATE\_ANY: create:any ### [**](#CREATE_OWN)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L18)CREATE\_OWN **CREATE\_OWN: create:own ### [**](#DELETE_ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L23)DELETE\_ANY **DELETE\_ANY: delete:any ### [**](#DELETE_OWN)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L24)DELETE\_OWN **DELETE\_OWN: delete:own ### [**](#READ_ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L26)READ\_ANY **READ\_ANY: read:any ### [**](#READ_OWN)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L27)READ\_OWN **READ\_OWN: read:own ### [**](#UPDATE_ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L20)UPDATE\_ANY **UPDATE\_ANY: update:any ### [**](#UPDATE_OWN)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L21)UPDATE\_OWN **UPDATE\_OWN: update:own --- # AuthActionVerb ## Index[**](#Index) ### Enumeration Members * [**CREATE](#CREATE) * [**DELETE](#DELETE) * [**READ](#READ) * [**UPDATE](#UPDATE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#CREATE)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L4)CREATE **CREATE: create ### [**](#DELETE)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L6)DELETE **DELETE: delete ### [**](#READ)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L7)READ **READ: read ### [**](#UPDATE)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L5)UPDATE **UPDATE: update --- # AuthPossession ## Index[**](#Index) ### Enumeration Members * [**ANY](#ANY) * [**OWN](#OWN) * [**OWN\_ANY](#OWN_ANY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L11)ANY **ANY: any ### [**](#OWN)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L12)OWN **OWN: own ### [**](#OWN_ANY)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/constants.ts#L13)OWN\_ANY **OWN\_ANY: own|any --- # UsePermission ### Callable * **UsePermission(...permissions: [Permission](/api/3.0.0/casbin/interface/Permission.md)\[]): MethodDecorator *** * You can define multiple permissions, but only when all of them satisfied, could you access the route. --- # CasbinConfigOptions ## Index[**](#Index) ### Properties * [**modelPath](#modelPath) * [**policyAdapter](#policyAdapter) * [**policyWatcher](#policyWatcher) * [**usernameFromContext](#usernameFromContext) ## Properties[**](#Properties) ### [**](#modelPath)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L6)modelPath **modelPath: string ### [**](#policyAdapter)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L7)policyAdapter **policyAdapter: string | (applicationContext: IMidwayContainer) => Promise\ | Adapter ### [**](#policyWatcher)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L8)optionalpolicyWatcher **policyWatcher? : Watcher | (applicationContext: IMidwayContainer) => Promise\ ### [**](#usernameFromContext)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L9)usernameFromContext **usernameFromContext: (ctx: Context) => string --- # Permission ## Index[**](#Index) ### Properties * [**action](#action) * [**isOwn](#isOwn) * [**possession](#possession) * [**resource](#resource) ## Properties[**](#Properties) ### [**](#action)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L14)action **action: string ### [**](#isOwn)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L16)optionalisOwn **isOwn? : (ctx: Context) => boolean ### [**](#possession)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L15)possession **possession: [AuthPossession](/api/3.0.0/casbin/enum/AuthPossession.md) ### [**](#resource)[**](https://github.com/midwayjs/midway/blob/main/packages/casbin/src/interface.ts#L13)resource **resource: string --- # @midwayjs/code-dye ## Index[**](#Index) ### Classes * [**CodeDyeMW](/api/3.0.0/code-dye/class/CodeDyeMW.md) * [**Configuration](/api/3.0.0/code-dye/class/Configuration.md) ### Interfaces * [**CodeDyeOptions](/api/3.0.0/code-dye/interface/CodeDyeOptions.md) --- # CodeDyeMW ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**codeDye](#codeDye) ### Methods * [**check](#check) * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CodeDyeMW(): [CodeDyeMW](/api/3.0.0/code-dye/class/CodeDyeMW.md) ## Properties[**](#Properties) ### [**](#codeDye)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/middleware.ts#L9)codeDye **codeDye: [CodeDyeOptions](/api/3.0.0/code-dye/interface/CodeDyeOptions.md) ## Methods[**](#Methods) ### [**](#check)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/middleware.ts#L23)check * **check(request: any): any ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/middleware.ts#L42)compatibleMiddleware * **compatibleMiddleware(request: any, response: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/middleware.ts#L11)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**codeDye](#codeDye) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CodeDyeConfiguration](/api/3.0.0/code-dye/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ### [**](#codeDye)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/configuration.ts#L23)codeDye **codeDye: any ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/configuration.ts#L25)onReady * **onReady(container: any): Promise\ --- # CodeDyeOptions ## Index[**](#Index) ### Properties * [**matchHeaderKey](#matchHeaderKey) * [**matchQueryKey](#matchQueryKey) ## Properties[**](#Properties) ### [**](#matchHeaderKey)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/interface.ts#L2)matchHeaderKey **matchHeaderKey: string ### [**](#matchQueryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/code-dye/src/interface.ts#L3)matchQueryKey **matchQueryKey: string --- # @midwayjs/consul ## Index[**](#Index) ### Classes * [**BalancerService](/api/3.0.0/consul/class/BalancerService.md) * [**Configuration](/api/3.0.0/consul/class/Configuration.md) * [**ConsulController](/api/3.0.0/consul/class/ConsulController.md) ### Interfaces * [**ConsulConfig](/api/3.0.0/consul/interface/ConsulConfig.md) * [**IConsulBalancer](/api/3.0.0/consul/interface/IConsulBalancer.md) * [**IConsulProviderInfoOptions](/api/3.0.0/consul/interface/IConsulProviderInfoOptions.md) * [**IConsulRegisterInfoOptions](/api/3.0.0/consul/interface/IConsulRegisterInfoOptions.md) * [**IServiceBalancer](/api/3.0.0/consul/interface/IServiceBalancer.md) --- # BalancerService ### Implements * [IConsulBalancer](/api/3.0.0/consul/interface/IConsulBalancer.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**consul](#consul) ### Methods * [**getServiceBalancer](#getServiceBalancer) * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BalancerService(): [BalancerService](/api/3.0.0/consul/class/BalancerService.md) ## Properties[**](#Properties) ### [**](#consul)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/service/balancer.ts#L10)consul **consul: Consul ## Methods[**](#Methods) ### [**](#getServiceBalancer)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/service/balancer.ts#L19)getServiceBalancer * **getServiceBalancer(strategy? : string): [IServiceBalancer](/api/3.0.0/consul/interface/IServiceBalancer.md) - Implementation of IConsulBalancer.getServiceBalancer 根绝策略返回负载均衡器 ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/service/balancer.ts#L15)init * **init(): void --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**consulProviderConfig](#consulProviderConfig) * [**consulRegisterConfig](#consulRegisterConfig) ### Accessors * [**consulProvider](#consulProvider) * [**shouldBeRegisterMe](#shouldBeRegisterMe) ### Methods * [**onServerReady](#onServerReady) * [**onStop](#onStop) * [**registerConsul](#registerConsul) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ConsulConfiguration](/api/3.0.0/consul/class/Configuration.md) ## Properties[**](#Properties) ### [**](#consulProviderConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L28)consulProviderConfig **consulProviderConfig: [IConsulProviderInfoOptions](/api/3.0.0/consul/interface/IConsulProviderInfoOptions.md) 有关 consul server 的配置 ### [**](#consulRegisterConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L34)consulRegisterConfig **consulRegisterConfig: [IConsulRegisterInfoOptions](/api/3.0.0/consul/interface/IConsulRegisterInfoOptions.md) 有关 service registry 注册的信息 ## Accessors[**](#Accessors) ### [**](#consulProvider)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L36)consulProvider * **get consulProvider(): ConsulProvider ### [**](#shouldBeRegisterMe)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L47)shouldBeRegisterMe * **get shouldBeRegisterMe(): boolean - 注册自己的条件 由于环境的复杂性(多网卡、自动端口冲突) address 和 port 必须提供 ## Methods[**](#Methods) ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L84)onServerReady * **onServerReady(container: IMidwayContainer, app? : IMidwayBaseApplication\): Promise\ - Implementation of ILifeCycle.onServerReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L91)onStop * **onStop(): Promise\ - Implementation of ILifeCycle.onStop ### [**](#registerConsul)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/configuration.ts#L57)registerConsul * **registerConsul(container: IMidwayContainer, app: IMidwayBaseApplication\): Promise\ - 注册 consul 服务 --- # ConsulController ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**healthCheck](#healthCheck) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ConsulController(): [ConsulController](/api/3.0.0/consul/class/ConsulController.md) ## Methods[**](#Methods) ### [**](#healthCheck)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/controller/consul.ts#L6)healthCheck * **healthCheck(): Promise\ --- # ConsulConfig ## Index[**](#Index) ### Properties * [**provider](#provider) * [**service](#service) ## Properties[**](#Properties) ### [**](#provider)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L81)optionalprovider **provider? : [IConsulProviderInfoOptions](/api/3.0.0/consul/interface/IConsulProviderInfoOptions.md) ### [**](#service)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L82)optionalservice **service? : [IConsulRegisterInfoOptions](/api/3.0.0/consul/interface/IConsulRegisterInfoOptions.md) --- # IConsulBalancer ### Implemented by * [BalancerService](/api/3.0.0/consul/class/BalancerService.md) ## Index[**](#Index) ### Methods * [**getServiceBalancer](#getServiceBalancer) ## Methods[**](#Methods) ### [**](#getServiceBalancer)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L19)getServiceBalancer * **getServiceBalancer(strategy? : string): [IServiceBalancer](/api/3.0.0/consul/interface/IServiceBalancer.md) - 根绝策略返回负载均衡器 --- # IConsulProviderInfoOptions ### Hierarchy * ConsulOptions * *IConsulProviderInfoOptions* ## Index[**](#Index) ### Properties * [**deregister](#deregister) * [**register](#register) * [**strategy](#strategy) ## Properties[**](#Properties) ### [**](#deregister)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L32)optionalderegister **deregister? : boolean 应用正常关闭的额时候自动反注册,默认是 YES 会执行反注册 如果 register=false 改参数无效 ### [**](#register)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L26)optionalregister **register? : boolean 本服务是否注册到 consul 服务器,默认是 NO 不会执行注册 ### [**](#strategy)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L37)optionalstrategy **strategy? : string 调用服务负载均衡的策略(default、random),默认是 random 随机 --- # IConsulRegisterInfoOptions ### Hierarchy * RegisterOptions * *IConsulRegisterInfoOptions* ## Index[**](#Index) ### Properties * [**address](#address) * [**check](#check) * [**id](#id) * [**name](#name) * [**port](#port) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#address)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L54)address **address: string Overrides RegisterOptions.address 服务地址 ### [**](#check)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L69)optionalcheck **check? : { http? : string; interval? : string; notes? : string; script? : string; status? : string; tcp? : string; ttl? : string } Overrides RegisterOptions.check 健康检查配置,组件默认会配置一个(检查间隔是3秒),如果指定 check=false 则关闭 consul 健康检查 ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L44)optionalid **id? : string Overrides RegisterOptions.id 注册 id 标识,默认是 name:address:port 的组合 ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L49)name **name: string Overrides RegisterOptions.name 服务名称 ### [**](#port)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L59)port **port: number Overrides RegisterOptions.port 服务端口 ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L64)optionaltags **tags? : string\[] Overrides RegisterOptions.tags 服务标签 --- # IServiceBalancer ## Index[**](#Index) ### Methods * [**select](#select) ## Methods[**](#Methods) ### [**](#select)[**](https://github.com/midwayjs/midway/blob/main/packages/consul/src/interface.ts#L11)select * **select(serviceName: string, passingOnly? : boolean): any - 根据服务名称选择实例 --- # @midwayjs/core ## Index[**](#Index) ### Classes * [**AbstractFileDetector](/api/3.0.0/core/class/AbstractFileDetector.md) * [**BaseFramework](/api/3.0.0/core/class/BaseFramework.md) * [**CommonJSFileDetector](/api/3.0.0/core/class/CommonJSFileDetector.md) * [**ContextMiddlewareManager](/api/3.0.0/core/class/ContextMiddlewareManager.md) * [**CustomModuleDetector](/api/3.0.0/core/class/CustomModuleDetector.md) * [**DataListener](/api/3.0.0/core/class/DataListener.md) * [**DataSourceManager](/api/3.0.0/core/class/DataSourceManager.md) * [**DecoratorManager](/api/3.0.0/core/class/DecoratorManager.md) * [**DefaultConsoleLoggerFactory](/api/3.0.0/core/class/DefaultConsoleLoggerFactory.md) * [**ESModuleFileDetector](/api/3.0.0/core/class/ESModuleFileDetector.md) * [**FilterManager](/api/3.0.0/core/class/FilterManager.md) * [**FrameworkType](/api/3.0.0/core/class/FrameworkType.md) * [**FunctionalConfiguration](/api/3.0.0/core/class/FunctionalConfiguration.md) * [**HttpClient](/api/3.0.0/core/class/HttpClient.md) * [**HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md) * [**LoggerFactory](/api/3.0.0/core/class/LoggerFactory.md) * [**MidwayApplicationManager](/api/3.0.0/core/class/MidwayApplicationManager.md) * [**MidwayAspectService](/api/3.0.0/core/class/MidwayAspectService.md) * [**MidwayCodeInvokeTimeoutError](/api/3.0.0/core/class/MidwayCodeInvokeTimeoutError.md) * [**MidwayCommonError](/api/3.0.0/core/class/MidwayCommonError.md) * [**MidwayConfigMissingError](/api/3.0.0/core/class/MidwayConfigMissingError.md) * [**MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) * [**MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) * [**MidwayDecoratorService](/api/3.0.0/core/class/MidwayDecoratorService.md) * [**MidwayDefinitionNotFoundError](/api/3.0.0/core/class/MidwayDefinitionNotFoundError.md) * [**MidwayDuplicateClassNameError](/api/3.0.0/core/class/MidwayDuplicateClassNameError.md) * [**MidwayDuplicateControllerOptionsError](/api/3.0.0/core/class/MidwayDuplicateControllerOptionsError.md) * [**MidwayDuplicateRouteError](/api/3.0.0/core/class/MidwayDuplicateRouteError.md) * [**MidwayEmptyValueError](/api/3.0.0/core/class/MidwayEmptyValueError.md) * [**MidwayEnvironmentService](/api/3.0.0/core/class/MidwayEnvironmentService.md) * [**MidwayError](/api/3.0.0/core/class/MidwayError.md) * [**MidwayFeatureNoLongerSupportedError](/api/3.0.0/core/class/MidwayFeatureNoLongerSupportedError.md) * [**MidwayFeatureNotImplementedError](/api/3.0.0/core/class/MidwayFeatureNotImplementedError.md) * [**MidwayFrameworkService](/api/3.0.0/core/class/MidwayFrameworkService.md) * [**MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) * [**MidwayHealthService](/api/3.0.0/core/class/MidwayHealthService.md) * [**MidwayHttpError](/api/3.0.0/core/class/MidwayHttpError.md) * [**MidwayInconsistentVersionError](/api/3.0.0/core/class/MidwayInconsistentVersionError.md) * [**MidwayInformationService](/api/3.0.0/core/class/MidwayInformationService.md) * [**MidwayInvalidConfigError](/api/3.0.0/core/class/MidwayInvalidConfigError.md) * [**MidwayInvalidConfigPropertyError](/api/3.0.0/core/class/MidwayInvalidConfigPropertyError.md) * [**MidwayInvokeForbiddenError](/api/3.0.0/core/class/MidwayInvokeForbiddenError.md) * [**MidwayLifeCycleService](/api/3.0.0/core/class/MidwayLifeCycleService.md) * [**MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md) * [**MidwayMainFrameworkMissingError](/api/3.0.0/core/class/MidwayMainFrameworkMissingError.md) * [**MidwayMiddlewareService](/api/3.0.0/core/class/MidwayMiddlewareService.md) * [**MidwayMissingImportComponentError](/api/3.0.0/core/class/MidwayMissingImportComponentError.md) * [**MidwayMockService](/api/3.0.0/core/class/MidwayMockService.md) * [**MidwayParameterError](/api/3.0.0/core/class/MidwayParameterError.md) * [**MidwayPerformanceManager](/api/3.0.0/core/class/MidwayPerformanceManager.md) * [**MidwayPipelineService](/api/3.0.0/core/class/MidwayPipelineService.md) * [**MidwayPriorityManager](/api/3.0.0/core/class/MidwayPriorityManager.md) * [**MidwayRequestContainer](/api/3.0.0/core/class/MidwayRequestContainer.md) * [**MidwayResolverMissingError](/api/3.0.0/core/class/MidwayResolverMissingError.md) * [**MidwayRetryExceededMaxTimesError](/api/3.0.0/core/class/MidwayRetryExceededMaxTimesError.md) * [**MidwayServerlessFunctionService](/api/3.0.0/core/class/MidwayServerlessFunctionService.md) * [**MidwaySingletonInjectRequestError](/api/3.0.0/core/class/MidwaySingletonInjectRequestError.md) * [**MidwayUseWrongMethodError](/api/3.0.0/core/class/MidwayUseWrongMethodError.md) * [**MidwayUtilHttpClientTimeoutError](/api/3.0.0/core/class/MidwayUtilHttpClientTimeoutError.md) * [**MidwayWebRouterService](/api/3.0.0/core/class/MidwayWebRouterService.md) * [**PipelineContext](/api/3.0.0/core/class/PipelineContext.md) * [**ServerResponse](/api/3.0.0/core/class/ServerResponse.md) * [**ServiceFactory](/api/3.0.0/core/class/ServiceFactory.md) * [**TypedResourceManager](/api/3.0.0/core/class/TypedResourceManager.md) * [**WebControllerGenerator](/api/3.0.0/core/class/WebControllerGenerator.md) * [**WebRouterCollector](/api/3.0.0/core/class/WebRouterCollector.md) ### Enumerations * [**BaseType](/api/3.0.0/core/enum/BaseType.md) * [**GrpcStreamTypeEnum](/api/3.0.0/core/enum/GrpcStreamTypeEnum.md) * [**HttpStatus](/api/3.0.0/core/enum/HttpStatus.md) * [**InjectModeEnum](/api/3.0.0/core/enum/InjectModeEnum.md) * [**MSListenerType](/api/3.0.0/core/enum/MSListenerType.md) * [**MSProviderType](/api/3.0.0/core/enum/MSProviderType.md) * [**MidwayProcessTypeEnum](/api/3.0.0/core/enum/MidwayProcessTypeEnum.md) * [**ObjectLifeCycleEvent](/api/3.0.0/core/enum/ObjectLifeCycleEvent.md) * [**RouteParamTypes](/api/3.0.0/core/enum/RouteParamTypes.md) * [**ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) * [**ServerlessTriggerType](/api/3.0.0/core/enum/ServerlessTriggerType.md) * [**WSEventTypeEnum](/api/3.0.0/core/enum/WSEventTypeEnum.md) ### Functions * [**All](/api/3.0.0/core/function/All.md) * [**App](/api/3.0.0/core/function/App.md) * [**ApplicationContext](/api/3.0.0/core/function/ApplicationContext.md) * [**Aspect](/api/3.0.0/core/function/Aspect.md) * [**Autoload](/api/3.0.0/core/function/Autoload.md) * [**Body](/api/3.0.0/core/function/Body.md) * [**Catch](/api/3.0.0/core/function/Catch.md) * [**Config](/api/3.0.0/core/function/Config.md) * [**Configuration](/api/3.0.0/core/function/Configuration.md) * [**Consumer](/api/3.0.0/core/function/Consumer.md) * [**ContentType](/api/3.0.0/core/function/ContentType.md) * [**Controller](/api/3.0.0/core/function/Controller.md) * [**Del](/api/3.0.0/core/function/Del.md) * [**Destroy](/api/3.0.0/core/function/Destroy.md) * [**DubboMethod](/api/3.0.0/core/function/DubboMethod.md) * [**Emit](/api/3.0.0/core/function/Emit.md) * [**Fields](/api/3.0.0/core/function/Fields.md) * [**File](/api/3.0.0/core/function/File.md) * [**Files](/api/3.0.0/core/function/Files.md) * [**Framework](/api/3.0.0/core/function/Framework.md) * [**Get](/api/3.0.0/core/function/Get.md) * [**GrpcMethod](/api/3.0.0/core/function/GrpcMethod.md) * [**Guard](/api/3.0.0/core/function/Guard.md) * [**HSF](/api/3.0.0/core/function/HSF.md) * [**Head](/api/3.0.0/core/function/Head.md) * [**Headers](/api/3.0.0/core/function/Headers.md) * [**HttpCode](/api/3.0.0/core/function/HttpCode.md) * [**Init](/api/3.0.0/core/function/Init.md) * [**Inject](/api/3.0.0/core/function/Inject.md) * [**InjectClient](/api/3.0.0/core/function/InjectClient.md) * [**KafkaListener](/api/3.0.0/core/function/KafkaListener.md) * [**Logger](/api/3.0.0/core/function/Logger.md) * [**Match](/api/3.0.0/core/function/Match.md) * [**Middleware](/api/3.0.0/core/function/Middleware.md) * [**Mock](/api/3.0.0/core/function/Mock.md) * [**OnConnection](/api/3.0.0/core/function/OnConnection.md) * [**OnDisConnection](/api/3.0.0/core/function/OnDisConnection.md) * [**OnMessage](/api/3.0.0/core/function/OnMessage.md) * [**OnWSConnection](/api/3.0.0/core/function/OnWSConnection.md) * [**OnWSDisConnection](/api/3.0.0/core/function/OnWSDisConnection.md) * [**OnWSMessage](/api/3.0.0/core/function/OnWSMessage.md) * [**Options](/api/3.0.0/core/function/Options.md) * [**Param](/api/3.0.0/core/function/Param.md) * [**Patch](/api/3.0.0/core/function/Patch.md) * [**Pipe](/api/3.0.0/core/function/Pipe.md) * [**Pipeline](/api/3.0.0/core/function/Pipeline.md) * [**Plugin](/api/3.0.0/core/function/Plugin.md) * [**Post](/api/3.0.0/core/function/Post.md) * [**Provide](/api/3.0.0/core/function/Provide.md) * [**Provider](/api/3.0.0/core/function/Provider.md) * [**Put](/api/3.0.0/core/function/Put.md) * [**Queries](/api/3.0.0/core/function/Queries.md) * [**Query](/api/3.0.0/core/function/Query.md) * [**Queue](/api/3.0.0/core/function/Queue.md) * [**RabbitMQListener](/api/3.0.0/core/function/RabbitMQListener.md) * [**Redirect](/api/3.0.0/core/function/Redirect.md) * [**RequestIP](/api/3.0.0/core/function/RequestIP.md) * [**RequestMapping](/api/3.0.0/core/function/RequestMapping.md) * [**RequestPath](/api/3.0.0/core/function/RequestPath.md) * [**Schedule](/api/3.0.0/core/function/Schedule.md) * [**Scope](/api/3.0.0/core/function/Scope.md) * [**ServerlessFunction](/api/3.0.0/core/function/ServerlessFunction.md) * [**ServerlessTrigger](/api/3.0.0/core/function/ServerlessTrigger.md) * [**Session](/api/3.0.0/core/function/Session.md) * [**SetHeader](/api/3.0.0/core/function/SetHeader.md) * [**Singleton](/api/3.0.0/core/function/Singleton.md) * [**Task](/api/3.0.0/core/function/Task.md) * [**TaskLocal](/api/3.0.0/core/function/TaskLocal.md) * [**UseGuard](/api/3.0.0/core/function/UseGuard.md) * [**WSBroadCast](/api/3.0.0/core/function/WSBroadCast.md) * [**WSController](/api/3.0.0/core/function/WSController.md) * [**WSEmit](/api/3.0.0/core/function/WSEmit.md) * [**attachClassMetadata](/api/3.0.0/core/function/attachClassMetadata.md) * [**attachPropertyDataToClass](/api/3.0.0/core/function/attachPropertyDataToClass.md) * [**attachPropertyMetadata](/api/3.0.0/core/function/attachPropertyMetadata.md) * [**bindContainer](/api/3.0.0/core/function/bindContainer.md) * [**clearAllModule](/api/3.0.0/core/function/clearAllModule.md) * [**clearBindContainer](/api/3.0.0/core/function/clearBindContainer.md) * [**createConfiguration](/api/3.0.0/core/function/createConfiguration.md) * [**createCustomMethodDecorator](/api/3.0.0/core/function/createCustomMethodDecorator.md) * [**createCustomParamDecorator](/api/3.0.0/core/function/createCustomParamDecorator.md) * [**createCustomPropertyDecorator](/api/3.0.0/core/function/createCustomPropertyDecorator.md) * [**createMiddleware](/api/3.0.0/core/function/createMiddleware.md) * [**createRender](/api/3.0.0/core/function/createRender.md) * [**createRequestParamDecorator](/api/3.0.0/core/function/createRequestParamDecorator.md) * [**delegateTargetAllPrototypeMethod](/api/3.0.0/core/function/delegateTargetAllPrototypeMethod.md) * [**delegateTargetMethod](/api/3.0.0/core/function/delegateTargetMethod.md) * [**delegateTargetProperties](/api/3.0.0/core/function/delegateTargetProperties.md) * [**delegateTargetPrototypeMethod](/api/3.0.0/core/function/delegateTargetPrototypeMethod.md) * [**deprecatedOutput](/api/3.0.0/core/function/deprecatedOutput.md) * [**destroyGlobalApplicationContext](/api/3.0.0/core/function/destroyGlobalApplicationContext.md) * [**extend](/api/3.0.0/core/function/extend.md) * [**extractExpressLikeValue](/api/3.0.0/core/function/extractExpressLikeValue.md) * [**extractKoaLikeValue](/api/3.0.0/core/function/extractKoaLikeValue.md) * [**getClassExtendedMetadata](/api/3.0.0/core/function/getClassExtendedMetadata.md) * [**getClassMetadata](/api/3.0.0/core/function/getClassMetadata.md) * [**getCurrentApplicationContext](/api/3.0.0/core/function/getCurrentApplicationContext.md) * [**getCurrentAsyncContextManager](/api/3.0.0/core/function/getCurrentAsyncContextManager.md) * [**getCurrentMainApp](/api/3.0.0/core/function/getCurrentMainApp.md) * [**getCurrentMainFramework](/api/3.0.0/core/function/getCurrentMainFramework.md) * [**getMethodParamTypes](/api/3.0.0/core/function/getMethodParamTypes.md) * [**getMethodReturnTypes](/api/3.0.0/core/function/getMethodReturnTypes.md) * [**getObjectDefinition](/api/3.0.0/core/function/getObjectDefinition.md) * [**getPropertyDataFromClass](/api/3.0.0/core/function/getPropertyDataFromClass.md) * [**getPropertyInject](/api/3.0.0/core/function/getPropertyInject.md) * [**getPropertyMetadata](/api/3.0.0/core/function/getPropertyMetadata.md) * [**getPropertyType](/api/3.0.0/core/function/getPropertyType.md) * [**getProviderId](/api/3.0.0/core/function/getProviderId.md) * [**getProviderName](/api/3.0.0/core/function/getProviderName.md) * [**getProviderUUId](/api/3.0.0/core/function/getProviderUUId.md) * [**initializeGlobalApplicationContext](/api/3.0.0/core/function/initializeGlobalApplicationContext.md) * [**isProvide](/api/3.0.0/core/function/isProvide.md) * [**isTypeScriptEnvironment](/api/3.0.0/core/function/isTypeScriptEnvironment.md) * [**listModule](/api/3.0.0/core/function/listModule.md) * [**listPreloadModule](/api/3.0.0/core/function/listPreloadModule.md) * [**listPropertyDataFromClass](/api/3.0.0/core/function/listPropertyDataFromClass.md) * [**loadModule](/api/3.0.0/core/function/loadModule.md) * [**makeHttpRequest](/api/3.0.0/core/function/makeHttpRequest.md) * [**pathMatching](/api/3.0.0/core/function/pathMatching.md) * [**prepareGlobalApplicationContext](/api/3.0.0/core/function/prepareGlobalApplicationContext.md) * [**prepareGlobalApplicationContextAsync](/api/3.0.0/core/function/prepareGlobalApplicationContextAsync.md) * [**providerWrapper](/api/3.0.0/core/function/providerWrapper.md) * [**registerErrorCode](/api/3.0.0/core/function/registerErrorCode.md) * [**resetModule](/api/3.0.0/core/function/resetModule.md) * [**retryWith](/api/3.0.0/core/function/retryWith.md) * [**retryWithAsync](/api/3.0.0/core/function/retryWithAsync.md) * [**safeRequire](/api/3.0.0/core/function/safeRequire.md) * [**safelyGet](/api/3.0.0/core/function/safelyGet.md) * [**saveClassMetadata](/api/3.0.0/core/function/saveClassMetadata.md) * [**saveModule](/api/3.0.0/core/function/saveModule.md) * [**saveObjectDefinition](/api/3.0.0/core/function/saveObjectDefinition.md) * [**savePreloadModule](/api/3.0.0/core/function/savePreloadModule.md) * [**savePropertyDataToClass](/api/3.0.0/core/function/savePropertyDataToClass.md) * [**savePropertyInject](/api/3.0.0/core/function/savePropertyInject.md) * [**savePropertyMetadata](/api/3.0.0/core/function/savePropertyMetadata.md) * [**saveProviderId](/api/3.0.0/core/function/saveProviderId.md) * [**sleep](/api/3.0.0/core/function/sleep.md) * [**transformRequestObjectByType](/api/3.0.0/core/function/transformRequestObjectByType.md) * [**transformTypeFromTSDesign](/api/3.0.0/core/function/transformTypeFromTSDesign.md) * [**wrapAsync](/api/3.0.0/core/function/wrapAsync.md) * [**wrapMiddleware](/api/3.0.0/core/function/wrapMiddleware.md) ### Interfaces * [**AspectMetadata](/api/3.0.0/core/interface/AspectMetadata.md) * [**AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) * [**AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) * [**CommonSchedule](/api/3.0.0/core/interface/CommonSchedule.md) * [**Context](/api/3.0.0/core/interface/Context.md) * [**ControllerOption](/api/3.0.0/core/interface/ControllerOption.md) * [**HSFOpts](/api/3.0.0/core/interface/HSFOpts.md) * [**HealthResult](/api/3.0.0/core/interface/HealthResult.md) * [**HealthResults](/api/3.0.0/core/interface/HealthResults.md) * [**HttpClientOptions](/api/3.0.0/core/interface/HttpClientOptions.md) * [**HttpClientResponse](/api/3.0.0/core/interface/HttpClientResponse.md) * [**IComponentInfo](/api/3.0.0/core/interface/IComponentInfo.md) * [**IConfigService](/api/3.0.0/core/interface/IConfigService.md) * [**IConfigurationOptions](/api/3.0.0/core/interface/IConfigurationOptions.md) * [**IEnvironmentService](/api/3.0.0/core/interface/IEnvironmentService.md) * [**IFileDetector](/api/3.0.0/core/interface/IFileDetector.md) * [**IFilter](/api/3.0.0/core/interface/IFilter.md) * [**IGuard](/api/3.0.0/core/interface/IGuard.md) * [**IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) * [**IInformationService](/api/3.0.0/core/interface/IInformationService.md) * [**ILifeCycle](/api/3.0.0/core/interface/ILifeCycle.md) * [**ILogger](/api/3.0.0/core/interface/ILogger.md) * [**IManagedInstance](/api/3.0.0/core/interface/IManagedInstance.md) * [**IManagedResolver](/api/3.0.0/core/interface/IManagedResolver.md) * [**IManagedResolverFactoryCreateOptions](/api/3.0.0/core/interface/IManagedResolverFactoryCreateOptions.md) * [**IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md) * [**IMiddleware](/api/3.0.0/core/interface/IMiddleware.md) * [**IMiddlewareManager](/api/3.0.0/core/interface/IMiddlewareManager.md) * [**IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md) * [**IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md) * [**IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) * [**IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md) * [**IModuleStore](/api/3.0.0/core/interface/IModuleStore.md) * [**IObjectCreator](/api/3.0.0/core/interface/IObjectCreator.md) * [**IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) * [**IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md) * [**IObjectFactory](/api/3.0.0/core/interface/IObjectFactory.md) * [**IObjectLifeCycle](/api/3.0.0/core/interface/IObjectLifeCycle.md) * [**IPipelineContext](/api/3.0.0/core/interface/IPipelineContext.md) * [**IPipelineHandler](/api/3.0.0/core/interface/IPipelineHandler.md) * [**IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md) * [**IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md) * [**IProperties](/api/3.0.0/core/interface/IProperties.md) * [**IServiceFactory](/api/3.0.0/core/interface/IServiceFactory.md) * [**ISimulation](/api/3.0.0/core/interface/ISimulation.md) * [**IValveHandler](/api/3.0.0/core/interface/IValveHandler.md) * [**InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md) * [**JoinPoint](/api/3.0.0/core/interface/JoinPoint.md) * [**KafkaListenerOptions](/api/3.0.0/core/interface/KafkaListenerOptions.md) * [**MethodDecoratorMetaData](/api/3.0.0/core/interface/MethodDecoratorMetaData.md) * [**MethodDecoratorOptions](/api/3.0.0/core/interface/MethodDecoratorOptions.md) * [**MidwayAppInfo](/api/3.0.0/core/interface/MidwayAppInfo.md) * [**MidwayConfig](/api/3.0.0/core/interface/MidwayConfig.md) * [**MidwayCoreDefaultConfig](/api/3.0.0/core/interface/MidwayCoreDefaultConfig.md) * [**MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md) * [**ObjectBeforeBindOptions](/api/3.0.0/core/interface/ObjectBeforeBindOptions.md) * [**ObjectBeforeCreatedOptions](/api/3.0.0/core/interface/ObjectBeforeCreatedOptions.md) * [**ObjectBeforeDestroyOptions](/api/3.0.0/core/interface/ObjectBeforeDestroyOptions.md) * [**ObjectCreatedOptions](/api/3.0.0/core/interface/ObjectCreatedOptions.md) * [**ObjectDefinitionOptions](/api/3.0.0/core/interface/ObjectDefinitionOptions.md) * [**ObjectInitOptions](/api/3.0.0/core/interface/ObjectInitOptions.md) * [**ParamDecoratorOptions](/api/3.0.0/core/interface/ParamDecoratorOptions.md) * [**ParameterDecoratorMetaData](/api/3.0.0/core/interface/ParameterDecoratorMetaData.md) * [**PipeTransform](/api/3.0.0/core/interface/PipeTransform.md) * [**RabbitMQListenerOptions](/api/3.0.0/core/interface/RabbitMQListenerOptions.md) * [**ReflectResult](/api/3.0.0/core/interface/ReflectResult.md) * [**ResolveFilter](/api/3.0.0/core/interface/ResolveFilter.md) * [**RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md) * [**RouterInfo](/api/3.0.0/core/interface/RouterInfo.md) * [**RouterOption](/api/3.0.0/core/interface/RouterOption.md) * [**RouterParamValue](/api/3.0.0/core/interface/RouterParamValue.md) * [**RouterPriority](/api/3.0.0/core/interface/RouterPriority.md) * [**ScheduleOpts](/api/3.0.0/core/interface/ScheduleOpts.md) * [**ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md) * [**ServerSendEventStreamOptions](/api/3.0.0/core/interface/ServerSendEventStreamOptions.md) * [**ServerStreamOptions](/api/3.0.0/core/interface/ServerStreamOptions.md) * [**TSDesignType](/api/3.0.0/core/interface/TSDesignType.md) * [**TagClsMetadata](/api/3.0.0/core/interface/TagClsMetadata.md) * [**TagPropsMetadata](/api/3.0.0/core/interface/TagPropsMetadata.md) * [**TransformOptions](/api/3.0.0/core/interface/TransformOptions.md) * [**WSControllerOption](/api/3.0.0/core/interface/WSControllerOption.md) * [**WSEventInfo](/api/3.0.0/core/interface/WSEventInfo.md) ### Namespaces * [**ConsumerMetadata](/api/3.0.0/core/namespace/ConsumerMetadata.md) * [**FaaSMetadata](/api/3.0.0/core/namespace/FaaSMetadata.md) * [**GRPCMetadata](/api/3.0.0/core/namespace/GRPCMetadata.md) ### Type Aliases * [**ClassMiddleware](/api/3.0.0/core.md#ClassMiddleware) * [**ClassType](/api/3.0.0/core.md#ClassType) * [**CommonFilterUnion](/api/3.0.0/core.md#CommonFilterUnion) * [**CommonGuardUnion](/api/3.0.0/core.md#CommonGuardUnion) * [**CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware) * [**CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion) * [**CompositionMiddleware](/api/3.0.0/core.md#CompositionMiddleware) * [**ConsumerRunConfig](/api/3.0.0/core.md#ConsumerRunConfig) * [**ConsumerSubscribeTopic](/api/3.0.0/core.md#ConsumerSubscribeTopic) * [**ConsumerSubscribeTopics](/api/3.0.0/core.md#ConsumerSubscribeTopics) * [**CreateDataSourceInstanceOptions](/api/3.0.0/core.md#CreateDataSourceInstanceOptions) * [**CustomParamDecorator](/api/3.0.0/core.md#CustomParamDecorator) * [**DataSourceManagerConfigOption](/api/3.0.0/core.md#DataSourceManagerConfigOption) * [**DynamicRouterInfo](/api/3.0.0/core.md#DynamicRouterInfo) * [**ExpressLikeCustomParamDecorator](/api/3.0.0/core.md#ExpressLikeCustomParamDecorator) * [**FileConfigOption](/api/3.0.0/core.md#FileConfigOption) * [**FunctionMiddleware](/api/3.0.0/core.md#FunctionMiddleware) * [**GroupModeType](/api/3.0.0/core.md#GroupModeType) * [**HandlerFunction](/api/3.0.0/core.md#HandlerFunction) * [**HttpClientMimeType](/api/3.0.0/core.md#HttpClientMimeType) * [**IApplicationContext](/api/3.0.0/core.md#IApplicationContext) * [**IMidwayApplication](/api/3.0.0/core.md#IMidwayApplication) * [**IMidwayContext](/api/3.0.0/core.md#IMidwayContext) * [**IMidwayLogger](/api/3.0.0/core.md#IMidwayLogger) * [**IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher) * [**KoaLikeCustomParamDecorator](/api/3.0.0/core.md#KoaLikeCustomParamDecorator) * [**MatchPattern](/api/3.0.0/core.md#MatchPattern) * [**MethodHandlerFunction](/api/3.0.0/core.md#MethodHandlerFunction) * [**MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) * [**MiddlewareRespond](/api/3.0.0/core.md#MiddlewareRespond) * [**ModuleLoadType](/api/3.0.0/core.md#ModuleLoadType) * [**NextFunction](/api/3.0.0/core.md#NextFunction) * [**ObjectContext](/api/3.0.0/core.md#ObjectContext) * [**ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier) * [**ParameterHandlerFunction](/api/3.0.0/core.md#ParameterHandlerFunction) * [**PipeTransformFunction](/api/3.0.0/core.md#PipeTransformFunction) * [**PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform) * [**PowerPartial](/api/3.0.0/core.md#PowerPartial) * [**ResOrMessage](/api/3.0.0/core.md#ResOrMessage) * [**ServiceFactoryConfigOption](/api/3.0.0/core.md#ServiceFactoryConfigOption) * [**WithFn](/api/3.0.0/core.md#WithFn) * [**WithoutFn](/api/3.0.0/core.md#WithoutFn) * [**Writable](/api/3.0.0/core.md#Writable) ### Variables * [**ALL](/api/3.0.0/core.md#ALL) * [**APPLICATION\_CONTEXT\_KEY](/api/3.0.0/core.md#APPLICATION_CONTEXT_KEY) * [**APPLICATION\_KEY](/api/3.0.0/core.md#APPLICATION_KEY) * [**ASPECT\_KEY](/api/3.0.0/core.md#ASPECT_KEY) * [**ASYNC\_CONTEXT\_KEY](/api/3.0.0/core.md#ASYNC_CONTEXT_KEY) * [**ASYNC\_CONTEXT\_MANAGER\_KEY](/api/3.0.0/core.md#ASYNC_CONTEXT_MANAGER_KEY) * [**ASYNC\_ROOT\_CONTEXT](/api/3.0.0/core.md#ASYNC_ROOT_CONTEXT) * [**CATCH\_KEY](/api/3.0.0/core.md#CATCH_KEY) * [**CLASS\_KEY\_CONSTRUCTOR](/api/3.0.0/core.md#CLASS_KEY_CONSTRUCTOR) * [**CONFIGURATION\_KEY](/api/3.0.0/core.md#CONFIGURATION_KEY) * [**CONFIG\_KEY](/api/3.0.0/core.md#CONFIG_KEY) * [**CONTAINER\_OBJ\_SCOPE](/api/3.0.0/core.md#CONTAINER_OBJ_SCOPE) * [**CONTROLLER\_KEY](/api/3.0.0/core.md#CONTROLLER_KEY) * [**DEFAULT\_PATTERN](/api/3.0.0/core.md#DEFAULT_PATTERN) * [**DEFAULT\_PRIORITY](/api/3.0.0/core.md#DEFAULT_PRIORITY) * [**FACTORY\_SERVICE\_CLIENT\_KEY](/api/3.0.0/core.md#FACTORY_SERVICE_CLIENT_KEY) * [**FORMAT](/api/3.0.0/core.md#FORMAT) * [**FRAMEWORK\_KEY](/api/3.0.0/core.md#FRAMEWORK_KEY) * [**FUNCTION\_INJECT\_KEY](/api/3.0.0/core.md#FUNCTION_INJECT_KEY) * [**FUNC\_KEY](/api/3.0.0/core.md#FUNC_KEY) * [**FileUtils](/api/3.0.0/core.md#FileUtils) * [**FrameworkErrorEnum](/api/3.0.0/core.md#FrameworkErrorEnum) * [**GUARD\_KEY](/api/3.0.0/core.md#GUARD_KEY) * [**HSF\_KEY](/api/3.0.0/core.md#HSF_KEY) * [**HTTP\_SERVER\_KEY](/api/3.0.0/core.md#HTTP_SERVER_KEY) * [**IGNORE\_PATTERN](/api/3.0.0/core.md#IGNORE_PATTERN) * [**INJECT\_CLASS\_KEY\_PREFIX](/api/3.0.0/core.md#INJECT_CLASS_KEY_PREFIX) * [**INJECT\_CUSTOM\_METHOD](/api/3.0.0/core.md#INJECT_CUSTOM_METHOD) * [**INJECT\_CUSTOM\_PARAM](/api/3.0.0/core.md#INJECT_CUSTOM_PARAM) * [**INJECT\_CUSTOM\_PROPERTY](/api/3.0.0/core.md#INJECT_CUSTOM_PROPERTY) * [**INJECT\_TAG](/api/3.0.0/core.md#INJECT_TAG) * [**KEYS](/api/3.0.0/core.md#KEYS) * [**LIFECYCLE\_IDENTIFIER\_PREFIX](/api/3.0.0/core.md#LIFECYCLE_IDENTIFIER_PREFIX) * [**LOGGER\_KEY](/api/3.0.0/core.md#LOGGER_KEY) * [**MAIN\_MODULE\_KEY](/api/3.0.0/core.md#MAIN_MODULE_KEY) * [**MATCH\_KEY](/api/3.0.0/core.md#MATCH_KEY) * [**MIDWAY\_LOGGER\_WRITEABLE\_DIR](/api/3.0.0/core.md#MIDWAY_LOGGER_WRITEABLE_DIR) * [**MOCK\_KEY](/api/3.0.0/core.md#MOCK_KEY) * [**MODULE\_TASK\_KEY](/api/3.0.0/core.md#MODULE_TASK_KEY) * [**MODULE\_TASK\_METADATA](/api/3.0.0/core.md#MODULE_TASK_METADATA) * [**MODULE\_TASK\_QUEUE\_KEY](/api/3.0.0/core.md#MODULE_TASK_QUEUE_KEY) * [**MODULE\_TASK\_QUEUE\_OPTIONS](/api/3.0.0/core.md#MODULE_TASK_QUEUE_OPTIONS) * [**MODULE\_TASK\_TASK\_LOCAL\_KEY](/api/3.0.0/core.md#MODULE_TASK_TASK_LOCAL_KEY) * [**MODULE\_TASK\_TASK\_LOCAL\_OPTIONS](/api/3.0.0/core.md#MODULE_TASK_TASK_LOCAL_OPTIONS) * [**MS\_CONSUMER\_KEY](/api/3.0.0/core.md#MS_CONSUMER_KEY) * [**MS\_DUBBO\_METHOD\_KEY](/api/3.0.0/core.md#MS_DUBBO_METHOD_KEY) * [**MS\_GRPC\_METHOD\_KEY](/api/3.0.0/core.md#MS_GRPC_METHOD_KEY) * [**MS\_HSF\_METHOD\_KEY](/api/3.0.0/core.md#MS_HSF_METHOD_KEY) * [**MS\_PRODUCER\_KEY](/api/3.0.0/core.md#MS_PRODUCER_KEY) * [**MS\_PROVIDER\_KEY](/api/3.0.0/core.md#MS_PROVIDER_KEY) * [**NAMED\_TAG](/api/3.0.0/core.md#NAMED_TAG) * [**OBJ\_DEF\_CLS](/api/3.0.0/core.md#OBJ_DEF_CLS) * [**PIPELINE\_IDENTIFIER](/api/3.0.0/core.md#PIPELINE_IDENTIFIER) * [**PLUGIN\_KEY](/api/3.0.0/core.md#PLUGIN_KEY) * [**PRELOAD\_MODULE\_KEY](/api/3.0.0/core.md#PRELOAD_MODULE_KEY) * [**PRIVATE\_META\_DATA\_KEY](/api/3.0.0/core.md#PRIVATE_META_DATA_KEY) * [**PathFileUtil](/api/3.0.0/core.md#PathFileUtil) * [**PathToRegexpUtil](/api/3.0.0/core.md#PathToRegexpUtil) * [**REQUEST\_CTX\_KEY](/api/3.0.0/core.md#REQUEST_CTX_KEY) * [**REQUEST\_CTX\_LOGGER\_CACHE\_KEY](/api/3.0.0/core.md#REQUEST_CTX_LOGGER_CACHE_KEY) * [**REQUEST\_OBJ\_CTX\_KEY](/api/3.0.0/core.md#REQUEST_OBJ_CTX_KEY) * [**RPC\_DUBBO\_KEY](/api/3.0.0/core.md#RPC_DUBBO_KEY) * [**RPC\_GRPC\_KEY](/api/3.0.0/core.md#RPC_GRPC_KEY) * [**RequestMethod](/api/3.0.0/core.md#RequestMethod) * [**SCHEDULE\_KEY](/api/3.0.0/core.md#SCHEDULE_KEY) * [**SERVERLESS\_FUNC\_KEY](/api/3.0.0/core.md#SERVERLESS_FUNC_KEY) * [**SINGLETON\_CONTAINER\_CTX](/api/3.0.0/core.md#SINGLETON_CONTAINER_CTX) * [**TAGGED\_CLS](/api/3.0.0/core.md#TAGGED_CLS) * [**TAGGED\_FUN](/api/3.0.0/core.md#TAGGED_FUN) * [**Types](/api/3.0.0/core.md#Types) * [**Utils](/api/3.0.0/core.md#Utils) * [**WEB\_RESPONSE\_CONTENT\_TYPE](/api/3.0.0/core.md#WEB_RESPONSE_CONTENT_TYPE) * [**WEB\_RESPONSE\_HEADER](/api/3.0.0/core.md#WEB_RESPONSE_HEADER) * [**WEB\_RESPONSE\_HTTP\_CODE](/api/3.0.0/core.md#WEB_RESPONSE_HTTP_CODE) * [**WEB\_RESPONSE\_KEY](/api/3.0.0/core.md#WEB_RESPONSE_KEY) * [**WEB\_RESPONSE\_REDIRECT](/api/3.0.0/core.md#WEB_RESPONSE_REDIRECT) * [**WEB\_RESPONSE\_RENDER](/api/3.0.0/core.md#WEB_RESPONSE_RENDER) * [**WEB\_ROUTER\_KEY](/api/3.0.0/core.md#WEB_ROUTER_KEY) * [**WEB\_ROUTER\_PARAM\_KEY](/api/3.0.0/core.md#WEB_ROUTER_PARAM_KEY) * [**WS\_CONTROLLER\_KEY](/api/3.0.0/core.md#WS_CONTROLLER_KEY) * [**WS\_EVENT\_KEY](/api/3.0.0/core.md#WS_EVENT_KEY) * [**httpError](/api/3.0.0/core.md#httpError) ## Type Aliases[**](<#Type Aliases>) ### [**](#ClassMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L875)ClassMiddleware **ClassMiddleware\: new (...args: any) => [IMiddleware](/api/3.0.0/core/interface/IMiddleware.md)\ #### Type parameters * **CTX** * **R** * **N** ### [**](#ClassType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1252)ClassType **ClassType\: new (...args: any\[]) => T #### Type parameters * **T** = any ### [**](#CommonFilterUnion)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L906)CommonFilterUnion **CommonFilterUnion\: new (...args: any) => [IFilter](/api/3.0.0/core/interface/IFilter.md)\ | new (...args: any) => [IFilter](/api/3.0.0/core/interface/IFilter.md)\\[] #### Type parameters * **CTX** * **R** * **N** ### [**](#CommonGuardUnion)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L917)CommonGuardUnion **CommonGuardUnion\: new (...args: any) => [IGuard](/api/3.0.0/core/interface/IGuard.md)\ | new (...args: any) => [IGuard](/api/3.0.0/core/interface/IGuard.md)\\[] #### Type parameters * **CTX** = unknown ### [**](#CommonMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L886)CommonMiddleware **CommonMiddleware\: [ClassMiddleware](/api/3.0.0/core.md#ClassMiddleware)\ | [FunctionMiddleware](/api/3.0.0/core.md#FunctionMiddleware)\ | [CompositionMiddleware](/api/3.0.0/core.md#CompositionMiddleware)\ #### Type parameters * **CTX** * **R** * **N** ### [**](#CommonMiddlewareUnion)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L890)CommonMiddlewareUnion **CommonMiddlewareUnion\: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\ | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\\[] #### Type parameters * **CTX** * **R** * **N** ### [**](#CompositionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L881)CompositionMiddleware **CompositionMiddleware\: { middleware: [ClassMiddleware](/api/3.0.0/core.md#ClassMiddleware)\; name? : string; options: any } #### Type parameters * **CTX** * **R** * **N** ### [**](#ConsumerRunConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L13)ConsumerRunConfig **ConsumerRunConfig: { autoCommit? : boolean; autoCommitInterval? : number | null; autoCommitThreshold? : number | null; eachBatchAutoResolve? : boolean; partitionsConsumedConcurrently? : number } ### [**](#ConsumerSubscribeTopic)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L6)ConsumerSubscribeTopic **ConsumerSubscribeTopic: { fromBeginning? : boolean } * **@deprecated** Replaced by ConsumerSubscribeTopics ### [**](#ConsumerSubscribeTopics)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L9)ConsumerSubscribeTopics **ConsumerSubscribeTopics: { fromBeginning? : boolean } ### [**](#CreateDataSourceInstanceOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L474)CreateDataSourceInstanceOptions **CreateDataSourceInstanceOptions: { cacheInstance? : boolean; validateConnection? : boolean } ### [**](#CustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L57)CustomParamDecorator **CustomParamDecorator\: [KoaLikeCustomParamDecorator](/api/3.0.0/core.md#KoaLikeCustomParamDecorator)\ | [ExpressLikeCustomParamDecorator](/api/3.0.0/core.md#ExpressLikeCustomParamDecorator)\ #### Type parameters * **T** = unknown ### [**](#DataSourceManagerConfigOption)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L485)DataSourceManagerConfigOption **DataSourceManagerConfigOption\: { dataSource? : {}; default? : OPTIONS; defaultDataSourceName? : string } & [CreateDataSourceInstanceOptions](/api/3.0.0/core.md#CreateDataSourceInstanceOptions) #### Type parameters * **OPTIONS** * **ENTITY\_CONFIG\_KEY**: string = entities ### [**](#DynamicRouterInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L128)DynamicRouterInfo **DynamicRouterInfo: Omit<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md), id | method | controllerId | controllerMiddleware | responseMetadata> ### [**](#ExpressLikeCustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L52)ExpressLikeCustomParamDecorator **ExpressLikeCustomParamDecorator\: (req: any, res: any) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#FileConfigOption)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L504)FileConfigOption **FileConfigOption\: K extends keyof ConfigType\ ? Pick\, K> : ConfigType\ Get definition from config *** #### Type parameters * **T** * **K** = unknown ### [**](#FunctionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L872)FunctionMiddleware **FunctionMiddleware\: N extends true ? (req: CTX, res: R, next: N) => any : (context: CTX, next: R, options? : any) => any #### Type parameters * **CTX** * **R** * **N** = unknown ### [**](#GroupModeType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L52)GroupModeType **GroupModeType: one | multi ### [**](#HandlerFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L716)HandlerFunction **HandlerFunction: (key: string, meta: any, instance: any) => any ### [**](#HttpClientMimeType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L10)HttpClientMimeType **HttpClientMimeType: text | json | undefined ### [**](#IApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L792)IApplicationContext **IApplicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) * **@deprecated** ### [**](#IMidwayApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1087)IMidwayApplication **IMidwayApplication\: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)\ & FrameworkApplication #### Type parameters * **T**: [IMidwayContext](/api/3.0.0/core.md#IMidwayContext) = [IMidwayContext](/api/3.0.0/core.md#IMidwayContext) * **FrameworkApplication** = unknown ### [**](#IMidwayContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L852)IMidwayContext **IMidwayContext\: [Context](/api/3.0.0/core/interface/Context.md) & FrameworkContext #### Type parameters * **FrameworkContext** = unknown ### [**](#IMidwayLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L425)IMidwayLogger **IMidwayLogger: [ILogger](/api/3.0.0/core/interface/ILogger.md) * **@deprecated** ### [**](#IgnoreMatcher)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L856)IgnoreMatcher **IgnoreMatcher\: string | RegExp | (ctx: CTX) => boolean #### Type parameters * **CTX** ### [**](#KoaLikeCustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L48)KoaLikeCustomParamDecorator **KoaLikeCustomParamDecorator\: (ctx: [IMidwayContext](/api/3.0.0/core.md#IMidwayContext)) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#MatchPattern)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/filter.ts#L29)MatchPattern **MatchPattern\: (ctxOrReq: CtxOrReq, res: Res) => boolean | string | string\[] | boolean #### Type parameters * **CtxOrReq** = any * **Res** = any ### [**](#MethodHandlerFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L728)MethodHandlerFunction **MethodHandlerFunction: (options: { metadata: any; propertyName: string; target: new (...args: any) => any }) => [IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md) ### [**](#MiddlewareParamArray)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L50)MiddlewareParamArray **MiddlewareParamArray: (string | any)\[] ### [**](#MiddlewareRespond)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L893)MiddlewareRespond **MiddlewareRespond\: (context: CTX, nextOrRes? : N extends true ? R : [NextFunction](/api/3.0.0/core.md#NextFunction), next? : N) => Promise\ #### Type parameters * **CTX** * **R** * **N** ### [**](#ModuleLoadType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1092)ModuleLoadType **ModuleLoadType: commonjs | esm ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L854)NextFunction **NextFunction: () => Promise\ ### [**](#ObjectContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L535)ObjectContext **ObjectContext: { originName? : string } ### [**](#ObjectIdentifier)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L51)ObjectIdentifier **ObjectIdentifier: string | Symbol ### [**](#ParameterHandlerFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L734)ParameterHandlerFunction **ParameterHandlerFunction: (options: { metadata: any; originArgs: any\[]; originParamType: any; parameterIndex: number; propertyName: string; target: new (...args: any) => any }) => any ### [**](#PipeTransformFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L372)PipeTransformFunction **PipeTransformFunction\: (value: T) => R #### Type parameters * **T** = any * **R** = any ### [**](#PipeUnionTransform)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L374)PipeUnionTransform **PipeUnionTransform\: [PipeTransform](/api/3.0.0/core/interface/PipeTransform.md)\ | new (...args: any) => [PipeTransform](/api/3.0.0/core/interface/PipeTransform.md)\ | [PipeTransformFunction](/api/3.0.0/core.md#PipeTransformFunction)\ #### Type parameters * **T** = any * **R** = any ### [**](#PowerPartial)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L5)PowerPartial **PowerPartial\: { \[ U in keyof T ]?: T\[U] extends {} ? [PowerPartial](/api/3.0.0/core.md#PowerPartial)\ : T\[U] } #### Type parameters * **T** ### [**](#ResOrMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L67)ResOrMessage **ResOrMessage: string | { message: string } | undefined ### [**](#ServiceFactoryConfigOption)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L462)ServiceFactoryConfigOption **ServiceFactoryConfigOption\: { client? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)\; clientPriority? : {}; clients? : {}; default? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)\; defaultClientName? : string } #### Type parameters * **OPTIONS** ### [**](#WithFn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L33)WithFn **WithFn\: { \[ K in keyof T ]: T\[K] extends (...args: infer P) => infer R ? (fn: (...args: P) => R) => void : T\[K] } Utility type that adds a `fn` parameter to each method in the input type `T`, transforming the original method's parameter types and return type into a function type. * **@example** ``` // Input: interface MyInterface { method1(a: string, b: number): boolean; method2(x: Foo, y: Bar): void; } // Output: interface MyInterfaceWithFn { method1(fn: (a: string, b: number) => boolean): void; method2(fn: (x: Foo, y: Bar) => void): void; } ``` *** #### Type parameters * **T** ### [**](#WithoutFn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L44)WithoutFn **WithoutFn\: { \[ K in keyof T ]: T\[K] extends (arg: any, ...args: any\[]) => any ? (...args: Parameters\) => ReturnType\ : T\[K] } Transform an object type `T` with methods that have function-type parameters to a new object type with the same methods, but with the parameters extracted as separate properties. *** #### Type parameters * **T** ### [**](#Writable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L12)Writable **Writable\: { -readonly \[ P in keyof T ]: T\[P] } Make object property writeable *** #### Type parameters * **T** ## Variables[**](#Variables) ### [**](#ALL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L2)constALL **ALL: common:all\_value\_key = 'common:all\_value\_key' ### [**](#APPLICATION_CONTEXT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L62)constAPPLICATION\_CONTEXT\_KEY **APPLICATION\_CONTEXT\_KEY: \_\_midway\_application\_context\_\_ = '\_\_midway\_application\_context\_\_' ### [**](#APPLICATION_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L61)constAPPLICATION\_KEY **APPLICATION\_KEY: \_\_midway\_framework\_app\_\_ = '\_\_midway\_framework\_app\_\_' ### [**](#ASPECT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L8)constASPECT\_KEY **ASPECT\_KEY: common:aspect = 'common:aspect' ### [**](#ASYNC_CONTEXT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L51)constASYNC\_CONTEXT\_KEY **ASYNC\_CONTEXT\_KEY: typeof [ASYNC\_CONTEXT\_KEY](/api/3.0.0/core.md#ASYNC_CONTEXT_KEY) = ... ### [**](#ASYNC_CONTEXT_MANAGER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L52)constASYNC\_CONTEXT\_MANAGER\_KEY **ASYNC\_CONTEXT\_MANAGER\_KEY: MIDWAY\_ASYNC\_CONTEXT\_MANAGER\_KEY = 'MIDWAY\_ASYNC\_CONTEXT\_MANAGER\_KEY' ### [**](#ASYNC_ROOT_CONTEXT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L137)constASYNC\_ROOT\_CONTEXT **ASYNC\_ROOT\_CONTEXT: [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) = ... The root context is used as the default parent context when there is no active context ### [**](#CATCH_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L9)constCATCH\_KEY **CATCH\_KEY: common:catch = 'common:catch' ### [**](#CLASS_KEY_CONSTRUCTOR)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L66)constCLASS\_KEY\_CONSTRUCTOR **CLASS\_KEY\_CONSTRUCTOR: midway:class\_key\_constructor = 'midway:class\_key\_constructor' ### [**](#CONFIGURATION_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L6)constCONFIGURATION\_KEY **CONFIGURATION\_KEY: common:configuration = 'common:configuration' ### [**](#CONFIG_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L58)constCONFIG\_KEY **CONFIG\_KEY: config = 'config' ### [**](#CONTAINER_OBJ_SCOPE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L47)constCONTAINER\_OBJ\_SCOPE **CONTAINER\_OBJ\_SCOPE: \_obj\_scope = '\_obj\_scope' ### [**](#CONTROLLER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L20)constCONTROLLER\_KEY **CONTROLLER\_KEY: web:controller = 'web:controller' ### [**](#DEFAULT_PATTERN)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L54)constDEFAULT\_PATTERN **DEFAULT\_PATTERN: string\[] = ... ### [**](#DEFAULT_PRIORITY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L4)constDEFAULT\_PRIORITY **DEFAULT\_PRIORITY: { L1: string; L2: string; L3: string } = ... ### [**](#FACTORY_SERVICE_CLIENT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L13)constFACTORY\_SERVICE\_CLIENT\_KEY **FACTORY\_SERVICE\_CLIENT\_KEY: common:service\_factory:client = 'common:service\_factory:client' ### [**](#FORMAT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/format.ts#L34)constFORMAT **FORMAT: { CRONTAB: { EVERY\_DAY: string; EVERY\_DAY\_ONE\_FIFTEEN: string; EVERY\_DAY\_ZERO\_FIFTEEN: string; EVERY\_HOUR: string; EVERY\_MINUTE: string; EVERY\_PER\_10\_MINUTE: string; EVERY\_PER\_10\_SECOND: string; EVERY\_PER\_30\_MINUTE: string; EVERY\_PER\_30\_SECOND: string; EVERY\_PER\_5\_MINUTE: string; EVERY\_PER\_5\_SECOND: string; EVERY\_SECOND: string }; MS: { ONE\_DAY: number; ONE\_HOUR: number; ONE\_MINUTE: number; ONE\_SECOND: number; ONE\_WEEK: number; ONE\_YEAR: number } } = ... ### [**](#FRAMEWORK_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L7)constFRAMEWORK\_KEY **FRAMEWORK\_KEY: common:framework = 'common:framework' ### [**](#FUNCTION_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L43)constFUNCTION\_INJECT\_KEY **FUNCTION\_INJECT\_KEY: midway:function\_inject\_key = 'midway:function\_inject\_key' ### [**](#FUNC_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L16)constFUNC\_KEY **FUNC\_KEY: faas:func = 'faas:func' ### [**](#FileUtils)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/fs.ts#L10)constFileUtils **FileUtils: { exists: (p: any) => Promise\ } = ... ### [**](#FrameworkErrorEnum)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L4)constFrameworkErrorEnum **FrameworkErrorEnum: ConvertString<{ CODE\_INVOKE\_TIMEOUT: 10019; COMMON: 10001; DEFINITION\_NOT\_FOUND: 10003; DUPLICATE\_CLASS\_NAME: 10015; DUPLICATE\_CONTROLLER\_PREFIX\_OPTIONS: 10016; DUPLICATE\_ROUTER: 10008; EMPTY\_VALUE: 10022; FEATURE\_NOT\_IMPLEMENTED: 10004; FEATURE\_NO\_LONGER\_SUPPORTED: 10004; INCONSISTENT\_VERSION: 10013; INVALID\_CONFIG: 10014; INVALID\_CONFIG\_PROPERTY: 10021; INVOKE\_METHOD\_FORBIDDEN: 10018; MAIN\_FRAMEWORK\_MISSING: 10020; MISSING\_CONFIG: 10006; MISSING\_IMPORTS: 10011; MISSING\_RESOLVER: 10007; PARAM\_TYPE: 10002; RETRY\_OVER\_MAX\_TIME: 10017; SINGLETON\_INJECT\_REQUEST: 10010; UNKNOWN: 10000; USE\_WRONG\_METHOD: 10009; UTIL\_HTTP\_TIMEOUT: 10012 }, midway> = ... ### [**](#GUARD_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L11)constGUARD\_KEY **GUARD\_KEY: common:guard = 'common:guard' ### [**](#HSF_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L43)constHSF\_KEY **HSF\_KEY: rpc:hsf = 'rpc:hsf' ### [**](#HTTP_SERVER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L48)constHTTP\_SERVER\_KEY **HTTP\_SERVER\_KEY: \_midway\_http\_server = '\_midway\_http\_server' ### [**](#IGNORE_PATTERN)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L63)constIGNORE\_PATTERN **IGNORE\_PATTERN: string\[] = ... ### [**](#INJECT_CLASS_KEY_PREFIX)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L32)constINJECT\_CLASS\_KEY\_PREFIX **INJECT\_CLASS\_KEY\_PREFIX: INJECTION\_CLASS\_META\_DATA = 'INJECTION\_CLASS\_META\_DATA' ### [**](#INJECT_CUSTOM_METHOD)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L76)constINJECT\_CUSTOM\_METHOD **INJECT\_CUSTOM\_METHOD: inject\_custom\_method = 'inject\_custom\_method' ### [**](#INJECT_CUSTOM_PARAM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L78)constINJECT\_CUSTOM\_PARAM **INJECT\_CUSTOM\_PARAM: inject\_custom\_param = 'inject\_custom\_param' ### [**](#INJECT_CUSTOM_PROPERTY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L74)constINJECT\_CUSTOM\_PROPERTY **INJECT\_CUSTOM\_PROPERTY: inject\_custom\_property = 'inject\_custom\_property' ### [**](#INJECT_TAG)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L72)constINJECT\_TAG **INJECT\_TAG: inject = 'inject' ### [**](#KEYS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L5)constKEYS **KEYS: { AROUND\_ELEMENT: string; ASPECT\_ELEMENT: string; ASYNC\_ATTRIBUTE: string; AUTOWIRE\_ATTRIBUTE: string; CONFIGURATION\_ELEMENT: string; CONSTRUCTOR\_ARG\_ELEMENT: string; DIRECT\_ATTRIBUTE: string; ENTRY\_ELEMENT: string; EXECUTE\_ATTRIBUTE: string; EXPRESSION\_ATTRIBUTE: string; EXTERNAL\_ATTRIBUTE: string; ID\_ATTRIBUTE: string; IMPORT\_ELEMENT: string; JSON\_ELEMENT: string; KEY\_ATTRIBUTE: string; LIST\_ELEMENT: string; MAP\_ELEMENT: string; NAME\_ATTRIBUTE: string; OBJECTS\_ELEMENT: string; OBJECT\_ATTRIBUTE: string; OBJECT\_ELEMENT: string; PATH\_ATTRIBUTE: string; PROPERTY\_ELEMENT: string; PROPS\_ELEMENT: string; PROP\_ELEMENT: string; REF\_ATTRIBUTE: string; REF\_ELEMENT: string; RESOURCE\_ATTRIBUTE: string; SCOPE\_ATTRIBUTE: string; SET\_ELEMENT: string; TYPE\_ATTRIBUTE: string; VALUE\_ATTRIBUTE: string; VALUE\_ELEMENT: string } = ... 静态参数 ### [**](#LIFECYCLE_IDENTIFIER_PREFIX)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L97)constLIFECYCLE\_IDENTIFIER\_PREFIX **LIFECYCLE\_IDENTIFIER\_PREFIX: \_\_lifecycle\_\_ = '\_\_lifecycle\_\_' ### [**](#LOGGER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L60)constLOGGER\_KEY **LOGGER\_KEY: logger = 'logger' ### [**](#MAIN_MODULE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L99)constMAIN\_MODULE\_KEY **MAIN\_MODULE\_KEY: \_\_main\_\_ = '\_\_main\_\_' ### [**](#MATCH_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L10)constMATCH\_KEY **MATCH\_KEY: common:match = 'common:match' ### [**](#MIDWAY_LOGGER_WRITEABLE_DIR)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L44)constMIDWAY\_LOGGER\_WRITEABLE\_DIR **MIDWAY\_LOGGER\_WRITEABLE\_DIR: MIDWAY\_LOGGER\_WRITEABLE\_DIR = 'MIDWAY\_LOGGER\_WRITEABLE\_DIR' ### [**](#MOCK_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L12)constMOCK\_KEY **MOCK\_KEY: common:mock = 'common:mock' ### [**](#MODULE_TASK_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L31)constMODULE\_TASK\_KEY **MODULE\_TASK\_KEY: task:task = 'task:task' ### [**](#MODULE_TASK_METADATA)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L32)constMODULE\_TASK\_METADATA **MODULE\_TASK\_METADATA: task:task:options = 'task:task:options' ### [**](#MODULE_TASK_QUEUE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L35)constMODULE\_TASK\_QUEUE\_KEY **MODULE\_TASK\_QUEUE\_KEY: task:task:queue = 'task:task:queue' ### [**](#MODULE_TASK_QUEUE_OPTIONS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L36)constMODULE\_TASK\_QUEUE\_OPTIONS **MODULE\_TASK\_QUEUE\_OPTIONS: task:task:queue:options = 'task:task:queue:options' ### [**](#MODULE_TASK_TASK_LOCAL_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L33)constMODULE\_TASK\_TASK\_LOCAL\_KEY **MODULE\_TASK\_TASK\_LOCAL\_KEY: task:task:task\_local = 'task:task:task\_local' ### [**](#MODULE_TASK_TASK_LOCAL_OPTIONS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L34)constMODULE\_TASK\_TASK\_LOCAL\_OPTIONS **MODULE\_TASK\_TASK\_LOCAL\_OPTIONS: task:task:task\_local:options = 'task:task:task\_local:options' ### [**](#MS_CONSUMER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L48)constMS\_CONSUMER\_KEY **MS\_CONSUMER\_KEY: ms:consumer = 'ms:consumer' ### [**](#MS_DUBBO_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L54)constMS\_DUBBO\_METHOD\_KEY **MS\_DUBBO\_METHOD\_KEY: ms:dubbo:method = 'ms:dubbo:method' ### [**](#MS_GRPC_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L53)constMS\_GRPC\_METHOD\_KEY **MS\_GRPC\_METHOD\_KEY: ms:grpc:method = 'ms:grpc:method' ### [**](#MS_HSF_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L55)constMS\_HSF\_METHOD\_KEY **MS\_HSF\_METHOD\_KEY: ms:hsf:method = 'ms:hsf:method' ### [**](#MS_PRODUCER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L49)constMS\_PRODUCER\_KEY **MS\_PRODUCER\_KEY: ms:producer = 'ms:producer' ### [**](#MS_PROVIDER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L50)constMS\_PROVIDER\_KEY **MS\_PROVIDER\_KEY: ms:provider = 'ms:provider' ### [**](#NAMED_TAG)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L69)constNAMED\_TAG **NAMED\_TAG: named = 'named' ### [**](#OBJ_DEF_CLS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L92)constOBJ\_DEF\_CLS **OBJ\_DEF\_CLS: injection:object\_definition\_class = 'injection:object\_definition\_class' ### [**](#PIPELINE_IDENTIFIER)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L95)constPIPELINE\_IDENTIFIER **PIPELINE\_IDENTIFIER: \_\_pipeline\_identifier\_\_ = '\_\_pipeline\_identifier\_\_' ### [**](#PLUGIN_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L59)constPLUGIN\_KEY **PLUGIN\_KEY: plugin = 'plugin' ### [**](#PRELOAD_MODULE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L30)constPRELOAD\_MODULE\_KEY **PRELOAD\_MODULE\_KEY: INJECTION\_PRELOAD\_MODULE\_KEY = 'INJECTION\_PRELOAD\_MODULE\_KEY' ### [**](#PRIVATE_META_DATA_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L100)constPRIVATE\_META\_DATA\_KEY **PRIVATE\_META\_DATA\_KEY: \_\_midway\_private\_meta\_data\_\_ = '\_\_midway\_private\_meta\_data\_\_' ### [**](#PathFileUtil)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/pathFileUtil.ts#L28)constPathFileUtil **PathFileUtil: { getFileContentSync: (filePath: any, encoding? : BufferEncoding) => any; isPath: (p: any) => boolean; isPathEqual: (one: string, two: string) => boolean } = ... ### [**](#PathToRegexpUtil)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/pathToRegexp.ts#L621)constPathToRegexpUtil **PathToRegexpUtil: { compile: \

(str: string, options? : ParseOptions & TokensToFunctionOptions) => PathFunction\

; match: \

(str: Path, options? : ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions) => MatchFunction\

; parse: (str: string, options? : ParseOptions) => Token\[]; toRegexp: (path: Path, keys? : Key\[], options? : TokensToRegexpOptions & ParseOptions) => RegExp } = ... ### [**](#REQUEST_CTX_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L45)constREQUEST\_CTX\_KEY **REQUEST\_CTX\_KEY: ctx = 'ctx' ### [**](#REQUEST_CTX_LOGGER_CACHE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L49)constREQUEST\_CTX\_LOGGER\_CACHE\_KEY **REQUEST\_CTX\_LOGGER\_CACHE\_KEY: \_midway\_ctx\_logger\_cache = '\_midway\_ctx\_logger\_cache' ### [**](#REQUEST_OBJ_CTX_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L46)constREQUEST\_OBJ\_CTX\_KEY **REQUEST\_OBJ\_CTX\_KEY: \_req\_ctx = '\_req\_ctx' ### [**](#RPC_DUBBO_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L45)constRPC\_DUBBO\_KEY **RPC\_DUBBO\_KEY: rpc:dubbo = 'rpc:dubbo' ### [**](#RPC_GRPC_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L44)constRPC\_GRPC\_KEY **RPC\_GRPC\_KEY: rpc:grpc = 'rpc:grpc' ### [**](#RequestMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L44)constRequestMethod **RequestMethod: { ALL: string; DELETE: string; GET: string; HEAD: string; OPTIONS: string; PATCH: string; POST: string; PUT: string } = ... ### [**](#SCHEDULE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L5)constSCHEDULE\_KEY **SCHEDULE\_KEY: common:schedule = 'common:schedule' ### [**](#SERVERLESS_FUNC_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L17)constSERVERLESS\_FUNC\_KEY **SERVERLESS\_FUNC\_KEY: faas:serverless:function = 'faas:serverless:function' ### [**](#SINGLETON_CONTAINER_CTX)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/constants.ts#L65)constSINGLETON\_CONTAINER\_CTX **SINGLETON\_CONTAINER\_CTX: { \_MAIN\_CTX\_: boolean } = ... ### [**](#TAGGED_CLS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L87)constTAGGED\_CLS **TAGGED\_CLS: injection:tagged\_class = 'injection:tagged\_class' ### [**](#TAGGED_FUN)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L90)constTAGGED\_FUN **TAGGED\_FUN: injection:tagged\_function = 'injection:tagged\_function' ### [**](#Types)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/types.ts#L98)constTypes **Types: { isAsyncFunction: (value: any) => boolean; isClass: (fn: any) => boolean; isFunction: (value: any) => boolean; isGeneratorFunction: (value: any) => value is GeneratorFunction; isMap: (value: any) => value is Map\; isNull: (value: any) => boolean; isNullOrUndefined: (value: any) => boolean; isNumber: (value: any) => value is number; isObject: (value: any) => boolean; isPlainObject: (obj: any) => any; isPromise: (value: any) => value is Promise\; isProxy: (value: any) => boolean; isRegExp: (value: any) => value is RegExp; isSet: (value: any) => value is Set\; isString: (value: any) => value is string; isUndefined: (value: any) => boolean } = ... ### [**](#Utils)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/index.ts#L633)constUtils **Utils: { camelCase: (input: string) => string; generateRandomId: () => string; getParamNames: (func: any) => string\[]; isTypeScriptEnvironment: () => boolean; pascalCase: (input: string) => string; randomUUID: (force? : boolean) => string; safeParse: (text: string, reviver? : (this: any, key: string, value: any) => any) => any; safeStringify: (value: any, replacer? : any, space? : string | number) => string; sleep: (sleepTime? : number) => Promise\; toAsyncFunction: \(method: T) => (...args: Parameters\) => Promise\> } = ... ### [**](#WEB_RESPONSE_CONTENT_TYPE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L27)constWEB\_RESPONSE\_CONTENT\_TYPE **WEB\_RESPONSE\_CONTENT\_TYPE: web:response\_content\_type = 'web:response\_content\_type' ### [**](#WEB_RESPONSE_HEADER)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L26)constWEB\_RESPONSE\_HEADER **WEB\_RESPONSE\_HEADER: web:response\_header = 'web:response\_header' ### [**](#WEB_RESPONSE_HTTP_CODE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L24)constWEB\_RESPONSE\_HTTP\_CODE **WEB\_RESPONSE\_HTTP\_CODE: web:response\_http\_code = 'web:response\_http\_code' ### [**](#WEB_RESPONSE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L23)constWEB\_RESPONSE\_KEY **WEB\_RESPONSE\_KEY: web:response = 'web:response' ### [**](#WEB_RESPONSE_REDIRECT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L25)constWEB\_RESPONSE\_REDIRECT **WEB\_RESPONSE\_REDIRECT: web:response\_redirect = 'web:response\_redirect' ### [**](#WEB_RESPONSE_RENDER)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L28)constWEB\_RESPONSE\_RENDER **WEB\_RESPONSE\_RENDER: web:response\_render = 'web:response\_render' ### [**](#WEB_ROUTER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L21)constWEB\_ROUTER\_KEY **WEB\_ROUTER\_KEY: web:router = 'web:router' ### [**](#WEB_ROUTER_PARAM_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L22)constWEB\_ROUTER\_PARAM\_KEY **WEB\_ROUTER\_PARAM\_KEY: web:router\_param = 'web:router\_param' ### [**](#WS_CONTROLLER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L39)constWS\_CONTROLLER\_KEY **WS\_CONTROLLER\_KEY: ws:controller = 'ws:controller' ### [**](#WS_EVENT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/constant.ts#L40)constWS\_EVENT\_KEY **WS\_EVENT\_KEY: ws:event = 'ws:event' ### [**](#httpError)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L204)consthttpError **httpError: { BadGatewayError: typeof BadGatewayError; BadRequestError: typeof BadRequestError; ConflictError: typeof ConflictError; ForbiddenError: typeof ForbiddenError; GatewayTimeoutError: typeof GatewayTimeoutError; GoneError: typeof GoneError; InternalServerErrorError: typeof InternalServerErrorError; NotAcceptableError: typeof NotAcceptableError; NotFoundError: typeof NotFoundError; NotImplementedError: typeof NotImplementedError; PayloadTooLargeError: typeof PayloadTooLargeError; RequestTimeoutError: typeof RequestTimeoutError; ServiceUnavailableError: typeof ServiceUnavailableError; TooManyRequestsError: typeof TooManyRequestsError; UnauthorizedError: typeof UnauthorizedError; UnprocessableEntityError: typeof UnprocessableEntityError; UnsupportedMediaTypeError: typeof UnsupportedMediaTypeError } = ... --- # abstractAbstractFileDetector \ ### Hierarchy * *AbstractFileDetector* * [CommonJSFileDetector](/api/3.0.0/core/class/CommonJSFileDetector.md) * [CustomModuleDetector](/api/3.0.0/core/class/CustomModuleDetector.md) ### Implements * [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**extraDetectorOptions](#extraDetectorOptions) * [**options](#options) ### Methods * [**run](#run) * [**setExtraDetectorOptions](#setExtraDetectorOptions) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L16)constructor * **new AbstractFileDetector\(options? : T): [AbstractFileDetector](/api/3.0.0/core/class/AbstractFileDetector.md)\ - #### Type parameters * **T** ## Properties[**](#Properties) ### [**](#extraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L15)extraDetectorOptions **extraDetectorOptions: T ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L14)options **options: T ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L21)abstractrun * **run(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): void | Promise\ - Implementation of IFileDetector.run ### [**](#setExtraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L23)setExtraDetectorOptions * **setExtraDetectorOptions(detectorOptions: T): void - Implementation of IFileDetector.setExtraDetectorOptions --- # abstractBaseFramework \ ### Implements * [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L81)constructor * **new BaseFramework\(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [BaseFramework](/api/3.0.0/core/class/BaseFramework.md)\ - #### Type parameters * **APP**: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)\ * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) * **OPT**: [IConfigurationOptions](/api/3.0.0/core/interface/IConfigurationOptions.md) * **ResOrNext** = unknown * **Next** = unknown ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L48)publicapp **app: APP Implementation of IMidwayFramework.app ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L81)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L70)configService **configService: [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) ### [**](#configurationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L49)publicconfigurationOptions **configurationOptions: OPT Implementation of IMidwayFramework.configurationOptions ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L67)environmentService **environmentService: [MidwayEnvironmentService](/api/3.0.0/core/class/MidwayEnvironmentService.md) ### [**](#informationService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L73)informationService **informationService: [MidwayInformationService](/api/3.0.0/core/class/MidwayInformationService.md) ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L64)loggerService **loggerService: [MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md) ### [**](#middlewareService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L76)middlewareService **middlewareService: [MidwayMiddlewareService](/api/3.0.0/core/class/MidwayMiddlewareService.md)\ ### [**](#mockService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L79)mockService **mockService: [MidwayMockService](/api/3.0.0/core/class/MidwayMockService.md) ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L151)publicabstractapplicationInitialize * **applicationInitialize(options: [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)): any ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L358)publicapplyMiddleware * **applyMiddleware\(lastMiddleware? : [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): Promise<[MiddlewareRespond](/api/3.0.0/core.md#MiddlewareRespond)\> - Implementation of IMidwayFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L94)abstractconfigure * **configure(options? : OPT): any - Implementation of IMidwayFramework.configure ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L438)publiccreateLogger * **createLogger(name: string, option? : [MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)): any - Implementation of IMidwayFramework.createLogger ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L193)publicgetAppDir * **getAppDir(): string - Implementation of IMidwayFramework.getAppDir ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L147)publicgetApplication * **getApplication(): APP - Implementation of IMidwayFramework.getApplication ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L135)publicgetApplicationContext * **getApplicationContext(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) - Implementation of IMidwayFramework.getApplicationContext ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L197)publicgetBaseDir * **getBaseDir(): string - Implementation of IMidwayFramework.getBaseDir ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L139)publicgetConfiguration * **getConfiguration(key? : string): any - Implementation of IMidwayFramework.getConfiguration ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L434)publicgetCoreLogger * **getCoreLogger(): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Implementation of IMidwayFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L143)publicgetCurrentEnvironment * **getCurrentEnvironment(): string - Implementation of IMidwayFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L446)publicgetFrameworkName * **getFrameworkName(): string - Implementation of IMidwayFramework.getFrameworkName ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L430)publicgetLogger * **getLogger(name? : string): any - Implementation of IMidwayFramework.getLogger ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L456)publicgetMiddleware * **getMiddleware(): [ContextMiddlewareManager](/api/3.0.0/core/class/ContextMiddlewareManager.md)\ - Implementation of IMidwayFramework.getMiddleware ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L492)publicgetNamespace * **getNamespace(): string - Implementation of IMidwayFramework.getNamespace ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L442)publicgetProjectName * **getProjectName(): string - Implementation of IMidwayFramework.getProjectName ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L84)init * **init(): Promise<[BaseFramework](/api/3.0.0/core/class/BaseFramework.md)\> ### [**](#initialize)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L100)publicinitialize * **initialize(options? : [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)): Promise\ - Implementation of IMidwayFramework.initialize ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L96)isEnable * **isEnable(): boolean - Implementation of IMidwayFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L153)publicabstractrun * **run(): Promise\ - Implementation of IMidwayFramework.run ### [**](#runGuard)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L468)publicrunGuard * **runGuard(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Implementation of IMidwayFramework.runGuard ### [**](#setNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L488)publicsetNamespace * **setNamespace(namespace: string): void - Implementation of IMidwayFramework.setNamespace ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L188)publicstop * **stop(): Promise\ - Implementation of IMidwayFramework.stop ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L460)publicuseFilter * **useFilter(filter: [CommonFilterUnion](/api/3.0.0/core.md#CommonFilterUnion)\): void - Implementation of IMidwayFramework.useFilter ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L464)publicuseGuard * **useGuard(guards: [CommonGuardUnion](/api/3.0.0/core.md#CommonGuardUnion)\): void - Implementation of IMidwayFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/baseFramework.ts#L450)publicuseMiddleware * **useMiddleware(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void - Implementation of IMidwayFramework.useMiddleware --- # CommonJSFileDetector CommonJS module loader ### Hierarchy * [AbstractFileDetector](/api/3.0.0/core/class/AbstractFileDetector.md)<{ conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] }> * *CommonJSFileDetector* * [ESModuleFileDetector](/api/3.0.0/core/class/ESModuleFileDetector.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**extraDetectorOptions](#extraDetectorOptions) * [**options](#options) ### Methods * [**getType](#getType) * [**loadAsync](#loadAsync) * [**loadSync](#loadSync) * [**run](#run) * [**setExtraDetectorOptions](#setExtraDetectorOptions) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L16)constructor * **new CommonJSFileDetector(options? : { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] }): [CommonJSFileDetector](/api/3.0.0/core/class/CommonJSFileDetector.md) - Inherited from AbstractFileDetector.constructor ## Properties[**](#Properties) ### [**](#extraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L15)extraDetectorOptions **extraDetectorOptions: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] } Inherited from AbstractFileDetector.extraDetectorOptions ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L14)options **options: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] } Inherited from AbstractFileDetector.options ## Methods[**](#Methods) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L178)getType * **getType(): commonjs | module ### [**](#loadAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L119)loadAsync * **loadAsync(container: any): Promise\ ### [**](#loadSync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L62)loadSync * **loadSync(container: any): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L54)run * **run(container: any): void | Promise\ - Overrides AbstractFileDetector.run ### [**](#setExtraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L23)setExtraDetectorOptions * **setExtraDetectorOptions(detectorOptions: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] }): void - Inherited from AbstractFileDetector.setExtraDetectorOptions --- # ContextMiddlewareManager \ ### Hierarchy * Array<[CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\> * *ContextMiddlewareManager* ### Implements * [IMiddlewareManager](/api/3.0.0/core/interface/IMiddlewareManager.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**findAndInsertAfter](#findAndInsertAfter) * [**findAndInsertBefore](#findAndInsertBefore) * [**findAndInsertFirst](#findAndInsertFirst) * [**findAndInsertLast](#findAndInsertLast) * [**findItem](#findItem) * [**findItemIndex](#findItemIndex) * [**getMiddlewareName](#getMiddlewareName) * [**getNames](#getNames) * [**insertAfter](#insertAfter) * [**insertBefore](#insertBefore) * [**insertFirst](#insertFirst) * [**insertLast](#insertLast) * [**push](#push) * [**remove](#remove) * [**unshift](#unshift) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1514)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1515)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1516)externalconstructor * **new ContextMiddlewareManager\(arrayLength: number): [ContextMiddlewareManager](/api/3.0.0/core/class/ContextMiddlewareManager.md)\ * **new ContextMiddlewareManager\(...items: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\\[]): [ContextMiddlewareManager](/api/3.0.0/core/class/ContextMiddlewareManager.md)\ - Inherited from Array\>.constructor #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) * **R** * **N** ## Methods[**](#Methods) ### [**](#findAndInsertAfter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L81)publicfindAndInsertAfter * **findAndInsertAfter(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\, afterMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertAfter move a middleware after another middleware ### [**](#findAndInsertBefore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L107)publicfindAndInsertBefore * **findAndInsertBefore(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\, beforeMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertBefore move a middleware before another middleware ### [**](#findAndInsertFirst)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L132)publicfindAndInsertFirst * **findAndInsertFirst(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertFirst find middleware and move to first ### [**](#findAndInsertLast)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L145)publicfindAndInsertLast * **findAndInsertLast(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertLast find middleware and move to last ### [**](#findItem)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L172)publicfindItem * **findItem(middlewareOrName: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\ - Implementation of IMiddlewareManager.findItem ### [**](#findItemIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L158)publicfindItemIndex * **findItemIndex(middlewareOrName: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): number - Implementation of IMiddlewareManager.findItemIndex find a middleware and return index ### [**](#getMiddlewareName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L192)publicgetMiddlewareName * **getMiddlewareName(middleware: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): string - Implementation of IMiddlewareManager.getMiddlewareName get name from middleware ### [**](#getNames)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L249)publicgetNames * **getNames(): string\[] - Implementation of IMiddlewareManager.getNames get middleware name list ### [**](#insertAfter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L62)publicinsertAfter * **insertAfter(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\, idxOrAfterMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.insertAfter insert a middleware or middleware array to after another middleware ### [**](#insertBefore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L43)publicinsertBefore * **insertBefore(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\, idxOrBeforeMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.insertBefore insert a middleware or middleware array to after another middleware ### [**](#insertFirst)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L18)publicinsertFirst * **insertFirst(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void - Implementation of IMiddlewareManager.insertFirst insert a middleware or middleware array to first ### [**](#insertLast)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L30)publicinsertLast * **insertLast(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void - Implementation of IMiddlewareManager.insertLast insert a middleware or middleware array to last ### [**](#push)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L228)publicpush * **push(...items: any\[]): number - Implementation of IMiddlewareManager.push Overrides Array.push ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L210)publicremove * **remove(middlewareOrNameOrIdx: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\ - Implementation of IMiddlewareManager.remove remove a middleware ### [**](#unshift)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/middlewareManager.ts#L237)publicunshift * **unshift(...items: any\[]): number - Implementation of IMiddlewareManager.unshift Overrides Array.unshift --- # CustomModuleDetector ### Hierarchy * [AbstractFileDetector](/api/3.0.0/core/class/AbstractFileDetector.md)<{ modules? : any\[]; namespace? : string }> * *CustomModuleDetector* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**extraDetectorOptions](#extraDetectorOptions) * [**options](#options) ### Methods * [**run](#run) * [**setExtraDetectorOptions](#setExtraDetectorOptions) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L16)constructor * **new CustomModuleDetector(options? : { modules? : any\[]; namespace? : string }): [CustomModuleDetector](/api/3.0.0/core/class/CustomModuleDetector.md) - Inherited from AbstractFileDetector.constructor ## Properties[**](#Properties) ### [**](#extraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L15)extraDetectorOptions **extraDetectorOptions: { modules? : any\[]; namespace? : string } Inherited from AbstractFileDetector.extraDetectorOptions ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L14)options **options: { modules? : any\[]; namespace? : string } Inherited from AbstractFileDetector.options ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L196)run * **run(container: any): Promise\ - Overrides AbstractFileDetector.run ### [**](#setExtraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L23)setExtraDetectorOptions * **setExtraDetectorOptions(detectorOptions: { modules? : any\[]; namespace? : string }): void - Inherited from AbstractFileDetector.setExtraDetectorOptions --- # abstractDataListener \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getData](#getData) * [**initData](#initData) * [**onData](#onData) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataListener\(): [DataListener](/api/3.0.0/core/class/DataListener.md)\ - #### Type parameters * **T** ## Methods[**](#Methods) ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataListener.ts#L19)publicgetData * **getData(): T ### [**](#initData)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataListener.ts#L12)abstractinitData * **initData(): T | Promise\ ### [**](#onData)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataListener.ts#L13)abstractonData * **onData(callback: (data: T) => void): any ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataListener.ts#L24)publicstop * **stop(): Promise\ --- # abstractDataSourceManager \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataSourceManager\(): [DataSourceManager](/api/3.0.0/core/class/DataSourceManager.md)\ - #### Type parameters * **T** * **ConnectionOpts**: Record\ = Record\ ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L137)publiccreateInstance * **createInstance(config: any, clientName: any, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ ### [**](#getAllDataSources)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L124)publicgetAllDataSources * **getAllDataSources(): Map\ ### [**](#getDataSource)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L108)publicgetDataSource * **getDataSource(dataSourceName: string): T - get a data source instance ### [**](#getDataSourceNameByModel)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L180)publicgetDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - get data source name by model or repository ### [**](#getDataSourceNames)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L120)publicgetDataSourceNames * **getDataSourceNames(): string\[] ### [**](#getDataSourcePriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L220)publicgetDataSourcePriority * **getDataSourcePriority(name: string): string ### [**](#getDefaultDataSourceName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L205)publicgetDefaultDataSourceName * **getDefaultDataSourceName(): string ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L184)publicabstractgetName * **getName(): string ### [**](#hasDataSource)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L116)publichasDataSource * **hasDataSource(dataSourceName: string): boolean - check data source has exists ### [**](#isConnected)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L132)publicisConnected * **isConnected(dataSourceName: string): Promise\ - check the data source is connected ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L224)publicisHighPriority * **isHighPriority(name: string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L232)publicisLowPriority * **isLowPriority(name: string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L228)publicisMediumPriority * **isMediumPriority(name: string): boolean ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/dataSourceManager.ts#L195)publicstop * **stop(): Promise\ - Call destroyDataSource() on all data sources --- # DecoratorManager ### Hierarchy * Map * *DecoratorManager* ### Implements * [IModuleStore](/api/3.0.0/core/interface/IModuleStore.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**container](#container) * [**injectClassKeyPrefix](#injectClassKeyPrefix) * [**injectClassMethodKeyPrefix](#injectClassMethodKeyPrefix) * [**injectMethodKeyPrefix](#injectMethodKeyPrefix) ### Methods * [**attachMetadata](#attachMetadata) * [**attachPropertyDataToClass](#attachPropertyDataToClass) * [**bindContainer](#bindContainer) * [**getMetadata](#getMetadata) * [**getPropertyDataFromClass](#getPropertyDataFromClass) * [**listModule](#listModule) * [**listPropertyDataFromClass](#listPropertyDataFromClass) * [**resetModule](#resetModule) * [**saveMetadata](#saveMetadata) * [**saveModule](#saveModule) * [**savePropertyDataToClass](#savePropertyDataToClass) * [**attachMetadata](#attachMetadata) * [**getDecoratorClassKey](#getDecoratorClassKey) * [**getDecoratorClsExtendedKey](#getDecoratorClsExtendedKey) * [**getDecoratorClsMethodKey](#getDecoratorClsMethodKey) * [**getDecoratorClsMethodPrefix](#getDecoratorClsMethodPrefix) * [**getDecoratorMethod](#getDecoratorMethod) * [**getDecoratorMethodKey](#getDecoratorMethodKey) * [**getMetadata](#getMetadata) * [**removeDecoratorClassKeySuffix](#removeDecoratorClassKeySuffix) * [**saveMetadata](#saveMetadata) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L49)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)externalconstructor * **new DecoratorManager(): [DecoratorManager](/api/3.0.0/core/class/DecoratorManager.md) * **new DecoratorManager(): [DecoratorManager](/api/3.0.0/core/class/DecoratorManager.md) - Inherited from Map.constructor ## Properties[**](#Properties) ### [**](#container)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L49)container **container: [IModuleStore](/api/3.0.0/core/interface/IModuleStore.md) ### [**](#injectClassKeyPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L38)injectClassKeyPrefix **injectClassKeyPrefix: string = INJECT\_CLASS\_KEY\_PREFIX the key for meta data store in class ### [**](#injectClassMethodKeyPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L42)injectClassMethodKeyPrefix **injectClassMethodKeyPrefix: string = 'INJECTION\_CLASS\_METHOD\_META\_DATA' the key for method meta data store in class ### [**](#injectMethodKeyPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L47)injectMethodKeyPrefix **injectMethodKeyPrefix: string = 'INJECTION\_METHOD\_META\_DATA' the key for method meta data store in method ## Methods[**](#Methods) ### [**](#attachMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L246)attachMetadata * **attachMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName? : string, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/core.md#GroupModeType)): void - attach data to class or property ### [**](#attachPropertyDataToClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L342)attachPropertyDataToClass * **attachPropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any, groupBy? : string): void - attach property data to class ### [**](#bindContainer)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L72)bindContainer * **bindContainer(container: [IModuleStore](/api/3.0.0/core/interface/IModuleStore.md)): void ### [**](#getMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L286)getMetadata * **getMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any, propertyName? : any): any - get single data from class or property ### [**](#getPropertyDataFromClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L368)getPropertyDataFromClass * **getPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any, propertyName: any): any - get property data from class ### [**](#listModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L61)listModule * **listModule(key: any): any - Implementation of IModuleStore.listModule ### [**](#listPropertyDataFromClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L389)listPropertyDataFromClass * **listPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any\[] - list property data from class ### [**](#resetModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L68)resetModule * **resetModule(key: any): void ### [**](#saveMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L210)saveMetadata * **saveMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName? : any): void - save meta data to class or property ### [**](#saveModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L51)saveModule * **saveModule(key: any, module: any): any - Implementation of IModuleStore.saveModule ### [**](#savePropertyDataToClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L316)savePropertyDataToClass * **savePropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void - save property data to class ### [**](#attachMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L141)staticattachMetadata * **attachMetadata(metaKey: string, target: any, dataKey: string, data: any, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/core.md#GroupModeType)): void ### [**](#getDecoratorClassKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L77)staticgetDecoratorClassKey * **getDecoratorClassKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getDecoratorClsExtendedKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L89)staticgetDecoratorClsExtendedKey * **getDecoratorClsExtendedKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getDecoratorClsMethodKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L97)staticgetDecoratorClsMethodKey * **getDecoratorClsMethodKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), methodKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getDecoratorClsMethodPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L93)staticgetDecoratorClsMethodPrefix * **getDecoratorClsMethodPrefix(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getDecoratorMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L108)staticgetDecoratorMethod * **getDecoratorMethod(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), methodKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getDecoratorMethodKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L85)staticgetDecoratorMethodKey * **getDecoratorMethodKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#getMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L184)staticgetMetadata * **getMetadata(metaKey: string, target: any, dataKey? : string): any ### [**](#removeDecoratorClassKeySuffix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L81)staticremoveDecoratorClassKeySuffix * **removeDecoratorClassKeySuffix(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#saveMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L119)staticsaveMetadata * **saveMetadata(metaKey: string, target: any, dataKey: string, data: any): void --- # DefaultConsoleLoggerFactory ### Implements * [LoggerFactory](/api/3.0.0/core/class/LoggerFactory.md)<[ILogger](/api/3.0.0/core/interface/ILogger.md), any> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**createContextLogger](#createContextLogger) * [**createLogger](#createLogger) * [**getClientKeys](#getClientKeys) * [**getClients](#getClients) * [**getDefaultMidwayLoggerConfig](#getDefaultMidwayLoggerConfig) * [**getLogger](#getLogger) * [**removeLogger](#removeLogger) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DefaultConsoleLoggerFactory(): [DefaultConsoleLoggerFactory](/api/3.0.0/core/class/DefaultConsoleLoggerFactory.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L34)close * **close(loggerName? : string): void - Implementation of LoggerFactory.close ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L51)createContextLogger * **createContextLogger(ctx: any, appLogger: [ILogger](/api/3.0.0/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Implementation of LoggerFactory.createContextLogger ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L27)createLogger * **createLogger(name: string, options: any): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Implementation of LoggerFactory.createLogger ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L59)publicgetClientKeys * **getClientKeys(): string\[] ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L55)publicgetClients * **getClients(): Map\ ### [**](#getDefaultMidwayLoggerConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L37)getDefaultMidwayLoggerConfig * **getDefaultMidwayLoggerConfig(): { midwayLogger: { clients? : {}; default? : any } } - Implementation of LoggerFactory.getDefaultMidwayLoggerConfig ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L31)getLogger * **getLogger(loggerName: string): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Implementation of LoggerFactory.getLogger ### [**](#removeLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L35)removeLogger * **removeLogger(loggerName: string): void - Implementation of LoggerFactory.removeLogger --- # ESModuleFileDetector ES module loader ### Hierarchy * [CommonJSFileDetector](/api/3.0.0/core/class/CommonJSFileDetector.md) * *ESModuleFileDetector* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**extraDetectorOptions](#extraDetectorOptions) * [**options](#options) ### Methods * [**getType](#getType) * [**loadAsync](#loadAsync) * [**loadSync](#loadSync) * [**run](#run) * [**setExtraDetectorOptions](#setExtraDetectorOptions) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L16)constructor * **new ESModuleFileDetector(options? : { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] }): [ESModuleFileDetector](/api/3.0.0/core/class/ESModuleFileDetector.md) - Inherited from CommonJSFileDetector.constructor ## Properties[**](#Properties) ### [**](#extraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L15)extraDetectorOptions **extraDetectorOptions: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] } Inherited from CommonJSFileDetector.extraDetectorOptions ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L14)options **options: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] } Inherited from CommonJSFileDetector.options ## Methods[**](#Methods) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L187)getType * **getType(): commonjs | module - Overrides CommonJSFileDetector.getType ### [**](#loadAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L119)loadAsync * **loadAsync(container: any): Promise\ - Inherited from CommonJSFileDetector.loadAsync ### [**](#loadSync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L62)loadSync * **loadSync(container: any): void - Inherited from CommonJSFileDetector.loadSync ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L54)run * **run(container: any): void | Promise\ - Inherited from CommonJSFileDetector.run ### [**](#setExtraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/fileDetector.ts#L23)setExtraDetectorOptions * **setExtraDetectorOptions(detectorOptions: { conflictCheck? : boolean; ignore? : string | string\[]; loadDir? : string | string\[]; namespace? : string; pattern? : string | string\[] }): void - Inherited from CommonJSFileDetector.setExtraDetectorOptions --- # FilterManager \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) * [**runErrorFilter](#runErrorFilter) * [**runResultFilter](#runResultFilter) * [**useFilter](#useFilter) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new FilterManager\(): [FilterManager](/api/3.0.0/core/class/FilterManager.md)\ - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) = [Context](/api/3.0.0/core/interface/Context.md) * **R** = any * **N** = any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/filterManager.ts#L49)publicinit * **init(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): Promise\ ### [**](#runErrorFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/filterManager.ts#L92)publicrunErrorFilter * **runErrorFilter(err: Error, ctx: CTX, res? : R, next? : N): Promise<{ error: any; result: any }> ### [**](#runResultFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/filterManager.ts#L139)publicrunResultFilter * **runResultFilter(result: any, ctx: CTX, res? : R, next? : N): Promise<{ error: any; result: any }> ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/filterManager.ts#L35)publicuseFilter * **useFilter(Filters: [CommonFilterUnion](/api/3.0.0/core.md#CommonFilterUnion)\): void --- # abstractFrameworkType ### Hierarchy * *FrameworkType* * [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**name](#name) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new FrameworkType(): [FrameworkType](/api/3.0.0/core/class/FrameworkType.md) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L283)abstractname **name: string --- # FunctionalConfiguration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getConfigurationOptions](#getConfigurationOptions) * [**onConfigLoad](#onConfigLoad) * [**onReady](#onReady) * [**onServerReady](#onServerReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L11)constructor * **new FunctionalConfiguration(options: [InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md)): [FunctionalConfiguration](/api/3.0.0/core/class/FunctionalConfiguration.md) ## Methods[**](#Methods) ### [**](#getConfigurationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L75)getConfigurationOptions * **getConfigurationOptions(): [InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md) ### [**](#onConfigLoad)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L19)onConfigLoad * **onConfigLoad(configLoadHandler: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) | (container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>) => any, app? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): any ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L33)onReady * **onReady(readyHandler: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) | (container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>) => void, app? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): any ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L47)onServerReady * **onServerReady(serverReadyHandler: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) | (container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>) => void, app? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): any ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/functional/configuration.ts#L61)onStop * **onStop(stopHandler: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) | (container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>) => void, app? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): any --- # HttpClient A simple http client ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**defaultOptions](#defaultOptions) ### Methods * [**request](#request) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L140)constructor * **new HttpClient(defaultOptions? : Pick<[HttpClientOptions](/api/3.0.0/core/interface/HttpClientOptions.md)\, headers | method | timeout>): [HttpClient](/api/3.0.0/core/class/HttpClient.md) ## Properties[**](#Properties) ### [**](#defaultOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L141)readonlydefaultOptions **defaultOptions: Pick<[HttpClientOptions](/api/3.0.0/core/interface/HttpClientOptions.md)\, headers | method | timeout> = {} ## Methods[**](#Methods) ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L147)request * **request(url: string, options? : [HttpClientOptions](/api/3.0.0/core/interface/HttpClientOptions.md)\): Promise<[HttpClientResponse](/api/3.0.0/core/interface/HttpClientResponse.md)\> --- # HttpServerResponse \ ### Hierarchy * [ServerResponse](/api/3.0.0/core/class/ServerResponse.md)\ * *HttpServerResponse* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**blob](#blob) * [**fail](#fail) * [**file](#file) * [**header](#header) * [**headers](#headers) * [**html](#html) * [**json](#json) * [**redirect](#redirect) * [**sse](#sse) * [**status](#status) * [**stream](#stream) * [**success](#success) * [**text](#text) * [**BLOB\_TPL](#BLOB_TPL) * [**FILE\_TPL](#FILE_TPL) * [**HTML\_TPL](#HTML_TPL) * [**JSON\_TPL](#JSON_TPL) * [**SSE\_TPL](#SSE_TPL) * [**STREAM\_TPL](#STREAM_TPL) * [**TEXT\_TPL](#TEXT_TPL) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L17)constructor * **new HttpServerResponse\(ctx: CTX): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ - Overrides ServerResponse.constructor #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ## Methods[**](#Methods) ### [**](#blob)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L100)blob * **blob(data: Buffer\, mimeType? : string): any - Overrides ServerResponse.blob ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L74)fail * **fail(): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ - Inherited from ServerResponse.fail ### [**](#file)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L87)file * **file(filePath: string, mimeType? : string): any ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L53)header * **header(key: string, value: string): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L58)headers * **headers(headers: Record\): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ ### [**](#html)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L109)html * **html(data: string): any ### [**](#json)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L69)json * **json(data: Record\): any - Overrides ServerResponse.json ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L118)redirect * **redirect(url: string, status? : number): any ### [**](#sse)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L129)sse * **sse(options? : [ServerSendEventStreamOptions](/api/3.0.0/core/interface/ServerSendEventStreamOptions.md)\): ServerSendEventStream<[Context](/api/3.0.0/core/interface/Context.md)> ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L48)status * **status(code: number): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ ### [**](#stream)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L136)stream * **stream(options? : [ServerStreamOptions](/api/3.0.0/core/interface/ServerStreamOptions.md)\): HttpStreamResponse<[Context](/api/3.0.0/core/interface/Context.md)> ### [**](#success)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L69)success * **success(): [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md)\ - Inherited from ServerResponse.success ### [**](#text)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L78)text * **text(data: string): any - Overrides ServerResponse.text ### [**](#BLOB_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L37)staticBLOB\_TPL * **BLOB\_TPL\(data: Buffer\, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.BLOB\_TPL #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#FILE_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L21)staticFILE\_TPL * **FILE\_TPL\(data: Readable, isSuccess: boolean, ctx: CTX): Readable - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#HTML_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L40)staticHTML\_TPL * **HTML\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#JSON_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L19)staticJSON\_TPL * **JSON\_TPL\(data: Record\, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.JSON\_TPL #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#SSE_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L29)staticSSE\_TPL * **SSE\_TPL\(data: [ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md), ctx: CTX): [ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md) - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#STREAM_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/http.ts#L36)staticSTREAM\_TPL * **STREAM\_TPL\(data: unknown, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#TEXT_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L11)staticTEXT\_TPL * **TEXT\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.TEXT\_TPL #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) --- # abstractLoggerFactory \ ### Implemented by * [DefaultConsoleLoggerFactory](/api/3.0.0/core/class/DefaultConsoleLoggerFactory.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**createContextLogger](#createContextLogger) * [**createLogger](#createLogger) * [**getDefaultMidwayLoggerConfig](#getDefaultMidwayLoggerConfig) * [**getLogger](#getLogger) * [**removeLogger](#removeLogger) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new LoggerFactory\(): [LoggerFactory](/api/3.0.0/core/class/LoggerFactory.md)\ - #### Type parameters * **Logger**: [ILogger](/api/3.0.0/core/interface/ILogger.md) * **LoggerOptions** ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L6)abstractclose * **close(loggerName? : string): any ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L16)abstractcreateContextLogger * **createContextLogger(ctx: any, appLogger: [ILogger](/api/3.0.0/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L4)abstractcreateLogger * **createLogger(name: string, options: LoggerOptions): Logger ### [**](#getDefaultMidwayLoggerConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L8)abstractgetDefaultMidwayLoggerConfig * **getDefaultMidwayLoggerConfig(appInfo: [MidwayAppInfo](/api/3.0.0/core/interface/MidwayAppInfo.md)): { midwayLogger: { clients? : {}; default? : LoggerOptions } } ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L5)abstractgetLogger * **getLogger(loggerName: string): Logger ### [**](#removeLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/loggerFactory.ts#L7)abstractremoveLogger * **removeLogger(loggerName: string): any --- # MidwayApplicationManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addFramework](#addFramework) * [**getApplication](#getApplication) * [**getApplications](#getApplications) * [**getFramework](#getFramework) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayApplicationManager(): [MidwayApplicationManager](/api/3.0.0/core/class/MidwayApplicationManager.md) ## Methods[**](#Methods) ### [**](#addFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/applicationManager.ts#L22)publicaddFramework * **addFramework(namespace: any, framework: [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\): void ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/applicationManager.ts#L44)publicgetApplication * **getApplication(namespaceOrFrameworkType: string | [FrameworkType](/api/3.0.0/core/class/FrameworkType.md)): [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)> ### [**](#getApplications)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/applicationManager.ts#L62)publicgetApplications * **getApplications(namespaces? : (string | [FrameworkType](/api/3.0.0/core/class/FrameworkType.md))\[]): [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>\[] ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/applicationManager.ts#L32)publicgetFramework * **getFramework(namespaceOrFrameworkType: string | [FrameworkType](/api/3.0.0/core/class/FrameworkType.md)): [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\ --- # MidwayAspectService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**addAspect](#addAspect) * [**interceptPrototypeMethod](#interceptPrototypeMethod) * [**loadAspect](#loadAspect) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/aspectService.ts#L21)constructor * **new MidwayAspectService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayAspectService](/api/3.0.0/core/class/MidwayAspectService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/aspectService.ts#L21)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#addAspect)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/aspectService.ts#L55)publicaddAspect * **addAspect(aspectIns: [IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md), aspectData: [AspectMetadata](/api/3.0.0/core/interface/AspectMetadata.md)): Promise\ ### [**](#interceptPrototypeMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/aspectService.ts#L82)publicinterceptPrototypeMethod * **interceptPrototypeMethod(Clz: new (...args: any\[]) => any, methodName: string, aspectObject: [IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md) | () => [IMethodAspect](/api/3.0.0/core/interface/IMethodAspect.md)): void - intercept class method in prototype ### [**](#loadAspect)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/aspectService.ts#L26)publicloadAspect * **loadAspect(): Promise\ - load aspect method for container --- # MidwayCodeInvokeTimeoutError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayCodeInvokeTimeoutError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L207)constructor * **new MidwayCodeInvokeTimeoutError(methodName: string, timeout: number): [MidwayCodeInvokeTimeoutError](/api/3.0.0/core/class/MidwayCodeInvokeTimeoutError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayCommonError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayCommonError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L31)constructor * **new MidwayCommonError(message: string): [MidwayCommonError](/api/3.0.0/core/class/MidwayCommonError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayConfigMissingError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayConfigMissingError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L85)constructor * **new MidwayConfigMissingError(configKey: string): [MidwayConfigMissingError](/api/3.0.0/core/class/MidwayConfigMissingError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayConfigService ### Implements * [IConfigService](/api/3.0.0/core/interface/IConfigService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**add](#add) * [**addFilter](#addFilter) * [**addObject](#addObject) * [**clearAllConfig](#clearAllConfig) * [**clearConfigMergeOrder](#clearConfigMergeOrder) * [**getAppInfo](#getAppInfo) * [**getConfigMergeOrder](#getConfigMergeOrder) * [**getConfiguration](#getConfiguration) * [**load](#load) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayConfigService(): [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) ## Methods[**](#Methods) ### [**](#add)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L57)publicadd * **add(configFilePaths: any\[]): void - Implementation of IConfigService.add ### [**](#addFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L248)publicaddFilter * **addFilter(filter: (config: Record\) => Record\): void - add a config filter ### [**](#addObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L92)publicaddObject * **addObject(obj: Record\, reverse? : boolean): void - Implementation of IConfigService.addObject ### [**](#clearAllConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L236)publicclearAllConfig * **clearAllConfig(): void - Implementation of IConfigService.clearAllConfig ### [**](#clearConfigMergeOrder)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L240)publicclearConfigMergeOrder * **clearConfigMergeOrder(): void ### [**](#getAppInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L267)publicgetAppInfo * **getAppInfo(): [MidwayAppInfo](/api/3.0.0/core/interface/MidwayAppInfo.md) ### [**](#getConfigMergeOrder)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L209)publicgetConfigMergeOrder * **getConfigMergeOrder(): ConfigMergeInfo\[] ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L202)publicgetConfiguration * **getConfiguration(configKey? : string): any - Implementation of IConfigService.getConfiguration ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/configService.ts#L133)publicload * **load(): void - Implementation of IConfigService.load --- # MidwayContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * *MidwayContainer* * [MidwayRequestContainer](/api/3.0.0/core/class/MidwayRequestContainer.md) ### Implements * [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) * [IModuleStore](/api/3.0.0/core/interface/IModuleStore.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**parent](#parent) ### Accessors * [**identifierMapping](#identifierMapping) * [**managedResolverFactory](#managedResolverFactory) * [**namespaceSet](#namespaceSet) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**registry](#registry) ### Methods * [**bind](#bind) * [**bindClass](#bindClass) * [**createChild](#createChild) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getInstanceScope](#getInstanceScope) * [**getNamespaceList](#getNamespaceList) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**listModule](#listModule) * [**load](#load) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**ready](#ready) * [**registerObject](#registerObject) * [**saveModule](#saveModule) * [**setAttr](#setAttr) * [**setFileDetector](#setFileDetector) * [**stop](#stop) * [**transformModule](#transformModule) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L249)constructor * **new MidwayContainer(parent? : [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) ## Properties[**](#Properties) ### [**](#parent)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L242)publicparent **parent: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) = null Implementation of IMidwayContainer.parent ## Accessors[**](#Accessors) ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L285)identifierMapping * **get identifierMapping(): [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) - Implementation of IMidwayContainer.identifierMapping ### [**](#managedResolverFactory)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L278)managedResolverFactory * **get managedResolverFactory(): ManagedResolverFactory ### [**](#namespaceSet)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L292)namespaceSet * **get namespaceSet(): Set\ ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L260)objectCreateEventTarget * **get objectCreateEventTarget(): EventEmitter\ - Implementation of IMidwayContainer.objectCreateEventTarget ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L267)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L274)registry * **get registry(): [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md) * **set registry(registry: [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md)): void - Implementation of IMidwayContainer.registry - Implementation of IMidwayContainer.registry ## Methods[**](#Methods) ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L353)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L354)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L359)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void * **bind\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void - Implementation of IMidwayContainer.bind #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L340)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void - Implementation of IMidwayContainer.bindClass ### [**](#createChild)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L522)createChild * **createChild(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) - Implementation of IMidwayContainer.createChild ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L554)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L559)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L564)get * **get\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T * **get\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T - Implementation of IMidwayContainer.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L586)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L591)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L596)getAsync * **getAsync\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ * **getAsync\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ - Implementation of IMidwayContainer.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L530)publicgetAttr * **getAttr\(key: string): T - Implementation of IMidwayContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L728)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) - Implementation of IMidwayContainer.getInstanceScope Get instance IoC container scope ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L716)getNamespaceList * **getNamespaceList(): string\[] - Implementation of IMidwayContainer.getNamespaceList ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L720)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L712)hasNamespace * **hasNamespace(ns: string): boolean - Implementation of IMidwayContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L724)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayContainer.hasObject ### [**](#listModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L704)listModule * **listModule(key: string): unknown\[] - Implementation of IModuleStore.listModule ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L299)load * **load(module: any): void - Implementation of IMidwayContainer.load ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L634)onBeforeBind * **onBeforeBind(fn: (Clzz: any, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md); replaceCallback: (newDefinition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)) => void }) => void): void - Implementation of IMidwayContainer.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L647)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (Clzz: any, options: { constructorArgs: any\[]; context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayContainer.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L685)onBeforeObjectDestroy * **onBeforeObjectDestroy\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayContainer.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L660)onObjectCreated * **onObjectCreated\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md); replaceCallback: (ins: T) => void }) => void): void - Implementation of IMidwayContainer.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L673)onObjectInit * **onObjectInit\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayContainer.onObjectInit #### Type parameters * **T** ### [**](#ready)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L550)ready * **ready(): void | Promise\ - Implementation of IMidwayContainer.ready ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L630)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): void - Implementation of IMidwayContainer.registerObject proxy registry.registerObject ### [**](#saveModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L697)saveModule * **saveModule(key: any, module: any): void - Implementation of IModuleStore.saveModule ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L526)publicsetAttr * **setAttr(key: string, value: any): void - Implementation of IMidwayContainer.setAttr Set value to app attribute map ### [**](#setFileDetector)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L518)setFileDetector * **setFileDetector(fileDetector: [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md)): void - Implementation of IMidwayContainer.setFileDetector ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L545)stop * **stop(): Promise\ - Implementation of IMidwayContainer.stop ### [**](#transformModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L708)transformModule * **transformModule(moduleMap: Map\>): void - Implementation of IModuleStore.transformModule --- # MidwayDecoratorService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**registerMethodHandler](#registerMethodHandler) * [**registerParameterHandler](#registerParameterHandler) * [**registerParameterPipes](#registerParameterPipes) * [**registerPropertyHandler](#registerPropertyHandler) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L44)constructor * **new MidwayDecoratorService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayDecoratorService](/api/3.0.0/core/class/MidwayDecoratorService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L44)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#registerMethodHandler)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L225)publicregisterMethodHandler * **registerMethodHandler(decoratorKey: string, fn: [MethodHandlerFunction](/api/3.0.0/core.md#MethodHandlerFunction)): void ### [**](#registerParameterHandler)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L233)publicregisterParameterHandler * **registerParameterHandler(decoratorKey: string, fn: [ParameterHandlerFunction](/api/3.0.0/core.md#ParameterHandlerFunction)): void ### [**](#registerParameterPipes)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L241)publicregisterParameterPipes * **registerParameterPipes(decoratorKey: string, pipes: [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): void ### [**](#registerPropertyHandler)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/decoratorService.ts#L220)publicregisterPropertyHandler * **registerPropertyHandler(decoratorKey: string, fn: [HandlerFunction](/api/3.0.0/core.md#HandlerFunction)): void --- # MidwayDefinitionNotFoundError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayDefinitionNotFoundError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**type](#type) ### Methods * [**updateErrorMsg](#updateErrorMsg) * [**isClosePrototypeOf](#isClosePrototypeOf) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L50)constructor * **new MidwayDefinitionNotFoundError(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): [MidwayDefinitionNotFoundError](/api/3.0.0/core/class/MidwayDefinitionNotFoundError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L43)staticreadonlytype **type: typeof type = ... ## Methods[**](#Methods) ### [**](#updateErrorMsg)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L58)updateErrorMsg * **updateErrorMsg(className: string): void ### [**](#isClosePrototypeOf)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L44)staticisClosePrototypeOf * **isClosePrototypeOf(ins: [MidwayDefinitionNotFoundError](/api/3.0.0/core/class/MidwayDefinitionNotFoundError.md)): boolean --- # MidwayDuplicateClassNameError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayDuplicateClassNameError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L162)constructor * **new MidwayDuplicateClassNameError(className: string, existPath: string, existPathOther: string): [MidwayDuplicateClassNameError](/api/3.0.0/core/class/MidwayDuplicateClassNameError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayDuplicateControllerOptionsError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayDuplicateControllerOptionsError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L171)constructor * **new MidwayDuplicateControllerOptionsError(prefix: string, existController: string, existControllerOther: string): [MidwayDuplicateControllerOptionsError](/api/3.0.0/core/class/MidwayDuplicateControllerOptionsError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayDuplicateRouteError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayDuplicateRouteError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L112)constructor * **new MidwayDuplicateRouteError(routerUrl: string, existPos: string, existPosOther: string): [MidwayDuplicateRouteError](/api/3.0.0/core/class/MidwayDuplicateRouteError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayEmptyValueError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayEmptyValueError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L238)constructor * **new MidwayEmptyValueError(msg: string): [MidwayEmptyValueError](/api/3.0.0/core/class/MidwayEmptyValueError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayEnvironmentService ### Implements * [IEnvironmentService](/api/3.0.0/core/interface/IEnvironmentService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getModuleLoadType](#getModuleLoadType) * [**isDevelopmentEnvironment](#isDevelopmentEnvironment) * [**isPkgEnvironment](#isPkgEnvironment) * [**setCurrentEnvironment](#setCurrentEnvironment) * [**setModuleLoadType](#setModuleLoadType) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayEnvironmentService(): [MidwayEnvironmentService](/api/3.0.0/core/class/MidwayEnvironmentService.md) ## Methods[**](#Methods) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L11)publicgetCurrentEnvironment * **getCurrentEnvironment(): string - Implementation of IEnvironmentService.getCurrentEnvironment ### [**](#getModuleLoadType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L30)publicgetModuleLoadType * **getModuleLoadType(): [ModuleLoadType](/api/3.0.0/core.md#ModuleLoadType) - Implementation of IEnvironmentService.getModuleLoadType ### [**](#isDevelopmentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L22)publicisDevelopmentEnvironment * **isDevelopmentEnvironment(): boolean - Implementation of IEnvironmentService.isDevelopmentEnvironment ### [**](#isPkgEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L34)publicisPkgEnvironment * **isPkgEnvironment(): boolean ### [**](#setCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L18)publicsetCurrentEnvironment * **setCurrentEnvironment(environment: string): void ### [**](#setModuleLoadType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/environmentService.ts#L26)publicsetModuleLoadType * **setModuleLoadType(moduleLoadType: [ModuleLoadType](/api/3.0.0/core.md#ModuleLoadType)): void --- # MidwayError ### Hierarchy * Error * *MidwayError* * [MidwayHttpError](/api/3.0.0/core/class/MidwayHttpError.md) * [MidwayCommonError](/api/3.0.0/core/class/MidwayCommonError.md) * [MidwayParameterError](/api/3.0.0/core/class/MidwayParameterError.md) * [MidwayDefinitionNotFoundError](/api/3.0.0/core/class/MidwayDefinitionNotFoundError.md) * [MidwayFeatureNoLongerSupportedError](/api/3.0.0/core/class/MidwayFeatureNoLongerSupportedError.md) * [MidwayFeatureNotImplementedError](/api/3.0.0/core/class/MidwayFeatureNotImplementedError.md) * [MidwayConfigMissingError](/api/3.0.0/core/class/MidwayConfigMissingError.md) * [MidwayInvalidConfigError](/api/3.0.0/core/class/MidwayInvalidConfigError.md) * [MidwayResolverMissingError](/api/3.0.0/core/class/MidwayResolverMissingError.md) * [MidwayDuplicateRouteError](/api/3.0.0/core/class/MidwayDuplicateRouteError.md) * [MidwayUseWrongMethodError](/api/3.0.0/core/class/MidwayUseWrongMethodError.md) * [MidwaySingletonInjectRequestError](/api/3.0.0/core/class/MidwaySingletonInjectRequestError.md) * [MidwayMissingImportComponentError](/api/3.0.0/core/class/MidwayMissingImportComponentError.md) * [MidwayUtilHttpClientTimeoutError](/api/3.0.0/core/class/MidwayUtilHttpClientTimeoutError.md) * [MidwayInconsistentVersionError](/api/3.0.0/core/class/MidwayInconsistentVersionError.md) * [MidwayDuplicateClassNameError](/api/3.0.0/core/class/MidwayDuplicateClassNameError.md) * [MidwayDuplicateControllerOptionsError](/api/3.0.0/core/class/MidwayDuplicateControllerOptionsError.md) * [MidwayRetryExceededMaxTimesError](/api/3.0.0/core/class/MidwayRetryExceededMaxTimesError.md) * [MidwayInvokeForbiddenError](/api/3.0.0/core/class/MidwayInvokeForbiddenError.md) * [MidwayCodeInvokeTimeoutError](/api/3.0.0/core/class/MidwayCodeInvokeTimeoutError.md) * [MidwayMainFrameworkMissingError](/api/3.0.0/core/class/MidwayMainFrameworkMissingError.md) * [MidwayInvalidConfigPropertyError](/api/3.0.0/core/class/MidwayInvalidConfigPropertyError.md) * [MidwayEmptyValueError](/api/3.0.0/core/class/MidwayEmptyValueError.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L53)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L54)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L55)constructor * **new MidwayError(message: string, options? : ErrorOption): [MidwayError](/api/3.0.0/core/class/MidwayError.md) * **new MidwayError(message: string, code: string, options? : ErrorOption): [MidwayError](/api/3.0.0/core/class/MidwayError.md) - Overrides Error.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number --- # MidwayFeatureNoLongerSupportedError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayFeatureNoLongerSupportedError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L67)constructor * **new MidwayFeatureNoLongerSupportedError(message? : string): [MidwayFeatureNoLongerSupportedError](/api/3.0.0/core/class/MidwayFeatureNoLongerSupportedError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayFeatureNotImplementedError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayFeatureNotImplementedError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L76)constructor * **new MidwayFeatureNotImplementedError(message? : string): [MidwayFeatureNotImplementedError](/api/3.0.0/core/class/MidwayFeatureNotImplementedError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayFrameworkService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**applicationManager](#applicationManager) * [**aspectService](#aspectService) * [**configService](#configService) * [**decoratorService](#decoratorService) * [**globalOptions](#globalOptions) * [**loggerService](#loggerService) ### Methods * [**getFramework](#getFramework) * [**getMainApp](#getMainApp) * [**getMainFramework](#getMainFramework) * [**runFramework](#runFramework) * [**stopFramework](#stopFramework) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L56)constructor * **new MidwayFrameworkService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), globalOptions: any): [MidwayFrameworkService](/api/3.0.0/core/class/MidwayFrameworkService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L57)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L54)applicationManager **applicationManager: [MidwayApplicationManager](/api/3.0.0/core/class/MidwayApplicationManager.md) ### [**](#aspectService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L48)aspectService **aspectService: [MidwayAspectService](/api/3.0.0/core/class/MidwayAspectService.md) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L42)configService **configService: [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L51)decoratorService **decoratorService: [MidwayDecoratorService](/api/3.0.0/core/class/MidwayDecoratorService.md) ### [**](#globalOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L58)readonlyglobalOptions **globalOptions: any ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L45)loggerService **loggerService: [MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md) ## Methods[**](#Methods) ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L244)publicgetFramework * **getFramework(namespaceOrFrameworkType: string | [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md)): [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\ ### [**](#getMainApp)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L236)publicgetMainApp * **getMainApp(): any ### [**](#getMainFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L240)publicgetMainFramework * **getMainFramework(): [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\ ### [**](#runFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L248)publicrunFramework * **runFramework(): Promise\ ### [**](#stopFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/frameworkService.ts#L276)publicstopFramework * **stopFramework(): Promise\ --- # MidwayFrameworkType ### Hierarchy * [FrameworkType](/api/3.0.0/core/class/FrameworkType.md) * *MidwayFrameworkType* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**name](#name) * [**CUSTOM](#CUSTOM) * [**EMPTY](#EMPTY) * [**FAAS](#FAAS) * [**LIGHT](#LIGHT) * [**MS\_GRPC](#MS_GRPC) * [**MS\_KAFKA](#MS_KAFKA) * [**MS\_RABBITMQ](#MS_RABBITMQ) * [**SERVERLESS\_APP](#SERVERLESS_APP) * [**TASK](#TASK) * [**WEB](#WEB) * [**WEB\_EXPRESS](#WEB_EXPRESS) * [**WEB\_KOA](#WEB_KOA) * [**WS](#WS) * [**WS\_IO](#WS_IO) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L301)constructor * **new MidwayFrameworkType(name: string): [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) - Overrides FrameworkType.constructor ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L301)publicname **name: string Inherited from FrameworkType.name ### [**](#CUSTOM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L297)staticCUSTOM **CUSTOM: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#EMPTY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L298)staticEMPTY **EMPTY: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#FAAS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L290)staticFAAS **FAAS: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#LIGHT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L299)staticLIGHT **LIGHT: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#MS_GRPC)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L291)staticMS\_GRPC **MS\_GRPC: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#MS_KAFKA)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L293)staticMS\_KAFKA **MS\_KAFKA: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#MS_RABBITMQ)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L292)staticMS\_RABBITMQ **MS\_RABBITMQ: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#SERVERLESS_APP)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L296)staticSERVERLESS\_APP **SERVERLESS\_APP: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#TASK)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L300)staticTASK **TASK: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#WEB)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L287)staticWEB **WEB: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#WEB_EXPRESS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L289)staticWEB\_EXPRESS **WEB\_EXPRESS: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#WEB_KOA)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L288)staticWEB\_KOA **WEB\_KOA: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#WS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L295)staticWS **WS: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... ### [**](#WS_IO)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L294)staticWS\_IO **WS\_IO: [MidwayFrameworkType](/api/3.0.0/core/class/MidwayFrameworkType.md) = ... --- # MidwayHealthService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getStatus](#getStatus) * [**init](#init) * [**setCheckTimeout](#setCheckTimeout) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayHealthService(): [MidwayHealthService](/api/3.0.0/core/class/MidwayHealthService.md) ## Methods[**](#Methods) ### [**](#getStatus)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/healthService.ts#L60)getStatus * **getStatus(): Promise<[HealthResults](/api/3.0.0/core/interface/HealthResults.md)> ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/healthService.ts#L32)init * **init(lifeCycleInstanceList: { instance? : any; namespace: string; target: any }\[]): Promise\ ### [**](#setCheckTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/healthService.ts#L105)setCheckTimeout * **setCheckTimeout(timeout: number): void --- # MidwayHttpError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayHttpError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L72)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L73)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L79)constructor * **new MidwayHttpError(resOrMessage: [ResOrMessage](/api/3.0.0/core.md#ResOrMessage), status: number): [MidwayHttpError](/api/3.0.0/core/class/MidwayHttpError.md) * **new MidwayHttpError(resOrMessage: [ResOrMessage](/api/3.0.0/core.md#ResOrMessage), status: number, code: string, options? : ErrorOption): [MidwayHttpError](/api/3.0.0/core/class/MidwayHttpError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L70)status **status: number --- # MidwayInconsistentVersionError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayInconsistentVersionError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L154)constructor * **new MidwayInconsistentVersionError(): [MidwayInconsistentVersionError](/api/3.0.0/core/class/MidwayInconsistentVersionError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInformationService ### Implements * [IInformationService](/api/3.0.0/core/interface/IInformationService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getAppDir](#getAppDir) * [**getBaseDir](#getBaseDir) * [**getHome](#getHome) * [**getPkg](#getPkg) * [**getProjectName](#getProjectName) * [**getRoot](#getRoot) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayInformationService(): [MidwayInformationService](/api/3.0.0/core/class/MidwayInformationService.md) ## Methods[**](#Methods) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L42)getAppDir * **getAppDir(): string - Implementation of IInformationService.getAppDir ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L46)getBaseDir * **getBaseDir(): string - Implementation of IInformationService.getBaseDir ### [**](#getHome)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L50)getHome * **getHome(): string - Implementation of IInformationService.getHome ### [**](#getPkg)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L54)getPkg * **getPkg(): any - Implementation of IInformationService.getPkg ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L58)getProjectName * **getProjectName(): string - Implementation of IInformationService.getProjectName ### [**](#getRoot)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/informationService.ts#L62)getRoot * **getRoot(): string - Implementation of IInformationService.getRoot --- # MidwayInvalidConfigError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayInvalidConfigError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L94)constructor * **new MidwayInvalidConfigError(message? : string): [MidwayInvalidConfigError](/api/3.0.0/core/class/MidwayInvalidConfigError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInvalidConfigPropertyError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayInvalidConfigPropertyError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L225)constructor * **new MidwayInvalidConfigPropertyError(propertyName: string, allowTypes? : string\[]): [MidwayInvalidConfigPropertyError](/api/3.0.0/core/class/MidwayInvalidConfigPropertyError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInvokeForbiddenError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayInvokeForbiddenError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L196)constructor * **new MidwayInvokeForbiddenError(methodName: string, module? : any): [MidwayInvokeForbiddenError](/api/3.0.0/core/class/MidwayInvokeForbiddenError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayLifeCycleService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**getLifecycleInstanceList](#getLifecycleInstanceList) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/lifeCycleService.ts#L41)constructor * **new MidwayLifeCycleService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayLifeCycleService](/api/3.0.0/core/class/MidwayLifeCycleService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/lifeCycleService.ts#L41)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#getLifecycleInstanceList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/lifeCycleService.ts#L216)publicgetLifecycleInstanceList * **getLifecycleInstanceList(): { instance? : any; namespace: string; target: any }\[] ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/lifeCycleService.ts#L123)publicstop * **stop(): Promise\ --- # MidwayLoggerService 多客户端工厂实现 ### Hierarchy * [ServiceFactory](/api/3.0.0/core/class/ServiceFactory.md)<[ILogger](/api/3.0.0/core/interface/ILogger.md)> * *MidwayLoggerService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**configService](#configService) * [**globalOptions](#globalOptions) ### Methods * [**createContextLogger](#createContextLogger) * [**createInstance](#createInstance) * [**createLogger](#createLogger) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getCurrentLoggerFactory](#getCurrentLoggerFactory) * [**getDefaultClientName](#getDefaultClientName) * [**getLogger](#getLogger) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L29)constructor * **new MidwayLoggerService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), globalOptions? : {}): [MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md) - Overrides ServiceFactory.constructor ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L30)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L21)publicconfigService **configService: [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) ### [**](#globalOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L31)readonlyglobalOptions **globalOptions: {} = {} ## Methods[**](#Methods) ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L113)publiccreateContextLogger * **createContextLogger(ctx: [Context](/api/3.0.0/core/interface/Context.md), appLogger: [ILogger](/api/3.0.0/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L47)publiccreateInstance * **createInstance(config: any, clientName? : any): Promise<[ILogger](/api/3.0.0/core/interface/ILogger.md)> - Inherited from ServiceFactory.createInstance ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L86)publiccreateLogger * **createLogger(name: string, config: [MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)): any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L39)publicget * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L129)publicgetClientKeys * **getClientKeys(): string\[] - Overrides ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L87)publicgetClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L125)publicgetClients * **getClients(): Map\ - Overrides ServiceFactory.getClients ### [**](#getCurrentLoggerFactory)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L109)publicgetCurrentLoggerFactory * **getCurrentLoggerFactory(): [LoggerFactory](/api/3.0.0/core/class/LoggerFactory.md)\ ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L75)publicgetDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L91)publicgetLogger * **getLogger(name: string): any ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/loggerService.ts#L82)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L43)publichas * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L91)publicisHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L99)publicisLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L95)publicisMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L69)publicstop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # MidwayMainFrameworkMissingError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayMainFrameworkMissingError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L216)constructor * **new MidwayMainFrameworkMissingError(): [MidwayMainFrameworkMissingError](/api/3.0.0/core/class/MidwayMainFrameworkMissingError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayMiddlewareService \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**compose](#compose) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/middlewareService.ts#L19)constructor * **new MidwayMiddlewareService\(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayMiddlewareService](/api/3.0.0/core/class/MidwayMiddlewareService.md)\ - #### Type parameters * **T** * **R** * **N** = unknown ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/middlewareService.ts#L19)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#compose)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/middlewareService.ts#L21)compose * **compose(middleware: (string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\)\[], app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>, name? : string): Promise<{ \_name: string }> --- # MidwayMissingImportComponentError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayMissingImportComponentError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L141)constructor * **new MidwayMissingImportComponentError(originName: string): [MidwayMissingImportComponentError](/api/3.0.0/core/class/MidwayMissingImportComponentError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayMockService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**prepareMocks](#prepareMocks) ### Methods * [**applyContextMocks](#applyContextMocks) * [**getContextMocksSize](#getContextMocksSize) * [**init](#init) * [**initSimulation](#initSimulation) * [**isMocked](#isMocked) * [**mockClassProperty](#mockClassProperty) * [**mockContext](#mockContext) * [**mockProperty](#mockProperty) * [**restore](#restore) * [**restoreAll](#restoreAll) * [**runSimulatorAppSetup](#runSimulatorAppSetup) * [**runSimulatorAppTearDown](#runSimulatorAppTearDown) * [**runSimulatorContextSetup](#runSimulatorContextSetup) * [**runSimulatorContextTearDown](#runSimulatorContextTearDown) * [**runSimulatorSetup](#runSimulatorSetup) * [**runSimulatorTearDown](#runSimulatorTearDown) * [**mockClassProperty](#mockClassProperty) * [**mockProperty](#mockProperty) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L46)constructor * **new MidwayMockService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayMockService](/api/3.0.0/core/class/MidwayMockService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L46)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#prepareMocks)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L61)staticprepareMocks **prepareMocks: any\[] = \[] Prepare mocks before the service is initialized ## Methods[**](#Methods) ### [**](#applyContextMocks)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L195)applyContextMocks * **applyContextMocks(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>, ctx: [Context](/api/3.0.0/core/interface/Context.md)): void ### [**](#getContextMocksSize)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L210)getContextMocksSize * **getContextMocksSize(): number ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L49)init * **init(): Promise\ ### [**](#initSimulation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L236)publicinitSimulation * **initSimulation(group? : string): Promise\ ### [**](#isMocked)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L186)publicisMocked * **isMocked(obj: any, key: any, group? : string): boolean ### [**](#mockClassProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L86)publicmockClassProperty * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void ### [**](#mockContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L133)publicmockContext * **mockContext(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>, key: string | (ctx: [Context](/api/3.0.0/core/interface/Context.md)) => void, value? : any, group? : string): void ### [**](#mockProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L95)publicmockProperty * **mockProperty(obj: any, key: string, value: any, group? : string): void ### [**](#restore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L149)publicrestore * **restore(group? : string): void ### [**](#restoreAll)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L154)publicrestoreAll * **restoreAll(): void ### [**](#runSimulatorAppSetup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L263)publicrunSimulatorAppSetup * **runSimulatorAppSetup(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorAppTearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L269)publicrunSimulatorAppTearDown * **runSimulatorAppTearDown(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorContextSetup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L277)publicrunSimulatorContextSetup * **runSimulatorContextSetup(ctx: [Context](/api/3.0.0/core/interface/Context.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorContextTearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L286)publicrunSimulatorContextTearDown * **runSimulatorContextTearDown(ctx: [Context](/api/3.0.0/core/interface/Context.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorSetup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L249)publicrunSimulatorSetup * **runSimulatorSetup(): Promise\ ### [**](#runSimulatorTearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L255)publicrunSimulatorTearDown * **runSimulatorTearDown(): Promise\ ### [**](#mockClassProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L63)staticmockClassProperty * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void ### [**](#mockProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/mockService.ts#L72)staticmockProperty * **mockProperty(obj: new (...args: any\[]) => any, key: string, value: any, group? : string): void --- # MidwayParameterError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayParameterError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L37)constructor * **new MidwayParameterError(message? : string): [MidwayParameterError](/api/3.0.0/core/class/MidwayParameterError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayPerformanceManager ## Index[**](#Index) ### Properties * [**DEFAULT\_GROUP](#DEFAULT_GROUP) ### Methods * [**clean](#clean) * [**disconnect](#disconnect) * [**markEnd](#markEnd) * [**markStart](#markStart) * [**observeMeasure](#observeMeasure) * [**cleanAll](#cleanAll) * [**getInitialPerformanceEntries](#getInitialPerformanceEntries) * [**getInstance](#getInstance) ## Properties[**](#Properties) ### [**](#DEFAULT_GROUP)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L9)publicstaticDEFAULT\_GROUP **DEFAULT\_GROUP: { INITIALIZE: string } = ... ## Methods[**](#Methods) ### [**](#clean)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L76)publicclean * **clean(): void ### [**](#disconnect)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L69)publicdisconnect * **disconnect(): void ### [**](#markEnd)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L35)publicmarkEnd * **markEnd(key: string): void ### [**](#markStart)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L29)publicmarkStart * **markStart(key: string): void ### [**](#observeMeasure)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L47)publicobserveMeasure * **observeMeasure(callback: (list: PerformanceObserverEntryList) => void): PerformanceObserver ### [**](#cleanAll)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L98)publicstaticcleanAll * **cleanAll(): void ### [**](#getInitialPerformanceEntries)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L103)publicstaticgetInitialPerformanceEntries * **getInitialPerformanceEntries(): any\[] ### [**](#getInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/performanceManager.ts#L18)staticgetInstance * **getInstance(group: string): [MidwayPerformanceManager](/api/3.0.0/core/class/MidwayPerformanceManager.md) --- # MidwayPipelineService ### Implements * [IPipelineHandler](/api/3.0.0/core/interface/IPipelineHandler.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**valves](#valves) ### Methods * [**concat](#concat) * [**concatSeries](#concatSeries) * [**parallel](#parallel) * [**series](#series) * [**waterfall](#waterfall) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L170)constructor * **new MidwayPipelineService(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), valves? : valvesType): [MidwayPipelineService](/api/3.0.0/core/class/MidwayPipelineService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L171)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#valves)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L172)optionalreadonlyvalves **valves? : valvesType ## Methods[**](#Methods) ### [**](#concat)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L189)concat * **concat\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - Implementation of IPipelineHandler.concat 并行执行,最终 result 为数组 *** #### Type parameters * **T** ### [**](#concatSeries)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L260)concatSeries * **concatSeries\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - Implementation of IPipelineHandler.concatSeries 串行执行,使用 foreach await,最终 result 为数组 *** #### Type parameters * **T** ### [**](#parallel)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L179)parallel * **parallel\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - Implementation of IPipelineHandler.parallel 并行执行,使用 Promise.all *** #### Type parameters * **T** ### [**](#series)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L199)series * **series\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - Implementation of IPipelineHandler.series 串行执行,使用 foreach await *** #### Type parameters * **T** ### [**](#waterfall)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L317)waterfall * **waterfall\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - Implementation of IPipelineHandler.waterfall 串行执行,但是会把前者执行结果当成入参,传入到下一个执行中去,最后一个执行的 valve 结果会被返回 *** #### Type parameters * **T** --- # MidwayPriorityManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getCurrentPriorityList](#getCurrentPriorityList) * [**getDefaultPriority](#getDefaultPriority) * [**getPriority](#getPriority) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayPriorityManager(): [MidwayPriorityManager](/api/3.0.0/core/class/MidwayPriorityManager.md) ## Methods[**](#Methods) ### [**](#getCurrentPriorityList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L16)publicgetCurrentPriorityList * **getCurrentPriorityList(): Record\ ### [**](#getDefaultPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L20)publicgetDefaultPriority * **getDefaultPriority(): string ### [**](#getPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L34)publicgetPriority * **getPriority(priority: string): string ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L24)publicisHighPriority * **isHighPriority(priority? : string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L30)publicisLowPriority * **isLowPriority(priority? : string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/priorityManager.ts#L27)publicisMediumPriority * **isMediumPriority(priority? : string): boolean --- # MidwayRequestContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) * *MidwayRequestContainer* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**parent](#parent) ### Accessors * [**identifierMapping](#identifierMapping) * [**managedResolverFactory](#managedResolverFactory) * [**namespaceSet](#namespaceSet) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**registry](#registry) ### Methods * [**bind](#bind) * [**bindClass](#bindClass) * [**createChild](#createChild) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getContext](#getContext) * [**getInstanceScope](#getInstanceScope) * [**getNamespaceList](#getNamespaceList) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**init](#init) * [**listModule](#listModule) * [**load](#load) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**ready](#ready) * [**registerObject](#registerObject) * [**saveModule](#saveModule) * [**setAttr](#setAttr) * [**setFileDetector](#setFileDetector) * [**stop](#stop) * [**transformModule](#transformModule) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L9)constructor * **new MidwayRequestContainer(ctx: any, applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): [MidwayRequestContainer](/api/3.0.0/core/class/MidwayRequestContainer.md) - Overrides MidwayContainer.constructor ## Properties[**](#Properties) ### [**](#parent)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L242)publicparent **parent: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) = null Inherited from MidwayContainer.parent ## Accessors[**](#Accessors) ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L285)identifierMapping * **get identifierMapping(): [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) - Inherited from MidwayContainer.identifierMapping ### [**](#managedResolverFactory)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L278)managedResolverFactory * **get managedResolverFactory(): ManagedResolverFactory - Inherited from MidwayContainer.managedResolverFactory ### [**](#namespaceSet)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L292)namespaceSet * **get namespaceSet(): Set\ - Inherited from MidwayContainer.namespaceSet ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L260)objectCreateEventTarget * **get objectCreateEventTarget(): EventEmitter\ - Inherited from MidwayContainer.objectCreateEventTarget ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L267)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L274)registry * **get registry(): [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md) * **set registry(registry: [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md)): void - Inherited from MidwayContainer.registry - Inherited from MidwayContainer.registry ## Methods[**](#Methods) ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L353)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L354)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L359)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void * **bind\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void - Inherited from MidwayContainer.bind #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L340)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void - Inherited from MidwayContainer.bindClass ### [**](#createChild)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L522)createChild * **createChild(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) - Inherited from MidwayContainer.createChild ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L34)get * **get\(identifier: any, args? : any): T - Overrides MidwayContainer.get #### Type parameters * **T** = any ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L63)getAsync * **getAsync\(identifier: any, args? : any): Promise\ - Overrides MidwayContainer.getAsync #### Type parameters * **T** = any ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L530)publicgetAttr * **getAttr\(key: string): T - Inherited from MidwayContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L96)getContext * **getContext(): { \_MAIN\_CTX\_: boolean } ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L728)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) - Inherited from MidwayContainer.getInstanceScope Get instance IoC container scope ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L716)getNamespaceList * **getNamespaceList(): string\[] - Inherited from MidwayContainer.getNamespaceList ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L720)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean - Inherited from MidwayContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L712)hasNamespace * **hasNamespace(ns: string): boolean - Inherited from MidwayContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L724)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean - Inherited from MidwayContainer.hasObject ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L30)init * **init(): void - Overrides MidwayContainer.init ### [**](#listModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L704)listModule * **listModule(key: string): unknown\[] - Inherited from MidwayContainer.listModule ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L299)load * **load(module: any): void - Inherited from MidwayContainer.load ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L634)onBeforeBind * **onBeforeBind(fn: (Clzz: any, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md); replaceCallback: (newDefinition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)) => void }) => void): void - Inherited from MidwayContainer.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L647)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (Clzz: any, options: { constructorArgs: any\[]; context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L685)onBeforeObjectDestroy * **onBeforeObjectDestroy\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L660)onObjectCreated * **onObjectCreated\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md); replaceCallback: (ins: T) => void }) => void): void - Inherited from MidwayContainer.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L673)onObjectInit * **onObjectInit\(fn: (ins: T, options: { context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onObjectInit #### Type parameters * **T** ### [**](#ready)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/requestContainer.ts#L92)ready * **ready(): Promise\ - Overrides MidwayContainer.ready ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L630)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): void - Inherited from MidwayContainer.registerObject proxy registry.registerObject ### [**](#saveModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L697)saveModule * **saveModule(key: any, module: any): void - Inherited from MidwayContainer.saveModule ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L526)publicsetAttr * **setAttr(key: string, value: any): void - Inherited from MidwayContainer.setAttr Set value to app attribute map ### [**](#setFileDetector)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L518)setFileDetector * **setFileDetector(fileDetector: [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md)): void - Inherited from MidwayContainer.setFileDetector ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L545)stop * **stop(): Promise\ - Inherited from MidwayContainer.stop ### [**](#transformModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/context/container.ts#L708)transformModule * **transformModule(moduleMap: Map\>): void - Inherited from MidwayContainer.transformModule --- # MidwayResolverMissingError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayResolverMissingError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L103)constructor * **new MidwayResolverMissingError(type: string): [MidwayResolverMissingError](/api/3.0.0/core/class/MidwayResolverMissingError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayRetryExceededMaxTimesError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayRetryExceededMaxTimesError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L184)constructor * **new MidwayRetryExceededMaxTimesError(methodName: any, times: number, err: Error): [MidwayRetryExceededMaxTimesError](/api/3.0.0/core/class/MidwayRetryExceededMaxTimesError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayServerlessFunctionService ### Hierarchy * [MidwayWebRouterService](/api/3.0.0/core/class/MidwayWebRouterService.md) * *MidwayServerlessFunctionService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**addController](#addController) * [**addRouter](#addRouter) * [**addServerlessFunction](#addServerlessFunction) * [**getFlattenRouterTable](#getFlattenRouterTable) * [**getFunctionList](#getFunctionList) * [**getMatchedRouterInfo](#getMatchedRouterInfo) * [**getRoutePriorityList](#getRoutePriorityList) * [**getRouterTable](#getRouterTable) * [**sortRouter](#sortRouter) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L30)constructor * **new MidwayServerlessFunctionService(options? : [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md)): [MidwayServerlessFunctionService](/api/3.0.0/core/class/MidwayServerlessFunctionService.md) - Overrides MidwayWebRouterService.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L30)readonlyoptions **options: [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md) = {} Inherited from MidwayWebRouterService.options ## Methods[**](#Methods) ### [**](#addController)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L210)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L215)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L223)publicaddController * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/3.0.0/core/interface/ControllerOption.md), functionMeta? : boolean): any * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/3.0.0/core/interface/ControllerOption.md), resourceOptions? : { resourceFilter: (routerInfo: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)) => boolean }, functionMeta? : boolean): any - Inherited from MidwayWebRouterService.addController dynamically add a controller ### [**](#addRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L373)publicaddRouter * **addRouter(routerFunction: (...args: any\[]) => void, routerInfoOption: [DynamicRouterInfo](/api/3.0.0/core.md#DynamicRouterInfo)): void - Inherited from MidwayWebRouterService.addRouter dynamically add a route to root prefix ### [**](#addServerlessFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L200)publicaddServerlessFunction * **addServerlessFunction(func: (...args: any\[]) => Promise\, triggerOptions: [TriggerMetadata](/api/3.0.0/core/namespace/FaaSMetadata.md#TriggerMetadata), functionOptions? : [ServerlessFunctionOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions)): void ### [**](#getFlattenRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L490)publicgetFlattenRouterTable * **getFlattenRouterTable(options? : { compileUrlPattern? : boolean }): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]> - Inherited from MidwayWebRouterService.getFlattenRouterTable ### [**](#getFunctionList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L194)publicgetFunctionList * **getFunctionList(): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]> ### [**](#getMatchedRouterInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L516)publicgetMatchedRouterInfo * **getMatchedRouterInfo(routerUrl: string, method: string): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)> - Inherited from MidwayWebRouterService.getMatchedRouterInfo ### [**](#getRoutePriorityList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L474)publicgetRoutePriorityList * **getRoutePriorityList(): Promise<[RouterPriority](/api/3.0.0/core/interface/RouterPriority.md)\[]> - Inherited from MidwayWebRouterService.getRoutePriorityList ### [**](#getRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L482)publicgetRouterTable * **getRouterTable(): Promise\> - Inherited from MidwayWebRouterService.getRouterTable ### [**](#sortRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L405)publicsortRouter * **sortRouter(urlMatchList: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]): { \_category: number; \_level: number; \_paramString: string; \_pureRouter: string; \_weight: number; controllerClz? : new (...args: any\[]) => any; controllerId? : string; controllerMiddleware? : any\[]; description? : string; fullUrl? : string; fullUrlCompiledRegexp? : RegExp; fullUrlFlattenString? : string; funcHandlerName? : string; functionMetadata? : any; functionName? : string; functionTriggerMetadata? : any; functionTriggerName? : string; handlerName? : string; id? : string; method: string | (...args: any\[]) => void; middleware? : any\[]; prefix? : string; requestMetadata? : any\[]; requestMethod: string; responseMetadata? : any\[]; routerName? : string; summary? : string; url: string | RegExp }\[] - Inherited from MidwayWebRouterService.sortRouter --- # MidwaySingletonInjectRequestError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwaySingletonInjectRequestError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L134)constructor * **new MidwaySingletonInjectRequestError(singletonScopeName: string, requestScopeName: string): [MidwaySingletonInjectRequestError](/api/3.0.0/core/class/MidwaySingletonInjectRequestError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayUseWrongMethodError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayUseWrongMethodError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L121)constructor * **new MidwayUseWrongMethodError(wrongMethod: string, replacedMethod: string, describeKey? : string): [MidwayUseWrongMethodError](/api/3.0.0/core/class/MidwayUseWrongMethodError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayUtilHttpClientTimeoutError ### Hierarchy * [MidwayError](/api/3.0.0/core/class/MidwayError.md) * *MidwayUtilHttpClientTimeoutError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/framework.ts#L148)constructor * **new MidwayUtilHttpClientTimeoutError(message: string): [MidwayUtilHttpClientTimeoutError](/api/3.0.0/core/class/MidwayUtilHttpClientTimeoutError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayWebRouterService ### Hierarchy * *MidwayWebRouterService* * [MidwayServerlessFunctionService](/api/3.0.0/core/class/MidwayServerlessFunctionService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**addController](#addController) * [**addRouter](#addRouter) * [**getFlattenRouterTable](#getFlattenRouterTable) * [**getMatchedRouterInfo](#getMatchedRouterInfo) * [**getRoutePriorityList](#getRoutePriorityList) * [**getRouterTable](#getRouterTable) * [**sortRouter](#sortRouter) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L157)constructor * **new MidwayWebRouterService(options? : [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md)): [MidwayWebRouterService](/api/3.0.0/core/class/MidwayWebRouterService.md) ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L157)readonlyoptions **options: [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md) = {} ## Methods[**](#Methods) ### [**](#addController)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L210)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L215)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L223)publicaddController * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/3.0.0/core/interface/ControllerOption.md), functionMeta? : boolean): any * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/3.0.0/core/interface/ControllerOption.md), resourceOptions? : { resourceFilter: (routerInfo: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)) => boolean }, functionMeta? : boolean): any - dynamically add a controller ### [**](#addRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L373)publicaddRouter * **addRouter(routerFunction: (...args: any\[]) => void, routerInfoOption: [DynamicRouterInfo](/api/3.0.0/core.md#DynamicRouterInfo)): void - dynamically add a route to root prefix ### [**](#getFlattenRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L490)publicgetFlattenRouterTable * **getFlattenRouterTable(options? : { compileUrlPattern? : boolean }): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]> ### [**](#getMatchedRouterInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L516)publicgetMatchedRouterInfo * **getMatchedRouterInfo(routerUrl: string, method: string): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)> ### [**](#getRoutePriorityList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L474)publicgetRoutePriorityList * **getRoutePriorityList(): Promise<[RouterPriority](/api/3.0.0/core/interface/RouterPriority.md)\[]> ### [**](#getRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L482)publicgetRouterTable * **getRouterTable(): Promise\> ### [**](#sortRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L405)publicsortRouter * **sortRouter(urlMatchList: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]): { \_category: number; \_level: number; \_paramString: string; \_pureRouter: string; \_weight: number; controllerClz? : new (...args: any\[]) => any; controllerId? : string; controllerMiddleware? : any\[]; description? : string; fullUrl? : string; fullUrlCompiledRegexp? : RegExp; fullUrlFlattenString? : string; funcHandlerName? : string; functionMetadata? : any; functionName? : string; functionTriggerMetadata? : any; functionTriggerName? : string; handlerName? : string; id? : string; method: string | (...args: any\[]) => void; middleware? : any\[]; prefix? : string; requestMetadata? : any\[]; requestMethod: string; responseMetadata? : any\[]; routerName? : string; summary? : string; url: string | RegExp }\[] --- # PipelineContext 执行pipeline 时当前上下文存储内容 ### Implements * [IPipelineContext](/api/3.0.0/core/interface/IPipelineContext.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**args](#args) * [**info](#info) ### Methods * [**get](#get) * [**keys](#keys) * [**set](#set) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L144)constructor * **new PipelineContext(args? : any): [PipelineContext](/api/3.0.0/core/class/PipelineContext.md) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L141)args **args: any Implementation of IPipelineContext.args pipeline 执行原始参数 ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L142)info **info: IPipelineInfo = ... Implementation of IPipelineContext.info valve 执行信息 ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L150)get * **get(key: string): any - Implementation of IPipelineContext.get 用于缓存当前 pipeline 执行中的中间过程参数 ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L158)keys * **keys(): string\[] - Implementation of IPipelineContext.keys 返回存在的所有 key ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L154)set * **set(key: string, val: any): void - Implementation of IPipelineContext.set 用于缓存当前 pipeline 执行中的中间过程参数 --- # ServerResponse \ ### Hierarchy * *ServerResponse* * [HttpServerResponse](/api/3.0.0/core/class/HttpServerResponse.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**blob](#blob) * [**fail](#fail) * [**json](#json) * [**success](#success) * [**text](#text) * [**BLOB\_TPL](#BLOB_TPL) * [**JSON\_TPL](#JSON_TPL) * [**TEXT\_TPL](#TEXT_TPL) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L7)constructor * **new ServerResponse\(ctx: CTX): [ServerResponse](/api/3.0.0/core/class/ServerResponse.md)\ - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) = [Context](/api/3.0.0/core/interface/Context.md) ## Methods[**](#Methods) ### [**](#blob)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L61)blob * **blob(data: Buffer\): any ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L74)fail * **fail(): [ServerResponse](/api/3.0.0/core/class/ServerResponse.md)\ ### [**](#json)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L45)json * **json(data: Record\): any ### [**](#success)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L69)success * **success(): [ServerResponse](/api/3.0.0/core/class/ServerResponse.md)\ ### [**](#text)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L53)text * **text(data: string): any ### [**](#BLOB_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L37)staticBLOB\_TPL * **BLOB\_TPL\(data: Buffer\, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#JSON_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L19)staticJSON\_TPL * **JSON\_TPL\(data: Record\, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) ### [**](#TEXT_TPL)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/response/base.ts#L11)staticTEXT\_TPL * **TEXT\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) --- # abstractServiceFactory \ 多客户端工厂实现 ### Hierarchy * *ServiceFactory* * [MidwayLoggerService](/api/3.0.0/core/class/MidwayLoggerService.md) ### Implements * [IServiceFactory](/api/3.0.0/core/interface/IServiceFactory.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ServiceFactory\(): [ServiceFactory](/api/3.0.0/core/class/ServiceFactory.md)\ - #### Type parameters * **T** ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L47)publiccreateInstance * **createInstance(config: any, clientName? : any): Promise\ - Implementation of IServiceFactory.createInstance ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L39)publicget * **get\(id? : string): U - Implementation of IServiceFactory.get #### Type parameters * **U** = T ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L83)publicgetClientKeys * **getClientKeys(): string\[] - Implementation of IServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L87)publicgetClientPriority * **getClientPriority(name: string): string - Implementation of IServiceFactory.getClientPriority ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L79)publicgetClients * **getClients(): Map\ - Implementation of IServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L75)publicgetDefaultClientName * **getDefaultClientName(): string - Implementation of IServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L59)publicabstractgetName * **getName(): string - Implementation of IServiceFactory.getName ### [**](#has)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L43)publichas * **has(id: string): boolean - Implementation of IServiceFactory.has ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L91)publicisHighPriority * **isHighPriority(name: string): boolean - Implementation of IServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L99)publicisLowPriority * **isLowPriority(name: string): boolean - Implementation of IServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L95)publicisMediumPriority * **isMediumPriority(name: string): boolean - Implementation of IServiceFactory.isMediumPriority ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/serviceFactory.ts#L69)publicstop * **stop(): Promise\ - Implementation of IServiceFactory.stop --- # TypedResourceManager \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createResource](#createResource) * [**destroy](#destroy) * [**destroyParallel](#destroyParallel) * [**getResource](#getResource) * [**init](#init) * [**start](#start) * [**startParallel](#startParallel) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L10)constructor * **new TypedResourceManager\(typedResourceInitializerOptions: { initializeClzProvider: {}; initializeValue: {}; resourceBinding: (ClzProvider: [ClassType](/api/3.0.0/core.md#ClassType)\, resourceInitializeConfig: ResourceInitializeConfig, resource: Resource, resourceName: string) => Promise\; resourceDestroy: (resource: Resource, resourceInitializeConfig: ResourceInitializeConfig) => Promise\; resourceInitialize: (resourceInitializeConfig: ResourceInitializeConfig, resourceName: string) => Promise\; resourceStart: (resource: Resource, resourceInitializeConfig: ResourceInitializeConfig, resourceBindingResult? : any) => Promise\ }): [TypedResourceManager](/api/3.0.0/core/class/TypedResourceManager.md)\ - #### Type parameters * **Resource** = any * **ResourceInitializeConfig** = any * **ResourceProviderType** = any ## Methods[**](#Methods) ### [**](#createResource)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L40)publiccreateResource * **createResource(resourceName: string, resourceInitializeConfig: ResourceInitializeConfig): Promise\ ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L119)publicdestroy * **destroy(): Promise\ ### [**](#destroyParallel)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L106)publicdestroyParallel * **destroyParallel(): Promise\ ### [**](#getResource)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L130)publicgetResource * **getResource(resourceName: string): any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L53)publicinit * **init(): Promise\ ### [**](#start)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L96)publicstart * **start(): Promise\ ### [**](#startParallel)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/typedResourceManager.ts#L82)publicstartParallel * **startParallel(): Promise\ --- # abstractWebControllerGenerator \ ## Index[**](#Index) ### Properties * [**app](#app) * [**midwayWebRouterService](#midwayWebRouterService) ### Methods * [**createRouter](#createRouter) * [**generateController](#generateController) * [**generateKoaController](#generateKoaController) * [**loadMidwayController](#loadMidwayController) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L28)readonlyapp **app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)> ### [**](#midwayWebRouterService)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L29)readonlymidwayWebRouterService **midwayWebRouterService: [MidwayWebRouterService](/api/3.0.0/core/class/MidwayWebRouterService.md) ## Methods[**](#Methods) ### [**](#createRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L188)abstractcreateRouter * **createRouter(routerOptions: any): Router ### [**](#generateController)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L189)abstractgenerateController * **generateController(routeInfo: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)): any ### [**](#generateKoaController)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L36)publicgenerateKoaController * **generateKoaController(routeInfo: [RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)): (ctx: any, next: any) => Promise\ - wrap controller string to middleware function ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/webGenerator.ts#L98)publicloadMidwayController * **loadMidwayController(routerHandler? : (newRouter: Router) => void): Promise\ --- # WebRouterCollector * **@deprecated** use built-in MidwayWebRouterService first ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getFlattenRouterTable](#getFlattenRouterTable) * [**getRoutePriorityList](#getRoutePriorityList) * [**getRouterTable](#getRouterTable) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L259)constructor * **new WebRouterCollector(baseDir? : string, options? : [RouterCollectorOptions](/api/3.0.0/core/interface/RouterCollectorOptions.md)): [WebRouterCollector](/api/3.0.0/core/class/WebRouterCollector.md) ## Methods[**](#Methods) ### [**](#getFlattenRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L306)getFlattenRouterTable * **getFlattenRouterTable(): Promise<[RouterInfo](/api/3.0.0/core/interface/RouterInfo.md)\[]> ### [**](#getRoutePriorityList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L296)getRoutePriorityList * **getRoutePriorityList(): Promise<[RouterPriority](/api/3.0.0/core/interface/RouterPriority.md)\[]> ### [**](#getRouterTable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/slsFunctionService.ts#L301)getRouterTable * **getRouterTable(): Promise\> --- # BaseType ## Index[**](#Index) ### Enumeration Members * [**Boolean](#Boolean) * [**Number](#Number) * [**String](#String) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Boolean)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L903)Boolean **Boolean: boolean ### [**](#Number)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L904)Number **Number: number ### [**](#String)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/decoratorManager.ts#L905)String **String: string --- # GrpcStreamTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BASE](#BASE) * [**DUPLEX](#DUPLEX) * [**READABLE](#READABLE) * [**WRITEABLE](#WRITEABLE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BASE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/provider.ts#L42)BASE **BASE: base ### [**](#DUPLEX)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/provider.ts#L43)DUPLEX **DUPLEX: ServerDuplexStream ### [**](#READABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/provider.ts#L44)READABLE **READABLE: ServerReadableStream ### [**](#WRITEABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/provider.ts#L45)WRITEABLE **WRITEABLE: ServerWritableStream --- # HttpStatus ## Index[**](#Index) ### Enumeration Members * [**ACCEPTED](#ACCEPTED) * [**AMBIGUOUS](#AMBIGUOUS) * [**BAD\_GATEWAY](#BAD_GATEWAY) * [**BAD\_REQUEST](#BAD_REQUEST) * [**CONFLICT](#CONFLICT) * [**CONTINUE](#CONTINUE) * [**CREATED](#CREATED) * [**EARLYHINTS](#EARLYHINTS) * [**EXPECTATION\_FAILED](#EXPECTATION_FAILED) * [**FAILED\_DEPENDENCY](#FAILED_DEPENDENCY) * [**FORBIDDEN](#FORBIDDEN) * [**FOUND](#FOUND) * [**GATEWAY\_TIMEOUT](#GATEWAY_TIMEOUT) * [**GONE](#GONE) * [**HTTP\_VERSION\_NOT\_SUPPORTED](#HTTP_VERSION_NOT_SUPPORTED) * [**INTERNAL\_SERVER\_ERROR](#INTERNAL_SERVER_ERROR) * [**I\_AM\_A\_TEAPOT](#I_AM_A_TEAPOT) * [**LENGTH\_REQUIRED](#LENGTH_REQUIRED) * [**METHOD\_NOT\_ALLOWED](#METHOD_NOT_ALLOWED) * [**MISDIRECTED](#MISDIRECTED) * [**MOVED\_PERMANENTLY](#MOVED_PERMANENTLY) * [**NON\_AUTHORITATIVE\_INFORMATION](#NON_AUTHORITATIVE_INFORMATION) * [**NOT\_ACCEPTABLE](#NOT_ACCEPTABLE) * [**NOT\_FOUND](#NOT_FOUND) * [**NOT\_IMPLEMENTED](#NOT_IMPLEMENTED) * [**NOT\_MODIFIED](#NOT_MODIFIED) * [**NO\_CONTENT](#NO_CONTENT) * [**OK](#OK) * [**PARTIAL\_CONTENT](#PARTIAL_CONTENT) * [**PAYLOAD\_TOO\_LARGE](#PAYLOAD_TOO_LARGE) * [**PAYMENT\_REQUIRED](#PAYMENT_REQUIRED) * [**PERMANENT\_REDIRECT](#PERMANENT_REDIRECT) * [**PRECONDITION\_FAILED](#PRECONDITION_FAILED) * [**PRECONDITION\_REQUIRED](#PRECONDITION_REQUIRED) * [**PROCESSING](#PROCESSING) * [**PROXY\_AUTHENTICATION\_REQUIRED](#PROXY_AUTHENTICATION_REQUIRED) * [**REQUESTED\_RANGE\_NOT\_SATISFIABLE](#REQUESTED_RANGE_NOT_SATISFIABLE) * [**REQUEST\_TIMEOUT](#REQUEST_TIMEOUT) * [**RESET\_CONTENT](#RESET_CONTENT) * [**SEE\_OTHER](#SEE_OTHER) * [**SERVICE\_UNAVAILABLE](#SERVICE_UNAVAILABLE) * [**SWITCHING\_PROTOCOLS](#SWITCHING_PROTOCOLS) * [**TEMPORARY\_REDIRECT](#TEMPORARY_REDIRECT) * [**TOO\_MANY\_REQUESTS](#TOO_MANY_REQUESTS) * [**UNAUTHORIZED](#UNAUTHORIZED) * [**UNPROCESSABLE\_ENTITY](#UNPROCESSABLE_ENTITY) * [**UNSUPPORTED\_MEDIA\_TYPE](#UNSUPPORTED_MEDIA_TYPE) * [**URI\_TOO\_LONG](#URI_TOO_LONG) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#ACCEPTED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L10)ACCEPTED **ACCEPTED: 202 ### [**](#AMBIGUOUS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L15)AMBIGUOUS **AMBIGUOUS: 300 ### [**](#BAD_GATEWAY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L48)BAD\_GATEWAY **BAD\_GATEWAY: 502 ### [**](#BAD_REQUEST)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L22)BAD\_REQUEST **BAD\_REQUEST: 400 ### [**](#CONFLICT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L31)CONFLICT **CONFLICT: 409 ### [**](#CONTINUE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L4)CONTINUE **CONTINUE: 100 ### [**](#CREATED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L9)CREATED **CREATED: 201 ### [**](#EARLYHINTS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L7)EARLYHINTS **EARLYHINTS: 103 ### [**](#EXPECTATION_FAILED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L39)EXPECTATION\_FAILED **EXPECTATION\_FAILED: 417 ### [**](#FAILED_DEPENDENCY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L43)FAILED\_DEPENDENCY **FAILED\_DEPENDENCY: 424 ### [**](#FORBIDDEN)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L25)FORBIDDEN **FORBIDDEN: 403 ### [**](#FOUND)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L17)FOUND **FOUND: 302 ### [**](#GATEWAY_TIMEOUT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L50)GATEWAY\_TIMEOUT **GATEWAY\_TIMEOUT: 504 ### [**](#GONE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L32)GONE **GONE: 410 ### [**](#HTTP_VERSION_NOT_SUPPORTED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L51)HTTP\_VERSION\_NOT\_SUPPORTED **HTTP\_VERSION\_NOT\_SUPPORTED: 505 ### [**](#INTERNAL_SERVER_ERROR)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L46)INTERNAL\_SERVER\_ERROR **INTERNAL\_SERVER\_ERROR: 500 ### [**](#I_AM_A_TEAPOT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L40)I\_AM\_A\_TEAPOT **I\_AM\_A\_TEAPOT: 418 ### [**](#LENGTH_REQUIRED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L33)LENGTH\_REQUIRED **LENGTH\_REQUIRED: 411 ### [**](#METHOD_NOT_ALLOWED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L27)METHOD\_NOT\_ALLOWED **METHOD\_NOT\_ALLOWED: 405 ### [**](#MISDIRECTED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L41)MISDIRECTED **MISDIRECTED: 421 ### [**](#MOVED_PERMANENTLY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L16)MOVED\_PERMANENTLY **MOVED\_PERMANENTLY: 301 ### [**](#NON_AUTHORITATIVE_INFORMATION)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L11)NON\_AUTHORITATIVE\_INFORMATION **NON\_AUTHORITATIVE\_INFORMATION: 203 ### [**](#NOT_ACCEPTABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L28)NOT\_ACCEPTABLE **NOT\_ACCEPTABLE: 406 ### [**](#NOT_FOUND)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L26)NOT\_FOUND **NOT\_FOUND: 404 ### [**](#NOT_IMPLEMENTED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L47)NOT\_IMPLEMENTED **NOT\_IMPLEMENTED: 501 ### [**](#NOT_MODIFIED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L19)NOT\_MODIFIED **NOT\_MODIFIED: 304 ### [**](#NO_CONTENT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L12)NO\_CONTENT **NO\_CONTENT: 204 ### [**](#OK)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L8)OK **OK: 200 ### [**](#PARTIAL_CONTENT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L14)PARTIAL\_CONTENT **PARTIAL\_CONTENT: 206 ### [**](#PAYLOAD_TOO_LARGE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L35)PAYLOAD\_TOO\_LARGE **PAYLOAD\_TOO\_LARGE: 413 ### [**](#PAYMENT_REQUIRED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L24)PAYMENT\_REQUIRED **PAYMENT\_REQUIRED: 402 ### [**](#PERMANENT_REDIRECT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L21)PERMANENT\_REDIRECT **PERMANENT\_REDIRECT: 308 ### [**](#PRECONDITION_FAILED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L34)PRECONDITION\_FAILED **PRECONDITION\_FAILED: 412 ### [**](#PRECONDITION_REQUIRED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L44)PRECONDITION\_REQUIRED **PRECONDITION\_REQUIRED: 428 ### [**](#PROCESSING)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L6)PROCESSING **PROCESSING: 102 ### [**](#PROXY_AUTHENTICATION_REQUIRED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L29)PROXY\_AUTHENTICATION\_REQUIRED **PROXY\_AUTHENTICATION\_REQUIRED: 407 ### [**](#REQUESTED_RANGE_NOT_SATISFIABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L38)REQUESTED\_RANGE\_NOT\_SATISFIABLE **REQUESTED\_RANGE\_NOT\_SATISFIABLE: 416 ### [**](#REQUEST_TIMEOUT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L30)REQUEST\_TIMEOUT **REQUEST\_TIMEOUT: 408 ### [**](#RESET_CONTENT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L13)RESET\_CONTENT **RESET\_CONTENT: 205 ### [**](#SEE_OTHER)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L18)SEE\_OTHER **SEE\_OTHER: 303 ### [**](#SERVICE_UNAVAILABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L49)SERVICE\_UNAVAILABLE **SERVICE\_UNAVAILABLE: 503 ### [**](#SWITCHING_PROTOCOLS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L5)SWITCHING\_PROTOCOLS **SWITCHING\_PROTOCOLS: 101 ### [**](#TEMPORARY_REDIRECT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L20)TEMPORARY\_REDIRECT **TEMPORARY\_REDIRECT: 307 ### [**](#TOO_MANY_REQUESTS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L45)TOO\_MANY\_REQUESTS **TOO\_MANY\_REQUESTS: 429 ### [**](#UNAUTHORIZED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L23)UNAUTHORIZED **UNAUTHORIZED: 401 ### [**](#UNPROCESSABLE_ENTITY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L42)UNPROCESSABLE\_ENTITY **UNPROCESSABLE\_ENTITY: 422 ### [**](#UNSUPPORTED_MEDIA_TYPE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L37)UNSUPPORTED\_MEDIA\_TYPE **UNSUPPORTED\_MEDIA\_TYPE: 415 ### [**](#URI_TOO_LONG)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/error/http.ts#L36)URI\_TOO\_LONG **URI\_TOO\_LONG: 414 --- # InjectModeEnum ## Index[**](#Index) ### Enumeration Members * [**Class](#Class) * [**Identifier](#Identifier) * [**PropertyName](#PropertyName) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Class)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L62)Class **Class: Class ### [**](#Identifier)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L61)Identifier **Identifier: Identifier ### [**](#PropertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L63)PropertyName **PropertyName: PropertyName --- # MidwayProcessTypeEnum ## Index[**](#Index) ### Enumeration Members * [**AGENT](#AGENT) * [**APPLICATION](#APPLICATION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AGENT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L824)AGENT **AGENT: AGENT ### [**](#APPLICATION)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L823)APPLICATION **APPLICATION: APPLICATION --- # MSListenerType ## Index[**](#Index) ### Enumeration Members * [**KAFKA](#KAFKA) * [**MQTT](#MQTT) * [**RABBITMQ](#RABBITMQ) * [**REDIS](#REDIS) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#KAFKA)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L111)KAFKA **KAFKA: kafka ### [**](#MQTT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L110)MQTT **MQTT: mqtt ### [**](#RABBITMQ)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L109)RABBITMQ **RABBITMQ: rabbitmq ### [**](#REDIS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L112)REDIS **REDIS: redis --- # MSProviderType ## Index[**](#Index) ### Enumeration Members * [**DUBBO](#DUBBO) * [**GRPC](#GRPC) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DUBBO)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L104)DUBBO **DUBBO: dubbo ### [**](#GRPC)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L105)GRPC **GRPC: gRPC --- # ObjectLifeCycleEvent ## Index[**](#Index) ### Enumeration Members * [**AFTER\_CREATED](#AFTER_CREATED) * [**AFTER\_INIT](#AFTER_INIT) * [**BEFORE\_BIND](#BEFORE_BIND) * [**BEFORE\_CREATED](#BEFORE_CREATED) * [**BEFORE\_DESTROY](#BEFORE_DESTROY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AFTER_CREATED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L570)AFTER\_CREATED **AFTER\_CREATED: afterObjectCreated ### [**](#AFTER_INIT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L571)AFTER\_INIT **AFTER\_INIT: afterObjectInit ### [**](#BEFORE_BIND)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L568)BEFORE\_BIND **BEFORE\_BIND: beforeBind ### [**](#BEFORE_CREATED)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L569)BEFORE\_CREATED **BEFORE\_CREATED: beforeObjectCreated ### [**](#BEFORE_DESTROY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L572)BEFORE\_DESTROY **BEFORE\_DESTROY: beforeObjectDestroy --- # RouteParamTypes ## Index[**](#Index) ### Enumeration Members * [**BODY](#BODY) * [**CUSTOM](#CUSTOM) * [**FIELDS](#FIELDS) * [**FILESSTREAM](#FILESSTREAM) * [**FILESTREAM](#FILESTREAM) * [**HEADERS](#HEADERS) * [**NEXT](#NEXT) * [**PARAM](#PARAM) * [**QUERIES](#QUERIES) * [**QUERY](#QUERY) * [**REQUEST\_IP](#REQUEST_IP) * [**REQUEST\_PATH](#REQUEST_PATH) * [**SESSION](#SESSION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BODY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L10)BODY **BODY: body ### [**](#CUSTOM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L21)CUSTOM **CUSTOM: custom ### [**](#FIELDS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L20)FIELDS **FIELDS: fields ### [**](#FILESSTREAM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L15)FILESSTREAM **FILESSTREAM: files\_stream ### [**](#FILESTREAM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L14)FILESTREAM **FILESTREAM: file\_stream ### [**](#HEADERS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L12)HEADERS **HEADERS: headers ### [**](#NEXT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L16)NEXT **NEXT: next ### [**](#PARAM)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L11)PARAM **PARAM: param ### [**](#QUERIES)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L19)QUERIES **QUERIES: queries ### [**](#QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L9)QUERY **QUERY: query ### [**](#REQUEST_IP)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L18)REQUEST\_IP **REQUEST\_IP: request\_ip ### [**](#REQUEST_PATH)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L17)REQUEST\_PATH **REQUEST\_PATH: request\_path ### [**](#SESSION)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L13)SESSION **SESSION: session --- # ScopeEnum ## Index[**](#Index) ### Enumeration Members * [**Prototype](#Prototype) * [**Request](#Request) * [**Singleton](#Singleton) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Prototype)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L57)Prototype **Prototype: Prototype ### [**](#Request)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L56)Request **Request: Request ### [**](#Singleton)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L55)Singleton **Singleton: Singleton --- # ServerlessTriggerType ## Index[**](#Index) ### Enumeration Members * [**API\_GATEWAY](#API_GATEWAY) * [**CDN](#CDN) * [**EVENT](#EVENT) * [**HSF](#HSF) * [**HTTP](#HTTP) * [**KAFKA](#KAFKA) * [**LOG](#LOG) * [**MQ](#MQ) * [**MTOP](#MTOP) * [**OS](#OS) * [**SSR](#SSR) * [**TIMER](#TIMER) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#API_GATEWAY)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L309)API\_GATEWAY **API\_GATEWAY: apigw ### [**](#CDN)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L311)CDN **CDN: cdn ### [**](#EVENT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L307)EVENT **EVENT: event ### [**](#HSF)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L316)HSF **HSF: hsf ### [**](#HTTP)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L308)HTTP **HTTP: http ### [**](#KAFKA)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L315)KAFKA **KAFKA: kafka ### [**](#LOG)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L312)LOG **LOG: log ### [**](#MQ)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L314)MQ **MQ: mq ### [**](#MTOP)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L317)MTOP **MTOP: mtop ### [**](#OS)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L310)OS **OS: os ### [**](#SSR)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L318)SSR **SSR: ssr ### [**](#TIMER)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L313)TIMER **TIMER: timer --- # WSEventTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BROADCAST](#BROADCAST) * [**EMIT](#EMIT) * [**ON\_CONNECTION](#ON_CONNECTION) * [**ON\_DISCONNECTION](#ON_DISCONNECTION) * [**ON\_MESSAGE](#ON_MESSAGE) * [**ON\_SOCKET\_ERROR](#ON_SOCKET_ERROR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BROADCAST)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L10)BROADCAST **BROADCAST: ws:broadcast ### [**](#EMIT)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L9)EMIT **EMIT: ws:Emit ### [**](#ON_CONNECTION)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L5)ON\_CONNECTION **ON\_CONNECTION: ws:onConnection ### [**](#ON_DISCONNECTION)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L6)ON\_DISCONNECTION **ON\_DISCONNECTION: ws:onDisconnection ### [**](#ON_MESSAGE)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L7)ON\_MESSAGE **ON\_MESSAGE: ws:onMessage ### [**](#ON_SOCKET_ERROR)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L8)ON\_SOCKET\_ERROR **ON\_SOCKET\_ERROR: ws:onSocketError --- # All ### Callable * **All(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes all HTTP requests to the specified path. --- # App ### Callable * **App(typeOrNamespace? : string | [FrameworkType](/api/3.0.0/core/class/FrameworkType.md)): PropertyDecorator --- # ApplicationContext ### Callable * **ApplicationContext(): PropertyDecorator --- # Aspect ### Callable * **Aspect(aspectTarget: any, match? : string | () => boolean, priority? : number): (target: any) => void --- # attachClassMetadata ### Callable * **attachClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/core.md#GroupModeType)): void *** * attach data to class --- # attachPropertyDataToClass ### Callable * **attachPropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any, groupBy? : string): void *** * attach property data to class --- # attachPropertyMetadata ### Callable * **attachPropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * attach property data --- # Autoload ### Callable * **Autoload(): (target: any) => void --- # bindContainer ### Callable * **bindContainer(container: any): void --- # Body ### Callable * **Body(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Catch ### Callable * **Catch(catchTarget? : any, options? : { matchPrototype? : boolean }): (target: any) => void --- # clearAllModule ### Callable * **clearAllModule(): void *** * clear all module --- # clearBindContainer ### Callable * **clearBindContainer(): any --- # Config ### Callable * **Config(identifier? : string): PropertyDecorator --- # Configuration ### Callable * **Configuration(options? : [InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md)): ClassDecorator --- # Consumer ### Callable * **Consumer(type: MQTT): ClassDecorator * **Consumer(type: RABBITMQ, options? : any): ClassDecorator * **Consumer(type: KAFKA, options? : any): ClassDecorator --- # ContentType ### Callable * **ContentType(contentType: string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Controller ### Callable * **Controller(prefix? : string, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string }): ClassDecorator --- # createConfiguration ### Callable * **createConfiguration(options: [InjectionConfigurationOptions](/api/3.0.0/core/interface/InjectionConfigurationOptions.md)): [FunctionalConfiguration](/api/3.0.0/core/class/FunctionalConfiguration.md) --- # createCustomMethodDecorator ### Callable * **createCustomMethodDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [MethodDecoratorOptions](/api/3.0.0/core/interface/MethodDecoratorOptions.md)): MethodDecorator --- # createCustomParamDecorator ### Callable * **createCustomParamDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [ParamDecoratorOptions](/api/3.0.0/core/interface/ParamDecoratorOptions.md)): ParameterDecorator --- # createCustomPropertyDecorator ### Callable * **createCustomPropertyDecorator(decoratorKey: string, metadata: any, impl? : boolean): PropertyDecorator *** * create a custom property inject --- # createMiddleware ### Callable * **createMiddleware\(middleware: M, options: MiddlewareResolveOptions\, name? : string): [CompositionMiddleware](/api/3.0.0/core.md#CompositionMiddleware)\ *** * wrap a middleware with options and composition a new middleware *** #### Type parameters * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) * **R** * **N** * **M**: [ClassMiddleware](/api/3.0.0/core.md#ClassMiddleware)\ --- # createRender ### Callable * **createRender(RenderEngine: { render: () => string; renderString: () => string }): (templateName: string) => (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # createRequestParamDecorator ### Callable * **createRequestParamDecorator(transform: [CustomParamDecorator](/api/3.0.0/core.md#CustomParamDecorator)\, pipesOrOptions? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[] | [ParamDecoratorOptions](/api/3.0.0/core/interface/ParamDecoratorOptions.md)): ParameterDecorator --- # Del ### Callable * **Del(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP DELETE requests to the specified path. --- # delegateTargetAllPrototypeMethod ### Callable * **delegateTargetAllPrototypeMethod(derivedCtor: any, constructor: any): void *** * 代理目标所有的原型方法,包括原型链,不包括构造器和内部隐藏方法 * **@since** 3.0.0 --- # delegateTargetMethod ### Callable * **delegateTargetMethod(derivedCtor: any, methods: string\[]): void *** * 代理目标原型上的特定方法 * **@since** 2.0.0 --- # delegateTargetProperties ### Callable * **delegateTargetProperties(derivedCtor: any, properties: string\[]): void *** * 代理目标原型属性 * **@since** 2.0.0 --- # delegateTargetPrototypeMethod ### Callable * **delegateTargetPrototypeMethod(derivedCtor: any, constructors: any\[], otherMethods? : string\[]): void *** * 代理目标所有的原型方法,不包括构造器和内部隐藏方法 * **@since** 2.0.0 --- # deprecatedOutput ### Callable * **deprecatedOutput(message: string): void *** * * **@since** 3.0.0 --- # Destroy ### Callable * **Destroy(): MethodDecorator --- # destroyGlobalApplicationContext ### Callable * **destroyGlobalApplicationContext(applicationContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): Promise\ --- # DubboMethod ### Callable * **DubboMethod(methodName? : string): MethodDecorator --- # Emit ### Callable * **Emit(messageName: string, roomName? : string | string\[]): MethodDecorator *** * * **@deprecated** please use * **@WSEmit** --- # extend ### Callable * **extend(...args: any\[]): any --- # extractExpressLikeValue ### Callable * **extractExpressLikeValue(key: any, data: any, paramType? : any): (req: any, res: any, next: any) => any --- # extractKoaLikeValue ### Callable * **extractKoaLikeValue(key: any, data: any, paramType? : any): (ctx: any, next: any) => any --- # Fields ### Callable * **Fields(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # File ### Callable * **File(propertyOrPipes? : any, pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Files ### Callable * **Files(propertyOrPipes? : any, pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Framework ### Callable * **Framework(): ClassDecorator --- # Get ### Callable * **Get(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP GET requests to the specified path. --- # getClassExtendedMetadata ### Callable * **getClassExtendedMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any, propertyName? : string, useCache? : boolean): T *** * get data from class and proto *** #### Type parameters * **T** = any --- # getClassMetadata ### Callable * **getClassMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): T *** * get data from class *** #### Type parameters * **T** = any --- # getCurrentApplicationContext ### Callable * **getCurrentApplicationContext(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) --- # getCurrentAsyncContextManager ### Callable * **getCurrentAsyncContextManager(): [AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) --- # getCurrentMainApp ### Callable * **getCurrentMainApp\(): APP *** * #### Type parameters * **APP**: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)> --- # getCurrentMainFramework ### Callable * **getCurrentMainFramework\(): [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)\ *** * #### Type parameters * **APP**: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)\ * **CTX**: [Context](/api/3.0.0/core/interface/Context.md) * **CONFIG**: [IConfigurationOptions](/api/3.0.0/core/interface/IConfigurationOptions.md) --- # getMethodParamTypes ### Callable * **getMethodParamTypes(target: any, methodName: string | symbol): any *** * get parameters type by reflect-metadata --- # getMethodReturnTypes ### Callable * **getMethodReturnTypes(target: any, methodName: string | symbol): any *** * get method return type from metadata --- # getObjectDefinition ### Callable * **getObjectDefinition(target: any): [ObjectDefinitionOptions](/api/3.0.0/core/interface/ObjectDefinitionOptions.md) *** * get class object definition from metadata --- # getPropertyDataFromClass ### Callable * **getPropertyDataFromClass\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data from class *** #### Type parameters * **T** = any --- # getPropertyInject ### Callable * **getPropertyInject(target: any, useCache? : boolean): {} *** * get property inject args --- # getPropertyMetadata ### Callable * **getPropertyMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data *** #### Type parameters * **T** = any --- # getPropertyType ### Callable * **getPropertyType(target: any, methodName: string | symbol): [TSDesignType](/api/3.0.0/core/interface/TSDesignType.md)\ *** * get property(method) type from metadata --- # getProviderId ### Callable * **getProviderId(module: any): string *** * get provider id from module --- # getProviderName ### Callable * **getProviderName(module: any): string --- # getProviderUUId ### Callable * **getProviderUUId(module: any): string *** * get provider uuid from module --- # GrpcMethod ### Callable * **GrpcMethod(methodOptions? : { methodName? : string; onEnd? : string; type? : [GrpcStreamTypeEnum](/api/3.0.0/core/enum/GrpcStreamTypeEnum.md) }): MethodDecorator --- # Guard ### Callable * **Guard(): ClassDecorator --- # Head ### Callable * **Head(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP HEAD requests to the specified path. --- # Headers ### Callable * **Headers(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # HSF ### Callable * **HSF(hsfOption? : [HSFOpts](/api/3.0.0/core/interface/HSFOpts.md)): ClassDecorator *** * * **@Deprecated** --- # HttpCode ### Callable * **HttpCode(code: number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Init ### Callable * **Init(): MethodDecorator --- # initializeGlobalApplicationContext ### Callable * **initializeGlobalApplicationContext(globalOptions: [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)): Promise<[IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)> *** * midway framework main entry, this method bootstrap all service and framework. --- # Inject ### Callable * **Inject(identifier? : [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): (target: any, targetKey: string) => void --- # InjectClient ### Callable * **InjectClient(serviceFactoryClz: new (...args: any\[]) => [IServiceFactory](/api/3.0.0/core/interface/IServiceFactory.md)\, clientName? : string): PropertyDecorator --- # isProvide ### Callable * **isProvide(target: any): boolean *** * use * **@Provide** decorator or not --- # isTypeScriptEnvironment ### Callable * **isTypeScriptEnvironment(): boolean --- # KafkaListener ### Callable * **KafkaListener(topic: string, options? : [KafkaListenerOptions](/api/3.0.0/core/interface/KafkaListenerOptions.md)): MethodDecorator --- # listModule ### Callable * **listModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), filter? : (module: any) => boolean): any\[] *** * list module from decorator key --- # listPreloadModule ### Callable * **listPreloadModule(): any\[] *** * list preload module --- # listPropertyDataFromClass ### Callable * **listPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any\[] *** * list property data from class --- # loadModule ### Callable * **loadModule(p: string, options? : { enableCache? : boolean; loadMode? : commonjs | esm; safeLoad? : boolean }): Promise\ *** * load module, and it can be chosen commonjs or esm mode * **@since** 3.12.0 --- # Logger ### Callable * **Logger(identifier? : string): PropertyDecorator --- # makeHttpRequest ### Callable * **makeHttpRequest\(url: string, options? : [HttpClientOptions](/api/3.0.0/core/interface/HttpClientOptions.md)\): Promise<[HttpClientResponse](/api/3.0.0/core/interface/HttpClientResponse.md)\> *** * #### Type parameters * **ResType** --- # Match ### Callable * **Match(matchPattern? : [MatchPattern](/api/3.0.0/core.md#MatchPattern)\): (target: any) => void --- # Middleware ### Callable * **Middleware(): ClassDecorator --- # Mock ### Callable * **Mock(): ClassDecorator --- # OnConnection ### Callable * **OnConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSConnection** --- # OnDisConnection ### Callable * **OnDisConnection(): MethodDecorator *** * * **@deprecated** please use * **@OnWSDisConnection** --- # OnMessage ### Callable * **OnMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSMessage** --- # OnWSConnection ### Callable * **OnWSConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) }): MethodDecorator --- # OnWSDisConnection ### Callable * **OnWSDisConnection(): MethodDecorator --- # OnWSMessage ### Callable * **OnWSMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) }): MethodDecorator --- # Options ### Callable * **Options(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP OPTIONS requests to the specified path. --- # Param ### Callable * **Param(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Patch ### Callable * **Patch(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PATCH requests to the specified path. --- # pathMatching ### Callable * **pathMatching(options: { ignore? : [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\\[]; match? : [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\\[]; thisResolver? : any }): (ctx? : any) => boolean --- # Pipe ### Callable * **Pipe(): ClassDecorator --- # Pipeline ### Callable * **Pipeline(valves? : ([ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier) | new (...args: any\[]) => any)\[]): PropertyDecorator --- # Plugin ### Callable * **Plugin(identifier? : string): PropertyDecorator --- # Post ### Callable * **Post(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP POST requests to the specified path. --- # prepareGlobalApplicationContext ### Callable * **prepareGlobalApplicationContext(globalOptions: [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)): [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) | [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) *** * prepare applicationContext, it use in egg framework, hooks and serverless function generator --- # prepareGlobalApplicationContextAsync ### Callable * **prepareGlobalApplicationContextAsync(globalOptions: [IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)): Promise<[MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) | [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)> *** * prepare applicationContext --- # Provide ### Callable * **Provide(identifier? : [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): (target: any) => any --- # Provider ### Callable * **Provider(type: GRPC, metadata? : [ProviderOptions](/api/3.0.0/core/namespace/GRPCMetadata.md#ProviderOptions)): ClassDecorator * **Provider(type: DUBBO, metadata? : any): ClassDecorator --- # providerWrapper ### Callable * **providerWrapper(wrapperInfo: { id: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier); provider: (context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), args? : any) => any; scope? : [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) }\[]): void --- # Put ### Callable * **Put(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PUT requests to the specified path. --- # Queries ### Callable * **Queries(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Query ### Callable * **Query(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Queue ### Callable * **Queue(options? : any): ClassDecorator --- # RabbitMQListener ### Callable * **RabbitMQListener(queueName: string, options? : [RabbitMQListenerOptions](/api/3.0.0/core/interface/RabbitMQListenerOptions.md)): MethodDecorator --- # Redirect ### Callable * **Redirect(url: string, code? : number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # registerErrorCode ### Callable * **registerErrorCode\(errorGroup: G, errorCodeMapping: T): ConvertString\ *** * Register error group and code, return the standard ErrorCode *** #### Type parameters * **T**: Convertable * **G**: string --- # RequestIP ### Callable * **RequestIP(pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # RequestMapping ### Callable * **RequestMapping(metadata? : [RouterOption](/api/3.0.0/core/interface/RouterOption.md)): MethodDecorator --- # RequestPath ### Callable * **RequestPath(pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # resetModule ### Callable * **resetModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): void *** * reset module --- # retryWith ### Callable * **retryWith\(retryFn: T, retryTimes? : number, options? : { receiver? : any; throwOriginError? : boolean }): (...args: Parameters\) => ReturnType\ *** * wrap sync function with retry *** #### Type parameters * **T**: (...args: any\[]) => unknown --- # retryWithAsync ### Callable * **retryWithAsync\(retryFn: T, retryTimes? : number, options? : { receiver? : any; retryInterval? : number; throwOriginError? : boolean }): (...args: Parameters\) => ReturnType\ *** * wrap async function with retry *** #### Type parameters * **T**: (...args: any\[]) => Promise\ --- # safelyGet ### Callable * **safelyGet(list: string | string\[], obj? : Record\): any *** * * **@example** ``` safelyGet(['a','b'],{a: {b: 2}}) // => 2 safelyGet(['a','b'],{c: {b: 2}}) // => undefined safelyGet(['a','1'],{a: {"1": 2}}) // => 2 safelyGet(['a','1'],{a: {b: 2}}) // => undefined safelyGet('a.b',{a: {b: 2}}) // => 2 safelyGet('a.b',{c: {b: 2}}) // => undefined ``` * **@since** 2.0.0 --- # safeRequire ### Callable * **safeRequire(p: any, enabledCache? : boolean): any *** * * **@since** 2.0.0 --- # saveClassMetadata ### Callable * **saveClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, mergeIfExist? : boolean): void *** * save data to class --- # saveModule ### Callable * **saveModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any *** * save module to inner map --- # saveObjectDefinition ### Callable * **saveObjectDefinition(target: any, props? : {}): any *** * save class object definition --- # savePreloadModule ### Callable * **savePreloadModule(target: any): any *** * save preload module by target --- # savePropertyDataToClass ### Callable * **savePropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data to class --- # savePropertyInject ### Callable * **savePropertyInject(opts: { args? : any; identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier); target: any; targetKey: string }): void *** * save property inject args --- # savePropertyMetadata ### Callable * **savePropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data --- # saveProviderId ### Callable * **saveProviderId(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any *** * class provider id --- # Schedule ### Callable * **Schedule(scheduleOpts: string | [ScheduleOpts](/api/3.0.0/core/interface/ScheduleOpts.md)): (target: any) => void --- # Scope ### Callable * **Scope(scope: [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md), scopeOptions? : { allowDowngrade? : boolean }): ClassDecorator --- # ServerlessFunction ### Callable * **ServerlessFunction(options: [ServerlessFunctionOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions) & Record\): MethodDecorator --- # ServerlessTrigger ### Callable * **ServerlessTrigger(type: HTTP, metadata: [HTTPTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HTTPTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: OS, metadata: [OSTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#OSTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: LOG, metadata: [LogTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#LogTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: TIMER, metadata: [TimerTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#TimerTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MQ, metadata: [MQTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MQTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: CDN, metadata? : [CDNTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#CDNTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: API\_GATEWAY, metadata? : [APIGatewayTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: HSF, metadata? : [HSFTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HSFTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MTOP, metadata? : [MTopTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MTopTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: SSR, metadata? : [SSRTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#SSRTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: EVENT, metadata? : [EventTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: string, metadata? : [EventTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerOptions) & Record\): MethodDecorator --- # Session ### Callable * **Session(propertyOrPipes? : string | [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # SetHeader ### Callable * **SetHeader(headerKey: string | Record\, value? : string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Singleton ### Callable * **Singleton(): ClassDecorator --- # sleep ### Callable * **sleep(sleepTime? : number): Promise\ --- # Task ### Callable * **Task(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # TaskLocal ### Callable * **TaskLocal(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # transformRequestObjectByType ### Callable * **transformRequestObjectByType(originValue: any, targetType? : any): any *** * transform request object to definition type * **@since** 3.0.0 --- # transformTypeFromTSDesign ### Callable * **transformTypeFromTSDesign(designFn: any): [TSDesignType](/api/3.0.0/core/interface/TSDesignType.md) --- # UseGuard ### Callable * **UseGuard(guardOrArr: [CommonGuardUnion](/api/3.0.0/core.md#CommonGuardUnion)): ClassDecorator & MethodDecorator --- # wrapAsync ### Callable * **wrapAsync(handler: any): (...args: any\[]) => any --- # wrapMiddleware ### Callable * **wrapMiddleware(mw: (context: any, next: any, options? : any) => any, options: any): (context: any, next: any, options? : any) => any *** * wrap function middleware with match and ignore --- # WSBroadCast ### Callable * **WSBroadCast(messageName? : string, roomName? : string | string\[]): MethodDecorator --- # WSController ### Callable * **WSController(namespace? : string | RegExp, routerOptions? : { connectionMiddleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) }): ClassDecorator --- # WSEmit ### Callable * **WSEmit(messageName: string, roomName? : string | string\[]): MethodDecorator --- # AspectMetadata ## Index[**](#Index) ### Properties * [**aspectTarget](#aspectTarget) * [**match](#match) * [**priority](#priority) ## Properties[**](#Properties) ### [**](#aspectTarget)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L330)aspectTarget **aspectTarget: any ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L331)optionalmatch **match? : string | () => boolean ### [**](#priority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L332)optionalpriority **priority? : number --- # AsyncContext ## Index[**](#Index) ### Methods * [**deleteValue](#deleteValue) * [**getValue](#getValue) * [**setValue](#setValue) ## Methods[**](#Methods) ### [**](#deleteValue)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L40)deleteValue * **deleteValue(key: symbol): [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) - Return a new context which inherits from this context but does not contain a value for the given key. ### [**](#getValue)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L23)getValue * **getValue(key: symbol): unknown - Get a value from the context. ### [**](#setValue)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L32)setValue * **setValue(key: symbol, value: unknown): [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) - Create a new context which inherits from this context and has the given key set to the given value. --- # AsyncContextManager ## Index[**](#Index) ### Methods * [**active](#active) * [**bind](#bind) * [**disable](#disable) * [**enable](#enable) * [**with](#with) ## Methods[**](#Methods) ### [**](#active)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L47)active * **active(): [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md) - Get the current active context ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L68)bind * **bind\(context? : [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md), target: T): T - Bind an object as the current context (or a specific one) *** #### Type parameters * **T** ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L78)disable * **disable(): [AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) - Disable context management ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L73)enable * **enable(): [AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) - Enable context management ### [**](#with)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/common/asyncContextManager.ts#L56)with * **with\(context: [AsyncContext](/api/3.0.0/core/interface/AsyncContext.md), fn: F, thisArg? : ThisParameterType\, ...args: A): ReturnType\ - Run the fn callback with object set as the current active context *** #### Type parameters * **A**: unknown\[] * **F**: (...args: A) => ReturnType\ --- # CommonSchedule ## Index[**](#Index) ### Methods * [**exec](#exec) ## Methods[**](#Methods) ### [**](#exec)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L11)exec * **exec(ctx? : any): any --- # Context ## Index[**](#Index) ### Properties * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L832)logger **logger: [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L831)requestContext **requestContext: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Custom properties. ### [**](#startTime)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L834)startTime **startTime: number ## Methods[**](#Methods) ### [**](#getApp)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L849)getApp * **getApp(): [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)> - Get current related application instance. ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L845)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L833)getLogger * **getLogger(name? : string): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L840)setAttr * **setAttr(key: string, value: any): any - Set value to app attribute map --- # ControllerOption ## Index[**](#Index) ### Properties * [**prefix](#prefix) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/controller.ts#L11)prefix **prefix: string ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/controller.ts#L12)optionalrouterOptions **routerOptions? : { alias? : string\[]; description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string } --- # HealthResult ## Index[**](#Index) ### Properties * [**reason](#reason) * [**status](#status) ## Properties[**](#Properties) ### [**](#reason)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1213)optionalreason **reason? : string failed reason ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1209)status **status: boolean health status --- # HealthResults ## Index[**](#Index) ### Properties * [**namespace](#namespace) * [**reason](#reason) * [**results](#results) * [**status](#status) ## Properties[**](#Properties) ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1224)namespace **namespace: string first failed namespace ### [**](#reason)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1228)optionalreason **reason? : string first failed reason ### [**](#results)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1229)optionalresults **results? : { namespace: string; reason? : string; status: boolean }\[] ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1220)status **status: boolean health status --- # HSFOpts ## Index[**](#Index) ### Properties * [**group](#group) * [**interfaceName](#interfaceName) * [**namespace](#namespace) * [**version](#version) ## Properties[**](#Properties) ### [**](#group)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/rpc/hsf.ts#L7)optionalgroup **group? : string ### [**](#interfaceName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/rpc/hsf.ts#L5)optionalinterfaceName **interfaceName? : string ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/rpc/hsf.ts#L8)optionalnamespace **namespace? : string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/rpc/hsf.ts#L6)optionalversion **version? : string --- # HttpClientOptions \ ### Hierarchy * RequestOptions * *HttpClientOptions* ## Index[**](#Index) ### Properties * [**contentType](#contentType) * [**data](#data) * [**dataType](#dataType) * [**headers](#headers) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#contentType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L19)optionalcontentType **contentType? : [HttpClientMimeType](/api/3.0.0/core.md#HttpClientMimeType) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L21)optionaldata **data? : Data ### [**](#dataType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L20)optionaldataType **dataType? : [HttpClientMimeType](/api/3.0.0/core.md#HttpClientMimeType) ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L18)optionalheaders **headers? : any Overrides https.RequestOptions.headers ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L22)optionaltimeout **timeout? : number Overrides https.RequestOptions.timeout --- # HttpClientResponse \ ### Hierarchy * IncomingMessage * *HttpClientResponse* ## Index[**](#Index) ### Properties * [**data](#data) * [**status](#status) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L28)data **data: string | Buffer\ | ResType ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/util/httpclient.ts#L27)status **status: number --- # IComponentInfo ## Index[**](#Index) ### Properties * [**component](#component) * [**enabledEnvironment](#enabledEnvironment) ## Properties[**](#Properties) ### [**](#component)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L5)component **component: any ### [**](#enabledEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L6)optionalenabledEnvironment **enabledEnvironment? : string\[] --- # IConfigService ### Implemented by * [MidwayConfigService](/api/3.0.0/core/class/MidwayConfigService.md) ## Index[**](#Index) ### Methods * [**add](#add) * [**addObject](#addObject) * [**clearAllConfig](#clearAllConfig) * [**getConfiguration](#getConfiguration) * [**load](#load) ## Methods[**](#Methods) ### [**](#add)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L800)add * **add(configFilePaths: any\[]): any ### [**](#addObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L801)addObject * **addObject(obj: object, reverse? : boolean): any ### [**](#clearAllConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L804)clearAllConfig * **clearAllConfig(): any ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L803)getConfiguration * **getConfiguration(configKey? : string): any ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L802)load * **load(): any --- # IConfigurationOptions ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1121)optionalappLogger **appLogger? : [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#contextLoggerApplyLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1122)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string ### [**](#contextLoggerFormat)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1123)optionalcontextLoggerFormat **contextLoggerFormat? : any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1120)optionallogger **logger? : [ILogger](/api/3.0.0/core/interface/ILogger.md) --- # IEnvironmentService ### Implemented by * [MidwayEnvironmentService](/api/3.0.0/core/class/MidwayEnvironmentService.md) ## Index[**](#Index) ### Methods * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getModuleLoadType](#getModuleLoadType) * [**isDevelopmentEnvironment](#isDevelopmentEnvironment) ## Methods[**](#Methods) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L817)getCurrentEnvironment * **getCurrentEnvironment(): string ### [**](#getModuleLoadType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L819)getModuleLoadType * **getModuleLoadType(): [ModuleLoadType](/api/3.0.0/core.md#ModuleLoadType) ### [**](#isDevelopmentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L818)isDevelopmentEnvironment * **isDevelopmentEnvironment(): boolean --- # IFileDetector ### Implemented by * [AbstractFileDetector](/api/3.0.0/core/class/AbstractFileDetector.md) ## Index[**](#Index) ### Methods * [**run](#run) * [**setExtraDetectorOptions](#setExtraDetectorOptions) ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L795)run * **run(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), fileDetectorOptions? : Record\): void | Promise\ ### [**](#setExtraDetectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L796)setExtraDetectorOptions * **setExtraDetectorOptions(detectorOptions: Record\): any --- # IFilter \ Common Exception Filter definition ## Index[**](#Index) ### Methods * [**catch](#catch) * [**match](#match) ## Methods[**](#Methods) ### [**](#catch)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L903)optionalcatch * **catch(err: Error, ctx: CTX, res? : R, next? : N): any ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L904)optionalmatch * **match(result: any, ctx: CTX, res? : R, next? : N): any --- # IGuard \ Guard definition ## Index[**](#Index) ### Methods * [**canActivate](#canActivate) ## Methods[**](#Methods) ### [**](#canActivate)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L914)canActivate * **canActivate(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): boolean | Promise\ --- # IIdentifierRelationShip ## Index[**](#Index) ### Methods * [**getRelation](#getRelation) * [**hasRelation](#hasRelation) * [**saveClassRelation](#saveClassRelation) * [**saveFunctionRelation](#saveFunctionRelation) ## Methods[**](#Methods) ### [**](#getRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L747)getRelation * **getRelation(id: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): string ### [**](#hasRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L746)hasRelation * **hasRelation(id: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean ### [**](#saveClassRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L744)saveClassRelation * **saveClassRelation(module: any, namespace? : string): any ### [**](#saveFunctionRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L745)saveFunctionRelation * **saveFunctionRelation(ObjectIdentifier: any, uuid: any): any --- # IInformationService ### Implemented by * [MidwayInformationService](/api/3.0.0/core/class/MidwayInformationService.md) ## Index[**](#Index) ### Methods * [**getAppDir](#getAppDir) * [**getBaseDir](#getBaseDir) * [**getHome](#getHome) * [**getPkg](#getPkg) * [**getProjectName](#getProjectName) * [**getRoot](#getRoot) ## Methods[**](#Methods) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L811)getAppDir * **getAppDir(): string ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L810)getBaseDir * **getBaseDir(): string ### [**](#getHome)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L812)getHome * **getHome(): string ### [**](#getPkg)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L808)getPkg * **getPkg(): any ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L809)getProjectName * **getProjectName(): any ### [**](#getRoot)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L813)getRoot * **getRoot(): string --- # ILifeCycle Lifecycle Definition 生命周期定义 ### Hierarchy * Partial<[IObjectLifeCycle](/api/3.0.0/core/interface/IObjectLifeCycle.md)> * *ILifeCycle* ## Index[**](#Index) ### Methods * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onConfigLoad](#onConfigLoad) * [**onHealthCheck](#onHealthCheck) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**onReady](#onReady) * [**onServerReady](#onServerReady) * [**onStop](#onStop) ## Methods[**](#Methods) ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L601)optionalonBeforeBind * **onBeforeBind(Clzz: any, options: [ObjectBeforeBindOptions](/api/3.0.0/core/interface/ObjectBeforeBindOptions.md)): void - Inherited from Partial.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L602)optionalonBeforeObjectCreated * **onBeforeObjectCreated(Clzz: any, options: [ObjectBeforeCreatedOptions](/api/3.0.0/core/interface/ObjectBeforeCreatedOptions.md)): void - Inherited from Partial.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L605)optionalonBeforeObjectDestroy * **onBeforeObjectDestroy\(ins: T, options: [ObjectBeforeDestroyOptions](/api/3.0.0/core/interface/ObjectBeforeDestroyOptions.md)): void - Inherited from Partial.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onConfigLoad)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L514)optionalonConfigLoad * **onConfigLoad(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), mainApp? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L526)optionalonHealthCheck * **onHealthCheck(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): Promise<[HealthResult](/api/3.0.0/core/interface/HealthResult.md)> ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L603)optionalonObjectCreated * **onObjectCreated\(ins: T, options: [ObjectCreatedOptions](/api/3.0.0/core/interface/ObjectCreatedOptions.md)\): void - Inherited from Partial.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L604)optionalonObjectInit * **onObjectInit\(ins: T, options: [ObjectInitOptions](/api/3.0.0/core/interface/ObjectInitOptions.md)): void - Inherited from Partial.onObjectInit #### Type parameters * **T** ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L518)optionalonReady * **onReady(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), mainApp? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L522)optionalonServerReady * **onServerReady(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), mainApp? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L529)optionalonStop * **onStop(container: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md), mainApp? : [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ --- # ILogger Logger Options for midway, you can merge this interface in package * **@example** ``` import { IMidwayLogger } from '@midwayjs/logger'; declare module '@midwayjs/core/dist/interface' { interface ILogger extends IMidwayLogger { } } ``` ## Index[**](#Index) ### Methods * [**debug](#debug) * [**error](#error) * [**info](#info) * [**warn](#warn) ## Methods[**](#Methods) ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L417)debug * **debug(msg: any, ...args: any\[]): void ### [**](#error)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L418)error * **error(msg: any, ...args: any\[]): void ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L416)info * **info(msg: any, ...args: any\[]): void ### [**](#warn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L419)warn * **warn(msg: any, ...args: any\[]): void --- # IManagedInstance 内部管理的属性、json、ref等解析实例存储 ## Index[**](#Index) ### Properties * [**args](#args) * [**type](#type) * [**value](#value) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L72)optionalargs **args? : any ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L70)type **type: string ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L71)optionalvalue **value? : any --- # IManagedResolver 解析内部管理的属性、json、ref等实例的解析器 同时创建这些对象的实际使用的对象 ## Index[**](#Index) ### Properties * [**type](#type) ### Methods * [**resolve](#resolve) * [**resolveAsync](#resolveAsync) ## Properties[**](#Properties) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L705)type **type: string ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L706)resolve * **resolve(managed: [IManagedInstance](/api/3.0.0/core/interface/IManagedInstance.md)): any ### [**](#resolveAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L707)resolveAsync * **resolveAsync(managed: [IManagedInstance](/api/3.0.0/core/interface/IManagedInstance.md)): Promise\ --- # IManagedResolverFactoryCreateOptions ## Index[**](#Index) ### Properties * [**args](#args) * [**definition](#definition) * [**namespace](#namespace) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L712)optionalargs **args? : any ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L711)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L713)optionalnamespace **namespace? : string --- # IMethodAspect ## Index[**](#Index) ### Methods * [**after](#after) * [**afterReturn](#afterReturn) * [**afterThrow](#afterThrow) * [**around](#around) * [**before](#before) ## Methods[**](#Methods) ### [**](#after)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L336)optionalafter * **after(joinPoint: [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md), result: any, error: Error): any ### [**](#afterReturn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L337)optionalafterReturn * **afterReturn(joinPoint: [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md), result: any): any ### [**](#afterThrow)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L338)optionalafterThrow * **afterThrow(joinPoint: [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md), error: Error): void ### [**](#around)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L340)optionalaround * **around(joinPoint: [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md)): any ### [**](#before)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L339)optionalbefore * **before(joinPoint: [JoinPoint](/api/3.0.0/core/interface/JoinPoint.md)): void --- # IMiddleware \ Common middleware definition ## Index[**](#Index) ### Properties * [**ignore](#ignore) * [**match](#match) * [**resolve](#resolve) ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L870)optionalignore **ignore? : [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\\[] Match those paths with higher priority than ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L866)optionalmatch **match? : [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/3.0.0/core.md#IgnoreMatcher)\\[] Which paths to ignore ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L862)resolve **resolve: (app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>, options? : any) => [FunctionMiddleware](/api/3.0.0/core.md#FunctionMiddleware)\ | Promise<[FunctionMiddleware](/api/3.0.0/core.md#FunctionMiddleware)\> --- # IMiddlewareManager \ ### Implemented by * [ContextMiddlewareManager](/api/3.0.0/core/class/ContextMiddlewareManager.md) ## Index[**](#Index) ### Methods * [**findAndInsertAfter](#findAndInsertAfter) * [**findAndInsertBefore](#findAndInsertBefore) * [**findAndInsertFirst](#findAndInsertFirst) * [**findAndInsertLast](#findAndInsertLast) * [**findItem](#findItem) * [**findItemIndex](#findItemIndex) * [**getMiddlewareName](#getMiddlewareName) * [**getNames](#getNames) * [**insertAfter](#insertAfter) * [**insertBefore](#insertBefore) * [**insertFirst](#insertFirst) * [**insertLast](#insertLast) * [**push](#push) * [**remove](#remove) * [**unshift](#unshift) ## Methods[**](#Methods) ### [**](#findAndInsertAfter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L932)findAndInsertAfter * **findAndInsertAfter(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\, afterMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#findAndInsertBefore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L936)findAndInsertBefore * **findAndInsertBefore(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\, beforeMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#findAndInsertFirst)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L940)findAndInsertFirst * **findAndInsertFirst(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#findAndInsertLast)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L943)findAndInsertLast * **findAndInsertLast(middlewareOrName: string | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#findItem)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L949)findItem * **findItem(middlewareOrName: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\ ### [**](#findItemIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L946)findItemIndex * **findItemIndex(middlewareOrName: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): number ### [**](#getMiddlewareName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L952)getMiddlewareName * **getMiddlewareName(middleware: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): string ### [**](#getNames)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L958)getNames * **getNames(): string\[] ### [**](#insertAfter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L928)insertAfter * **insertAfter(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\, idxOrAfterMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#insertBefore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L924)insertBefore * **insertBefore(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\, idxOrBeforeMiddleware: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): void ### [**](#insertFirst)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L922)insertFirst * **insertFirst(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void ### [**](#insertLast)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L923)insertLast * **insertLast(middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void ### [**](#push)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L956)push * **push(...items: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\\[]): number ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L953)remove * **remove(middlewareOrNameOrIdx: string | number | [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\): [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\ ### [**](#unshift)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L957)unshift * **unshift(...items: [CommonMiddleware](/api/3.0.0/core.md#CommonMiddleware)\\[]): number --- # IMidwayBaseApplication \ ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1043)addConfigObject * **addConfigObject(obj: any): any - Add new value to current config ### [**](#createAnonymousContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1031)createAnonymousContext * **createAnonymousContext(...args: any\[]): CTX - create a context with RequestContainer ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1020)createLogger * **createLogger(name: string, options: [MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Create a logger by name and options ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L970)getAppDir * **getAppDir(): string - Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L996)getApplicationContext * **getApplicationContext(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) - Get global Midway IoC Container ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1056)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L965)getBaseDir * **getBaseDir(): string - Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1002)getConfig * **getConfig(key? : string): any - Get all configuration values or get the specified configuration through parameters ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1013)getCoreLogger * **getCoreLogger(): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Get core logger ### [**](#getEnv)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L975)getEnv * **getEnv(): string - Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L980)getFramework * **getFramework(): [IMidwayFramework](/api/3.0.0/core/interface/IMidwayFramework.md)<[IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)\, CTX, unknown, unknown, unknown> - get current related framework ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L986)getFrameworkType * **getFrameworkType(): [FrameworkType](/api/3.0.0/core/class/FrameworkType.md) - - **@deprecated** Get current framework type in MidwayFrameworkType enum ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1008)getLogger * **getLogger(name? : string): [ILogger](/api/3.0.0/core/interface/ILogger.md) - Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1067)getMiddleware * **getMiddleware\(): [IMiddlewareManager](/api/3.0.0/core/interface/IMiddlewareManager.md)\ - get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1084)getNamespace * **getNamespace(): string - get current namespace ### [**](#getProcessType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L991)getProcessType * **getProcessType(): [MidwayProcessTypeEnum](/api/3.0.0/core/enum/MidwayProcessTypeEnum.md) - Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1025)getProjectName * **getProjectName(): string - Get project name, just package.json name ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1050)setAttr * **setAttr(key: string, value: any): any - Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1037)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1073)useFilter * **useFilter\(Filter: [CommonFilterUnion](/api/3.0.0/core.md#CommonFilterUnion)\): void - add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1079)useGuard * **useGuard(guard: [CommonGuardUnion](/api/3.0.0/core.md#CommonGuardUnion)\): void - add global guard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1062)useMiddleware * **useMiddleware\(Middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void - add global filter to app *** #### Type parameters * **R** * **N** --- # IMidwayBootstrapOptions ### Indexable **\[customPropertyKey : string]: any ## Index[**](#Index) ### Properties * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**asyncContextManager](#asyncContextManager) * [**baseDir](#baseDir) * [**configurationModule](#configurationModule) * [**globalConfig](#globalConfig) * [**ignore](#ignore) * [**imports](#imports) * [**logger](#logger) * [**loggerFactory](#loggerFactory) * [**moduleDetector](#moduleDetector) * [**moduleLoadType](#moduleLoadType) * [**preloadModules](#preloadModules) ## Properties[**](#Properties) ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1097)optionalappDir **appDir? : string ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1098)optionalapplicationContext **applicationContext? : [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1115)optionalasyncContextManager **asyncContextManager? : [AsyncContextManager](/api/3.0.0/core/interface/AsyncContextManager.md) ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1096)optionalbaseDir **baseDir? : string ### [**](#configurationModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1103)optionalconfigurationModule **configurationModule? : any * **@deprecated** please use 'imports' ### [**](#globalConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1112)optionalglobalConfig **globalConfig? : Record\ | {}\[] ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1111)optionalignore **ignore? : string\[] * **@deprecated** please set it from '@Configuration' decorator ### [**](#imports)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1104)optionalimports **imports? : any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1107)optionallogger **logger? : boolean | [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#loggerFactory)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1116)optionalloggerFactory **loggerFactory? : [LoggerFactory](/api/3.0.0/core/class/LoggerFactory.md)\ ### [**](#moduleDetector)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1106)optionalmoduleDetector **moduleDetector? : false | [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md) ### [**](#moduleLoadType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1105)optionalmoduleLoadType **moduleLoadType? : [ModuleLoadType](/api/3.0.0/core.md#ModuleLoadType) ### [**](#preloadModules)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1099)optionalpreloadModules **preloadModules? : any\[] --- # IMidwayContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * [IObjectFactory](/api/3.0.0/core/interface/IObjectFactory.md) * [WithFn](/api/3.0.0/core.md#WithFn)<[IObjectLifeCycle](/api/3.0.0/core/interface/IObjectLifeCycle.md)> * *IMidwayContainer* ### Implemented by * [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) ## Index[**](#Index) ### Properties * [**identifierMapping](#identifierMapping) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**parent](#parent) * [**registry](#registry) ### Methods * [**bind](#bind) * [**bindClass](#bindClass) * [**createChild](#createChild) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getInstanceScope](#getInstanceScope) * [**getNamespaceList](#getNamespaceList) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**load](#load) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**ready](#ready) * [**registerObject](#registerObject) * [**setAttr](#setAttr) * [**setFileDetector](#setFileDetector) * [**stop](#stop) ## Properties[**](#Properties) ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L752)identifierMapping **identifierMapping: [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L753)objectCreateEventTarget **objectCreateEventTarget: EventEmitter\ ### [**](#parent)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L751)parent **parent: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L544)registry **registry: [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md) Inherited from IObjectFactory.registry ## Methods[**](#Methods) ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L762)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L763)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void * **bind\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): void - #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L768)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)>): any ### [**](#createChild)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L770)createChild * **createChild(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L545)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L550)get * **get\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T * **get\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T - Inherited from IObjectFactory.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L555)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L560)getAsync * **getAsync\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ * **getAsync\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ - Inherited from IObjectFactory.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L781)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L786)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) - Get instance IoC container scope ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L759)getNamespaceList * **getNamespaceList(): string\[] ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L760)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): any ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L758)hasNamespace * **hasNamespace(namespace: string): boolean ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L761)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): any ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L757)load * **load(module: any): any ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L601)onBeforeBind * **onBeforeBind(fn: (...args: \[Clzz: any, options: [ObjectBeforeBindOptions](/api/3.0.0/core/interface/ObjectBeforeBindOptions.md)]) => void): void - Inherited from WithFn.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L602)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (...args: \[Clzz: any, options: [ObjectBeforeCreatedOptions](/api/3.0.0/core/interface/ObjectBeforeCreatedOptions.md)]) => void): void - Inherited from WithFn.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L605)onBeforeObjectDestroy * **onBeforeObjectDestroy(fn: (...args: \[ins: unknown, options: [ObjectBeforeDestroyOptions](/api/3.0.0/core/interface/ObjectBeforeDestroyOptions.md)]) => void): void - Inherited from WithFn.onBeforeObjectDestroy ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L603)onObjectCreated * **onObjectCreated(fn: (...args: \[ins: unknown, options: [ObjectCreatedOptions](/api/3.0.0/core/interface/ObjectCreatedOptions.md)\]) => void): void - Inherited from WithFn.onObjectCreated ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L604)onObjectInit * **onObjectInit(fn: (...args: \[ins: unknown, options: [ObjectInitOptions](/api/3.0.0/core/interface/ObjectInitOptions.md)]) => void): void - Inherited from WithFn.onObjectInit ### [**](#ready)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L754)ready * **ready(): void | Promise\ ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L756)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L776)setAttr * **setAttr(key: string, value: any): any - Set value to app attribute map ### [**](#setFileDetector)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L769)setFileDetector * **setFileDetector(fileDetector: [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md)): any ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L755)stop * **stop(): Promise\ --- # IMidwayFramework \ ### Implemented by * [BaseFramework](/api/3.0.0/core/class/BaseFramework.md) ## Index[**](#Index) ### Properties * [**app](#app) * [**configurationOptions](#configurationOptions) ### Methods * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1133)app **app: APP ### [**](#configurationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1134)configurationOptions **configurationOptions: CONFIG ## Methods[**](#Methods) ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1153)applyMiddleware * **applyMiddleware(lastMiddleware? : [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): Promise<[MiddlewareRespond](/api/3.0.0/core.md#MiddlewareRespond)\> ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1135)configure * **configure(options? : CONFIG): any ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1149)createLogger * **createLogger(name: string, options: [MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1145)getAppDir * **getAppDir(): string ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1140)getApplication * **getApplication(): APP ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1141)getApplicationContext * **getApplicationContext(): [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1146)getBaseDir * **getBaseDir(): string ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1142)getConfiguration * **getConfiguration(key? : string): any ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1148)getCoreLogger * **getCoreLogger(): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1143)getCurrentEnvironment * **getCurrentEnvironment(): string ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1144)getFrameworkName * **getFrameworkName(): string ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1147)getLogger * **getLogger(name? : string): [ILogger](/api/3.0.0/core/interface/ILogger.md) ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1152)getMiddleware * **getMiddleware(): [IMiddlewareManager](/api/3.0.0/core/interface/IMiddlewareManager.md)\ ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1159)getNamespace * **getNamespace(): string ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1150)getProjectName * **getProjectName(): string ### [**](#initialize)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1137)initialize * **initialize(options: Partial<[IMidwayBootstrapOptions](/api/3.0.0/core/interface/IMidwayBootstrapOptions.md)>): Promise\ ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1136)isEnable * **isEnable(): boolean ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1138)run * **run(): Promise\ ### [**](#runGuard)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1158)runGuard * **runGuard(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ ### [**](#setNamespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1160)setNamespace * **setNamespace(namespace: string): void ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1139)stop * **stop(): Promise\ ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1156)useFilter * **useFilter(Filter: [CommonFilterUnion](/api/3.0.0/core.md#CommonFilterUnion)\): void ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1157)useGuard * **useGuard(guard: [CommonGuardUnion](/api/3.0.0/core.md#CommonGuardUnion)\): void ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1151)useMiddleware * **useMiddleware(Middleware: [CommonMiddlewareUnion](/api/3.0.0/core.md#CommonMiddlewareUnion)\): void --- # IModuleStore ### Implemented by * [DecoratorManager](/api/3.0.0/core/class/DecoratorManager.md) * [MidwayContainer](/api/3.0.0/core/class/MidwayContainer.md) ## Index[**](#Index) ### Methods * [**listModule](#listModule) * [**saveModule](#saveModule) * [**transformModule](#transformModule) ## Methods[**](#Methods) ### [**](#listModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L344)listModule * **listModule(key: string): any ### [**](#saveModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L345)saveModule * **saveModule(key: string, module: any): any ### [**](#transformModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L346)optionaltransformModule * **transformModule(moduleMap: Map\>): any --- # InjectionConfigurationOptions ## Index[**](#Index) ### Properties * [**conflictCheck](#conflictCheck) * [**detector](#detector) * [**detectorOptions](#detectorOptions) * [**importConfigFilter](#importConfigFilter) * [**importConfigs](#importConfigs) * [**importObjects](#importObjects) * [**imports](#imports) * [**namespace](#namespace) ## Properties[**](#Properties) ### [**](#conflictCheck)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L25)optionalconflictCheck **conflictCheck? : boolean ### [**](#detector)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L23)optionaldetector **detector? : false | [IFileDetector](/api/3.0.0/core/interface/IFileDetector.md) ### [**](#detectorOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L24)optionaldetectorOptions **detectorOptions? : Record\ ### [**](#importConfigFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L21)optionalimportConfigFilter **importConfigFilter? : (config: Record\) => Record\ ### [**](#importConfigs)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L18)optionalimportConfigs **importConfigs? : Record\ | {}\[] ### [**](#importObjects)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L17)optionalimportObjects **importObjects? : Record\ ### [**](#imports)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L16)optionalimports **imports? : (string | [IComponentInfo](/api/3.0.0/core/interface/IComponentInfo.md) | { Configuration: any })\[] ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L22)optionalnamespace **namespace? : string --- # IObjectCreator ## Index[**](#Index) ### Methods * [**doConstruct](#doConstruct) * [**doConstructAsync](#doConstructAsync) * [**doDestroy](#doDestroy) * [**doDestroyAsync](#doDestroyAsync) * [**doInit](#doInit) * [**doInitAsync](#doInitAsync) * [**load](#load) ## Methods[**](#Methods) ### [**](#doConstruct)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L657)doConstruct * **doConstruct(Clzz: any, args? : any, context? : [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): any ### [**](#doConstructAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L658)doConstructAsync * **doConstructAsync(Clzz: any, args? : any, context? : [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md)): Promise\ ### [**](#doDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L665)doDestroy * **doDestroy(obj: any): void ### [**](#doDestroyAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L666)doDestroyAsync * **doDestroyAsync(obj: any): Promise\ ### [**](#doInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L663)doInit * **doInit(obj: any): void ### [**](#doInitAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L664)doInitAsync * **doInitAsync(obj: any): Promise\ ### [**](#load)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L656)load * **load(): any --- # IObjectDefinition Object Definition 对象描述定义 ## Index[**](#Index) ### Properties * [**allowDowngrade](#allowDowngrade) * [**bindHook](#bindHook) * [**constructMethod](#constructMethod) * [**constructorArgs](#constructorArgs) * [**createFrom](#createFrom) * [**creator](#creator) * [**dependsOn](#dependsOn) * [**destroyMethod](#destroyMethod) * [**export](#export) * [**handlerProps](#handlerProps) * [**id](#id) * [**initMethod](#initMethod) * [**name](#name) * [**namespace](#namespace) * [**path](#path) * [**properties](#properties) * [**scope](#scope) * [**srcPath](#srcPath) ### Methods * [**getAttr](#getAttr) * [**hasAttr](#hasAttr) * [**hasConstructorArgs](#hasConstructorArgs) * [**hasDependsOn](#hasDependsOn) * [**isAsync](#isAsync) * [**isRequestScope](#isRequestScope) * [**isSingletonScope](#isSingletonScope) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#allowDowngrade)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L651)allowDowngrade **allowDowngrade: boolean ### [**](#bindHook)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L652)optionalbindHook **bindHook? : (module: any, options? : [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)) => void ### [**](#constructMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L619)constructMethod **constructMethod: string ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L624)constructorArgs **constructorArgs: [IManagedInstance](/api/3.0.0/core/interface/IManagedInstance.md)\[] ### [**](#createFrom)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L650)createFrom **createFrom: framework | file | module ### [**](#creator)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L614)creator **creator: [IObjectCreator](/api/3.0.0/core/interface/IObjectCreator.md) ### [**](#dependsOn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L623)dependsOn **dependsOn: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)\[] ### [**](#destroyMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L618)destroyMethod **destroyMethod: string ### [**](#export)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L622)export **export: string ### [**](#handlerProps)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L636)handlerProps **handlerProps: { key: string; metadata: any; propertyName: string }\[] ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L615)id **id: string ### [**](#initMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L617)initMethod **initMethod: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L616)name **name: string ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L613)optionalnamespace **namespace? : string ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L621)path **path: any ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L625)properties **properties: [IProperties](/api/3.0.0/core/interface/IProperties.md) ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L626)scope **scope: [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) ### [**](#srcPath)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L620)srcPath **srcPath: string ## Methods[**](#Methods) ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L632)getAttr * **getAttr(key: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): any ### [**](#hasAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L633)hasAttr * **hasAttr(key: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean ### [**](#hasConstructorArgs)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L631)hasConstructorArgs * **hasConstructorArgs(): boolean ### [**](#hasDependsOn)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L630)hasDependsOn * **hasDependsOn(): boolean ### [**](#isAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L627)isAsync * **isAsync(): boolean ### [**](#isRequestScope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L629)isRequestScope * **isRequestScope(): boolean ### [**](#isSingletonScope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L628)isSingletonScope * **isSingletonScope(): boolean ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L634)setAttr * **setAttr(key: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), value: any): void --- # IObjectDefinitionRegistry Object Definition Registry 对象定义存储容器 ## Index[**](#Index) ### Properties * [**count](#count) * [**identifiers](#identifiers) ### Methods * [**clearAll](#clearAll) * [**getDefinition](#getDefinition) * [**getDefinitionByName](#getDefinitionByName) * [**getIdentifierRelation](#getIdentifierRelation) * [**getObject](#getObject) * [**getSingletonDefinitionIds](#getSingletonDefinitionIds) * [**hasDefinition](#hasDefinition) * [**hasObject](#hasObject) * [**registerDefinition](#registerDefinition) * [**registerObject](#registerObject) * [**removeDefinition](#removeDefinition) * [**setIdentifierRelation](#setIdentifierRelation) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L674)readonlycount **count: number ### [**](#identifiers)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L673)readonlyidentifiers **identifiers: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)\[] ## Methods[**](#Methods) ### [**](#clearAll)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L684)clearAll * **clearAll(): void ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L680)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) ### [**](#getDefinitionByName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L681)getDefinitionByName * **getDefinitionByName(name: string): [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)\[] ### [**](#getIdentifierRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L688)getIdentifierRelation * **getIdentifierRelation(): [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md) ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L687)getObject * **getObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): any ### [**](#getSingletonDefinitionIds)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L679)getSingletonDefinitionIds * **getSingletonDefinitionIds(): [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)\[] ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L683)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L685)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): boolean ### [**](#registerDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L675)registerDefinition * **registerDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)): any ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L686)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), target: any): any ### [**](#removeDefinition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L682)removeDefinition * **removeDefinition(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)): void ### [**](#setIdentifierRelation)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L689)setIdentifierRelation * **setIdentifierRelation(identifierRelation: [IIdentifierRelationShip](/api/3.0.0/core/interface/IIdentifierRelationShip.md)): any --- # IObjectFactory Abstract Object Factory 对象容器抽象 ### Hierarchy * *IObjectFactory* * [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) ## Index[**](#Index) ### Properties * [**registry](#registry) ### Methods * [**get](#get) * [**getAsync](#getAsync) ## Properties[**](#Properties) ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L544)registry **registry: [IObjectDefinitionRegistry](/api/3.0.0/core/interface/IObjectDefinitionRegistry.md) ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L545)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L550)get * **get\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T * **get\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): T - #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L555)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L560)getAsync * **getAsync\(identifier: new (...args: any\[]) => T, args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ * **getAsync\(identifier: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), args? : any\[], objectContext? : [ObjectContext](/api/3.0.0/core.md#ObjectContext)): Promise\ - #### Type parameters * **T** --- # IObjectLifeCycle Object Lifecycle 对象生命周期 ## Index[**](#Index) ### Methods * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) ## Methods[**](#Methods) ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L601)onBeforeBind * **onBeforeBind(Clzz: any, options: [ObjectBeforeBindOptions](/api/3.0.0/core/interface/ObjectBeforeBindOptions.md)): void ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L602)onBeforeObjectCreated * **onBeforeObjectCreated(Clzz: any, options: [ObjectBeforeCreatedOptions](/api/3.0.0/core/interface/ObjectBeforeCreatedOptions.md)): void ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L605)onBeforeObjectDestroy * **onBeforeObjectDestroy\(ins: T, options: [ObjectBeforeDestroyOptions](/api/3.0.0/core/interface/ObjectBeforeDestroyOptions.md)): void - #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L603)onObjectCreated * **onObjectCreated\(ins: T, options: [ObjectCreatedOptions](/api/3.0.0/core/interface/ObjectCreatedOptions.md)\): void - #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L604)onObjectInit * **onObjectInit\(ins: T, options: [ObjectInitOptions](/api/3.0.0/core/interface/ObjectInitOptions.md)): void - #### Type parameters * **T** --- # IPipelineContext 执行pipeline 时当前上下文存储内容 ### Implemented by * [PipelineContext](/api/3.0.0/core/class/PipelineContext.md) ## Index[**](#Index) ### Properties * [**args](#args) * [**info](#info) ### Methods * [**get](#get) * [**keys](#keys) * [**set](#set) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L42)args **args: any pipeline 执行原始参数 ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L46)optionalinfo **info? : IPipelineInfo valve 执行信息 ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L51)get * **get(key: string): any - 用于缓存当前 pipeline 执行中的中间过程参数 ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L61)keys * **keys(): string\[] - 返回存在的所有 key ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L57)set * **set(key: string, val: any): void - 用于缓存当前 pipeline 执行中的中间过程参数 --- # IPipelineHandler ### Implemented by * [MidwayPipelineService](/api/3.0.0/core/class/MidwayPipelineService.md) ## Index[**](#Index) ### Methods * [**concat](#concat) * [**concatSeries](#concatSeries) * [**parallel](#parallel) * [**series](#series) * [**waterfall](#waterfall) ## Methods[**](#Methods) ### [**](#concat)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L123)concat * **concat\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - #### Type parameters * **T** ### [**](#concatSeries)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L125)concatSeries * **concatSeries\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - #### Type parameters * **T** ### [**](#parallel)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L122)parallel * **parallel\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - #### Type parameters * **T** ### [**](#series)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L124)series * **series\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - #### Type parameters * **T** ### [**](#waterfall)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L126)waterfall * **waterfall\(opts: [IPipelineOptions](/api/3.0.0/core/interface/IPipelineOptions.md)): Promise<[IPipelineResult](/api/3.0.0/core/interface/IPipelineResult.md)\> - #### Type parameters * **T** --- # IPipelineOptions pipeline 执行参数 ## Index[**](#Index) ### Properties * [**args](#args) * [**valves](#valves) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L84)optionalargs **args? : any pipeline 原始参数 ### [**](#valves)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L88)optionalvalves **valves? : valvesType 这次 pipeline 执行那几个 valve 白名单 --- # IPipelineResult \ pipeline 执行返回结果 ## Index[**](#Index) ### Properties * [**error](#error) * [**result](#result) * [**success](#success) ## Properties[**](#Properties) ### [**](#error)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L101)optionalerror **error? : { error? : Error; message? : string; valveName? : string } 异常信息(如果有则返回) ### [**](#result)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L118)result **result: T 返回结果 ### [**](#success)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L97)success **success: boolean 是否成功 --- # IProperties 属性配置抽象 ### Hierarchy * Map<[ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), any> * *IProperties* ## Index[**](#Index) ### Methods * [**getProperty](#getProperty) * [**propertyKeys](#propertyKeys) * [**setProperty](#setProperty) ## Methods[**](#Methods) ### [**](#getProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L695)getProperty * **getProperty(key: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), defaultValue? : any): any ### [**](#propertyKeys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L697)propertyKeys * **propertyKeys(): [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier)\[] ### [**](#setProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L696)setProperty * **setProperty(key: [ObjectIdentifier](/api/3.0.0/core.md#ObjectIdentifier), value: any): any --- # IServiceFactory \ ### Implemented by * [ServiceFactory](/api/3.0.0/core/class/ServiceFactory.md) ## Index[**](#Index) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1183)createInstance * **createInstance(config: any, clientId? : string): Promise\ ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1181)get * **get(clientId: string): Client ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1188)getClientKeys * **getClientKeys(): string\[] ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1189)getClientPriority * **getClientPriority(clientName: string): string ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1187)getClients * **getClients(): Map\ ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1186)getDefaultClientName * **getDefaultClientName(): string ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1184)getName * **getName(): string ### [**](#has)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1182)has * **has(clientId: string): boolean ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1190)isHighPriority * **isHighPriority(clientName: string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1192)isLowPriority * **isLowPriority(clientName: string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1191)isMediumPriority * **isMediumPriority(clientName: string): boolean ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1185)stop * **stop(): Promise\ --- # ISimulation ## Index[**](#Index) ### Methods * [**appSetup](#appSetup) * [**appTearDown](#appTearDown) * [**contextSetup](#contextSetup) * [**contextTearDown](#contextTearDown) * [**enableCondition](#enableCondition) * [**setup](#setup) * [**tearDown](#tearDown) ## Methods[**](#Methods) ### [**](#appSetup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1198)optionalappSetup * **appSetup(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#appTearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1201)optionalappTearDown * **appTearDown(app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#contextSetup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1199)optionalcontextSetup * **contextSetup(ctx: [Context](/api/3.0.0/core/interface/Context.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#contextTearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1200)optionalcontextTearDown * **contextTearDown(ctx: [Context](/api/3.0.0/core/interface/Context.md), app: [IMidwayBaseApplication](/api/3.0.0/core/interface/IMidwayBaseApplication.md)<[Context](/api/3.0.0/core/interface/Context.md)>): Promise\ ### [**](#enableCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1202)enableCondition * **enableCondition(): boolean | Promise\ ### [**](#setup)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1196)optionalsetup * **setup(): Promise\ ### [**](#tearDown)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1197)optionaltearDown * **tearDown(): Promise\ --- # IValveHandler 每个具体的 valve 需要继承实现该接口 ## Index[**](#Index) ### Properties * [**alias](#alias) ### Methods * [**invoke](#invoke) ## Properties[**](#Properties) ### [**](#alias)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L70)optionalalias **alias? : string 最终合并结果object中的key,默认为 valve 名称 ## Methods[**](#Methods) ### [**](#invoke)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/pipelineService.ts#L75)invoke * **invoke(ctx: [IPipelineContext](/api/3.0.0/core/interface/IPipelineContext.md)): Promise\ - 执行当前 valve --- # JoinPoint ## Index[**](#Index) ### Properties * [**args](#args) * [**methodName](#methodName) * [**proceedIsAsyncFunction](#proceedIsAsyncFunction) * [**target](#target) ### Methods * [**proceed](#proceed) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L324)args **args: any\[] ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L322)methodName **methodName: string ### [**](#proceedIsAsyncFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L326)optionalproceedIsAsyncFunction **proceedIsAsyncFunction? : boolean ### [**](#target)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L323)target **target: any ## Methods[**](#Methods) ### [**](#proceed)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L325)optionalproceed * **proceed(...args: any\[]): any --- # KafkaListenerOptions ## Index[**](#Index) ### Properties * [**propertyKey](#propertyKey) * [**runConfig](#runConfig) * [**subscription](#subscription) * [**topic](#topic) ## Properties[**](#Properties) ### [**](#propertyKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L22)optionalpropertyKey **propertyKey? : string ### [**](#runConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L26)optionalrunConfig **runConfig? : [ConsumerRunConfig](/api/3.0.0/core.md#ConsumerRunConfig) ### [**](#subscription)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L25)optionalsubscription **subscription? : [ConsumerSubscribeTopic](/api/3.0.0/core.md#ConsumerSubscribeTopic) | [ConsumerSubscribeTopics](/api/3.0.0/core.md#ConsumerSubscribeTopics) ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/kafkaListener.ts#L23)optionaltopic **topic? : string --- # MethodDecoratorMetaData \ ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**options](#options) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L379)key **key: string decorator key ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L380)metadata **metadata: Metadata ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L381)options **options: [MethodDecoratorOptions](/api/3.0.0/core/interface/MethodDecoratorOptions.md) ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L377)propertyName **propertyName: string --- # MethodDecoratorOptions ## Index[**](#Index) ### Properties * [**impl](#impl) ## Properties[**](#Properties) ### [**](#impl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L384)optionalimpl **impl? : boolean --- # MidwayAppInfo ## Index[**](#Index) ### Properties * [**HOME](#HOME) * [**appDir](#appDir) * [**baseDir](#baseDir) * [**env](#env) * [**name](#name) * [**pkg](#pkg) * [**root](#root) ## Properties[**](#Properties) ### [**](#HOME)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1168)HOME **HOME: string ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1167)appDir **appDir: string ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1166)baseDir **baseDir: string ### [**](#env)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1170)env **env: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1165)name **name: string ### [**](#pkg)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1164)pkg **pkg: Record\ ### [**](#root)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1169)root **root: string --- # MidwayConfig midway global config definition ### Hierarchy * [FileConfigOption](/api/3.0.0/core.md#FileConfigOption)<[MidwayCoreDefaultConfig](/api/3.0.0/core/interface/MidwayCoreDefaultConfig.md)> * *MidwayConfig* ### Indexable **\[customConfigKey : string]: unknown ## Index[**](#Index) ### Properties * [**asyncContextManager](#asyncContextManager) * [**core](#core) * [**debug](#debug) * [**midwayLogger](#midwayLogger) ## Properties[**](#Properties) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L454)optionalasyncContextManager **asyncContextManager? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)<{ enable? : boolean }> Inherited from FileConfigOption.asyncContextManager ### [**](#core)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L457)optionalcore **core? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)<{ healthCheckTimeout? : number }> Inherited from FileConfigOption.core ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L451)optionaldebug **debug? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)<{ recordConfigMergeOrder? : boolean }> Inherited from FileConfigOption.debug ### [**](#midwayLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L450)optionalmidwayLogger **midwayLogger? : [PowerPartial](/api/3.0.0/core.md#PowerPartial)<[ServiceFactoryConfigOption](/api/3.0.0/core.md#ServiceFactoryConfigOption)<[MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)>> Inherited from FileConfigOption.midwayLogger --- # MidwayCoreDefaultConfig ## Index[**](#Index) ### Properties * [**asyncContextManager](#asyncContextManager) * [**core](#core) * [**debug](#debug) * [**midwayLogger](#midwayLogger) ## Properties[**](#Properties) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L454)optionalasyncContextManager **asyncContextManager? : { enable? : boolean } ### [**](#core)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L457)optionalcore **core? : { healthCheckTimeout? : number } ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L451)optionaldebug **debug? : { recordConfigMergeOrder? : boolean } ### [**](#midwayLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L450)optionalmidwayLogger **midwayLogger? : [ServiceFactoryConfigOption](/api/3.0.0/core.md#ServiceFactoryConfigOption)<[MidwayLoggerOptions](/api/3.0.0/core/interface/MidwayLoggerOptions.md)> --- # MidwayLoggerOptions Logger Options for midway, you can merge this interface in package * **@example** ``` import { LoggerOptions } from '@midwayjs/logger'; declare module '@midwayjs/core/dist/interface' { interface MidwayLoggerOptions extends LoggerOptions { logDir?: string; level?: string; } } ``` ### Indexable **\[key : string]: any ## Index[**](#Index) ### Properties * [**aliasName](#aliasName) * [**lazyLoad](#lazyLoad) ## Properties[**](#Properties) ### [**](#aliasName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L445)optionalaliasName **aliasName? : string ### [**](#lazyLoad)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L444)optionallazyLoad **lazyLoad? : boolean --- # ObjectBeforeBindOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeBindOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) * [**replaceCallback](#replaceCallback) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L576)context **context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L577)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition ### [**](#replaceCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L581)replaceCallback **replaceCallback: (newDefinition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md)) => void --- # ObjectBeforeCreatedOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeCreatedOptions* ## Index[**](#Index) ### Properties * [**constructorArgs](#constructorArgs) * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L585)constructorArgs **constructorArgs: any\[] ### [**](#context)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L576)context **context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L577)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ObjectBeforeDestroyOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeDestroyOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L576)context **context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L577)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ObjectCreatedOptions \ ### Hierarchy * ObjectLifeCycleOptions * *ObjectCreatedOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) * [**replaceCallback](#replaceCallback) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L576)context **context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L577)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition ### [**](#replaceCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L589)replaceCallback **replaceCallback: (ins: T) => void --- # ObjectDefinitionOptions ## Index[**](#Index) ### Properties * [**allowDowngrade](#allowDowngrade) * [**constructorArgs](#constructorArgs) * [**destroyMethod](#destroyMethod) * [**initMethod](#initMethod) * [**isAsync](#isAsync) * [**namespace](#namespace) * [**scope](#scope) * [**srcPath](#srcPath) ## Properties[**](#Properties) ### [**](#allowDowngrade)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L83)optionalallowDowngrade **allowDowngrade? : boolean ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L80)optionalconstructorArgs **constructorArgs? : any\[] ### [**](#destroyMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L78)optionaldestroyMethod **destroyMethod? : string ### [**](#initMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L77)optionalinitMethod **initMethod? : string ### [**](#isAsync)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L76)optionalisAsync **isAsync? : boolean ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L81)optionalnamespace **namespace? : string ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L79)optionalscope **scope? : [ScopeEnum](/api/3.0.0/core/enum/ScopeEnum.md) ### [**](#srcPath)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L82)optionalsrcPath **srcPath? : string --- # ObjectInitOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectInitOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L576)context **context: [IMidwayContainer](/api/3.0.0/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L577)definition **definition: [IObjectDefinition](/api/3.0.0/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ParamDecoratorOptions ## Index[**](#Index) ### Properties * [**impl](#impl) * [**pipes](#pipes) * [**throwError](#throwError) ## Properties[**](#Properties) ### [**](#impl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L396)optionalimpl **impl? : boolean ### [**](#pipes)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L398)optionalpipes **pipes? : [PipeUnionTransform](/api/3.0.0/core.md#PipeUnionTransform)\\[] ### [**](#throwError)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L397)optionalthrowError **throwError? : boolean --- # ParameterDecoratorMetaData \ ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**options](#options) * [**parameterIndex](#parameterIndex) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L388)key **key: string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L391)metadata **metadata: Metadata ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L392)options **options: [ParamDecoratorOptions](/api/3.0.0/core/interface/ParamDecoratorOptions.md) ### [**](#parameterIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L389)parameterIndex **parameterIndex: number ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L390)propertyName **propertyName: string --- # PipeTransform \ ## Index[**](#Index) ### Methods * [**transform](#transform) ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L369)transform * **transform(value: T, transformOptions: [TransformOptions](/api/3.0.0/core/interface/TransformOptions.md)\): R --- # RabbitMQListenerOptions ## Index[**](#Index) ### Properties * [**autoDelete](#autoDelete) * [**consumeOptions](#consumeOptions) * [**deadLetterExchange](#deadLetterExchange) * [**deadLetterRoutingKey](#deadLetterRoutingKey) * [**durable](#durable) * [**exchange](#exchange) * [**exchangeOptions](#exchangeOptions) * [**exclusive](#exclusive) * [**expires](#expires) * [**maxLength](#maxLength) * [**maxPriority](#maxPriority) * [**messageTtl](#messageTtl) * [**pattern](#pattern) * [**prefetch](#prefetch) * [**propertyKey](#propertyKey) * [**queueName](#queueName) * [**routingKey](#routingKey) ## Properties[**](#Properties) ### [**](#autoDelete)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L12)optionalautoDelete **autoDelete? : boolean ### [**](#consumeOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L42)optionalconsumeOptions **consumeOptions? : { arguments? : any; consumerTag? : string; exclusive? : boolean; noAck? : boolean; noLocal? : boolean; priority? : number } consumeOptions ### [**](#deadLetterExchange)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L15)optionaldeadLetterExchange **deadLetterExchange? : string ### [**](#deadLetterRoutingKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L16)optionaldeadLetterRoutingKey **deadLetterRoutingKey? : string ### [**](#durable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L11)optionaldurable **durable? : boolean ### [**](#exchange)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L6)optionalexchange **exchange? : string ### [**](#exchangeOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L31)optionalexchangeOptions **exchangeOptions? : { alternateExchange? : string; arguments? : any; autoDelete? : boolean; durable? : boolean; internal? : boolean; type? : string } exchange options ### [**](#exclusive)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L10)optionalexclusive **exclusive? : boolean queue options ### [**](#expires)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L14)optionalexpires **expires? : number ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L17)optionalmaxLength **maxLength? : number ### [**](#maxPriority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L18)optionalmaxPriority **maxPriority? : number ### [**](#messageTtl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L13)optionalmessageTtl **messageTtl? : number ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L19)optionalpattern **pattern? : string ### [**](#prefetch)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L23)optionalprefetch **prefetch? : number prefetch ### [**](#propertyKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L4)optionalpropertyKey **propertyKey? : string ### [**](#queueName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L5)optionalqueueName **queueName? : string ### [**](#routingKey)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/microservice/rabbitmqListener.ts#L27)optionalroutingKey **routingKey? : string router --- # ReflectResult ### Indexable **\[key : string]: any\[] --- # ResolveFilter ## Index[**](#Index) ### Properties * [**filter](#filter) * [**ignoreRequire](#ignoreRequire) * [**pattern](#pattern) ## Properties[**](#Properties) ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L11)filter **filter: (module: any, filter: any, bindModule: any) => any ### [**](#ignoreRequire)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L12)optionalignoreRequire **ignoreRequire? : boolean ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/common/configuration.ts#L10)pattern **pattern: string | RegExp --- # RouterCollectorOptions ## Index[**](#Index) ### Properties * [**globalPrefix](#globalPrefix) * [**includeFunctionRouter](#includeFunctionRouter) ## Properties[**](#Properties) ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L147)optionalglobalPrefix **globalPrefix? : string ### [**](#includeFunctionRouter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L146)optionalincludeFunctionRouter **includeFunctionRouter? : boolean --- # RouterInfo ## Index[**](#Index) ### Properties * [**controllerClz](#controllerClz) * [**controllerId](#controllerId) * [**controllerMiddleware](#controllerMiddleware) * [**description](#description) * [**fullUrl](#fullUrl) * [**fullUrlCompiledRegexp](#fullUrlCompiledRegexp) * [**fullUrlFlattenString](#fullUrlFlattenString) * [**funcHandlerName](#funcHandlerName) * [**functionMetadata](#functionMetadata) * [**functionName](#functionName) * [**functionTriggerMetadata](#functionTriggerMetadata) * [**functionTriggerName](#functionTriggerName) * [**handlerName](#handlerName) * [**id](#id) * [**method](#method) * [**middleware](#middleware) * [**prefix](#prefix) * [**requestMetadata](#requestMetadata) * [**requestMethod](#requestMethod) * [**responseMetadata](#responseMetadata) * [**routerName](#routerName) * [**summary](#summary) * [**url](#url) ## Properties[**](#Properties) ### [**](#controllerClz)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L78)optionalcontrollerClz **controllerClz? : new (...args: any\[]) => any ### [**](#controllerId)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L74)optionalcontrollerId **controllerId? : string controller provideId ### [**](#controllerMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L86)optionalcontrollerMiddleware **controllerMiddleware? : any\[] controller middleware in this router ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L58)optionaldescription **description? : string router description ### [**](#fullUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L115)optionalfullUrl **fullUrl? : string url with prefix ### [**](#fullUrlCompiledRegexp)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L120)optionalfullUrlCompiledRegexp **fullUrlCompiledRegexp? : RegExp pattern after path-regexp compile ### [**](#fullUrlFlattenString)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L125)optionalfullUrlFlattenString **fullUrlFlattenString? : string url after wildcard and can be path-to-regexp by path-to-regexp v6 ### [**](#funcHandlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L70)optionalfuncHandlerName **funcHandlerName? : string serverless func load key, will be override by * **@ServerlessTrigger** and * **@ServerlessFunction** ### [**](#functionMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L110)optionalfunctionMetadata **functionMetadata? : any serverless function metadata ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L98)optionalfunctionName **functionName? : string serverless function name, will be override by * **@ServerlessTrigger** and * **@ServerlessFunction** ### [**](#functionTriggerMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L106)optionalfunctionTriggerMetadata **functionTriggerMetadata? : any serverless function trigger metadata ### [**](#functionTriggerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L102)optionalfunctionTriggerName **functionTriggerName? : string serverless trigger name ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L66)optionalhandlerName **handlerName? : string router handler function key,for IoC container load ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L34)optionalid **id? : string uuid ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L54)method **method: string | (...args: any\[]) => void invoke function method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L82)optionalmiddleware **middleware? : any\[] router middleware ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L38)optionalprefix **prefix? : string router prefix from controller ### [**](#requestMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L90)optionalrequestMetadata **requestMetadata? : any\[] request args metadata ### [**](#requestMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L50)requestMethod **requestMethod: string request method for http, like get/post/delete ### [**](#responseMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L94)optionalresponseMetadata **responseMetadata? : any\[] response data metadata ### [**](#routerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L42)optionalrouterName **routerName? : string router alias name ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L62)optionalsummary **summary? : string * **@deprecated** ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L46)url **url: string | RegExp router path, without prefix --- # RouterOption ## Index[**](#Index) ### Properties * [**description](#description) * [**ignoreGlobalPrefix](#ignoreGlobalPrefix) * [**method](#method) * [**middleware](#middleware) * [**path](#path) * [**requestMethod](#requestMethod) * [**routerName](#routerName) * [**summary](#summary) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L37)optionaldescription **description? : string router description, for swagger * **@deprecated** ### [**](#ignoreGlobalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L41)optionalignoreGlobalPrefix **ignoreGlobalPrefix? : boolean ignore global prefix ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L23)optionalmethod **method? : string which method decorator attached ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L27)optionalmiddleware **middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) middleware array in router ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L11)optionalpath **path? : string | RegExp router path, like "/api" ### [**](#requestMethod)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L15)requestMethod **requestMethod: string http method, like "get", "post" ### [**](#routerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L19)optionalrouterName **routerName? : string router alias name ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/requestMapping.ts#L32)optionalsummary **summary? : string router summary, for swagger * **@deprecated** --- # RouterParamValue ## Index[**](#Index) ### Properties * [**index](#index) * [**propertyData](#propertyData) * [**type](#type) ## Properties[**](#Properties) ### [**](#index)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L25)index **index: number ### [**](#propertyData)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L27)optionalpropertyData **propertyData? : any ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/web/paramMapping.ts#L26)type **type: [RouteParamTypes](/api/3.0.0/core/enum/RouteParamTypes.md) --- # RouterPriority ## Index[**](#Index) ### Properties * [**controllerId](#controllerId) * [**middleware](#middleware) * [**prefix](#prefix) * [**priority](#priority) * [**routerModule](#routerModule) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#controllerId)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L138)controllerId **controllerId: string ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L136)middleware **middleware: any\[] ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L134)prefix **prefix: string ### [**](#priority)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L135)priority **priority: number ### [**](#routerModule)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L142)routerModule **routerModule: any 路由控制器或者函数 module 本身 ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/service/webRouterService.ts#L137)routerOptions **routerOptions: any --- # ScheduleOpts ## Index[**](#Index) ### Properties * [**cron](#cron) * [**cronOptions](#cronOptions) * [**disable](#disable) * [**env](#env) * [**immediate](#immediate) * [**interval](#interval) * [**type](#type) ## Properties[**](#Properties) ### [**](#cron)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L16)optionalcron **cron? : string ### [**](#cronOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L21)optionalcronOptions **cronOptions? : { currentDate? : string | number | Date; endDate? : string | number | Date; iterator? : boolean; startDate? : string | number | Date; tz? : string; utc? : boolean } ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L19)optionaldisable **disable? : boolean ### [**](#env)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L20)optionalenv **env? : string\[] ### [**](#immediate)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L18)optionalimmediate **immediate? : boolean ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L17)optionalinterval **interval? : string | number ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/task/schedule.ts#L15)type **type: string --- # ServerSendEventMessage ## Index[**](#Index) ### Properties * [**data](#data) * [**event](#event) * [**id](#id) * [**retry](#retry) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1237)optionaldata **data? : string | object ### [**](#event)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1238)optionalevent **event? : string ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1239)optionalid **id? : string ### [**](#retry)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1240)optionalretry **retry? : number --- # ServerSendEventStreamOptions \ ## Index[**](#Index) ### Properties * [**closeEvent](#closeEvent) * [**tpl](#tpl) ## Properties[**](#Properties) ### [**](#closeEvent)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1248)optionalcloseEvent **closeEvent? : string ### [**](#tpl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1249)optionaltpl **tpl? : (data: [ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md), ctx: CTX) => [ServerSendEventMessage](/api/3.0.0/core/interface/ServerSendEventMessage.md) --- # ServerStreamOptions \ ## Index[**](#Index) ### Properties * [**tpl](#tpl) ## Properties[**](#Properties) ### [**](#tpl)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L1244)optionaltpl **tpl? : (data: unknown, ctx: CTX) => unknown --- # TagClsMetadata ## Index[**](#Index) ### Properties * [**id](#id) * [**name](#name) * [**originName](#originName) * [**uuid](#uuid) ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L93)id **id: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L96)name **name: string ### [**](#originName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L94)originName **originName: string ### [**](#uuid)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L95)uuid **uuid: string --- # TagPropsMetadata ## Index[**](#Index) ### Properties * [**args](#args) * [**key](#key) * [**value](#value) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L89)optionalargs **args? : any ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L87)key **key: string | number | symbol ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L88)value **value: any --- # TransformOptions \ ## Index[**](#Index) ### Properties * [**metaType](#metaType) * [**metadata](#metadata) * [**methodName](#methodName) * [**target](#target) ## Properties[**](#Properties) ### [**](#metaType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L356)metaType **metaType: [TSDesignType](/api/3.0.0/core/interface/TSDesignType.md)\ ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L357)metadata **metadata: any ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L365)methodName **methodName: string the name of method ### [**](#target)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L361)target **target: any current instance --- # TSDesignType \ ## Index[**](#Index) ### Properties * [**isBaseType](#isBaseType) * [**name](#name) * [**originDesign](#originDesign) ## Properties[**](#Properties) ### [**](#isBaseType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L352)isBaseType **isBaseType: boolean ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L350)name **name: string ### [**](#originDesign)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L351)originDesign **originDesign: OriginType --- # WSControllerOption ## Index[**](#Index) ### Properties * [**namespace](#namespace) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketController.ts#L11)namespace **namespace: string ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketController.ts#L12)routerOptions **routerOptions: { connectionMiddleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) } --- # WSEventInfo ## Index[**](#Index) ### Properties * [**descriptor](#descriptor) * [**eventOptions](#eventOptions) * [**eventType](#eventType) * [**messageEventName](#messageEventName) * [**propertyName](#propertyName) * [**roomName](#roomName) ## Properties[**](#Properties) ### [**](#descriptor)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L22)descriptor **descriptor: PropertyDescriptor ### [**](#eventOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L34)optionaleventOptions **eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/core.md#MiddlewareParamArray) } event options, like middleware ### [**](#eventType)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L17)eventType **eventType: [WSEventTypeEnum](/api/3.0.0/core/enum/WSEventTypeEnum.md) web socket event name in enum ### [**](#messageEventName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L26)optionalmessageEventName **messageEventName? : string the event name by user definition ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L21)propertyName **propertyName: string decorator method name ### [**](#roomName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/decorator/ws/webSocketEvent.ts#L30)optionalroomName **roomName? : string\[] the room name to emit --- # ConsumerMetadata ## Index[**](#Index) ### Interfaces * [**ConsumerMetadata](/api/3.0.0/core/namespace/ConsumerMetadata.md#ConsumerMetadata) ## Interfaces[**](#Interfaces) ### [**](#ConsumerMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L116)ConsumerMetadata **ConsumerMetadata: ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L118)metadata **metadata: any ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L117)type **type: [MSListenerType](/api/3.0.0/core/enum/MSListenerType.md) --- # FaaSMetadata ## Index[**](#Index) ### Interfaces * [**APIGatewayTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) * [**CDNTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#CDNTriggerOptions) * [**EventTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerOptions) * [**HSFTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HSFTriggerOptions) * [**HTTPTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HTTPTriggerOptions) * [**LogTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#LogTriggerOptions) * [**MQTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MQTriggerOptions) * [**MTopTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MTopTriggerOptions) * [**OSTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#OSTriggerOptions) * [**SSRTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#SSRTriggerOptions) * [**ServerlessFunctionOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions) * [**TimerTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#TimerTriggerOptions) * [**TriggerMetadata](/api/3.0.0/core/namespace/FaaSMetadata.md#TriggerMetadata) ### Type Aliases * [**EventTriggerUnionOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ## Interfaces[**](#Interfaces) ### [**](#APIGatewayTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L219)APIGatewayTriggerOptions **APIGatewayTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L216)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L215)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#CDNTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L258)CDNTriggerOptions **CDNTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#EventTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L212)EventTriggerOptions **EventTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HSFTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L252)HSFTriggerOptions **HSFTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HTTPTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L214)HTTPTriggerOptions **HTTPTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L216)optionalmethod **method? : get | delete | head | post | put | patch | all ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L215)path **path: string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#LogTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L230)LogTriggerOptions **LogTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L235)optionalinterval **interval? : number ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#log)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L233)log **log: string ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#project)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L232)project **project: string ### [**](#retryTime)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L234)optionalretryTime **retryTime? : number ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#source)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L231)source **source: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MQTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L245)MQTriggerOptions **MQTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#region)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L248)optionalregion **region? : string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#strategy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L249)optionalstrategy **strategy? : BACKOFF\_RETRY | EXPONENTIAL\_DECAY\_RETRY ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L247)optionaltags **tags? : string ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L246)topic **topic: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MTopTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L254)MTopTriggerOptions **MTopTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#OSTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L221)OSTriggerOptions **OSTriggerOptions: ### [**](#bucket)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L222)bucket **bucket: string ### [**](#events)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L223)events **events: string | string\[] ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L224)optionalfilter **filter? : { prefix: string; suffix: string } ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#SSRTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L256)SSRTriggerOptions **SSRTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L216)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L215)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#ServerlessFunctionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L138)ServerlessFunctionOptions **ServerlessFunctionOptions: ### [**](#concurrency)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L166)optionalconcurrency **concurrency? : number invoke concurrency, just for aliyun ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L146)optionaldescription **description? : string function description ### [**](#environment)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L174)optionalenvironment **environment? : any environment variable, key-value ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L142)optionalfunctionName **functionName? : string function name ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L182)optionalhandlerName **handlerName? : string function handler name, like 'index.handler' ### [**](#initTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L158)optionalinitTimeout **initTimeout? : number function init timeout, just for aliyun ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L178)optionalisDeploy **isDeploy? : boolean deploy or not ### [**](#memorySize)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L150)optionalmemorySize **memorySize? : number function memory size, unit: M ### [**](#runtime)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L162)optionalruntime **runtime? : string function runtime, nodejs10, nodejs12, nodejs14 ### [**](#stage)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L170)optionalstage **stage? : string function invoke stage, like env, just for tencent ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L154)optionaltimeout **timeout? : number function timeout value, unit: seconds ### [**](#TimerTriggerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L238)TimerTriggerOptions **TimerTriggerOptions: ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L242)optionalenable **enable? : boolean ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L189)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L205)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L209)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L193)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#payload)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L241)optionalpayload **payload? : string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L197)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L239)type **type: every | cron | interval ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L240)value **value: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L201)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#TriggerMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L273)TriggerMetadata **TriggerMetadata: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L275)optionalfunctionName **functionName? : string ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L276)optionalhandlerName **handlerName? : string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L278)metadata **metadata: [EventTriggerUnionOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L277)optionalmethodName **methodName? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L274)type **type: string ## Type Aliases[**](<#Type Aliases>) ### [**](#EventTriggerUnionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L260)EventTriggerUnionOptions **EventTriggerUnionOptions: [EventTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#EventTriggerOptions) | [HTTPTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HTTPTriggerOptions) | [APIGatewayTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) | [OSTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#OSTriggerOptions) | [CDNTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#CDNTriggerOptions) | [LogTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#LogTriggerOptions) | [TimerTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#TimerTriggerOptions) | [MQTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MQTriggerOptions) | [HSFTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#HSFTriggerOptions) | [MTopTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#MTopTriggerOptions) | [SSRTriggerOptions](/api/3.0.0/core/namespace/FaaSMetadata.md#SSRTriggerOptions) --- # GRPCMetadata grpc decorator metadata format ## Index[**](#Index) ### Interfaces * [**ProviderMetadata](/api/3.0.0/core/namespace/GRPCMetadata.md#ProviderMetadata) * [**ProviderOptions](/api/3.0.0/core/namespace/GRPCMetadata.md#ProviderOptions) ## Interfaces[**](#Interfaces) ### [**](#ProviderMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L131)ProviderMetadata **ProviderMetadata: ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L133)metadata **metadata: [ProviderOptions](/api/3.0.0/core/namespace/GRPCMetadata.md#ProviderOptions) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L132)type **type: [MSProviderType](/api/3.0.0/core/enum/MSProviderType.md) ### [**](#ProviderOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L126)ProviderOptions **ProviderOptions: ### [**](#package)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L128)optionalpackage **package? : string ### [**](#serviceName)[**](https://github.com/midwayjs/midway/blob/main/packages/core/src/interface.ts#L127)optionalserviceName **serviceName? : string --- # @midwayjs/cos ## Index[**](#Index) ### Classes * [**COSService](/api/3.0.0/cos/class/COSService.md) * [**COSServiceFactory](/api/3.0.0/cos/class/COSServiceFactory.md) * [**Configuration](/api/3.0.0/cos/class/Configuration.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [COSConfiguration](/api/3.0.0/cos/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/configuration.ts#L14)onReady * **onReady(container: any): Promise\ --- # COSService ### Hierarchy * COS * *COSService* ### Implements * COS ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new COSService(): [COSService](/api/3.0.0/cos/class/COSService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L54)init * **init(): Promise\ --- # COSServiceFactory ### Hierarchy * ServiceFactory\ * *COSServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cosConfig](#cosConfig) * [**logger](#logger) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new COSServiceFactory(): [COSServiceFactory](/api/3.0.0/cos/class/COSServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#cosConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L20)cosConfig **cosConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L28)logger **logger: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L30)createClient * **createClient(config: COSOptions): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = COS ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L40)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/cos/src/manager.ts#L23)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # @midwayjs/cron ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/cron/class/Configuration.md) * [**Framework](/api/3.0.0/cron/class/Framework.md) ### Functions * [**InjectJob](/api/3.0.0/cron/function/InjectJob.md) * [**Job](/api/3.0.0/cron/function/Job.md) ### Interfaces * [**Application](/api/3.0.0/cron/interface/Application.md) * [**Context](/api/3.0.0/cron/interface/Context.md) * [**CronOptions](/api/3.0.0/cron/interface/CronOptions.md) * [**IJob](/api/3.0.0/cron/interface/IJob.md) ### Type Aliases * [**CronJobOptions](/api/3.0.0/cron.md#CronJobOptions) * [**JobNameOrClz](/api/3.0.0/cron.md#JobNameOrClz) * [**NextFunction](/api/3.0.0/cron.md#NextFunction) ### Variables * [**CRON\_JOB\_KEY](/api/3.0.0/cron.md#CRON_JOB_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#CronJobOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L6)CronJobOptions **CronJobOptions: Omit\ ### [**](#JobNameOrClz)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L23)JobNameOrClz **JobNameOrClz: string | new (...args: any) => [IJob](/api/3.0.0/cron/interface/IJob.md) ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L26)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#CRON_JOB_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/constants.ts#L2)constCRON\_JOB\_KEY **CRON\_JOB\_KEY: cron:job = 'cron:job' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CronConfiguration](/api/3.0.0/cron/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/configuration.ts#L39)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/configuration.ts#L36)framework **framework: [CronFramework](/api/3.0.0/cron/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/configuration.ts#L42)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/configuration.ts#L56)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/3.0.0/cron/interface/Application.md), [Context](/api/3.0.0/cron/interface/Context.md), any> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**addJob](#addJob) * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**deleteJob](#deleteJob) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getJob](#getJob) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadConfig](#loadConfig) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [CronFramework](/api/3.0.0/cron/class/Framework.md) - Inherited from BaseFramework\.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/3.0.0/cron/interface/Application.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/cron/interface/Context.md), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#addJob)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L59)publicaddJob * **addJob(name: [JobNameOrClz](/api/3.0.0/cron.md#JobNameOrClz), jobOptions? : Partial\): CronJob\ ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L27)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/cron/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L37)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#deleteJob)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L124)publicdeleteJob * **deleteJob(name: [JobNameOrClz](/api/3.0.0/cron.md#JobNameOrClz)): Promise\ ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [Application](/api/3.0.0/cron/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L41)getFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L120)publicgetJob * **getJob(name: [JobNameOrClz](/api/3.0.0/cron.md#JobNameOrClz)): CronJob\ ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/cron/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[CronFramework](/api/3.0.0/cron/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L31)publicloadConfig * **loadConfig(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/framework.ts#L45)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/cron/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/cron/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/cron/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/cron/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # InjectJob ### Callable * **InjectJob(jobName: string | new (...args: any\[]) => [IJob](/api/3.0.0/cron/interface/IJob.md)): PropertyDecorator --- # Job ### Callable * **Job(jobOptions? : [CronJobOptions](/api/3.0.0/cron.md#CronJobOptions)): ClassDecorator * **Job(jobName: string, jobOptions? : [CronJobOptions](/api/3.0.0/cron.md#CronJobOptions)): ClassDecorator --- # Application ### Hierarchy * IMidwayApplication<[Context](/api/3.0.0/cron/interface/Context.md)> * *Application* ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L840)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L830)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/3.0.0/cron/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L821)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L780)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L801)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L851)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L776)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L806)getConfig * **getConfig(key? : string): any - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L815)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L784)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L788)getFramework * **getFramework(): IMidwayFramework<[Application](/api/3.0.0/cron/interface/Application.md), [Context](/api/3.0.0/cron/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getFrameworkType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L793)getFrameworkType * **getFrameworkType(): [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) - Inherited from IMidwayApplication.getFrameworkType * **@deprecated** Get current framework type in MidwayFrameworkType enum ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L811)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L860)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/3.0.0/cron/interface/Context.md), R, N> - Inherited from IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L874)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L797)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L825)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L846)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L835)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L865)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/3.0.0/cron/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L870)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/3.0.0/cron/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L856)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/cron/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * IMidwayContext * *Context* ## Index[**](#Index) ### Properties * [**job](#job) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#job)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L29)job **job: CronJob\ ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayContext.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # CronOptions ## Index[**](#Index) ### Properties * [**defaultCronJobOptions](#defaultCronJobOptions) ## Properties[**](#Properties) ### [**](#defaultCronJobOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L8)optionaldefaultCronJobOptions **defaultCronJobOptions? : [CronJobOptions](/api/3.0.0/cron.md#CronJobOptions) --- # IJob ## Index[**](#Index) ### Methods * [**onComplete](#onComplete) * [**onTick](#onTick) ## Methods[**](#Methods) ### [**](#onComplete)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L20)optionalonComplete * **onComplete(result: any): any - A function that will fire when the job is stopped with job.stop(), and may also be called by onTick at the end of each run. ### [**](#onTick)[**](https://github.com/midwayjs/midway/blob/main/packages/cron/src/interface.ts#L15)onTick * **onTick(): any - The function to fire at the specified time. If an onComplete callback was provided, onTick will receive it as an argument. onTick may call onComplete when it has finished its work. --- # @midwayjs/cross-domain ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/cross-domain/class/Configuration.md) * [**CorsMiddleware](/api/3.0.0/cross-domain/class/CorsMiddleware.md) * [**JSONPFilter](/api/3.0.0/cross-domain/class/JSONPFilter.md) * [**JSONPMiddleware](/api/3.0.0/cross-domain/class/JSONPMiddleware.md) * [**JSONPService](/api/3.0.0/cross-domain/class/JSONPService.md) ### Interfaces * [**CORSOptions](/api/3.0.0/cross-domain/interface/CORSOptions.md) * [**JSONPOptions](/api/3.0.0/cross-domain/interface/JSONPOptions.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CrossDomainConfiguration](/api/3.0.0/cross-domain/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/configuration.ts#L18)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/configuration.ts#L20)onReady * **onReady(): Promise\ --- # CorsMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cors](#cors) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CorsMiddleware(): [CorsMiddleware](/api/3.0.0/cross-domain/class/CorsMiddleware.md) ## Properties[**](#Properties) ### [**](#cors)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/cors.ts#L12)cors **cors: [CORSOptions](/api/3.0.0/cross-domain/interface/CORSOptions.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/cors.ts#L26)compatibleMiddleware * **compatibleMiddleware(request: any, response: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/cors.ts#L14)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/cors.ts#L123)staticgetName * **getName(): string --- # JSONPFilter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**match](#match) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPFilter(): [JSONPFilter](/api/3.0.0/cross-domain/class/JSONPFilter.md) ## Methods[**](#Methods) ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/jsonp.ts#L14)match * **match(value: any, req: any): Promise\ --- # JSONPMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**jsonp](#jsonp) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPMiddleware(): [JSONPMiddleware](/api/3.0.0/cross-domain/class/JSONPMiddleware.md) ## Properties[**](#Properties) ### [**](#jsonp)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/jsonp.ts#L23)jsonp **jsonp: [JSONPOptions](/api/3.0.0/cross-domain/interface/JSONPOptions.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/jsonp.ts#L40)compatibleMiddleware * **compatibleMiddleware(context: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/jsonp.ts#L25)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/middleware/jsonp.ts#L53)staticgetName * **getName(): string --- # JSONPService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) * [**jsonpConfig](#jsonpConfig) * [**res](#res) ### Methods * [**jsonp](#jsonp) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPService(): [JSONPService](/api/3.0.0/cross-domain/class/JSONPService.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/jsonp.ts#L6)ctx **ctx: any ### [**](#jsonpConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/jsonp.ts#L9)jsonpConfig **jsonpConfig: any ### [**](#res)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/jsonp.ts#L12)res **res: any ## Methods[**](#Methods) ### [**](#jsonp)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/jsonp.ts#L14)jsonp * **jsonp(body: any, config? : [JSONPOptions](/api/3.0.0/cross-domain/interface/JSONPOptions.md)): string --- # CORSOptions ## Index[**](#Index) ### Properties * [**allowHeaders](#allowHeaders) * [**allowMethods](#allowMethods) * [**credentials](#credentials) * [**exposeHeaders](#exposeHeaders) * [**keepHeadersOnError](#keepHeadersOnError) * [**maxAge](#maxAge) * [**origin](#origin) ## Properties[**](#Properties) ### [**](#allowHeaders)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L5)allowHeaders **allowHeaders: string | string\[] ### [**](#allowMethods)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L2)allowMethods **allowMethods: string | string\[] ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L6)credentials **credentials: boolean | Function ### [**](#exposeHeaders)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L4)exposeHeaders **exposeHeaders: string | string\[] ### [**](#keepHeadersOnError)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L7)keepHeadersOnError **keepHeadersOnError: boolean ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L8)maxAge **maxAge: number ### [**](#origin)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L3)origin **origin: string | Function --- # JSONPOptions ## Index[**](#Index) ### Properties * [**callback](#callback) * [**csrf](#csrf) * [**limit](#limit) ## Properties[**](#Properties) ### [**](#callback)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L11)callback **callback: string ### [**](#csrf)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L13)csrf **csrf: boolean ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/main/packages/cross-domain/src/interface.ts#L12)limit **limit: number --- # @midwayjs/decorator ## Index[**](#Index) ### Classes * [**DecoratorManager](/api/3.0.0/decorator/class/DecoratorManager.md) * [**FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) * [**MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### Enumerations * [**BaseType](/api/3.0.0/decorator/enum/BaseType.md) * [**GrpcStreamTypeEnum](/api/3.0.0/decorator/enum/GrpcStreamTypeEnum.md) * [**InjectModeEnum](/api/3.0.0/decorator/enum/InjectModeEnum.md) * [**MSListenerType](/api/3.0.0/decorator/enum/MSListenerType.md) * [**MSProviderType](/api/3.0.0/decorator/enum/MSProviderType.md) * [**RouteParamTypes](/api/3.0.0/decorator/enum/RouteParamTypes.md) * [**ScopeEnum](/api/3.0.0/decorator/enum/ScopeEnum.md) * [**ServerlessTriggerType](/api/3.0.0/decorator/enum/ServerlessTriggerType.md) * [**WSEventTypeEnum](/api/3.0.0/decorator/enum/WSEventTypeEnum.md) ### Functions * [**All](/api/3.0.0/decorator/function/All.md) * [**App](/api/3.0.0/decorator/function/App.md) * [**ApplicationContext](/api/3.0.0/decorator/function/ApplicationContext.md) * [**Aspect](/api/3.0.0/decorator/function/Aspect.md) * [**Autoload](/api/3.0.0/decorator/function/Autoload.md) * [**Body](/api/3.0.0/decorator/function/Body.md) * [**Catch](/api/3.0.0/decorator/function/Catch.md) * [**Config](/api/3.0.0/decorator/function/Config.md) * [**Configuration](/api/3.0.0/decorator/function/Configuration.md) * [**Consumer](/api/3.0.0/decorator/function/Consumer.md) * [**ContentType](/api/3.0.0/decorator/function/ContentType.md) * [**Controller](/api/3.0.0/decorator/function/Controller.md) * [**Del](/api/3.0.0/decorator/function/Del.md) * [**Destroy](/api/3.0.0/decorator/function/Destroy.md) * [**DubboMethod](/api/3.0.0/decorator/function/DubboMethod.md) * [**Emit](/api/3.0.0/decorator/function/Emit.md) * [**Fields](/api/3.0.0/decorator/function/Fields.md) * [**File](/api/3.0.0/decorator/function/File.md) * [**Files](/api/3.0.0/decorator/function/Files.md) * [**Framework](/api/3.0.0/decorator/function/Framework.md) * [**Get](/api/3.0.0/decorator/function/Get.md) * [**GrpcMethod](/api/3.0.0/decorator/function/GrpcMethod.md) * [**Guard](/api/3.0.0/decorator/function/Guard.md) * [**HSF](/api/3.0.0/decorator/function/HSF.md) * [**Head](/api/3.0.0/decorator/function/Head.md) * [**Headers](/api/3.0.0/decorator/function/Headers.md) * [**HttpCode](/api/3.0.0/decorator/function/HttpCode.md) * [**Init](/api/3.0.0/decorator/function/Init.md) * [**Inject](/api/3.0.0/decorator/function/Inject.md) * [**InjectClient](/api/3.0.0/decorator/function/InjectClient.md) * [**KafkaListener](/api/3.0.0/decorator/function/KafkaListener.md) * [**Logger](/api/3.0.0/decorator/function/Logger.md) * [**Match](/api/3.0.0/decorator/function/Match.md) * [**Middleware](/api/3.0.0/decorator/function/Middleware.md) * [**Mock](/api/3.0.0/decorator/function/Mock.md) * [**OnConnection](/api/3.0.0/decorator/function/OnConnection.md) * [**OnDisConnection](/api/3.0.0/decorator/function/OnDisConnection.md) * [**OnMessage](/api/3.0.0/decorator/function/OnMessage.md) * [**OnWSConnection](/api/3.0.0/decorator/function/OnWSConnection.md) * [**OnWSDisConnection](/api/3.0.0/decorator/function/OnWSDisConnection.md) * [**OnWSMessage](/api/3.0.0/decorator/function/OnWSMessage.md) * [**Options](/api/3.0.0/decorator/function/Options.md) * [**Param](/api/3.0.0/decorator/function/Param.md) * [**Patch](/api/3.0.0/decorator/function/Patch.md) * [**Pipe](/api/3.0.0/decorator/function/Pipe.md) * [**Pipeline](/api/3.0.0/decorator/function/Pipeline.md) * [**Plugin](/api/3.0.0/decorator/function/Plugin.md) * [**Post](/api/3.0.0/decorator/function/Post.md) * [**Provide](/api/3.0.0/decorator/function/Provide.md) * [**Provider](/api/3.0.0/decorator/function/Provider.md) * [**Put](/api/3.0.0/decorator/function/Put.md) * [**Queries](/api/3.0.0/decorator/function/Queries.md) * [**Query](/api/3.0.0/decorator/function/Query.md) * [**Queue](/api/3.0.0/decorator/function/Queue.md) * [**RabbitMQListener](/api/3.0.0/decorator/function/RabbitMQListener.md) * [**Redirect](/api/3.0.0/decorator/function/Redirect.md) * [**RequestIP](/api/3.0.0/decorator/function/RequestIP.md) * [**RequestMapping](/api/3.0.0/decorator/function/RequestMapping.md) * [**RequestPath](/api/3.0.0/decorator/function/RequestPath.md) * [**Schedule](/api/3.0.0/decorator/function/Schedule.md) * [**Scope](/api/3.0.0/decorator/function/Scope.md) * [**ServerlessFunction](/api/3.0.0/decorator/function/ServerlessFunction.md) * [**ServerlessTrigger](/api/3.0.0/decorator/function/ServerlessTrigger.md) * [**Session](/api/3.0.0/decorator/function/Session.md) * [**SetHeader](/api/3.0.0/decorator/function/SetHeader.md) * [**Singleton](/api/3.0.0/decorator/function/Singleton.md) * [**Task](/api/3.0.0/decorator/function/Task.md) * [**TaskLocal](/api/3.0.0/decorator/function/TaskLocal.md) * [**UseGuard](/api/3.0.0/decorator/function/UseGuard.md) * [**WSBroadCast](/api/3.0.0/decorator/function/WSBroadCast.md) * [**WSController](/api/3.0.0/decorator/function/WSController.md) * [**WSEmit](/api/3.0.0/decorator/function/WSEmit.md) * [**attachClassMetadata](/api/3.0.0/decorator/function/attachClassMetadata.md) * [**attachPropertyDataToClass](/api/3.0.0/decorator/function/attachPropertyDataToClass.md) * [**attachPropertyMetadata](/api/3.0.0/decorator/function/attachPropertyMetadata.md) * [**bindContainer](/api/3.0.0/decorator/function/bindContainer.md) * [**clearAllModule](/api/3.0.0/decorator/function/clearAllModule.md) * [**clearBindContainer](/api/3.0.0/decorator/function/clearBindContainer.md) * [**createCustomMethodDecorator](/api/3.0.0/decorator/function/createCustomMethodDecorator.md) * [**createCustomParamDecorator](/api/3.0.0/decorator/function/createCustomParamDecorator.md) * [**createCustomPropertyDecorator](/api/3.0.0/decorator/function/createCustomPropertyDecorator.md) * [**createRender](/api/3.0.0/decorator/function/createRender.md) * [**createRequestParamDecorator](/api/3.0.0/decorator/function/createRequestParamDecorator.md) * [**getClassExtendedMetadata](/api/3.0.0/decorator/function/getClassExtendedMetadata.md) * [**getClassMetadata](/api/3.0.0/decorator/function/getClassMetadata.md) * [**getMethodParamTypes](/api/3.0.0/decorator/function/getMethodParamTypes.md) * [**getMethodReturnTypes](/api/3.0.0/decorator/function/getMethodReturnTypes.md) * [**getObjectDefinition](/api/3.0.0/decorator/function/getObjectDefinition.md) * [**getPropertyDataFromClass](/api/3.0.0/decorator/function/getPropertyDataFromClass.md) * [**getPropertyInject](/api/3.0.0/decorator/function/getPropertyInject.md) * [**getPropertyMetadata](/api/3.0.0/decorator/function/getPropertyMetadata.md) * [**getPropertyType](/api/3.0.0/decorator/function/getPropertyType.md) * [**getProviderId](/api/3.0.0/decorator/function/getProviderId.md) * [**getProviderName](/api/3.0.0/decorator/function/getProviderName.md) * [**getProviderUUId](/api/3.0.0/decorator/function/getProviderUUId.md) * [**isProvide](/api/3.0.0/decorator/function/isProvide.md) * [**listModule](/api/3.0.0/decorator/function/listModule.md) * [**listPreloadModule](/api/3.0.0/decorator/function/listPreloadModule.md) * [**listPropertyDataFromClass](/api/3.0.0/decorator/function/listPropertyDataFromClass.md) * [**resetModule](/api/3.0.0/decorator/function/resetModule.md) * [**saveClassMetadata](/api/3.0.0/decorator/function/saveClassMetadata.md) * [**saveModule](/api/3.0.0/decorator/function/saveModule.md) * [**saveObjectDefinition](/api/3.0.0/decorator/function/saveObjectDefinition.md) * [**savePreloadModule](/api/3.0.0/decorator/function/savePreloadModule.md) * [**savePropertyDataToClass](/api/3.0.0/decorator/function/savePropertyDataToClass.md) * [**savePropertyInject](/api/3.0.0/decorator/function/savePropertyInject.md) * [**savePropertyMetadata](/api/3.0.0/decorator/function/savePropertyMetadata.md) * [**saveProviderId](/api/3.0.0/decorator/function/saveProviderId.md) * [**sleep](/api/3.0.0/decorator/function/sleep.md) * [**transformTypeFromTSDesign](/api/3.0.0/decorator/function/transformTypeFromTSDesign.md) ### Interfaces * [**CommonSchedule](/api/3.0.0/decorator/interface/CommonSchedule.md) * [**ControllerOption](/api/3.0.0/decorator/interface/ControllerOption.md) * [**HSFOpts](/api/3.0.0/decorator/interface/HSFOpts.md) * [**IComponentInfo](/api/3.0.0/decorator/interface/IComponentInfo.md) * [**IManagedInstance](/api/3.0.0/decorator/interface/IManagedInstance.md) * [**IMethodAspect](/api/3.0.0/decorator/interface/IMethodAspect.md) * [**IModuleStore](/api/3.0.0/decorator/interface/IModuleStore.md) * [**InjectionConfigurationOptions](/api/3.0.0/decorator/interface/InjectionConfigurationOptions.md) * [**JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md) * [**KafkaListenerOptions](/api/3.0.0/decorator/interface/KafkaListenerOptions.md) * [**ObjectDefinitionOptions](/api/3.0.0/decorator/interface/ObjectDefinitionOptions.md) * [**RabbitMQListenerOptions](/api/3.0.0/decorator/interface/RabbitMQListenerOptions.md) * [**ReflectResult](/api/3.0.0/decorator/interface/ReflectResult.md) * [**ResolveFilter](/api/3.0.0/decorator/interface/ResolveFilter.md) * [**RouterOption](/api/3.0.0/decorator/interface/RouterOption.md) * [**RouterParamValue](/api/3.0.0/decorator/interface/RouterParamValue.md) * [**ScheduleOpts](/api/3.0.0/decorator/interface/ScheduleOpts.md) * [**TagClsMetadata](/api/3.0.0/decorator/interface/TagClsMetadata.md) * [**TagPropsMetadata](/api/3.0.0/decorator/interface/TagPropsMetadata.md) * [**WSControllerOption](/api/3.0.0/decorator/interface/WSControllerOption.md) * [**WSEventInfo](/api/3.0.0/decorator/interface/WSEventInfo.md) ### Namespaces * [**ConsumerMetadata](/api/3.0.0/decorator/namespace/ConsumerMetadata.md) * [**FaaSMetadata](/api/3.0.0/decorator/namespace/FaaSMetadata.md) * [**GRPCMetadata](/api/3.0.0/decorator/namespace/GRPCMetadata.md) ### Type Aliases * [**ConsumerRunConfig](/api/3.0.0/decorator.md#ConsumerRunConfig) * [**ConsumerSubscribeTopic](/api/3.0.0/decorator.md#ConsumerSubscribeTopic) * [**ConsumerSubscribeTopics](/api/3.0.0/decorator.md#ConsumerSubscribeTopics) * [**CustomParamDecorator](/api/3.0.0/decorator.md#CustomParamDecorator) * [**ExpressLikeCustomParamDecorator](/api/3.0.0/decorator.md#ExpressLikeCustomParamDecorator) * [**GroupModeType](/api/3.0.0/decorator.md#GroupModeType) * [**KoaLikeCustomParamDecorator](/api/3.0.0/decorator.md#KoaLikeCustomParamDecorator) * [**MatchPattern](/api/3.0.0/decorator.md#MatchPattern) * [**MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) * [**ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier) ### Variables * [**ALL](/api/3.0.0/decorator.md#ALL) * [**APPLICATION\_CONTEXT\_KEY](/api/3.0.0/decorator.md#APPLICATION_CONTEXT_KEY) * [**APPLICATION\_KEY](/api/3.0.0/decorator.md#APPLICATION_KEY) * [**ASPECT\_KEY](/api/3.0.0/decorator.md#ASPECT_KEY) * [**CATCH\_KEY](/api/3.0.0/decorator.md#CATCH_KEY) * [**CLASS\_KEY\_CONSTRUCTOR](/api/3.0.0/decorator.md#CLASS_KEY_CONSTRUCTOR) * [**CONFIGURATION\_KEY](/api/3.0.0/decorator.md#CONFIGURATION_KEY) * [**CONFIG\_KEY](/api/3.0.0/decorator.md#CONFIG_KEY) * [**CONTROLLER\_KEY](/api/3.0.0/decorator.md#CONTROLLER_KEY) * [**FACTORY\_SERVICE\_CLIENT\_KEY](/api/3.0.0/decorator.md#FACTORY_SERVICE_CLIENT_KEY) * [**FORMAT](/api/3.0.0/decorator.md#FORMAT) * [**FRAMEWORK\_KEY](/api/3.0.0/decorator.md#FRAMEWORK_KEY) * [**FUNC\_KEY](/api/3.0.0/decorator.md#FUNC_KEY) * [**FileUtils](/api/3.0.0/decorator.md#FileUtils) * [**GUARD\_KEY](/api/3.0.0/decorator.md#GUARD_KEY) * [**HSF\_KEY](/api/3.0.0/decorator.md#HSF_KEY) * [**INJECT\_CLASS\_KEY\_PREFIX](/api/3.0.0/decorator.md#INJECT_CLASS_KEY_PREFIX) * [**INJECT\_CUSTOM\_METHOD](/api/3.0.0/decorator.md#INJECT_CUSTOM_METHOD) * [**INJECT\_CUSTOM\_PARAM](/api/3.0.0/decorator.md#INJECT_CUSTOM_PARAM) * [**INJECT\_CUSTOM\_PROPERTY](/api/3.0.0/decorator.md#INJECT_CUSTOM_PROPERTY) * [**INJECT\_TAG](/api/3.0.0/decorator.md#INJECT_TAG) * [**LIFECYCLE\_IDENTIFIER\_PREFIX](/api/3.0.0/decorator.md#LIFECYCLE_IDENTIFIER_PREFIX) * [**LOGGER\_KEY](/api/3.0.0/decorator.md#LOGGER_KEY) * [**MAIN\_MODULE\_KEY](/api/3.0.0/decorator.md#MAIN_MODULE_KEY) * [**MATCH\_KEY](/api/3.0.0/decorator.md#MATCH_KEY) * [**MOCK\_KEY](/api/3.0.0/decorator.md#MOCK_KEY) * [**MODULE\_TASK\_KEY](/api/3.0.0/decorator.md#MODULE_TASK_KEY) * [**MODULE\_TASK\_METADATA](/api/3.0.0/decorator.md#MODULE_TASK_METADATA) * [**MODULE\_TASK\_QUEUE\_KEY](/api/3.0.0/decorator.md#MODULE_TASK_QUEUE_KEY) * [**MODULE\_TASK\_QUEUE\_OPTIONS](/api/3.0.0/decorator.md#MODULE_TASK_QUEUE_OPTIONS) * [**MODULE\_TASK\_TASK\_LOCAL\_KEY](/api/3.0.0/decorator.md#MODULE_TASK_TASK_LOCAL_KEY) * [**MODULE\_TASK\_TASK\_LOCAL\_OPTIONS](/api/3.0.0/decorator.md#MODULE_TASK_TASK_LOCAL_OPTIONS) * [**MS\_CONSUMER\_KEY](/api/3.0.0/decorator.md#MS_CONSUMER_KEY) * [**MS\_DUBBO\_METHOD\_KEY](/api/3.0.0/decorator.md#MS_DUBBO_METHOD_KEY) * [**MS\_GRPC\_METHOD\_KEY](/api/3.0.0/decorator.md#MS_GRPC_METHOD_KEY) * [**MS\_HSF\_METHOD\_KEY](/api/3.0.0/decorator.md#MS_HSF_METHOD_KEY) * [**MS\_PRODUCER\_KEY](/api/3.0.0/decorator.md#MS_PRODUCER_KEY) * [**MS\_PROVIDER\_KEY](/api/3.0.0/decorator.md#MS_PROVIDER_KEY) * [**NAMED\_TAG](/api/3.0.0/decorator.md#NAMED_TAG) * [**OBJ\_DEF\_CLS](/api/3.0.0/decorator.md#OBJ_DEF_CLS) * [**PIPELINE\_IDENTIFIER](/api/3.0.0/decorator.md#PIPELINE_IDENTIFIER) * [**PLUGIN\_KEY](/api/3.0.0/decorator.md#PLUGIN_KEY) * [**PRELOAD\_MODULE\_KEY](/api/3.0.0/decorator.md#PRELOAD_MODULE_KEY) * [**PRIVATE\_META\_DATA\_KEY](/api/3.0.0/decorator.md#PRIVATE_META_DATA_KEY) * [**RPC\_DUBBO\_KEY](/api/3.0.0/decorator.md#RPC_DUBBO_KEY) * [**RPC\_GRPC\_KEY](/api/3.0.0/decorator.md#RPC_GRPC_KEY) * [**RequestMethod](/api/3.0.0/decorator.md#RequestMethod) * [**SCHEDULE\_KEY](/api/3.0.0/decorator.md#SCHEDULE_KEY) * [**SERVERLESS\_FUNC\_KEY](/api/3.0.0/decorator.md#SERVERLESS_FUNC_KEY) * [**TAGGED\_CLS](/api/3.0.0/decorator.md#TAGGED_CLS) * [**TAGGED\_FUN](/api/3.0.0/decorator.md#TAGGED_FUN) * [**Types](/api/3.0.0/decorator.md#Types) * [**Utils](/api/3.0.0/decorator.md#Utils) * [**WEB\_RESPONSE\_CONTENT\_TYPE](/api/3.0.0/decorator.md#WEB_RESPONSE_CONTENT_TYPE) * [**WEB\_RESPONSE\_HEADER](/api/3.0.0/decorator.md#WEB_RESPONSE_HEADER) * [**WEB\_RESPONSE\_HTTP\_CODE](/api/3.0.0/decorator.md#WEB_RESPONSE_HTTP_CODE) * [**WEB\_RESPONSE\_KEY](/api/3.0.0/decorator.md#WEB_RESPONSE_KEY) * [**WEB\_RESPONSE\_REDIRECT](/api/3.0.0/decorator.md#WEB_RESPONSE_REDIRECT) * [**WEB\_RESPONSE\_RENDER](/api/3.0.0/decorator.md#WEB_RESPONSE_RENDER) * [**WEB\_ROUTER\_KEY](/api/3.0.0/decorator.md#WEB_ROUTER_KEY) * [**WEB\_ROUTER\_PARAM\_KEY](/api/3.0.0/decorator.md#WEB_ROUTER_PARAM_KEY) * [**WS\_CONTROLLER\_KEY](/api/3.0.0/decorator.md#WS_CONTROLLER_KEY) * [**WS\_EVENT\_KEY](/api/3.0.0/decorator.md#WS_EVENT_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#ConsumerRunConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L10)ConsumerRunConfig **ConsumerRunConfig: { autoCommit? : boolean; autoCommitInterval? : number | null; autoCommitThreshold? : number | null; eachBatchAutoResolve? : boolean; partitionsConsumedConcurrently? : number } ### [**](#ConsumerSubscribeTopic)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L4)ConsumerSubscribeTopic **ConsumerSubscribeTopic: { fromBeginning? : boolean } * **@deprecated** Replaced by ConsumerSubscribeTopics ### [**](#ConsumerSubscribeTopics)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L7)ConsumerSubscribeTopics **ConsumerSubscribeTopics: { fromBeginning? : boolean } ### [**](#CustomParamDecorator)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L24)CustomParamDecorator **CustomParamDecorator\: [KoaLikeCustomParamDecorator](/api/3.0.0/decorator.md#KoaLikeCustomParamDecorator)\ | [ExpressLikeCustomParamDecorator](/api/3.0.0/decorator.md#ExpressLikeCustomParamDecorator)\ #### Type parameters * **T** = unknown ### [**](#ExpressLikeCustomParamDecorator)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L23)ExpressLikeCustomParamDecorator **ExpressLikeCustomParamDecorator\: (req: any, res: any) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#GroupModeType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L44)GroupModeType **GroupModeType: one | multi ### [**](#KoaLikeCustomParamDecorator)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L22)KoaLikeCustomParamDecorator **KoaLikeCustomParamDecorator\: (ctx: IMidwayContext) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#MatchPattern)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/filter.d.ts#L4)MatchPattern **MatchPattern\: (ctxOrReq: CtxOrReq, res: Res) => boolean | string | string\[] | boolean #### Type parameters * **CtxOrReq** = any * **Res** = any ### [**](#MiddlewareParamArray)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L42)MiddlewareParamArray **MiddlewareParamArray: (string | any)\[] ### [**](#ObjectIdentifier)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L43)ObjectIdentifier **ObjectIdentifier: string | Symbol ## Variables[**](#Variables) ### [**](#ALL)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L1)constALL **ALL: common:all\_value\_key = "common:all\_value\_key" ### [**](#APPLICATION_CONTEXT_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L43)constAPPLICATION\_CONTEXT\_KEY **APPLICATION\_CONTEXT\_KEY: \_\_midway\_application\_context\_\_ = "\_\_midway\_application\_context\_\_" ### [**](#APPLICATION_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L42)constAPPLICATION\_KEY **APPLICATION\_KEY: \_\_midway\_framework\_app\_\_ = "\_\_midway\_framework\_app\_\_" ### [**](#ASPECT_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L5)constASPECT\_KEY **ASPECT\_KEY: common:aspect = "common:aspect" ### [**](#CATCH_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L6)constCATCH\_KEY **CATCH\_KEY: common:catch = "common:catch" ### [**](#CLASS_KEY_CONSTRUCTOR)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L44)constCLASS\_KEY\_CONSTRUCTOR **CLASS\_KEY\_CONSTRUCTOR: midway:class\_key\_constructor = "midway:class\_key\_constructor" ### [**](#CONFIGURATION_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L3)constCONFIGURATION\_KEY **CONFIGURATION\_KEY: common:configuration = "common:configuration" ### [**](#CONFIG_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L39)constCONFIG\_KEY **CONFIG\_KEY: config = "config" ### [**](#CONTROLLER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L13)constCONTROLLER\_KEY **CONTROLLER\_KEY: web:controller = "web:controller" ### [**](#FACTORY_SERVICE_CLIENT_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L10)constFACTORY\_SERVICE\_CLIENT\_KEY **FACTORY\_SERVICE\_CLIENT\_KEY: common:service\_factory:client = "common:service\_factory:client" ### [**](#FORMAT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/util/format.d.ts#L1)constFORMAT **FORMAT: { CRONTAB: { EVERY\_DAY: string; EVERY\_DAY\_ONE\_FIFTEEN: string; EVERY\_DAY\_ZERO\_FIFTEEN: string; EVERY\_HOUR: string; EVERY\_MINUTE: string; EVERY\_PER\_10\_MINUTE: string; EVERY\_PER\_10\_SECOND: string; EVERY\_PER\_30\_MINUTE: string; EVERY\_PER\_30\_SECOND: string; EVERY\_PER\_5\_MINUTE: string; EVERY\_PER\_5\_SECOND: string; EVERY\_SECOND: string }; MS: { ONE\_DAY: number; ONE\_HOUR: number; ONE\_MINUTE: number; ONE\_SECOND: number; ONE\_WEEK: number; ONE\_YEAR: number } } ### [**](#FRAMEWORK_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L4)constFRAMEWORK\_KEY **FRAMEWORK\_KEY: common:framework = "common:framework" ### [**](#FUNC_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L11)constFUNC\_KEY **FUNC\_KEY: faas:func = "faas:func" ### [**](#FileUtils)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/util/fs.d.ts#L2)constFileUtils **FileUtils: { exists: typeof exists } ### [**](#GUARD_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L8)constGUARD\_KEY **GUARD\_KEY: common:guard = "common:guard" ### [**](#HSF_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L30)constHSF\_KEY **HSF\_KEY: rpc:hsf = "rpc:hsf" ### [**](#INJECT_CLASS_KEY_PREFIX)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L4)constINJECT\_CLASS\_KEY\_PREFIX **INJECT\_CLASS\_KEY\_PREFIX: INJECTION\_CLASS\_META\_DATA = "INJECTION\_CLASS\_META\_DATA" ### [**](#INJECT_CUSTOM_METHOD)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L48)constINJECT\_CUSTOM\_METHOD **INJECT\_CUSTOM\_METHOD: inject\_custom\_method = "inject\_custom\_method" ### [**](#INJECT_CUSTOM_PARAM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L49)constINJECT\_CUSTOM\_PARAM **INJECT\_CUSTOM\_PARAM: inject\_custom\_param = "inject\_custom\_param" ### [**](#INJECT_CUSTOM_PROPERTY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L47)constINJECT\_CUSTOM\_PROPERTY **INJECT\_CUSTOM\_PROPERTY: inject\_custom\_property = "inject\_custom\_property" ### [**](#INJECT_TAG)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L46)constINJECT\_TAG **INJECT\_TAG: inject = "inject" ### [**](#LIFECYCLE_IDENTIFIER_PREFIX)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L54)constLIFECYCLE\_IDENTIFIER\_PREFIX **LIFECYCLE\_IDENTIFIER\_PREFIX: \_\_lifecycle\_\_ = "\_\_lifecycle\_\_" ### [**](#LOGGER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L41)constLOGGER\_KEY **LOGGER\_KEY: logger = "logger" ### [**](#MAIN_MODULE_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L55)constMAIN\_MODULE\_KEY **MAIN\_MODULE\_KEY: \_\_main\_\_ = "\_\_main\_\_" ### [**](#MATCH_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L7)constMATCH\_KEY **MATCH\_KEY: common:match = "common:match" ### [**](#MOCK_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L9)constMOCK\_KEY **MOCK\_KEY: common:mock = "common:mock" ### [**](#MODULE_TASK_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L22)constMODULE\_TASK\_KEY **MODULE\_TASK\_KEY: task:task = "task:task" ### [**](#MODULE_TASK_METADATA)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L23)constMODULE\_TASK\_METADATA **MODULE\_TASK\_METADATA: task:task:options = "task:task:options" ### [**](#MODULE_TASK_QUEUE_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L26)constMODULE\_TASK\_QUEUE\_KEY **MODULE\_TASK\_QUEUE\_KEY: task:task:queue = "task:task:queue" ### [**](#MODULE_TASK_QUEUE_OPTIONS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L27)constMODULE\_TASK\_QUEUE\_OPTIONS **MODULE\_TASK\_QUEUE\_OPTIONS: task:task:queue:options = "task:task:queue:options" ### [**](#MODULE_TASK_TASK_LOCAL_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L24)constMODULE\_TASK\_TASK\_LOCAL\_KEY **MODULE\_TASK\_TASK\_LOCAL\_KEY: task:task:task\_local = "task:task:task\_local" ### [**](#MODULE_TASK_TASK_LOCAL_OPTIONS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L25)constMODULE\_TASK\_TASK\_LOCAL\_OPTIONS **MODULE\_TASK\_TASK\_LOCAL\_OPTIONS: task:task:task\_local:options = "task:task:task\_local:options" ### [**](#MS_CONSUMER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L33)constMS\_CONSUMER\_KEY **MS\_CONSUMER\_KEY: ms:consumer = "ms:consumer" ### [**](#MS_DUBBO_METHOD_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L37)constMS\_DUBBO\_METHOD\_KEY **MS\_DUBBO\_METHOD\_KEY: ms:dubbo:method = "ms:dubbo:method" ### [**](#MS_GRPC_METHOD_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L36)constMS\_GRPC\_METHOD\_KEY **MS\_GRPC\_METHOD\_KEY: ms:grpc:method = "ms:grpc:method" ### [**](#MS_HSF_METHOD_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L38)constMS\_HSF\_METHOD\_KEY **MS\_HSF\_METHOD\_KEY: ms:hsf:method = "ms:hsf:method" ### [**](#MS_PRODUCER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L34)constMS\_PRODUCER\_KEY **MS\_PRODUCER\_KEY: ms:producer = "ms:producer" ### [**](#MS_PROVIDER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L35)constMS\_PROVIDER\_KEY **MS\_PROVIDER\_KEY: ms:provider = "ms:provider" ### [**](#NAMED_TAG)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L45)constNAMED\_TAG **NAMED\_TAG: named = "named" ### [**](#OBJ_DEF_CLS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L52)constOBJ\_DEF\_CLS **OBJ\_DEF\_CLS: injection:object\_definition\_class = "injection:object\_definition\_class" ### [**](#PIPELINE_IDENTIFIER)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L53)constPIPELINE\_IDENTIFIER **PIPELINE\_IDENTIFIER: \_\_pipeline\_identifier\_\_ = "\_\_pipeline\_identifier\_\_" ### [**](#PLUGIN_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L40)constPLUGIN\_KEY **PLUGIN\_KEY: plugin = "plugin" ### [**](#PRELOAD_MODULE_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L3)constPRELOAD\_MODULE\_KEY **PRELOAD\_MODULE\_KEY: INJECTION\_PRELOAD\_MODULE\_KEY = "INJECTION\_PRELOAD\_MODULE\_KEY" ### [**](#PRIVATE_META_DATA_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L56)constPRIVATE\_META\_DATA\_KEY **PRIVATE\_META\_DATA\_KEY: \_\_midway\_private\_meta\_data\_\_ = "\_\_midway\_private\_meta\_data\_\_" ### [**](#RPC_DUBBO_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L32)constRPC\_DUBBO\_KEY **RPC\_DUBBO\_KEY: rpc:dubbo = "rpc:dubbo" ### [**](#RPC_GRPC_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L31)constRPC\_GRPC\_KEY **RPC\_GRPC\_KEY: rpc:grpc = "rpc:grpc" ### [**](#RequestMethod)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L38)constRequestMethod **RequestMethod: { ALL: string; DELETE: string; GET: string; HEAD: string; OPTIONS: string; PATCH: string; POST: string; PUT: string } ### [**](#SCHEDULE_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L2)constSCHEDULE\_KEY **SCHEDULE\_KEY: common:schedule = "common:schedule" ### [**](#SERVERLESS_FUNC_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L12)constSERVERLESS\_FUNC\_KEY **SERVERLESS\_FUNC\_KEY: faas:serverless:function = "faas:serverless:function" ### [**](#TAGGED_CLS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L50)constTAGGED\_CLS **TAGGED\_CLS: injection:tagged\_class = "injection:tagged\_class" ### [**](#TAGGED_FUN)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L51)constTAGGED\_FUN **TAGGED\_FUN: injection:tagged\_function = "injection:tagged\_function" ### [**](#Types)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/util/types.d.ts#L17)constTypes **Types: { isAsyncFunction: typeof isAsyncFunction; isClass: typeof isClass; isFunction: typeof isFunction; isGeneratorFunction: typeof isGeneratorFunction; isMap: typeof isMap; isNull: typeof isNull; isNullOrUndefined: typeof isNullOrUndefined; isNumber: typeof isNumber; isObject: typeof isObject; isPlainObject: typeof isPlainObject; isPromise: typeof isPromise; isProxy: typeof isProxy; isRegExp: typeof isRegExp; isSet: typeof isSet; isString: typeof isString; isUndefined: typeof isUndefined } ### [**](#Utils)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/util/index.d.ts#L142)constUtils **Utils: { camelCase: typeof camelCase; generateRandomId: typeof generateRandomId; getParamNames: typeof getParamNames; isTypeScriptEnvironment: typeof isTypeScriptEnvironment; pascalCase: typeof pascalCase; randomUUID: typeof randomUUID; safeParse: typeof safeParse; safeStringify: typeof safeStringify; sleep: typeof [sleep](/api/3.0.0/decorator/function/sleep.md); toAsyncFunction: typeof toAsyncFunction } ### [**](#WEB_RESPONSE_CONTENT_TYPE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L20)constWEB\_RESPONSE\_CONTENT\_TYPE **WEB\_RESPONSE\_CONTENT\_TYPE: web:response\_content\_type = "web:response\_content\_type" ### [**](#WEB_RESPONSE_HEADER)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L19)constWEB\_RESPONSE\_HEADER **WEB\_RESPONSE\_HEADER: web:response\_header = "web:response\_header" ### [**](#WEB_RESPONSE_HTTP_CODE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L17)constWEB\_RESPONSE\_HTTP\_CODE **WEB\_RESPONSE\_HTTP\_CODE: web:response\_http\_code = "web:response\_http\_code" ### [**](#WEB_RESPONSE_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L16)constWEB\_RESPONSE\_KEY **WEB\_RESPONSE\_KEY: web:response = "web:response" ### [**](#WEB_RESPONSE_REDIRECT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L18)constWEB\_RESPONSE\_REDIRECT **WEB\_RESPONSE\_REDIRECT: web:response\_redirect = "web:response\_redirect" ### [**](#WEB_RESPONSE_RENDER)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L21)constWEB\_RESPONSE\_RENDER **WEB\_RESPONSE\_RENDER: web:response\_render = "web:response\_render" ### [**](#WEB_ROUTER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L14)constWEB\_ROUTER\_KEY **WEB\_ROUTER\_KEY: web:router = "web:router" ### [**](#WEB_ROUTER_PARAM_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L15)constWEB\_ROUTER\_PARAM\_KEY **WEB\_ROUTER\_PARAM\_KEY: web:router\_param = "web:router\_param" ### [**](#WS_CONTROLLER_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L28)constWS\_CONTROLLER\_KEY **WS\_CONTROLLER\_KEY: ws:controller = "ws:controller" ### [**](#WS_EVENT_KEY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.d.ts#L29)constWS\_EVENT\_KEY **WS\_EVENT\_KEY: ws:event = "ws:event" --- # DecoratorManager ### Hierarchy * Map * *DecoratorManager* ### Implements * [IModuleStore](/api/3.0.0/decorator/interface/IModuleStore.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**container](#container) * [**injectClassKeyPrefix](#injectClassKeyPrefix) * [**injectClassMethodKeyPrefix](#injectClassMethodKeyPrefix) * [**injectMethodKeyPrefix](#injectMethodKeyPrefix) ### Methods * [**attachMetadata](#attachMetadata) * [**attachPropertyDataToClass](#attachPropertyDataToClass) * [**bindContainer](#bindContainer) * [**getMetadata](#getMetadata) * [**getPropertyDataFromClass](#getPropertyDataFromClass) * [**listModule](#listModule) * [**listPropertyDataFromClass](#listPropertyDataFromClass) * [**resetModule](#resetModule) * [**saveMetadata](#saveMetadata) * [**saveModule](#saveModule) * [**savePropertyDataToClass](#savePropertyDataToClass) * [**attachMetadata](#attachMetadata) * [**getDecoratorClassKey](#getDecoratorClassKey) * [**getDecoratorClsExtendedKey](#getDecoratorClsExtendedKey) * [**getDecoratorClsMethodKey](#getDecoratorClsMethodKey) * [**getDecoratorClsMethodPrefix](#getDecoratorClsMethodPrefix) * [**getDecoratorMethod](#getDecoratorMethod) * [**getDecoratorMethodKey](#getDecoratorMethodKey) * [**getMetadata](#getMetadata) * [**removeDecoratorClassKeySuffix](#removeDecoratorClassKeySuffix) * [**saveMetadata](#saveMetadata) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L49)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)externalconstructor * **new DecoratorManager(): [DecoratorManager](/api/3.0.0/decorator/class/DecoratorManager.md) * **new DecoratorManager(): [DecoratorManager](/api/3.0.0/decorator/class/DecoratorManager.md) - Inherited from Map.constructor ## Properties[**](#Properties) ### [**](#container)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L18)container **container: [IModuleStore](/api/3.0.0/decorator/interface/IModuleStore.md) ### [**](#injectClassKeyPrefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L9)injectClassKeyPrefix **injectClassKeyPrefix: string the key for meta data store in class ### [**](#injectClassMethodKeyPrefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L13)injectClassMethodKeyPrefix **injectClassMethodKeyPrefix: string the key for method meta data store in class ### [**](#injectMethodKeyPrefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L17)injectMethodKeyPrefix **injectMethodKeyPrefix: string the key for method meta data store in method ## Methods[**](#Methods) ### [**](#attachMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L49)attachMetadata * **attachMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName? : string, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/decorator.md#GroupModeType)): void - attach data to class or property ### [**](#attachPropertyDataToClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L73)attachPropertyDataToClass * **attachPropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any, groupBy? : string): void - attach property data to class ### [**](#bindContainer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L22)bindContainer * **bindContainer(container: [IModuleStore](/api/3.0.0/decorator/interface/IModuleStore.md)): void ### [**](#getMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L56)getMetadata * **getMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any, propertyName? : any): any - get single data from class or property ### [**](#getPropertyDataFromClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L80)getPropertyDataFromClass * **getPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any, propertyName: any): any - get property data from class ### [**](#listModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L20)listModule * **listModule(key: any): any - Implementation of IModuleStore.listModule ### [**](#listPropertyDataFromClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L86)listPropertyDataFromClass * **listPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any): any\[] - list property data from class ### [**](#resetModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L21)resetModule * **resetModule(key: any): void ### [**](#saveMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L40)saveMetadata * **saveMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName? : any): void - save meta data to class or property ### [**](#saveModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L19)saveModule * **saveModule(key: any, module: any): any - Implementation of IModuleStore.saveModule ### [**](#savePropertyDataToClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L64)savePropertyDataToClass * **savePropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any): void - save property data to class ### [**](#attachMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L31)staticattachMetadata * **attachMetadata(metaKey: string, target: any, dataKey: string, data: any, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/decorator.md#GroupModeType)): void ### [**](#getDecoratorClassKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L23)staticgetDecoratorClassKey * **getDecoratorClassKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getDecoratorClsExtendedKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L26)staticgetDecoratorClsExtendedKey * **getDecoratorClsExtendedKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getDecoratorClsMethodKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L28)staticgetDecoratorClsMethodKey * **getDecoratorClsMethodKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), methodKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getDecoratorClsMethodPrefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L27)staticgetDecoratorClsMethodPrefix * **getDecoratorClsMethodPrefix(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getDecoratorMethod)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L29)staticgetDecoratorMethod * **getDecoratorMethod(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), methodKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getDecoratorMethodKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L25)staticgetDecoratorMethodKey * **getDecoratorMethodKey(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#getMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L32)staticgetMetadata * **getMetadata(metaKey: string, target: any, dataKey? : string): any ### [**](#removeDecoratorClassKeySuffix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L24)staticremoveDecoratorClassKeySuffix * **removeDecoratorClassKeySuffix(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): string ### [**](#saveMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L30)staticsaveMetadata * **saveMetadata(metaKey: string, target: any, dataKey: string, data: any): void --- # abstractFrameworkType ### Hierarchy * *FrameworkType* * [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**name](#name) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new FrameworkType(): [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) ## Properties[**](#Properties) ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L243)abstractname **name: string --- # MidwayFrameworkType ### Hierarchy * [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) * *MidwayFrameworkType* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**name](#name) * [**CUSTOM](#CUSTOM) * [**EMPTY](#EMPTY) * [**FAAS](#FAAS) * [**LIGHT](#LIGHT) * [**MS\_GRPC](#MS_GRPC) * [**MS\_KAFKA](#MS_KAFKA) * [**MS\_RABBITMQ](#MS_RABBITMQ) * [**SERVERLESS\_APP](#SERVERLESS_APP) * [**TASK](#TASK) * [**WEB](#WEB) * [**WEB\_EXPRESS](#WEB_EXPRESS) * [**WEB\_KOA](#WEB_KOA) * [**WS](#WS) * [**WS\_IO](#WS_IO) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L261)constructor * **new MidwayFrameworkType(name: string): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) - Overrides FrameworkType.constructor ## Properties[**](#Properties) ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L246)name **name: string Overrides FrameworkType.name ### [**](#CUSTOM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L257)staticCUSTOM **CUSTOM: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#EMPTY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L258)staticEMPTY **EMPTY: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#FAAS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L250)staticFAAS **FAAS: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#LIGHT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L259)staticLIGHT **LIGHT: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#MS_GRPC)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L251)staticMS\_GRPC **MS\_GRPC: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#MS_KAFKA)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L253)staticMS\_KAFKA **MS\_KAFKA: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#MS_RABBITMQ)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L252)staticMS\_RABBITMQ **MS\_RABBITMQ: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#SERVERLESS_APP)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L256)staticSERVERLESS\_APP **SERVERLESS\_APP: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#TASK)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L260)staticTASK **TASK: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#WEB)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L247)staticWEB **WEB: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#WEB_EXPRESS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L249)staticWEB\_EXPRESS **WEB\_EXPRESS: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#WEB_KOA)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L248)staticWEB\_KOA **WEB\_KOA: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#WS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L255)staticWS **WS: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#WS_IO)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L254)staticWS\_IO **WS\_IO: [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) --- # BaseType ## Index[**](#Index) ### Enumeration Members * [**Boolean](#Boolean) * [**Number](#Number) * [**String](#String) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Boolean)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L256)Boolean **Boolean: boolean ### [**](#Number)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L257)Number **Number: number ### [**](#String)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.d.ts#L258)String **String: string --- # GrpcStreamTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BASE](#BASE) * [**DUPLEX](#DUPLEX) * [**READABLE](#READABLE) * [**WRITEABLE](#WRITEABLE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BASE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.d.ts#L5)BASE **BASE: base ### [**](#DUPLEX)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.d.ts#L6)DUPLEX **DUPLEX: ServerDuplexStream ### [**](#READABLE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.d.ts#L7)READABLE **READABLE: ServerReadableStream ### [**](#WRITEABLE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.d.ts#L8)WRITEABLE **WRITEABLE: ServerWritableStream --- # InjectModeEnum ## Index[**](#Index) ### Enumeration Members * [**Class](#Class) * [**Identifier](#Identifier) * [**PropertyName](#PropertyName) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Class)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L52)Class **Class: Class ### [**](#Identifier)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L51)Identifier **Identifier: Identifier ### [**](#PropertyName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L53)PropertyName **PropertyName: PropertyName --- # MSListenerType ## Index[**](#Index) ### Enumeration Members * [**KAFKA](#KAFKA) * [**MQTT](#MQTT) * [**RABBITMQ](#RABBITMQ) * [**REDIS](#REDIS) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#KAFKA)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L94)KAFKA **KAFKA: kafka ### [**](#MQTT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L93)MQTT **MQTT: mqtt ### [**](#RABBITMQ)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L92)RABBITMQ **RABBITMQ: rabbitmq ### [**](#REDIS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L95)REDIS **REDIS: redis --- # MSProviderType ## Index[**](#Index) ### Enumeration Members * [**DUBBO](#DUBBO) * [**GRPC](#GRPC) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DUBBO)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L88)DUBBO **DUBBO: dubbo ### [**](#GRPC)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L89)GRPC **GRPC: gRPC --- # RouteParamTypes ## Index[**](#Index) ### Enumeration Members * [**BODY](#BODY) * [**CUSTOM](#CUSTOM) * [**FIELDS](#FIELDS) * [**FILESSTREAM](#FILESSTREAM) * [**FILESTREAM](#FILESTREAM) * [**HEADERS](#HEADERS) * [**NEXT](#NEXT) * [**PARAM](#PARAM) * [**QUERIES](#QUERIES) * [**QUERY](#QUERY) * [**REQUEST\_IP](#REQUEST_IP) * [**REQUEST\_PATH](#REQUEST_PATH) * [**SESSION](#SESSION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BODY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L4)BODY **BODY: body ### [**](#CUSTOM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L15)CUSTOM **CUSTOM: custom ### [**](#FIELDS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L14)FIELDS **FIELDS: fields ### [**](#FILESSTREAM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L9)FILESSTREAM **FILESSTREAM: files\_stream ### [**](#FILESTREAM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L8)FILESTREAM **FILESTREAM: file\_stream ### [**](#HEADERS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L6)HEADERS **HEADERS: headers ### [**](#NEXT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L10)NEXT **NEXT: next ### [**](#PARAM)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L5)PARAM **PARAM: param ### [**](#QUERIES)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L13)QUERIES **QUERIES: queries ### [**](#QUERY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L3)QUERY **QUERY: query ### [**](#REQUEST_IP)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L12)REQUEST\_IP **REQUEST\_IP: request\_ip ### [**](#REQUEST_PATH)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L11)REQUEST\_PATH **REQUEST\_PATH: request\_path ### [**](#SESSION)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L7)SESSION **SESSION: session --- # ScopeEnum ## Index[**](#Index) ### Enumeration Members * [**Prototype](#Prototype) * [**Request](#Request) * [**Singleton](#Singleton) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Prototype)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L48)Prototype **Prototype: Prototype ### [**](#Request)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L47)Request **Request: Request ### [**](#Singleton)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L46)Singleton **Singleton: Singleton --- # ServerlessTriggerType ## Index[**](#Index) ### Enumeration Members * [**API\_GATEWAY](#API_GATEWAY) * [**CDN](#CDN) * [**EVENT](#EVENT) * [**HSF](#HSF) * [**HTTP](#HTTP) * [**KAFKA](#KAFKA) * [**LOG](#LOG) * [**MQ](#MQ) * [**MTOP](#MTOP) * [**OS](#OS) * [**SSR](#SSR) * [**TIMER](#TIMER) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#API_GATEWAY)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L266)API\_GATEWAY **API\_GATEWAY: apigw ### [**](#CDN)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L268)CDN **CDN: cdn ### [**](#EVENT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L264)EVENT **EVENT: event ### [**](#HSF)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L273)HSF **HSF: hsf ### [**](#HTTP)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L265)HTTP **HTTP: http ### [**](#KAFKA)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L272)KAFKA **KAFKA: kafka ### [**](#LOG)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L269)LOG **LOG: log ### [**](#MQ)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L271)MQ **MQ: mq ### [**](#MTOP)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L274)MTOP **MTOP: mtop ### [**](#OS)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L267)OS **OS: os ### [**](#SSR)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L275)SSR **SSR: ssr ### [**](#TIMER)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L270)TIMER **TIMER: timer --- # WSEventTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BROADCAST](#BROADCAST) * [**EMIT](#EMIT) * [**ON\_CONNECTION](#ON_CONNECTION) * [**ON\_DISCONNECTION](#ON_DISCONNECTION) * [**ON\_MESSAGE](#ON_MESSAGE) * [**ON\_SOCKET\_ERROR](#ON_SOCKET_ERROR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BROADCAST)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L8)BROADCAST **BROADCAST: ws:broadcast ### [**](#EMIT)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L7)EMIT **EMIT: ws:Emit ### [**](#ON_CONNECTION)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L3)ON\_CONNECTION **ON\_CONNECTION: ws:onConnection ### [**](#ON_DISCONNECTION)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L4)ON\_DISCONNECTION **ON\_DISCONNECTION: ws:onDisconnection ### [**](#ON_MESSAGE)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L5)ON\_MESSAGE **ON\_MESSAGE: ws:onMessage ### [**](#ON_SOCKET_ERROR)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L6)ON\_SOCKET\_ERROR **ON\_SOCKET\_ERROR: ws:onSocketError --- # All ### Callable * **All(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes all HTTP requests to the specified path. --- # App ### Callable * **App(typeOrNamespace? : string | [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md)): PropertyDecorator --- # ApplicationContext ### Callable * **ApplicationContext(): PropertyDecorator --- # Aspect ### Callable * **Aspect(aspectTarget: any, match? : string | () => boolean, priority? : number): (target: any) => void --- # attachClassMetadata ### Callable * **attachClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, groupBy? : string, groupMode? : [GroupModeType](/api/3.0.0/decorator.md#GroupModeType)): void *** * attach data to class --- # attachPropertyDataToClass ### Callable * **attachPropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any, groupBy? : string): void *** * attach property data to class --- # attachPropertyMetadata ### Callable * **attachPropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * attach property data --- # Autoload ### Callable * **Autoload(): (target: any) => void --- # bindContainer ### Callable * **bindContainer(container: any): void --- # Body ### Callable * **Body(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Catch ### Callable * **Catch(catchTarget? : any, options? : { matchPrototype? : boolean }): (target: any) => void --- # clearAllModule ### Callable * **clearAllModule(): void *** * clear all module --- # clearBindContainer ### Callable * **clearBindContainer(): any --- # Config ### Callable * **Config(identifier? : string): PropertyDecorator --- # Configuration ### Callable * **Configuration(options? : [InjectionConfigurationOptions](/api/3.0.0/decorator/interface/InjectionConfigurationOptions.md)): ClassDecorator --- # Consumer ### Callable * **Consumer(type: MQTT): ClassDecorator * **Consumer(type: RABBITMQ, options? : any): ClassDecorator * **Consumer(type: KAFKA, options? : any): ClassDecorator --- # ContentType ### Callable * **ContentType(contentType: string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Controller ### Callable * **Controller(prefix? : string, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string }): ClassDecorator --- # createCustomMethodDecorator ### Callable * **createCustomMethodDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | MethodDecoratorOptions): MethodDecorator --- # createCustomParamDecorator ### Callable * **createCustomParamDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | ParamDecoratorOptions): ParameterDecorator --- # createCustomPropertyDecorator ### Callable * **createCustomPropertyDecorator(decoratorKey: string, metadata: any, impl? : boolean): PropertyDecorator *** * create a custom property inject --- # createRender ### Callable * **createRender(RenderEngine: { render: () => string; renderString: () => string }): (templateName: string) => (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # createRequestParamDecorator ### Callable * **createRequestParamDecorator(transform: [CustomParamDecorator](/api/3.0.0/decorator.md#CustomParamDecorator)\, pipesOrOptions? : ParamDecoratorOptions | PipeUnionTransform\[]): ParameterDecorator --- # Del ### Callable * **Del(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP DELETE requests to the specified path. --- # Destroy ### Callable * **Destroy(): MethodDecorator --- # DubboMethod ### Callable * **DubboMethod(methodName? : string): MethodDecorator --- # Emit ### Callable * **Emit(messageName: string, roomName? : string | string\[]): MethodDecorator *** * * **@deprecated** please use * **@WSEmit** --- # Fields ### Callable * **Fields(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # File ### Callable * **File(propertyOrPipes? : any, pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Files ### Callable * **Files(propertyOrPipes? : any, pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Framework ### Callable * **Framework(): ClassDecorator --- # Get ### Callable * **Get(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP GET requests to the specified path. --- # getClassExtendedMetadata ### Callable * **getClassExtendedMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any, propertyName? : string, useCache? : boolean): T *** * get data from class and proto *** #### Type parameters * **T** = any --- # getClassMetadata ### Callable * **getClassMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any): T *** * get data from class *** #### Type parameters * **T** = any --- # getMethodParamTypes ### Callable * **getMethodParamTypes(target: any, methodName: string | symbol): any *** * get parameters type by reflect-metadata --- # getMethodReturnTypes ### Callable * **getMethodReturnTypes(target: any, methodName: string | symbol): any *** * get method return type from metadata --- # getObjectDefinition ### Callable * **getObjectDefinition(target: any): [ObjectDefinitionOptions](/api/3.0.0/decorator/interface/ObjectDefinitionOptions.md) *** * get class object definition from metadata --- # getPropertyDataFromClass ### Callable * **getPropertyDataFromClass\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data from class *** #### Type parameters * **T** = any --- # getPropertyInject ### Callable * **getPropertyInject(target: any, useCache? : boolean): {} *** * get property inject args --- # getPropertyMetadata ### Callable * **getPropertyMetadata\(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data *** #### Type parameters * **T** = any --- # getPropertyType ### Callable * **getPropertyType(target: any, methodName: string | symbol): TSDesignType\ *** * get property(method) type from metadata --- # getProviderId ### Callable * **getProviderId(module: any): string *** * get provider id from module --- # getProviderName ### Callable * **getProviderName(module: any): string --- # getProviderUUId ### Callable * **getProviderUUId(module: any): string *** * get provider uuid from module --- # GrpcMethod ### Callable * **GrpcMethod(methodOptions? : { methodName? : string; onEnd? : string; type? : [GrpcStreamTypeEnum](/api/3.0.0/decorator/enum/GrpcStreamTypeEnum.md) }): MethodDecorator --- # Guard ### Callable * **Guard(): ClassDecorator --- # Head ### Callable * **Head(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP HEAD requests to the specified path. --- # Headers ### Callable * **Headers(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # HSF ### Callable * **HSF(hsfOption? : [HSFOpts](/api/3.0.0/decorator/interface/HSFOpts.md)): ClassDecorator *** * * **@Deprecated** --- # HttpCode ### Callable * **HttpCode(code: number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Init ### Callable * **Init(): MethodDecorator --- # Inject ### Callable * **Inject(identifier? : [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): (target: any, targetKey: string) => void --- # InjectClient ### Callable * **InjectClient(serviceFactoryClz: new (...args: any\[]) => IServiceFactory\, clientName? : string): PropertyDecorator --- # isProvide ### Callable * **isProvide(target: any): boolean *** * use * **@Provide** decorator or not --- # KafkaListener ### Callable * **KafkaListener(topic: string, options? : [KafkaListenerOptions](/api/3.0.0/decorator/interface/KafkaListenerOptions.md)): MethodDecorator --- # listModule ### Callable * **listModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), filter? : (module: any) => boolean): any\[] *** * list module from decorator key --- # listPreloadModule ### Callable * **listPreloadModule(): any\[] *** * list preload module --- # listPropertyDataFromClass ### Callable * **listPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any): any\[] *** * list property data from class --- # Logger ### Callable * **Logger(identifier? : string): PropertyDecorator --- # Match ### Callable * **Match(matchPattern? : [MatchPattern](/api/3.0.0/decorator.md#MatchPattern)\): (target: any) => void --- # Middleware ### Callable * **Middleware(): ClassDecorator --- # Mock ### Callable * **Mock(): ClassDecorator --- # OnConnection ### Callable * **OnConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSConnection** --- # OnDisConnection ### Callable * **OnDisConnection(): MethodDecorator *** * * **@deprecated** please use * **@OnWSDisConnection** --- # OnMessage ### Callable * **OnMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSMessage** --- # OnWSConnection ### Callable * **OnWSConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) }): MethodDecorator --- # OnWSDisConnection ### Callable * **OnWSDisConnection(): MethodDecorator --- # OnWSMessage ### Callable * **OnWSMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) }): MethodDecorator --- # Options ### Callable * **Options(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP OPTIONS requests to the specified path. --- # Param ### Callable * **Param(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Patch ### Callable * **Patch(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PATCH requests to the specified path. --- # Pipe ### Callable * **Pipe(): ClassDecorator --- # Pipeline ### Callable * **Pipeline(valves? : ([ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier) | new (...args: any\[]) => any)\[]): PropertyDecorator --- # Plugin ### Callable * **Plugin(identifier? : string): PropertyDecorator --- # Post ### Callable * **Post(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP POST requests to the specified path. --- # Provide ### Callable * **Provide(identifier? : [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): (target: any) => any --- # Provider ### Callable * **Provider(type: GRPC, metadata? : [ProviderOptions](/api/3.0.0/decorator/namespace/GRPCMetadata.md#ProviderOptions)): ClassDecorator * **Provider(type: DUBBO, metadata? : any): ClassDecorator --- # Put ### Callable * **Put(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PUT requests to the specified path. --- # Queries ### Callable * **Queries(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Query ### Callable * **Query(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Queue ### Callable * **Queue(options? : any): ClassDecorator --- # RabbitMQListener ### Callable * **RabbitMQListener(queueName: string, options? : [RabbitMQListenerOptions](/api/3.0.0/decorator/interface/RabbitMQListenerOptions.md)): MethodDecorator --- # Redirect ### Callable * **Redirect(url: string, code? : number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # RequestIP ### Callable * **RequestIP(pipes? : PipeUnionTransform\[]): ParameterDecorator --- # RequestMapping ### Callable * **RequestMapping(metadata? : [RouterOption](/api/3.0.0/decorator/interface/RouterOption.md)): MethodDecorator --- # RequestPath ### Callable * **RequestPath(pipes? : PipeUnionTransform\[]): ParameterDecorator --- # resetModule ### Callable * **resetModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier)): void *** * reset module --- # saveClassMetadata ### Callable * **saveClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, mergeIfExist? : boolean): void *** * save data to class --- # saveModule ### Callable * **saveModule(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any): any *** * save module to inner map --- # saveObjectDefinition ### Callable * **saveObjectDefinition(target: any, props? : {}): any *** * save class object definition --- # savePreloadModule ### Callable * **savePreloadModule(target: any): any *** * save preload module by target --- # savePropertyDataToClass ### Callable * **savePropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data to class --- # savePropertyInject ### Callable * **savePropertyInject(opts: { args? : any; identifier: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier); target: any; targetKey: string }): void *** * save property inject args --- # savePropertyMetadata ### Callable * **savePropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data --- # saveProviderId ### Callable * **saveProviderId(identifier: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier), target: any): any *** * class provider id --- # Schedule ### Callable * **Schedule(scheduleOpts: string | [ScheduleOpts](/api/3.0.0/decorator/interface/ScheduleOpts.md)): (target: any) => void --- # Scope ### Callable * **Scope(scope: [ScopeEnum](/api/3.0.0/decorator/enum/ScopeEnum.md), scopeOptions? : { allowDowngrade? : boolean }): ClassDecorator --- # ServerlessFunction ### Callable * **ServerlessFunction(options: [ServerlessFunctionOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#ServerlessFunctionOptions) & Record\): MethodDecorator --- # ServerlessTrigger ### Callable * **ServerlessTrigger(type: HTTP, metadata: [HTTPTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HTTPTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: OS, metadata: [OSTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#OSTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: LOG, metadata: [LogTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#LogTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: TIMER, metadata: [TimerTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#TimerTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MQ, metadata: [MQTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MQTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: CDN, metadata? : [CDNTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#CDNTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: API\_GATEWAY, metadata? : [APIGatewayTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#APIGatewayTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: HSF, metadata? : [HSFTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HSFTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MTOP, metadata? : [MTopTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MTopTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: SSR, metadata? : [SSRTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#SSRTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: EVENT, metadata? : [EventTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: string, metadata? : [EventTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerOptions) & Record\): MethodDecorator --- # Session ### Callable * **Session(propertyOrPipes? : string | PipeUnionTransform\[], pipes? : PipeUnionTransform\[]): ParameterDecorator --- # SetHeader ### Callable * **SetHeader(headerKey: string | Record\, value? : string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Singleton ### Callable * **Singleton(): ClassDecorator --- # sleep ### Callable * **sleep(sleepTime? : number): Promise\ --- # Task ### Callable * **Task(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # TaskLocal ### Callable * **TaskLocal(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # transformTypeFromTSDesign ### Callable * **transformTypeFromTSDesign(designFn: any): TSDesignType --- # UseGuard ### Callable * **UseGuard(guardOrArr: CommonGuardUnion): ClassDecorator & MethodDecorator --- # WSBroadCast ### Callable * **WSBroadCast(messageName? : string, roomName? : string | string\[]): MethodDecorator --- # WSController ### Callable * **WSController(namespace? : string | RegExp, routerOptions? : { connectionMiddleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) }): ClassDecorator --- # WSEmit ### Callable * **WSEmit(messageName: string, roomName? : string | string\[]): MethodDecorator --- # CommonSchedule ## Index[**](#Index) ### Methods * [**exec](#exec) ## Methods[**](#Methods) ### [**](#exec)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L2)exec * **exec(ctx? : any): any --- # ControllerOption ## Index[**](#Index) ### Properties * [**prefix](#prefix) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#prefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/controller.d.ts#L3)prefix **prefix: string ### [**](#routerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/controller.d.ts#L4)optionalrouterOptions **routerOptions? : { alias? : string\[]; description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string } --- # HSFOpts ## Index[**](#Index) ### Properties * [**group](#group) * [**interfaceName](#interfaceName) * [**namespace](#namespace) * [**version](#version) ## Properties[**](#Properties) ### [**](#group)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/rpc/hsf.d.ts#L4)optionalgroup **group? : string ### [**](#interfaceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/rpc/hsf.d.ts#L2)optionalinterfaceName **interfaceName? : string ### [**](#namespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/rpc/hsf.d.ts#L5)optionalnamespace **namespace? : string ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/rpc/hsf.d.ts#L3)optionalversion **version? : string --- # IComponentInfo ## Index[**](#Index) ### Properties * [**component](#component) * [**enabledEnvironment](#enabledEnvironment) ## Properties[**](#Properties) ### [**](#component)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L3)component **component: any ### [**](#enabledEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L4)optionalenabledEnvironment **enabledEnvironment? : string\[] --- # IManagedInstance 内部管理的属性、json、ref等解析实例存储 ## Index[**](#Index) ### Properties * [**args](#args) * [**type](#type) * [**value](#value) ## Properties[**](#Properties) ### [**](#args)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L61)optionalargs **args? : any ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L59)type **type: string ### [**](#value)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L60)optionalvalue **value? : any --- # IMethodAspect ## Index[**](#Index) ### Methods * [**after](#after) * [**afterReturn](#afterReturn) * [**afterThrow](#afterThrow) * [**around](#around) * [**before](#before) ## Methods[**](#Methods) ### [**](#after)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L290)optionalafter * **after(joinPoint: [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md), result: any, error: Error): any ### [**](#afterReturn)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L291)optionalafterReturn * **afterReturn(joinPoint: [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md), result: any): any ### [**](#afterThrow)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L292)optionalafterThrow * **afterThrow(joinPoint: [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md), error: Error): void ### [**](#around)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L294)optionalaround * **around(joinPoint: [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md)): any ### [**](#before)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L293)optionalbefore * **before(joinPoint: [JoinPoint](/api/3.0.0/decorator/interface/JoinPoint.md)): void --- # IModuleStore ### Implemented by * [DecoratorManager](/api/3.0.0/decorator/class/DecoratorManager.md) ## Index[**](#Index) ### Methods * [**listModule](#listModule) * [**saveModule](#saveModule) * [**transformModule](#transformModule) ## Methods[**](#Methods) ### [**](#listModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L297)listModule * **listModule(key: string): any ### [**](#saveModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L298)saveModule * **saveModule(key: string, module: any): any ### [**](#transformModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L299)optionaltransformModule * **transformModule(moduleMap: Map\>): any --- # InjectionConfigurationOptions ## Index[**](#Index) ### Properties * [**conflictCheck](#conflictCheck) * [**detector](#detector) * [**detectorOptions](#detectorOptions) * [**importConfigFilter](#importConfigFilter) * [**importConfigs](#importConfigs) * [**importObjects](#importObjects) * [**imports](#imports) * [**namespace](#namespace) ## Properties[**](#Properties) ### [**](#conflictCheck)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L23)optionalconflictCheck **conflictCheck? : boolean ### [**](#detector)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L21)optionaldetector **detector? : false | IFileDetector ### [**](#detectorOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L22)optionaldetectorOptions **detectorOptions? : Record\ ### [**](#importConfigFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L19)optionalimportConfigFilter **importConfigFilter? : (config: Record\) => Record\ ### [**](#importConfigs)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L16)optionalimportConfigs **importConfigs? : Record\ | {}\[] ### [**](#importObjects)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L15)optionalimportObjects **importObjects? : Record\ ### [**](#imports)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L12)optionalimports **imports? : (string | [IComponentInfo](/api/3.0.0/decorator/interface/IComponentInfo.md) | { Configuration: any })\[] ### [**](#namespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L20)optionalnamespace **namespace? : string --- # JoinPoint ## Index[**](#Index) ### Properties * [**args](#args) * [**methodName](#methodName) * [**proceedIsAsyncFunction](#proceedIsAsyncFunction) * [**target](#target) ### Methods * [**proceed](#proceed) ## Properties[**](#Properties) ### [**](#args)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L280)args **args: any\[] ### [**](#methodName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L278)methodName **methodName: string ### [**](#proceedIsAsyncFunction)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L282)optionalproceedIsAsyncFunction **proceedIsAsyncFunction? : boolean ### [**](#target)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L279)target **target: any ## Methods[**](#Methods) ### [**](#proceed)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L281)optionalproceed * **proceed(...args: any\[]): any --- # KafkaListenerOptions ## Index[**](#Index) ### Properties * [**propertyKey](#propertyKey) * [**runConfig](#runConfig) * [**subscription](#subscription) * [**topic](#topic) ## Properties[**](#Properties) ### [**](#propertyKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L18)optionalpropertyKey **propertyKey? : string ### [**](#runConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L21)optionalrunConfig **runConfig? : [ConsumerRunConfig](/api/3.0.0/decorator.md#ConsumerRunConfig) ### [**](#subscription)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L20)optionalsubscription **subscription? : [ConsumerSubscribeTopic](/api/3.0.0/decorator.md#ConsumerSubscribeTopic) | [ConsumerSubscribeTopics](/api/3.0.0/decorator.md#ConsumerSubscribeTopics) ### [**](#topic)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.d.ts#L19)optionaltopic **topic? : string --- # ObjectDefinitionOptions ## Index[**](#Index) ### Properties * [**allowDowngrade](#allowDowngrade) * [**constructorArgs](#constructorArgs) * [**destroyMethod](#destroyMethod) * [**initMethod](#initMethod) * [**isAsync](#isAsync) * [**namespace](#namespace) * [**scope](#scope) * [**srcPath](#srcPath) ## Properties[**](#Properties) ### [**](#allowDowngrade)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L71)optionalallowDowngrade **allowDowngrade? : boolean ### [**](#constructorArgs)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L68)optionalconstructorArgs **constructorArgs? : any\[] ### [**](#destroyMethod)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L66)optionaldestroyMethod **destroyMethod? : string ### [**](#initMethod)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L65)optionalinitMethod **initMethod? : string ### [**](#isAsync)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L64)optionalisAsync **isAsync? : boolean ### [**](#namespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L69)optionalnamespace **namespace? : string ### [**](#scope)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L67)optionalscope **scope? : [ScopeEnum](/api/3.0.0/decorator/enum/ScopeEnum.md) ### [**](#srcPath)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L70)optionalsrcPath **srcPath? : string --- # RabbitMQListenerOptions ## Index[**](#Index) ### Properties * [**autoDelete](#autoDelete) * [**consumeOptions](#consumeOptions) * [**deadLetterExchange](#deadLetterExchange) * [**deadLetterRoutingKey](#deadLetterRoutingKey) * [**durable](#durable) * [**exchange](#exchange) * [**exchangeOptions](#exchangeOptions) * [**exclusive](#exclusive) * [**expires](#expires) * [**maxLength](#maxLength) * [**maxPriority](#maxPriority) * [**messageTtl](#messageTtl) * [**pattern](#pattern) * [**prefetch](#prefetch) * [**propertyKey](#propertyKey) * [**queueName](#queueName) * [**routingKey](#routingKey) ## Properties[**](#Properties) ### [**](#autoDelete)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L10)optionalautoDelete **autoDelete? : boolean ### [**](#consumeOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L40)optionalconsumeOptions **consumeOptions? : { arguments? : any; consumerTag? : string; exclusive? : boolean; noAck? : boolean; noLocal? : boolean; priority? : number } consumeOptions ### [**](#deadLetterExchange)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L13)optionaldeadLetterExchange **deadLetterExchange? : string ### [**](#deadLetterRoutingKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L14)optionaldeadLetterRoutingKey **deadLetterRoutingKey? : string ### [**](#durable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L9)optionaldurable **durable? : boolean ### [**](#exchange)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L4)optionalexchange **exchange? : string ### [**](#exchangeOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L29)optionalexchangeOptions **exchangeOptions? : { alternateExchange? : string; arguments? : any; autoDelete? : boolean; durable? : boolean; internal? : boolean; type? : string } exchange options ### [**](#exclusive)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L8)optionalexclusive **exclusive? : boolean queue options ### [**](#expires)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L12)optionalexpires **expires? : number ### [**](#maxLength)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L15)optionalmaxLength **maxLength? : number ### [**](#maxPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L16)optionalmaxPriority **maxPriority? : number ### [**](#messageTtl)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L11)optionalmessageTtl **messageTtl? : number ### [**](#pattern)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L17)optionalpattern **pattern? : string ### [**](#prefetch)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L21)optionalprefetch **prefetch? : number prefetch ### [**](#propertyKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L2)optionalpropertyKey **propertyKey? : string ### [**](#queueName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L3)optionalqueueName **queueName? : string ### [**](#routingKey)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.d.ts#L25)optionalroutingKey **routingKey? : string router --- # ReflectResult ### Indexable **\[key : string]: any\[] --- # ResolveFilter ## Index[**](#Index) ### Properties * [**filter](#filter) * [**ignoreRequire](#ignoreRequire) * [**pattern](#pattern) ## Properties[**](#Properties) ### [**](#filter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L8)filter **filter: (module: any, filter: any, bindModule: any) => any ### [**](#ignoreRequire)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L9)optionalignoreRequire **ignoreRequire? : boolean ### [**](#pattern)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/configuration.d.ts#L7)pattern **pattern: string | RegExp --- # RouterOption ## Index[**](#Index) ### Properties * [**description](#description) * [**ignoreGlobalPrefix](#ignoreGlobalPrefix) * [**method](#method) * [**middleware](#middleware) * [**path](#path) * [**requestMethod](#requestMethod) * [**routerName](#routerName) * [**summary](#summary) ## Properties[**](#Properties) ### [**](#description)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L32)optionaldescription **description? : string router description, for swagger * **@deprecated** ### [**](#ignoreGlobalPrefix)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L36)optionalignoreGlobalPrefix **ignoreGlobalPrefix? : boolean ignore global prefix ### [**](#method)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L18)optionalmethod **method? : string which method decorator attached ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L22)optionalmiddleware **middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) middleware array in router ### [**](#path)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L6)optionalpath **path? : string | RegExp router path, like "/api" ### [**](#requestMethod)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L10)requestMethod **requestMethod: string http method, like "get", "post" ### [**](#routerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L14)optionalrouterName **routerName? : string router alias name ### [**](#summary)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.d.ts#L27)optionalsummary **summary? : string router summary, for swagger * **@deprecated** --- # RouterParamValue ## Index[**](#Index) ### Properties * [**index](#index) * [**propertyData](#propertyData) * [**type](#type) ## Properties[**](#Properties) ### [**](#index)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L18)index **index: number ### [**](#propertyData)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L20)optionalpropertyData **propertyData? : any ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.d.ts#L19)type **type: [RouteParamTypes](/api/3.0.0/decorator/enum/RouteParamTypes.md) --- # ScheduleOpts ## Index[**](#Index) ### Properties * [**cron](#cron) * [**cronOptions](#cronOptions) * [**disable](#disable) * [**env](#env) * [**immediate](#immediate) * [**interval](#interval) * [**type](#type) ## Properties[**](#Properties) ### [**](#cron)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L6)optionalcron **cron? : string ### [**](#cronOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L11)optionalcronOptions **cronOptions? : { currentDate? : string | number | Date; endDate? : string | number | Date; iterator? : boolean; startDate? : string | number | Date; tz? : string; utc? : boolean } ### [**](#disable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L9)optionaldisable **disable? : boolean ### [**](#env)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L10)optionalenv **env? : string\[] ### [**](#immediate)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L8)optionalimmediate **immediate? : boolean ### [**](#interval)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L7)optionalinterval **interval? : string | number ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.d.ts#L5)type **type: string --- # TagClsMetadata ## Index[**](#Index) ### Properties * [**id](#id) * [**name](#name) * [**originName](#originName) * [**uuid](#uuid) ## Properties[**](#Properties) ### [**](#id)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L79)id **id: string ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L82)name **name: string ### [**](#originName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L80)originName **originName: string ### [**](#uuid)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L81)uuid **uuid: string --- # TagPropsMetadata ## Index[**](#Index) ### Properties * [**args](#args) * [**key](#key) * [**value](#value) ## Properties[**](#Properties) ### [**](#args)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L76)optionalargs **args? : any ### [**](#key)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L74)key **key: string | number | symbol ### [**](#value)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L75)value **value: any --- # WSControllerOption ## Index[**](#Index) ### Properties * [**namespace](#namespace) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#namespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketController.d.ts#L3)namespace **namespace: string ### [**](#routerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketController.d.ts#L4)routerOptions **routerOptions: { connectionMiddleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) } --- # WSEventInfo ## Index[**](#Index) ### Properties * [**descriptor](#descriptor) * [**eventOptions](#eventOptions) * [**eventType](#eventType) * [**messageEventName](#messageEventName) * [**propertyName](#propertyName) * [**roomName](#roomName) ## Properties[**](#Properties) ### [**](#descriptor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L19)descriptor **descriptor: PropertyDescriptor ### [**](#eventOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L31)optionaleventOptions **eventOptions? : { middleware? : [MiddlewareParamArray](/api/3.0.0/decorator.md#MiddlewareParamArray) } event options, like middleware ### [**](#eventType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L14)eventType **eventType: [WSEventTypeEnum](/api/3.0.0/decorator/enum/WSEventTypeEnum.md) web socket event name in enum ### [**](#messageEventName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L23)optionalmessageEventName **messageEventName? : string the event name by user definition ### [**](#propertyName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L18)propertyName **propertyName: string decorator method name ### [**](#roomName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.d.ts#L27)optionalroomName **roomName? : string\[] the room name to emit --- # ConsumerMetadata ## Index[**](#Index) ### Interfaces * [**ConsumerMetadata](/api/3.0.0/decorator/namespace/ConsumerMetadata.md#ConsumerMetadata) ## Interfaces[**](#Interfaces) ### [**](#ConsumerMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L98)ConsumerMetadata **ConsumerMetadata: ### [**](#metadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L100)metadata **metadata: any ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L99)type **type: [MSListenerType](/api/3.0.0/decorator/enum/MSListenerType.md) --- # FaaSMetadata ## Index[**](#Index) ### Interfaces * [**APIGatewayTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) * [**CDNTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#CDNTriggerOptions) * [**EventTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerOptions) * [**HSFTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HSFTriggerOptions) * [**HTTPTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HTTPTriggerOptions) * [**LogTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#LogTriggerOptions) * [**MQTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MQTriggerOptions) * [**MTopTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MTopTriggerOptions) * [**OSTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#OSTriggerOptions) * [**SSRTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#SSRTriggerOptions) * [**ServerlessFunctionOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#ServerlessFunctionOptions) * [**TimerTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#TimerTriggerOptions) * [**TriggerMetadata](/api/3.0.0/decorator/namespace/FaaSMetadata.md#TriggerMetadata) ### Type Aliases * [**EventTriggerUnionOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ## Interfaces[**](#Interfaces) ### [**](#APIGatewayTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L195)APIGatewayTriggerOptions **APIGatewayTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L193)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L192)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#CDNTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L230)CDNTriggerOptions **CDNTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#EventTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L189)EventTriggerOptions **EventTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HSFTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L224)HSFTriggerOptions **HSFTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HTTPTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L191)HTTPTriggerOptions **HTTPTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#method)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L193)optionalmethod **method? : get | delete | head | post | put | patch | all ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#path)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L192)path **path: string ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#LogTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L205)LogTriggerOptions **LogTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#interval)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L210)optionalinterval **interval? : number ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#log)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L208)log **log: string ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#project)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L207)project **project: string ### [**](#retryTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L209)optionalretryTime **retryTime? : number ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#source)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L206)source **source: string ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MQTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L218)MQTriggerOptions **MQTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#region)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L221)optionalregion **region? : string ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#strategy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L222)optionalstrategy **strategy? : BACKOFF\_RETRY | EXPONENTIAL\_DECAY\_RETRY ### [**](#tags)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L220)optionaltags **tags? : string ### [**](#topic)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L219)topic **topic: string ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MTopTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L226)MTopTriggerOptions **MTopTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#OSTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L197)OSTriggerOptions **OSTriggerOptions: ### [**](#bucket)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L198)bucket **bucket: string ### [**](#events)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L199)events **events: string | string\[] ### [**](#filter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L200)optionalfilter **filter? : { prefix: string; suffix: string } ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#SSRTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L228)SSRTriggerOptions **SSRTriggerOptions: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L193)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L192)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#ServerlessFunctionOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L117)ServerlessFunctionOptions **ServerlessFunctionOptions: ### [**](#concurrency)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L145)optionalconcurrency **concurrency? : number invoke concurrency, just for aliyun ### [**](#description)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L125)optionaldescription **description? : string function description ### [**](#environment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L153)optionalenvironment **environment? : any environment variable, key-value ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L121)optionalfunctionName **functionName? : string function name ### [**](#handlerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L161)optionalhandlerName **handlerName? : string function handler name, like 'index.handler' ### [**](#initTimeout)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L137)optionalinitTimeout **initTimeout? : number function init timeout, just for aliyun ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L157)optionalisDeploy **isDeploy? : boolean deploy or not ### [**](#memorySize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L129)optionalmemorySize **memorySize? : number function memory size, unit: M ### [**](#runtime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L141)optionalruntime **runtime? : string function runtime, nodejs10, nodejs12, nodejs14 ### [**](#stage)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L149)optionalstage **stage? : string function invoke stage, like env, just for tencent ### [**](#timeout)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L133)optionaltimeout **timeout? : number function timeout value, unit: seconds ### [**](#TimerTriggerOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L212)TimerTriggerOptions **TimerTriggerOptions: ### [**](#enable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L216)optionalenable **enable? : boolean ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L167)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L183)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L187)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L171)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#payload)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L215)optionalpayload **payload? : string ### [**](#role)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L175)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L213)type **type: every | cron | interval ### [**](#value)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L214)value **value: string ### [**](#version)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L179)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#TriggerMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L233)TriggerMetadata **TriggerMetadata: ### [**](#functionName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L235)optionalfunctionName **functionName? : string ### [**](#handlerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L236)optionalhandlerName **handlerName? : string ### [**](#metadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L238)metadata **metadata: [EventTriggerUnionOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ### [**](#methodName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L237)optionalmethodName **methodName? : string ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L234)type **type: string ## Type Aliases[**](<#Type Aliases>) ### [**](#EventTriggerUnionOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L232)EventTriggerUnionOptions **EventTriggerUnionOptions: [EventTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#EventTriggerOptions) | [HTTPTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HTTPTriggerOptions) | [APIGatewayTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) | [OSTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#OSTriggerOptions) | [CDNTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#CDNTriggerOptions) | [LogTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#LogTriggerOptions) | [TimerTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#TimerTriggerOptions) | [MQTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MQTriggerOptions) | [HSFTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#HSFTriggerOptions) | [MTopTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#MTopTriggerOptions) | [SSRTriggerOptions](/api/3.0.0/decorator/namespace/FaaSMetadata.md#SSRTriggerOptions) --- # GRPCMetadata grpc decorator metadata format ## Index[**](#Index) ### Interfaces * [**ProviderMetadata](/api/3.0.0/decorator/namespace/GRPCMetadata.md#ProviderMetadata) * [**ProviderOptions](/api/3.0.0/decorator/namespace/GRPCMetadata.md#ProviderOptions) ## Interfaces[**](#Interfaces) ### [**](#ProviderMetadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L111)ProviderMetadata **ProviderMetadata: ### [**](#metadata)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L113)metadata **metadata: [ProviderOptions](/api/3.0.0/decorator/namespace/GRPCMetadata.md#ProviderOptions) ### [**](#type)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L112)type **type: [MSProviderType](/api/3.0.0/decorator/enum/MSProviderType.md) ### [**](#ProviderOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L107)ProviderOptions **ProviderOptions: ### [**](#package)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L109)optionalpackage **package? : string ### [**](#serviceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L108)optionalserviceName **serviceName? : string --- # @midwayjs/etcd ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/etcd/class/Configuration.md) * [**ETCDService](/api/3.0.0/etcd/class/ETCDService.md) * [**ETCDServiceFactory](/api/3.0.0/etcd/class/ETCDServiceFactory.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ETCDConfiguration](/api/3.0.0/etcd/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/configuration.ts#L14)onReady * **onReady(container: any): Promise\ --- # ETCDService ### Hierarchy * Etcd3 * *ETCDService* ### Implements * Etcd3 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ETCDService(): [ETCDService](/api/3.0.0/etcd/class/ETCDService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L52)init * **init(): Promise\ --- # ETCDServiceFactory ### Hierarchy * ServiceFactory\ * *ETCDServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**etcdConfig](#etcdConfig) * [**logger](#logger) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ETCDServiceFactory(): [ETCDServiceFactory](/api/3.0.0/etcd/class/ETCDServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#etcdConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L19)etcdConfig **etcdConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L27)logger **logger: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L29)createClient * **createClient(config: IOptions): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L38)destroyClient * **destroyClient(client: Etcd3): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Etcd3 ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L34)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/etcd/src/manager.ts#L22)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # @midwayjs/express-session ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/express-session/class/Configuration.md) * [**SessionMiddleware](/api/3.0.0/express-session/class/SessionMiddleware.md) * [**SessionStoreManager](/api/3.0.0/express-session/class/SessionStoreManager.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SessionConfiguration](/api/3.0.0/express-session/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/configuration.ts#L22)onReady * **onReady(): Promise\ --- # SessionMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**logger](#logger) * [**sessionConfig](#sessionConfig) * [**sessionStoreManager](#sessionStoreManager) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionMiddleware(): [SessionMiddleware](/api/3.0.0/express-session/class/SessionMiddleware.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L26)configService **configService: MidwayConfigService ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L20)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L17)sessionConfig **sessionConfig: any ### [**](#sessionStoreManager)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L23)sessionStoreManager **sessionStoreManager: [SessionStoreManager](/api/3.0.0/express-session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L28)resolve * **resolve(): any - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/middleware/session.ts#L60)staticgetName * **getName(): string --- # SessionStoreManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSessionStore](#getSessionStore) * [**setSessionStore](#setSessionStore) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStoreManager(): [SessionStoreManager](/api/3.0.0/express-session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#getSessionStore)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/store.ts#L15)getSessionStore * **getSessionStore(session? : any): any ### [**](#setSessionStore)[**](https://github.com/midwayjs/midway/blob/main/packages/express-session/src/store.ts#L11)setSessionStore * **setSessionStore(sessionStore: any, options? : {}): void --- # @midwayjs/faas ## Index[**](#Index) ### Classes * [**AbstractBootstrapStarter](/api/3.0.0/faas/class/AbstractBootstrapStarter.md) * [**Configuration](/api/3.0.0/faas/class/Configuration.md) * [**Framework](/api/3.0.0/faas/class/Framework.md) ### Functions * [**Event](/api/3.0.0/faas/function/Event.md) ### Interfaces * [**Application](/api/3.0.0/faas/interface/Application.md) * [**Context](/api/3.0.0/faas/interface/Context.md) * [**FaaSContext](/api/3.0.0/faas/interface/FaaSContext.md) * [**FaaSHTTPContext](/api/3.0.0/faas/interface/FaaSHTTPContext.md) * [**FaaSHTTPRequest](/api/3.0.0/faas/interface/FaaSHTTPRequest.md) * [**FaaSHTTPResponse](/api/3.0.0/faas/interface/FaaSHTTPResponse.md) * [**FormatResponseOptions](/api/3.0.0/faas/interface/FormatResponseOptions.md) * [**HandlerOptions](/api/3.0.0/faas/interface/HandlerOptions.md) * [**HttpResponseFormat](/api/3.0.0/faas/interface/HttpResponseFormat.md) * [**IFaaSConfigurationOptions](/api/3.0.0/faas/interface/IFaaSConfigurationOptions.md) * [**IWebMiddleware](/api/3.0.0/faas/interface/IWebMiddleware.md) * [**ServerlessStarterOptions](/api/3.0.0/faas/interface/ServerlessStarterOptions.md) * [**State](/api/3.0.0/faas/interface/State.md) * [**wrapHttpRequestOptions](/api/3.0.0/faas/interface/wrapHttpRequestOptions.md) ### Type Aliases * [**FaaSMiddleware](/api/3.0.0/faas.md#FaaSMiddleware) * [**IMidwayFaaSApplication](/api/3.0.0/faas.md#IMidwayFaaSApplication) * [**NextFunction](/api/3.0.0/faas.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#FaaSMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L412)FaaSMiddleware **FaaSMiddleware: (context: [Context](/api/3.0.0/faas/interface/Context.md), next: () => Promise\) => any | string * **@deprecated** ### [**](#IMidwayFaaSApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L426)IMidwayFaaSApplication **IMidwayFaaSApplication: IMidwayApplication<[Context](/api/3.0.0/faas/interface/Context.md), { generateMiddleware: any; getEventMiddleware: any; getFunctionName: any; getFunctionServiceName: any; getInitializeContext: any; getServerlessInstance: any; invokeTriggerFunction: any; use: any; useEventMiddleware: any }> & ServerlessHttpApplication ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L472)NextFunction **NextFunction: BaseNextFunction --- # abstractAbstractBootstrapStarter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**getApplicationContext](#getApplicationContext) * [**initFramework](#initFramework) * [**onClose](#onClose) * [**onInit](#onInit) * [**onRequest](#onRequest) * [**onStart](#onStart) * [**start](#start) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L14)constructor * **new AbstractBootstrapStarter(options? : [ServerlessStarterOptions](/api/3.0.0/faas/interface/ServerlessStarterOptions.md)): [AbstractBootstrapStarter](/api/3.0.0/faas/class/AbstractBootstrapStarter.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L22)publicclose * **close(): Promise\ ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L18)publicgetApplicationContext * **getApplicationContext(): any ### [**](#initFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L53)publicinitFramework * **initFramework(bootstrapOptions? : IMidwayBootstrapOptions): Promise\ ### [**](#onClose)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L74)abstractonClose * **onClose(): any ### [**](#onInit)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L72)abstractonInit * **onInit(...args: unknown\[]): any ### [**](#onRequest)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L73)abstractonRequest * **onRequest(...args: unknown\[]): any ### [**](#onStart)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L71)abstractonStart * **onStart(): unknown ### [**](#start)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/starter.ts#L37)publicstart * **start(options? : [ServerlessStarterOptions](/api/3.0.0/faas/interface/ServerlessStarterOptions.md)): Record\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onServerReady](#onServerReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [FaaSConfiguration](/api/3.0.0/faas/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L32)applicationContext **applicationContext: any ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L29)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L26)framework **framework: [MidwayFaaSFramework](/api/3.0.0/faas/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L35)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L67)onReady * **onReady(container: any): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/configuration.ts#L69)onServerReady * **onServerReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/3.0.0/faas/interface/Application.md), [Context](/api/3.0.0/faas/interface/Context.md), [IFaaSConfigurationOptions](/api/3.0.0/faas/interface/IFaaSConfigurationOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**formatHttpResponse](#formatHttpResponse) * [**generateMiddleware](#generateMiddleware) * [**getAllHandlerNames](#getAllHandlerNames) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getContext](#getContext) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getEventMiddleware](#getEventMiddleware) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**handleInvokeWrapper](#handleInvokeWrapper) * [**init](#init) * [**initialize](#initialize) * [**invokeTriggerFunction](#invokeTriggerFunction) * [**isEnable](#isEnable) * [**loadFunction](#loadFunction) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useEventMiddleware](#useEventMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) * [**wrapHttpRequest](#wrapHttpRequest) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayFaaSFramework](/api/3.0.0/faas/class/Framework.md) - Inherited from BaseFramework< Application, Context, IFaaSConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L54)publicapp **app: [Application](/api/3.0.0/faas/interface/Application.md) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IFaaSConfigurationOptions](/api/3.0.0/faas/interface/IFaaSConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L68)environmentService **environmentService: MidwayEnvironmentService Overrides BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L71)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/faas/interface/Context.md), any, unknown> Overrides BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L87)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/faas/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L555)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L73)configure * **configure(options: [IFaaSConfigurationOptions](/api/3.0.0/faas/interface/IFaaSConfigurationOptions.md)): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L542)publiccreateLogger * **createLogger(name: string, option? : LoggerOptions): ILogger - Overrides BaseFramework.createLogger ### [**](#formatHttpResponse)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L370)publicformatHttpResponse * **formatHttpResponse(context: any, options? : { supportBufferResponse? : boolean }): [HttpResponseFormat](/api/3.0.0/faas/interface/HttpResponseFormat.md)\ ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L449)publicgenerateMiddleware * **generateMiddleware(middlewareId: string): Promise<(context: [Context](/api/3.0.0/faas/interface/Context.md), next: any, options? : any) => any> - - **@deprecated** ### [**](#getAllHandlerNames)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L589)publicgetAllHandlerNames * **getAllHandlerNames(): string\[] ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [Application](/api/3.0.0/faas/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L458)publicgetContext * **getContext(context? : any): any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getEventMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L581)publicgetEventMiddleware * **getEventMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/faas/interface/Context.md), NextFunction, undefined> ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L547)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L194)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/faas/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L551)publicgetServer * **getServer(): Server\ ### [**](#handleInvokeWrapper)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L202)publichandleInvokeWrapper * **handleInvokeWrapper(handlerMapping: string): (...args: any\[]) => Promise\ - - **@deprecated** ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayFaaSFramework](/api/3.0.0/faas/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#invokeTriggerFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L275)publicinvokeTriggerFunction * **invokeTriggerFunction(context: any, handlerMapping: string, options: [HandlerOptions](/api/3.0.0/faas/interface/HandlerOptions.md)): Promise\ ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L83)isEnable * **isEnable(): boolean - Overrides BaseFramework.isEnable ### [**](#loadFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L172)publicloadFunction * **loadFunction(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L166)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/faas/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useEventMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L575)publicuseEventMiddleware * **useEventMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/faas/interface/Context.md), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/faas/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/faas/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L569)publicuseMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/faas/interface/Context.md), NextFunction, undefined>): void - Overrides BaseFramework.useMiddleware ### [**](#wrapHttpRequest)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/framework.ts#L435)publicwrapHttpRequest * **wrapHttpRequest(req: Record\ | IncomingMessage, res? : Record\ | ServerResponse\, options? : [wrapHttpRequestOptions](/api/3.0.0/faas/interface/wrapHttpRequestOptions.md)): Promise\ --- # Event ### Callable * **Event(pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Application ### Hierarchy * [IMidwayFaaSApplication](/api/3.0.0/faas.md#IMidwayFaaSApplication) * *Application* ## Index[**](#Index) ### Properties * [**context](#context) * [**keys](#keys) * [**maxIpsCount](#maxIpsCount) * [**middleware](#middleware) * [**proxy](#proxy) * [**proxyIpHeader](#proxyIpHeader) * [**request](#request) * [**response](#response) * [**subdomainOffset](#subdomainOffset) ### Methods * [**addConfigObject](#addConfigObject) * [**callback](#callback) * [**createAnonymousContext](#createAnonymousContext) * [**createContext](#createContext) * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getEventMiddleware](#getEventMiddleware) * [**getFramework](#getFramework) * [**getFrameworkType](#getFrameworkType) * [**getFunctionName](#getFunctionName) * [**getFunctionServiceName](#getFunctionServiceName) * [**getInitializeContext](#getInitializeContext) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**getServerlessInstance](#getServerlessInstance) * [**inspect](#inspect) * [**invokeTriggerFunction](#invokeTriggerFunction) * [**onerror](#onerror) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**toJSON](#toJSON) * [**use](#use) * [**useEventMiddleware](#useEventMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Properties[**](#Properties) ### [**](#context)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L10)context **context: any Inherited from IMidwayFaaSApplication.context ### [**](#keys)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L9)keys **keys: any Inherited from IMidwayFaaSApplication.keys ### [**](#maxIpsCount)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L7)maxIpsCount **maxIpsCount: number Inherited from IMidwayFaaSApplication.maxIpsCount ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L8)middleware **middleware: any\[] Inherited from IMidwayFaaSApplication.middleware ### [**](#proxy)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L4)proxy **proxy: boolean Inherited from IMidwayFaaSApplication.proxy ### [**](#proxyIpHeader)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L6)proxyIpHeader **proxyIpHeader: string Inherited from IMidwayFaaSApplication.proxyIpHeader ### [**](#request)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L11)request **request: any Inherited from IMidwayFaaSApplication.request ### [**](#response)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L12)response **response: any Inherited from IMidwayFaaSApplication.response ### [**](#subdomainOffset)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L5)subdomainOffset **subdomainOffset: number Inherited from IMidwayFaaSApplication.subdomainOffset ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L840)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayFaaSApplication.addConfigObject Add new value to current config ### [**](#callback)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L35)callback * **callback(): (req: any, res: any, respond: any) => any - Inherited from IMidwayFaaSApplication.callback Return a request handler callback for node's native http server. * **@api** public ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L830)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/3.0.0/faas/interface/Context.md) - Inherited from IMidwayFaaSApplication.createAnonymousContext create a context with RequestContainer ### [**](#createContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L17)createContext * **createContext(req: any, res: any): any - Inherited from IMidwayFaaSApplication.createContext Initialize a new context. ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L821)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayFaaSApplication.createLogger Create a logger by name and options ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L438)generateMiddleware * **generateMiddleware(middlewareId: any): Promise<[FaaSMiddleware](/api/3.0.0/faas.md#FaaSMiddleware)> - Inherited from IMidwayFaaSApplication.generateMiddleware * **@deprecated** ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L780)getAppDir * **getAppDir(): string - Inherited from IMidwayFaaSApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L801)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from IMidwayFaaSApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L851)getAttr * **getAttr\(key: string): T - Inherited from IMidwayFaaSApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L776)getBaseDir * **getBaseDir(): string - Inherited from IMidwayFaaSApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L806)getConfig * **getConfig(key? : string): any - Inherited from IMidwayFaaSApplication.getConfig Get all configuration values or get the specified configuration through parameters ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L815)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayFaaSApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L784)getEnv * **getEnv(): string - Inherited from IMidwayFaaSApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getEventMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L451)getEventMiddleware * **getEventMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/faas/interface/Context.md), NextFunction, undefined> - Inherited from IMidwayFaaSApplication.getEventMiddleware ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L788)getFramework * **getFramework(): IMidwayFramework<[Application](/api/3.0.0/faas/interface/Application.md), [Context](/api/3.0.0/faas/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayFaaSApplication.getFramework get current related framework ### [**](#getFrameworkType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L793)getFrameworkType * **getFrameworkType(): [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) - Inherited from IMidwayFaaSApplication.getFrameworkType * **@deprecated** Get current framework type in MidwayFrameworkType enum ### [**](#getFunctionName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L442)getFunctionName * **getFunctionName(): string - Inherited from IMidwayFaaSApplication.getFunctionName Get function name in serverless environment ### [**](#getFunctionServiceName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L446)getFunctionServiceName * **getFunctionServiceName(): string - Inherited from IMidwayFaaSApplication.getFunctionServiceName Get function service name in serverless environment ### [**](#getInitializeContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L429)getInitializeContext * **getInitializeContext(): any - Inherited from IMidwayFaaSApplication.getInitializeContext ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L811)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayFaaSApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L860)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/3.0.0/faas/interface/Context.md), R, N> - Inherited from IMidwayFaaSApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L874)getNamespace * **getNamespace(): string - Inherited from IMidwayFaaSApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L797)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayFaaSApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L825)getProjectName * **getProjectName(): string - Inherited from IMidwayFaaSApplication.getProjectName Get project name, just package.json name ### [**](#getServerlessInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L461)getServerlessInstance * **getServerlessInstance\(serviceClass: [ObjectIdentifier](/api/3.0.0/decorator.md#ObjectIdentifier) | new (...args: any\[]) => T, customContext? : Record\): Promise\ - Inherited from IMidwayFaaSApplication.getServerlessInstance #### Type parameters * **T** ### [**](#inspect)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L50)inspect * **inspect(): any - Inherited from IMidwayFaaSApplication.inspect Inspect implementation. * **@api** public ### [**](#invokeTriggerFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L456)invokeTriggerFunction * **invokeTriggerFunction(context: any, handler: string, options: [HandlerOptions](/api/3.0.0/faas/interface/HandlerOptions.md)): Promise\ - Inherited from IMidwayFaaSApplication.invokeTriggerFunction ### [**](#onerror)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L57)onerror * **onerror(err: any): void - Inherited from IMidwayFaaSApplication.onerror Default error handler. * **@api** private ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L846)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayFaaSApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L835)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayFaaSApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#toJSON)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L43)toJSON * **toJSON(): any - Inherited from IMidwayFaaSApplication.toJSON Return JSON representation. We only bother showing settings. * **@api** public ### [**](#use)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L433)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L27)use * **use(middleware: [FaaSMiddleware](/api/3.0.0/faas.md#FaaSMiddleware)): any * **use(fn: (...args: any\[]) => Promise\): [Application](/api/3.0.0/faas/interface/Application.md) - Inherited from IMidwayFaaSApplication.use * **@deprecated** use useMiddleware instead ### [**](#useEventMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L448)useEventMiddleware * **useEventMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/faas/interface/Context.md), NextFunction, undefined>): void - Inherited from IMidwayFaaSApplication.useEventMiddleware ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L865)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/3.0.0/faas/interface/Context.md), R, N>): void - Inherited from IMidwayFaaSApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L870)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/3.0.0/faas/interface/Context.md)>): void - Inherited from IMidwayFaaSApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L856)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/faas/interface/Context.md), R, N>): void - Inherited from IMidwayFaaSApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * [FaaSContext](/api/3.0.0/faas/interface/FaaSContext.md) * *Context* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**env](#env) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**logger](#logger) * [**method](#method) * [**originContext](#originContext) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**requestContext](#requestContext) * [**res](#res) * [**response](#response) * [**startTime](#startTime) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**setAttr](#setAttr) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L154)accept **accept: any Inherited from FaaSContext.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L201)body **body: any Inherited from FaaSContext.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L373)cookies **cookies: Cookies Inherited from FaaSContext.cookies FaaS Cookies Object ### [**](#env)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L405)env **env: string Inherited from FaaSContext.env ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L246)etag **etag: string Inherited from FaaSContext.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L166)header **header: {} Inherited from FaaSContext.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L170)headers **headers: {} Inherited from FaaSContext.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L140)host **host: string Inherited from FaaSContext.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L144)hostname **hostname: string Inherited from FaaSContext.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L148)ip **ip: string Inherited from FaaSContext.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L233)lastModified **lastModified: Date Inherited from FaaSContext.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L207)length **length: number Inherited from FaaSContext.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L404)logger **logger: ILogger Inherited from FaaSContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L162)method **method: string Inherited from FaaSContext.method Get request method. ### [**](#originContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L407)originContext **originContext: any Inherited from FaaSContext.originContext ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L369)originEvent **originEvent: Record\ Inherited from FaaSContext.originEvent FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L153)originalUrl **originalUrl: string Inherited from FaaSContext.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L179)params **params: {} Inherited from FaaSContext.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L158)path **path: string Inherited from FaaSContext.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L174)query **query: {} Inherited from FaaSContext.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L353)req **req: any Inherited from FaaSContext.req It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L361)request **request: [FaaSHTTPRequest](/api/3.0.0/faas/interface/FaaSHTTPRequest.md) Inherited from FaaSContext.request FaaS http request object ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L406)requestContext **requestContext: MidwayRequestContainer Inherited from FaaSContext.requestContext ### [**](#res)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L357)res **res: any Inherited from FaaSContext.res It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L365)response **response: [FaaSHTTPResponse](/api/3.0.0/faas/interface/FaaSHTTPResponse.md) Inherited from FaaSContext.response FaaS http response object ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from FaaSContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L377)state **state: [State](/api/3.0.0/faas/interface/State.md) Inherited from FaaSContext.state FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L197)status **status: number Inherited from FaaSContext.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L301)streaming **streaming: boolean Inherited from FaaSContext.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L224)type **type: string Inherited from FaaSContext.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L152)url **url: string Inherited from FaaSContext.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L54)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L55)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L56)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from FaaSContext.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L78)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L79)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L80)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from FaaSContext.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L66)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L67)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L68)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from FaaSContext.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L90)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L91)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L92)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from FaaSContext.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L272)append * **append(field: string, val: string | string\[]): void - Inherited from FaaSContext.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L136)get * **get(field: string): string - Inherited from FaaSContext.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from FaaSContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from FaaSContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from FaaSContext.getLogger ### [**](#is)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L116)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L117)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from FaaSContext.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L292)redirect * **redirect(url: string, alt? : string): void - Inherited from FaaSContext.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L277)remove * **remove(field: string): void - Inherited from FaaSContext.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L258)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L259)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from FaaSContext.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from FaaSContext.setAttr Set value to app attribute map ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L393)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L398)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L399)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Inherited from FaaSContext.throw Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSContext ### Hierarchy * IMidwayContext<[FaaSHTTPContext](/api/3.0.0/faas/interface/FaaSHTTPContext.md)> * *FaaSContext* * [Context](/api/3.0.0/faas/interface/Context.md) ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**env](#env) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**logger](#logger) * [**method](#method) * [**originContext](#originContext) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**requestContext](#requestContext) * [**res](#res) * [**response](#response) * [**startTime](#startTime) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**setAttr](#setAttr) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L154)accept **accept: any Inherited from IMidwayContext.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L201)body **body: any Inherited from IMidwayContext.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L373)cookies **cookies: Cookies Inherited from IMidwayContext.cookies FaaS Cookies Object ### [**](#env)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L405)env **env: string ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L246)etag **etag: string Inherited from IMidwayContext.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L166)header **header: {} Inherited from IMidwayContext.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L170)headers **headers: {} Inherited from IMidwayContext.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L140)host **host: string Inherited from IMidwayContext.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L144)hostname **hostname: string Inherited from IMidwayContext.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L148)ip **ip: string Inherited from IMidwayContext.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L233)lastModified **lastModified: Date Inherited from IMidwayContext.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L207)length **length: number Inherited from IMidwayContext.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L404)logger **logger: ILogger Overrides IMidwayContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L162)method **method: string Inherited from IMidwayContext.method Get request method. ### [**](#originContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L407)originContext **originContext: any ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L369)originEvent **originEvent: Record\ Inherited from IMidwayContext.originEvent FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L153)originalUrl **originalUrl: string Inherited from IMidwayContext.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L179)params **params: {} Inherited from IMidwayContext.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L158)path **path: string Inherited from IMidwayContext.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L174)query **query: {} Inherited from IMidwayContext.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L353)req **req: any Inherited from IMidwayContext.req It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L361)request **request: [FaaSHTTPRequest](/api/3.0.0/faas/interface/FaaSHTTPRequest.md) Inherited from IMidwayContext.request FaaS http request object ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L406)requestContext **requestContext: MidwayRequestContainer Overrides IMidwayContext.requestContext ### [**](#res)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L357)res **res: any Inherited from IMidwayContext.res It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L365)response **response: [FaaSHTTPResponse](/api/3.0.0/faas/interface/FaaSHTTPResponse.md) Inherited from IMidwayContext.response FaaS http response object ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L377)state **state: [State](/api/3.0.0/faas/interface/State.md) Inherited from IMidwayContext.state FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L197)status **status: number Inherited from IMidwayContext.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L301)streaming **streaming: boolean Inherited from IMidwayContext.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L224)type **type: string Inherited from IMidwayContext.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L152)url **url: string Inherited from IMidwayContext.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L54)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L55)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L56)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from IMidwayContext.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L78)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L79)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L80)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from IMidwayContext.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L66)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L67)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L68)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from IMidwayContext.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L90)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L91)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L92)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from IMidwayContext.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L272)append * **append(field: string, val: string | string\[]): void - Inherited from IMidwayContext.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L136)get * **get(field: string): string - Inherited from IMidwayContext.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#is)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L116)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L117)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from IMidwayContext.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L292)redirect * **redirect(url: string, alt? : string): void - Inherited from IMidwayContext.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L277)remove * **remove(field: string): void - Inherited from IMidwayContext.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L258)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L259)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from IMidwayContext.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L393)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L398)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L399)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Inherited from IMidwayContext.throw Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSHTTPContext ### Hierarchy * ContextDelegatedRequest * ContextDelegatedResponse * *FaaSHTTPContext* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**method](#method) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**res](#res) * [**response](#response) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L154)accept **accept: any Inherited from ContextDelegatedRequest.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L201)body **body: any Inherited from ContextDelegatedResponse.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L373)cookies **cookies: Cookies FaaS Cookies Object ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L246)etag **etag: string Inherited from ContextDelegatedResponse.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L166)header **header: {} Inherited from ContextDelegatedRequest.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L170)headers **headers: {} Inherited from ContextDelegatedRequest.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L140)host **host: string Inherited from ContextDelegatedRequest.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L144)hostname **hostname: string Inherited from ContextDelegatedRequest.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L148)ip **ip: string Inherited from ContextDelegatedRequest.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L233)lastModified **lastModified: Date Inherited from ContextDelegatedResponse.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L207)length **length: number Inherited from ContextDelegatedResponse.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L162)method **method: string Inherited from ContextDelegatedRequest.method Get request method. ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L369)originEvent **originEvent: Record\ FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L153)originalUrl **originalUrl: string Inherited from ContextDelegatedRequest.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L179)params **params: {} Inherited from ContextDelegatedRequest.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L158)path **path: string Inherited from ContextDelegatedRequest.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L174)query **query: {} Inherited from ContextDelegatedRequest.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L353)req **req: any It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L361)request **request: [FaaSHTTPRequest](/api/3.0.0/faas/interface/FaaSHTTPRequest.md) FaaS http request object ### [**](#res)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L357)res **res: any It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L365)response **response: [FaaSHTTPResponse](/api/3.0.0/faas/interface/FaaSHTTPResponse.md) FaaS http response object ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L377)state **state: [State](/api/3.0.0/faas/interface/State.md) FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L197)status **status: number Inherited from ContextDelegatedResponse.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L301)streaming **streaming: boolean Inherited from ContextDelegatedResponse.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L224)type **type: string Inherited from ContextDelegatedResponse.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L152)url **url: string Inherited from ContextDelegatedRequest.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L54)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L55)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L56)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L78)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L79)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L80)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L66)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L67)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L68)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L90)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L91)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L92)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L272)append * **append(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L136)get * **get(field: string): string - Inherited from ContextDelegatedRequest.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L116)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L117)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L292)redirect * **redirect(url: string, alt? : string): void - Inherited from ContextDelegatedResponse.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L277)remove * **remove(field: string): void - Inherited from ContextDelegatedResponse.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L258)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L259)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L393)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L398)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L399)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSHTTPRequest ### Hierarchy * ContextDelegatedRequest * *FaaSHTTPRequest* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**method](#method) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**pathParameters](#pathParameters) * [**query](#query) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**get](#get) * [**is](#is) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L154)accept **accept: any Inherited from ContextDelegatedRequest.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L186)body **body: any Get parsed request body from event ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L166)header **header: {} Inherited from ContextDelegatedRequest.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L170)headers **headers: {} Inherited from ContextDelegatedRequest.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L140)host **host: string Inherited from ContextDelegatedRequest.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L144)hostname **hostname: string Inherited from ContextDelegatedRequest.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L148)ip **ip: string Inherited from ContextDelegatedRequest.ip Request remote address. ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L162)method **method: string Inherited from ContextDelegatedRequest.method Get request method. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L153)originalUrl **originalUrl: string Inherited from ContextDelegatedRequest.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L179)params **params: {} Inherited from ContextDelegatedRequest.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L158)path **path: string Inherited from ContextDelegatedRequest.path Get request pathname. ### [**](#pathParameters)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L190)pathParameters **pathParameters: any Get Parsed path parameters from event ### [**](#query)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L174)query **query: {} Inherited from ContextDelegatedRequest.query Get parsed query-string. ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L152)url **url: string Inherited from ContextDelegatedRequest.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L54)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L55)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L56)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L78)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L79)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L80)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L66)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L67)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L68)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L90)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L91)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L92)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L136)get * **get(field: string): string - Inherited from ContextDelegatedRequest.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L116)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L117)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` --- # FaaSHTTPResponse ### Hierarchy * ContextDelegatedResponse * Pick\ * *FaaSHTTPResponse* ## Index[**](#Index) ### Properties * [**body](#body) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**lastModified](#lastModified) * [**length](#length) * [**status](#status) * [**streaming](#streaming) * [**type](#type) ### Methods * [**append](#append) * [**get](#get) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) ## Properties[**](#Properties) ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L201)body **body: any Inherited from ContextDelegatedResponse.body Get/Set response body. ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L246)etag **etag: string Inherited from ContextDelegatedResponse.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L310)header **header: {} Return response header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L314)headers **headers: {} Return response header, alias as response.header ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L233)lastModified **lastModified: Date Inherited from ContextDelegatedResponse.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L207)length **length: number Inherited from ContextDelegatedResponse.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L197)status **status: number Inherited from ContextDelegatedResponse.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L301)streaming **streaming: boolean Inherited from ContextDelegatedResponse.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L224)type **type: string Inherited from ContextDelegatedResponse.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ## Methods[**](#Methods) ### [**](#append)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L272)append * **append(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L344)get * **get(field: string): string - Return response header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L324)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L325)is * **is(...types: string\[]): string * **is(types: string\[]): string - Check whether the response is one of the listed types. Pretty much the same as `this.request.is()`. * **@api** public ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L292)redirect * **redirect(url: string, alt? : string): void - Inherited from ContextDelegatedResponse.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L277)remove * **remove(field: string): void - Inherited from ContextDelegatedResponse.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L258)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L259)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); --- # FormatResponseOptions ### Hierarchy * *FormatResponseOptions* * [HandlerOptions](/api/3.0.0/faas/interface/HandlerOptions.md) ## Index[**](#Index) ### Properties * [**supportBufferResponse](#supportBufferResponse) ## Properties[**](#Properties) ### [**](#supportBufferResponse)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L418)optionalsupportBufferResponse **supportBufferResponse? : boolean --- # HandlerOptions ### Hierarchy * [FormatResponseOptions](/api/3.0.0/faas/interface/FormatResponseOptions.md) * *HandlerOptions* ## Index[**](#Index) ### Properties * [**isCustomHttpResponse](#isCustomHttpResponse) * [**isHttpFunction](#isHttpFunction) * [**supportBufferResponse](#supportBufferResponse) ## Properties[**](#Properties) ### [**](#isCustomHttpResponse)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L423)optionalisCustomHttpResponse **isCustomHttpResponse? : boolean ### [**](#isHttpFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L422)optionalisHttpFunction **isHttpFunction? : boolean ### [**](#supportBufferResponse)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L418)optionalsupportBufferResponse **supportBufferResponse? : boolean Inherited from FormatResponseOptions.supportBufferResponse --- # HttpResponseFormat \ ## Index[**](#Index) ### Properties * [**body](#body) * [**headers](#headers) * [**isBase64Encoded](#isBase64Encoded) * [**statusCode](#statusCode) ## Properties[**](#Properties) ### [**](#body)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L518)body **body: T ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L517)headers **headers: Record\ ### [**](#isBase64Encoded)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L515)isBase64Encoded **isBase64Encoded: boolean ### [**](#statusCode)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L516)statusCode **statusCode: number --- # IFaaSConfigurationOptions ### Hierarchy * IConfigurationOptions * *IFaaSConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**applicationAdapter](#applicationAdapter) * [**config](#config) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**initializeContext](#initializeContext) * [**logger](#logger) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#applicationAdapter)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L477)optionalapplicationAdapter **applicationAdapter? : { getApplication: any; getFunctionName: any; getFunctionServiceName: any; runAppHook? : any; runContextHook? : any } ### [**](#config)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L475)optionalconfig **config? : object ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#initializeContext)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L476)optionalinitializeContext **initializeContext? : object ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger --- # IWebMiddleware * **@deprecated** ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L493)resolve * **resolve(): [FaaSMiddleware](/api/3.0.0/faas.md#FaaSMiddleware) --- # ServerlessStarterOptions ### Hierarchy * IMidwayBootstrapOptions * *ServerlessStarterOptions* ## Index[**](#Index) ### Properties * [**aggregationHandlerName](#aggregationHandlerName) * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**asyncContextManager](#asyncContextManager) * [**baseDir](#baseDir) * [**configurationModule](#configurationModule) * [**createAdapter](#createAdapter) * [**globalConfig](#globalConfig) * [**handlerName](#handlerName) * [**handlerNameMapping](#handlerNameMapping) * [**ignore](#ignore) * [**imports](#imports) * [**initializeMethodName](#initializeMethodName) * [**logger](#logger) * [**loggerFactory](#loggerFactory) * [**moduleDetector](#moduleDetector) * [**moduleLoadType](#moduleLoadType) * [**performance](#performance) * [**preloadModules](#preloadModules) ## Properties[**](#Properties) ### [**](#aggregationHandlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L499)optionalaggregationHandlerName **aggregationHandlerName? : string ### [**](#appDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L881)optionalappDir **appDir? : string Inherited from IMidwayBootstrapOptions.appDir ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L882)optionalapplicationContext **applicationContext? : IMidwayContainer Inherited from IMidwayBootstrapOptions.applicationContext ### [**](#asyncContextManager)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L899)optionalasyncContextManager **asyncContextManager? : AsyncContextManager Inherited from IMidwayBootstrapOptions.asyncContextManager ### [**](#baseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L880)optionalbaseDir **baseDir? : string Inherited from IMidwayBootstrapOptions.baseDir ### [**](#configurationModule)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalconfigurationModule **configurationModule? : any Inherited from IMidwayBootstrapOptions.configurationModule * **@deprecated** please use 'imports' ### [**](#createAdapter)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L504)optionalcreateAdapter **createAdapter? : () => Promise<{ close: any; createAppHook: any }> ### [**](#globalConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L896)optionalglobalConfig **globalConfig? : Record\ | {}\[] Inherited from IMidwayBootstrapOptions.globalConfig ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L498)optionalhandlerName **handlerName? : string ### [**](#handlerNameMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L500)optionalhandlerNameMapping **handlerNameMapping? : (handlerName: string, ...args: unknown\[]) => \[string, ...unknown\[]] ### [**](#ignore)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L895)optionalignore **ignore? : string\[] Inherited from IMidwayBootstrapOptions.ignore * **@deprecated** please set it from '@Configuration' decorator ### [**](#imports)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalimports **imports? : any Inherited from IMidwayBootstrapOptions.imports ### [**](#initializeMethodName)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L497)optionalinitializeMethodName **initializeMethodName? : string ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L891)optionallogger **logger? : boolean | ILogger Inherited from IMidwayBootstrapOptions.logger ### [**](#loggerFactory)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L900)optionalloggerFactory **loggerFactory? : LoggerFactory\ Inherited from IMidwayBootstrapOptions.loggerFactory ### [**](#moduleDetector)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L890)optionalmoduleDetector **moduleDetector? : false | IFileDetector Inherited from IMidwayBootstrapOptions.moduleDetector ### [**](#moduleLoadType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalmoduleLoadType **moduleLoadType? : ModuleLoadType Inherited from IMidwayBootstrapOptions.moduleLoadType ### [**](#performance)[**](https://github.com/midwayjs/midway/blob/main/packages/faas/src/interface.ts#L508)optionalperformance **performance? : { end: any; mark: any } ### [**](#preloadModules)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L883)optionalpreloadModules **preloadModules? : any\[] Inherited from IMidwayBootstrapOptions.preloadModules --- # State --- # wrapHttpRequestOptions ### Hierarchy * HttpResponseOptions * *wrapHttpRequestOptions* ## Index[**](#Index) ### Properties * [**writeableImpl](#writeableImpl) ## Properties[**](#Properties) ### [**](#writeableImpl)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/interface.d.ts#L2)optionalwriteableImpl **writeableImpl? : { end: (chunk? : any, encoding? : string) => void; write: (chunk: any, encoding? : string) => void } Inherited from HttpResponseOptions.writeableImpl --- # @midwayjs/grpc ## Index[**](#Index) ### Classes * [**Clients](/api/3.0.0/grpc/class/Clients.md) * [**Configuration](/api/3.0.0/grpc/class/Configuration.md) * [**Framework](/api/3.0.0/grpc/class/Framework.md) ### Functions * [**createGRPCConsumer](/api/3.0.0/grpc/function/createGRPCConsumer.md) * [**loadProto](/api/3.0.0/grpc/function/loadProto.md) ### Interfaces * [**Context](/api/3.0.0/grpc/interface/Context.md) * [**DefaultConfig](/api/3.0.0/grpc/interface/DefaultConfig.md) * [**IClientDuplexStreamService](/api/3.0.0/grpc/interface/IClientDuplexStreamService.md) * [**IClientOptions](/api/3.0.0/grpc/interface/IClientOptions.md) * [**IClientReadableStreamService](/api/3.0.0/grpc/interface/IClientReadableStreamService.md) * [**IClientUnaryService](/api/3.0.0/grpc/interface/IClientUnaryService.md) * [**IClientWritableStreamService](/api/3.0.0/grpc/interface/IClientWritableStreamService.md) * [**IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md) * [**IGRPCServiceOptions](/api/3.0.0/grpc/interface/IGRPCServiceOptions.md) * [**IMidwayGRPFrameworkOptions](/api/3.0.0/grpc/interface/IMidwayGRPFrameworkOptions.md) ### Type Aliases * [**Application](/api/3.0.0/grpc.md#Application) * [**IMidwayGRPCApplication](/api/3.0.0/grpc.md#IMidwayGRPCApplication) * [**NextFunction](/api/3.0.0/grpc.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L35)Application **Application: [IMidwayGRPCApplication](/api/3.0.0/grpc.md#IMidwayGRPCApplication) ### [**](#IMidwayGRPCApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L33)IMidwayGRPCApplication **IMidwayGRPCApplication: IMidwayApplication<[Context](/api/3.0.0/grpc/interface/Context.md), Server> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L36)NextFunction **NextFunction: BaseNextFunction --- # Clients ### Hierarchy * Map * *Clients* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**grpcConfig](#grpcConfig) * [**logger](#logger) ### Methods * [**createClient](#createClient) * [**getClientRequestImpl](#getClientRequestImpl) * [**getService](#getService) * [**initService](#initService) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L49)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)externalconstructor * **new Clients(): [GRPCClients](/api/3.0.0/grpc/class/Clients.md) * **new Clients(): [GRPCClients](/api/3.0.0/grpc/class/Clients.md) - Inherited from Map.constructor ## Properties[**](#Properties) ### [**](#grpcConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L28)grpcConfig **grpcConfig: [DefaultConfig](/api/3.0.0/grpc/interface/DefaultConfig.md) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L31)logger **logger: ILogger ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L44)createClient * **createClient\(options: [IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md)): Promise\ - #### Type parameters * **T** ### [**](#getClientRequestImpl)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L92)getClientRequestImpl * **getClientRequestImpl(client: any, originalFunction: any, options? : {}): any ### [**](#getService)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L88)getService * **getService\(serviceName: string): T - #### Type parameters * **T** ### [**](#initService)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/comsumer/clients.ts#L34)initService * **initService(): Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**clientConfig](#clientConfig) * [**logger](#logger) * [**providerConfig](#providerConfig) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [GrpcConfiguration](/api/3.0.0/grpc/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L26)applicationContext **applicationContext: IMidwayContainer ### [**](#clientConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L32)clientConfig **clientConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L35)logger **logger: ILogger ### [**](#providerConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L29)providerConfig **providerConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L38)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/configuration.ts#L42)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayGRPCApplication](/api/3.0.0/grpc.md#IMidwayGRPCApplication), [Context](/api/3.0.0/grpc/interface/Context.md), [IMidwayGRPFrameworkOptions](/api/3.0.0/grpc/interface/IMidwayGRPFrameworkOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) * [**providerConfig](#providerConfig) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayGRPCFramework](/api/3.0.0/grpc/class/Framework.md) - Inherited from BaseFramework< IMidwayGRPCApplication, Context, IMidwayGRPFrameworkOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L44)publicapp **app: [IMidwayGRPCApplication](/api/3.0.0/grpc.md#IMidwayGRPCApplication) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayGRPFrameworkOptions](/api/3.0.0/grpc/interface/IMidwayGRPFrameworkOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/grpc/interface/Context.md)\, unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ### [**](#providerConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L48)providerConfig **providerConfig: any ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L58)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/grpc/interface/Context.md)\, R, N>): Promise\, R, N>> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L253)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L50)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [IMidwayGRPCApplication](/api/3.0.0/grpc.md#IMidwayGRPCApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L289)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L281)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/grpc/interface/Context.md)\, unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L285)publicgetServer * **getServer(): Server ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayGRPCFramework](/api/3.0.0/grpc/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L54)isEnable * **isEnable(): boolean - Overrides BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/provider/framework.ts#L234)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/grpc/interface/Context.md)\, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/grpc/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/grpc/interface/Context.md)\>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/grpc/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # createGRPCConsumer ### Callable * **createGRPCConsumer\(options: [IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md)): Promise\ *** * #### Type parameters * **T** --- # loadProto ### Callable * **loadProto(options: { loaderOptions? : any; protoPath: string }): PackageDefinition --- # Context \ ### Hierarchy * IMidwayContext\> * *Context* ## Index[**](#Index) ### Properties * [**logger](#logger) * [**method](#method) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L30)method **method: string ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayContext.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # DefaultConfig ### Hierarchy * IConfigurationOptions * *DefaultConfig* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) * [**services](#services) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#services)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L95)services **services: [IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md)\[] --- # IClientDuplexStreamService \ ## Index[**](#Index) ### Methods * [**end](#end) * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#end)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L123)end * **end(): void ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L121)getCall * **getCall(): ClientDuplexStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L119)sendMessage * **sendMessage(reqData: reqType): Promise\ --- # IClientOptions ## Index[**](#Index) ### Properties * [**messageKey](#messageKey) * [**metadata](#metadata) * [**timeout](#timeout) * [**timeoutMessage](#timeoutMessage) ## Properties[**](#Properties) ### [**](#messageKey)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L130)optionalmessageKey **messageKey? : string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L127)optionalmetadata **metadata? : Metadata ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L128)optionaltimeout **timeout? : number ### [**](#timeoutMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L129)optionaltimeoutMessage **timeoutMessage? : number --- # IClientReadableStreamService \ ## Index[**](#Index) ### Methods * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L107)getCall * **getCall(): ClientReadableStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L105)sendMessage * **sendMessage(reqData: reqType): Promise\ --- # IClientUnaryService \ ## Index[**](#Index) ### Methods * [**sendMessage](#sendMessage) * [**sendMessageWithCallback](#sendMessageWithCallback) ## Methods[**](#Methods) ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L99)sendMessage * **sendMessage(reqData: reqType, handler? : (call: SurfaceCall) => void): Promise\ ### [**](#sendMessageWithCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L101)sendMessageWithCallback * **sendMessageWithCallback(content: reqType, callback: any): SurfaceCall --- # IClientWritableStreamService \ ## Index[**](#Index) ### Methods * [**end](#end) * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#end)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L113)end * **end(): Promise\ ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L115)getCall * **getCall(): ClientWritableStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L111)sendMessage * **sendMessage(reqData: reqType): [IClientWritableStreamService](/api/3.0.0/grpc/interface/IClientWritableStreamService.md)\ --- # IGRPCClientServiceOptions ### Hierarchy * [IGRPCServiceOptions](/api/3.0.0/grpc/interface/IGRPCServiceOptions.md) * *IGRPCClientServiceOptions* ## Index[**](#Index) ### Properties * [**clientOptions](#clientOptions) * [**credentials](#credentials) * [**loaderOptions](#loaderOptions) * [**package](#package) * [**protoPath](#protoPath) * [**service](#service) * [**url](#url) ## Properties[**](#Properties) ### [**](#clientOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L67)optionalclientOptions **clientOptions? : ClientOptions Client options. Optional. ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L63)optionalcredentials **credentials? : ServerCredentials Server credentials. Optional. ### [**](#loaderOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L58)optionalloaderOptions **loaderOptions? : object proto file loader options. Optional ### [**](#package)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L47)optionalpackage **package? : string Inherited from IGRPCServiceOptions.package protobuf package name ### [**](#protoPath)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L42)optionalprotoPath **protoPath? : string Inherited from IGRPCServiceOptions.protoPath proto path ### [**](#service)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L71)optionalservice **service? : string Service name. Optional. ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L54)url **url: string application gRPC connection string --- # IGRPCServiceOptions ### Hierarchy * *IGRPCServiceOptions* * [IGRPCClientServiceOptions](/api/3.0.0/grpc/interface/IGRPCClientServiceOptions.md) ## Index[**](#Index) ### Properties * [**package](#package) * [**protoPath](#protoPath) ## Properties[**](#Properties) ### [**](#package)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L47)optionalpackage **package? : string protobuf package name ### [**](#protoPath)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L42)optionalprotoPath **protoPath? : string proto path --- # IMidwayGRPFrameworkOptions ### Hierarchy * IConfigurationOptions * *IMidwayGRPFrameworkOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**credentials](#credentials) * [**loaderOptions](#loaderOptions) * [**logger](#logger) * [**serverOptions](#serverOptions) * [**services](#services) * [**url](#url) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L87)optionalcredentials **credentials? : ServerCredentials Server credentials. Optional. ### [**](#loaderOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L83)optionalloaderOptions **loaderOptions? : object proto file loader options. Optional ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L91)optionalserverOptions **serverOptions? : ChannelOptions grpc server options ### [**](#services)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L79)optionalservices **services? : [IGRPCServiceOptions](/api/3.0.0/grpc/interface/IGRPCServiceOptions.md)\[] ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/grpc/src/interface.ts#L78)optionalurl **url? : string gRPC Server connection url, like 'localhost:6565' --- # @midwayjs/http-proxy ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/http-proxy/class/Configuration.md) * [**HttpProxyMiddleware](/api/3.0.0/http-proxy/class/HttpProxyMiddleware.md) ### Interfaces * [**HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md) * [**HttpProxyStrategy](/api/3.0.0/http-proxy/interface/HttpProxyStrategy.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**httpProxy](#httpProxy) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [HttpProxyConfiguration](/api/3.0.0/http-proxy/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#httpProxy)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/configuration.ts#L24)httpProxy **httpProxy: Partial<[HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md)> ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/configuration.ts#L26)onReady * **onReady(): Promise\ --- # HttpProxyMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**httpProxy](#httpProxy) * [**logger](#logger) ### Methods * [**execProxy](#execProxy) * [**getProxyList](#getProxyList) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpProxyMiddleware(): [HttpProxyMiddleware](/api/3.0.0/http-proxy/class/HttpProxyMiddleware.md) ## Properties[**](#Properties) ### [**](#httpProxy)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L15)httpProxy **httpProxy: [HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L18)logger **logger: ILogger ## Methods[**](#Methods) ### [**](#execProxy)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L34)execProxy * **execProxy(ctx: any, req: any, res: any, next: any, isServerless: any): Promise\ ### [**](#getProxyList)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L119)getProxyList * **getProxyList(url: any): { proxy: [HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md); url: URL } ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L20)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/middleware.ts#L160)staticgetName * **getName(): string --- # HttpProxyConfig ### Hierarchy * [HttpProxyStrategy](/api/3.0.0/http-proxy/interface/HttpProxyStrategy.md) * *HttpProxyConfig* ## Index[**](#Index) ### Properties * [**default](#default) * [**enable](#enable) * [**host](#host) * [**ignoreHeaders](#ignoreHeaders) * [**match](#match) * [**proxyTimeout](#proxyTimeout) * [**strategy](#strategy) * [**target](#target) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L13)optionaldefault **default? : [HttpProxyStrategy](/api/3.0.0/http-proxy/interface/HttpProxyStrategy.md) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L12)optionalenable **enable? : boolean ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L3)optionalhost **host? : string Inherited from HttpProxyStrategy.host ### [**](#ignoreHeaders)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L6)optionalignoreHeaders **ignoreHeaders? : {} Inherited from HttpProxyStrategy.ignoreHeaders ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L2)optionalmatch **match? : RegExp Inherited from HttpProxyStrategy.match ### [**](#proxyTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L5)optionalproxyTimeout **proxyTimeout? : number Inherited from HttpProxyStrategy.proxyTimeout ### [**](#strategy)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L14)optionalstrategy **strategy? : {} ### [**](#target)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L4)optionaltarget **target? : string Inherited from HttpProxyStrategy.target --- # HttpProxyStrategy ### Hierarchy * *HttpProxyStrategy* * [HttpProxyConfig](/api/3.0.0/http-proxy/interface/HttpProxyConfig.md) ## Index[**](#Index) ### Properties * [**host](#host) * [**ignoreHeaders](#ignoreHeaders) * [**match](#match) * [**proxyTimeout](#proxyTimeout) * [**target](#target) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L3)optionalhost **host? : string ### [**](#ignoreHeaders)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L6)optionalignoreHeaders **ignoreHeaders? : {} ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L2)optionalmatch **match? : RegExp ### [**](#proxyTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L5)optionalproxyTimeout **proxyTimeout? : number ### [**](#target)[**](https://github.com/midwayjs/midway/blob/main/packages/http-proxy/src/interface.ts#L4)optionaltarget **target? : string --- # @midwayjs/i18n ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/i18n/class/Configuration.md) * [**I18nFilter](/api/3.0.0/i18n/class/I18nFilter.md) * [**I18nMiddleware](/api/3.0.0/i18n/class/I18nMiddleware.md) * [**MidwayI18nService](/api/3.0.0/i18n/class/MidwayI18nService.md) * [**MidwayI18nServiceSingleton](/api/3.0.0/i18n/class/MidwayI18nServiceSingleton.md) ### Functions * [**formatLocale](/api/3.0.0/i18n/function/formatLocale.md) ### Interfaces * [**I18nOptions](/api/3.0.0/i18n/interface/I18nOptions.md) * [**RequestResolver](/api/3.0.0/i18n/interface/RequestResolver.md) * [**TranslateOptions](/api/3.0.0/i18n/interface/TranslateOptions.md) ### Variables * [**I18N\_ATTR\_KEY](/api/3.0.0/i18n.md#I18N_ATTR_KEY) ## Variables[**](#Variables) ### [**](#I18N_ATTR_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L25)constI18N\_ATTR\_KEY **I18N\_ATTR\_KEY: i18n:locale = 'i18n:locale' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [I18nConfiguration](/api/3.0.0/i18n/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/configuration.ts#L19)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/configuration.ts#L20)onReady * **onReady(): Promise\ --- # I18nFilter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**i18nConfig](#i18nConfig) * [**resolverConfig](#resolverConfig) ### Methods * [**match](#match) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new I18nFilter(): [I18nFilter](/api/3.0.0/i18n/class/I18nFilter.md) ## Properties[**](#Properties) ### [**](#i18nConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L19)i18nConfig **i18nConfig: [I18nOptions](/api/3.0.0/i18n/interface/I18nOptions.md) ### [**](#resolverConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L16)resolverConfig **resolverConfig: false | [RequestResolver](/api/3.0.0/i18n/interface/RequestResolver.md) ## Methods[**](#Methods) ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L21)match * **match(value: any, req: any, res: any): any --- # I18nMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**i18nConfig](#i18nConfig) * [**resolverConfig](#resolverConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new I18nMiddleware(): [I18nMiddleware](/api/3.0.0/i18n/class/I18nMiddleware.md) ## Properties[**](#Properties) ### [**](#i18nConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L53)i18nConfig **i18nConfig: [I18nOptions](/api/3.0.0/i18n/interface/I18nOptions.md) ### [**](#resolverConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L50)resolverConfig **resolverConfig: false | [RequestResolver](/api/3.0.0/i18n/interface/RequestResolver.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L55)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/middleware.ts#L199)staticgetName * **getName(): string --- # MidwayI18nService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) ### Methods * [**addLocale](#addLocale) * [**getAvailableLocale](#getAvailableLocale) * [**getDefaultLocale](#getDefaultLocale) * [**getLocaleMapping](#getLocaleMapping) * [**hasAvailableLocale](#hasAvailableLocale) * [**saveRequestLocale](#saveRequestLocale) * [**translate](#translate) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayI18nService(): [MidwayI18nService](/api/3.0.0/i18n/class/MidwayI18nService.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L211)ctx **ctx: Context ## Methods[**](#Methods) ### [**](#addLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L225)publicaddLocale * **addLocale(locale: string, localeTextMapping: Record\): void - add a language text mapping ### [**](#getAvailableLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L261)publicgetAvailableLocale * **getAvailableLocale(locale: string, group? : string): any - get locale string by find fallback and default, ignore match message ### [**](#getDefaultLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L241)publicgetDefaultLocale * **getDefaultLocale(): string - get current default language ### [**](#getLocaleMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L234)publicgetLocaleMapping * **getLocaleMapping(locale: any, group? : string): any - get mapping by lang ### [**](#hasAvailableLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L269)publichasAvailableLocale * **hasAvailableLocale(locale: string): boolean - get available local in locale text map, include fallbacks ### [**](#saveRequestLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L248)publicsaveRequestLocale * **saveRequestLocale(locale? : string): void - save current context lang to flag, middleware will be set it to cookie ### [**](#translate)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L213)publictranslate * **translate(message: string, options? : [TranslateOptions](/api/3.0.0/i18n/interface/TranslateOptions.md)): any --- # MidwayI18nServiceSingleton ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addLocale](#addLocale) * [**getAvailableLocale](#getAvailableLocale) * [**getDefaultLocale](#getDefaultLocale) * [**getLocaleMapping](#getLocaleMapping) * [**hasAvailableLocale](#hasAvailableLocale) * [**translate](#translate) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayI18nServiceSingleton(): [MidwayI18nServiceSingleton](/api/3.0.0/i18n/class/MidwayI18nServiceSingleton.md) ## Methods[**](#Methods) ### [**](#addLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L49)publicaddLocale * **addLocale(locale: string, localeTextMapping: Record\): void - add a language text mapping ### [**](#getAvailableLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L113)publicgetAvailableLocale * **getAvailableLocale(locale: string, group? : string): any - get locale string by find fallback and default, ignore match message ### [**](#getDefaultLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L187)publicgetDefaultLocale * **getDefaultLocale(): string - get current default language ### [**](#getLocaleMapping)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L176)publicgetLocaleMapping * **getLocaleMapping(locale: string, group? : string): any - get mapping by locale ### [**](#hasAvailableLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L151)publichasAvailableLocale * **hasAvailableLocale(locale: string): boolean - get available local in locale text map, include fallbacks ### [**](#translate)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/i18nService.ts#L73)publictranslate * **translate(message: string, options? : [TranslateOptions](/api/3.0.0/i18n/interface/TranslateOptions.md)): any - translate a message --- # formatLocale ### Callable * **formatLocale(locale: string): string --- # I18nOptions ## Index[**](#Index) ### Properties * [**defaultLocale](#defaultLocale) * [**fallbacks](#fallbacks) * [**localeTable](#localeTable) * [**localsField](#localsField) * [**resolver](#resolver) * [**writeCookie](#writeCookie) ## Properties[**](#Properties) ### [**](#defaultLocale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L17)defaultLocale **defaultLocale: string ### [**](#fallbacks)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L19)fallbacks **fallbacks: Record\ ### [**](#localeTable)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L18)localeTable **localeTable: Record\> ### [**](#localsField)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L22)localsField **localsField: string ### [**](#resolver)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L21)resolver **resolver: false | [RequestResolver](/api/3.0.0/i18n/interface/RequestResolver.md) ### [**](#writeCookie)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L20)writeCookie **writeCookie: boolean --- # RequestResolver ## Index[**](#Index) ### Properties * [**cookieField](#cookieField) * [**queryField](#queryField) ## Properties[**](#Properties) ### [**](#cookieField)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L9)cookieField **cookieField: { cookieDomain: string; cookieMaxAge: number; fieldName: string } ### [**](#queryField)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L8)queryField **queryField: string --- # TranslateOptions ## Index[**](#Index) ### Properties * [**args](#args) * [**group](#group) * [**locale](#locale) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L4)optionalargs **args? : any ### [**](#group)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L3)optionalgroup **group? : string ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/main/packages/i18n/src/interface.ts#L2)optionallocale **locale? : string --- # @midwayjs/info ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/info/class/Configuration.md) * [**InfoMiddleware](/api/3.0.0/info/class/InfoMiddleware.md) * [**InfoService](/api/3.0.0/info/class/InfoService.md) ### Enumerations * [**InfoType](/api/3.0.0/info/enum/InfoType.md) ### Interfaces * [**InfoConfigOptions](/api/3.0.0/info/interface/InfoConfigOptions.md) * [**TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### Type Aliases * [**InfoValueType](/api/3.0.0/info.md#InfoValueType) ### Variables * [**DefaultHiddenKey](/api/3.0.0/info.md#DefaultHiddenKey) ## Type Aliases[**](<#Type Aliases>) ### [**](#InfoValueType)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L1)InfoValueType **InfoValueType: html | json ## Variables[**](#Variables) ### [**](#DefaultHiddenKey)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L3)constDefaultHiddenKey **DefaultHiddenKey: string\[] = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [InfoConfiguration](/api/3.0.0/info/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/configuration.ts#L19)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # InfoMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new InfoMiddleware(): [InfoMiddleware](/api/3.0.0/info/class/InfoMiddleware.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/middleware/info.middleware.ts#L17)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ | (ctx: any, next: any) => Promise\ ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/middleware/info.middleware.ts#L39)staticgetName * **getName(): string --- # InfoService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**container](#container) * [**defaultHiddenKey](#defaultHiddenKey) * [**environment](#environment) * [**ignoreKey](#ignoreKey) * [**midwayInformationService](#midwayInformationService) * [**secretMatchList](#secretMatchList) * [**titleConfig](#titleConfig) ### Methods * [**dependenciesInfo](#dependenciesInfo) * [**envInfo](#envInfo) * [**info](#info) * [**init](#init) * [**midwayConfig](#midwayConfig) * [**midwayService](#midwayService) * [**networkInfo](#networkInfo) * [**projectInfo](#projectInfo) * [**resourceOccupationInfo](#resourceOccupationInfo) * [**softwareInfo](#softwareInfo) * [**systemInfo](#systemInfo) * [**timeInfo](#timeInfo) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new InfoService(): [InfoService](/api/3.0.0/info/class/InfoService.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L36)configService **configService: MidwayConfigService ### [**](#container)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L53)container **container: IMidwayContainer ### [**](#defaultHiddenKey)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L45)defaultHiddenKey **defaultHiddenKey: string\[] ### [**](#environment)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L39)environment **environment: MidwayEnvironmentService ### [**](#ignoreKey)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L48)ignoreKey **ignoreKey: string\[] ### [**](#midwayInformationService)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L33)midwayInformationService **midwayInformationService: MidwayInformationService ### [**](#secretMatchList)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L50)secretMatchList **secretMatchList: any\[] ### [**](#titleConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L42)titleConfig **titleConfig: string ## Methods[**](#Methods) ### [**](#dependenciesInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L237)dependenciesInfo * **dependenciesInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#envInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L179)envInfo * **envInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L64)info * **info(infoValueType? : [InfoValueType](/api/3.0.0/info.md#InfoValueType)): string | { info: {}; type: string }\[] ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L56)init * **init(): Promise\ ### [**](#midwayConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L271)midwayConfig * **midwayConfig(): { info: {}; type: [InfoType](/api/3.0.0/info/enum/InfoType.md) } ### [**](#midwayService)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L253)midwayService * **midwayService(): { info: {}; type: [InfoType](/api/3.0.0/info/enum/InfoType.md) } ### [**](#networkInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L206)networkInfo * **networkInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#projectInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L94)projectInfo * **projectInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#resourceOccupationInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L125)resourceOccupationInfo * **resourceOccupationInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#softwareInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L160)softwareInfo * **softwareInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#systemInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L107)systemInfo * **systemInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) ### [**](#timeInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/infoService.ts#L190)timeInfo * **timeInfo(): [TypeInfo](/api/3.0.0/info/interface/TypeInfo.md) --- # InfoType ## Index[**](#Index) ### Enumeration Members * [**DEPENDENCIES](#DEPENDENCIES) * [**ENVIRONMENT\_VARIABLE](#ENVIRONMENT_VARIABLE) * [**MEMORY\_CPU](#MEMORY_CPU) * [**MIDWAY\_CONFIG](#MIDWAY_CONFIG) * [**MIDWAY\_SERVICE](#MIDWAY_SERVICE) * [**NETWORK](#NETWORK) * [**PROJECT](#PROJECT) * [**RESOURCE](#RESOURCE) * [**SOFTWARE](#SOFTWARE) * [**SYSTEM](#SYSTEM) * [**TIME](#TIME) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DEPENDENCIES)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L29)DEPENDENCIES **DEPENDENCIES: Dependencies ### [**](#ENVIRONMENT_VARIABLE)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L25)ENVIRONMENT\_VARIABLE **ENVIRONMENT\_VARIABLE: Environment Variable ### [**](#MEMORY_CPU)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L23)MEMORY\_CPU **MEMORY\_CPU: Memory & CPU ### [**](#MIDWAY_CONFIG)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L31)MIDWAY\_CONFIG **MIDWAY\_CONFIG: Midway Config ### [**](#MIDWAY_SERVICE)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L30)MIDWAY\_SERVICE **MIDWAY\_SERVICE: Midway Service ### [**](#NETWORK)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L27)NETWORK **NETWORK: Network ### [**](#PROJECT)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L21)PROJECT **PROJECT: Project ### [**](#RESOURCE)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L28)RESOURCE **RESOURCE: Resource ### [**](#SOFTWARE)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L24)SOFTWARE **SOFTWARE: Software ### [**](#SYSTEM)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L22)SYSTEM **SYSTEM: System ### [**](#TIME)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L26)TIME **TIME: Time --- # InfoConfigOptions ## Index[**](#Index) ### Properties * [**hiddenKey](#hiddenKey) * [**ignoreKey](#ignoreKey) * [**infoPath](#infoPath) * [**title](#title) ## Properties[**](#Properties) ### [**](#hiddenKey)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L15)hiddenKey **hiddenKey: string\[] ### [**](#ignoreKey)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L16)ignoreKey **ignoreKey: string\[] ### [**](#infoPath)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L14)infoPath **infoPath: string ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L13)title **title: string --- # TypeInfo ## Index[**](#Index) ### Properties * [**info](#info) * [**type](#type) ## Properties[**](#Properties) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L7)info **info: {} ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/info/src/interface.ts#L6)type **type: string --- # @midwayjs/jwt ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/jwt/class/Configuration.md) * [**JwtService](/api/3.0.0/jwt/class/JwtService.md) ### Type Aliases * [**JwtConfig](/api/3.0.0/jwt.md#JwtConfig) * [**JwtUserConfig](/api/3.0.0/jwt.md#JwtUserConfig) ## Type Aliases[**](<#Type Aliases>) ### [**](#JwtConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/interface.ts#L7)JwtConfig **JwtConfig: { decode? : DecodeOptions; secret? : string; sign? : SignOptions; verify? : VerifyOptions } ### [**](#JwtUserConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/interface.ts#L3)JwtUserConfig **JwtUserConfig: (SignOptions & { secret? : string }) | [JwtConfig](/api/3.0.0/jwt.md#JwtConfig) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [JwtConfiguration](/api/3.0.0/jwt/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/configuration.ts#L15)publiconReady * **onReady(container: IMidwayContainer): Promise\ --- # JwtService @see ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**decode](#decode) * [**decodeSync](#decodeSync) * [**getDecodeOptions](#getDecodeOptions) * [**getSignOptions](#getSignOptions) * [**getVerifyOptions](#getVerifyOptions) * [**isSecret](#isSecret) * [**sign](#sign) * [**signSync](#signSync) * [**verify](#verify) * [**verifySync](#verifySync) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JwtService(): [JwtService](/api/3.0.0/jwt/class/JwtService.md) ## Methods[**](#Methods) ### [**](#decode)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L194)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L198)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L202)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L206)publicdecode * **decode(token: string, options: DecodeOptions & { complete: true }): Jwt * **decode(token: string, options: DecodeOptions & { json: true }): JwtPayload * **decode(token: string, options? : DecodeOptions): JwtPayload - Returns the decoded payload without verifying if the signature is valid. token - JWT string to decode \[options] - Options for decoding returns - The decoded Token ### [**](#decodeSync)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L215)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L219)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L223)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L227)publicdecodeSync * **decodeSync(token: string, options: DecodeOptions & { complete: true }): Jwt * **decodeSync(token: string, options: DecodeOptions & { json: true }): JwtPayload * **decodeSync(token: string, options? : DecodeOptions): JwtPayload - alias decode method ### [**](#getDecodeOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L249)getDecodeOptions * **getDecodeOptions(options? : DecodeOptions): DecodeOptions ### [**](#getSignOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L231)getSignOptions * **getSignOptions(options? : SignOptions): SignOptions | [JwtConfig](/api/3.0.0/jwt.md#JwtConfig) ### [**](#getVerifyOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L242)getVerifyOptions * **getVerifyOptions(options? : VerifyOptions): VerifyOptions ### [**](#isSecret)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L256)isSecret * **isSecret(secret: any): secret is Secret ### [**](#sign)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L69)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L73)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L78)publicsign * **sign(payload: JwtPayload, options? : SignOptions): Promise\ * **sign(payload: JwtPayload, secretOrPrivateKey: Secret, options? : SignOptions): Promise\ - Asynchronous sign the given payload into a JSON Web Token string payload - Payload to sign, could be an literal, buffer or string secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA. \[options] - Options for the signature returns - The JSON Web Token string ### [**](#signSync)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L39)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L40)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L45)publicsignSync * **signSync(payload: JwtPayload, options? : SignOptions): string * **signSync(payload: JwtPayload, secretOrPrivateKey: Secret, options? : SignOptions): string - Synchronously sign the given payload into a JSON Web Token string payload - Payload to sign, could be an literal, buffer or string secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA. \[options] - Options for the signature returns - The JSON Web Token string ### [**](#verify)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L145)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L149)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L153)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L158)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L163)publicverify * **verify(token: string, options? : VerifyOptions & { complete: true }): Promise\ * **verify(token: string, options? : VerifyOptions): Promise\ * **verify(token: string, secretOrPublicKey: Secret | GetPublicKeyOrSecret, options? : VerifyOptions & { complete: true }): Promise\ * **verify(token: string, secretOrPublicKey: Secret | GetPublicKeyOrSecret, options? : VerifyOptions): Promise\ - Asynchronous verify given token using a secret or a public key to get a decoded token token - JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. \[options] - Options for the verification returns - The decoded token. ### [**](#verifySync)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L110)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L114)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L115)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L120)[**](https://github.com/midwayjs/midway/blob/main/packages/jwt/src/jwt.ts#L125)publicverifySync * **verifySync(token: string, options: VerifyOptions & { complete: true }): string | Jwt * **verifySync(token: string, options: VerifyOptions): JwtPayload * **verifySync(token: string, secretOrPublicKey: Secret, options? : VerifyOptions & { complete: true }): string | Jwt * **verifySync(token: string, secretOrPublicKey: Secret, options? : VerifyOptions): JwtPayload - Synchronously verify given token using a secret or a public key to get a decoded token token - JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. \[options] - Options for the verification returns - The decoded token. --- # @midwayjs/kafka ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/kafka/class/Configuration.md) * [**Framework](/api/3.0.0/kafka/class/Framework.md) * [**KafkaAdminFactory](/api/3.0.0/kafka/class/KafkaAdminFactory.md) * [**KafkaProducerFactory](/api/3.0.0/kafka/class/KafkaProducerFactory.md) ### Functions * [**KafkaConsumer](/api/3.0.0/kafka/function/KafkaConsumer.md) ### Interfaces * [**Context](/api/3.0.0/kafka/interface/Context.md) * [**IKafkaApplication](/api/3.0.0/kafka/interface/IKafkaApplication.md) * [**IKafkaConsumer](/api/3.0.0/kafka/interface/IKafkaConsumer.md) * [**IKafkaConsumerInitOptions](/api/3.0.0/kafka/interface/IKafkaConsumerInitOptions.md) * [**IMidwayConsumerConfig](/api/3.0.0/kafka/interface/IMidwayConsumerConfig.md) * [**IMidwayKafkaAdminInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaAdminInitOptions.md) * [**IMidwayKafkaConfigurationOptions](/api/3.0.0/kafka/interface/IMidwayKafkaConfigurationOptions.md) * [**IMidwayKafkaProducerInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaProducerInitOptions.md) ### Type Aliases * [**Application](/api/3.0.0/kafka.md#Application) * [**DefaultConfig](/api/3.0.0/kafka.md#DefaultConfig) * [**IMidwayKafkaApplication](/api/3.0.0/kafka.md#IMidwayKafkaApplication) * [**IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext) * [**NextFunction](/api/3.0.0/kafka.md#NextFunction) ### Variables * [**KAFKA\_DECORATOR\_KEY](/api/3.0.0/kafka.md#KAFKA_DECORATOR_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L51)Application **Application: [IMidwayKafkaApplication](/api/3.0.0/kafka.md#IMidwayKafkaApplication) ### [**](#DefaultConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L54)DefaultConfig **DefaultConfig: string | Kafka ### [**](#IMidwayKafkaApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L27)IMidwayKafkaApplication **IMidwayKafkaApplication: IMidwayApplication<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext)> & [IKafkaApplication](/api/3.0.0/kafka/interface/IKafkaApplication.md) ### [**](#IMidwayKafkaContext)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L30)IMidwayKafkaContext **IMidwayKafkaContext: IMidwayContext<{ consumer: Consumer; message? : any; partition? : any; payload: EachMessagePayload | EachBatchPayload; topic? : any; commitOffsets? : any }> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L53)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#KAFKA_DECORATOR_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/decorator.ts#L8)constKAFKA\_DECORATOR\_KEY **KAFKA\_DECORATOR\_KEY: rpc:kafka = 'rpc:kafka' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [KafkaConfiguration](/api/3.0.0/kafka/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/configuration.ts#L24)onReady * **onReady(container: IMidwayContainer): Promise\ --- # Framework ### Hierarchy * BaseFramework\ * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**kafKaLogger](#kafKaLogger) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConsumer](#getConsumer) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getKafka](#getKafka) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayKafkaFramework](/api/3.0.0/kafka/class/Framework.md) - Inherited from BaseFramework< any, IMidwayKafkaContext, any >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: any Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#kafKaLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L61)kafKaLogger **kafKaLogger: ILogger ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L63)applicationInitialize * **applicationInitialize(): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L56)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): any - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConsumer)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L297)publicgetConsumer * **getConsumer(subscriberNameOrInstanceName: string): any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L309)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L319)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getKafka)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L305)publicgetKafka * **getKafka(instanceName: string): Kafka ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayKafkaFramework](/api/3.0.0/kafka/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/framework.ts#L85)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # KafkaAdminFactory ### Hierarchy * ServiceFactory\ * *KafkaAdminFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**adminConfig](#adminConfig) * [**logger](#logger) ### Methods * [**createInstance](#createInstance) * [**destroy](#destroy) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new KafkaAdminFactory(): [KafkaAdminFactory](/api/3.0.0/kafka/class/KafkaAdminFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#adminConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L79)adminConfig **adminConfig: ServiceFactoryConfigOption<[IMidwayKafkaProducerInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaProducerInitOptions.md)> ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L76)logger **logger: ILogger ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L118)destroy * **destroy(): Promise\ ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L112)destroyClient * **destroyClient(admin: Admin, name: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Admin ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L81)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L86)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # KafkaProducerFactory ### Hierarchy * ServiceFactory\ * *KafkaProducerFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**pubConfig](#pubConfig) ### Methods * [**createInstance](#createInstance) * [**destroy](#destroy) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new KafkaProducerFactory(): [KafkaProducerFactory](/api/3.0.0/kafka/class/KafkaProducerFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L22)logger **logger: ILogger ### [**](#pubConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L25)pubConfig **pubConfig: ServiceFactoryConfigOption<[IMidwayKafkaProducerInitOptions](/api/3.0.0/kafka/interface/IMidwayKafkaProducerInitOptions.md)> ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L68)destroy * **destroy(): Promise\ ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L62)destroyClient * **destroyClient(producer: Producer, name: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Producer ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L27)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/service.ts#L32)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # KafkaConsumer ### Callable * **KafkaConsumer(consumerName: string): ClassDecorator --- # Context ### Hierarchy * [IMidwayKafkaContext](/api/3.0.0/kafka.md#IMidwayKafkaContext) * *Context* ## Index[**](#Index) ### Properties * [**consumer](#consumer) * [**logger](#logger) * [**message](#message) * [**partition](#partition) * [**payload](#payload) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**topic](#topic) ### Methods * [**commitOffsets](#commitOffsets) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#consumer)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L48)consumer **consumer: Consumer Inherited from IMidwayKafkaContext.consumer ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayKafkaContext.logger ### [**](#message)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L42)optionalmessage **message? : any Inherited from IMidwayKafkaContext.message * **@deprecated** please use `ctx.payload` instead ### [**](#partition)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L38)optionalpartition **partition? : any Inherited from IMidwayKafkaContext.partition * **@deprecated** please use `ctx.payload` instead ### [**](#payload)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L47)payload **payload: EachMessagePayload | EachBatchPayload Inherited from IMidwayKafkaContext.payload ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayKafkaContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayKafkaContext.startTime ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L34)optionaltopic **topic? : any Inherited from IMidwayKafkaContext.topic * **@deprecated** please use `ctx.payload` instead ## Methods[**](#Methods) ### [**](#commitOffsets)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L46)optionalcommitOffsets * **commitOffsets(data: any): void - Inherited from IMidwayKafkaContext.commitOffsets * **@deprecated** please use `ctx.consumer.commitOffsets` instead ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayKafkaContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayKafkaContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayKafkaContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayKafkaContext.setAttr Set value to app attribute map --- # IKafkaApplication --- # IKafkaConsumer ## Index[**](#Index) ### Properties * [**eachBatch](#eachBatch) * [**eachMessage](#eachMessage) ## Properties[**](#Properties) ### [**](#eachBatch)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L113)optionaleachBatch **eachBatch? : EachBatchHandler ### [**](#eachMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L114)optionaleachMessage **eachMessage? : EachMessageHandler --- # IKafkaConsumerInitOptions The options for the kafka consumer initialization in midway ## Index[**](#Index) ### Properties * [**connectionOptions](#connectionOptions) * [**consumerOptions](#consumerOptions) * [**consumerRunConfig](#consumerRunConfig) * [**kafkaInstanceRef](#kafkaInstanceRef) * [**subscribeOptions](#subscribeOptions) ## Properties[**](#Properties) ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L73)connectionOptions **connectionOptions: KafkaConfig The connection options for the kafka instance ### [**](#consumerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L77)consumerOptions **consumerOptions: ConsumerConfig The consumer options for the kafka consumer ### [**](#consumerRunConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L79)consumerRunConfig **consumerRunConfig: ConsumerRunConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L80)optionalkafkaInstanceRef **kafkaInstanceRef? : string ### [**](#subscribeOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L78)subscribeOptions **subscribeOptions: ConsumerSubscribeTopics | ConsumerSubscribeTopic --- # IMidwayConsumerConfig 客户端的相关配置,在midwayjs的自定义配置项 * **@deprecated** ## Index[**](#Index) ### Properties * [**runConfig](#runConfig) * [**subscription](#subscription) * [**topic](#topic) ## Properties[**](#Properties) ### [**](#runConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L63)runConfig **runConfig: any ### [**](#subscription)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L62)subscription **subscription: any ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L61)topic **topic: string --- # IMidwayKafkaAdminInitOptions The options for the kafka admin initialization in midway ## Index[**](#Index) ### Properties * [**adminOptions](#adminOptions) * [**connectionOptions](#connectionOptions) * [**kafkaInstanceRef](#kafkaInstanceRef) ## Properties[**](#Properties) ### [**](#adminOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L101)adminOptions **adminOptions: AdminConfig The options for the kafka admin initialization ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L97)connectionOptions **connectionOptions: KafkaConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L96)optionalkafkaInstanceRef **kafkaInstanceRef? : string --- # IMidwayKafkaConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayKafkaConfigurationOptions* ## Index[**](#Index) ### Properties * [**admin](#admin) * [**appLogger](#appLogger) * [**consumer](#consumer) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) * [**producer](#producer) ## Properties[**](#Properties) ### [**](#admin)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L109)admin **admin: ServiceFactoryConfigOption\> ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#consumer)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L105)consumer **consumer: {} ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#producer)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L108)producer **producer: ServiceFactoryConfigOption\> --- # IMidwayKafkaProducerInitOptions The options for the kafka producer initialization in midway ## Index[**](#Index) ### Properties * [**connectionOptions](#connectionOptions) * [**kafkaInstanceRef](#kafkaInstanceRef) * [**producerOptions](#producerOptions) ## Properties[**](#Properties) ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L87)connectionOptions **connectionOptions: KafkaConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L89)optionalkafkaInstanceRef **kafkaInstanceRef? : string ### [**](#producerOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/kafka/src/interface.ts#L88)producerOptions **producerOptions: ProducerConfig --- # @midwayjs/mikro ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/mikro/class/Configuration.md) * [**MikroDataSourceManager](/api/3.0.0/mikro/class/MikroDataSourceManager.md) ### Functions * [**InjectDataSource](/api/3.0.0/mikro/function/InjectDataSource.md) * [**InjectEntityManager](/api/3.0.0/mikro/function/InjectEntityManager.md) * [**InjectRepository](/api/3.0.0/mikro/function/InjectRepository.md) ### Type Aliases * [**MikroConfigOptions](/api/3.0.0/mikro.md#MikroConfigOptions) ### Variables * [**DATA\_SOURCE\_KEY](/api/3.0.0/mikro.md#DATA_SOURCE_KEY) * [**ENTITY\_MANAGER\_KEY](/api/3.0.0/mikro.md#ENTITY_MANAGER_KEY) * [**ENTITY\_MODEL\_KEY](/api/3.0.0/mikro.md#ENTITY_MODEL_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#MikroConfigOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/interface.ts#L4)MikroConfigOptions **MikroConfigOptions\: DataSourceManagerConfigOption<(Options\ | Configuration\) & { logger? : string | (message: string) => void }> #### Type parameters * **D**: IDatabaseDriver = IDatabaseDriver ## Variables[**](#Variables) ### [**](#DATA_SOURCE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/decorator.ts#L6)constDATA\_SOURCE\_KEY **DATA\_SOURCE\_KEY: mikro:data\_source\_key = 'mikro:data\_source\_key' ### [**](#ENTITY_MANAGER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/decorator.ts#L5)constENTITY\_MANAGER\_KEY **ENTITY\_MANAGER\_KEY: mikro:entity\_manager\_key = 'mikro:entity\_manager\_key' ### [**](#ENTITY_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/decorator.ts#L4)constENTITY\_MODEL\_KEY **ENTITY\_MODEL\_KEY: mikro:entity\_model\_key = 'mikro:entity\_model\_key' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationManager](#applicationManager) * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MikroConfiguration](/api/3.0.0/mikro/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L32)app **app: IMidwayBaseApplication\ ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L38)applicationManager **applicationManager: MidwayApplicationManager ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L40)dataSourceManager **dataSourceManager: [MikroDataSourceManager](/api/3.0.0/mikro/class/MikroDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L35)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L43)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L99)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/configuration.ts#L122)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # MikroDataSourceManager ### Hierarchy * DataSourceManager\>> * *MikroDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**baseDir](#baseDir) * [**loggerService](#loggerService) * [**mikroConfig](#mikroConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MikroDataSourceManager(): [MikroDataSourceManager](/api/3.0.0/mikro/class/MikroDataSourceManager.md) - Inherited from DataSourceManager< MikroORM\> >.constructor ## Properties[**](#Properties) ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/dataSourceManager.ts#L22)baseDir **baseDir: string ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/dataSourceManager.ts#L25)loggerService **loggerService: MidwayLoggerService ### [**](#mikroConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/dataSourceManager.ts#L19)mikroConfig **mikroConfig: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L34)createInstance * **createInstance(config: any, clientName: any, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\, EntityManager\>>> - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)getAllDataSources * **getAllDataSources(): Map\, EntityManager\>>> - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L21)getDataSource * **getDataSource(dataSourceName: string): MikroORM\, EntityManager\>> - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L42)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L27)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L52)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/dataSourceManager.ts#L32)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L26)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/mikro/src/dataSourceManager.ts#L28)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L33)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L53)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L55)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L54)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L50)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectEntityManager ### Callable * **InjectEntityManager(connectionName? : string): PropertyDecorator --- # InjectRepository ### Callable * **InjectRepository(modelKey: EntityName\, connectionName? : string): PropertyDecorator --- # @midwayjs/mock ## Index[**](#Index) ### Classes * [**SocketIOWrapperClient](/api/3.0.0/mock/class/SocketIOWrapperClient.md) ### Functions * [**close](/api/3.0.0/mock/function/close.md) * [**create](/api/3.0.0/mock/function/create.md) * [**createApp](/api/3.0.0/mock/function/createApp.md) * [**createBootstrap](/api/3.0.0/mock/function/createBootstrap.md) * [**createFunctionApp](/api/3.0.0/mock/function/createFunctionApp.md) * [**createHttpRequest](/api/3.0.0/mock/function/createHttpRequest.md) * [**createKafkaProducer](/api/3.0.0/mock/function/createKafkaProducer.md) * [**createLightApp](/api/3.0.0/mock/function/createLightApp.md) * [**createRabbitMQProducer](/api/3.0.0/mock/function/createRabbitMQProducer.md) * [**createSocketIOClient](/api/3.0.0/mock/function/createSocketIOClient.md) * [**createWebSocketClient](/api/3.0.0/mock/function/createWebSocketClient.md) * [**mockClassProperty](/api/3.0.0/mock/function/mockClassProperty.md) * [**mockContext](/api/3.0.0/mock/function/mockContext.md) * [**mockHeader](/api/3.0.0/mock/function/mockHeader.md) * [**mockProperty](/api/3.0.0/mock/function/mockProperty.md) * [**mockSession](/api/3.0.0/mock/function/mockSession.md) * [**processArgsParser](/api/3.0.0/mock/function/processArgsParser.md) * [**restoreAllMocks](/api/3.0.0/mock/function/restoreAllMocks.md) * [**restoreMocks](/api/3.0.0/mock/function/restoreMocks.md) * [**transformFrameworkToConfiguration](/api/3.0.0/mock/function/transformFrameworkToConfiguration.md) ### Interfaces * [**MidwaySocketIOClientOptions](/api/3.0.0/mock/interface/MidwaySocketIOClientOptions.md) --- # SocketIOWrapperClient ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**connect](#connect) * [**emit](#emit) * [**getSocket](#getSocket) * [**on](#on) * [**once](#once) * [**removeListener](#removeListener) * [**send](#send) * [**sendWithAck](#sendWithAck) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L14)constructor * **new SocketIOWrapperClient(socket: any): [SocketIOWrapperClient](/api/3.0.0/mock/class/SocketIOWrapperClient.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L55)close * **close(): void ### [**](#connect)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L17)connect * **connect(): Promise\ ### [**](#emit)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L45)emit * **emit(eventName: string, ...args: any\[]): Socket\ ### [**](#getSocket)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L25)getSocket * **getSocket(): Socket\ ### [**](#on)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L33)on * **on(eventName: string, handler: any): void ### [**](#once)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L37)once * **once(eventName: string, handler: any): Socket\ ### [**](#removeListener)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L41)removeListener * **removeListener(event: string, fn? : any): Socket\ ### [**](#send)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L29)send * **send(eventName: string, ...args: any\[]): void ### [**](#sendWithAck)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L49)sendWithAck * **sendWithAck(eventName: string, ...args: any\[]): Promise\ --- # close ### Callable * **close(app: IMidwayBaseApplication\ | { close: (...args: any\[]) => void }, options? : { cleanLogsDir? : boolean; cleanTempDir? : boolean; sleep? : number }): Promise\ --- # create ### Callable * **create\(appDir: string | MockAppConfigurationOptions, options? : MockAppConfigurationOptions, customFramework? : new (...args: any\[]) => T | ComponentModule): Promise\ *** * #### Type parameters * **T**: IMidwayFramework\ --- # createApp ### Callable * **createApp\(baseDir? : string, options? : MockAppConfigurationOptions, customFramework? : ComponentModule | new (...args: any\[]) => T): Promise\> *** * #### Type parameters * **T**: IMidwayFramework\ --- # createBootstrap ### Callable * **createBootstrap(entryFile: string, options? : MockBootstrapOptions): Promise\ --- # createFunctionApp ### Callable * **createFunctionApp\(baseDir? : string | MockAppConfigurationOptions, options? : MockAppConfigurationOptions, customFrameworkModule? : ComponentModule | new (...args: any\[]) => T): Promise\ *** * #### Type parameters * **T**: IMidwayFramework\ * **Y** = ReturnType\ --- # createHttpRequest ### Callable * **createHttpRequest\(app: T): request.SuperTest\ *** * #### Type parameters * **T**: IMidwayBaseApplication\ --- # createKafkaProducer ### Callable * **createKafkaProducer(options: { kafkaConfig: KafkaConfig; mock? : boolean; producerConfig? : ProducerConfig }): Promise\ --- # createLightApp ### Callable * **createLightApp(baseDirOrOptions: string | MockAppConfigurationOptions, options? : MockAppConfigurationOptions): Promise\ *** * Create a real project but not ready or a virtual project --- # createRabbitMQProducer ### Callable * **createRabbitMQProducer(options: { url? : string }): Promise\ * **createRabbitMQProducer(queueName: string, options: { isConfirmChannel? : boolean; mock? : boolean; url? : string }): Promise\ --- # createSocketIOClient ### Callable * **createSocketIOClient(opts: [MidwaySocketIOClientOptions](/api/3.0.0/mock/interface/MidwaySocketIOClientOptions.md)): Promise<[SocketIOWrapperClient](/api/3.0.0/mock/class/SocketIOWrapperClient.md) & NodeJS.EventEmitter> --- # createWebSocketClient ### Callable * **createWebSocketClient(address: string | URL, options? : ClientRequestArgs | ClientOptions): Promise\ --- # mockClassProperty ### Callable * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void --- # mockContext ### Callable * **mockContext(app: IMidwayBaseApplication\, key: string | (ctx: Context) => void, value? : any, group? : string): void --- # mockHeader ### Callable * **mockHeader(app: IMidwayBaseApplication\, headerKey: string, headerValue: string, group? : string): void --- # mockProperty ### Callable * **mockProperty(obj: any, key: string, value: any, group? : string): void --- # mockSession ### Callable * **mockSession(app: IMidwayBaseApplication\, key: string, value: any, group? : string): void --- # processArgsParser ### Callable * **processArgsParser(argv: string\[]): {} *** * 解析命令行参数的函数。 它接受一个字符串数组作为输入,然后解析这个数组, 将形如 `--key value` 或 `--key=value` 的参数转换为对象的键值对, 形如 `--key` 的参数转换为 `{ key: true }`。 --- # restoreAllMocks ### Callable * **restoreAllMocks(): void --- # restoreMocks ### Callable * **restoreMocks(group? : string): void --- # transformFrameworkToConfiguration ### Callable * **transformFrameworkToConfiguration\(Framework: any, loadMode: commonjs | esm): Promise<{ Configuration: any }> *** * transform a framework component or framework module to configuration class *** #### Type parameters * **T**: IMidwayFramework\ --- # MidwaySocketIOClientOptions ### Hierarchy * Partial\ * *MidwaySocketIOClientOptions* ## Index[**](#Index) ### Properties * [**host](#host) * [**namespace](#namespace) * [**port](#port) * [**protocol](#protocol) * [**url](#url) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L7)optionalhost **host? : string Overrides Partial.host ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L8)optionalnamespace **namespace? : string ### [**](#port)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L9)optionalport **port? : any Overrides Partial.port ### [**](#protocol)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L6)optionalprotocol **protocol? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/mock/src/client/socketio.ts#L5)optionalurl **url? : string --- # @midwayjs/mongoose ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/mongoose/class/Configuration.md) * [**MongooseConnectionService](/api/3.0.0/mongoose/class/MongooseConnectionService.md) * [**MongooseConnectionServiceFactory](/api/3.0.0/mongoose/class/MongooseConnectionServiceFactory.md) * [**MongooseDataSourceManager](/api/3.0.0/mongoose/class/MongooseDataSourceManager.md) ### Type Aliases * [**ConnectionOptions](/api/3.0.0/mongoose.md#ConnectionOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#ConnectionOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/interface.ts#L21)ConnectionOptions **ConnectionOptions: ExtractConnectionOptions\ --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**mongooseDataSourceManager](#mongooseDataSourceManager) ### Methods * [**onHealthCheck](#onHealthCheck) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MongooseConfiguration](/api/3.0.0/mongoose/class/Configuration.md) ## Properties[**](#Properties) ### [**](#mongooseDataSourceManager)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/configuration.ts#L36)mongooseDataSourceManager **mongooseDataSourceManager: [MongooseDataSourceManager](/api/3.0.0/mongoose/class/MongooseDataSourceManager.md) ## Methods[**](#Methods) ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/configuration.ts#L47)optionalonHealthCheck * **onHealthCheck(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onHealthCheck ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/configuration.ts#L37)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/configuration.ts#L43)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # MongooseConnectionService * **@deprecated** ### Hierarchy * Connection * *MongooseConnectionService* ### Implements * Connection ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseConnectionService(): [MongooseConnectionService](/api/3.0.0/mongoose/class/MongooseConnectionService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L133)init * **init(): Promise\ --- # MongooseConnectionServiceFactory * **@deprecated** ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**mongooseDataSourceManager](#mongooseDataSourceManager) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getName](#getName) * [**has](#has) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseConnectionServiceFactory(): [MongooseConnectionServiceFactory](/api/3.0.0/mongoose/class/MongooseConnectionServiceFactory.md) ## Properties[**](#Properties) ### [**](#mongooseDataSourceManager)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L99)mongooseDataSourceManager **mongooseDataSourceManager: [MongooseDataSourceManager](/api/3.0.0/mongoose/class/MongooseDataSourceManager.md) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L101)createInstance * **createInstance(config: any, clientName: any): Promise\ ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L108)get * **get(id: string): Connection ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L112)getName * **getName(): string ### [**](#has)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L116)has * **has(id: string): boolean --- # MongooseDataSourceManager ### Hierarchy * DataSourceManager\ * *MongooseDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**baseDir](#baseDir) * [**config](#config) * [**logger](#logger) ### Methods * [**createInstance](#createInstance) * [**destroyDataSource](#destroyDataSource) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseDataSourceManager(): [MongooseDataSourceManager](/api/3.0.0/mongoose/class/MongooseDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L26)baseDir **baseDir: string ### [**](#config)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L20)config **config: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L23)logger **logger: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L34)createInstance * **createInstance(config: any, clientName: any, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#destroyDataSource)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L81)destroyDataSource * **destroyDataSource(dataSource: Connection): Promise\ - Overrides DataSourceManager.destroyDataSource ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L21)getDataSource * **getDataSource(dataSourceName: string): Connection - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L42)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L27)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L52)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L77)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L26)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/mongoose/src/manager.ts#L29)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L33)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L53)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L55)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L54)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L50)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources --- # @midwayjs/otel ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/otel/class/Configuration.md) * [**TraceService](/api/3.0.0/otel/class/TraceService.md) ### Functions * [**Trace](/api/3.0.0/otel/function/Trace.md) ### Variables * [**TRACE\_KEY](/api/3.0.0/otel.md#TRACE_KEY) ## Variables[**](#Variables) ### [**](#TRACE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/decorator/tracer.decorator.ts#L3)constTRACE\_KEY **TRACE\_KEY: decorator:open\_telemetry\_key = 'decorator:open\_telemetry\_key' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**decoratorService](#decoratorService) * [**traceService](#traceService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [OtelConfiguration](/api/3.0.0/otel/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/configuration.ts#L23)applicationManager **applicationManager: MidwayApplicationManager ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/configuration.ts#L17)decoratorService **decoratorService: MidwayDecoratorService ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/configuration.ts#L20)traceService **traceService: [TraceService](/api/3.0.0/otel/class/TraceService.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/configuration.ts#L25)onReady * **onReady(): Promise\ --- # TraceService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createSpan](#createSpan) * [**getTraceId](#getTraceId) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TraceService(): [TraceService](/api/3.0.0/otel/class/TraceService.md) ## Methods[**](#Methods) ### [**](#createSpan)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/service.ts#L32)createSpan * **createSpan(name: string, callback: (span: Span) => unknown): unknown ### [**](#getTraceId)[**](https://github.com/midwayjs/midway/blob/main/packages/otel/src/service.ts#L28)getTraceId * **getTraceId(): string --- # Trace ### Callable * **Trace(spanName: string): MethodDecorator --- # @midwayjs/passport ## Index[**](#Index) ### Classes * [**AbstractPassportMiddleware](/api/3.0.0/passport/class/AbstractPassportMiddleware.md) * [**Configuration](/api/3.0.0/passport/class/Configuration.md) * [**PassportAuthenticator](/api/3.0.0/passport/class/PassportAuthenticator.md) ### Functions * [**CustomStrategy](/api/3.0.0/passport/function/CustomStrategy.md) * [**PassportMiddleware](/api/3.0.0/passport/function/PassportMiddleware.md) * [**PassportStrategy](/api/3.0.0/passport/function/PassportStrategy.md) ### Interfaces * [**AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md) * [**IPassportMiddleware](/api/3.0.0/passport/interface/IPassportMiddleware.md) * [**IPassportStrategy](/api/3.0.0/passport/interface/IPassportStrategy.md) * [**StrategyCreatedStatic](/api/3.0.0/passport/interface/StrategyCreatedStatic.md) ### Type Aliases * [**StrategyClass](/api/3.0.0/passport.md#StrategyClass) ## Type Aliases[**](<#Type Aliases>) ### [**](#StrategyClass)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/passport.service.ts#L73)StrategyClass **StrategyClass: new (...args: any) => AbstractStrategyWrapper --- # abstractAbstractPassportMiddleware ### Implements * Pick<[IPassportMiddleware](/api/3.0.0/passport/interface/IPassportMiddleware.md), authenticate> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**authenticate](#authenticate) * [**getAuthenticateOptions](#getAuthenticateOptions) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AbstractPassportMiddleware(): [AbstractPassportMiddleware](/api/3.0.0/passport/class/AbstractPassportMiddleware.md) ## Methods[**](#Methods) ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L37)optionalauthenticate * **authenticate(options: [AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md), callback? : Function): any - Implementation of Pick.authenticate ### [**](#getAuthenticateOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L36)abstractgetAuthenticateOptions * **getAuthenticateOptions(): [AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md) | Promise<[AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md)> ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L38)resolve * **resolve(): any --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PassportConfiguration](/api/3.0.0/passport/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/configuration.ts#L24)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/configuration.ts#L26)onReady * **onReady(container: IMidwayContainer): Promise\ --- # PassportAuthenticator ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**\_deserializers](#_deserializers) * [**\_infoTransformers](#_infoTransformers) * [**\_key](#_key) * [**\_serializers](#_serializers) * [**applicationContext](#applicationContext) * [**passportConfig](#passportConfig) ### Methods * [**addDeserializer](#addDeserializer) * [**addInfoTransformer](#addInfoTransformer) * [**addSerializer](#addSerializer) * [**authenticate](#authenticate) * [**deserializeUser](#deserializeUser) * [**getSessionUserProperty](#getSessionUserProperty) * [**getUserProperty](#getUserProperty) * [**isEnableSession](#isEnableSession) * [**isExpressMode](#isExpressMode) * [**logInToSession](#logInToSession) * [**logOutFromSession](#logOutFromSession) * [**serializeUser](#serializeUser) * [**transformAuthInfo](#transformAuthInfo) * [**unuse](#unuse) * [**use](#use) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new PassportAuthenticator(): [PassportAuthenticator](/api/3.0.0/passport/class/PassportAuthenticator.md) ## Properties[**](#Properties) ### [**](#_deserializers)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L24)\_deserializers **\_deserializers: any\[] = \[] ### [**](#_infoTransformers)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L25)\_infoTransformers **\_infoTransformers: any\[] = \[] ### [**](#_key)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L22)\_key **\_key: string = 'passport' ### [**](#_serializers)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L23)\_serializers **\_serializers: any\[] = \[] ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L28)applicationContext **applicationContext: IMidwayContainer ### [**](#passportConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L31)passportConfig **passportConfig: any ## Methods[**](#Methods) ### [**](#addDeserializer)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L479)publicaddDeserializer * **addDeserializer(fn: any): void ### [**](#addInfoTransformer)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L483)publicaddInfoTransformer * **addInfoTransformer(fn: any): void ### [**](#addSerializer)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L475)publicaddSerializer * **addSerializer(fn: any): void ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L110)publicauthenticate * **authenticate(strategies: Strategy\[], options? : [AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md)): (req: any) => Promise<{ failResult? : { failures: { challenge: string; status: number }\[] }; redirectResult? : { status: number; url: string }; successResult? : { info: any; user: any } }> - Authenticates requests. Applies the `name`ed strategy (or strategies) to the incoming request, in order to authenticate the request. If authentication is successful, the user will be logged in and populated at `req.user` and a session will be established by default. If authentication fails, an unauthorized response will be sent. Options: * `session` Save login state in session, defaults to *true* * `successRedirect` After successful login, redirect to given URL * `successMessage` True to store success message in req.session.messages, or a string to use as override message for success. * `successFlash` True to flash success messages or a string to use as a flash message for success (overrides any from the strategy itself). * `failureRedirect` After failed login, redirect to given URL * `failureMessage` True to store failure message in req.session.messages, or a string to use as override message for failure. * `failureFlash` True to flash failure messages or a string to use as a flash message for failures (overrides any from the strategy itself). * `assignProperty` Assign the object provided by the verify callback to given property ### [**](#deserializeUser)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L293)publicdeserializeUser * **deserializeUser(obj: any, req: any, done: any): void - Registers a function used to deserialize user objects out of the session. Examples: ``` passport.deserializeUser(function(id, done) { User.findById(id, function (err, user) { done(err, user); }); }); ``` * **@api** public ### [**](#getSessionUserProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L63)publicgetSessionUserProperty * **getSessionUserProperty(): string ### [**](#getUserProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L59)publicgetUserProperty * **getUserProperty(): string ### [**](#isEnableSession)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L55)publicisEnableSession * **isEnableSession(): boolean ### [**](#isExpressMode)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L51)publicisExpressMode * **isExpressMode(): boolean ### [**](#logInToSession)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L410)publiclogInToSession * **logInToSession(req: IncomingMessage & { session: any }, user: any): Promise\ ### [**](#logOutFromSession)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L436)publiclogOutFromSession * **logOutFromSession(req: any, options? : { keepSessionInfo? : boolean }): Promise\ ### [**](#serializeUser)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L246)publicserializeUser * **serializeUser(user: any, req: any, done: any): void ### [**](#transformAuthInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L370)publictransformAuthInfo * **transformAuthInfo(info: any, req: any, done: any): void - Registers a function used to transform auth info. In some circumstances authorization details are contained in authentication credentials or loaded as part of verification. For example, when using bearer tokens for API authentication, the tokens may encode (either directly or indirectly in a database), details such as scope of access or the client to which the token was issued. Such authorization details should be enforced separately from authentication. Because Passport deals only with the latter, this is the responsiblity of middleware or routes further along the chain. However, it is not optimal to decode the same data or execute the same database query later. To avoid this, Passport accepts optional `info` along with the authenticated `user` in a strategy's `success()` action. This info is set at `req.authInfo`, where said later middlware or routes can access it. Optionally, applications can register transforms to proccess this info, which take effect prior to `req.authInfo` being set. This is useful, for example, when the info contains a client ID. The transform can load the client from the database and include the instance in the transformed info, allowing the full set of client properties to be convieniently accessed. If no transforms are registered, `info` supplied by the strategy will be left unmodified. Examples: ``` passport.transformAuthInfo(function(info, done) { Client.findById(info.clientID, function (err, client) { info.client = client; done(err, info); }); }); ``` * **@api** public ### [**](#unuse)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L80)publicunuse * **unuse(name: string): [PassportAuthenticator](/api/3.0.0/passport/class/PassportAuthenticator.md) ### [**](#use)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/passport/authenticator.ts#L67)publicuse * **use(name: string | Strategy, strategy? : Strategy): [PassportAuthenticator](/api/3.0.0/passport/class/PassportAuthenticator.md) --- # CustomStrategy ### Callable * **CustomStrategy(): ClassDecorator --- # PassportMiddleware ### Callable * **PassportMiddleware(strategy: [StrategyClass](/api/3.0.0/passport.md#StrategyClass) | [StrategyClass](/api/3.0.0/passport.md#StrategyClass)\[]): new (...args: any) => [AbstractPassportMiddleware](/api/3.0.0/passport/class/AbstractPassportMiddleware.md) --- # PassportStrategy ### Callable * **PassportStrategy(Strategy: new (...args: any\[]) => Strategy, name? : string): new (...args: any) => AbstractStrategyWrapper --- # AuthenticateOptions ## Index[**](#Index) ### Properties * [**assignProperty](#assignProperty) * [**authInfo](#authInfo) * [**failureMessage](#failureMessage) * [**failureRedirect](#failureRedirect) * [**passReqToCallback](#passReqToCallback) * [**pauseStream](#pauseStream) * [**prompt](#prompt) * [**scope](#scope) * [**session](#session) * [**state](#state) * [**successMessage](#successMessage) * [**successRedirect](#successRedirect) * [**successReturnToOrRedirect](#successReturnToOrRedirect) * [**userProperty](#userProperty) ## Properties[**](#Properties) ### [**](#assignProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L5)optionalassignProperty **assignProperty? : string ### [**](#authInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L4)optionalauthInfo **authInfo? : boolean ### [**](#failureMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L7)optionalfailureMessage **failureMessage? : string | boolean ### [**](#failureRedirect)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L8)optionalfailureRedirect **failureRedirect? : string ### [**](#passReqToCallback)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L19)optionalpassReqToCallback **passReqToCallback? : boolean ### [**](#pauseStream)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L17)optionalpauseStream **pauseStream? : boolean ### [**](#prompt)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L20)optionalprompt **prompt? : string ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L11)optionalscope **scope? : string | string\[] ### [**](#session)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L10)optionalsession **session? : boolean ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L16)optionalstate **state? : string ### [**](#successMessage)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L13)optionalsuccessMessage **successMessage? : string | boolean ### [**](#successRedirect)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L14)optionalsuccessRedirect **successRedirect? : string ### [**](#successReturnToOrRedirect)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L15)optionalsuccessReturnToOrRedirect **successReturnToOrRedirect? : string ### [**](#userProperty)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L18)optionaluserProperty **userProperty? : string --- # IPassportMiddleware ### Hierarchy * IMiddleware\ * *IPassportMiddleware* ## Index[**](#Index) ### Properties * [**ignore](#ignore) * [**match](#match) * [**resolve](#resolve) ### Methods * [**authenticate](#authenticate) ## Properties[**](#Properties) ### [**](#ignore)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L728)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from IMiddleware.ignore Match those paths with higher priority than ignore ### [**](#match)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L724)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from IMiddleware.match Which paths to ignore ### [**](#resolve)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L720)resolve **resolve: (app: IMidwayBaseApplication\, options? : any) => (context: any, next: any, options? : any) => any | Promise<(context: any, next: any, options? : any) => any> Inherited from IMiddleware.resolve ## Methods[**](#Methods) ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L32)optionalauthenticate * **authenticate(options: [AuthenticateOptions](/api/3.0.0/passport/interface/AuthenticateOptions.md), callback: Function): any --- # IPassportStrategy ## Index[**](#Index) ### Methods * [**deserializeUser](#deserializeUser) * [**getStrategyOptions](#getStrategyOptions) * [**serializeUser](#serializeUser) * [**transformAuthInfo](#transformAuthInfo) * [**validate](#validate) ## Methods[**](#Methods) ### [**](#deserializeUser)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L27)optionaldeserializeUser * **deserializeUser(id: any, done: (err: any, user? : any) => void): void ### [**](#getStrategyOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L25)getStrategyOptions * **getStrategyOptions(): any ### [**](#serializeUser)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L26)optionalserializeUser * **serializeUser(user: any, done: (err: any, id? : any) => void): void ### [**](#transformAuthInfo)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L28)optionaltransformAuthInfo * **transformAuthInfo(info: any, done: (err: any, info: any) => void): void ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L24)validate * **validate(...args: any\[]): any --- # StrategyCreatedStatic ## Index[**](#Index) ### Methods * [**error](#error) * [**fail](#fail) * [**pass](#pass) * [**redirect](#redirect) * [**success](#success) ## Methods[**](#Methods) ### [**](#error)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L82)error * **error(err: any): void - Internal error while performing authentication. Strategies should call this function when an internal error occurs during the process of performing authentication; for example, if the user directory is not available. ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L59)fail * **fail(challenge? : string | number, status? : number): void - Fail authentication, with optional `challenge` and `status`, defaulting to 401. Strategies should call this function to fail an authentication attempt. ### [**](#pass)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L74)pass * **pass(): void - Pass without making a success or fail decision. Under most circumstances, Strategies should not need to call this function. It exists primarily to allow previous authentication state to be restored, for example from an HTTP session. ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L66)redirect * **redirect(url: string, status? : number): void - Redirect to `url` with optional `status`, defaulting to 302. Strategies should call this function to redirect the user (via their user agent) to a third-party website for authentication. ### [**](#success)[**](https://github.com/midwayjs/midway/blob/main/packages/passport/src/interface.ts#L52)success * **success(user: any, info? : Record\): void - Authenticate `user`, with optional `info`. Strategies should call this function to successfully authenticate a user. `user` should be an object supplied by the application after it has been given an opportunity to verify credentials. `info` is an optional argument containing additional user information. This is useful for third-party authentication strategies to pass profile details. --- # @midwayjs/process-agent ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/processAgent/class/Configuration.md) ### Functions * [**RunInPrimary](/api/3.0.0/processAgent/function/RunInPrimary.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**http\_server](#http_server) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ProcessAgentConfiguration](/api/3.0.0/processAgent/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/processAgent/src/configuration.ts#L21)app **app: any ### [**](#http_server)[**](https://github.com/midwayjs/midway/blob/main/packages/processAgent/src/configuration.ts#L18)http\_server **http\_server: any ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/processAgent/src/configuration.ts#L23)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/processAgent/src/configuration.ts#L74)onStop * **onStop(): Promise\ --- # RunInPrimary ### Callable * **RunInPrimary(): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # @midwayjs/prometheus ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/prometheus/class/Configuration.md) * [**DataService](/api/3.0.0/prometheus/class/DataService.md) --- # @midwayjs/prometheus-socket-io ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/prometheus-socket-io/class/Configuration.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**dataService](#dataService) * [**socketApp](#socketApp) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PrometheusSocketIOConfiguration](/api/3.0.0/prometheus-socket-io/class/Configuration.md) ## Properties[**](#Properties) ### [**](#dataService)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus-socket-io/src/configuration.ts#L20)dataService **dataService: DataService ### [**](#socketApp)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus-socket-io/src/configuration.ts#L17)socketApp **socketApp: Application ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus-socket-io/src/configuration.ts#L22)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus-socket-io/src/configuration.ts#L146)onStop * **onStop(): Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**http\_server](#http_server) * [**prometheusConfig](#prometheusConfig) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PrometheusConfiguration](/api/3.0.0/prometheus/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/configuration.ts#L32)app **app: any ### [**](#http_server)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/configuration.ts#L34)http\_server **http\_server: any ### [**](#prometheusConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/configuration.ts#L29)prometheusConfig **prometheusConfig: DefaultMetricsCollectorConfiguration ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/configuration.ts#L36)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/configuration.ts#L98)onStop * **onStop(): Promise\ --- # DataService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**bInit](#bInit) * [**metrics](#metrics) * [**prometheusConfig](#prometheusConfig) * [**responseHistogram](#responseHistogram) * [**responseSummary](#responseSummary) * [**userDefinedMetrics](#userDefinedMetrics) ### Methods * [**define](#define) * [**getData](#getData) * [**getUser](#getUser) * [**inc](#inc) * [**init](#init) * [**observe](#observe) * [**set](#set) * [**setDiff](#setDiff) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataService(): [DataService](/api/3.0.0/prometheus/class/DataService.md) ## Properties[**](#Properties) ### [**](#bInit)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L20)bInit **bInit: boolean = false ### [**](#metrics)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L15)metrics **metrics: any ### [**](#prometheusConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L18)prometheusConfig **prometheusConfig: any ### [**](#responseHistogram)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L11)responseHistogram **responseHistogram: Histogram\ ### [**](#responseSummary)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L9)responseSummary **responseSummary: Summary\ ### [**](#userDefinedMetrics)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L13)userDefinedMetrics **userDefinedMetrics: any = {} ## Methods[**](#Methods) ### [**](#define)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L70)define * **define(name: any, type: any, options: any): void ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L117)getData * **getData(): Promise\ ### [**](#getUser)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L47)getUser * **getUser(method: any, status: any, path: any, time: any): Promise\ ### [**](#inc)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L78)inc * **inc(name: any, labels: any, value? : number): Promise\ ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L22)init * **init(): Promise\ ### [**](#observe)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L86)observe * **observe(name: any, labels: any, value: any): Promise\ ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L96)set * **set(name: any, value: any): Promise\ ### [**](#setDiff)[**](https://github.com/midwayjs/midway/blob/main/packages/prometheus/src/service/dataService.ts#L104)setDiff * **setDiff(name: any, diff: any): Promise\ --- # @midwayjs/rabbitmq ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/rabbitmq/class/Configuration.md) * [**Framework](/api/3.0.0/rabbitmq/class/Framework.md) ### Interfaces * [**Context](/api/3.0.0/rabbitmq/interface/Context.md) * [**IMidwayRabbitMQConfigurationOptions](/api/3.0.0/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) * [**IRabbitMQApplication](/api/3.0.0/rabbitmq/interface/IRabbitMQApplication.md) * [**IRabbitMQExchange](/api/3.0.0/rabbitmq/interface/IRabbitMQExchange.md) ### Type Aliases * [**Application](/api/3.0.0/rabbitmq.md#Application) * [**DefaultConfig](/api/3.0.0/rabbitmq.md#DefaultConfig) * [**IMidwayRabbitMQApplication](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQApplication) * [**IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext) * [**NextFunction](/api/3.0.0/rabbitmq.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L50)Application **Application: [IMidwayRabbitMQApplication](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQApplication) ### [**](#DefaultConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L53)DefaultConfig **DefaultConfig: string | AmqpOptions.Connect ### [**](#IMidwayRabbitMQApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L25)IMidwayRabbitMQApplication **IMidwayRabbitMQApplication: IMidwayApplication<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext)> & [IRabbitMQApplication](/api/3.0.0/rabbitmq/interface/IRabbitMQApplication.md) ### [**](#IMidwayRabbitMQContext)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L43)IMidwayRabbitMQContext **IMidwayRabbitMQContext: IMidwayContext<{ ack: (data: any) => void; channel: Channel; data: ConsumeMessage; queueName: string }> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L52)NextFunction **NextFunction: BaseNextFunction --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [RabbitMQConfiguration](/api/3.0.0/rabbitmq/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/configuration.ts#L14)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayRabbitMQApplication](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQApplication), [IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), [IMidwayRabbitMQConfigurationOptions](/api/3.0.0/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**consumerHandlerList](#consumerHandlerList) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayRabbitMQFramework](/api/3.0.0/rabbitmq/class/Framework.md) - Inherited from BaseFramework< IMidwayRabbitMQApplication, IMidwayRabbitMQContext, IMidwayRabbitMQConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L28)publicapp **app: [IMidwayRabbitMQApplication](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQApplication) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayRabbitMQConfigurationOptions](/api/3.0.0/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#consumerHandlerList)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L29)publicconsumerHandlerList **consumerHandlerList: any\[] = \[] ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L35)applicationInitialize * **applicationInitialize(options: any): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L31)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [IMidwayRabbitMQApplication](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L125)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L62)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayRabbitMQFramework](/api/3.0.0/rabbitmq/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/framework.ts#L43)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # Context ### Hierarchy * [IMidwayRabbitMQContext](/api/3.0.0/rabbitmq.md#IMidwayRabbitMQContext) * *Context* ## Index[**](#Index) ### Properties * [**ack](#ack) * [**channel](#channel) * [**data](#data) * [**logger](#logger) * [**queueName](#queueName) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#ack)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L47)ack **ack: (data: any) => void Inherited from IMidwayRabbitMQContext.ack ### [**](#channel)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L45)channel **channel: Channel Inherited from IMidwayRabbitMQContext.channel ### [**](#data)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L44)data **data: ConsumeMessage Inherited from IMidwayRabbitMQContext.data ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayRabbitMQContext.logger ### [**](#queueName)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L46)queueName **queueName: string Inherited from IMidwayRabbitMQContext.queueName ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayRabbitMQContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayRabbitMQContext.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayRabbitMQContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayRabbitMQContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayRabbitMQContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayRabbitMQContext.setAttr Set value to app attribute map --- # IMidwayRabbitMQConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayRabbitMQConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**exchanges](#exchanges) * [**logger](#logger) * [**reconnectTime](#reconnectTime) * [**socketOptions](#socketOptions) * [**url](#url) * [**useConfirmChannel](#useConfirmChannel) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#exchanges)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L39)optionalexchanges **exchanges? : [IRabbitMQExchange](/api/3.0.0/rabbitmq/interface/IRabbitMQExchange.md)\[] ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#reconnectTime)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L38)optionalreconnectTime **reconnectTime? : number ### [**](#socketOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L37)optionalsocketOptions **socketOptions? : any ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L36)url **url: string | Connect ### [**](#useConfirmChannel)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L40)optionaluseConfirmChannel **useConfirmChannel? : boolean --- # IRabbitMQApplication ## Index[**](#Index) ### Methods * [**close](#close) * [**connect](#connect) * [**createChannel](#createChannel) * [**createConsumer](#createConsumer) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L22)close * **close(): Promise\ ### [**](#connect)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L12)connect * **connect(...args: any\[]): Promise\ ### [**](#createChannel)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L13)createChannel * **createChannel(): Promise\ ### [**](#createConsumer)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L14)createConsumer * **createConsumer(listenerOptions: [RabbitMQListenerOptions](/api/3.0.0/decorator/interface/RabbitMQListenerOptions.md), listenerCallback: (msg: ConsumeMessage, channel: Channel, channelWrapper: any) => Promise\): Promise\ --- # IRabbitMQExchange ## Index[**](#Index) ### Properties * [**name](#name) * [**options](#options) * [**type](#type) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L29)name **name: string ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L31)optionaloptions **options? : AssertExchange ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/rabbitmq/src/interface.ts#L30)type **type: string --- # @midwayjs/redis ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/redis/class/Configuration.md) * [**RedisService](/api/3.0.0/redis/class/RedisService.md) * [**RedisServiceFactory](/api/3.0.0/redis/class/RedisServiceFactory.md) ### Type Aliases * [**RedisConfigOptions](/api/3.0.0/redis.md#RedisConfigOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#RedisConfigOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/interface.ts#L4)RedisConfigOptions **RedisConfigOptions: Redis.RedisOptions | ({ cluster? : boolean; nodes? : ClusterNode\[] } & ClusterOptions) --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onHealthCheck](#onHealthCheck) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [RedisConfiguration](/api/3.0.0/redis/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/configuration.ts#L29)onHealthCheck * **onHealthCheck(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onHealthCheck ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/configuration.ts#L20)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/configuration.ts#L24)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # RedisService ### Hierarchy * Redis * *RedisService* ### Implements * Redis ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RedisService(): [RedisService](/api/3.0.0/redis/class/RedisService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/manager.ts#L120)init * **init(): Promise\ --- # RedisServiceFactory ### Hierarchy * ServiceFactory\ * *RedisServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RedisServiceFactory(): [RedisServiceFactory](/api/3.0.0/redis/class/RedisServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Redis ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/redis/src/manager.ts#L93)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # @midwayjs/security ## Index[**](#Index) ### Classes * [**CSPMiddleware](/api/3.0.0/security/class/CSPMiddleware.md) * [**Configuration](/api/3.0.0/security/class/Configuration.md) * [**CsrfMiddleware](/api/3.0.0/security/class/CsrfMiddleware.md) * [**HSTSMiddleware](/api/3.0.0/security/class/HSTSMiddleware.md) * [**NoOpenMiddleware](/api/3.0.0/security/class/NoOpenMiddleware.md) * [**NoSniffMiddleware](/api/3.0.0/security/class/NoSniffMiddleware.md) * [**SecurityHelper](/api/3.0.0/security/class/SecurityHelper.md) * [**XFrameMiddleware](/api/3.0.0/security/class/XFrameMiddleware.md) * [**XSSProtectionMiddleware](/api/3.0.0/security/class/XSSProtectionMiddleware.md) ### Interfaces * [**SecurityCSPOptions](/api/3.0.0/security/interface/SecurityCSPOptions.md) * [**SecurityCSRFOptions](/api/3.0.0/security/interface/SecurityCSRFOptions.md) * [**SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * [**SecurityHSTSOptions](/api/3.0.0/security/interface/SecurityHSTSOptions.md) * [**SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) * [**SecurityXFrameOptions](/api/3.0.0/security/interface/SecurityXFrameOptions.md) * [**SecurityXSSProtectionOptions](/api/3.0.0/security/interface/SecurityXSSProtectionOptions.md) ### Type Aliases * [**SecurityCSRFType](/api/3.0.0/security.md#SecurityCSRFType) ## Type Aliases[**](<#Type Aliases>) ### [**](#SecurityCSRFType)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L97)SecurityCSRFType **SecurityCSRFType: all | any | ctoken | referer --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**security](#security) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SecurityConfiguration](/api/3.0.0/security/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/configuration.ts#L27)applicationManager **applicationManager: MidwayApplicationManager ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/configuration.ts#L30)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/configuration.ts#L32)onReady * **onReady(): Promise\ --- # CSPMiddleware ### Hierarchy * BaseMiddleware * *CSPMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CSPMiddleware(): [CSPMiddleware](/api/3.0.0/security/class/CSPMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csp.middleware.ts#L15)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csp.middleware.ts#L74)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # CsrfMiddleware ### Hierarchy * BaseMiddleware * *CsrfMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**assertCsrf](#assertCsrf) * [**compatibleMiddleware](#compatibleMiddleware) * [**getCSRFSecret](#getCSRFSecret) * [**getInputToken](#getInputToken) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CsrfMiddleware(): [CsrfMiddleware](/api/3.0.0/security/class/CsrfMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#assertCsrf)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csrf.middleware.ts#L45)assertCsrf * **assertCsrf(context: any, request: any): void ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csrf.middleware.ts#L12)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#getCSRFSecret)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csrf.middleware.ts#L64)getCSRFSecret * **getCSRFSecret(context: any): any ### [**](#getInputToken)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csrf.middleware.ts#L91)getInputToken * **getInputToken(context: any, request: any): any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/csrf.middleware.ts#L157)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # HSTSMiddleware ### Hierarchy * BaseMiddleware * *HSTSMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HSTSMiddleware(): [HSTSMiddleware](/api/3.0.0/security/class/HSTSMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/hsts.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/hsts.middleware.ts#L15)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # NoOpenMiddleware ### Hierarchy * BaseMiddleware * *NoOpenMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NoOpenMiddleware(): [NoOpenMiddleware](/api/3.0.0/security/class/NoOpenMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/noopen.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/noopen.middleware.ts#L11)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # NoSniffMiddleware ### Hierarchy * BaseMiddleware * *NoSniffMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NoSniffMiddleware(): [NoSniffMiddleware](/api/3.0.0/security/class/NoSniffMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/nosniff.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/nosniff.middleware.ts#L14)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # SecurityHelper ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SecurityHelper(): [SecurityHelper](/api/3.0.0/security/class/SecurityHelper.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/helper.ts#L19)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/helper.ts#L7)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve --- # XFrameMiddleware ### Hierarchy * BaseMiddleware * *XFrameMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new XFrameMiddleware(): [XFrameMiddleware](/api/3.0.0/security/class/XFrameMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/xframe.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/xframe.middleware.ts#L13)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # XSSProtectionMiddleware ### Hierarchy * BaseMiddleware * *XSSProtectionMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new XSSProtectionMiddleware(): [XSSProtectionMiddleware](/api/3.0.0/security/class/XSSProtectionMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L14)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L13)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L12)security **security: [SecurityOptions](/api/3.0.0/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/xssProtection.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L17)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/base.ts#L26)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/middleware/xssProtection.middleware.ts#L12)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # SecurityCSPOptions ### Hierarchy * [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * *SecurityCSPOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**policy](#policy) * [**reportOnly](#reportOnly) * [**supportIE](#supportIE) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#policy)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L85)policy **policy: {} ### [**](#reportOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L88)reportOnly **reportOnly: boolean ### [**](#supportIE)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L89)supportIE **supportIE: boolean --- # SecurityCSRFOptions ### Hierarchy * [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * *SecurityCSRFOptions* ## Index[**](#Index) ### Properties * [**bodyName](#bodyName) * [**cookieDomain](#cookieDomain) * [**cookieName](#cookieName) * [**enable](#enable) * [**headerName](#headerName) * [**ignore](#ignore) * [**match](#match) * [**queryName](#queryName) * [**refererWhiteList](#refererWhiteList) * [**sessionName](#sessionName) * [**type](#type) * [**useSession](#useSession) ## Properties[**](#Properties) ### [**](#bodyName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L62)bodyName **bodyName: string The name of the csrf token in the body. ### [**](#cookieDomain)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L68)cookieDomain **cookieDomain: (context: any) => string ### [**](#cookieName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L50)cookieName **cookieName: string | string\[] The key name stored in the cookie by the token of csrf ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#headerName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L58)headerName **headerName: string The name of the csrf token in the header ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#queryName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L66)queryName **queryName: string The name of the csrf token in the query. ### [**](#refererWhiteList)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L67)refererWhiteList **refererWhiteList: string\[] ### [**](#sessionName)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L54)sessionName **sessionName: string The key name of the CSRF token stored in the session. ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L42)type **type: [SecurityCSRFType](/api/3.0.0/security.md#SecurityCSRFType) ### [**](#useSession)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L46)useSession **useSession: boolean If set to true, the secret will be stored in the session instead of the cookie. --- # SecurityEnableOptions ### Hierarchy * *SecurityEnableOptions* * [SecurityCSRFOptions](/api/3.0.0/security/interface/SecurityCSRFOptions.md) * [SecurityXFrameOptions](/api/3.0.0/security/interface/SecurityXFrameOptions.md) * [SecurityHSTSOptions](/api/3.0.0/security/interface/SecurityHSTSOptions.md) * [SecurityXSSProtectionOptions](/api/3.0.0/security/interface/SecurityXSSProtectionOptions.md) * [SecurityCSPOptions](/api/3.0.0/security/interface/SecurityCSPOptions.md) ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] --- # SecurityHSTSOptions ### Hierarchy * [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * *SecurityHSTSOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**includeSubdomains](#includeSubdomains) * [**match](#match) * [**maxAge](#maxAge) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#includeSubdomains)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L77)includeSubdomains **includeSubdomains: boolean ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L76)maxAge **maxAge: number --- # SecurityOptions ## Index[**](#Index) ### Properties * [**csp](#csp) * [**csrf](#csrf) * [**hsts](#hsts) * [**noopen](#noopen) * [**nosniff](#nosniff) * [**xframe](#xframe) * [**xssProtection](#xssProtection) ## Properties[**](#Properties) ### [**](#csp)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L13)csp **csp: Partial<[SecurityCSPOptions](/api/3.0.0/security/interface/SecurityCSPOptions.md)> content security policy config default not enable ### [**](#csrf)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L8)csrf **csrf: Partial<[SecurityCSRFOptions](/api/3.0.0/security/interface/SecurityCSRFOptions.md)> whether defend csrf attack default enable and use cookie ### [**](#hsts)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L23)hsts **hsts: Partial<[SecurityHSTSOptions](/api/3.0.0/security/interface/SecurityHSTSOptions.md)> whether enable Strict-Transport-Security response header default not enable and maxAge equals one year ### [**](#noopen)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L28)noopen **noopen: Partial<[SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md)> whether enable IE automaticlly download open default not enable ### [**](#nosniff)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L33)nosniff **nosniff: Partial<[SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md)> whether enable IE8 automaticlly dedect mime default not enable ### [**](#xframe)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L18)xframe **xframe: Partial<[SecurityXFrameOptions](/api/3.0.0/security/interface/SecurityXFrameOptions.md)> whether enable X-Frame-Options response header default enable and value equals SAMEORIGIN ### [**](#xssProtection)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L38)xssProtection **xssProtection: Partial<[SecurityXSSProtectionOptions](/api/3.0.0/security/interface/SecurityXSSProtectionOptions.md)> whether enable IE8 XSS Filter, default is open default enable --- # SecurityXFrameOptions ### Hierarchy * [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * *SecurityXFrameOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**value](#value) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L72)value **value: string --- # SecurityXSSProtectionOptions ### Hierarchy * [SecurityEnableOptions](/api/3.0.0/security/interface/SecurityEnableOptions.md) * *SecurityXSSProtectionOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**value](#value) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/security/src/interface.ts#L81)value **value: string --- # @midwayjs/sequelize ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/sequelize/class/Configuration.md) * [**SequelizeDataSourceManager](/api/3.0.0/sequelize/class/SequelizeDataSourceManager.md) ### Functions * [**BaseTable](/api/3.0.0/sequelize/function/BaseTable.md) * [**InjectDataSource](/api/3.0.0/sequelize/function/InjectDataSource.md) * [**InjectRepository](/api/3.0.0/sequelize/function/InjectRepository.md) ### Type Aliases * [**SequelizeConfigOptions](/api/3.0.0/sequelize.md#SequelizeConfigOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#SequelizeConfigOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/interface.ts#L5)SequelizeConfigOptions **SequelizeConfigOptions: DataSourceManagerConfigOption\ : boolean; syncOptions? : SyncOptions }> --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) * [**sequelizeConfig](#sequelizeConfig) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SequelizeConfiguration](/api/3.0.0/sequelize/class/Configuration.md) ## Properties[**](#Properties) ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L43)dataSourceManager **dataSourceManager: [SequelizeDataSourceManager](/api/3.0.0/sequelize/class/SequelizeDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L41)decoratorService **decoratorService: MidwayDecoratorService ### [**](#sequelizeConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L38)sequelizeConfig **sequelizeConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L46)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L82)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/configuration.ts#L88)onStop * **onStop(): Promise\ --- # SequelizeDataSourceManager ### Hierarchy * DataSourceManager\ * *SequelizeDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**baseDir](#baseDir) * [**coreLogger](#coreLogger) * [**sequelizeConfig](#sequelizeConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SequelizeDataSourceManager(): [SequelizeDataSourceManager](/api/3.0.0/sequelize/class/SequelizeDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/dataSourceManager.ts#L25)baseDir **baseDir: string ### [**](#coreLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/dataSourceManager.ts#L22)coreLogger **coreLogger: ILogger ### [**](#sequelizeConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/dataSourceManager.ts#L19)sequelizeConfig **sequelizeConfig: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L34)createInstance * **createInstance(config: any, clientName: any, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L21)getDataSource * **getDataSource(dataSourceName: string): Sequelize - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L42)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L27)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L52)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/dataSourceManager.ts#L32)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L26)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/sequelize/src/dataSourceManager.ts#L28)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L33)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L53)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L55)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L54)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L50)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources --- # BaseTable ### Callable * **BaseTable\(options: TableOptions\): any * **BaseTable(target: any): void *** * * **@deprecated** *** #### Type parameters * **M**: Model\ = Model\ --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectRepository ### Callable * **InjectRepository(modelKey: new () => Model\, connectionName? : string): PropertyDecorator --- # @midwayjs/session ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/session/class/Configuration.md) * [**SessionMiddleware](/api/3.0.0/session/class/SessionMiddleware.md) * [**SessionStore](/api/3.0.0/session/class/SessionStore.md) * [**SessionStoreManager](/api/3.0.0/session/class/SessionStoreManager.md) ### Interfaces * [**ISession](/api/3.0.0/session/interface/ISession.md) * [**SessionOptions](/api/3.0.0/session/interface/SessionOptions.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**logger](#logger) * [**sessionConfig](#sessionConfig) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SessionConfiguration](/api/3.0.0/session/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/configuration.ts#L24)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/configuration.ts#L27)sessionConfig **sessionConfig: any ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/configuration.ts#L29)onReady * **onReady(): Promise\ --- # SessionMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**sessionConfig](#sessionConfig) * [**sessionStoreManager](#sessionStoreManager) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionMiddleware(): [SessionMiddleware](/api/3.0.0/session/class/SessionMiddleware.md) ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/middleware/session.ts#L144)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/middleware/session.ts#L141)sessionConfig **sessionConfig: any ### [**](#sessionStoreManager)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/middleware/session.ts#L147)sessionStoreManager **sessionStoreManager: [SessionStoreManager](/api/3.0.0/session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/middleware/session.ts#L149)resolve * **resolve(app: any): (ctx: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/middleware/session.ts#L178)staticgetName * **getName(): string --- # abstractSessionStore ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**destroy](#destroy) * [**get](#get) * [**set](#set) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStore(): [SessionStore](/api/3.0.0/session/class/SessionStore.md) ## Methods[**](#Methods) ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L134)abstractdestroy * **destroy(key: any): any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L132)abstractget * **get(key: string): any ### [**](#set)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L133)abstractset * **set(key: string, value: string, maxAge: number): any --- # SessionStoreManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSessionStore](#getSessionStore) * [**setSessionStore](#setSessionStore) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStoreManager(): [SessionStoreManager](/api/3.0.0/session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#getSessionStore)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/lib/store.ts#L11)getSessionStore * **getSessionStore(): [SessionStore](/api/3.0.0/session/class/SessionStore.md) ### [**](#setSessionStore)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/lib/store.ts#L8)setSessionStore * **setSessionStore(sessionStore: any): void --- # ISession ### Indexable **\[\_ : string]: any ## Index[**](#Index) ### Properties * [**length](#length) * [**maxAge](#maxAge) * [**populated](#populated) ### Methods * [**manuallyCommit](#manuallyCommit) * [**regenerate](#regenerate) * [**save](#save) * [**toJSON](#toJSON) ## Properties[**](#Properties) ### [**](#length)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L13)readonlylength **length: number Return how many values there are in the session object. Used to see if it"s "populated". ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L23)maxAge **maxAge: number | session get/set session maxAge ### [**](#populated)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L18)readonlypopulated **populated: boolean populated flag, which is just a boolean alias of .length. ## Methods[**](#Methods) ### [**](#manuallyCommit)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L28)manuallyCommit * **manuallyCommit(): Promise\ - commit this session's headers if autoCommit is set to false. ### [**](#regenerate)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L33)regenerate * **regenerate(callback? : () => void): void - regenerate this session ### [**](#save)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L38)save * **save(callback? : () => void): void - save this session no matter whether it is populated ### [**](#toJSON)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L7)toJSON * **toJSON(): object - JSON representation of the session. --- # SessionOptions ### Hierarchy * Omit\ * *SessionOptions* ## Index[**](#Index) ### Properties * [**ContextStore](#ContextStore) * [**autoCommit](#autoCommit) * [**decode](#decode) * [**enable](#enable) * [**encode](#encode) * [**externalKey](#externalKey) * [**genid](#genid) * [**key](#key) * [**maxAge](#maxAge) * [**prefix](#prefix) * [**renew](#renew) * [**rolling](#rolling) ### Methods * [**beforeSave](#beforeSave) * [**valid](#valid) ## Properties[**](#Properties) ### [**](#ContextStore)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L108)optionalContextStore **ContextStore? : new (ctx: any) => [SessionStore](/api/3.0.0/session/class/SessionStore.md) ### [**](#autoCommit)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L128)optionalautoCommit **autoCommit? : boolean (boolean) automatically commit headers (default true). ### [**](#decode)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L80)decode **decode: (obj: Record\) => string ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L59)enable **enable: boolean ### [**](#encode)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L75)encode **encode: (str: string) => Record\ ### [**](#externalKey)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L101)optionalexternalKey **externalKey? : ExternalKeys External key is used the cookie by default, but you can use options.externalKey to customize your own external key methods. ### [**](#genid)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L85)genid **genid: () => string ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L63)key **key: string cookie key (default is koa:sess) ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L70)optionalmaxAge **maxAge? : number | session maxAge in ms (default is 1 days) "session" will result in a cookie that expires when session/browser is closed Warning: If a session cookie is stolen, this cookie will never expire ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L113)optionalprefix **prefix? : string If you want to add prefix for all external session id, you can use options.prefix, it will not work if options.genid present. ### [**](#renew)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L95)optionalrenew **renew? : boolean Renew session when session is nearly expired, so we can always keep user logged in. (default is false) ### [**](#rolling)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L90)optionalrolling **rolling? : boolean Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. default is false ## Methods[**](#Methods) ### [**](#beforeSave)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L123)optionalbeforeSave * **beforeSave(ctx: any, session: [ISession](/api/3.0.0/session/interface/ISession.md)): void - Hook: before save session ### [**](#valid)[**](https://github.com/midwayjs/midway/blob/main/packages/session/src/interface.ts#L118)optionalvalid * **valid(ctx: any, session: Partial<[ISession](/api/3.0.0/session/interface/ISession.md)>): void - Hook: valid session value before use it --- # @midwayjs/socketio ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/socketio/class/Configuration.md) * [**Framework](/api/3.0.0/socketio/class/Framework.md) ### Functions * [**createRedisAdapter](/api/3.0.0/socketio/function/createRedisAdapter.md) ### Type Aliases * [**Application](/api/3.0.0/socketio.md#Application) * [**Context](/api/3.0.0/socketio.md#Context) * [**IMidwaySocketIOOptions](/api/3.0.0/socketio.md#IMidwaySocketIOOptions) * [**NextFunction](/api/3.0.0/socketio.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/interface.ts#L11)Application **Application: IMidwayApplication<[Context](/api/3.0.0/socketio.md#Context), { getConnectionMiddleware: ContextMiddlewareManager<[Context](/api/3.0.0/socketio.md#Context), [NextFunction](/api/3.0.0/socketio.md#NextFunction), undefined>; useConnectionMiddleware: (middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/socketio.md#Context), [NextFunction](/api/3.0.0/socketio.md#NextFunction), undefined>) => void; use: any } & SocketIO.Server> ### [**](#Context)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/interface.ts#L25)Context **Context: IMidwayContext\ ### [**](#IMidwaySocketIOOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/interface.ts#L19)IMidwaySocketIOOptions **IMidwaySocketIOOptions: { port? : number; pubClient? : any; subClient? : any } & Partial\ & IConfigurationOptions ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/interface.ts#L29)NextFunction **NextFunction: BaseNextFunction --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SocketIOConfiguration](/api/3.0.0/socketio/class/Configuration.md) --- # Framework ### Hierarchy * BaseFramework<[Application](/api/3.0.0/socketio.md#Application), [Context](/api/3.0.0/socketio.md#Context), [IMidwaySocketIOOptions](/api/3.0.0/socketio.md#IMidwaySocketIOOptions)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConnectionMiddleware](#getConnectionMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useConnectionMiddleware](#useConnectionMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwaySocketIOFramework](/api/3.0.0/socketio/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwaySocketIOOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L37)publicapp **app: [Application](/api/3.0.0/socketio.md#Application) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwaySocketIOOptions](/api/3.0.0/socketio.md#IMidwaySocketIOOptions) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/socketio.md#Context), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L44)applicationInitialize * **applicationInitialize(): void - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/socketio.md#Context), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L40)configure * **configure(): [IMidwaySocketIOOptions](/api/3.0.0/socketio.md#IMidwaySocketIOOptions) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [Application](/api/3.0.0/socketio.md#Application) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L345)publicgetConnectionMiddleware * **getConnectionMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/socketio.md#Context), NextFunction, undefined> ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L335)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L99)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/socketio.md#Context), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwaySocketIOFramework](/api/3.0.0/socketio/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L62)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/socketio.md#Context), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/socketio/src/framework.ts#L339)publicuseConnectionMiddleware * **useConnectionMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/socketio.md#Context), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/socketio.md#Context), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/socketio.md#Context)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/socketio.md#Context), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # createRedisAdapter ### Callable * **createRedisAdapter(options: { host: string; port: number } & Partial\): any * **createRedisAdapter(options: Partial\): any --- # @midwayjs/static-file ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/static-file/class/Configuration.md) * [**DirectoryNotFoundError](/api/3.0.0/static-file/class/DirectoryNotFoundError.md) * [**StaticMiddleware](/api/3.0.0/static-file/class/StaticMiddleware.md) ### Interfaces * [**StaticFileOption](/api/3.0.0/static-file/interface/StaticFileOption.md) * [**StaticFileOptions](/api/3.0.0/static-file/interface/StaticFileOptions.md) ### Variables * [**StaticFileErrorEnum](/api/3.0.0/static-file.md#StaticFileErrorEnum) ## Variables[**](#Variables) ### [**](#StaticFileErrorEnum)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/error.ts#L3)constStaticFileErrorEnum **StaticFileErrorEnum: ConvertString<{ DIRECTORY\_NOT\_EXISTS: 10000 }, static\_file> = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onConfigLoad](#onConfigLoad) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [StaticFileConfiguration](/api/3.0.0/static-file/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onConfigLoad)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/configuration.ts#L22)onConfigLoad * **onConfigLoad(): Promise<{ staticFile: { buffer: boolean } }> ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/configuration.ts#L32)onReady * **onReady(container: IMidwayContainer): Promise\ --- # DirectoryNotFoundError ### Hierarchy * MidwayError * *DirectoryNotFoundError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/error.ts#L8)constructor * **new DirectoryNotFoundError(p: string): [DirectoryNotFoundError](/api/3.0.0/static-file/class/DirectoryNotFoundError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayError.code --- # StaticMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**environmentService](#environmentService) * [**logger](#logger) * [**middlewareService](#middlewareService) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new StaticMiddleware(): [StaticMiddleware](/api/3.0.0/static-file/class/StaticMiddleware.md) ## Properties[**](#Properties) ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/middleware/static.middleware.ts#L27)environmentService **environmentService: MidwayEnvironmentService ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/middleware/static.middleware.ts#L30)logger **logger: any ### [**](#middlewareService)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/middleware/static.middleware.ts#L24)middlewareService **middlewareService: MidwayMiddlewareService\ ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/middleware/static.middleware.ts#L32)resolve * **resolve(app: any): Promise<{ \_name: string }> ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/middleware/static.middleware.ts#L89)staticgetName * **getName(): string --- # StaticFileOption ## Index[**](#Index) ### Properties * [**alias](#alias) * [**buffer](#buffer) * [**cacheControl](#cacheControl) * [**dir](#dir) * [**dynamic](#dynamic) * [**filter](#filter) * [**gzip](#gzip) * [**maxAge](#maxAge) * [**maxFiles](#maxFiles) * [**prefix](#prefix) * [**preload](#preload) ## Properties[**](#Properties) ### [**](#alias)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L41)optionalalias **alias? : {} object map of aliases ### [**](#buffer)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L21)optionalbuffer **buffer? : boolean store the files in memory instead of streaming from the filesystem on each request. ### [**](#cacheControl)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L33)optionalcacheControl **cacheControl? : string optional cache control header. Overrides options.maxAge. ### [**](#dir)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L9)optionaldir **dir? : string the directory you wish to serve ### [**](#dynamic)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L13)optionaldynamic **dynamic? : boolean dynamic load file which not cached on initialization. ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L47)optionalfilter **filter? : Function | string\[] filter files at init dir, for example - skip non build (source) files. If array set - allow only listed files ### [**](#gzip)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L37)optionalgzip **gzip? : boolean when request's accept-encoding include gzip, files will compressed by gzip. ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L29)optionalmaxAge **maxAge? : number cache control max age for the files, 0 by default. ### [**](#maxFiles)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L25)optionalmaxFiles **maxFiles? : number cache control max age for the files, 0 by default. ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L5)optionalprefix **prefix? : string url prefix ### [**](#preload)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L17)optionalpreload **preload? : boolean caches the assets on initialization or not, default to true. always work together with options.dynamic. --- # StaticFileOptions ### Hierarchy * Omit<[StaticFileOption](/api/3.0.0/static-file/interface/StaticFileOption.md), prefix | dir> * *StaticFileOptions* ## Index[**](#Index) ### Properties * [**alias](#alias) * [**buffer](#buffer) * [**cacheControl](#cacheControl) * [**dirs](#dirs) * [**dynamic](#dynamic) * [**filter](#filter) * [**gzip](#gzip) * [**maxAge](#maxAge) * [**maxFiles](#maxFiles) * [**preload](#preload) ## Properties[**](#Properties) ### [**](#alias)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L41)optionalalias **alias? : {} Inherited from Omit.alias object map of aliases ### [**](#buffer)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L21)optionalbuffer **buffer? : boolean Inherited from Omit.buffer store the files in memory instead of streaming from the filesystem on each request. ### [**](#cacheControl)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L33)optionalcacheControl **cacheControl? : string Inherited from Omit.cacheControl optional cache control header. Overrides options.maxAge. ### [**](#dirs)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L52)optionaldirs **dirs? : {} ### [**](#dynamic)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L13)optionaldynamic **dynamic? : boolean Inherited from Omit.dynamic dynamic load file which not cached on initialization. ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L47)optionalfilter **filter? : Function | string\[] Inherited from Omit.filter filter files at init dir, for example - skip non build (source) files. If array set - allow only listed files ### [**](#gzip)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L37)optionalgzip **gzip? : boolean Inherited from Omit.gzip when request's accept-encoding include gzip, files will compressed by gzip. ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L29)optionalmaxAge **maxAge? : number Inherited from Omit.maxAge cache control max age for the files, 0 by default. ### [**](#maxFiles)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L25)optionalmaxFiles **maxFiles? : number Inherited from Omit.maxFiles cache control max age for the files, 0 by default. ### [**](#preload)[**](https://github.com/midwayjs/midway/blob/main/packages/static-file/src/interface.ts#L17)optionalpreload **preload? : boolean Inherited from Omit.preload caches the assets on initialization or not, default to true. always work together with options.dynamic. --- # @midwayjs/swagger ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/swagger/class/Configuration.md) * [**SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md) * [**SwaggerMiddleware](/api/3.0.0/swagger/class/SwaggerMiddleware.md) ### Enumerations * [**BodyContentType](/api/3.0.0/swagger/enum/BodyContentType.md) ### Functions * [**ApiAcceptedResponse](/api/3.0.0/swagger/function/ApiAcceptedResponse.md) * [**ApiBadGatewayResponse](/api/3.0.0/swagger/function/ApiBadGatewayResponse.md) * [**ApiBadRequestResponse](/api/3.0.0/swagger/function/ApiBadRequestResponse.md) * [**ApiBasicAuth](/api/3.0.0/swagger/function/ApiBasicAuth.md) * [**ApiBearerAuth](/api/3.0.0/swagger/function/ApiBearerAuth.md) * [**ApiBody](/api/3.0.0/swagger/function/ApiBody.md) * [**ApiConflictResponse](/api/3.0.0/swagger/function/ApiConflictResponse.md) * [**ApiCookieAuth](/api/3.0.0/swagger/function/ApiCookieAuth.md) * [**ApiCreatedResponse](/api/3.0.0/swagger/function/ApiCreatedResponse.md) * [**ApiDefaultResponse](/api/3.0.0/swagger/function/ApiDefaultResponse.md) * [**ApiExcludeController](/api/3.0.0/swagger/function/ApiExcludeController.md) * [**ApiExcludeEndpoint](/api/3.0.0/swagger/function/ApiExcludeEndpoint.md) * [**ApiExcludeSecurity](/api/3.0.0/swagger/function/ApiExcludeSecurity.md) * [**ApiExtension](/api/3.0.0/swagger/function/ApiExtension.md) * [**ApiExtraModel](/api/3.0.0/swagger/function/ApiExtraModel.md) * [**ApiForbiddenResponse](/api/3.0.0/swagger/function/ApiForbiddenResponse.md) * [**ApiFoundResponse](/api/3.0.0/swagger/function/ApiFoundResponse.md) * [**ApiGatewayTimeoutResponse](/api/3.0.0/swagger/function/ApiGatewayTimeoutResponse.md) * [**ApiGoneResponse](/api/3.0.0/swagger/function/ApiGoneResponse.md) * [**ApiHeader](/api/3.0.0/swagger/function/ApiHeader.md) * [**ApiHeaders](/api/3.0.0/swagger/function/ApiHeaders.md) * [**ApiInternalServerErrorResponse](/api/3.0.0/swagger/function/ApiInternalServerErrorResponse.md) * [**ApiMethodNotAllowedResponse](/api/3.0.0/swagger/function/ApiMethodNotAllowedResponse.md) * [**ApiMovedPermanentlyResponse](/api/3.0.0/swagger/function/ApiMovedPermanentlyResponse.md) * [**ApiNoContentResponse](/api/3.0.0/swagger/function/ApiNoContentResponse.md) * [**ApiNotAcceptableResponse](/api/3.0.0/swagger/function/ApiNotAcceptableResponse.md) * [**ApiNotFoundResponse](/api/3.0.0/swagger/function/ApiNotFoundResponse.md) * [**ApiNotImplementedResponse](/api/3.0.0/swagger/function/ApiNotImplementedResponse.md) * [**ApiOAuth2](/api/3.0.0/swagger/function/ApiOAuth2.md) * [**ApiOkResponse](/api/3.0.0/swagger/function/ApiOkResponse.md) * [**ApiOperation](/api/3.0.0/swagger/function/ApiOperation.md) * [**ApiParam](/api/3.0.0/swagger/function/ApiParam.md) * [**ApiPayloadTooLargeResponse](/api/3.0.0/swagger/function/ApiPayloadTooLargeResponse.md) * [**ApiPreconditionFailedResponse](/api/3.0.0/swagger/function/ApiPreconditionFailedResponse.md) * [**ApiProperty](/api/3.0.0/swagger/function/ApiProperty.md) * [**ApiPropertyOptional](/api/3.0.0/swagger/function/ApiPropertyOptional.md) * [**ApiQuery](/api/3.0.0/swagger/function/ApiQuery.md) * [**ApiRequestTimeoutResponse](/api/3.0.0/swagger/function/ApiRequestTimeoutResponse.md) * [**ApiResponse](/api/3.0.0/swagger/function/ApiResponse.md) * [**ApiResponseProperty](/api/3.0.0/swagger/function/ApiResponseProperty.md) * [**ApiSecurity](/api/3.0.0/swagger/function/ApiSecurity.md) * [**ApiServiceUnavailableResponse](/api/3.0.0/swagger/function/ApiServiceUnavailableResponse.md) * [**ApiTags](/api/3.0.0/swagger/function/ApiTags.md) * [**ApiTooManyRequestsResponse](/api/3.0.0/swagger/function/ApiTooManyRequestsResponse.md) * [**ApiUnauthorizedResponse](/api/3.0.0/swagger/function/ApiUnauthorizedResponse.md) * [**ApiUnprocessableEntityResponse](/api/3.0.0/swagger/function/ApiUnprocessableEntityResponse.md) * [**ApiUnsupportedMediaTypeResponse](/api/3.0.0/swagger/function/ApiUnsupportedMediaTypeResponse.md) * [**getSchemaPath](/api/3.0.0/swagger/function/getSchemaPath.md) * [**renderJSON](/api/3.0.0/swagger/function/renderJSON.md) * [**renderSwaggerUIDist](/api/3.0.0/swagger/function/renderSwaggerUIDist.md) * [**renderSwaggerUIRemote](/api/3.0.0/swagger/function/renderSwaggerUIRemote.md) ### Interfaces * [**ApiHeaderOptions](/api/3.0.0/swagger/interface/ApiHeaderOptions.md) * [**ApiPropertyOptions](/api/3.0.0/swagger/interface/ApiPropertyOptions.md) * [**ApiResponseMetadata](/api/3.0.0/swagger/interface/ApiResponseMetadata.md) * [**ApiResponseSchemaHost](/api/3.0.0/swagger/interface/ApiResponseSchemaHost.md) * [**AuthOptions](/api/3.0.0/swagger/interface/AuthOptions.md) * [**BaseParameterObject](/api/3.0.0/swagger/interface/BaseParameterObject.md) * [**ComponentsObject](/api/3.0.0/swagger/interface/ComponentsObject.md) * [**ContactObject](/api/3.0.0/swagger/interface/ContactObject.md) * [**DiscriminatorObject](/api/3.0.0/swagger/interface/DiscriminatorObject.md) * [**EncodingPropertyObject](/api/3.0.0/swagger/interface/EncodingPropertyObject.md) * [**ExampleObject](/api/3.0.0/swagger/interface/ExampleObject.md) * [**ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) * [**InfoObject](/api/3.0.0/swagger/interface/InfoObject.md) * [**LicenseObject](/api/3.0.0/swagger/interface/LicenseObject.md) * [**LinkObject](/api/3.0.0/swagger/interface/LinkObject.md) * [**MediaTypeObject](/api/3.0.0/swagger/interface/MediaTypeObject.md) * [**MixDecoratorMetadata](/api/3.0.0/swagger/interface/MixDecoratorMetadata.md) * [**OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) * [**OAuthFlowsObject](/api/3.0.0/swagger/interface/OAuthFlowsObject.md) * [**OpenAPIObject](/api/3.0.0/swagger/interface/OpenAPIObject.md) * [**OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) * [**ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md) * [**PathItemObject](/api/3.0.0/swagger/interface/PathItemObject.md) * [**ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) * [**RequestBodyObject](/api/3.0.0/swagger/interface/RequestBodyObject.md) * [**ResponseObject](/api/3.0.0/swagger/interface/ResponseObject.md) * [**ResponsesObject](/api/3.0.0/swagger/interface/ResponsesObject.md) * [**SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) * [**SchemaObjectMetadata](/api/3.0.0/swagger/interface/SchemaObjectMetadata.md) * [**SecuritySchemeObject](/api/3.0.0/swagger/interface/SecuritySchemeObject.md) * [**ServerObject](/api/3.0.0/swagger/interface/ServerObject.md) * [**ServerVariableObject](/api/3.0.0/swagger/interface/ServerVariableObject.md) * [**SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md) * [**TagObject](/api/3.0.0/swagger/interface/TagObject.md) * [**Type](/api/3.0.0/swagger/interface/Type.md) * [**XmlObject](/api/3.0.0/swagger/interface/XmlObject.md) ### Type Aliases * [**ApiBodyOptions](/api/3.0.0/swagger.md#ApiBodyOptions) * [**ApiOperationOptions](/api/3.0.0/swagger.md#ApiOperationOptions) * [**ApiParamOptions](/api/3.0.0/swagger.md#ApiParamOptions) * [**ApiQueryOptions](/api/3.0.0/swagger.md#ApiQueryOptions) * [**ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions) * [**AuthType](/api/3.0.0/swagger.md#AuthType) * [**CallbackObject](/api/3.0.0/swagger.md#CallbackObject) * [**CallbacksObject](/api/3.0.0/swagger.md#CallbacksObject) * [**ContentObject](/api/3.0.0/swagger.md#ContentObject) * [**EncodingObject](/api/3.0.0/swagger.md#EncodingObject) * [**ExamplesObject](/api/3.0.0/swagger.md#ExamplesObject) * [**HeaderObject](/api/3.0.0/swagger.md#HeaderObject) * [**HeadersObject](/api/3.0.0/swagger.md#HeadersObject) * [**LinkParametersObject](/api/3.0.0/swagger.md#LinkParametersObject) * [**LinksObject](/api/3.0.0/swagger.md#LinksObject) * [**ParameterLocation](/api/3.0.0/swagger.md#ParameterLocation) * [**ParameterStyle](/api/3.0.0/swagger.md#ParameterStyle) * [**PathsObject](/api/3.0.0/swagger.md#PathsObject) * [**SchemasObject](/api/3.0.0/swagger.md#SchemasObject) * [**ScopesObject](/api/3.0.0/swagger.md#ScopesObject) * [**SecurityRequirementObject](/api/3.0.0/swagger.md#SecurityRequirementObject) * [**SecuritySchemeType](/api/3.0.0/swagger.md#SecuritySchemeType) * [**SwaggerEnumType](/api/3.0.0/swagger.md#SwaggerEnumType) ### Variables * [**DECORATORS](/api/3.0.0/swagger.md#DECORATORS) * [**DECORATORS\_CLASS\_METADATA](/api/3.0.0/swagger.md#DECORATORS_CLASS_METADATA) * [**DECORATORS\_METHOD\_METADATA](/api/3.0.0/swagger.md#DECORATORS_METHOD_METADATA) * [**DECORATORS\_PREFIX](/api/3.0.0/swagger.md#DECORATORS_PREFIX) ## Type Aliases[**](<#Type Aliases>) ### [**](#ApiBodyOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L41)ApiBodyOptions **ApiBodyOptions: ApiBodyMetadata | ApiBodySchemaHost ### [**](#ApiOperationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-operation.decorator.ts#L5)ApiOperationOptions **ApiOperationOptions: Partial<[OperationObject](/api/3.0.0/swagger/interface/OperationObject.md)> ### [**](#ApiParamOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-param.decorator.ts#L23)ApiParamOptions **ApiParamOptions: ApiParamMetadata | ApiParamSchemaHost ### [**](#ApiQueryOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-query.decorator.ts#L31)ApiQueryOptions **ApiQueryOptions: ApiQueryMetadata | ApiQuerySchemaHost ### [**](#ApiResponseOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L26)ApiResponseOptions **ApiResponseOptions: [ApiResponseMetadata](/api/3.0.0/swagger/interface/ApiResponseMetadata.md) | [ApiResponseSchemaHost](/api/3.0.0/swagger/interface/ApiResponseSchemaHost.md) ### [**](#AuthType)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L307)AuthType **AuthType: basic | bearer | cookie | oauth2 | apikey | custom ### [**](#CallbackObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L166)CallbackObject **CallbackObject: Record\ ### [**](#CallbacksObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L165)CallbacksObject **CallbacksObject: Record\ ### [**](#ContentObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L136)ContentObject **ContentObject: Record\ ### [**](#EncodingObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L144)EncodingObject **EncodingObject: Record\ ### [**](#ExamplesObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L194)ExamplesObject **ExamplesObject: Record\ ### [**](#HeaderObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L187)HeaderObject **HeaderObject: [BaseParameterObject](/api/3.0.0/swagger/interface/BaseParameterObject.md) ### [**](#HeadersObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L167)HeadersObject **HeadersObject: Record\ ### [**](#LinkParametersObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L186)LinkParametersObject **LinkParametersObject: Record\ ### [**](#LinksObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L176)LinksObject **LinksObject: Record\ ### [**](#ParameterLocation)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L101)ParameterLocation **ParameterLocation: query | header | path | cookie ### [**](#ParameterStyle)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L102)ParameterStyle **ParameterStyle: matrix | label | form | simple | spaceDelimited | pipeDelimited | deepObject ### [**](#PathsObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L64)PathsObject **PathsObject: Record\ ### [**](#SchemasObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L240)SchemasObject **SchemasObject: Record\ ### [**](#ScopesObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L282)ScopesObject **ScopesObject: Record\ ### [**](#SecurityRequirementObject)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L283)SecurityRequirementObject **SecurityRequirementObject: Record\ ### [**](#SecuritySchemeType)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L255)SecuritySchemeType **SecuritySchemeType: apiKey | http | oauth2 | openIdConnect ### [**](#SwaggerEnumType)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L288)SwaggerEnumType **SwaggerEnumType: string\[] | number\[] | (string | number)\[] | Record\ 非 open api spec ## Variables[**](#Variables) ### [**](#DECORATORS)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/constants.ts#L6)constDECORATORS **DECORATORS: { API\_EXCLUDE\_CONTROLLER: string; API\_EXCLUDE\_ENDPOINT: string; API\_EXCLUDE\_SECURITY: string; API\_EXTENSION: string; API\_EXTRA\_MODEL: string; API\_HEADERS: string; API\_MODEL\_PROPERTIES: string; API\_MODEL\_PROPERTIES\_ARRAY: string; API\_OPERATION: string; API\_PARAMETERS: string; API\_RESPONSE: string; API\_SECURITY: string; API\_TAGS: string } = ... ### [**](#DECORATORS_CLASS_METADATA)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/constants.ts#L3)constDECORATORS\_CLASS\_METADATA **DECORATORS\_CLASS\_METADATA: swagger:class\_metadata = 'swagger:class\_metadata' ### [**](#DECORATORS_METHOD_METADATA)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/constants.ts#L4)constDECORATORS\_METHOD\_METADATA **DECORATORS\_METHOD\_METADATA: swagger:method\_metadata = 'swagger:method\_metadata' ### [**](#DECORATORS_PREFIX)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/constants.ts#L1)constDECORATORS\_PREFIX **DECORATORS\_PREFIX: swagger = 'swagger' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SwaggerConfiguration](/api/3.0.0/swagger/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/configuration.ts#L22)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/configuration.ts#L25)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/configuration.ts#L27)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady --- # SwaggerExplorer ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addGlobalPrefix](#addGlobalPrefix) * [**getData](#getData) * [**getDocumentBuilder](#getDocumentBuilder) * [**getOperationId](#getOperationId) * [**init](#init) * [**scanApp](#scanApp) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SwaggerExplorer(): [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md) ## Methods[**](#Methods) ### [**](#addGlobalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L125)publicaddGlobalPrefix * **addGlobalPrefix(globalPrefix: string): void ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L156)publicgetData * **getData(): Omit<[OpenAPIObject](/api/3.0.0/swagger/interface/OpenAPIObject.md), paths> ### [**](#getDocumentBuilder)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L160)publicgetDocumentBuilder * **getDocumentBuilder(): DocumentBuilder ### [**](#getOperationId)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L722)getOperationId * **getOperationId(controllerKey: string, webRouter: [RouterOption](/api/3.0.0/decorator/interface/RouterOption.md)): string ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L57)init * **init(): Promise\ ### [**](#scanApp)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerExplorer.ts#L144)publicscanApp * **scanApp(): void --- # SwaggerMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**environmentService](#environmentService) ### Methods * [**init](#init) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SwaggerMiddleware(): [SwaggerMiddleware](/api/3.0.0/swagger/class/SwaggerMiddleware.md) ## Properties[**](#Properties) ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerMiddleware.ts#L34)environmentService **environmentService: MidwayEnvironmentService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerMiddleware.ts#L37)init * **init(): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerMiddleware.ts#L47)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/swaggerMiddleware.ts#L94)staticgetName * **getName(): string --- # BodyContentType ## Index[**](#Index) ### Enumeration Members * [**FormUrlEncoded](#FormUrlEncoded) * [**JSON](#JSON) * [**Multipart](#Multipart) * [**MultipartMixed](#MultipartMixed) * [**OctetStream](#OctetStream) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#FormUrlEncoded)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L21)FormUrlEncoded **FormUrlEncoded: application/x-www-form-urlencoded ### [**](#JSON)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L22)JSON **JSON: application/json ### [**](#Multipart)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L23)Multipart **Multipart: multipart/form-data ### [**](#MultipartMixed)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L24)MultipartMixed **MultipartMixed: multipart/mixed ### [**](#OctetStream)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-body.decorator.ts#L25)OctetStream **OctetStream: application/octet-stream --- # ApiAcceptedResponse ### Callable * **ApiAcceptedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiBadGatewayResponse ### Callable * **ApiBadGatewayResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiBadRequestResponse ### Callable * **ApiBadRequestResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiBasicAuth ### Callable * **ApiBasicAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiBearerAuth ### Callable * **ApiBearerAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiBody ### Callable * **ApiBody(options: [ApiBodyOptions](/api/3.0.0/swagger.md#ApiBodyOptions)): MethodDecorator --- # ApiConflictResponse ### Callable * **ApiConflictResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiCookieAuth ### Callable * **ApiCookieAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiCreatedResponse ### Callable * **ApiCreatedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiDefaultResponse ### Callable * **ApiDefaultResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiExcludeController ### Callable * **ApiExcludeController(disable? : boolean): ClassDecorator --- # ApiExcludeEndpoint ### Callable * **ApiExcludeEndpoint(disable? : boolean): MethodDecorator --- # ApiExcludeSecurity ### Callable * **ApiExcludeSecurity(): ClassDecorator & MethodDecorator --- # ApiExtension ### Callable * **ApiExtension(extensionKey: string, extensionProperties: any): ClassDecorator & MethodDecorator --- # ApiExtraModel ### Callable * **ApiExtraModel(models: [Type](/api/3.0.0/swagger/interface/Type.md)\ | [Type](/api/3.0.0/swagger/interface/Type.md)\\[]): ClassDecorator --- # ApiForbiddenResponse ### Callable * **ApiForbiddenResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiFoundResponse ### Callable * **ApiFoundResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiGatewayTimeoutResponse ### Callable * **ApiGatewayTimeoutResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiGoneResponse ### Callable * **ApiGoneResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiHeader ### Callable * **ApiHeader(options: [ApiHeaderOptions](/api/3.0.0/swagger/interface/ApiHeaderOptions.md)): any --- # ApiHeaders ### Callable * **ApiHeaders(headers: [ApiHeaderOptions](/api/3.0.0/swagger/interface/ApiHeaderOptions.md)\[]): MethodDecorator & ClassDecorator --- # ApiInternalServerErrorResponse ### Callable * **ApiInternalServerErrorResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiMethodNotAllowedResponse ### Callable * **ApiMethodNotAllowedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiMovedPermanentlyResponse ### Callable * **ApiMovedPermanentlyResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiNoContentResponse ### Callable * **ApiNoContentResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiNotAcceptableResponse ### Callable * **ApiNotAcceptableResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiNotFoundResponse ### Callable * **ApiNotFoundResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiNotImplementedResponse ### Callable * **ApiNotImplementedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiOAuth2 ### Callable * **ApiOAuth2(scopes: string\[], name? : string): ClassDecorator & MethodDecorator --- # ApiOkResponse ### Callable * **ApiOkResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiOperation ### Callable * **ApiOperation(options: Partial<[OperationObject](/api/3.0.0/swagger/interface/OperationObject.md)>): MethodDecorator --- # ApiParam ### Callable * **ApiParam(options: [ApiParamOptions](/api/3.0.0/swagger.md#ApiParamOptions)): MethodDecorator --- # ApiPayloadTooLargeResponse ### Callable * **ApiPayloadTooLargeResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiPreconditionFailedResponse ### Callable * **ApiPreconditionFailedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiProperty ### Callable * **ApiProperty(options? : [ApiPropertyOptions](/api/3.0.0/swagger/interface/ApiPropertyOptions.md)): PropertyDecorator --- # ApiPropertyOptional ### Callable * **ApiPropertyOptional(options? : [ApiPropertyOptions](/api/3.0.0/swagger/interface/ApiPropertyOptions.md)): PropertyDecorator --- # ApiQuery ### Callable * **ApiQuery(options: [ApiQueryOptions](/api/3.0.0/swagger.md#ApiQueryOptions)): MethodDecorator --- # ApiRequestTimeoutResponse ### Callable * **ApiRequestTimeoutResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiResponse ### Callable * **ApiResponse(options: [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiResponseProperty ### Callable * **ApiResponseProperty(options? : Pick<[ApiPropertyOptions](/api/3.0.0/swagger/interface/ApiPropertyOptions.md), type | enum | example | deprecated | format>): PropertyDecorator --- # ApiSecurity ### Callable * **ApiSecurity(name: string | [SecurityRequirementObject](/api/3.0.0/swagger.md#SecurityRequirementObject), requirements? : string\[]): ClassDecorator & MethodDecorator --- # ApiServiceUnavailableResponse ### Callable * **ApiServiceUnavailableResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiTags ### Callable * **ApiTags(tags: string | string\[]): ClassDecorator & MethodDecorator --- # ApiTooManyRequestsResponse ### Callable * **ApiTooManyRequestsResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiUnauthorizedResponse ### Callable * **ApiUnauthorizedResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiUnprocessableEntityResponse ### Callable * **ApiUnprocessableEntityResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # ApiUnsupportedMediaTypeResponse ### Callable * **ApiUnsupportedMediaTypeResponse(options? : [ApiResponseOptions](/api/3.0.0/swagger.md#ApiResponseOptions)): any --- # getSchemaPath ### Callable * **getSchemaPath(clzz: string | [Type](/api/3.0.0/swagger/interface/Type.md)\): string --- # renderJSON ### Callable * **renderJSON(swaggerConfig: [SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: Omit<[OpenAPIObject](/api/3.0.0/swagger/interface/OpenAPIObject.md), paths>; ext: string }> --- # renderSwaggerUIDist ### Callable * **renderSwaggerUIDist(swaggerConfig: [SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: any; ext: string }> --- # renderSwaggerUIRemote ### Callable * **renderSwaggerUIRemote(swaggerConfig: [SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: Omit<[OpenAPIObject](/api/3.0.0/swagger/interface/OpenAPIObject.md), paths>; ext: string } | { content: string; ext: string }> --- # ApiHeaderOptions ### Hierarchy * Omit<[ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md), in> * *ApiHeaderOptions* ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**enum](#enum) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**name](#name) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean Inherited from Omit.allowEmptyValue ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean Inherited from Omit.allowReserved ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) Inherited from Omit.content ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string Inherited from Omit.description ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-header.decorator.ts#L7)optionalenum **enum? : [SwaggerEnumType](/api/3.0.0/swagger.md#SwaggerEnumType) ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ Inherited from Omit.examples ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean Inherited from Omit.explode ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L126)name **name: string Inherited from Omit.name ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean Inherited from Omit.required ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.schema ### [**](#style)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/3.0.0/swagger.md#ParameterStyle) Inherited from Omit.style --- # ApiPropertyOptions ### Hierarchy * Omit<[SchemaObjectMetadata](/api/3.0.0/swagger/interface/SchemaObjectMetadata.md), name | enum> * *ApiPropertyOptions* ## Index[**](#Index) ### Properties * [**$ref](#$ref) * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**enumName](#enumName) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**isArray](#isArray) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**name](#name) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-property.decorator.ts#L11)optional$ref **$ref? : string ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L217)optionaladditionalProperties **additionalProperties? : boolean | [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.additionalProperties ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L211)optionalallOf **allOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.allOf ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L213)optionalanyOf **anyOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.anyOf ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L221)optionaldefault **default? : any Inherited from Omit.default ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L209)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L219)optionaldescription **description? : string Inherited from Omit.description ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L202)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/3.0.0/swagger/interface/DiscriminatorObject.md) Inherited from Omit.discriminator ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-property.decorator.ts#L9)optionalenum **enum? : any\[] | Record\ ### [**](#enumName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-property.decorator.ts#L10)optionalenumName **enumName? : string Overrides Omit.enumName ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L207)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L208)optionalexamples **examples? : any\[] | Record\ Inherited from Omit.examples ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L225)optionalexclusiveMaximum **exclusiveMaximum? : boolean Inherited from Omit.exclusiveMaximum ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMinimum **exclusiveMinimum? : boolean Inherited from Omit.exclusiveMinimum ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L206)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) Inherited from Omit.externalDocs ### [**](#format)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L220)optionalformat **format? : string Inherited from Omit.format ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L301)optionalisArray **isArray? : boolean Inherited from Omit.isArray ### [**](#items)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L215)optionalitems **items? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.items ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L231)optionalmaxItems **maxItems? : number Inherited from Omit.maxItems ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L228)optionalmaxLength **maxLength? : number Inherited from Omit.maxLength ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L234)optionalmaxProperties **maxProperties? : number Inherited from Omit.maxProperties ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L224)optionalmaximum **maximum? : number Inherited from Omit.maximum ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L232)optionalminItems **minItems? : number Inherited from Omit.minItems ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L229)optionalminLength **minLength? : number Inherited from Omit.minLength ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L235)optionalminProperties **minProperties? : number Inherited from Omit.minProperties ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L226)optionalminimum **minimum? : number Inherited from Omit.minimum ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L223)optionalmultipleOf **multipleOf? : number Inherited from Omit.multipleOf ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-property.decorator.ts#L8)optionalname **name? : string ### [**](#not)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L214)optionalnot **not? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.not ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L201)optionalnullable **nullable? : boolean Inherited from Omit.nullable ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L212)optionaloneOf **oneOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.oneOf ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L230)optionalpattern **pattern? : string Inherited from Omit.pattern ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L218)optionalpatternProperties **patternProperties? : any Inherited from Omit.patternProperties ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L216)optionalproperties **properties? : Record\ Inherited from Omit.properties ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L203)optionalreadOnly **readOnly? : boolean Inherited from Omit.readOnly ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L302)optionalrequired **required? : boolean Inherited from Omit.required ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L222)optionaltitle **title? : string Inherited from Omit.title ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L300)optionaltype **type? : string | Record\ | [Type](/api/3.0.0/swagger/interface/Type.md)\ | \[[Type](/api/3.0.0/swagger/interface/Type.md)\] Inherited from Omit.type ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L233)optionaluniqueItems **uniqueItems? : boolean Inherited from Omit.uniqueItems ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L204)optionalwriteOnly **writeOnly? : boolean Inherited from Omit.writeOnly ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L205)optionalxml **xml? : [XmlObject](/api/3.0.0/swagger/interface/XmlObject.md) Inherited from Omit.xml --- # ApiResponseMetadata ### Hierarchy * Omit<[ResponseObject](/api/3.0.0/swagger/interface/ResponseObject.md), description> * *ApiResponseMetadata* ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**isArray](#isArray) * [**links](#links) * [**status](#status) * [**type](#type) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L161)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) Inherited from Omit.content ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L16)optionaldescription **description? : string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L160)optionalheaders **headers? : [HeadersObject](/api/3.0.0/swagger.md#HeadersObject) Inherited from Omit.headers ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L15)optionalisArray **isArray? : boolean ### [**](#links)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L162)optionallinks **links? : [LinksObject](/api/3.0.0/swagger.md#LinksObject) Inherited from Omit.links ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L13)optionalstatus **status? : number | default ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L14)optionaltype **type? : string | Record\ | [Type](/api/3.0.0/swagger/interface/Type.md)\ --- # ApiResponseSchemaHost ### Hierarchy * Omit<[ResponseObject](/api/3.0.0/swagger/interface/ResponseObject.md), description> * *ApiResponseSchemaHost* ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**links](#links) * [**schema](#schema) * [**status](#status) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L161)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) Inherited from Omit.content ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L23)optionaldescription **description? : string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L160)optionalheaders **headers? : [HeadersObject](/api/3.0.0/swagger.md#HeadersObject) Inherited from Omit.headers ### [**](#links)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L162)optionallinks **links? : [LinksObject](/api/3.0.0/swagger.md#LinksObject) Inherited from Omit.links ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L21)schema **schema: [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) & Partial<[ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md)> ### [**](#status)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/decorators/api-response.decorator.ts#L22)optionalstatus **status? : number --- # AuthOptions 继承自 ### Hierarchy * Omit<[SecuritySchemeObject](/api/3.0.0/swagger/interface/SecuritySchemeObject.md), type> * *AuthOptions* ## Index[**](#Index) ### Properties * [**addSecurityRequirements](#addSecurityRequirements) * [**authType](#authType) * [**bearerFormat](#bearerFormat) * [**cookieName](#cookieName) * [**description](#description) * [**flows](#flows) * [**in](#in) * [**name](#name) * [**openIdConnectUrl](#openIdConnectUrl) * [**scheme](#scheme) * [**securityName](#securityName) * [**type](#type) ## Properties[**](#Properties) ### [**](#addSecurityRequirements)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L344)optionaladdSecurityRequirements **addSecurityRequirements? : boolean 添加全局默认要求 ### [**](#authType)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L328)authType **authType: [AuthType](/api/3.0.0/swagger.md#AuthType) 验权类型 basic => http basic 验证 bearer => http jwt 验证 cookie => cookie 方式验证 oauth2 => 使用 oauth2 apikey => apiKey custom => 自定义方式 ### [**](#bearerFormat)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L263)optionalbearerFormat **bearerFormat? : string Inherited from Omit.bearerFormat ### [**](#cookieName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L340)optionalcookieName **cookieName? : string authType = cookie 时可以修改,cookie 的名称 ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L259)optionaldescription **description? : string Inherited from Omit.description ### [**](#flows)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L264)optionalflows **flows? : [OAuthFlowsObject](/api/3.0.0/swagger/interface/OAuthFlowsObject.md) Inherited from Omit.flows ### [**](#in)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L261)optionalin **in? : string Inherited from Omit.in ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L260)optionalname **name? : string Inherited from Omit.name ### [**](#openIdConnectUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L265)optionalopenIdConnectUrl **openIdConnectUrl? : string Inherited from Omit.openIdConnectUrl ### [**](#scheme)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L262)optionalscheme **scheme? : string Inherited from Omit.scheme ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L336)optionalsecurityName **securityName? : string authType = cookie 时可以修改,通过 ApiCookie 装饰器关联的名称 ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L332)optionaltype **type? : [SecuritySchemeType](/api/3.0.0/swagger.md#SecuritySchemeType) type 字段 --- # BaseParameterObject ### Hierarchy * *BaseParameterObject* * [ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md) ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) ### [**](#style)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/3.0.0/swagger.md#ParameterStyle) --- # ComponentsObject ## Index[**](#Index) ### Properties * [**callbacks](#callbacks) * [**examples](#examples) * [**headers](#headers) * [**links](#links) * [**parameters](#parameters) * [**requestBodies](#requestBodies) * [**responses](#responses) * [**schemas](#schemas) * [**securitySchemes](#securitySchemes) ## Properties[**](#Properties) ### [**](#callbacks)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L61)optionalcallbacks **callbacks? : Record\ ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L56)optionalexamples **examples? : Record\ ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L58)optionalheaders **headers? : Record\ ### [**](#links)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L60)optionallinks **links? : Record\ ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L55)optionalparameters **parameters? : Record\ ### [**](#requestBodies)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L57)optionalrequestBodies **requestBodies? : Record\ ### [**](#responses)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L54)optionalresponses **responses? : Record\ ### [**](#schemas)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L53)optionalschemas **schemas? : Record\ ### [**](#securitySchemes)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L59)optionalsecuritySchemes **securitySchemes? : Record\ --- # ContactObject ## Index[**](#Index) ### Properties * [**email](#email) * [**name](#name) * [**url](#url) ## Properties[**](#Properties) ### [**](#email)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L32)optionalemail **email? : string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L30)optionalname **name? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L31)optionalurl **url? : string --- # DiscriminatorObject ## Index[**](#Index) ### Properties * [**mapping](#mapping) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#mapping)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L244)optionalmapping **mapping? : Record\ ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L243)propertyName **propertyName: string --- # EncodingPropertyObject ## Index[**](#Index) ### Properties * [**allowReserved](#allowReserved) * [**contentType](#contentType) * [**explode](#explode) * [**headers](#headers) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L150)optionalallowReserved **allowReserved? : boolean ### [**](#contentType)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L146)optionalcontentType **contentType? : string ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L149)optionalexplode **explode? : boolean ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L147)optionalheaders **headers? : Record\ ### [**](#style)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L148)optionalstyle **style? : string --- # ExampleObject ## Index[**](#Index) ### Properties * [**description](#description) * [**externalValue](#externalValue) * [**summary](#summary) * [**value](#value) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L171)optionaldescription **description? : string ### [**](#externalValue)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L173)optionalexternalValue **externalValue? : string ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L170)optionalsummary **summary? : string ### [**](#value)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L172)optionalvalue **value? : any --- # ExternalDocumentationObject ## Index[**](#Index) ### Properties * [**description](#description) * [**url](#url) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L97)optionaldescription **description? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L98)url **url: string --- # InfoObject ## Index[**](#Index) ### Properties * [**contact](#contact) * [**description](#description) * [**license](#license) * [**termsOfService](#termsOfService) * [**title](#title) * [**version](#version) ## Properties[**](#Properties) ### [**](#contact)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L24)optionalcontact **contact? : [ContactObject](/api/3.0.0/swagger/interface/ContactObject.md) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L22)optionaldescription **description? : string ### [**](#license)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L25)optionallicense **license? : [LicenseObject](/api/3.0.0/swagger/interface/LicenseObject.md) ### [**](#termsOfService)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L23)optionaltermsOfService **termsOfService? : string ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L21)title **title: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L26)version **version: string --- # LicenseObject ## Index[**](#Index) ### Properties * [**name](#name) * [**url](#url) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L36)name **name: string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L37)optionalurl **url? : string --- # LinkObject ## Index[**](#Index) ### Properties * [**description](#description) * [**operationId](#operationId) * [**operationRef](#operationRef) * [**parameters](#parameters) * [**requestBody](#requestBody) * [**server](#server) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L182)optionaldescription **description? : string ### [**](#operationId)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L179)optionaloperationId **operationId? : string ### [**](#operationRef)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L178)optionaloperationRef **operationRef? : string ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L180)optionalparameters **parameters? : [LinkParametersObject](/api/3.0.0/swagger.md#LinkParametersObject) ### [**](#requestBody)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L181)optionalrequestBody **requestBody? : any ### [**](#server)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L183)optionalserver **server? : [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md) --- # MediaTypeObject ## Index[**](#Index) ### Properties * [**encoding](#encoding) * [**example](#example) * [**examples](#examples) * [**schema](#schema) ## Properties[**](#Properties) ### [**](#encoding)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L141)optionalencoding **encoding? : [EncodingObject](/api/3.0.0/swagger.md#EncodingObject) ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L140)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L139)optionalexamples **examples? : [ExamplesObject](/api/3.0.0/swagger.md#ExamplesObject) ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L138)optionalschema **schema? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) --- # MixDecoratorMetadata ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L451)key **key: string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L452)metadata **metadata: any ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L453)optionalpropertyName **propertyName? : string --- # OAuthFlowObject ## Index[**](#Index) ### Properties * [**authorizationUrl](#authorizationUrl) * [**refreshUrl](#refreshUrl) * [**scopes](#scopes) * [**tokenUrl](#tokenUrl) ## Properties[**](#Properties) ### [**](#authorizationUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L276)optionalauthorizationUrl **authorizationUrl? : string ### [**](#refreshUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L278)optionalrefreshUrl **refreshUrl? : string ### [**](#scopes)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L279)scopes **scopes: [ScopesObject](/api/3.0.0/swagger.md#ScopesObject) ### [**](#tokenUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L277)optionaltokenUrl **tokenUrl? : string --- # OAuthFlowsObject ## Index[**](#Index) ### Properties * [**authorizationCode](#authorizationCode) * [**clientCredentials](#clientCredentials) * [**implicit](#implicit) * [**password](#password) ## Properties[**](#Properties) ### [**](#authorizationCode)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L272)optionalauthorizationCode **authorizationCode? : [OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) ### [**](#clientCredentials)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L271)optionalclientCredentials **clientCredentials? : [OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) ### [**](#implicit)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L269)optionalimplicit **implicit? : [OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) ### [**](#password)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L270)optionalpassword **password? : [OAuthFlowObject](/api/3.0.0/swagger/interface/OAuthFlowObject.md) --- # OpenAPIObject ## Index[**](#Index) ### Properties * [**components](#components) * [**externalDocs](#externalDocs) * [**info](#info) * [**openapi](#openapi) * [**paths](#paths) * [**security](#security) * [**servers](#servers) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#components)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L14)optionalcomponents **components? : [ComponentsObject](/api/3.0.0/swagger/interface/ComponentsObject.md) ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L17)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L11)info **info: [InfoObject](/api/3.0.0/swagger/interface/InfoObject.md) ### [**](#openapi)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L10)openapi **openapi: string ### [**](#paths)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L13)paths **paths: [PathsObject](/api/3.0.0/swagger.md#PathsObject) ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L15)optionalsecurity **security? : [SecurityRequirementObject](/api/3.0.0/swagger.md#SecurityRequirementObject)\[] ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L12)optionalservers **servers? : [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md)\[] ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L16)optionaltags **tags? : [TagObject](/api/3.0.0/swagger/interface/TagObject.md)\[] --- # OperationObject ## Index[**](#Index) ### Properties * [**callbacks](#callbacks) * [**deprecated](#deprecated) * [**description](#description) * [**externalDocs](#externalDocs) * [**operationId](#operationId) * [**parameters](#parameters) * [**requestBody](#requestBody) * [**responses](#responses) * [**security](#security) * [**servers](#servers) * [**summary](#summary) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#callbacks)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L90)optionalcallbacks **callbacks? : [CallbacksObject](/api/3.0.0/swagger.md#CallbacksObject) ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L91)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L84)optionaldescription **description? : string ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L85)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) ### [**](#operationId)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L86)optionaloperationId **operationId? : string ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L87)optionalparameters **parameters? : ([ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) | [ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md))\[] ### [**](#requestBody)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L88)optionalrequestBody **requestBody? : [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) | [RequestBodyObject](/api/3.0.0/swagger/interface/RequestBodyObject.md) ### [**](#responses)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L89)responses **responses: [ResponsesObject](/api/3.0.0/swagger/interface/ResponsesObject.md) ### [**](#security)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L92)optionalsecurity **security? : [SecurityRequirementObject](/api/3.0.0/swagger.md#SecurityRequirementObject)\[] ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L93)optionalservers **servers? : [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md)\[] ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L83)optionalsummary **summary? : string ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L82)optionaltags **tags? : string\[] --- # ParameterObject ### Hierarchy * [BaseParameterObject](/api/3.0.0/swagger/interface/BaseParameterObject.md) * *ParameterObject* ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**in](#in) * [**name](#name) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean Inherited from BaseParameterObject.allowEmptyValue ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean Inherited from BaseParameterObject.allowReserved ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) Inherited from BaseParameterObject.content ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean Inherited from BaseParameterObject.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string Inherited from BaseParameterObject.description ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any Inherited from BaseParameterObject.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ Inherited from BaseParameterObject.examples ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean Inherited from BaseParameterObject.explode ### [**](#in)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L127)in **in: [ParameterLocation](/api/3.0.0/swagger.md#ParameterLocation) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L126)name **name: string ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean Inherited from BaseParameterObject.required ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from BaseParameterObject.schema ### [**](#style)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/3.0.0/swagger.md#ParameterStyle) Inherited from BaseParameterObject.style --- # PathItemObject ## Index[**](#Index) ### Properties * [**$ref](#$ref) * [**delete](#delete) * [**description](#description) * [**get](#get) * [**head](#head) * [**options](#options) * [**parameters](#parameters) * [**patch](#patch) * [**post](#post) * [**put](#put) * [**servers](#servers) * [**summary](#summary) * [**trace](#trace) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L66)optional$ref **$ref? : string ### [**](#delete)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L72)optionaldelete **delete? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L68)optionaldescription **description? : string ### [**](#get)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L69)optionalget **get? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#head)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L74)optionalhead **head? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L73)optionaloptions **options? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L78)optionalparameters **parameters? : ([ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) | [ParameterObject](/api/3.0.0/swagger/interface/ParameterObject.md))\[] ### [**](#patch)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L75)optionalpatch **patch? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#post)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L71)optionalpost **post? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#put)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L70)optionalput **put? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L77)optionalservers **servers? : [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md)\[] ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L67)optionalsummary **summary? : string ### [**](#trace)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L76)optionaltrace **trace? : [OperationObject](/api/3.0.0/swagger/interface/OperationObject.md) --- # ReferenceObject ## Index[**](#Index) ### Properties * [**$ref](#$ref) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L197)$ref **$ref: string | () => string --- # RequestBodyObject ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**required](#required) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L132)content **content: [ContentObject](/api/3.0.0/swagger.md#ContentObject) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L131)optionaldescription **description? : string ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L133)optionalrequired **required? : boolean --- # ResponseObject ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**links](#links) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L161)optionalcontent **content? : [ContentObject](/api/3.0.0/swagger.md#ContentObject) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L159)description **description: string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L160)optionalheaders **headers? : [HeadersObject](/api/3.0.0/swagger.md#HeadersObject) ### [**](#links)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L162)optionallinks **links? : [LinksObject](/api/3.0.0/swagger.md#LinksObject) --- # ResponsesObject ### Hierarchy * Record\ * *ResponsesObject* ## Index[**](#Index) ### Properties * [**default](#default) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L155)optionaldefault **default? : [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) | [ResponseObject](/api/3.0.0/swagger/interface/ResponseObject.md) --- # SchemaObject ## Index[**](#Index) ### Properties * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L217)optionaladditionalProperties **additionalProperties? : boolean | [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L211)optionalallOf **allOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L213)optionalanyOf **anyOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L221)optionaldefault **default? : any ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L209)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L219)optionaldescription **description? : string ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L202)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/3.0.0/swagger/interface/DiscriminatorObject.md) ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L237)optionalenum **enum? : any\[] ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L207)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L208)optionalexamples **examples? : any\[] | Record\ ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L225)optionalexclusiveMaximum **exclusiveMaximum? : boolean ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMinimum **exclusiveMinimum? : boolean ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L206)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) ### [**](#format)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L220)optionalformat **format? : string ### [**](#items)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L215)optionalitems **items? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L231)optionalmaxItems **maxItems? : number ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L228)optionalmaxLength **maxLength? : number ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L234)optionalmaxProperties **maxProperties? : number ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L224)optionalmaximum **maximum? : number ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L232)optionalminItems **minItems? : number ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L229)optionalminLength **minLength? : number ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L235)optionalminProperties **minProperties? : number ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L226)optionalminimum **minimum? : number ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L223)optionalmultipleOf **multipleOf? : number ### [**](#not)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L214)optionalnot **not? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L201)optionalnullable **nullable? : boolean ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L212)optionaloneOf **oneOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L230)optionalpattern **pattern? : string ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L218)optionalpatternProperties **patternProperties? : any ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L216)optionalproperties **properties? : Record\ ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L203)optionalreadOnly **readOnly? : boolean ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L236)optionalrequired **required? : string\[] ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L222)optionaltitle **title? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L210)optionaltype **type? : string | new (...args: any\[]) => any | () => new (...args: any\[]) => any ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L233)optionaluniqueItems **uniqueItems? : boolean ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L204)optionalwriteOnly **writeOnly? : boolean ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L205)optionalxml **xml? : [XmlObject](/api/3.0.0/swagger/interface/XmlObject.md) --- # SchemaObjectMetadata ### Hierarchy * Omit<[SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md), type | required> * *SchemaObjectMetadata* ## Index[**](#Index) ### Properties * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**enumName](#enumName) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**isArray](#isArray) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**name](#name) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L217)optionaladditionalProperties **additionalProperties? : boolean | [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.additionalProperties ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L211)optionalallOf **allOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.allOf ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L213)optionalanyOf **anyOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.anyOf ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L221)optionaldefault **default? : any Inherited from Omit.default ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L209)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L219)optionaldescription **description? : string Inherited from Omit.description ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L202)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/3.0.0/swagger/interface/DiscriminatorObject.md) Inherited from Omit.discriminator ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L237)optionalenum **enum? : any\[] Inherited from Omit.enum ### [**](#enumName)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L304)optionalenumName **enumName? : string ### [**](#example)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L207)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L208)optionalexamples **examples? : any\[] | Record\ Inherited from Omit.examples ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L225)optionalexclusiveMaximum **exclusiveMaximum? : boolean Inherited from Omit.exclusiveMaximum ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMinimum **exclusiveMinimum? : boolean Inherited from Omit.exclusiveMinimum ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L206)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) Inherited from Omit.externalDocs ### [**](#format)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L220)optionalformat **format? : string Inherited from Omit.format ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L301)optionalisArray **isArray? : boolean ### [**](#items)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L215)optionalitems **items? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.items ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L231)optionalmaxItems **maxItems? : number Inherited from Omit.maxItems ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L228)optionalmaxLength **maxLength? : number Inherited from Omit.maxLength ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L234)optionalmaxProperties **maxProperties? : number Inherited from Omit.maxProperties ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L224)optionalmaximum **maximum? : number Inherited from Omit.maximum ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L232)optionalminItems **minItems? : number Inherited from Omit.minItems ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L229)optionalminLength **minLength? : number Inherited from Omit.minLength ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L235)optionalminProperties **minProperties? : number Inherited from Omit.minProperties ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L226)optionalminimum **minimum? : number Inherited from Omit.minimum ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L223)optionalmultipleOf **multipleOf? : number Inherited from Omit.multipleOf ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L303)optionalname **name? : string ### [**](#not)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L214)optionalnot **not? : [SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md) Inherited from Omit.not ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L201)optionalnullable **nullable? : boolean Inherited from Omit.nullable ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L212)optionaloneOf **oneOf? : ([SchemaObject](/api/3.0.0/swagger/interface/SchemaObject.md) | [ReferenceObject](/api/3.0.0/swagger/interface/ReferenceObject.md))\[] Inherited from Omit.oneOf ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L230)optionalpattern **pattern? : string Inherited from Omit.pattern ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L218)optionalpatternProperties **patternProperties? : any Inherited from Omit.patternProperties ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L216)optionalproperties **properties? : Record\ Inherited from Omit.properties ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L203)optionalreadOnly **readOnly? : boolean Inherited from Omit.readOnly ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L302)optionalrequired **required? : boolean ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L222)optionaltitle **title? : string Inherited from Omit.title ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L300)optionaltype **type? : string | Record\ | [Type](/api/3.0.0/swagger/interface/Type.md)\ | \[[Type](/api/3.0.0/swagger/interface/Type.md)\] ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L233)optionaluniqueItems **uniqueItems? : boolean Inherited from Omit.uniqueItems ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L204)optionalwriteOnly **writeOnly? : boolean Inherited from Omit.writeOnly ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L205)optionalxml **xml? : [XmlObject](/api/3.0.0/swagger/interface/XmlObject.md) Inherited from Omit.xml --- # SecuritySchemeObject ## Index[**](#Index) ### Properties * [**bearerFormat](#bearerFormat) * [**description](#description) * [**flows](#flows) * [**in](#in) * [**name](#name) * [**openIdConnectUrl](#openIdConnectUrl) * [**scheme](#scheme) * [**type](#type) ## Properties[**](#Properties) ### [**](#bearerFormat)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L263)optionalbearerFormat **bearerFormat? : string ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L259)optionaldescription **description? : string ### [**](#flows)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L264)optionalflows **flows? : [OAuthFlowsObject](/api/3.0.0/swagger/interface/OAuthFlowsObject.md) ### [**](#in)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L261)optionalin **in? : string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L260)optionalname **name? : string ### [**](#openIdConnectUrl)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L265)optionalopenIdConnectUrl **openIdConnectUrl? : string ### [**](#scheme)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L262)optionalscheme **scheme? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L258)type **type: [SecuritySchemeType](/api/3.0.0/swagger.md#SecuritySchemeType) --- # ServerObject ## Index[**](#Index) ### Properties * [**description](#description) * [**url](#url) * [**variables](#variables) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L42)optionaldescription **description? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L41)url **url: string ### [**](#variables)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L43)optionalvariables **variables? : Record\ --- # ServerVariableObject ## Index[**](#Index) ### Properties * [**default](#default) * [**description](#description) * [**enum](#enum) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L48)default **default: string | number | boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L49)optionaldescription **description? : string ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L47)optionalenum **enum? : string\[] | number\[] | boolean\[] --- # SwaggerOptions see ## Index[**](#Index) ### Properties * [**auth](#auth) * [**contact](#contact) * [**description](#description) * [**displayOptions](#displayOptions) * [**documentOptions](#documentOptions) * [**externalDocs](#externalDocs) * [**isGenerateTagForController](#isGenerateTagForController) * [**license](#license) * [**routerFilter](#routerFilter) * [**servers](#servers) * [**swaggerPath](#swaggerPath) * [**swaggerUIRender](#swaggerUIRender) * [**swaggerUIRenderOptions](#swaggerUIRenderOptions) * [**tagSortable](#tagSortable) * [**tags](#tags) * [**termsOfService](#termsOfService) * [**title](#title) * [**version](#version) ## Properties[**](#Properties) ### [**](#auth)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L392)optionalauth **auth? : [AuthOptions](/api/3.0.0/swagger/interface/AuthOptions.md) | [AuthOptions](/api/3.0.0/swagger/interface/AuthOptions.md)\[] 可以参考 ### [**](#contact)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L368)optionalcontact **contact? : [ContactObject](/api/3.0.0/swagger/interface/ContactObject.md) contact 字段 ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L359)optionaldescription **description? : string 默认值: This is a swagger-ui for midwayjs project description 字段 ### [**](#displayOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L407)optionaldisplayOptions **displayOptions? : { deepLinking? : boolean; defaultModelExpandDepth? : number; defaultModelRendering? : example | model; defaultModelsExpandDepth? : number; displayOperationId? : boolean; displayRequestDuration? : boolean; docExpansion? : list | none | full; filter? : string | boolean; maxDisplayedTags? : number; showCommonExtensions? : boolean; showExtensions? : boolean; tryItOutEnabled? : boolean; useUnsafeMarkdown? : boolean } UI 展示中需要用到的配置 可以参考 ### [**](#documentOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L422)optionaldocumentOptions **documentOptions? : { operationIdFactory? : (controllerKey: string, webRouter: [RouterOption](/api/3.0.0/decorator/interface/RouterOption.md)) => string } ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L380)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) externalDocs 字段 ### [**](#isGenerateTagForController)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L447)optionalisGenerateTagForController **isGenerateTagForController? : boolean Weather to generate the Tag for controller ### [**](#license)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L372)optionallicense **license? : [LicenseObject](/api/3.0.0/swagger/interface/LicenseObject.md) license 字段 ### [**](#routerFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L443)optionalrouterFilter **routerFilter? : (url: string, options: [RouterOption](/api/3.0.0/decorator/interface/RouterOption.md)) => boolean ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L384)optionalservers **servers? : [ServerObject](/api/3.0.0/swagger/interface/ServerObject.md)\[] servers 字段 ### [**](#swaggerPath)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L397)optionalswaggerPath **swaggerPath? : string 默认值: /swagger-ui 访问 swagger ui 的路径 ### [**](#swaggerUIRender)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L433)optionalswaggerUIRender **swaggerUIRender? : (config: [SwaggerOptions](/api/3.0.0/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/3.0.0/swagger/class/SwaggerExplorer.md)) => (pathname: string) => Promise<{ content: any; ext: string }> ### [**](#swaggerUIRenderOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L438)optionalswaggerUIRenderOptions **swaggerUIRenderOptions? : Record\ ### [**](#tagSortable)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L402)optionaltagSortable **tagSortable? : boolean 对路由 tag 进行 ascii 排序 可以使用 1-xxx、2-xxx、3-xxx 来定义 tag ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L388)optionaltags **tags? : [TagObject](/api/3.0.0/swagger/interface/TagObject.md)\[] tags 字段 ### [**](#termsOfService)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L376)optionaltermsOfService **termsOfService? : string termsOfService 字段 ### [**](#title)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L354)optionaltitle **title? : string 默认值: My Project title 字段 ### [**](#version)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L364)optionalversion **version? : string 默认值: 1.0.0 version 字段 --- # TagObject ## Index[**](#Index) ### Properties * [**description](#description) * [**externalDocs](#externalDocs) * [**name](#name) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L190)optionaldescription **description? : string ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L191)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/3.0.0/swagger/interface/ExternalDocumentationObject.md) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L189)name **name: string --- # Type \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L294)constructor * **new Type(...args: any\[]): T --- # XmlObject ## Index[**](#Index) ### Properties * [**attribute](#attribute) * [**name](#name) * [**namespace](#namespace) * [**prefix](#prefix) * [**wrapped](#wrapped) ## Properties[**](#Properties) ### [**](#attribute)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L251)optionalattribute **attribute? : boolean ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L248)optionalname **name? : string ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L249)optionalnamespace **namespace? : string ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L250)optionalprefix **prefix? : string ### [**](#wrapped)[**](https://github.com/midwayjs/midway/blob/main/packages/swagger/src/interfaces/index.ts#L252)optionalwrapped **wrapped? : boolean --- # @midwayjs/tablestore ## Index[**](#Index) ### Classes * [**CompositeCondition](/api/3.0.0/tablestore/class/CompositeCondition.md) * [**Condition](/api/3.0.0/tablestore/class/Condition.md) * [**Configuration](/api/3.0.0/tablestore/class/Configuration.md) * [**SingleColumnCondition](/api/3.0.0/tablestore/class/SingleColumnCondition.md) * [**TableStoreService](/api/3.0.0/tablestore/class/TableStoreService.md) * [**TableStoreServiceFactory](/api/3.0.0/tablestore/class/TableStoreServiceFactory.md) ### Enumerations * [**ColumnConditionType](/api/3.0.0/tablestore/enum/ColumnConditionType.md) * [**ColumnReturnType](/api/3.0.0/tablestore/enum/ColumnReturnType.md) * [**ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md) * [**DefinedColumnType](/api/3.0.0/tablestore/enum/DefinedColumnType.md) * [**Direction](/api/3.0.0/tablestore/enum/Direction.md) * [**FieldType](/api/3.0.0/tablestore/enum/FieldType.md) * [**FilterType](/api/3.0.0/tablestore/enum/FilterType.md) * [**GeoDistanceType](/api/3.0.0/tablestore/enum/GeoDistanceType.md) * [**IndexOptions](/api/3.0.0/tablestore/enum/IndexOptions.md) * [**IndexType](/api/3.0.0/tablestore/enum/IndexType.md) * [**IndexUpdateMode](/api/3.0.0/tablestore/enum/IndexUpdateMode.md) * [**LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md) * [**PrimaryKeyOption](/api/3.0.0/tablestore/enum/PrimaryKeyOption.md) * [**PrimaryKeyType](/api/3.0.0/tablestore/enum/PrimaryKeyType.md) * [**QueryOperator](/api/3.0.0/tablestore/enum/QueryOperator.md) * [**QueryType](/api/3.0.0/tablestore/enum/QueryType.md) * [**ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) * [**RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md) * [**ScoreMode](/api/3.0.0/tablestore/enum/ScoreMode.md) * [**SortMode](/api/3.0.0/tablestore/enum/SortMode.md) * [**SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md) * [**UpdateType](/api/3.0.0/tablestore/enum/UpdateType.md) ### Functions * [**formatRow](/api/3.0.0/tablestore/function/formatRow.md) * [**formatRows](/api/3.0.0/tablestore/function/formatRows.md) ### Interfaces * [**BatchGetRowParams](/api/3.0.0/tablestore/interface/BatchGetRowParams.md) * [**BatchWriteRowParams](/api/3.0.0/tablestore/interface/BatchWriteRowParams.md) * [**ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) * [**CreateIndexParams](/api/3.0.0/tablestore/interface/CreateIndexParams.md) * [**CreateSearchIndexParams](/api/3.0.0/tablestore/interface/CreateSearchIndexParams.md) * [**CreateTableParams](/api/3.0.0/tablestore/interface/CreateTableParams.md) * [**DeleteRowParams](/api/3.0.0/tablestore/interface/DeleteRowParams.md) * [**DeleteSearchIndexParams](/api/3.0.0/tablestore/interface/DeleteSearchIndexParams.md) * [**DeleteTableParams](/api/3.0.0/tablestore/interface/DeleteTableParams.md) * [**DescribeSearchIndexParams](/api/3.0.0/tablestore/interface/DescribeSearchIndexParams.md) * [**DescribeTableParams](/api/3.0.0/tablestore/interface/DescribeTableParams.md) * [**DropIndexParams](/api/3.0.0/tablestore/interface/DropIndexParams.md) * [**GetRangeParams](/api/3.0.0/tablestore/interface/GetRangeParams.md) * [**GetRowParams](/api/3.0.0/tablestore/interface/GetRowParams.md) * [**ListSearchIndexParams](/api/3.0.0/tablestore/interface/ListSearchIndexParams.md) * [**PutRowParams](/api/3.0.0/tablestore/interface/PutRowParams.md) * [**SearchIndexFieldSchema](/api/3.0.0/tablestore/interface/SearchIndexFieldSchema.md) * [**SearchIndexNestedFilter](/api/3.0.0/tablestore/interface/SearchIndexNestedFilter.md) * [**SearchIndexSchema](/api/3.0.0/tablestore/interface/SearchIndexSchema.md) * [**SearchIndexSetting](/api/3.0.0/tablestore/interface/SearchIndexSetting.md) * [**SearchIndexSorter](/api/3.0.0/tablestore/interface/SearchIndexSorter.md) * [**SearchParams](/api/3.0.0/tablestore/interface/SearchParams.md) * [**SearchQuery](/api/3.0.0/tablestore/interface/SearchQuery.md) * [**StartLocalTransactionParams](/api/3.0.0/tablestore/interface/StartLocalTransactionParams.md) * [**TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md) * [**TableStoreCompositeCondition](/api/3.0.0/tablestore/interface/TableStoreCompositeCondition.md) * [**TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) * [**TableStoreConfig](/api/3.0.0/tablestore/interface/TableStoreConfig.md) * [**TableStoreLong](/api/3.0.0/tablestore/interface/TableStoreLong.md) * [**TableStoreResult](/api/3.0.0/tablestore/interface/TableStoreResult.md) * [**TableStoreSingleColumnCondition](/api/3.0.0/tablestore/interface/TableStoreSingleColumnCondition.md) * [**UpdateRowParams](/api/3.0.0/tablestore/interface/UpdateRowParams.md) * [**UpdateTableParams](/api/3.0.0/tablestore/interface/UpdateTableParams.md) ### Type Aliases * [**AbortTransactionParams](/api/3.0.0/tablestore.md#AbortTransactionParams) * [**AttributeColumn](/api/3.0.0/tablestore.md#AttributeColumn) * [**BatchWriteRowItem](/api/3.0.0/tablestore.md#BatchWriteRowItem) * [**ColumnValue](/api/3.0.0/tablestore.md#ColumnValue) * [**CommitTransactionParams](/api/3.0.0/tablestore.md#CommitTransactionParams) * [**ExtraMetadata](/api/3.0.0/tablestore.md#ExtraMetadata) * [**ListTableParams](/api/3.0.0/tablestore.md#ListTableParams) * [**PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey) * [**PrimaryKeyValue](/api/3.0.0/tablestore.md#PrimaryKeyValue) * [**SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery) * [**UpdateColumn](/api/3.0.0/tablestore.md#UpdateColumn) ### Variables * [**INF\_MAX](/api/3.0.0/tablestore.md#INF_MAX) * [**INF\_MIN](/api/3.0.0/tablestore.md#INF_MIN) * [**Long](/api/3.0.0/tablestore.md#Long) * [**PK\_AUTO\_INCR](/api/3.0.0/tablestore.md#PK_AUTO_INCR) ## Type Aliases[**](<#Type Aliases>) ### [**](#AbortTransactionParams)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L591)AbortTransactionParams **AbortTransactionParams: string | { transactionId: string } ### [**](#AttributeColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L236)AttributeColumn **AttributeColumn: { timestamp? : number } ### [**](#BatchWriteRowItem)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L317)BatchWriteRowItem **BatchWriteRowItem: ({ attributeColumns? : [AttributeColumn](/api/3.0.0/tablestore.md#AttributeColumn)\[]; type: PUT | DELETE } | { type: UPDATE; updateOfAttributeColumns: [UpdateColumn](/api/3.0.0/tablestore.md#UpdateColumn)\[] }) & { condition? : [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) | null; primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[]; returnContent? : { returnColumns? : string\[]; returnType? : [ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) } } ### [**](#ColumnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L10)ColumnValue **ColumnValue: number | boolean | [PrimaryKeyValue](/api/3.0.0/tablestore.md#PrimaryKeyValue) ### [**](#CommitTransactionParams)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L590)CommitTransactionParams **CommitTransactionParams: string | { transactionId: string } ### [**](#ExtraMetadata)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L8)ExtraMetadata **ExtraMetadata: typeof [INF\_MIN](/api/3.0.0/tablestore.md#INF_MIN) & typeof [INF\_MAX](/api/3.0.0/tablestore.md#INF_MAX) & typeof [PK\_AUTO\_INCR](/api/3.0.0/tablestore.md#PK_AUTO_INCR) protocol/proto\_buffer ### [**](#ListTableParams)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L196)ListTableParams **ListTableParams: undefined | null | {} ### [**](#PrimaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L11)PrimaryKey **PrimaryKey: {} ### [**](#PrimaryKeyValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L9)PrimaryKeyValue **PrimaryKeyValue: Int64LE | string | Buffer ### [**](#SearchIndexQuery)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L374)SearchIndexQuery **SearchIndexQuery: { query? : { fieldName: string; minimumShouldMatch? : number; operator? : [QueryOperator](/api/3.0.0/tablestore/enum/QueryOperator.md); text? : string }; queryType? : QueryType.MATCH\_QUERY } | { query? : { fieldName: string; text? : string }; queryType? : QueryType.MATCH\_PHRASE\_QUERY } | { query? : { fieldName: string; term: [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue) }; queryType? : QueryType.TERM\_QUERY } | { query? : { fieldName: string; includeLower? : boolean; includeUpper? : boolean; rangeFrom? : [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue); rangeTo? : [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue) }; queryType? : QueryType.RANGE\_QUERY } | { query? : { fieldName: string; prefix? : string }; queryType? : QueryType.PREFIX\_QUERY } | { query? : { filterQueries? : [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery)\[]; minimumShouldMatch? : number; mustNotQueries? : [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery)\[]; mustQueries? : [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery)\[]; shouldQueries? : [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery)\[] }; queryType? : QueryType.BOOL\_QUERY } | { query? : { filter: [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery) }; queryType? : QueryType.CONST\_SCORE\_QUERY } | { query? : { fieldValueFactor: { fieldName: string }; query: [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery) }; queryType? : QueryType.FUNCTION\_SCORE\_QUERY } | { query? : { path: string; query: [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery); scoreMode? : [ScoreMode](/api/3.0.0/tablestore/enum/ScoreMode.md) }; type? : QueryType.NESTED\_QUERY } | { query? : { fieldName: string; value? : string }; queryType? : QueryType.WILDCARD\_QUERY } | { query? : {}; queryType? : QueryType.MATCH\_ALL\_QUERY } | { query? : { bottomRight? : string; fieldName: string; topLeft? : string }; queryType? : QueryType.GEO\_BOUNDING\_BOX\_QUERY } | { query? : { centerPoint? : string; distance? : number; fieldName: string }; queryType? : QueryType.GEO\_DISTANCE\_QUERY } | { query? : { fieldName: string; points? : string\[] }; queryType? : QueryType.GEO\_POLYGON\_QUERY } | { query? : { fieldName: string; terms? : [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue)\[] }; queryType? : QueryType.TERMS\_QUERY } | { query? : { fieldName: string }; queryType? : QueryType.EXISTS\_QUERY } ### [**](#UpdateColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L241)UpdateColumn **UpdateColumn: { \[ key in UpdateType.DELETE\_ALL ]?: string\[] } & { \[ key in Exclude<[UpdateType](/api/3.0.0/tablestore/enum/UpdateType.md), UpdateType.DELETE\_ALL> ]?: [AttributeColumn](/api/3.0.0/tablestore.md#AttributeColumn)\[] } ## Variables[**](#Variables) ### [**](#INF_MAX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L70)constINF\_MAX **INF\_MAX: any = TableStore.INF\_MAX ### [**](#INF_MIN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L69)constINF\_MIN **INF\_MIN: any = TableStore.INF\_MIN ### [**](#Long)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/proxy.ts#L62)constLong **Long: [TableStoreLong](/api/3.0.0/tablestore/interface/TableStoreLong.md) = ... ### [**](#PK_AUTO_INCR)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L71)constPK\_AUTO\_INCR **PK\_AUTO\_INCR: any = TableStore.PK\_AUTO\_INCR --- # CompositeCondition ### Hierarchy * unknown * [TableStoreCompositeCondition](/api/3.0.0/tablestore/interface/TableStoreCompositeCondition.md) * *CompositeCondition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**sub\_conditions](#sub_conditions) ### Methods * [**addSubCondition](#addSubCondition) * [**clearSubCondition](#clearSubCondition) * [**getCombinator](#getCombinator) * [**getType](#getType) * [**setCombinator](#setCombinator) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/proxy.ts#L14)constructor * **new CompositeCondition(combinator: [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md)): [CompositeCondition](/api/3.0.0/tablestore/class/CompositeCondition.md) - Overrides TableStore.CompositeCondition.constructor ## Properties[**](#Properties) ### [**](#sub_conditions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L745)sub\_conditions **sub\_conditions: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)\[] Inherited from TableStoreCompositeCondition.sub\_conditions ## Methods[**](#Methods) ### [**](#addSubCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L753)addSubCondition * **addSubCondition(condition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)): void - Inherited from TableStoreCompositeCondition.addSubCondition ### [**](#clearSubCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L755)clearSubCondition * **clearSubCondition(): void - Inherited from TableStoreCompositeCondition.clearSubCondition ### [**](#getCombinator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L751)getCombinator * **getCombinator(): [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md) - Inherited from TableStoreCompositeCondition.getCombinator ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L747)getType * **getType(): FT\_COMPOSITE\_COLUMN\_VALUE - Inherited from TableStoreCompositeCondition.getType ### [**](#setCombinator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L749)setCombinator * **setCombinator(combinator: [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md)): void - Inherited from TableStoreCompositeCondition.setCombinator --- # Condition ### Hierarchy * unknown * [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) * *Condition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**columnCondition](#columnCondition) * [**rowExistenceExpectation](#rowExistenceExpectation) ### Methods * [**getColumnCondition](#getColumnCondition) * [**getRowExistenceExpectation](#getRowExistenceExpectation) * [**setColumnCondition](#setColumnCondition) * [**setRowExistenceExpectation](#setRowExistenceExpectation) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/proxy.ts#L25)constructor * **new Condition(rowExistenceExpectation: [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md), columnCondition? : [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)): [Condition](/api/3.0.0/tablestore/class/Condition.md) - Overrides TableStore.Condition.constructor ## Properties[**](#Properties) ### [**](#columnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L759)columnCondition **columnCondition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) Inherited from TableStoreCondition.columnCondition ### [**](#rowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L760)rowExistenceExpectation **rowExistenceExpectation: [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md) Inherited from TableStoreCondition.rowExistenceExpectation ## Methods[**](#Methods) ### [**](#getColumnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L768)getColumnCondition * **getColumnCondition(): [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) - Inherited from TableStoreCondition.getColumnCondition ### [**](#getRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L764)getRowExistenceExpectation * **getRowExistenceExpectation(): [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md) - Inherited from TableStoreCondition.getRowExistenceExpectation ### [**](#setColumnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L766)setColumnCondition * **setColumnCondition(columnCondition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)): void - Inherited from TableStoreCondition.setColumnCondition ### [**](#setRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L762)setRowExistenceExpectation * **setRowExistenceExpectation(rowExistenceExpectation: [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md)): void - Inherited from TableStoreCondition.setRowExistenceExpectation --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TableStoreConfiguration](/api/3.0.0/tablestore/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/configuration.ts#L8)onReady * **onReady(container: any): Promise\ --- # SingleColumnCondition \ ### Hierarchy * unknown * [TableStoreSingleColumnCondition](/api/3.0.0/tablestore/interface/TableStoreSingleColumnCondition.md) * *SingleColumnCondition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**columnName](#columnName) * [**columnValue](#columnValue) * [**comparator](#comparator) * [**latestVersionOnly](#latestVersionOnly) * [**passIfMissing](#passIfMissing) ### Methods * [**getColumnName](#getColumnName) * [**getColumnValue](#getColumnValue) * [**getLatestVersionOnly](#getLatestVersionOnly) * [**getPassIfMissing](#getPassIfMissing) * [**getType](#getType) * [**setColumnName](#setColumnName) * [**setColumnValue](#setColumnValue) * [**setComparator](#setComparator) * [**setLatestVersionOnly](#setLatestVersionOnly) * [**setPassIfMissing](#setPassIfMissing) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/proxy.ts#L39)constructor * **new SingleColumnCondition\(columnName: string, columnValue: T, comparator: [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md), passIfMissing? : boolean, latestVersionOnly? : boolean): [SingleColumnCondition](/api/3.0.0/tablestore/class/SingleColumnCondition.md)\ - Overrides TableStore.SingleColumnCondition.constructor #### Type parameters * **T** ## Properties[**](#Properties) ### [**](#columnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L784)columnName **columnName: string Inherited from TableStoreSingleColumnCondition.columnName ### [**](#columnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L785)columnValue **columnValue: [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue) Inherited from TableStoreSingleColumnCondition.columnValue ### [**](#comparator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L786)comparator **comparator: [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md) Inherited from TableStoreSingleColumnCondition.comparator ### [**](#latestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L788)latestVersionOnly **latestVersionOnly: boolean Inherited from TableStoreSingleColumnCondition.latestVersionOnly ### [**](#passIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L787)passIfMissing **passIfMissing: boolean Inherited from TableStoreSingleColumnCondition.passIfMissing ## Methods[**](#Methods) ### [**](#getColumnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L810)getColumnName * **getColumnName(): string - Inherited from TableStoreSingleColumnCondition.getColumnName ### [**](#getColumnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L814)getColumnValue * **getColumnValue(): [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue) - Inherited from TableStoreSingleColumnCondition.getColumnValue ### [**](#getLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L806)getLatestVersionOnly * **getLatestVersionOnly(): boolean - Inherited from TableStoreSingleColumnCondition.getLatestVersionOnly ### [**](#getPassIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L802)getPassIfMissing * **getPassIfMissing(): boolean - Inherited from TableStoreSingleColumnCondition.getPassIfMissing ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L790)getType * **getType(): FT\_SINGLE\_COLUMN\_VALUE - Inherited from TableStoreSingleColumnCondition.getType ### [**](#setColumnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L808)setColumnName * **setColumnName(columnName: string): void - Inherited from TableStoreSingleColumnCondition.setColumnName ### [**](#setColumnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L812)setColumnValue * **setColumnValue(columnValue: [ColumnValue](/api/3.0.0/tablestore.md#ColumnValue)): void - Inherited from TableStoreSingleColumnCondition.setColumnValue ### [**](#setComparator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L816)setComparator * **setComparator(comparator: [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md)): void - Inherited from TableStoreSingleColumnCondition.setComparator ### [**](#setLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L804)setLatestVersionOnly * **setLatestVersionOnly(latestVersionOnly: boolean): void - Inherited from TableStoreSingleColumnCondition.setLatestVersionOnly ### [**](#setPassIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L800)setPassIfMissing * **setPassIfMissing(passIfMissing: boolean): void - Inherited from TableStoreSingleColumnCondition.setPassIfMissing 设置 `passIfMissing` 由于OTS一行的属性列不固定,有可能存在有condition条件的列在该行不存在的情况,这时 参数控制在这种情况下对该行的检查结果。 如果设置为True,则若列在该行中不存在,则检查条件通过。 如果设置为False,则若列在该行中不存在,则检查条件失败。 默认值为True。 --- # TableStoreService ### Hierarchy * [TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md) * *TableStoreService* ### Implements * [TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**abortTransaction](#abortTransaction) * [**batchGetRow](#batchGetRow) * [**batchWriteRow](#batchWriteRow) * [**commitTransaction](#commitTransaction) * [**createIndex](#createIndex) * [**createSearchIndex](#createSearchIndex) * [**createTable](#createTable) * [**deleteRow](#deleteRow) * [**deleteSearchIndex](#deleteSearchIndex) * [**deleteTable](#deleteTable) * [**describeSearchIndex](#describeSearchIndex) * [**describeTable](#describeTable) * [**dropIndex](#dropIndex) * [**getRange](#getRange) * [**getRow](#getRow) * [**init](#init) * [**listSearchIndex](#listSearchIndex) * [**listTable](#listTable) * [**putRow](#putRow) * [**search](#search) * [**startLocalTransaction](#startLocalTransaction) * [**updateRow](#updateRow) * [**updateTable](#updateTable) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TableStoreService(): [TableStoreService](/api/3.0.0/tablestore/class/TableStoreService.md) ## Methods[**](#Methods) ### [**](#abortTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L715)abortTransaction * **abortTransaction\(params: [AbortTransactionParams](/api/3.0.0/tablestore.md#AbortTransactionParams)): Promise\ - Implementation of TableStoreClient.abortTransaction Inherited from TableStoreClient.abortTransaction 丢弃事务 *** #### Type parameters * **R** = any ### [**](#batchGetRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L660)batchGetRow * **batchGetRow\(params: [BatchGetRowParams](/api/3.0.0/tablestore/interface/BatchGetRowParams.md)): Promise\ - Implementation of TableStoreClient.batchGetRow Inherited from TableStoreClient.batchGetRow 批量读取一个或多个表中的若干行数据。 *** #### Type parameters * **R** = any ### [**](#batchWriteRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L665)batchWriteRow * **batchWriteRow\(params: [BatchWriteRowParams](/api/3.0.0/tablestore/interface/BatchWriteRowParams.md)): Promise\ - Implementation of TableStoreClient.batchWriteRow Inherited from TableStoreClient.batchWriteRow 批量修改行 *** #### Type parameters * **R** = any ### [**](#commitTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L710)commitTransaction * **commitTransaction\(params: [CommitTransactionParams](/api/3.0.0/tablestore.md#CommitTransactionParams)): Promise\ - Implementation of TableStoreClient.commitTransaction Inherited from TableStoreClient.commitTransaction 提交事务 *** #### Type parameters * **R** = any ### [**](#createIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L695)createIndex * **createIndex\(params: [CreateIndexParams](/api/3.0.0/tablestore/interface/CreateIndexParams.md)): Promise\ - Implementation of TableStoreClient.createIndex Inherited from TableStoreClient.createIndex 创建GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#createSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L680)createSearchIndex * **createSearchIndex\(params: [CreateSearchIndexParams](/api/3.0.0/tablestore/interface/CreateSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.createSearchIndex Inherited from TableStoreClient.createSearchIndex SearchIndex创建新索引。 *** #### Type parameters * **R** = any ### [**](#createTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L607)createTable * **createTable\(params: [CreateTableParams](/api/3.0.0/tablestore/interface/CreateTableParams.md)): Promise\ - Implementation of TableStoreClient.createTable Inherited from TableStoreClient.createTable 根据给定的表结构信息创建相应的表。 *** #### Type parameters * **R** = any ### [**](#deleteRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L650)deleteRow * **deleteRow\(params: [DeleteRowParams](/api/3.0.0/tablestore/interface/DeleteRowParams.md)): Promise\ - Implementation of TableStoreClient.deleteRow Inherited from TableStoreClient.deleteRow 删除一行数据。 *** #### Type parameters * **R** = any ### [**](#deleteSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L685)deleteSearchIndex * **deleteSearchIndex\(params: [DeleteSearchIndexParams](/api/3.0.0/tablestore/interface/DeleteSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.deleteSearchIndex Inherited from TableStoreClient.deleteSearchIndex SearchIndex删除索引。 *** #### Type parameters * **R** = any ### [**](#deleteTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L617)deleteTable * **deleteTable\(params: [DeleteTableParams](/api/3.0.0/tablestore/interface/DeleteTableParams.md)): Promise\ - Implementation of TableStoreClient.deleteTable Inherited from TableStoreClient.deleteTable 删除本实例下指定的表。 *** #### Type parameters * **R** = any ### [**](#describeSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L675)describeSearchIndex * **describeSearchIndex\(params: [DescribeSearchIndexParams](/api/3.0.0/tablestore/interface/DescribeSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.describeSearchIndex Inherited from TableStoreClient.describeSearchIndex 获取SearchIndex索引描述信息。 *** #### Type parameters * **R** = any ### [**](#describeTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L627)describeTable * **describeTable\(params: [DescribeTableParams](/api/3.0.0/tablestore/interface/DescribeTableParams.md)): Promise\ - Implementation of TableStoreClient.describeTable Inherited from TableStoreClient.describeTable 查询指定表的结构信息和预留读/写吞吐量设置信息。 *** #### Type parameters * **R** = any ### [**](#dropIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L700)dropIndex * **dropIndex\(params: [DropIndexParams](/api/3.0.0/tablestore/interface/DropIndexParams.md)): Promise\ - Implementation of TableStoreClient.dropIndex Inherited from TableStoreClient.dropIndex 删除GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#getRange)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L655)getRange * **getRange\(params: [GetRangeParams](/api/3.0.0/tablestore/interface/GetRangeParams.md)): Promise\ - Implementation of TableStoreClient.getRange Inherited from TableStoreClient.getRange 读取指定主键范围内的数据。 *** #### Type parameters * **R** = any ### [**](#getRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L635)getRow * **getRow\(params: [GetRowParams](/api/3.0.0/tablestore/interface/GetRowParams.md)): Promise\ - Implementation of TableStoreClient.getRow Inherited from TableStoreClient.getRow 根据给定的主键读取单行数据。 *** #### Type parameters * **R** = any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/manager.ts#L44)init * **init(): Promise\ ### [**](#listSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L670)listSearchIndex * **listSearchIndex\(params: [ListSearchIndexParams](/api/3.0.0/tablestore/interface/ListSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.listSearchIndex Inherited from TableStoreClient.listSearchIndex 获取表下所有SearchIndex索引名。 *** #### Type parameters * **R** = any ### [**](#listTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L612)listTable * **listTable\(params: {}): Promise\ - Implementation of TableStoreClient.listTable Inherited from TableStoreClient.listTable 获取当前实例下已创建的所有表的表名。 *** #### Type parameters * **R** = any ### [**](#putRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L640)putRow * **putRow\(params: [PutRowParams](/api/3.0.0/tablestore/interface/PutRowParams.md)): Promise\ - Implementation of TableStoreClient.putRow Inherited from TableStoreClient.putRow 插入数据到指定的行,如果该行不存在,则新增一行;若该行存在,则覆盖原有行。 *** #### Type parameters * **R** = any ### [**](#search)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L690)search * **search\(params: [SearchParams](/api/3.0.0/tablestore/interface/SearchParams.md)): Promise\ - Implementation of TableStoreClient.search Inherited from TableStoreClient.search SearchIndex搜索。 *** #### Type parameters * **R** = any ### [**](#startLocalTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L705)startLocalTransaction * **startLocalTransaction\(params: [StartLocalTransactionParams](/api/3.0.0/tablestore/interface/StartLocalTransactionParams.md)): Promise\ - Implementation of TableStoreClient.startLocalTransaction Inherited from TableStoreClient.startLocalTransaction 创建局部事务 *** #### Type parameters * **R** = any ### [**](#updateRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L645)updateRow * **updateRow\(params: [UpdateRowParams](/api/3.0.0/tablestore/interface/UpdateRowParams.md)): Promise\ - Implementation of TableStoreClient.updateRow Inherited from TableStoreClient.updateRow 更新指定行的数据。如果该行不存在,则新增一行;若该行存在,则根据请求的内容在这一行中新增、修改或者删除指定列的值。 *** #### Type parameters * **R** = any ### [**](#updateTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L622)updateTable * **updateTable\(params: [UpdateTableParams](/api/3.0.0/tablestore/interface/UpdateTableParams.md)): Promise\ - Implementation of TableStoreClient.updateTable Inherited from TableStoreClient.updateTable 更新指定表的预留读吞吐量或预留写吞吐量设置。 *** #### Type parameters * **R** = any --- # TableStoreServiceFactory ### Hierarchy * ServiceFactory<[TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md)> * *TableStoreServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**tableStoreConfig](#tableStoreConfig) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TableStoreServiceFactory(): [TableStoreServiceFactory](/api/3.0.0/tablestore/class/TableStoreServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#tableStoreConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/manager.ts#L19)tableStoreConfig **tableStoreConfig: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/manager.ts#L26)createClient * **createClient(config: any): Promise<[TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md)> - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise<[TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md)> - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [TableStoreClient](/api/3.0.0/tablestore/interface/TableStoreClient.md) ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/manager.ts#L30)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/manager.ts#L22)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # ColumnConditionType ## Index[**](#Index) ### Enumeration Members * [**COMPOSITE\_COLUMN\_CONDITION](#COMPOSITE_COLUMN_CONDITION) * [**SINGLE\_COLUMN\_CONDITION](#SINGLE_COLUMN_CONDITION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#COMPOSITE_COLUMN_CONDITION)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L731)COMPOSITE\_COLUMN\_CONDITION **COMPOSITE\_COLUMN\_CONDITION: 0 ### [**](#SINGLE_COLUMN_CONDITION)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L732)SINGLE\_COLUMN\_CONDITION **SINGLE\_COLUMN\_CONDITION: 1 --- # ColumnReturnType ## Index[**](#Index) ### Enumeration Members * [**RETURN\_ALL](#RETURN_ALL) * [**RETURN\_NONE](#RETURN_NONE) * [**RETURN\_SPECIFIED](#RETURN_SPECIFIED) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#RETURN_ALL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L126)RETURN\_ALL **RETURN\_ALL: 1 ### [**](#RETURN_NONE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L128)RETURN\_NONE **RETURN\_NONE: 3 ### [**](#RETURN_SPECIFIED)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L127)RETURN\_SPECIFIED **RETURN\_SPECIFIED: 2 --- # ComparatorType ## Index[**](#Index) ### Enumeration Members * [**EQUAL](#EQUAL) * [**GREATER\_EQUAL](#GREATER_EQUAL) * [**GREATER\_THAN](#GREATER_THAN) * [**LESS\_EQUAL](#LESS_EQUAL) * [**LESS\_THAN](#LESS_THAN) * [**NOT\_EQUAL](#NOT_EQUAL) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#EQUAL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L736)EQUAL **EQUAL: 1 ### [**](#GREATER_EQUAL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L739)GREATER\_EQUAL **GREATER\_EQUAL: 4 ### [**](#GREATER_THAN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L738)GREATER\_THAN **GREATER\_THAN: 3 ### [**](#LESS_EQUAL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L741)LESS\_EQUAL **LESS\_EQUAL: 6 ### [**](#LESS_THAN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L740)LESS\_THAN **LESS\_THAN: 5 ### [**](#NOT_EQUAL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L737)NOT\_EQUAL **NOT\_EQUAL: 2 --- # DefinedColumnType ## Index[**](#Index) ### Enumeration Members * [**DCT\_BOOLEAN](#DCT_BOOLEAN) * [**DCT\_DOUBLE](#DCT_DOUBLE) * [**DCT\_INTEGER](#DCT_INTEGER) * [**DCT\_STRING](#DCT_STRING) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DCT_BOOLEAN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L45)DCT\_BOOLEAN **DCT\_BOOLEAN: 3 ### [**](#DCT_DOUBLE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L44)DCT\_DOUBLE **DCT\_DOUBLE: 2 ### [**](#DCT_INTEGER)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L43)DCT\_INTEGER **DCT\_INTEGER: 1 ### [**](#DCT_STRING)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L46)DCT\_STRING **DCT\_STRING: 4 --- # Direction ## Index[**](#Index) ### Enumeration Members * [**BACKWARD](#BACKWARD) * [**FORWARD](#FORWARD) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BACKWARD)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L26)BACKWARD **BACKWARD: BACKWARD ### [**](#FORWARD)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L25)FORWARD **FORWARD: FORWARD --- # FieldType ## Index[**](#Index) ### Enumeration Members * [**BOOLEAN](#BOOLEAN) * [**DOUBLE](#DOUBLE) * [**GEO\_POINT](#GEO_POINT) * [**KEYWORD](#KEYWORD) * [**LONG](#LONG) * [**NESTED](#NESTED) * [**TEXT](#TEXT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BOOLEAN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L118)BOOLEAN **BOOLEAN: 3 ### [**](#DOUBLE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L117)DOUBLE **DOUBLE: 2 ### [**](#GEO_POINT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L122)GEO\_POINT **GEO\_POINT: 7 ### [**](#KEYWORD)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L119)KEYWORD **KEYWORD: 4 ### [**](#LONG)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L116)LONG **LONG: 1 ### [**](#NESTED)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L121)NESTED **NESTED: 6 ### [**](#TEXT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L120)TEXT **TEXT: 5 --- # FilterType ## Index[**](#Index) ### Enumeration Members * [**FT\_COLUMN\_PAGINATION](#FT_COLUMN_PAGINATION) * [**FT\_COMPOSITE\_COLUMN\_VALUE](#FT_COMPOSITE_COLUMN_VALUE) * [**FT\_SINGLE\_COLUMN\_VALUE](#FT_SINGLE_COLUMN_VALUE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#FT_COLUMN_PAGINATION)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L721)FT\_COLUMN\_PAGINATION **FT\_COLUMN\_PAGINATION: 3 ### [**](#FT_COMPOSITE_COLUMN_VALUE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L720)FT\_COMPOSITE\_COLUMN\_VALUE **FT\_COMPOSITE\_COLUMN\_VALUE: 2 ### [**](#FT_SINGLE_COLUMN_VALUE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L719)FT\_SINGLE\_COLUMN\_VALUE **FT\_SINGLE\_COLUMN\_VALUE: 1 --- # GeoDistanceType ## Index[**](#Index) ### Enumeration Members * [**GEO\_DISTANCE\_ARC](#GEO_DISTANCE_ARC) * [**GEO\_DISTANCE\_PLANE](#GEO_DISTANCE_PLANE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#GEO_DISTANCE_ARC)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L132)GEO\_DISTANCE\_ARC **GEO\_DISTANCE\_ARC: 0 ### [**](#GEO_DISTANCE_PLANE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L133)GEO\_DISTANCE\_PLANE **GEO\_DISTANCE\_PLANE: 1 --- # IndexOptions ## Index[**](#Index) ### Enumeration Members * [**DOCS](#DOCS) * [**FREQS](#FREQS) * [**OFFSETS](#OFFSETS) * [**POSITIONS](#POSITIONS) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DOCS)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L137)DOCS **DOCS: 1 ### [**](#FREQS)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L138)FREQS **FREQS: 2 ### [**](#OFFSETS)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L140)OFFSETS **OFFSETS: 4 ### [**](#POSITIONS)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L139)POSITIONS **POSITIONS: 3 --- # IndexType ## Index[**](#Index) ### Enumeration Members * [**IT\_GLOBAL\_INDEX](#IT_GLOBAL_INDEX) * [**IT\_LOCAL\_INDEX](#IT_LOCAL_INDEX) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#IT_GLOBAL_INDEX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L65)IT\_GLOBAL\_INDEX **IT\_GLOBAL\_INDEX: 0 ### [**](#IT_LOCAL_INDEX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L66)IT\_LOCAL\_INDEX **IT\_LOCAL\_INDEX: 1 --- # IndexUpdateMode ## Index[**](#Index) ### Enumeration Members * [**IUM\_ASYNC\_INDEX](#IUM_ASYNC_INDEX) * [**IUM\_SYNC\_INDEX](#IUM_SYNC_INDEX) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#IUM_ASYNC_INDEX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L60)IUM\_ASYNC\_INDEX **IUM\_ASYNC\_INDEX: 0 ### [**](#IUM_SYNC_INDEX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L61)IUM\_SYNC\_INDEX **IUM\_SYNC\_INDEX: 1 --- # LogicalOperator ## Index[**](#Index) ### Enumeration Members * [**AND](#AND) * [**NOT](#NOT) * [**OR](#OR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AND)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L726)AND **AND: 2 ### [**](#NOT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L725)NOT **NOT: 1 ### [**](#OR)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L727)OR **OR: 3 --- # PrimaryKeyOption ## Index[**](#Index) ### Enumeration Members * [**AUTO\_INCREMENT](#AUTO_INCREMENT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AUTO_INCREMENT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L56)AUTO\_INCREMENT **AUTO\_INCREMENT: 1 --- # PrimaryKeyType ## Index[**](#Index) ### Enumeration Members * [**BINARY](#BINARY) * [**INTEGER](#INTEGER) * [**STRING](#STRING) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BINARY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L52)BINARY **BINARY: 3 ### [**](#INTEGER)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L50)INTEGER **INTEGER: 1 ### [**](#STRING)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L51)STRING **STRING: 2 --- # QueryOperator ## Index[**](#Index) ### Enumeration Members * [**AND](#AND) * [**OR](#OR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AND)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L145)AND **AND: 2 ### [**](#OR)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L144)OR **OR: 1 --- # QueryType search ## Index[**](#Index) ### Enumeration Members * [**BOOL\_QUERY](#BOOL_QUERY) * [**CONST\_SCORE\_QUERY](#CONST_SCORE_QUERY) * [**EXISTS\_QUERY](#EXISTS_QUERY) * [**FUNCTION\_SCORE\_QUERY](#FUNCTION_SCORE_QUERY) * [**GEO\_BOUNDING\_BOX\_QUERY](#GEO_BOUNDING_BOX_QUERY) * [**GEO\_DISTANCE\_QUERY](#GEO_DISTANCE_QUERY) * [**GEO\_POLYGON\_QUERY](#GEO_POLYGON_QUERY) * [**MATCH\_ALL\_QUERY](#MATCH_ALL_QUERY) * [**MATCH\_PHRASE\_QUERY](#MATCH_PHRASE_QUERY) * [**MATCH\_QUERY](#MATCH_QUERY) * [**NESTED\_QUERY](#NESTED_QUERY) * [**PREFIX\_QUERY](#PREFIX_QUERY) * [**RANGE\_QUERY](#RANGE_QUERY) * [**TERMS\_QUERY](#TERMS_QUERY) * [**TERM\_QUERY](#TERM_QUERY) * [**WILDCARD\_QUERY](#WILDCARD_QUERY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BOOL_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L83)BOOL\_QUERY **BOOL\_QUERY: 6 ### [**](#CONST_SCORE_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L84)CONST\_SCORE\_QUERY **CONST\_SCORE\_QUERY: 7 ### [**](#EXISTS_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L93)EXISTS\_QUERY **EXISTS\_QUERY: 16 ### [**](#FUNCTION_SCORE_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L85)FUNCTION\_SCORE\_QUERY **FUNCTION\_SCORE\_QUERY: 8 ### [**](#GEO_BOUNDING_BOX_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L89)GEO\_BOUNDING\_BOX\_QUERY **GEO\_BOUNDING\_BOX\_QUERY: 12 ### [**](#GEO_DISTANCE_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L90)GEO\_DISTANCE\_QUERY **GEO\_DISTANCE\_QUERY: 13 ### [**](#GEO_POLYGON_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L91)GEO\_POLYGON\_QUERY **GEO\_POLYGON\_QUERY: 14 ### [**](#MATCH_ALL_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L88)MATCH\_ALL\_QUERY **MATCH\_ALL\_QUERY: 11 ### [**](#MATCH_PHRASE_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L79)MATCH\_PHRASE\_QUERY **MATCH\_PHRASE\_QUERY: 2 ### [**](#MATCH_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L78)MATCH\_QUERY **MATCH\_QUERY: 1 ### [**](#NESTED_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L86)NESTED\_QUERY **NESTED\_QUERY: 9 ### [**](#PREFIX_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L82)PREFIX\_QUERY **PREFIX\_QUERY: 5 ### [**](#RANGE_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L81)RANGE\_QUERY **RANGE\_QUERY: 4 ### [**](#TERMS_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L92)TERMS\_QUERY **TERMS\_QUERY: 15 ### [**](#TERM_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L80)TERM\_QUERY **TERM\_QUERY: 3 ### [**](#WILDCARD_QUERY)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L87)WILDCARD\_QUERY **WILDCARD\_QUERY: 10 --- # ReturnType ## Index[**](#Index) ### Enumeration Members * [**AfterModify](#AfterModify) * [**NONE](#NONE) * [**Primarykey](#Primarykey) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AfterModify)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L39)AfterModify **AfterModify: 2 ### [**](#NONE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L37)NONE **NONE: 0 ### [**](#Primarykey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L38)Primarykey **Primarykey: 1 --- # RowExistenceExpectation metadata ## Index[**](#Index) ### Enumeration Members * [**EXPECT\_EXIST](#EXPECT_EXIST) * [**EXPECT\_NOT\_EXIST](#EXPECT_NOT_EXIST) * [**IGNORE](#IGNORE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#EXPECT_EXIST)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L20)EXPECT\_EXIST **EXPECT\_EXIST: 1 ### [**](#EXPECT_NOT_EXIST)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L21)EXPECT\_NOT\_EXIST **EXPECT\_NOT\_EXIST: 2 ### [**](#IGNORE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L19)IGNORE **IGNORE: 0 --- # ScoreMode ## Index[**](#Index) ### Enumeration Members * [**SCORE\_MODE\_AVG](#SCORE_MODE_AVG) * [**SCORE\_MODE\_MAX](#SCORE_MODE_MAX) * [**SCORE\_MODE\_MIN](#SCORE_MODE_MIN) * [**SCORE\_MODE\_NONE](#SCORE_MODE_NONE) * [**SCORE\_MODE\_TOTAL](#SCORE_MODE_TOTAL) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SCORE_MODE_AVG)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L98)SCORE\_MODE\_AVG **SCORE\_MODE\_AVG: 2 ### [**](#SCORE_MODE_MAX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L99)SCORE\_MODE\_MAX **SCORE\_MODE\_MAX: 3 ### [**](#SCORE_MODE_MIN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L101)SCORE\_MODE\_MIN **SCORE\_MODE\_MIN: 5 ### [**](#SCORE_MODE_NONE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L97)SCORE\_MODE\_NONE **SCORE\_MODE\_NONE: 1 ### [**](#SCORE_MODE_TOTAL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L100)SCORE\_MODE\_TOTAL **SCORE\_MODE\_TOTAL: 4 --- # SortMode ## Index[**](#Index) ### Enumeration Members * [**SORT\_MODE\_AVG](#SORT_MODE_AVG) * [**SORT\_MODE\_MAX](#SORT_MODE_MAX) * [**SORT\_MODE\_MIN](#SORT_MODE_MIN) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SORT_MODE_AVG)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L112)SORT\_MODE\_AVG **SORT\_MODE\_AVG: 2 ### [**](#SORT_MODE_MAX)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L111)SORT\_MODE\_MAX **SORT\_MODE\_MAX: 1 ### [**](#SORT_MODE_MIN)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L110)SORT\_MODE\_MIN **SORT\_MODE\_MIN: 0 --- # SortOrder ## Index[**](#Index) ### Enumeration Members * [**SORT\_ORDER\_ASC](#SORT_ORDER_ASC) * [**SORT\_ORDER\_DESC](#SORT_ORDER_DESC) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SORT_ORDER_ASC)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L105)SORT\_ORDER\_ASC **SORT\_ORDER\_ASC: 0 ### [**](#SORT_ORDER_DESC)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L106)SORT\_ORDER\_DESC **SORT\_ORDER\_DESC: 1 --- # UpdateType ## Index[**](#Index) ### Enumeration Members * [**DELETE](#DELETE) * [**DELETE\_ALL](#DELETE_ALL) * [**INCREMENT](#INCREMENT) * [**PUT](#PUT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DELETE)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L31)DELETE **DELETE: DELETE ### [**](#DELETE_ALL)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L32)DELETE\_ALL **DELETE\_ALL: DELETE\_ALL ### [**](#INCREMENT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L33)INCREMENT **INCREMENT: INCREMENT ### [**](#PUT)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L30)PUT **PUT: PUT --- # formatRow ### Callable * **formatRow(row: any, filterColumn: any): {} --- # formatRows ### Callable * **formatRows(result: any, filterColumn: any): { list: any\[]; next: any } --- # BatchGetRowParams ## Index[**](#Index) ### Properties * [**tables](#tables) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#tables)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L300)tables **tables: { columnFilter? : [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md); columnsToGet? : string\[]; endColumn? : string; maxVersions? : number; primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[]\[]; startColumn? : string; tableName: string; timeRange? : { endTime? : string; specificTime? : string; startTime? : string } }\[] ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L314)optionaltransactionId **transactionId? : string --- # BatchWriteRowParams ## Index[**](#Index) ### Properties * [**tables](#tables) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#tables)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L335)tables **tables: { rows: [BatchWriteRowItem](/api/3.0.0/tablestore.md#BatchWriteRowItem)\[]; tableName: string }\[] ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L339)optionaltransactionId **transactionId? : string --- # ColumnCondition ### Hierarchy * *ColumnCondition* * [TableStoreSingleColumnCondition](/api/3.0.0/tablestore/interface/TableStoreSingleColumnCondition.md) --- # CreateIndexParams ## Index[**](#Index) ### Properties * [**indexMeta](#indexMeta) * [**mainTableName](#mainTableName) ## Properties[**](#Properties) ### [**](#indexMeta)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L570)indexMeta **indexMeta: { definedColumn: string\[]; includeBaseData? : boolean; indexType? : [IndexType](/api/3.0.0/tablestore/enum/IndexType.md); indexUpdateMode? : [IndexUpdateMode](/api/3.0.0/tablestore/enum/IndexUpdateMode.md); name: string; primaryKey: string\[] } ### [**](#mainTableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L569)mainTableName **mainTableName: string --- # CreateSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**schema](#schema) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L536)indexName **indexName: string ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L537)schema **schema: [SearchIndexSchema](/api/3.0.0/tablestore/interface/SearchIndexSchema.md) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L535)tableName **tableName: string --- # CreateTableParams params ## Index[**](#Index) ### Properties * [**indexMetas](#indexMetas) * [**reservedThroughput](#reservedThroughput) * [**streamSpecification](#streamSpecification) * [**tableMeta](#tableMeta) * [**tableOptions](#tableOptions) ## Properties[**](#Properties) ### [**](#indexMetas)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L189)optionalindexMetas **indexMetas? : { definedColumn: string\[]; name: string; primaryKey: string\[] }\[] ### [**](#reservedThroughput)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L165)reservedThroughput **reservedThroughput: { capacityUnit: { read: number; write: number } } ### [**](#streamSpecification)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L182)optionalstreamSpecification **streamSpecification? : { enableStream? : boolean; expirationTime? : number } ### [**](#tableMeta)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L153)tableMeta **tableMeta: { definedColumn? : { name: string; type: [DefinedColumnType](/api/3.0.0/tablestore/enum/DefinedColumnType.md) }\[]; primaryKey: { name: string; option? : AUTO\_INCREMENT; type: [PrimaryKeyType](/api/3.0.0/tablestore/enum/PrimaryKeyType.md) }\[]; tableName: string } ### [**](#tableOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L171)optionaltableOptions **tableOptions? : { maxTimeDeviation? : number; maxVersions? : number; timeToLive? : number } --- # DeleteRowParams ## Index[**](#Index) ### Properties * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L273)optionalcondition **condition? : [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L272)primaryKey **primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L274)optionalreturnContent **returnContent? : { returnType? : [ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L271)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L277)optionaltransactionId **transactionId? : string --- # DeleteSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L542)indexName **indexName: string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L541)tableName **tableName: string --- # DeleteTableParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L199)tableName **tableName: string --- # DescribeSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L348)indexName **indexName: string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L347)tableName **tableName: string --- # DescribeTableParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L210)tableName **tableName: string --- # DropIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**mainTableName](#mainTableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L582)indexName **indexName: string ### [**](#mainTableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L581)mainTableName **mainTableName: string --- # GetRangeParams ## Index[**](#Index) ### Properties * [**columnFilter](#columnFilter) * [**columnsToGet](#columnsToGet) * [**direction](#direction) * [**endColumn](#endColumn) * [**exclusiveEndPrimaryKey](#exclusiveEndPrimaryKey) * [**inclusiveStartPrimaryKey](#inclusiveStartPrimaryKey) * [**limit](#limit) * [**maxVersions](#maxVersions) * [**startColumn](#startColumn) * [**tableName](#tableName) * [**timeRange](#timeRange) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#columnFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L286)optionalcolumnFilter **columnFilter? : [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) ### [**](#columnsToGet)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L295)optionalcolumnsToGet **columnsToGet? : string\[] ### [**](#direction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L284)direction **direction: [Direction](/api/3.0.0/tablestore/enum/Direction.md) ### [**](#endColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L294)optionalendColumn **endColumn? : string ### [**](#exclusiveEndPrimaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L283)exclusiveEndPrimaryKey **exclusiveEndPrimaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#inclusiveStartPrimaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L282)inclusiveStartPrimaryKey **inclusiveStartPrimaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L287)optionallimit **limit? : number ### [**](#maxVersions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L285)optionalmaxVersions **maxVersions? : number ### [**](#startColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L293)optionalstartColumn **startColumn? : string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L281)tableName **tableName: string ### [**](#timeRange)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L288)optionaltimeRange **timeRange? : { endTime? : string; specificTime? : string; startTime? : string } ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L296)optionaltransactionId **transactionId? : string --- # GetRowParams ## Index[**](#Index) ### Properties * [**columnFilter](#columnFilter) * [**columnsToGet](#columnsToGet) * [**endColumn](#endColumn) * [**maxVersions](#maxVersions) * [**primaryKey](#primaryKey) * [**startColumn](#startColumn) * [**tableName](#tableName) * [**timeRange](#timeRange) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#columnFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L224)optionalcolumnFilter **columnFilter? : [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) ### [**](#columnsToGet)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L232)optionalcolumnsToGet **columnsToGet? : string\[] ### [**](#endColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L231)optionalendColumn **endColumn? : string ### [**](#maxVersions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L223)optionalmaxVersions **maxVersions? : number = \`\`\`ts 1 \`\`\` ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L218)primaryKey **primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#startColumn)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L230)optionalstartColumn **startColumn? : string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L217)tableName **tableName: string ### [**](#timeRange)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L225)optionaltimeRange **timeRange? : { endTime? : string; specificTime? : string; startTime? : string } ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L233)optionaltransactionId **transactionId? : string --- # ListSearchIndexParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L343)tableName **tableName: string --- # PutRowParams ## Index[**](#Index) ### Properties * [**attributeColumns](#attributeColumns) * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#attributeColumns)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L250)optionalattributeColumns **attributeColumns? : [AttributeColumn](/api/3.0.0/tablestore.md#AttributeColumn)\[] ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L251)optionalcondition **condition? : [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L249)primaryKey **primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L252)optionalreturnContent **returnContent? : { returnType? : [ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L248)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L255)optionaltransactionId **transactionId? : string --- # SearchIndexFieldSchema ## Index[**](#Index) ### Properties * [**analyzer](#analyzer) * [**enableSortAndAgg](#enableSortAndAgg) * [**fieldName](#fieldName) * [**fieldSchemas](#fieldSchemas) * [**fieldType](#fieldType) * [**index](#index) * [**indexOptions](#indexOptions) * [**isAnArray](#isAnArray) * [**store](#store) ## Properties[**](#Properties) ### [**](#analyzer)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L365)optionalanalyzer **analyzer? : string ### [**](#enableSortAndAgg)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L361)optionalenableSortAndAgg **enableSortAndAgg? : boolean 设置开启排序和统计功能 ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L352)fieldName **fieldName: string ### [**](#fieldSchemas)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L366)optionalfieldSchemas **fieldSchemas? : [SearchIndexFieldSchema](/api/3.0.0/tablestore/interface/SearchIndexFieldSchema.md)\[] ### [**](#fieldType)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L353)fieldType **fieldType: [FieldType](/api/3.0.0/tablestore/enum/FieldType.md) ### [**](#index)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L357)optionalindex **index? : boolean 设置开启索引 ### [**](#indexOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L364)optionalindexOptions **indexOptions? : [IndexOptions](/api/3.0.0/tablestore/enum/IndexOptions.md) ### [**](#isAnArray)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L363)optionalisAnArray **isAnArray? : boolean ### [**](#store)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L362)optionalstore **store? : boolean --- # SearchIndexNestedFilter ## Index[**](#Index) ### Properties * [**filter](#filter) * [**path](#path) ## Properties[**](#Properties) ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L500)optionalfilter **filter? : [SearchIndexQuery](/api/3.0.0/tablestore.md#SearchIndexQuery) ### [**](#path)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L499)optionalpath **path? : string --- # SearchIndexSchema ## Index[**](#Index) ### Properties * [**fieldSchemas](#fieldSchemas) * [**indexSetting](#indexSetting) * [**indexSort](#indexSort) ## Properties[**](#Properties) ### [**](#fieldSchemas)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L527)optionalfieldSchemas **fieldSchemas? : [SearchIndexFieldSchema](/api/3.0.0/tablestore/interface/SearchIndexFieldSchema.md)\[] ### [**](#indexSetting)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L528)optionalindexSetting **indexSetting? : [SearchIndexSetting](/api/3.0.0/tablestore/interface/SearchIndexSetting.md) ### [**](#indexSort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L529)optionalindexSort **indexSort? : { sorters: [SearchIndexSorter](/api/3.0.0/tablestore/interface/SearchIndexSorter.md)\[] } --- # SearchIndexSetting ## Index[**](#Index) ### Properties * [**routingFields](#routingFields) * [**routingPartitionSize](#routingPartitionSize) ## Properties[**](#Properties) ### [**](#routingFields)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L370)optionalroutingFields **routingFields? : string\[] ### [**](#routingPartitionSize)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L371)optionalroutingPartitionSize **routingPartitionSize? : number --- # SearchIndexSorter ## Index[**](#Index) ### Properties * [**fieldSort](#fieldSort) * [**geoDistanceSort](#geoDistanceSort) * [**primaryKeySort](#primaryKeySort) * [**scoreSort](#scoreSort) ## Properties[**](#Properties) ### [**](#fieldSort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L504)optionalfieldSort **fieldSort? : { fieldName: string; mode? : [SortMode](/api/3.0.0/tablestore/enum/SortMode.md); nestedFilter? : [SearchIndexNestedFilter](/api/3.0.0/tablestore/interface/SearchIndexNestedFilter.md); order? : [SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md) } ### [**](#geoDistanceSort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L510)optionalgeoDistanceSort **geoDistanceSort? : { distanceType? : [GeoDistanceType](/api/3.0.0/tablestore/enum/GeoDistanceType.md); fieldName: string; mode? : [SortMode](/api/3.0.0/tablestore/enum/SortMode.md); nestedFilter? : [SearchIndexNestedFilter](/api/3.0.0/tablestore/interface/SearchIndexNestedFilter.md); order? : [SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md); points? : string\[] } ### [**](#primaryKeySort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L521)optionalprimaryKeySort **primaryKeySort? : { order? : [SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md) } ### [**](#scoreSort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L518)optionalscoreSort **scoreSort? : { order? : [SortOrder](/api/3.0.0/tablestore/enum/SortOrder.md) } --- # SearchParams ## Index[**](#Index) ### Properties * [**columnToGet](#columnToGet) * [**indexName](#indexName) * [**routingValues](#routingValues) * [**searchQuery](#searchQuery) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#columnToGet)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L562)columnToGet **columnToGet: { returnNames: string\[]; returnType: [ColumnReturnType](/api/3.0.0/tablestore/enum/ColumnReturnType.md) } | { returnType: RETURN\_ALL | RETURN\_NONE } ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L560)indexName **indexName: string ### [**](#routingValues)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L565)optionalroutingValues **routingValues? : [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[]\[] ### [**](#searchQuery)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L561)searchQuery **searchQuery: [SearchQuery](/api/3.0.0/tablestore/interface/SearchQuery.md) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L559)tableName **tableName: string --- # SearchQuery ## Index[**](#Index) ### Properties * [**getTotalCount](#getTotalCount) * [**limit](#limit) * [**offset](#offset) * [**query](#query) * [**sort](#sort) * [**token](#token) ## Properties[**](#Properties) ### [**](#getTotalCount)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L548)optionalgetTotalCount **getTotalCount? : boolean ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L547)limit **limit: number ### [**](#offset)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L546)offset **offset: number ### [**](#query)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L553)optionalquery **query? : { queryType: [QueryType](/api/3.0.0/tablestore/enum/QueryType.md) } ### [**](#sort)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L550)optionalsort **sort? : { sorters: [SearchIndexSorter](/api/3.0.0/tablestore/interface/SearchIndexSorter.md)\[] } ### [**](#token)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L549)optionaltoken **token? : string --- # StartLocalTransactionParams ## Index[**](#Index) ### Properties * [**primaryKey](#primaryKey) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L587)primaryKey **primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L586)tableName **tableName: string --- # TableStoreClient ### Hierarchy * *TableStoreClient* * [TableStoreService](/api/3.0.0/tablestore/class/TableStoreService.md) ### Implemented by * [TableStoreService](/api/3.0.0/tablestore/class/TableStoreService.md) ## Index[**](#Index) ### Methods * [**abortTransaction](#abortTransaction) * [**batchGetRow](#batchGetRow) * [**batchWriteRow](#batchWriteRow) * [**commitTransaction](#commitTransaction) * [**createIndex](#createIndex) * [**createSearchIndex](#createSearchIndex) * [**createTable](#createTable) * [**deleteRow](#deleteRow) * [**deleteSearchIndex](#deleteSearchIndex) * [**deleteTable](#deleteTable) * [**describeSearchIndex](#describeSearchIndex) * [**describeTable](#describeTable) * [**dropIndex](#dropIndex) * [**getRange](#getRange) * [**getRow](#getRow) * [**listSearchIndex](#listSearchIndex) * [**listTable](#listTable) * [**putRow](#putRow) * [**search](#search) * [**startLocalTransaction](#startLocalTransaction) * [**updateRow](#updateRow) * [**updateTable](#updateTable) ## Methods[**](#Methods) ### [**](#abortTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L715)abortTransaction * **abortTransaction\(params: [AbortTransactionParams](/api/3.0.0/tablestore.md#AbortTransactionParams)): Promise\ - 丢弃事务 *** #### Type parameters * **R** = any ### [**](#batchGetRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L660)batchGetRow * **batchGetRow\(params: [BatchGetRowParams](/api/3.0.0/tablestore/interface/BatchGetRowParams.md)): Promise\ - 批量读取一个或多个表中的若干行数据。 *** #### Type parameters * **R** = any ### [**](#batchWriteRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L665)batchWriteRow * **batchWriteRow\(params: [BatchWriteRowParams](/api/3.0.0/tablestore/interface/BatchWriteRowParams.md)): Promise\ - 批量修改行 *** #### Type parameters * **R** = any ### [**](#commitTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L710)commitTransaction * **commitTransaction\(params: [CommitTransactionParams](/api/3.0.0/tablestore.md#CommitTransactionParams)): Promise\ - 提交事务 *** #### Type parameters * **R** = any ### [**](#createIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L695)createIndex * **createIndex\(params: [CreateIndexParams](/api/3.0.0/tablestore/interface/CreateIndexParams.md)): Promise\ - 创建GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#createSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L680)createSearchIndex * **createSearchIndex\(params: [CreateSearchIndexParams](/api/3.0.0/tablestore/interface/CreateSearchIndexParams.md)): Promise\ - SearchIndex创建新索引。 *** #### Type parameters * **R** = any ### [**](#createTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L607)createTable * **createTable\(params: [CreateTableParams](/api/3.0.0/tablestore/interface/CreateTableParams.md)): Promise\ - 根据给定的表结构信息创建相应的表。 *** #### Type parameters * **R** = any ### [**](#deleteRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L650)deleteRow * **deleteRow\(params: [DeleteRowParams](/api/3.0.0/tablestore/interface/DeleteRowParams.md)): Promise\ - 删除一行数据。 *** #### Type parameters * **R** = any ### [**](#deleteSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L685)deleteSearchIndex * **deleteSearchIndex\(params: [DeleteSearchIndexParams](/api/3.0.0/tablestore/interface/DeleteSearchIndexParams.md)): Promise\ - SearchIndex删除索引。 *** #### Type parameters * **R** = any ### [**](#deleteTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L617)deleteTable * **deleteTable\(params: [DeleteTableParams](/api/3.0.0/tablestore/interface/DeleteTableParams.md)): Promise\ - 删除本实例下指定的表。 *** #### Type parameters * **R** = any ### [**](#describeSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L675)describeSearchIndex * **describeSearchIndex\(params: [DescribeSearchIndexParams](/api/3.0.0/tablestore/interface/DescribeSearchIndexParams.md)): Promise\ - 获取SearchIndex索引描述信息。 *** #### Type parameters * **R** = any ### [**](#describeTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L627)describeTable * **describeTable\(params: [DescribeTableParams](/api/3.0.0/tablestore/interface/DescribeTableParams.md)): Promise\ - 查询指定表的结构信息和预留读/写吞吐量设置信息。 *** #### Type parameters * **R** = any ### [**](#dropIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L700)dropIndex * **dropIndex\(params: [DropIndexParams](/api/3.0.0/tablestore/interface/DropIndexParams.md)): Promise\ - 删除GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#getRange)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L655)getRange * **getRange\(params: [GetRangeParams](/api/3.0.0/tablestore/interface/GetRangeParams.md)): Promise\ - 读取指定主键范围内的数据。 *** #### Type parameters * **R** = any ### [**](#getRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L635)getRow * **getRow\(params: [GetRowParams](/api/3.0.0/tablestore/interface/GetRowParams.md)): Promise\ - 根据给定的主键读取单行数据。 *** #### Type parameters * **R** = any ### [**](#listSearchIndex)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L670)listSearchIndex * **listSearchIndex\(params: [ListSearchIndexParams](/api/3.0.0/tablestore/interface/ListSearchIndexParams.md)): Promise\ - 获取表下所有SearchIndex索引名。 *** #### Type parameters * **R** = any ### [**](#listTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L612)listTable * **listTable\(params: {}): Promise\ - 获取当前实例下已创建的所有表的表名。 *** #### Type parameters * **R** = any ### [**](#putRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L640)putRow * **putRow\(params: [PutRowParams](/api/3.0.0/tablestore/interface/PutRowParams.md)): Promise\ - 插入数据到指定的行,如果该行不存在,则新增一行;若该行存在,则覆盖原有行。 *** #### Type parameters * **R** = any ### [**](#search)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L690)search * **search\(params: [SearchParams](/api/3.0.0/tablestore/interface/SearchParams.md)): Promise\ - SearchIndex搜索。 *** #### Type parameters * **R** = any ### [**](#startLocalTransaction)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L705)startLocalTransaction * **startLocalTransaction\(params: [StartLocalTransactionParams](/api/3.0.0/tablestore/interface/StartLocalTransactionParams.md)): Promise\ - 创建局部事务 *** #### Type parameters * **R** = any ### [**](#updateRow)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L645)updateRow * **updateRow\(params: [UpdateRowParams](/api/3.0.0/tablestore/interface/UpdateRowParams.md)): Promise\ - 更新指定行的数据。如果该行不存在,则新增一行;若该行存在,则根据请求的内容在这一行中新增、修改或者删除指定列的值。 *** #### Type parameters * **R** = any ### [**](#updateTable)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L622)updateTable * **updateTable\(params: [UpdateTableParams](/api/3.0.0/tablestore/interface/UpdateTableParams.md)): Promise\ - 更新指定表的预留读吞吐量或预留写吞吐量设置。 *** #### Type parameters * **R** = any --- # TableStoreCompositeCondition ### Hierarchy * *TableStoreCompositeCondition* * [CompositeCondition](/api/3.0.0/tablestore/class/CompositeCondition.md) ## Index[**](#Index) ### Properties * [**sub\_conditions](#sub_conditions) ### Methods * [**addSubCondition](#addSubCondition) * [**clearSubCondition](#clearSubCondition) * [**getCombinator](#getCombinator) * [**getType](#getType) * [**setCombinator](#setCombinator) ## Properties[**](#Properties) ### [**](#sub_conditions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L745)sub\_conditions **sub\_conditions: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)\[] ## Methods[**](#Methods) ### [**](#addSubCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L753)addSubCondition * **addSubCondition(condition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)): void ### [**](#clearSubCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L755)clearSubCondition * **clearSubCondition(): void ### [**](#getCombinator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L751)getCombinator * **getCombinator(): [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L747)getType * **getType(): FT\_COMPOSITE\_COLUMN\_VALUE ### [**](#setCombinator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L749)setCombinator * **setCombinator(combinator: [LogicalOperator](/api/3.0.0/tablestore/enum/LogicalOperator.md)): void --- # TableStoreCondition ### Hierarchy * *TableStoreCondition* * [Condition](/api/3.0.0/tablestore/class/Condition.md) ## Index[**](#Index) ### Properties * [**columnCondition](#columnCondition) * [**rowExistenceExpectation](#rowExistenceExpectation) ### Methods * [**getColumnCondition](#getColumnCondition) * [**getRowExistenceExpectation](#getRowExistenceExpectation) * [**setColumnCondition](#setColumnCondition) * [**setRowExistenceExpectation](#setRowExistenceExpectation) ## Properties[**](#Properties) ### [**](#columnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L759)columnCondition **columnCondition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) ### [**](#rowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L760)rowExistenceExpectation **rowExistenceExpectation: [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md) ## Methods[**](#Methods) ### [**](#getColumnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L768)getColumnCondition * **getColumnCondition(): [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) ### [**](#getRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L764)getRowExistenceExpectation * **getRowExistenceExpectation(): [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md) ### [**](#setColumnCondition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L766)setColumnCondition * **setColumnCondition(columnCondition: [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md)): void ### [**](#setRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L762)setRowExistenceExpectation * **setRowExistenceExpectation(rowExistenceExpectation: [RowExistenceExpectation](/api/3.0.0/tablestore/enum/RowExistenceExpectation.md)): void --- # TableStoreConfig ## Index[**](#Index) ### Properties * [**accessKeyId](#accessKeyId) * [**accessKeySecret](#accessKeySecret) * [**computeChecksums](#computeChecksums) * [**endpoint](#endpoint) * [**httpOptions](#httpOptions) * [**instancename](#instancename) * [**logger](#logger) * [**maxRetries](#maxRetries) * [**secretAccessKey](#secretAccessKey) * [**securityToken](#securityToken) * [**stsToken](#stsToken) ## Properties[**](#Properties) ### [**](#accessKeyId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L820)accessKeyId **accessKeyId: string ### [**](#accessKeySecret)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L822)optionalaccessKeySecret **accessKeySecret? : string ### [**](#computeChecksums)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L841)optionalcomputeChecksums **computeChecksums? : boolean = \`\`\`ts true \`\`\` ### [**](#endpoint)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L826)endpoint **endpoint: string ### [**](#httpOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L827)optionalhttpOptions **httpOptions? : { maxSockets? : number; timeout? : number } ### [**](#instancename)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L836)instancename **instancename: string ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L825)optionallogger **logger? : any ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L835)optionalmaxRetries **maxRetries? : number ### [**](#secretAccessKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L821)optionalsecretAccessKey **secretAccessKey? : string ### [**](#securityToken)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L824)optionalsecurityToken **securityToken? : string ### [**](#stsToken)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L823)optionalstsToken **stsToken? : string --- # TableStoreLong ## Index[**](#Index) ### Properties * [**int64](#int64) ### Methods * [**fromNumber](#fromNumber) * [**fromString](#fromString) * [**toBuffer](#toBuffer) * [**toNumber](#toNumber) ## Properties[**](#Properties) ### [**](#int64)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L772)optionalint64 **int64? : Int64LE ## Methods[**](#Methods) ### [**](#fromNumber)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L774)fromNumber * **fromNumber(num: number): Int64LE ### [**](#fromString)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L776)fromString * **fromString(str: string): Int64LE ### [**](#toBuffer)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L778)toBuffer * **toBuffer(): Buffer\ ### [**](#toNumber)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L780)toNumber * **toNumber(): number --- # TableStoreResult ## Index[**](#Index) ### Properties * [**primaryKey](#primaryKey) ## Properties[**](#Properties) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L594)primaryKey **primaryKey: \[{ name: string; value: any }] --- # TableStoreSingleColumnCondition \ ### Hierarchy * [ColumnCondition](/api/3.0.0/tablestore/interface/ColumnCondition.md) * *TableStoreSingleColumnCondition* * [SingleColumnCondition](/api/3.0.0/tablestore/class/SingleColumnCondition.md) ## Index[**](#Index) ### Properties * [**columnName](#columnName) * [**columnValue](#columnValue) * [**comparator](#comparator) * [**latestVersionOnly](#latestVersionOnly) * [**passIfMissing](#passIfMissing) ### Methods * [**getColumnName](#getColumnName) * [**getColumnValue](#getColumnValue) * [**getLatestVersionOnly](#getLatestVersionOnly) * [**getPassIfMissing](#getPassIfMissing) * [**getType](#getType) * [**setColumnName](#setColumnName) * [**setColumnValue](#setColumnValue) * [**setComparator](#setComparator) * [**setLatestVersionOnly](#setLatestVersionOnly) * [**setPassIfMissing](#setPassIfMissing) ## Properties[**](#Properties) ### [**](#columnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L784)columnName **columnName: string ### [**](#columnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L785)columnValue **columnValue: T ### [**](#comparator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L786)comparator **comparator: [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md) ### [**](#latestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L788)latestVersionOnly **latestVersionOnly: boolean ### [**](#passIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L787)passIfMissing **passIfMissing: boolean ## Methods[**](#Methods) ### [**](#getColumnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L810)getColumnName * **getColumnName(): string ### [**](#getColumnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L814)getColumnValue * **getColumnValue(): T ### [**](#getLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L806)getLatestVersionOnly * **getLatestVersionOnly(): boolean ### [**](#getPassIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L802)getPassIfMissing * **getPassIfMissing(): boolean ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L790)getType * **getType(): FT\_SINGLE\_COLUMN\_VALUE ### [**](#setColumnName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L808)setColumnName * **setColumnName(columnName: string): void ### [**](#setColumnValue)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L812)setColumnValue * **setColumnValue(columnValue: T): void ### [**](#setComparator)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L816)setComparator * **setComparator(comparator: [ComparatorType](/api/3.0.0/tablestore/enum/ComparatorType.md)): void ### [**](#setLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L804)setLatestVersionOnly * **setLatestVersionOnly(latestVersionOnly: boolean): void ### [**](#setPassIfMissing)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L800)setPassIfMissing * **setPassIfMissing(passIfMissing: boolean): void - 设置 `passIfMissing` 由于OTS一行的属性列不固定,有可能存在有condition条件的列在该行不存在的情况,这时 参数控制在这种情况下对该行的检查结果。 如果设置为True,则若列在该行中不存在,则检查条件通过。 如果设置为False,则若列在该行中不存在,则检查条件失败。 默认值为True。 --- # UpdateRowParams ## Index[**](#Index) ### Properties * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) * [**updateOfAttributeColumns](#updateOfAttributeColumns) ## Properties[**](#Properties) ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L262)optionalcondition **condition? : [TableStoreCondition](/api/3.0.0/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L260)primaryKey **primaryKey: [PrimaryKey](/api/3.0.0/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L263)optionalreturnContent **returnContent? : { returnColumns? : string\[]; returnType? : [ReturnType](/api/3.0.0/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L259)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L267)optionaltransactionId **transactionId? : string ### [**](#updateOfAttributeColumns)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L261)updateOfAttributeColumns **updateOfAttributeColumns: [UpdateColumn](/api/3.0.0/tablestore.md#UpdateColumn)\[] --- # UpdateTableParams ## Index[**](#Index) ### Properties * [**reservedThroughput](#reservedThroughput) * [**streamSpecification](#streamSpecification) * [**tableName](#tableName) * [**tableOptions](#tableOptions) ## Properties[**](#Properties) ### [**](#reservedThroughput)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L204)reservedThroughput **reservedThroughput: { capacityUnit: { read: number; write: number } } ### [**](#streamSpecification)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L206)optionalstreamSpecification **streamSpecification? : { enableStream? : boolean; expirationTime? : number } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L203)tableName **tableName: string ### [**](#tableOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/tablestore/src/interface.ts#L205)tableOptions **tableOptions: { maxTimeDeviation? : number; maxVersions? : number; timeToLive? : number } --- # @midwayjs/tags ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/tags/class/Configuration.md) * [**ITagDialect](/api/3.0.0/tags/class/ITagDialect.md) * [**ITagDialectInstance](/api/3.0.0/tags/class/ITagDialectInstance.md) * [**TagClient](/api/3.0.0/tags/class/TagClient.md) * [**TagServiceFactory](/api/3.0.0/tags/class/TagServiceFactory.md) ### Enumerations * [**MATCH\_TYPE](/api/3.0.0/tags/enum/MATCH_TYPE.md) * [**TAG\_ERROR](/api/3.0.0/tags/enum/TAG_ERROR.md) ### Interfaces * [**ITagBindOptions](/api/3.0.0/tags/interface/ITagBindOptions.md) * [**ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md) * [**ITagInstance](/api/3.0.0/tags/interface/ITagInstance.md) * [**ITagItem](/api/3.0.0/tags/interface/ITagItem.md) * [**ITagListInstanceOptions](/api/3.0.0/tags/interface/ITagListInstanceOptions.md) * [**ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md) * [**ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md) * [**ITagMysqlDialectOption](/api/3.0.0/tags/interface/ITagMysqlDialectOption.md) * [**ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md) * [**ITagPages](/api/3.0.0/tags/interface/ITagPages.md) * [**ITagSearchOptions](/api/3.0.0/tags/interface/ITagSearchOptions.md) * [**ITagServiceInitOptions](/api/3.0.0/tags/interface/ITagServiceInitOptions.md) * [**ITagUnBindOptions](/api/3.0.0/tags/interface/ITagUnBindOptions.md) * [**ITagUserDialect](/api/3.0.0/tags/interface/ITagUserDialect.md) ### Type Aliases * [**IMysqlQuery](/api/3.0.0/tags.md#IMysqlQuery) * [**ITagDialectOption](/api/3.0.0/tags.md#ITagDialectOption) ## Type Aliases[**](<#Type Aliases>) ### [**](#IMysqlQuery)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L15)IMysqlQuery **IMysqlQuery: (sql: string, placeholder? : any\[]) => \[any, any] ### [**](#ITagDialectOption)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L7)ITagDialectOption **ITagDialectOption: { dialectType: memory } | [ITagMysqlDialectOption](/api/3.0.0/tags/interface/ITagMysqlDialectOption.md) | [ITagUserDialect](/api/3.0.0/tags/interface/ITagUserDialect.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TagsConfiguration](/api/3.0.0/tags/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/configuration.ts#L20)onReady * **onReady(container: any): Promise\ --- # abstractITagDialect ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getInstance](#getInstance) * [**ready](#ready) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ITagDialect(): [ITagDialect](/api/3.0.0/tags/class/ITagDialect.md) ## Methods[**](#Methods) ### [**](#getInstance)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L45)abstractgetInstance * **getInstance(instanceName: string): [ITagDialectInstance](/api/3.0.0/tags/class/ITagDialectInstance.md) ### [**](#ready)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L43)abstractready * **ready(): Promise\ --- # abstractITagDialectInstance ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**bind](#bind) * [**list](#list) * [**listObjectTags](#listObjectTags) * [**listObjects](#listObjects) * [**new](#new) * [**remove](#remove) * [**unbind](#unbind) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ITagDialectInstance(): [ITagDialectInstance](/api/3.0.0/tags/class/ITagDialectInstance.md) ## Methods[**](#Methods) ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L58)abstractbind * **bind(bindOptions: [ITagBindOptions](/api/3.0.0/tags/interface/ITagBindOptions.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#list)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L56)abstractlist * **list(listOptions? : [ITagSearchOptions](/api/3.0.0/tags/interface/ITagSearchOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)<[ITagItem](/api/3.0.0/tags/interface/ITagItem.md)>> ### [**](#listObjectTags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L64)abstractlistObjectTags * **listObjectTags(listOptions? : [ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)<[ITagItem](/api/3.0.0/tags/interface/ITagItem.md)>> ### [**](#listObjects)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L62)abstractlistObjects * **listObjects(listOptions? : [ITagListInstanceOptions](/api/3.0.0/tags/interface/ITagListInstanceOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)\> ### [**](#new)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L50)abstractnew * **new(tagDefine: [ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L52)abstractremove * **remove(tagIdOrName: string | number): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#unbind)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L60)abstractunbind * **unbind(unbindOptions: [ITagUnBindOptions](/api/3.0.0/tags/interface/ITagUnBindOptions.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#update)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L54)abstractupdate * **update(tagIdOrName: string | number, params: Partial<[ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md)>): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> --- # TagClient ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**bind](#bind) * [**list](#list) * [**listObjectTags](#listObjectTags) * [**listObjects](#listObjects) * [**new](#new) * [**remove](#remove) * [**unbind](#unbind) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L22)constructor * **new TagClient(dialect: [ITagDialect](/api/3.0.0/tags/class/ITagDialect.md), tagGroup: string): [TagClient](/api/3.0.0/tags/class/TagClient.md) ## Methods[**](#Methods) ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L50)bind * **bind(bindOptions: [ITagBindOptions](/api/3.0.0/tags/interface/ITagBindOptions.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#list)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L40)list * **list(listOptions? : [ITagSearchOptions](/api/3.0.0/tags/interface/ITagSearchOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)<[ITagItem](/api/3.0.0/tags/interface/ITagItem.md)>> ### [**](#listObjectTags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L72)listObjectTags * **listObjectTags(listOptions? : [ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)<[ITagItem](/api/3.0.0/tags/interface/ITagItem.md)>> ### [**](#listObjects)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L61)listObjects * **listObjects(listOptions? : [ITagListInstanceOptions](/api/3.0.0/tags/interface/ITagListInstanceOptions.md)): Promise<[ITagListResult](/api/3.0.0/tags/interface/ITagListResult.md)\> ### [**](#new)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L26)new * **new(tagDefine: [ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L30)remove * **remove(tagIdOrName: string | number): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#unbind)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L57)unbind * **unbind(unbindOptions: [ITagUnBindOptions](/api/3.0.0/tags/interface/ITagUnBindOptions.md)): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> ### [**](#update)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/service.ts#L34)update * **update(tagIdOrName: string | number, params: Partial<[ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md)>): Promise<[ITagOperResult](/api/3.0.0/tags/interface/ITagOperResult.md)> --- # TagServiceFactory ### Hierarchy * ServiceFactory<[TagClient](/api/3.0.0/tags/class/TagClient.md)> * *TagServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**tags](#tags) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TagServiceFactory(): [TagServiceFactory](/api/3.0.0/tags/class/TagServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/manager.ts#L20)tags **tags: ServiceFactoryConfigOption<[ITagDialectOption](/api/3.0.0/tags.md#ITagDialectOption)> ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/manager.ts#L27)createClient * **createClient(config: [ITagDialectOption](/api/3.0.0/tags.md#ITagDialectOption), name: string): Promise<[TagClient](/api/3.0.0/tags/class/TagClient.md)> - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L14)createInstance * **createInstance(config: any, clientName? : any): Promise<[TagClient](/api/3.0.0/tags/class/TagClient.md)> - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L12)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [TagClient](/api/3.0.0/tags/class/TagClient.md) ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L20)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L19)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/manager.ts#L43)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L13)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/manager.ts#L23)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L18)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # MATCH\_TYPE ## Index[**](#Index) ### Enumeration Members * [**And](#And) * [**Or](#Or) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#And)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L111)And **And: and ### [**](#Or)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L113)Or **Or: or --- # TAG\_ERROR ## Index[**](#Index) ### Enumeration Members * [**EXISTS](#EXISTS) * [**MISSING\_PARAMETERS](#MISSING_PARAMETERS) * [**NOT\_EXISTS](#NOT_EXISTS) * [**OPER\_ERROR](#OPER_ERROR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#EXISTS)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/error.ts#L2)EXISTS **EXISTS: tag already exists ### [**](#MISSING_PARAMETERS)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/error.ts#L4)MISSING\_PARAMETERS **MISSING\_PARAMETERS: missing parameters ### [**](#NOT_EXISTS)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/error.ts#L3)NOT\_EXISTS **NOT\_EXISTS: tag does not exist ### [**](#OPER_ERROR)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/error.ts#L5)OPER\_ERROR **OPER\_ERROR: operation error --- # ITagBindOptions ### Hierarchy * [ITagInstance](/api/3.0.0/tags/interface/ITagInstance.md) * *ITagBindOptions* ## Index[**](#Index) ### Properties * [**autoCreateTag](#autoCreateTag) * [**objectId](#objectId) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#autoCreateTag)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L94)optionalautoCreateTag **autoCreateTag? : boolean ### [**](#objectId)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L106)objectId **objectId: number Inherited from ITagInstance.objectId ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L92)tags **tags: (string | number)\[] --- # ITagDefine ### Hierarchy * *ITagDefine* * [ITagItem](/api/3.0.0/tags/interface/ITagItem.md) ## Index[**](#Index) ### Properties * [**desc](#desc) * [**name](#name) ## Properties[**](#Properties) ### [**](#desc)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L32)optionaldesc **desc? : string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L31)name **name: string --- # ITagInstance ### Hierarchy * *ITagInstance* * [ITagBindOptions](/api/3.0.0/tags/interface/ITagBindOptions.md) * [ITagUnBindOptions](/api/3.0.0/tags/interface/ITagUnBindOptions.md) * [ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md) ## Index[**](#Index) ### Properties * [**objectId](#objectId) ## Properties[**](#Properties) ### [**](#objectId)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L106)objectId **objectId: number --- # ITagItem ### Hierarchy * [ITagDefine](/api/3.0.0/tags/interface/ITagDefine.md) * *ITagItem* ## Index[**](#Index) ### Properties * [**createAt](#createAt) * [**desc](#desc) * [**id](#id) * [**name](#name) * [**updateAt](#updateAt) ## Properties[**](#Properties) ### [**](#createAt)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L37)createAt **createAt: number ### [**](#desc)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L32)optionaldesc **desc? : string Inherited from ITagDefine.desc ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L36)id **id: number ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L31)name **name: string Inherited from ITagDefine.name ### [**](#updateAt)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L38)updateAt **updateAt: number --- # ITagListInstanceOptions ### Hierarchy * [ITagPages](/api/3.0.0/tags/interface/ITagPages.md) * *ITagListInstanceOptions* ## Index[**](#Index) ### Properties * [**count](#count) * [**page](#page) * [**pageSize](#pageSize) * [**tags](#tags) * [**type](#type) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L118)optionalcount **count? : boolean Overrides ITagPages.count ### [**](#page)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L87)optionalpage **page? : number Inherited from ITagPages.page ### [**](#pageSize)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L86)optionalpageSize **pageSize? : number Inherited from ITagPages.pageSize ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L117)optionaltags **tags? : (string | number)\[] ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L119)optionaltype **type? : [MATCH\_TYPE](/api/3.0.0/tags/enum/MATCH_TYPE.md) --- # ITagListInstanceTagsOptions ### Hierarchy * [ITagInstance](/api/3.0.0/tags/interface/ITagInstance.md) * [ITagPages](/api/3.0.0/tags/interface/ITagPages.md) * *ITagListInstanceTagsOptions* ## Index[**](#Index) ### Properties * [**count](#count) * [**objectId](#objectId) * [**page](#page) * [**pageSize](#pageSize) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L85)optionalcount **count? : boolean Inherited from ITagPages.count ### [**](#objectId)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L106)objectId **objectId: number Inherited from ITagInstance.objectId ### [**](#page)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L87)optionalpage **page? : number Inherited from ITagPages.page ### [**](#pageSize)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L86)optionalpageSize **pageSize? : number Inherited from ITagPages.pageSize --- # ITagListResult \ ## Index[**](#Index) ### Properties * [**list](#list) * [**total](#total) ## Properties[**](#Properties) ### [**](#list)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L74)list **list: ListType\[] ### [**](#total)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L75)optionaltotal **total? : number --- # ITagMysqlDialectOption ## Index[**](#Index) ### Properties * [**dialectType](#dialectType) * [**instance](#instance) * [**sync](#sync) * [**tablePrefix](#tablePrefix) * [**tableSeparator](#tableSeparator) ## Properties[**](#Properties) ### [**](#dialectType)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L17)dialectType **dialectType: mysql ### [**](#instance)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L25)instance **instance: { query: [IMysqlQuery](/api/3.0.0/tags.md#IMysqlQuery) } ### [**](#sync)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L19)optionalsync **sync? : boolean ### [**](#tablePrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L21)optionaltablePrefix **tablePrefix? : string ### [**](#tableSeparator)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L23)optionaltableSeparator **tableSeparator? : string --- # ITagOperResult ## Index[**](#Index) ### Properties * [**id](#id) * [**message](#message) * [**success](#success) ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L70)optionalid **id? : number ### [**](#message)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L69)message **message: string ### [**](#success)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L68)success **success: boolean --- # ITagPages ### Hierarchy * *ITagPages* * [ITagSearchOptions](/api/3.0.0/tags/interface/ITagSearchOptions.md) * [ITagListInstanceTagsOptions](/api/3.0.0/tags/interface/ITagListInstanceTagsOptions.md) * [ITagListInstanceOptions](/api/3.0.0/tags/interface/ITagListInstanceOptions.md) ## Index[**](#Index) ### Properties * [**count](#count) * [**page](#page) * [**pageSize](#pageSize) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L85)optionalcount **count? : boolean ### [**](#page)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L87)optionalpage **page? : number ### [**](#pageSize)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L86)optionalpageSize **pageSize? : number --- # ITagSearchOptions ### Hierarchy * [ITagPages](/api/3.0.0/tags/interface/ITagPages.md) * *ITagSearchOptions* ## Index[**](#Index) ### Properties * [**count](#count) * [**page](#page) * [**pageSize](#pageSize) * [**tags](#tags) * [**type](#type) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L85)optionalcount **count? : boolean Inherited from ITagPages.count ### [**](#page)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L87)optionalpage **page? : number Inherited from ITagPages.page ### [**](#pageSize)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L86)optionalpageSize **pageSize? : number Inherited from ITagPages.pageSize ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L80)optionaltags **tags? : (string | number)\[] ### [**](#type)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L81)optionaltype **type? : [MATCH\_TYPE](/api/3.0.0/tags/enum/MATCH_TYPE.md) --- # ITagServiceInitOptions ## Index[**](#Index) ### Properties * [**dialect](#dialect) * [**group](#group) ## Properties[**](#Properties) ### [**](#dialect)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L3)optionaldialect **dialect? : [ITagDialect](/api/3.0.0/tags/class/ITagDialect.md) ### [**](#group)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L2)group **group: string --- # ITagUnBindOptions ### Hierarchy * [ITagInstance](/api/3.0.0/tags/interface/ITagInstance.md) * *ITagUnBindOptions* ## Index[**](#Index) ### Properties * [**objectId](#objectId) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#objectId)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L106)objectId **objectId: number Inherited from ITagInstance.objectId ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L99)tags **tags: (string | number)\[] --- # ITagUserDialect ## Index[**](#Index) ### Properties * [**dialect](#dialect) * [**dialectType](#dialectType) ## Properties[**](#Properties) ### [**](#dialect)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L13)dialect **dialect: [ITagDialect](/api/3.0.0/tags/class/ITagDialect.md) ### [**](#dialectType)[**](https://github.com/midwayjs/midway/blob/main/packages/tags/src/interface.ts#L12)dialectType **dialectType: string --- # @midwayjs/typegoose ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/typegoose/class/Configuration.md) ### Functions * [**EntityModel](/api/3.0.0/typegoose/function/EntityModel.md) * [**InjectEntityModel](/api/3.0.0/typegoose/function/InjectEntityModel.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**decoratorService](#decoratorService) * [**legacyMode](#legacyMode) * [**modelMap](#modelMap) * [**oldMongooseConfig](#oldMongooseConfig) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TypegooseConfiguration](/api/3.0.0/typegoose/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L29)app **app: IMidwayBaseApplication\ ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L32)decoratorService **decoratorService: MidwayDecoratorService ### [**](#legacyMode)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L26)legacyMode **legacyMode: boolean = false ### [**](#modelMap)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L34)modelMap **modelMap: WeakMap\ = ... ### [**](#oldMongooseConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L24)oldMongooseConfig **oldMongooseConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L37)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L52)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/typegoose/src/configuration.ts#L91)onStop * **onStop(): Promise\ --- # EntityModel ### Callable * **EntityModel(options? : EntityOptions): ClassDecorator --- # InjectEntityModel ### Callable * **InjectEntityModel(modelKey: any): PropertyDecorator --- # @midwayjs/typeorm ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/typeorm/class/Configuration.md) * [**TypeORMDataSourceManager](/api/3.0.0/typeorm/class/TypeORMDataSourceManager.md) ### Functions * [**EventSubscriberModel](/api/3.0.0/typeorm/function/EventSubscriberModel.md) * [**InjectDataSource](/api/3.0.0/typeorm/function/InjectDataSource.md) * [**InjectEntityModel](/api/3.0.0/typeorm/function/InjectEntityModel.md) ### Type Aliases * [**typeormConfigOptions](/api/3.0.0/typeorm.md#typeormConfigOptions) ### Variables * [**ENTITY\_MODEL\_KEY](/api/3.0.0/typeorm.md#ENTITY_MODEL_KEY) * [**EVENT\_SUBSCRIBER\_KEY](/api/3.0.0/typeorm.md#EVENT_SUBSCRIBER_KEY) * [**ORM\_DATA\_SOURCE\_KEY](/api/3.0.0/typeorm.md#ORM_DATA_SOURCE_KEY) * [**ORM\_MODEL\_KEY](/api/3.0.0/typeorm.md#ORM_MODEL_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#typeormConfigOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/interface.ts#L4)typeormConfigOptions **typeormConfigOptions: DataSourceManagerConfigOption\ & { allowExecuteMigrations: boolean } ## Variables[**](#Variables) ### [**](#ENTITY_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/decorator.ts#L9)constENTITY\_MODEL\_KEY **ENTITY\_MODEL\_KEY: typeorm:entity\_model\_key = 'typeorm:entity\_model\_key' ### [**](#EVENT_SUBSCRIBER_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/decorator.ts#L10)constEVENT\_SUBSCRIBER\_KEY **EVENT\_SUBSCRIBER\_KEY: typeorm:event\_subscriber\_key = 'typeorm:event\_subscriber\_key' ### [**](#ORM_DATA_SOURCE_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/decorator.ts#L12)constORM\_DATA\_SOURCE\_KEY **ORM\_DATA\_SOURCE\_KEY: typeorm:data\_source\_key = 'typeorm:data\_source\_key' ### [**](#ORM_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/decorator.ts#L11)constORM\_MODEL\_KEY **ORM\_MODEL\_KEY: typeorm:orm\_model\_key = 'typeorm:orm\_model\_key' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [OrmConfiguration](/api/3.0.0/typeorm/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L47)app **app: IMidwayBaseApplication\ ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L52)dataSourceManager **dataSourceManager: [TypeORMDataSourceManager](/api/3.0.0/typeorm/class/TypeORMDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L50)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L55)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L105)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/configuration.ts#L110)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # TypeORMDataSourceManager ### Hierarchy * DataSourceManager\ * *TypeORMDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**baseDir](#baseDir) * [**loggerService](#loggerService) * [**typeormConfig](#typeormConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TypeORMDataSourceManager(): [TypeORMDataSourceManager](/api/3.0.0/typeorm/class/TypeORMDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L24)applicationContext **applicationContext: IMidwayContainer ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L27)baseDir **baseDir: string ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L30)loggerService **loggerService: MidwayLoggerService ### [**](#typeormConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L21)typeormConfig **typeormConfig: [typeormConfigOptions](/api/3.0.0/typeorm.md#typeormConfigOptions) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L34)createInstance * **createInstance(config: any, clientName: any, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L21)getDataSource * **getDataSource(dataSourceName: string): DataSource - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L42)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L27)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L52)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L37)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L26)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/typeorm/src/dataSourceManager.ts#L33)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L33)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L53)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L55)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L54)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L50)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources --- # EventSubscriberModel ### Callable * **EventSubscriberModel(): ClassDecorator *** * EventSubscriber - typeorm implements EntitySubscriberInterface --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectEntityModel ### Callable * **InjectEntityModel(modelKey: EntityTarget\, connectionName? : string): PropertyDecorator --- # @midwayjs/upload ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/upload/class/Configuration.md) * [**MultipartInvalidFileTypeError](/api/3.0.0/upload/class/MultipartInvalidFileTypeError.md) * [**MultipartInvalidFilenameError](/api/3.0.0/upload/class/MultipartInvalidFilenameError.md) * [**UploadMiddleware](/api/3.0.0/upload/class/UploadMiddleware.md) ### Interfaces * [**UploadFileInfo](/api/3.0.0/upload/interface/UploadFileInfo.md) * [**UploadOptions](/api/3.0.0/upload/interface/UploadOptions.md) ### Type Aliases * [**UploadMode](/api/3.0.0/upload.md#UploadMode) ### Variables * [**DefaultUploadFileMimeType](/api/3.0.0/upload.md#DefaultUploadFileMimeType) * [**EXT\_KEY](/api/3.0.0/upload.md#EXT_KEY) * [**uploadWhiteList](/api/3.0.0/upload.md#uploadWhiteList) ## Type Aliases[**](<#Type Aliases>) ### [**](#UploadMode)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L4)UploadMode **UploadMode: stream | file ## Variables[**](#Variables) ### [**](#DefaultUploadFileMimeType)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/constants.ts#L36)constDefaultUploadFileMimeType **DefaultUploadFileMimeType: { .avi: string; .bmp: string; .gif: string; .gz: string; .gzip: string; .jpeg: string; .jpg: string; .mp3: string; .mp4: string; .pdf: string; .png: string; .psd: string; .svg: string; .tif: string; .tiff: string; .wbmp: string; .webp: string; .xml: string; .zip: string } = ... ### [**](#EXT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/constants.ts#L58)constEXT\_KEY **EXT\_KEY: typeof [EXT\_KEY](/api/3.0.0/upload.md#EXT_KEY) = ... ### [**](#uploadWhiteList)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/constants.ts#L1)constuploadWhiteList **uploadWhiteList: string\[] = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**uploadConfig](#uploadConfig) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [UploadConfiguration](/api/3.0.0/upload/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/configuration.ts#L25)applicationManager **applicationManager: MidwayApplicationManager ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/configuration.ts#L28)uploadConfig **uploadConfig: [UploadOptions](/api/3.0.0/upload/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/configuration.ts#L30)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/configuration.ts#L45)onStop * **onStop(): Promise\ --- # MultipartInvalidFilenameError ### Hierarchy * BadRequestError * *MultipartInvalidFilenameError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/error.ts#L4)constructor * **new MultipartInvalidFilenameError(filename: string): [MultipartInvalidFilenameError](/api/3.0.0/upload/class/MultipartInvalidFilenameError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartInvalidFileTypeError ### Hierarchy * BadRequestError * *MultipartInvalidFileTypeError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/error.ts#L10)constructor * **new MultipartInvalidFileTypeError(filename: string, currentType: string, type: string): [MultipartInvalidFileTypeError](/api/3.0.0/upload/class/MultipartInvalidFileTypeError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # UploadMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**logger](#logger) * [**match](#match) * [**uploadConfig](#uploadConfig) ### Methods * [**checkAndGetExt](#checkAndGetExt) * [**checkFileType](#checkFileType) * [**execUpload](#execUpload) * [**getUploadBoundary](#getUploadBoundary) * [**init](#init) * [**isReadableStream](#isReadableStream) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new UploadMiddleware(): [UploadMiddleware](/api/3.0.0/upload/class/UploadMiddleware.md) ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L47)ignore **ignore: IgnoreMatcher\\[] Implementation of IMiddleware.ignore ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L34)logger **logger: ILogger ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L46)match **match: IgnoreMatcher\\[] Implementation of IMiddleware.match ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L31)uploadConfig **uploadConfig: [UploadOptions](/api/3.0.0/upload/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#checkAndGetExt)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L264)checkAndGetExt * **checkAndGetExt(filename: any, whiteListMap? : Map\): string | boolean ### [**](#checkFileType)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L284)checkFileType * **checkFileType(ext: string, data: Buffer\, uploadFileMimeTypeMap? : Map\): Promise<{ current? : string; mime? : string; passed: boolean }> ### [**](#execUpload)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L85)execUpload * **execUpload(ctx: any, req: any, res: any, next: any, isExpress: any): Promise\ ### [**](#getUploadBoundary)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L222)getUploadBoundary * **getUploadBoundary(request: any): string | false ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L50)init * **init(): Promise\ ### [**](#isReadableStream)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L247)isReadableStream * **isReadableStream(req: any, isExpress: any): boolean ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L58)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/middleware.ts#L313)staticgetName * **getName(): string --- # UploadFileInfo \ ## Index[**](#Index) ### Properties * [**data](#data) * [**fieldName](#fieldName) * [**filename](#filename) * [**mimeType](#mimeType) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L55)data **data: T extends string ? string : Readable ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L53)fieldName **fieldName: string ### [**](#filename)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L52)filename **filename: string ### [**](#mimeType)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L54)mimeType **mimeType: string --- # UploadOptions ## Index[**](#Index) ### Properties * [**allowFieldsDuplication](#allowFieldsDuplication) * [**base64](#base64) * [**cleanTimeout](#cleanTimeout) * [**fileSize](#fileSize) * [**ignore](#ignore) * [**match](#match) * [**mimeTypeWhiteList](#mimeTypeWhiteList) * [**mode](#mode) * [**tmpdir](#tmpdir) * [**whitelist](#whitelist) ## Properties[**](#Properties) ### [**](#allowFieldsDuplication)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L46)optionalallowFieldsDuplication **allowFieldsDuplication? : boolean Whether to allow fields duplication, default is `false` ### [**](#base64)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L30)optionalbase64 **base64? : boolean Whether the uploaded body is base64, for example, apigw of Tencent Cloud ### [**](#cleanTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L26)optionalcleanTimeout **cleanTimeout? : number Temporary file automatic cleanup time, default is 5 minutes ### [**](#fileSize)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L14)optionalfileSize **fileSize? : string Max file size (in bytes), default is `10mb` ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L34)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Which paths to ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L38)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Match those paths with higher priority than ignore ### [**](#mimeTypeWhiteList)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L42)optionalmimeTypeWhiteList **mimeTypeWhiteList? : Record\ | (ctx: any) => string | string\[] Mime type white list ### [**](#mode)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L10)optionalmode **mode? : [UploadMode](/api/3.0.0/upload.md#UploadMode) Upload mode, default is `file` ### [**](#tmpdir)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L22)optionaltmpdir **tmpdir? : string Temporary file directory ### [**](#whitelist)[**](https://github.com/midwayjs/midway/blob/main/packages/upload/src/interface.ts#L18)optionalwhitelist **whitelist? : string\[] | (ctx: any) => string\[] The white ext file names --- # @midwayjs/validate ## Index[**](#Index) ### Classes * [**AbstractValidationPipe](/api/3.0.0/validate/class/AbstractValidationPipe.md) * [**Configuration](/api/3.0.0/validate/class/Configuration.md) * [**DecoratorValidPipe](/api/3.0.0/validate/class/DecoratorValidPipe.md) * [**DefaultValuePipe](/api/3.0.0/validate/class/DefaultValuePipe.md) * [**MidwayValidationError](/api/3.0.0/validate/class/MidwayValidationError.md) * [**ParseBoolPipe](/api/3.0.0/validate/class/ParseBoolPipe.md) * [**ParseFloatPipe](/api/3.0.0/validate/class/ParseFloatPipe.md) * [**ParseIntPipe](/api/3.0.0/validate/class/ParseIntPipe.md) * [**ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) * [**ValidateService](/api/3.0.0/validate/class/ValidateService.md) * [**ValidationPipe](/api/3.0.0/validate/class/ValidationPipe.md) ### Functions * [**OmitDto](/api/3.0.0/validate/function/OmitDto.md) * [**PickDto](/api/3.0.0/validate/function/PickDto.md) * [**Rule](/api/3.0.0/validate/function/Rule.md) * [**Valid](/api/3.0.0/validate/function/Valid.md) * [**Validate](/api/3.0.0/validate/function/Validate.md) * [**getSchema](/api/3.0.0/validate/function/getSchema.md) ### Interfaces * [**Dto](/api/3.0.0/validate/interface/Dto.md) * [**RuleOptions](/api/3.0.0/validate/interface/RuleOptions.md) * [**ValidateOptions](/api/3.0.0/validate/interface/ValidateOptions.md) --- # abstractAbstractValidationPipe ### Hierarchy * *AbstractValidationPipe* * [ValidationPipe](/api/3.0.0/validate/class/ValidationPipe.md) * [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) ### Implements * PipeTransform ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AbstractValidationPipe(): [AbstractValidationPipe](/api/3.0.0/validate/class/AbstractValidationPipe.md) ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L18)abstracttransform * **transform(value: any, options: TransformOptions\): any - Implementation of PipeTransform.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**validateService](#validateService) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ValidateConfiguration](/api/3.0.0/validate/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/configuration.ts#L32)decoratorService **decoratorService: MidwayDecoratorService ### [**](#validateService)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/configuration.ts#L35)validateService **validateService: [ValidateService](/api/3.0.0/validate/class/ValidateService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/configuration.ts#L38)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/configuration.ts#L50)onReady * **onReady(container: IMidwayContainer): Promise\ --- # DecoratorValidPipe ### Hierarchy * [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) * *DecoratorValidPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DecoratorValidPipe(): [DecoratorValidPipe](/api/3.0.0/validate/class/DecoratorValidPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L81)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # DefaultValuePipe \ ### Implements * PipeTransform\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L115)constructor * **new DefaultValuePipe\(defaultValue: R): [DefaultValuePipe](/api/3.0.0/validate/class/DefaultValuePipe.md)\ - #### Type parameters * **T** = any * **R** = any ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L116)transform * **transform(value: any, options: any): any - Implementation of PipeTransform.transform --- # MidwayValidationError ### Hierarchy * MidwayHttpError * *MidwayValidationError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/error.ts#L8)constructor * **new MidwayValidationError(message: any, status: any, cause: any): [MidwayValidationError](/api/3.0.0/validate/class/MidwayValidationError.md) - Overrides MidwayHttpError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayHttpError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayHttpError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from MidwayHttpError.status --- # ParseBoolPipe ### Hierarchy * [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) * *ParseBoolPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseBoolPipe(): [ParseBoolPipe](/api/3.0.0/validate/class/ParseBoolPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L102)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L81)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # ParseFloatPipe ### Hierarchy * [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) * *ParseFloatPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseFloatPipe(): [ParseFloatPipe](/api/3.0.0/validate/class/ParseFloatPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L109)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L81)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # ParseIntPipe ### Hierarchy * [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) * *ParseIntPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseIntPipe(): [ParseIntPipe](/api/3.0.0/validate/class/ParseIntPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L95)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L81)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # abstractParsePipe ### Hierarchy * [AbstractValidationPipe](/api/3.0.0/validate/class/AbstractValidationPipe.md) * *ParsePipe* * [DecoratorValidPipe](/api/3.0.0/validate/class/DecoratorValidPipe.md) * [ParseIntPipe](/api/3.0.0/validate/class/ParseIntPipe.md) * [ParseBoolPipe](/api/3.0.0/validate/class/ParseBoolPipe.md) * [ParseFloatPipe](/api/3.0.0/validate/class/ParseFloatPipe.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParsePipe(): [ParsePipe](/api/3.0.0/validate/class/ParsePipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L81)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from AbstractValidationPipe.validateWithSchema --- # ValidateService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidateService(): [ValidateService](/api/3.0.0/validate/class/ValidateService.md) ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/service.ts#L100)publicgetSchema * **getSchema\(ClzType: T): ObjectSchema\ - #### Type parameters * **T**: new (...args: any\[]) => any ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/service.ts#L41)publicvalidate * **validate\(ClzType: T, value: any, options? : { errorStatus? : number; locale? : string; validationOptions? : ValidationOptions }): ValidationResult\ - #### Type parameters * **T**: new (...args: any\[]) => any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/service.ts#L54)publicvalidateWithSchema * **validateWithSchema\(schema: AnySchema\, value: any, options? : { errorStatus? : number; locale? : string; validationOptions? : ValidationOptions }): ValidationResult\ - #### Type parameters * **T** --- # ValidationPipe ### Hierarchy * [AbstractValidationPipe](/api/3.0.0/validate/class/AbstractValidationPipe.md) * *ValidationPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidationPipe(): [ValidationPipe](/api/3.0.0/validate/class/ValidationPipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L75)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from AbstractValidationPipe.validateWithSchema --- # getSchema ### Callable * **getSchema\(ClzType: T): ObjectSchema\ *** * #### Type parameters * **T**: new (...args: any\[]) => any --- # OmitDto ### Callable * **OmitDto\(dto: [Dto](/api/3.0.0/validate/interface/Dto.md)\, keys: K\[]): [Dto](/api/3.0.0/validate/interface/Dto.md)\> *** * #### Type parameters * **T** * **K**: string | number | symbol --- # PickDto ### Callable * **PickDto\(dto: [Dto](/api/3.0.0/validate/interface/Dto.md)\, keys: K\[]): [Dto](/api/3.0.0/validate/interface/Dto.md)\> *** * #### Type parameters * **T** * **K**: string | number | symbol --- # Rule ### Callable * **Rule(rule: AnySchema\): PropertyDecorator & ClassDecorator * **Rule(rule: new (...args: any\[]) => any, options? : [RuleOptions](/api/3.0.0/validate/interface/RuleOptions.md)): PropertyDecorator & ClassDecorator --- # Valid ### Callable * **Valid(schemaOrPipes? : PipeUnionTransform\[] | AnySchema\, pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Validate ### Callable * **Validate(options? : [ValidateOptions](/api/3.0.0/validate/interface/ValidateOptions.md)): (target: any, methodName: any, descriptor: any) => void --- # Dto \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/dtoHelper.ts#L4)constructor * **new Dto(): T --- # RuleOptions * **@deprecated** ## Index[**](#Index) ### Properties * [**max](#max) * [**min](#min) * [**required](#required) ## Properties[**](#Properties) ### [**](#max)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/rule.ts#L15)optionalmax **max? : number ### [**](#min)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/rule.ts#L14)optionalmin **min? : number ### [**](#required)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/rule.ts#L13)optionalrequired **required? : boolean --- # ValidateOptions ## Index[**](#Index) ### Properties * [**errorStatus](#errorStatus) * [**locale](#locale) * [**validationOptions](#validationOptions) ## Properties[**](#Properties) ### [**](#errorStatus)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/validate.ts#L6)optionalerrorStatus **errorStatus? : number ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/validate.ts#L7)optionallocale **locale? : string ### [**](#validationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/validate/src/decorator/validate.ts#L8)optionalvalidationOptions **validationOptions? : ValidationOptions --- # @midwayjs/view ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/view/class/Configuration.md) * [**ContextView](/api/3.0.0/view/class/ContextView.md) * [**ViewManager](/api/3.0.0/view/class/ViewManager.md) ### Interfaces * [**IViewEngine](/api/3.0.0/view/interface/IViewEngine.md) * [**RenderOptions](/api/3.0.0/view/interface/RenderOptions.md) --- # @midwayjs/view-ejs ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/view-ejs/class/Configuration.md) * [**EjsView](/api/3.0.0/view-ejs/class/EjsView.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**viewManager](#viewManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewEJSConfiguration](/api/3.0.0/view-ejs/class/Configuration.md) ## Properties[**](#Properties) ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/configuration.ts#L19)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # EjsView ### Implements * IViewEngine ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ejsConfig](#ejsConfig) * [**viewManager](#viewManager) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new EjsView(): [EjsView](/api/3.0.0/view-ejs/class/EjsView.md) ## Properties[**](#Properties) ### [**](#ejsConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/view.ts#L8)ejsConfig **ejsConfig: any ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/view.ts#L11)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/view.ts#L25)render * **render(name: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.render ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/main/packages/view-ejs/src/view.ts#L41)renderString * **renderString(tpl: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.renderString --- # @midwayjs/view-nunjucks ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/view-nunjucks/class/Configuration.md) * [**NunjucksEnvironment](/api/3.0.0/view-nunjucks/class/NunjucksEnvironment.md) * [**NunjucksView](/api/3.0.0/view-nunjucks/class/NunjucksView.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**viewManager](#viewManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewNunjucksConfiguration](/api/3.0.0/view-nunjucks/class/Configuration.md) ## Properties[**](#Properties) ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/configuration.ts#L19)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # NunjucksEnvironment ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addFilter](#addFilter) * [**addGlobal](#addGlobal) * [**getFilter](#getFilter) * [**hasExtension](#hasExtension) * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NunjucksEnvironment(): [NunjucksEnvironment](/api/3.0.0/view-nunjucks/class/NunjucksEnvironment.md) ## Methods[**](#Methods) ### [**](#addFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L101)addFilter * **addFilter(name: string, callback: (...args: any\[]) => string): any ### [**](#addGlobal)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L113)addGlobal * **addGlobal(name: string, value: any): any ### [**](#getFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L105)getFilter * **getFilter(name: string): any ### [**](#hasExtension)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L109)hasExtension * **hasExtension(name: string): boolean ### [**](#render)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L79)render * **render(name: string, context? : Record\, callback? : TemplateCallback\): any ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/engine.ts#L87)renderString * **renderString(tpl: string, context? : Record\, options? : RenderOptions, callback? : TemplateCallback\): any --- # NunjucksView ### Implements * IViewEngine ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**nunjucks](#nunjucks) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NunjucksView(): [NunjucksView](/api/3.0.0/view-nunjucks/class/NunjucksView.md) ## Properties[**](#Properties) ### [**](#nunjucks)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/view.ts#L8)nunjucks **nunjucks: [NunjucksEnvironment](/api/3.0.0/view-nunjucks/class/NunjucksEnvironment.md) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/view.ts#L10)render * **render(name: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.render ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/main/packages/view-nunjucks/src/view.ts#L24)renderString * **renderString(tpl: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.renderString --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewConfiguration](/api/3.0.0/view/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/configuration.ts#L22)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/configuration.ts#L24)onReady * **onReady(container: any): Promise\ --- # ContextView View instance for each request. It will find the view engine, and render it. The view engine should be registered in [ViewManager](/api/3.0.0/view/class/ViewManager.md). ### Implements * [IViewEngine](/api/3.0.0/view/interface/IViewEngine.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) * [**viewConfig](#viewConfig) * [**viewManager](#viewManager) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ContextView(): [ContextView](/api/3.0.0/view/class/ContextView.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/contextView.ts#L22)ctx **ctx: any ### [**](#viewConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/contextView.ts#L19)viewConfig **viewConfig: any ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/contextView.ts#L16)viewManager **viewManager: [ViewManager](/api/3.0.0/view/class/ViewManager.md) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/contextView.ts#L24)render * **render(name: string, locals? : Record\, options? : [RenderOptions](/api/3.0.0/view/interface/RenderOptions.md)): Promise\ - Implementation of IViewEngine.render Render a file by view engine, then set to body ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/contextView.ts#L54)renderString * **renderString(tpl: string, locals? : Record\, options? : [RenderOptions](/api/3.0.0/view/interface/RenderOptions.md)): Promise\ - Implementation of IViewEngine.renderString Render a template string by view engine --- # ViewManager ### Hierarchy * Map * *ViewManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addLocals](#addLocals) * [**findEngine](#findEngine) * [**getLocals](#getLocals) * [**resolve](#resolve) * [**use](#use) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L49)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)externalconstructor * **new ViewManager(): [ViewManager](/api/3.0.0/view/class/ViewManager.md) * **new ViewManager(): [ViewManager](/api/3.0.0/view/class/ViewManager.md) - Inherited from Map.constructor ## Methods[**](#Methods) ### [**](#addLocals)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/viewManager.ts#L104)publicaddLocals * **addLocals(key: any, localValue: any): void - add a global data for all views ### [**](#findEngine)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/viewManager.ts#L115)publicfindEngine * **findEngine(ext: string): string ### [**](#getLocals)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/viewManager.ts#L111)publicgetLocals * **getLocals(): {} - get global locals data ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/viewManager.ts#L80)publicresolve * **resolve(name: string): Promise\ - Resolve the path based on the given name, if the name is `user.html` and root is `view` (by default), it will return `view/user.html` ### [**](#use)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/viewManager.ts#L56)publicuse * **use(name: string, viewEngine: new (...args: any\[]) => [IViewEngine](/api/3.0.0/view/interface/IViewEngine.md)): void - This method can register view engine. You can define a view engine class contains two method, `render` and `renderString` ``` class View { render() {} renderString() {} } ``` --- # IViewEngine ### Implemented by * [ContextView](/api/3.0.0/view/class/ContextView.md) ## Index[**](#Index) ### Methods * [**render](#render) * [**renderString](#renderString) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L16)render * **render(name: string, locals? : Record\, options? : [RenderOptions](/api/3.0.0/view/interface/RenderOptions.md)): Promise\ - Render a file by view engine, then set to body ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L25)renderString * **renderString(tpl: string, locals? : Record\, options? : [RenderOptions](/api/3.0.0/view/interface/RenderOptions.md)): Promise\ - Render a template string by view engine --- # RenderOptions ## Index[**](#Index) ### Properties * [**locals](#locals) * [**name](#name) * [**root](#root) * [**viewEngine](#viewEngine) ## Properties[**](#Properties) ### [**](#locals)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L4)optionallocals **locals? : Record\ ### [**](#name)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L2)optionalname **name? : string ### [**](#root)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L3)optionalroot **root? : string ### [**](#viewEngine)[**](https://github.com/midwayjs/midway/blob/main/packages/view/src/interface.ts#L5)optionalviewEngine **viewEngine? : string --- # @midwayjs/web ## Index[**](#Index) ### Classes * [**Agent](/api/3.0.0/web/class/Agent.md) * [**Application](/api/3.0.0/web/class/Application.md) * [**Configuration](/api/3.0.0/web/class/Configuration.md) * [**Framework](/api/3.0.0/web/class/Framework.md) ### Functions * [**AgentApp](/api/3.0.0/web/function/AgentApp.md) * [**RunInEggAgent](/api/3.0.0/web/function/RunInEggAgent.md) * [**createAgentWorkerLoader](/api/3.0.0/web/function/createAgentWorkerLoader.md) * [**createAppWorkerLoader](/api/3.0.0/web/function/createAppWorkerLoader.md) * [**createEggAgent](/api/3.0.0/web/function/createEggAgent.md) * [**createEggApplication](/api/3.0.0/web/function/createEggApplication.md) * [**startCluster](/api/3.0.0/web/function/startCluster.md) ### Interfaces * [**Context](/api/3.0.0/web/interface/Context.md) * [**IMidwayWebBaseApplication](/api/3.0.0/web/interface/IMidwayWebBaseApplication.md) * [**IMidwayWebConfigurationOptions](/api/3.0.0/web/interface/IMidwayWebConfigurationOptions.md) * [**IWebMiddleware](/api/3.0.0/web/interface/IWebMiddleware.md) * [**State](/api/3.0.0/web/interface/State.md) ### Type Aliases * [**IMidwayWebApplication](/api/3.0.0/web.md#IMidwayWebApplication) * [**IMidwayWebContext](/api/3.0.0/web.md#IMidwayWebContext) * [**IMidwayWebNext](/api/3.0.0/web.md#IMidwayWebNext) * [**MidwayWebMiddleware](/api/3.0.0/web.md#MidwayWebMiddleware) * [**NextFunction](/api/3.0.0/web.md#NextFunction) ### Variables * [**EGG\_AGENT\_APP\_KEY](/api/3.0.0/web.md#EGG_AGENT_APP_KEY) * [**RUN\_IN\_AGENT\_KEY](/api/3.0.0/web.md#RUN_IN_AGENT_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#IMidwayWebApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L30)IMidwayWebApplication **IMidwayWebApplication: IMidwayApplication<[Context](/api/3.0.0/web/interface/Context.md), EggApplication & [IMidwayWebBaseApplication](/api/3.0.0/web/interface/IMidwayWebBaseApplication.md)> * **@deprecated** since version 3.0.0 Please use Application from '@midwayjs/web' ### [**](#IMidwayWebContext)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L36)IMidwayWebContext **IMidwayWebContext\: IMidwayContext\> * **@deprecated** since version 3.0.0 Please use Context from '@midwayjs/web' *** #### Type parameters * **ResponseBodyT** = unknown ### [**](#IMidwayWebNext)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L75)IMidwayWebNext **IMidwayWebNext: BaseNextFunction * **@deprecated** since version 3.0.0 Please use NextFunction from '@midwayjs/web' ### [**](#MidwayWebMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L136)MidwayWebMiddleware **MidwayWebMiddleware: Middleware<[State](/api/3.0.0/web/interface/State.md), [Context](/api/3.0.0/web/interface/Context.md)> * **@deprecated** since version 3.0.0 Please use IMiddleware from '@midwayjs/core' ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L76)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#EGG_AGENT_APP_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L14)constEGG\_AGENT\_APP\_KEY **EGG\_AGENT\_APP\_KEY: egg\_agent\_app = 'egg\_agent\_app' ### [**](#RUN_IN_AGENT_KEY)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L13)constRUN\_IN\_AGENT\_KEY **RUN\_IN\_AGENT\_KEY: egg:run\_in\_agent = 'egg:run\_in\_agent' --- # @midwayjs/express ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/web-express/class/Configuration.md) * [**Framework](/api/3.0.0/web-express/class/Framework.md) * [**MidwayExpressMiddlewareService](/api/3.0.0/web-express/class/MidwayExpressMiddlewareService.md) ### Functions * [**wrapAsyncHandler](/api/3.0.0/web-express/function/wrapAsyncHandler.md) * [**wrapMiddleware](/api/3.0.0/web-express/function/wrapMiddleware.md) ### Interfaces * [**Context](/api/3.0.0/web-express/interface/Context.md) * [**IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md) * [**IMidwayExpressConfigurationOptions](/api/3.0.0/web-express/interface/IMidwayExpressConfigurationOptions.md) ### Type Aliases * [**Application](/api/3.0.0/web-express.md#Application) * [**IMidwayExpressContext](/api/3.0.0/web-express.md#IMidwayExpressContext) * [**IMidwayExpressMiddleware](/api/3.0.0/web-express.md#IMidwayExpressMiddleware) * [**IMidwayExpressRequest](/api/3.0.0/web-express.md#IMidwayExpressRequest) * [**NextFunction](/api/3.0.0/web-express.md#NextFunction) * [**Response](/api/3.0.0/web-express.md#Response) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L90)Application **Application: [IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md) ### [**](#IMidwayExpressContext)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L29)IMidwayExpressContext **IMidwayExpressContext: [Context](/api/3.0.0/web-express/interface/Context.md) * **@deprecated** use Context ### [**](#IMidwayExpressMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L30)IMidwayExpressMiddleware **IMidwayExpressMiddleware: IMiddleware<[Context](/api/3.0.0/web-express/interface/Context.md), ExpressResponse, ExpressNextFunction> ### [**](#IMidwayExpressRequest)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L25)IMidwayExpressRequest **IMidwayExpressRequest: [Context](/api/3.0.0/web-express/interface/Context.md) * **@deprecated** use Context ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L19)NextFunction **NextFunction: ExpressNextFunction ### [**](#Response)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L18)Response **Response: ExpressResponse --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**decoratorService](#decoratorService) * [**expressFramework](#expressFramework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ExpressConfiguration](/api/3.0.0/web-express/class/Configuration.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/configuration.ts#L33)configService **configService: MidwayConfigService ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/configuration.ts#L27)decoratorService **decoratorService: MidwayDecoratorService ### [**](#expressFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/configuration.ts#L30)expressFramework **expressFramework: [MidwayExpressFramework](/api/3.0.0/web-express/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/configuration.ts#L36)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/configuration.ts#L49)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md), [Context](/api/3.0.0/web-express/interface/Context.md), [IMidwayExpressConfigurationOptions](/api/3.0.0/web-express/interface/IMidwayExpressConfigurationOptions.md), Response, NextFunction> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getPort](#getPort) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) * [**useRouterMiddleware](#useRouterMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayExpressFramework](/api/3.0.0/web-express/class/Framework.md) - Inherited from BaseFramework< IMidwayExpressApplication, Context, IMidwayExpressConfigurationOptions, Response, NextFunction >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L43)publicapp **app: [IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayExpressConfigurationOptions](/api/3.0.0/web-express/interface/IMidwayExpressConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/web-express/interface/Context.md), Response\>, NextFunction> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L52)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L374)publicapplyMiddleware * **applyMiddleware\(): Promise\> - Overrides BaseFramework.applyMiddleware #### Type parameters * **Response** * **NextFunction** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L387)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L48)configure * **configure(): [IMidwayExpressConfigurationOptions](/api/3.0.0/web-express/interface/IMidwayExpressConfigurationOptions.md) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L403)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L215)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/web-express/interface/Context.md), Response\>, NextFunction> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getPort)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L399)publicgetPort * **getPort(): string ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L395)publicgetServer * **getServer(): Server ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayExpressFramework](/api/3.0.0/web-express/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L287)publicloadMidwayController * **loadMidwayController(): Promise<{ middleware: any; prefix: string }\[]> ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L90)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/web-express/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/web-express/interface/Context.md), Response\>, NextFunction>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/web-express/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/web-express/interface/Context.md), Response\>, NextFunction>): void - Inherited from BaseFramework.useMiddleware ### [**](#useRouterMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/framework.ts#L370)publicuseRouterMiddleware * **useRouterMiddleware(routerPath: string, middleware: any): void --- # MidwayExpressMiddlewareService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**compose](#compose) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/middlewareService.ts#L31)constructor * **new MidwayExpressMiddlewareService(applicationContext: IMidwayContainer): [MidwayExpressMiddlewareService](/api/3.0.0/web-express/class/MidwayExpressMiddlewareService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/middlewareService.ts#L31)readonlyapplicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#compose)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/middlewareService.ts#L33)compose * **compose(middleware: (string | CommonMiddleware<[Context](/api/3.0.0/web-express/interface/Context.md), Response\>, NextFunction>)\[], app: [IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md), name? : string): Promise<{ \_name: string }> --- # wrapAsyncHandler ### Callable * **wrapAsyncHandler(fn: any): any --- # wrapMiddleware ### Callable * **wrapMiddleware(mw: (context: any, next: any, options? : any) => any | (req: any, res: any, next: any) => any, options: any): (context: any, next: any, options? : any) => any --- # Context ### Hierarchy * Request * *Context* ## Index[**](#Index) ### Properties * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from Request.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from Request.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from Request.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from Request.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from Request.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from Request.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from Request.setAttr Set value to app attribute map --- # IMidwayExpressApplication ### Hierarchy * IMidwayApplication<[Context](/api/3.0.0/web-express/interface/Context.md), ExpressApplication> * *IMidwayExpressApplication* ### Callable * **IMidwayExpressApplication(req: IncomingMessage | Request\>, res: ServerResponse\ | Response\, number>): any * **IMidwayExpressApplication(req: Request\>, res: Response\, number>, next: NextFunction): void *** * Express instance itself is a request handler, which could be invoked without third argument. ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L840)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L830)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/3.0.0/web-express/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L821)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L780)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L801)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L851)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L776)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L806)getConfig * **getConfig(key? : string): any - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L815)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L784)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L788)getFramework * **getFramework(): IMidwayFramework<[IMidwayExpressApplication](/api/3.0.0/web-express/interface/IMidwayExpressApplication.md), [Context](/api/3.0.0/web-express/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getFrameworkType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L793)getFrameworkType * **getFrameworkType(): [FrameworkType](/api/3.0.0/decorator/class/FrameworkType.md) - Inherited from IMidwayApplication.getFrameworkType * **@deprecated** Get current framework type in MidwayFrameworkType enum ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L811)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L47)getMiddleware * **getMiddleware\(): ContextMiddlewareManager<[Context](/api/3.0.0/web-express/interface/Context.md), Response, NextFunction> - Overrides IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **Response** * **NextFunction** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L874)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L797)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L825)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L846)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L835)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L865)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/3.0.0/web-express/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L870)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/3.0.0/web-express/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L37)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L42)useMiddleware * **useMiddleware\(routerPath: string, ...middleware: FunctionMiddleware<[Context](/api/3.0.0/web-express/interface/Context.md), Response, NextFunction>\[]): void * **useMiddleware\(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/web-express/interface/Context.md), Response, NextFunction>): void - Overrides IMidwayApplication.useMiddleware mount router and middleware *** #### Type parameters * **Response** * **NextFunction** --- # IMidwayExpressConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayExpressConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**keys](#keys) * [**logger](#logger) * [**port](#port) * [**serverOptions](#serverOptions) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L75)optionalca **ca? : string | Buffer\ | (string | Buffer\)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L71)optionalcert **cert? : string | Buffer\ | (string | Buffer\)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L83)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L63)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L79)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L67)optionalkey **key? : string | Buffer\ | (Object | Buffer\)\[] https key ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L55)optionalkeys **keys? : string | string\[] session or cookie secret key ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#port)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L59)optionalport **port? : number application http port ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web-express/src/interface.ts#L87)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options --- # @midwayjs/koa ## Index[**](#Index) ### Classes * [**BodyParserMiddleware](/api/3.0.0/web-koa/class/BodyParserMiddleware.md) * [**Configuration](/api/3.0.0/web-koa/class/Configuration.md) * [**Framework](/api/3.0.0/web-koa/class/Framework.md) * [**SiteFileMiddleware](/api/3.0.0/web-koa/class/SiteFileMiddleware.md) ### Interfaces * [**BodyParserOptions](/api/3.0.0/web-koa/interface/BodyParserOptions.md) * [**Context](/api/3.0.0/web-koa/interface/Context.md) * [**IMidwayKoaConfigurationOptions](/api/3.0.0/web-koa/interface/IMidwayKoaConfigurationOptions.md) * [**IWebMiddleware](/api/3.0.0/web-koa/interface/IWebMiddleware.md) * [**State](/api/3.0.0/web-koa/interface/State.md) ### Type Aliases * [**Application](/api/3.0.0/web-koa.md#Application) * [**IMidwayKoaApplication](/api/3.0.0/web-koa.md#IMidwayKoaApplication) * [**IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext) * [**IMidwayKoaNext](/api/3.0.0/web-koa.md#IMidwayKoaNext) * [**MiddlewareParamArray](/api/3.0.0/web-koa.md#MiddlewareParamArray) * [**NextFunction](/api/3.0.0/web-koa.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L117)Application **Application: [IMidwayKoaApplication](/api/3.0.0/web-koa.md#IMidwayKoaApplication) ### [**](#IMidwayKoaApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L11)IMidwayKoaApplication **IMidwayKoaApplication: IMidwayApplication<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), koa<[State](/api/3.0.0/web-koa/interface/State.md), [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext)> & { generateController: any; generateMiddleware: any; getPort: any }> ### [**](#IMidwayKoaContext)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L10)IMidwayKoaContext **IMidwayKoaContext: IMidwayContext\ ### [**](#IMidwayKoaNext)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L31)IMidwayKoaNext **IMidwayKoaNext: Next * **@deprecated** use NextFunction definition ### [**](#MiddlewareParamArray)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L109)MiddlewareParamArray **MiddlewareParamArray: Middleware\\[] ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L32)NextFunction **NextFunction: Next --- # BodyParserMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**bodyparserConfig](#bodyparserConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BodyParserMiddleware(): [BodyParserMiddleware](/api/3.0.0/web-koa/class/BodyParserMiddleware.md) ## Properties[**](#Properties) ### [**](#bodyparserConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/bodyparser.middleware.ts#L7)bodyparserConfig **bodyparserConfig: any ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/bodyparser.middleware.ts#L9)resolve * **resolve(): any ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/bodyparser.middleware.ts#L16)staticgetName * **getName(): string --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**decoratorService](#decoratorService) * [**koaFramework](#koaFramework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [KoaConfiguration](/api/3.0.0/web-koa/class/Configuration.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/configuration.ts#L33)configService **configService: MidwayConfigService ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/configuration.ts#L27)decoratorService **decoratorService: MidwayDecoratorService ### [**](#koaFramework)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/configuration.ts#L30)koaFramework **koaFramework: [MidwayKoaFramework](/api/3.0.0/web-koa/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/configuration.ts#L36)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/configuration.ts#L50)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayKoaApplication](/api/3.0.0/web-koa.md#IMidwayKoaApplication), [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), [IMidwayKoaConfigurationOptions](/api/3.0.0/web-koa/interface/IMidwayKoaConfigurationOptions.md), Next> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**generateController](#generateController) * [**generateMiddleware](#generateMiddleware) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getPort](#getPort) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayKoaFramework](/api/3.0.0/web-koa/class/Framework.md) - Inherited from BaseFramework< IMidwayKoaApplication, IMidwayKoaContext, IMidwayKoaConfigurationOptions, Next >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayKoaApplication](/api/3.0.0/web-koa.md#IMidwayKoaApplication) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayKoaConfigurationOptions](/api/3.0.0/web-koa/interface/IMidwayKoaConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), Next, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L67)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L349)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L63)configure * **configure(): [IMidwayKoaConfigurationOptions](/api/3.0.0/web-koa/interface/IMidwayKoaConfigurationOptions.md) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#generateController)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L248)publicgenerateController * **generateController(routeInfo: RouterInfo): Middleware\ - wrap controller string to middleware function ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L258)publicgenerateMiddleware * **generateMiddleware(middlewareId: any): Promise\> - - **@deprecated** ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [IMidwayKoaApplication](/api/3.0.0/web-koa.md#IMidwayKoaApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L362)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L358)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), Next, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getPort)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L370)publicgetPort * **getPort(): string ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L366)publicgetServer * **getServer(): Server\ ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayKoaFramework](/api/3.0.0/web-koa/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L237)loadMidwayController * **loadMidwayController(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L265)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L380)publicuseFilter * **useFilter(Filter: CommonFilterUnion<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), Next, unknown>): void - Overrides BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/framework.ts#L374)publicuseMiddleware * **useMiddleware(Middleware: CommonMiddlewareUnion<[IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext), Next, unknown>): void - Overrides BaseFramework.useMiddleware --- # SiteFileMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**siteFileConfig](#siteFileConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SiteFileMiddleware(): [SiteFileMiddleware](/api/3.0.0/web-koa/class/SiteFileMiddleware.md) ## Properties[**](#Properties) ### [**](#siteFileConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/fav.middleware.ts#L9)siteFileConfig **siteFileConfig: any ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/fav.middleware.ts#L11)resolve * **resolve(): (ctx: any, next: any) => Promise\ ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/middleware/fav.middleware.ts#L45)staticgetName * **getName(): string --- # BodyParserOptions ## Index[**](#Index) ### Properties * [**detectJSON](#detectJSON) * [**enable](#enable) * [**enableTypes](#enableTypes) * [**encoding](#encoding) * [**extendTypes](#extendTypes) * [**formLimit](#formLimit) * [**jsonLimit](#jsonLimit) * [**onerror](#onerror) * [**strict](#strict) * [**textLimit](#textLimit) * [**xmlLimit](#xmlLimit) ## Properties[**](#Properties) ### [**](#detectJSON)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L164)optionaldetectJSON **detectJSON? : (ctx: [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext)) => boolean ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L124)optionalenable **enable? : boolean ### [**](#enableTypes)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L128)optionalenableTypes **enableTypes? : string\[] parser will only parse when request type hits enableTypes, default is \['json', 'form']. ### [**](#encoding)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L133)optionalencoding **encoding? : string requested encoding. Default is utf-8 by co-body ### [**](#extendTypes)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L169)optionalextendTypes **extendTypes? : { form? : string | string\[]; json? : string | string\[]; text? : string | string\[] } support extend types ### [**](#formLimit)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L139)optionalformLimit **formLimit? : string limit of the urlencoded body. If the body ends up being larger than this limit a 413 error code is returned. Default is 56kb ### [**](#jsonLimit)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L144)optionaljsonLimit **jsonLimit? : string limit of the json body. Default is 1mb ### [**](#onerror)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L178)optionalonerror **onerror? : (err: Error, ctx: [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext)) => void ### [**](#strict)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L159)optionalstrict **strict? : boolean when set to true, JSON parser will only accept arrays and objects. Default is true ### [**](#textLimit)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L149)optionaltextLimit **textLimit? : string limit of the text body. Default is 1mb. ### [**](#xmlLimit)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L154)optionalxmlLimit **xmlLimit? : string limit of the xml body. Default is 1mb. --- # Context ### Hierarchy * [IMidwayKoaContext](/api/3.0.0/web-koa.md#IMidwayKoaContext) * *Context* ## Index[**](#Index) ### Properties * [**app](#app) * [**cookies](#cookies) * [**forward](#forward) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**state](#state) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/index.d.ts#L43)app **app: IMidwayKoaApplication Inherited from IMidwayKoaContext.app ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/index.d.ts#L42)cookies **cookies: Cookies Inherited from IMidwayKoaContext.cookies ### [**](#forward)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/index.d.ts#L44)forward **forward: (url: string) => void Inherited from IMidwayKoaContext.forward ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayKoaContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayKoaContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayKoaContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L120)state **state: [State](/api/3.0.0/web-koa/interface/State.md) Overrides IMidwayKoaContext.state ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayKoaContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayKoaContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayKoaContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayKoaContext.setAttr Set value to app attribute map --- # IMidwayKoaConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayKoaConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**keys](#keys) * [**listenOptions](#listenOptions) * [**logger](#logger) * [**maxIpsCount](#maxIpsCount) * [**port](#port) * [**proxy](#proxy) * [**proxyIpHeader](#proxyIpHeader) * [**queryParseMode](#queryParseMode) * [**queryParseOptions](#queryParseOptions) * [**serverOptions](#serverOptions) * [**serverTimeout](#serverTimeout) * [**subdomainOffset](#subdomainOffset) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L58)optionalca **ca? : string | Buffer\ | (string | Buffer\)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L54)optionalcert **cert? : string | Buffer\ | (string | Buffer\)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L66)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L46)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L62)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L50)optionalkey **key? : string | Buffer\ | (Object | Buffer\)\[] https key ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L38)optionalkeys **keys? : string\[] cookies sign keys ### [**](#listenOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L106)optionallistenOptions **listenOptions? : ListenOptions listen options ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#maxIpsCount)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L82)optionalmaxIpsCount **maxIpsCount? : number Max IPs read from proxy IP header, default to 0 (means infinity) ### [**](#port)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L42)optionalport **port? : number application http port ### [**](#proxy)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L70)optionalproxy **proxy? : boolean Trust proxy headers ### [**](#proxyIpHeader)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L78)optionalproxyIpHeader **proxyIpHeader? : string Proxy IP header, defaults to X-Forwarded-For ### [**](#queryParseMode)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L94)optionalqueryParseMode **queryParseMode? : strict | extended | first qs mode ### [**](#queryParseOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L98)optionalqueryParseOptions **queryParseOptions? : IParseOptions\ qs options ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L102)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options ### [**](#serverTimeout)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L90)optionalserverTimeout **serverTimeout? : number server timeout in milliseconds, default to 2 minutes. for special request, just use `ctx.req.setTimeout(ms)` * **@see** ### [**](#subdomainOffset)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L74)optionalsubdomainOffset **subdomainOffset? : number Subdomain offset --- # IWebMiddleware ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/web-koa/src/interface.ts#L114)resolve * **resolve(): Middleware\ --- # State ### Hierarchy * DefaultState * *State* --- # Agent ### Hierarchy * BaseEggAgent * *Agent* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**\[EGG\_LOADER\]](#\[EGG_LOADER]) * [**\[EGG\_PATH\]](#\[EGG_PATH]) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Agent(): [EggAgent](/api/3.0.0/web/class/Agent.md) - Inherited from BaseEggAgent.constructor ## Accessors[**](#Accessors) ### [**](#\[EGG_LOADER])[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/application.ts#L31)\[EGG\_LOADER] * **get \[EGG\_LOADER]\(): any ### [**](#\[EGG_PATH])[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/application.ts#L35)\[EGG\_PATH] * **get \[EGG\_PATH]\(): string --- # Application ### Hierarchy * BaseEggApplication * *Application* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**\[EGG\_LOADER\]](#\[EGG_LOADER]) * [**\[EGG\_PATH\]](#\[EGG_PATH]) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Application(): [EggApplication](/api/3.0.0/web/class/Application.md) - Inherited from BaseEggApplication.constructor ## Accessors[**](#Accessors) ### [**](#\[EGG_LOADER])[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/application.ts#L21)\[EGG\_LOADER] * **get \[EGG\_LOADER]\(): any ### [**](#\[EGG_PATH])[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/application.ts#L25)\[EGG\_PATH] * **get \[EGG\_PATH]\(): string --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**appDir](#appDir) * [**baseDir](#baseDir) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onServerReady](#onServerReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [EggConfiguration](/api/3.0.0/web/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L25)app **app: [IMidwayWebApplication](/api/3.0.0/web.md#IMidwayWebApplication) ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L22)appDir **appDir: any ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L19)baseDir **baseDir: any ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L28)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L31)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L44)onReady * **onReady(): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L53)onServerReady * **onServerReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/configuration.ts#L60)onStop * **onStop(): Promise\ --- # Framework ### Hierarchy * BaseFramework\ * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initSingleProcessEgg](#initSingleProcessEgg) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**overwriteApplication](#overwriteApplication) * [**run](#run) * [**runGuard](#runGuard) * [**setContextLoggerClass](#setContextLoggerClass) * [**setNamespace](#setNamespace) * [**setServer](#setServer) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayWebFramework](/api/3.0.0/web/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwayWebConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: Application Inherited from BaseFramework.app ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L62)appDir **appDir: any ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayWebConfigurationOptions](/api/3.0.0/web/interface/IMidwayWebConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/web/interface/Context.md)\, unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L95)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/web/interface/Context.md)\, R, N>): Promise\, R, N>> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L328)beforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L64)publicconfigure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L321)publicgenerateMiddleware * **generateMiddleware(middlewareId: any): Promise\ ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): Application - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L84)getFrameworkName * **getFrameworkName(): string - Inherited from BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L219)getFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L301)publicgetLogger * **getLogger(name? : string): any - Overrides BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/web/interface/Context.md)\, unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayWebFramework](/api/3.0.0/web/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initSingleProcessEgg)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L72)initSingleProcessEgg * **initSingleProcessEgg(): Promise\ ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L204)loadMidwayController * **loadMidwayController(): Promise\ ### [**](#overwriteApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L149)overwriteApplication * **overwriteApplication(processType: any): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L223)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/web/interface/Context.md)\, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setContextLoggerClass)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L308)publicsetContextLoggerClass * **setContextLoggerClass(): void ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#setServer)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/framework/web.ts#L338)publicsetServer * **setServer(server: any): void ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/web/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/web/interface/Context.md)\>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/web/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # AgentApp ### Callable * **AgentApp(): PropertyDecorator --- # createAgentWorkerLoader ### Callable * **createAgentWorkerLoader(): any --- # createAppWorkerLoader ### Callable * **createAppWorkerLoader(): any --- # createEggAgent ### Callable * **createEggAgent(): any --- # createEggApplication ### Callable * **createEggApplication(): any --- # RunInEggAgent ### Callable * **RunInEggAgent(): ClassDecorator --- # startCluster ### Callable * **startCluster(serverConfig: any, callback? : any): any --- # Context \ * **@deprecated** since version 3.0.0 Please use Context from '@midwayjs/web' ### Hierarchy * [IMidwayWebContext](/api/3.0.0/web.md#IMidwayWebContext)\ * *Context* ## Index[**](#Index) ### Properties * [**forward](#forward) * [**requestContext](#requestContext) * [**session](#session) * [**startTime](#startTime) * [**state](#state) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#forward)[**](https://github.com/midwayjs/midway/blob/main/packages/web/index.d.ts#L33)forward **forward: (url: string) => void Inherited from IMidwayWebContext.forward ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayWebContext.requestContext Custom properties. ### [**](#session)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L38)session **session: { length: number; maxAge: number | session; populated: boolean; manuallyCommit: any; save: any; toJSON: any } ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayWebContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L69)state **state: [State](/api/3.0.0/web/interface/State.md) Overrides IMidwayWebContext.state ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayWebContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayWebContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayWebContext.setAttr Set value to app attribute map --- # IMidwayWebBaseApplication ## Index[**](#Index) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getLogger](#getLogger) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L19)applicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L23)createLogger * **createLogger(name: string, options: LoggerOptions): ILogger ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L22)optionalgenerateMiddleware * **generateMiddleware(middlewareId: any): Promise\>> ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L21)getCoreLogger * **getCoreLogger(): ILogger ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L20)getLogger * **getLogger(name? : string): ILogger --- # IMidwayWebConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayWebConfigurationOptions* ## Index[**](#Index) ### Properties * [**app](#app) * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalConfig](#globalConfig) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**logger](#logger) * [**plugins](#plugins) * [**port](#port) * [**processType](#processType) * [**queryParseMode](#queryParseMode) * [**queryParseOptions](#queryParseOptions) * [**serverOptions](#serverOptions) * [**typescript](#typescript) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L79)optionalapp **app? : [IMidwayWebApplication](/api/3.0.0/web.md#IMidwayWebApplication) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L904)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L109)optionalca **ca? : string | Buffer\ | (string | Buffer\)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L105)optionalcert **cert? : string | Buffer\ | (string | Buffer\)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L905)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L906)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalConfig)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L89)optionalglobalConfig **globalConfig? : any ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L117)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L97)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L113)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L101)optionalkey **key? : string | Buffer\ | (Object | Buffer\)\[] https key ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L903)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#plugins)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L80)optionalplugins **plugins? : {} ### [**](#port)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L93)optionalport **port? : number application http port ### [**](#processType)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L88)optionalprocessType **processType? : agent | application ### [**](#queryParseMode)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L121)optionalqueryParseMode **queryParseMode? : simple | extended http query parser mode, default is extended ### [**](#queryParseOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L125)optionalqueryParseOptions **queryParseOptions? : IParseOptions http query parse options, used when 'simple' mode is used ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L129)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options ### [**](#typescript)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L87)optionaltypescript **typescript? : boolean --- # IWebMiddleware * **@deprecated** since version 3.0.0 Please use IMiddleware from '@midwayjs/core' ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/main/packages/web/src/interface.ts#L143)resolve * **resolve(): [MidwayWebMiddleware](/api/3.0.0/web.md#MidwayWebMiddleware) --- # State ### Hierarchy * DefaultState * *State* --- # @midwayjs/ws ## Index[**](#Index) ### Classes * [**Configuration](/api/3.0.0/ws/class/Configuration.md) * [**Framework](/api/3.0.0/ws/class/Framework.md) ### Interfaces * [**Context](/api/3.0.0/ws/interface/Context.md) ### Type Aliases * [**Application](/api/3.0.0/ws.md#Application) * [**IMidwayWSApplication](/api/3.0.0/ws.md#IMidwayWSApplication) * [**IMidwayWSConfigurationOptions](/api/3.0.0/ws.md#IMidwayWSConfigurationOptions) * [**IMidwayWSContext](/api/3.0.0/ws.md#IMidwayWSContext) * [**NextFunction](/api/3.0.0/ws.md#NextFunction) * [**UpgradeAuthHandler](/api/3.0.0/ws.md#UpgradeAuthHandler) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L39)Application **Application: [IMidwayWSApplication](/api/3.0.0/ws.md#IMidwayWSApplication) ### [**](#IMidwayWSApplication)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L12)IMidwayWSApplication **IMidwayWSApplication: IMidwayApplication<[IMidwayWSContext](/api/3.0.0/ws.md#IMidwayWSContext), { getConnectionMiddleware: ContextMiddlewareManager<[Context](/api/3.0.0/ws/interface/Context.md), [NextFunction](/api/3.0.0/ws.md#NextFunction), undefined>; onWebSocketUpgrade: (handler: [UpgradeAuthHandler](/api/3.0.0/ws.md#UpgradeAuthHandler) | null) => void; useConnectionMiddleware: (middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/ws/interface/Context.md), [NextFunction](/api/3.0.0/ws.md#NextFunction), undefined>) => void }> & WebSocket.Server ### [**](#IMidwayWSConfigurationOptions)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L20)IMidwayWSConfigurationOptions **IMidwayWSConfigurationOptions: { enableServerHeartbeatCheck? : boolean; pubClient? : any; serverHeartbeatInterval? : number; subClient? : any } & Partial\ & IConfigurationOptions ### [**](#IMidwayWSContext)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L33)IMidwayWSContext **IMidwayWSContext: IMidwayContext\ ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L40)NextFunction **NextFunction: BaseNextFunction ### [**](#UpgradeAuthHandler)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L46)UpgradeAuthHandler **UpgradeAuthHandler: (request: IncomingMessage, socket: any, head: Buffer) => Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [WebSocketConfiguration](/api/3.0.0/ws/class/Configuration.md) --- # Framework ### Hierarchy * BaseFramework<[Application](/api/3.0.0/ws.md#Application), [Context](/api/3.0.0/ws/interface/Context.md), [IMidwayWSConfigurationOptions](/api/3.0.0/ws.md#IMidwayWSConfigurationOptions)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configService](#configService) * [**configurationOptions](#configurationOptions) * [**environmentService](#environmentService) * [**informationService](#informationService) * [**loggerService](#loggerService) * [**middlewareService](#middlewareService) * [**mockService](#mockService) * [**server](#server) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConnectionMiddleware](#getConnectionMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getFrameworkType](#getFrameworkType) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**init](#init) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**onWebSocketUpgrade](#onWebSocketUpgrade) * [**run](#run) * [**runGuard](#runGuard) * [**setNamespace](#setNamespace) * [**startHeartBeat](#startHeartBeat) * [**stop](#stop) * [**useConnectionMiddleware](#useConnectionMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L34)constructor * **new Framework(applicationContext: IMidwayContainer): [MidwayWSFramework](/api/3.0.0/ws/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwayWSConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L71)publicapp **app: [IMidwayWSApplication](/api/3.0.0/ws.md#IMidwayWSApplication) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayContainer Inherited from BaseFramework.applicationContext ### [**](#configService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L30)configService **configService: MidwayConfigService Inherited from BaseFramework.configService ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayWSConfigurationOptions](/api/3.0.0/ws.md#IMidwayWSConfigurationOptions) Inherited from BaseFramework.configurationOptions ### [**](#environmentService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L29)environmentService **environmentService: MidwayEnvironmentService Inherited from BaseFramework.environmentService ### [**](#informationService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L31)informationService **informationService: MidwayInformationService Inherited from BaseFramework.informationService ### [**](#loggerService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L28)loggerService **loggerService: MidwayLoggerService Inherited from BaseFramework.loggerService ### [**](#middlewareService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)middlewareService **middlewareService: MidwayMiddlewareService<[Context](/api/3.0.0/ws/interface/Context.md), unknown, unknown> Inherited from BaseFramework.middlewareService ### [**](#mockService)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L33)mockService **mockService: MidwayMockService Inherited from BaseFramework.mockService ### [**](#server)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L40)server **server: Server\ ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L49)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): void - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L79)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/3.0.0/ws/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L45)configure * **configure(): [IMidwayWSConfigurationOptions](/api/3.0.0/ws.md#IMidwayWSConfigurationOptions) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L82)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getApplication * **getApplication(): [IMidwayWSApplication](/api/3.0.0/ws.md#IMidwayWSApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getApplicationContext * **getApplicationContext(): IMidwayContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L60)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L401)publicgetConnectionMiddleware * **getConnectionMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/ws/interface/Context.md), NextFunction, undefined> ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L81)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L391)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getFrameworkType)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L170)publicgetFrameworkType * **getFrameworkType(): [MidwayFrameworkType](/api/3.0.0/decorator/class/MidwayFrameworkType.md) ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L80)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L86)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/3.0.0/ws/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L94)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L83)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#init)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L35)init * **init(): Promise<[MidwayWSFramework](/api/3.0.0/ws/class/Framework.md)> - Inherited from BaseFramework.init ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#onWebSocketUpgrade)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L178)publiconWebSocketUpgrade * **onWebSocketUpgrade(handler: [UpgradeAuthHandler](/api/3.0.0/ws.md#UpgradeAuthHandler)): void - 设置升级前鉴权处理函数 ### [**](#run)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L79)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L89)runGuard * **runGuard(ctx: [Context](/api/3.0.0/ws/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L93)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#startHeartBeat)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L409)publicstartHeartBeat * **startHeartBeat(): void ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/framework.ts#L395)publicuseConnectionMiddleware * **useConnectionMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/ws/interface/Context.md), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L87)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/3.0.0/ws/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L88)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/3.0.0/ws/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L85)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/3.0.0/ws/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # Context ### Hierarchy * [IMidwayWSContext](/api/3.0.0/ws.md#IMidwayWSContext) * *Context* ## Index[**](#Index) ### Properties * [**app](#app) * [**isAlive](#isAlive) * [**logger](#logger) * [**request](#request) * [**requestContext](#requestContext) * [**startTime](#startTime) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L34)app **app: [IMidwayWSApplication](/api/3.0.0/ws.md#IMidwayWSApplication) Inherited from IMidwayWSContext.app ### [**](#isAlive)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L35)isAlive **isAlive: boolean Inherited from IMidwayWSContext.isAlive ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)logger **logger: ILogger Inherited from IMidwayWSContext.logger ### [**](#request)[**](https://github.com/midwayjs/midway/blob/main/packages/ws/src/interface.ts#L36)request **request: IncomingMessage Inherited from IMidwayWSContext.request ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)requestContext **requestContext: IMidwayContainer Inherited from IMidwayWSContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L696)startTime **startTime: number Inherited from IMidwayWSContext.startTime ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L711)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayWSContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L707)getAttr * **getAttr\(key: string): T - Inherited from IMidwayWSContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L695)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayWSContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L702)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayWSContext.setAttr Set value to app attribute map --- # API ### Packages * [v](/api/axios.md) [4.0.3 @midwayjs/axios](/api/axios.md) * [v](/api/bootstrap.md) [4.0.3 @midwayjs/bootstrap](/api/bootstrap.md) * [v](/api/bull.md) [4.0.3 @midwayjs/bull](/api/bull.md) * [v](/api/bull-board.md) [4.0.3 @midwayjs/bull-board](/api/bull-board.md) * [v](/api/bullmq.md) [4.0.3 @midwayjs/bullmq](/api/bullmq.md) * [v](/api/busboy.md) [4.0.3 @midwayjs/busboy](/api/busboy.md) * [v](/api/cache-manager.md) [4.0.3 @midwayjs/cache-manager](/api/cache-manager.md) * [v](/api/captcha.md) [4.0.3 @midwayjs/captcha](/api/captcha.md) * [v](/api/casbin.md) [4.0.3 @midwayjs/casbin](/api/casbin.md) * [v](/api/casbin-redis-adapter.md) [4.0.3 @midwayjs/casbin-redis-adapter](/api/casbin-redis-adapter.md) * [v](/api/casbin-typeorm-adapter.md) [4.0.3 @midwayjs/casbin-typeorm-adapter](/api/casbin-typeorm-adapter.md) * [v](/api/code-dye.md) [4.0.3 @midwayjs/code-dye](/api/code-dye.md) * [v](/api/consul.md) [4.0.3 @midwayjs/consul](/api/consul.md) * [v](/api/core.md) [4.0.3 @midwayjs/core](/api/core.md) * [v](/api/cos.md) [4.0.3 @midwayjs/cos](/api/cos.md) * [v](/api/cron.md) [4.0.3 @midwayjs/cron](/api/cron.md) * [v](/api/cross-domain.md) [4.0.3 @midwayjs/cross-domain](/api/cross-domain.md) * [v](/api/etcd.md) [4.0.3 @midwayjs/etcd](/api/etcd.md) * [v](/api/event-emitter.md) [4.0.3 @midwayjs/event-emitter](/api/event-emitter.md) * [v](/api/web-express.md) [4.0.3 @midwayjs/express](/api/web-express.md) * [v](/api/express-session.md) [4.0.3 @midwayjs/express-session](/api/express-session.md) * [v](/api/faas.md) [4.0.3 @midwayjs/faas](/api/faas.md) * [v](/api/grpc.md) [4.0.3 @midwayjs/grpc](/api/grpc.md) * [v](/api/http-proxy.md) [4.0.3 @midwayjs/http-proxy](/api/http-proxy.md) * [v](/api/i18n.md) [4.0.3 @midwayjs/i18n](/api/i18n.md) * [v](/api/info.md) [4.0.3 @midwayjs/info](/api/info.md) * [v](/api/jwt.md) [4.0.3 @midwayjs/jwt](/api/jwt.md) * [v](/api/kafka.md) [4.0.3 @midwayjs/kafka](/api/kafka.md) * [v](/api/web-koa.md) [4.0.3 @midwayjs/koa](/api/web-koa.md) * [v](/api/leoric.md) [4.0.3 @midwayjs/leoric](/api/leoric.md) * [v](/api/mcp.md) [4.0.3 @midwayjs/mcp](/api/mcp.md) * [v](/api/mikro.md) [4.0.3 @midwayjs/mikro](/api/mikro.md) * [v](/api/mock.md) [4.0.3 @midwayjs/mock](/api/mock.md) * [v](/api/mongoose.md) [4.0.3 @midwayjs/mongoose](/api/mongoose.md) * [v](/api/mqtt.md) [4.0.3 @midwayjs/mqtt](/api/mqtt.md) * [v](/api/nextjs.md) [4.0.3 @midwayjs/nextjs](/api/nextjs.md) * [v](/api/oss.md) [4.0.3 @midwayjs/oss](/api/oss.md) * [v](/api/passport.md) [4.0.3 @midwayjs/passport](/api/passport.md) * [v](/api/prometheus.md) [4.0.3 @midwayjs/prometheus](/api/prometheus.md) * [v](/api/prometheus-socket-io.md) [4.0.3 @midwayjs/prometheus-socket-io](/api/prometheus-socket-io.md) * [v](/api/rabbitmq.md) [4.0.3 @midwayjs/rabbitmq](/api/rabbitmq.md) * [v](/api/redis.md) [4.0.3 @midwayjs/redis](/api/redis.md) * [v](/api/security.md) [4.0.3 @midwayjs/security](/api/security.md) * [v](/api/sequelize.md) [4.0.3 @midwayjs/sequelize](/api/sequelize.md) * [v](/api/session.md) [4.0.3 @midwayjs/session](/api/session.md) * [v](/api/socketio.md) [4.0.3 @midwayjs/socketio](/api/socketio.md) * [v](/api/static-file.md) [4.0.3 @midwayjs/static-file](/api/static-file.md) * [v](/api/swagger.md) [4.0.3 @midwayjs/swagger](/api/swagger.md) * [v](/api/tablestore.md) [4.0.3 @midwayjs/tablestore](/api/tablestore.md) * [v](/api/tenant.md) [4.0.3 @midwayjs/tenant](/api/tenant.md) * [v](/api/typegoose.md) [4.0.3 @midwayjs/typegoose](/api/typegoose.md) * [v](/api/typeorm.md) [4.0.3 @midwayjs/typeorm](/api/typeorm.md) * [v](/api/upload.md) [4.0.3 @midwayjs/upload](/api/upload.md) * [v](/api/validate.md) [4.0.3 @midwayjs/validate](/api/validate.md) * [v](/api/validation.md) [4.0.3 @midwayjs/validation](/api/validation.md) * [v](/api/validation-class-validator.md) [4.0.3 @midwayjs/validation-class-validator](/api/validation-class-validator.md) * [v](/api/validation-joi.md) [4.0.3 @midwayjs/validation-joi](/api/validation-joi.md) * [v](/api/validation-zod.md) [4.0.3 @midwayjs/validation-zod](/api/validation-zod.md) * [v](/api/view.md) [4.0.3 @midwayjs/view](/api/view.md) * [v](/api/view-ejs.md) [4.0.3 @midwayjs/view-ejs](/api/view-ejs.md) * [v](/api/view-nunjucks.md) [4.0.3 @midwayjs/view-nunjucks](/api/view-nunjucks.md) * [v](/api/web.md) [4.0.3 @midwayjs/web](/api/web.md) * [v](/api/ws.md) [4.0.3 @midwayjs/ws](/api/ws.md) Powered by [docusaurus-plugin-typedoc-api](https://github.com/milesj/docusaurus-plugin-typedoc-api) and [TypeDoc](https://typedoc.org/) --- # @midwayjs/axios ## Index[**](#Index) ### Classes * [**Configuration](/api/axios/class/Configuration.md) * [**HttpService](/api/axios/class/HttpService.md) * [**HttpServiceFactory](/api/axios/class/HttpServiceFactory.md) ### Interfaces * [**AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md) * [**AxiosResponse](/api/axios/interface/AxiosResponse.md) ### Variables * [**Axios](/api/axios.md#Axios) ## Variables[**](#Variables) ### [**](#Axios)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/index.ts#L2)constAxios **Axios: any = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [AxiosConfiguration](/api/axios/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/configuration.ts#L33)publiconReady * **onReady(container: IMidwayContainer): Promise\ --- # HttpService ### Hierarchy * AxiosInstance * *HttpService* ### Callable * **HttpService\(config: AxiosRequestConfig\): Promise\ * **HttpService\(url: string, config? : AxiosRequestConfig\): Promise\ *** * #### Type parameters * **T** = any * **R** = AxiosResponse\ * **D** = any ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**defaults](#defaults) * [**interceptors](#interceptors) ### Methods * [**delete](#delete) * [**get](#get) * [**getUri](#getUri) * [**head](#head) * [**options](#options) * [**patch](#patch) * [**patchForm](#patchForm) * [**post](#post) * [**postForm](#postForm) * [**put](#put) * [**putForm](#putForm) * [**request](#request) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpService(): [HttpService](/api/axios/class/HttpService.md) ## Accessors[**](#Accessors) ### [**](#defaults)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L30)defaults * **get defaults(): Omit\, headers> & {} ### [**](#interceptors)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L34)interceptors * **get interceptors(): {} ## Methods[**](#Methods) ### [**](#delete)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L55)delete * **delete\(url: string, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L48)get * **get\(url: string, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#getUri)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L38)getUri * **getUri(config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): string ### [**](#head)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L62)head * **head\(url: string, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L69)options * **options\(url: string, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#patch)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L92)patch * **patch\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#patchForm)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L116)patchForm * **patchForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#post)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L76)post * **post\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#postForm)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L100)postForm * **postForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#put)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L84)put * **put\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#putForm)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L108)putForm * **putForm\(url: string, data? : D, config? : [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.ts#L42)request * **request\(config: [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\): Promise\ - #### Type parameters * **T** = any * **R** = [AxiosResponse](/api/axios/interface/AxiosResponse.md)\ * **D** = any --- # HttpServiceFactory ### Hierarchy * ServiceFactory\ * *HttpServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**axiosConfig](#axiosConfig) * [**traceEnabled](#traceEnabled) * [**traceInjector](#traceInjector) * [**traceService](#traceService) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpServiceFactory(): [HttpServiceFactory](/api/axios/class/HttpServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#axiosConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L18)axiosConfig **axiosConfig: any ### [**](#traceEnabled)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L21)traceEnabled **traceEnabled: boolean ### [**](#traceInjector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L24)traceInjector **traceInjector: (args: { custom? : Record\; request? : unknown }) => any ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L30)traceService **traceService: MidwayTraceService ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = AxiosInstance ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L45)publicgetName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/http-service.factory.ts#L33)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # AxiosRequestConfig \ Interface for custom axios request config merging. ### Hierarchy * AxiosRequestConfig\ * *AxiosRequestConfig* --- # AxiosResponse \ ### Hierarchy * AxiosResponse\ * *AxiosResponse* ## Index[**](#Index) ### Properties * [**config](#config) ## Properties[**](#Properties) ### [**](#config)[**](https://github.com/midwayjs/midway/blob/3.x/packages/axios/src/interface.ts#L17)config **config: [AxiosRequestConfig](/api/axios/interface/AxiosRequestConfig.md)\ & { headers: AxiosRequestHeaders } Overrides OriginAxiosResponse.config --- # @midwayjs/bootstrap ## Index[**](#Index) ### Classes * [**AbstractForkManager](/api/bootstrap/class/AbstractForkManager.md) * [**Bootstrap](/api/bootstrap/class/Bootstrap.md) * [**BootstrapStarter](/api/bootstrap/class/BootstrapStarter.md) * [**ClusterManager](/api/bootstrap/class/ClusterManager.md) ### Functions * [**setupStickyMaster](/api/bootstrap/function/setupStickyMaster.md) ### Interfaces * [**ForkOptions](/api/bootstrap/interface/ForkOptions.md) * [**IForkManager](/api/bootstrap/interface/IForkManager.md) ### Type Aliases * [**ClusterOptions](/api/bootstrap.md#ClusterOptions) * [**ThreadOptions](/api/bootstrap.md#ThreadOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#ClusterOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L44)ClusterOptions **ClusterOptions: [ForkOptions](/api/bootstrap/interface/ForkOptions.md) & ClusterSettings & { sticky? : boolean; stickyLoadBalancingMethod? : random | round-robin | least-connection } ### [**](#ThreadOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L50)ThreadOptions **ThreadOptions: [ForkOptions](/api/bootstrap/interface/ForkOptions.md) & WorkerOptions --- # abstractAbstractForkManager \ ### Hierarchy * *AbstractForkManager* * [ClusterManager](/api/bootstrap/class/ClusterManager.md) ## Index[**](#Index) ### Properties * [**options](#options) ### Methods * [**bindWorkerDisconnect](#bindWorkerDisconnect) * [**bindWorkerExit](#bindWorkerExit) * [**closeWorker](#closeWorker) * [**createEventBus](#createEventBus) * [**createWorker](#createWorker) * [**getWorker](#getWorker) * [**getWorkerId](#getWorkerId) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**onStop](#onStop) * [**start](#start) * [**stop](#stop) ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L24)readonlyoptions **options: ClusterOptions ## Methods[**](#Methods) ### [**](#bindWorkerDisconnect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L343)abstractbindWorkerDisconnect * **bindWorkerDisconnect(listener: (worker: Worker) => void): void ### [**](#bindWorkerExit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L344)abstractbindWorkerExit * **bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void ### [**](#closeWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L349)abstractcloseWorker * **closeWorker(worker: Worker): any ### [**](#createEventBus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L350)abstractcreateEventBus * **createEventBus(eventBusOptions: EventBusOptions\): IEventBus\ ### [**](#createWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L342)abstractcreateWorker * **createWorker(oldWorker? : Worker): Worker ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L289)publicgetWorker * **getWorker(workerId: string): Worker ### [**](#getWorkerId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L347)abstractgetWorkerId * **getWorkerId(worker: Worker): string ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L293)publicgetWorkerIds * **getWorkerIds(): string\[] ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L285)publichasWorker * **hasWorker(workerId: string): boolean ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L353)abstractisPrimary * **isPrimary(): boolean ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L348)abstractisWorkerDead * **isWorkerDead(worker: Worker): boolean ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L297)publiconStop * **onStop(exitListener: any): void ### [**](#start)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L36)publicstart * **start(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L271)publicstop * **stop(timeout? : number): Promise\ --- # Bootstrap ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**configure](#configure) * [**getApplicationContext](#getApplicationContext) * [**getStarter](#getStarter) * [**reset](#reset) * [**run](#run) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Bootstrap(): [Bootstrap](/api/bootstrap/class/Bootstrap.md) ## Methods[**](#Methods) ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L127)staticconfigure * **configure(configuration? : IMidwayBootstrapOptions): typeof [Bootstrap](/api/bootstrap/class/Bootstrap.md) - set global configuration for midway ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L273)staticgetApplicationContext * **getApplicationContext(): IMidwayGlobalContainer ### [**](#getStarter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L158)staticgetStarter * **getStarter(): [BootstrapStarter](/api/bootstrap/class/BootstrapStarter.md) ### [**](#reset)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L215)staticreset * **reset(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L165)staticrun * **run(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L204)staticstop * **stop(): Promise\ --- # BootstrapStarter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**configure](#configure) * [**getApplicationContext](#getApplicationContext) * [**init](#init) * [**run](#run) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BootstrapStarter(): [BootstrapStarter](/api/bootstrap/class/BootstrapStarter.md) ## Methods[**](#Methods) ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L29)publicconfigure * **configure(options? : IMidwayBootstrapOptions): [BootstrapStarter](/api/bootstrap/class/BootstrapStarter.md) ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L99)publicgetApplicationContext * **getApplicationContext(): IMidwayGlobalContainer ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L34)publicinit * **init(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L68)publicrun * **run(): Promise\ ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/bootstrap.ts#L90)publicstop * **stop(): Promise\ --- # ClusterManager ### Hierarchy * [AbstractForkManager](/api/bootstrap/class/AbstractForkManager.md)\ * *ClusterManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**bindWorkerDisconnect](#bindWorkerDisconnect) * [**bindWorkerExit](#bindWorkerExit) * [**closeWorker](#closeWorker) * [**createEventBus](#createEventBus) * [**createWorker](#createWorker) * [**getWorker](#getWorker) * [**getWorkerId](#getWorkerId) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**onStop](#onStop) * [**start](#start) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L15)constructor * **new ClusterManager(options? : [ClusterOptions](/api/bootstrap.md#ClusterOptions)): [ClusterManager](/api/bootstrap/class/ClusterManager.md) - Overrides AbstractForkManager< Worker, ClusterOptions >.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L15)readonlyoptions **options: [ClusterOptions](/api/bootstrap.md#ClusterOptions) = {} Inherited from AbstractForkManager.options ## Methods[**](#Methods) ### [**](#bindWorkerDisconnect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L36)bindWorkerDisconnect * **bindWorkerDisconnect(listener: (worker: Worker) => void): void - Overrides AbstractForkManager.bindWorkerDisconnect ### [**](#bindWorkerExit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L41)bindWorkerExit * **bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void - Overrides AbstractForkManager.bindWorkerExit ### [**](#closeWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L54)closeWorker * **closeWorker(worker: Worker): void - Overrides AbstractForkManager.closeWorker ### [**](#createEventBus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L58)createEventBus * **createEventBus(options: any): any - Overrides AbstractForkManager.createEventBus ### [**](#createWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L23)createWorker * **createWorker(): any - Overrides AbstractForkManager.createWorker ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L289)publicgetWorker * **getWorker(workerId: string): Worker - Inherited from AbstractForkManager.getWorker ### [**](#getWorkerId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L46)getWorkerId * **getWorkerId(worker: Worker): string - Overrides AbstractForkManager.getWorkerId ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L293)publicgetWorkerIds * **getWorkerIds(): string\[] - Inherited from AbstractForkManager.getWorkerIds ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L285)publichasWorker * **hasWorker(workerId: string): boolean - Inherited from AbstractForkManager.hasWorker ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L62)isPrimary * **isPrimary(): boolean - Overrides AbstractForkManager.isPrimary ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/cp.ts#L50)isWorkerDead * **isWorkerDead(worker: Worker): boolean - Overrides AbstractForkManager.isWorkerDead ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L297)publiconStop * **onStop(exitListener: any): void - Inherited from AbstractForkManager.onStop ### [**](#start)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L36)publicstart * **start(): Promise\ - Inherited from AbstractForkManager.start ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/manager/base.ts#L271)publicstop * **stop(timeout? : number): Promise\ - Inherited from AbstractForkManager.stop --- # setupStickyMaster ### Callable * **setupStickyMaster(httpServer: any, opts? : {}): void --- # ForkOptions ## Index[**](#Index) ### Properties * [**count](#count) * [**duration](#duration) * [**env](#env) * [**exec](#exec) * [**limit](#limit) * [**logger](#logger) * [**refork](#refork) * [**workerInitTimeout](#workerInitTimeout) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L10)optionalcount **count? : number worker num, default is `os.cpus().length` ### [**](#duration)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L20)optionalduration **duration? : number ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L26)optionalenv **env? : Record\ Some environments set to worker ### [**](#exec)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L6)optionalexec **exec? : string ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L18)optionallimit **limit? : number restart limit, default is `60` ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L22)optionallogger **logger? : MidwayLogger | Console ### [**](#refork)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L14)optionalrefork **refork? : boolean refork when disconect and unexpected exit, default is `true` ### [**](#workerInitTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L31)optionalworkerInitTimeout **workerInitTimeout? : number Worker init Timeout, default is 30s, --- # IForkManager \ ## Index[**](#Index) ### Methods * [**close](#close) * [**getWorker](#getWorker) * [**getWorkerIds](#getWorkerIds) * [**hasWorker](#hasWorker) * [**isPrimary](#isPrimary) * [**isWorkerDead](#isWorkerDead) * [**start](#start) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L36)close * **close(): any ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L38)getWorker * **getWorker(workerId: string): T ### [**](#getWorkerIds)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L39)getWorkerIds * **getWorkerIds(): string\[] ### [**](#hasWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L37)hasWorker * **hasWorker(workerId: string): boolean ### [**](#isPrimary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L41)isPrimary * **isPrimary(): boolean ### [**](#isWorkerDead)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L40)isWorkerDead * **isWorkerDead(worker: T): boolean ### [**](#start)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bootstrap/src/interface.ts#L35)start * **start(): any --- # @midwayjs/bull ## Index[**](#Index) ### Classes * [**BullQueue](/api/bull/class/BullQueue.md) * [**Configuration](/api/bull/class/Configuration.md) * [**Framework](/api/bull/class/Framework.md) ### Functions * [**InjectQueue](/api/bull/function/InjectQueue.md) * [**Processor](/api/bull/function/Processor.md) ### Interfaces * [**Application](/api/bull/interface/Application.md) * [**Context](/api/bull/interface/Context.md) * [**IProcessor](/api/bull/interface/IProcessor.md) * [**IQueue](/api/bull/interface/IQueue.md) * [**IQueueManager](/api/bull/interface/IQueueManager.md) ### Type Aliases * [**NextFunction](/api/bull.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L42)NextFunction **NextFunction: BaseNextFunction --- # @midwayjs/bull-board ## Index[**](#Index) ### Classes * [**BoardMiddleware](/api/bull-board/class/BoardMiddleware.md) * [**BullBoardManager](/api/bull-board/class/BullBoardManager.md) * [**Configuration](/api/bull-board/class/Configuration.md) * [**MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) ### Interfaces * [**BullBoardOption](/api/bull-board/interface/BullBoardOption.md) --- # BoardMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BoardMiddleware(): [BoardMiddleware](/api/bull-board/class/BoardMiddleware.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.middleware.ts#L52)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.middleware.ts#L149)staticgetName * **getName(): string --- # BullBoardManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addQueue](#addQueue) * [**getBasePath](#getBasePath) * [**getBullBoardOrigin](#getBullBoardOrigin) * [**getServerAdapter](#getServerAdapter) * [**removeQueue](#removeQueue) * [**replaceQueues](#replaceQueues) * [**setBullBoard](#setBullBoard) * [**setQueues](#setQueues) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BullBoardManager(): [BullBoardManager](/api/bull-board/class/BullBoardManager.md) ## Methods[**](#Methods) ### [**](#addQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L86)publicaddQueue * **addQueue(queue: BaseAdapter): void ### [**](#getBasePath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L70)publicgetBasePath * **getBasePath(): string ### [**](#getBullBoardOrigin)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L82)publicgetBullBoardOrigin * **getBullBoardOrigin(): {} ### [**](#getServerAdapter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L74)publicgetServerAdapter * **getServerAdapter(): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) ### [**](#removeQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L90)publicremoveQueue * **removeQueue(queueOrName: string | BaseAdapter): void ### [**](#replaceQueues)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L94)publicreplaceQueues * **replaceQueues(newBullQueues: readonly BaseAdapter\[]): void ### [**](#setBullBoard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L78)publicsetBullBoard * **setBullBoard(bullBoard: {}): void ### [**](#setQueues)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/board.manager.ts#L98)publicsetQueues * **setQueues(newBullQueues: readonly BaseAdapter\[]): void --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) * [**onServerReady](#onServerReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BullBoardConfiguration](/api/bull-board/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/configuration.ts#L29)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/configuration.ts#L32)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/configuration.ts#L34)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/configuration.ts#L52)onServerReady * **onServerReady(container: IMidwayContainer): Promise\ --- # MidwayAdapter ### Implements * IServerAdapter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getEntryRoute](#getEntryRoute) * [**getStaticRoutes](#getStaticRoutes) * [**getViewRoutes](#getViewRoutes) * [**matchApiRoutes](#matchApiRoutes) * [**renderStatic](#renderStatic) * [**renderView](#renderView) * [**runAPI](#runAPI) * [**setApiRoutes](#setApiRoutes) * [**setBasePath](#setBasePath) * [**setEntryRoute](#setEntryRoute) * [**setErrorHandler](#setErrorHandler) * [**setQueues](#setQueues) * [**setStaticPath](#setStaticPath) * [**setUIConfig](#setUIConfig) * [**setViewsPath](#setViewsPath) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayAdapter(): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) ## Methods[**](#Methods) ### [**](#getEntryRoute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L70)publicgetEntryRoute * **getEntryRoute(): AppViewRoute ### [**](#getStaticRoutes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L99)publicgetStaticRoutes * **getStaticRoutes(): string ### [**](#getViewRoutes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L79)publicgetViewRoutes * **getViewRoutes(): string\[] ### [**](#matchApiRoutes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L84)publicmatchApiRoutes * **matchApiRoutes(method: string, url: string): AppControllerRoute ### [**](#renderStatic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L103)publicrenderStatic * **renderStatic(filename: any): Promise\ ### [**](#renderView)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L118)publicrenderView * **renderView(filename: any, params? : {}): Promise\ ### [**](#runAPI)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L144)publicrunAPI * **runAPI(route: any, query: any): Promise\ ### [**](#setApiRoutes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L55)publicsetApiRoutes * **setApiRoutes(routes: AppControllerRoute\[]): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setApiRoutes ### [**](#setBasePath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L24)publicsetBasePath * **setBasePath(path: string): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) ### [**](#setEntryRoute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L65)publicsetEntryRoute * **setEntryRoute(routeDef: AppViewRoute): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setEntryRoute ### [**](#setErrorHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L48)publicsetErrorHandler * **setErrorHandler(handler: (error: Error) => ControllerHandlerReturnType): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setErrorHandler ### [**](#setQueues)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L74)publicsetQueues * **setQueues(bullBoardQueues: BullBoardQueues): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setQueues ### [**](#setStaticPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L34)publicsetStaticPath * **setStaticPath(staticsRoute: string, staticsPath: string): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setStaticPath ### [**](#setUIConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L29)publicsetUIConfig * **setUIConfig(config: Partial<{}>): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setUIConfig ### [**](#setViewsPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/adapter.ts#L43)publicsetViewsPath * **setViewsPath(viewPath: string): [MidwayAdapter](/api/bull-board/class/MidwayAdapter.md) - Implementation of IServerAdapter.setViewsPath --- # BullBoardOption ## Index[**](#Index) ### Properties * [**adapterOptions](#adapterOptions) * [**basePath](#basePath) * [**uiConfig](#uiConfig) ## Properties[**](#Properties) ### [**](#adapterOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/interface.ts#L9)optionaladapterOptions **adapterOptions? : QueueAdapterOptions ### [**](#basePath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/interface.ts#L7)optionalbasePath **basePath? : string ### [**](#uiConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull-board/src/interface.ts#L8)optionaluiConfig **uiConfig? : Partial<{}> --- # BullQueue ### Hierarchy * Bull * *BullQueue* ### Implements * [IQueue](/api/bull/interface/IQueue.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addJobToQueue](#addJobToQueue) * [**getQueueName](#getQueueName) * [**runJob](#runJob) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L24)constructor * **new BullQueue(queueName: string, queueOptions: QueueOptions): [BullQueue](/api/bull/class/BullQueue.md) - Overrides Bull.constructor ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L28)publicaddJobToQueue * **addJobToQueue(data: any, options? : JobOptions): Promise\> - Implementation of IQueue.addJobToQueue ### [**](#getQueueName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L39)publicgetQueueName * **getQueueName(): string - Implementation of IQueue.getQueueName ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L35)publicrunJob * **runJob(data: any, options? : JobOptions): Promise\> - Implementation of IQueue.runJob * **@deprecated** use addJobToQueue instead --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BullConfiguration](/api/bull/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/configuration.ts#L24)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/configuration.ts#L21)framework **framework: [BullFramework](/api/bull/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/configuration.ts#L27)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/configuration.ts#L41)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/bull/interface/Application.md), [Context](/api/bull/interface/Context.md), any> * *Framework* ### Implements * [IQueueManager](/api/bull/interface/IQueueManager.md)<[BullQueue](/api/bull/class/BullQueue.md), Job> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**addJobToQueue](#addJobToQueue) * [**addProcessor](#addProcessor) * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**createQueue](#createQueue) * [**ensureQueue](#ensureQueue) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getJob](#getJob) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getQueue](#getQueue) * [**getQueueList](#getQueueList) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadConfig](#loadConfig) * [**run](#run) * [**runGuard](#runGuard) * [**runJob](#runJob) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [BullFramework](/api/bull/class/Framework.md) - Inherited from BaseFramework\.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/bull/interface/Application.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L235)publicaddJobToQueue * **addJobToQueue(queueName: string, jobData: any, options? : JobOptions): Promise\> - Implementation of IQueueManager.addJobToQueue ### [**](#addProcessor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L146)publicaddProcessor * **addProcessor(processor: new (...args: any\[]) => [IProcessor](/api/bull/interface/IProcessor.md), queueName: string | [BullQueue](/api/bull/class/BullQueue.md), concurrency? : number): Promise\ ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L55)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/bull/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L71)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#createQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L119)publiccreateQueue * **createQueue(name: string, queueOptions? : QueueOptions): [BullQueue](/api/bull/class/BullQueue.md) - Implementation of IQueueManager.createQueue ### [**](#ensureQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L135)publicensureQueue * **ensureQueue(name: string, queueOptions? : QueueOptions): [BullQueue](/api/bull/class/BullQueue.md) ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [Application](/api/bull/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L75)getFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L299)publicgetJob * **getJob(queueName: string, jobName: string): Promise\> - Implementation of IQueueManager.getJob ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/bull/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L131)publicgetQueue * **getQueue(name: string): [BullQueue](/api/bull/class/BullQueue.md) - Implementation of IQueueManager.getQueue ### [**](#getQueueList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L142)publicgetQueueList * **getQueueList(): [BullQueue](/api/bull/class/BullQueue.md)\[] ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L59)publicloadConfig * **loadConfig(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L79)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/bull/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/framework.ts#L291)publicrunJob * **runJob(queueName: string, jobData: any, options? : JobOptions): Promise\> - Implementation of IQueueManager.runJob * **@deprecated** use addJob instead ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/bull/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/bull/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/bull/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # InjectQueue ### Callable * **InjectQueue(queueName: string): PropertyDecorator --- # Processor ### Callable * **Processor(queueName: string, jobOptions? : JobOptions, queueOptions? : QueueOptions): ClassDecorator * **Processor(queueName: string, concurrency? : number, jobOptions? : JobOptions, queueOptions? : QueueOptions): ClassDecorator --- # Application ### Hierarchy * IMidwayApplication<[Context](/api/bull/interface/Context.md)> * *Application* ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L833)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L823)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/bull/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L814)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L778)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L794)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L844)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L774)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L799)getConfig * **getConfig\(key? : string): T - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L808)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L782)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L786)getFramework * **getFramework(): IMidwayFramework<[Application](/api/bull/interface/Application.md), [Context](/api/bull/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L804)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L853)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/bull/interface/Context.md), R, N> - Inherited from IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L867)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L790)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L818)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L839)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L828)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L858)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/bull/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L863)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/bull/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L849)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/bull/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * IMidwayContext * *Context* ## Index[**](#Index) ### Properties * [**from](#from) * [**job](#job) * [**jobId](#jobId) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#from)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L47)from **from: new (...args: any\[]) => [IProcessor](/api/bull/interface/IProcessor.md) ### [**](#job)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L46)job **job: Job\ ### [**](#jobId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L45)jobId **jobId: JobId ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # IProcessor ## Index[**](#Index) ### Methods * [**execute](#execute) ## Methods[**](#Methods) ### [**](#execute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L9)execute * **execute(data: any): any --- # IQueue \ ### Implemented by * [BullQueue](/api/bull/class/BullQueue.md) ## Index[**](#Index) ### Methods * [**addJobToQueue](#addJobToQueue) * [**getJob](#getJob) * [**getQueueName](#getQueueName) * [**runJob](#runJob) ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L17)addJobToQueue * **addJobToQueue(data: Record\, options? : unknown): Promise\ ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L18)getJob * **getJob(name: string): Promise\ ### [**](#getQueueName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L19)getQueueName * **getQueueName(): string ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L16)runJob * **runJob(data: Record\, options? : unknown): Promise\ - - **@deprecated** use addJobToQueue instead --- # IQueueManager \ ### Implemented by * [Framework](/api/bull/class/Framework.md) ## Index[**](#Index) ### Methods * [**addJobToQueue](#addJobToQueue) * [**createQueue](#createQueue) * [**getJob](#getJob) * [**getQueue](#getQueue) * [**runJob](#runJob) ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L23)addJobToQueue * **addJobToQueue(queueName: string, jobData: any, options? : unknown): Promise\ ### [**](#createQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L37)createQueue * **createQueue(queueName: string, queueOptions? : unknown): Queue ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L36)getJob * **getJob(queueName: string, jobName: string): Promise\ ### [**](#getQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L38)getQueue * **getQueue(queueName: string): Queue ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bull/src/interface.ts#L31)runJob * **runJob(queueName: string, jobData: any, options? : unknown): Promise\ - - **@deprecated** use addJobToQueue instead --- # @midwayjs/bullmq ## Index[**](#Index) ### Classes * [**BullMQQueue](/api/bullmq/class/BullMQQueue.md) * [**Configuration](/api/bullmq/class/Configuration.md) * [**Framework](/api/bullmq/class/Framework.md) ### Functions * [**InjectFlowProducer](/api/bullmq/function/InjectFlowProducer.md) * [**InjectQueue](/api/bullmq/function/InjectQueue.md) * [**InjectWorker](/api/bullmq/function/InjectWorker.md) * [**Processor](/api/bullmq/function/Processor.md) ### Interfaces * [**Application](/api/bullmq/interface/Application.md) * [**BullMQConfig](/api/bullmq/interface/BullMQConfig.md) * [**Context](/api/bullmq/interface/Context.md) * [**IProcessor](/api/bullmq/interface/IProcessor.md) ### Type Aliases * [**NextFunction](/api/bullmq.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L13)NextFunction **NextFunction: BaseNextFunction --- # BullMQQueue ### Hierarchy * Queue * *BullMQQueue* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addJobToQueue](#addJobToQueue) * [**close](#close) * [**createQueueEvents](#createQueueEvents) * [**createQueueEventsProducer](#createQueueEventsProducer) * [**getQueueEventsList](#getQueueEventsList) * [**getQueueEventsProducerList](#getQueueEventsProducerList) * [**getQueueName](#getQueueName) * [**runJob](#runJob) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L36)constructor * **new BullMQQueue(queueName: string, queueOptions: QueueOptions): [BullMQQueue](/api/bullmq/class/BullMQQueue.md) - Overrides Queue.constructor ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L43)publicaddJobToQueue * **addJobToQueue(data: any, options? : JobsOptions): Promise\> ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L95)publicclose * **close(): Promise\ - Overrides Queue.close ### [**](#createQueueEvents)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L67)publiccreateQueueEvents * **createQueueEvents(options? : QueueEventsOptions): QueueEvents ### [**](#createQueueEventsProducer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L81)publiccreateQueueEventsProducer * **createQueueEventsProducer(options? : QueueBaseOptions): QueueEventsProducer ### [**](#getQueueEventsList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L77)publicgetQueueEventsList * **getQueueEventsList(): QueueEvents\[] ### [**](#getQueueEventsProducerList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L91)publicgetQueueEventsProducerList * **getQueueEventsProducerList(): QueueEventsProducer\[] ### [**](#getQueueName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L63)publicgetQueueName * **getQueueName(): string ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L59)publicrunJob * **runJob(data: any, options? : JobsOptions): Promise\> - - **@deprecated** use addJobToQueue instead --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BullConfiguration](/api/bullmq/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/configuration.ts#L28)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/configuration.ts#L25)framework **framework: [BullMQFramework](/api/bullmq/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/configuration.ts#L31)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/configuration.ts#L69)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/bullmq/interface/Application.md), [Context](/api/bullmq/interface/Context.md), any> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**addJobToQueue](#addJobToQueue) * [**addProcessor](#addProcessor) * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createFlowProducer](#createFlowProducer) * [**createLogger](#createLogger) * [**createQueue](#createQueue) * [**createWorker](#createWorker) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFlowProducer](#getFlowProducer) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getQueue](#getQueue) * [**getQueueList](#getQueueList) * [**getWorker](#getWorker) * [**getWorkers](#getWorkers) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadConfig](#loadConfig) * [**run](#run) * [**runGuard](#runGuard) * [**runJob](#runJob) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [BullMQFramework](/api/bullmq/class/Framework.md) - Inherited from BaseFramework\.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/bullmq/interface/Application.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#addJobToQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L399)publicaddJobToQueue * **addJobToQueue(queueName: string, jobData: any, options? : JobsOptions): Promise\> - Add a job to the queue ### [**](#addProcessor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L305)publicaddProcessor * **addProcessor(processor: new (...args: any\[]) => [IProcessor](/api/bullmq/interface/IProcessor.md), queueName: string, workerOptions? : WorkerOptions): Promise\> - Add a processor class and init a worker ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L121)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/bullmq/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L150)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createFlowProducer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L466)publiccreateFlowProducer * **createFlowProducer(options? : Partial\, producerName? : string): FlowProducer - Create a flow producer, if producerName is provided, it will be store. ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#createQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L225)publiccreateQueue * **createQueue(name: string, queueOptions? : Partial\): [BullMQQueue](/api/bullmq/class/BullMQQueue.md) - Create a queue with name and queueOptions ### [**](#createWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L282)publiccreateWorker * **createWorker(queueName: string, processor: (job: Job\, token? : string) => Promise\, workerOptions? : Partial\): Worker\ - Create a worker ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [Application](/api/bullmq/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFlowProducer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L484)publicgetFlowProducer * **getFlowProducer(producerName: string): FlowProducer - Get a flow producer by name ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L154)getFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/bullmq/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getQueue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L244)publicgetQueue * **getQueue(name: string): [BullMQQueue](/api/bullmq/class/BullMQQueue.md) - Get a queue by name ### [**](#getQueueList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L261)publicgetQueueList * **getQueueList(): [BullMQQueue](/api/bullmq/class/BullMQQueue.md)\[] ### [**](#getWorker)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L268)publicgetWorker * **getWorker(queueName: string): Worker\ - Get the first worker by queueName ### [**](#getWorkers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L275)publicgetWorkers * **getWorkers(queueName: string): Worker\\[] - Get all workers by queueName ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L125)publicloadConfig * **loadConfig(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L158)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/bullmq/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#runJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/framework.ts#L455)publicrunJob * **runJob(queueName: string, jobData: any, options? : JobsOptions): Promise\> - - **@deprecated** use addJobToQueue instead ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/bullmq/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/bullmq/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/bullmq/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # InjectFlowProducer ### Callable * **InjectFlowProducer(producerName: string): PropertyDecorator --- # InjectQueue ### Callable * **InjectQueue(queueName: string): PropertyDecorator --- # InjectWorker ### Callable * **InjectWorker(queueName: string): PropertyDecorator --- # Processor ### Callable * **Processor(queueName: string, jobOptions? : JobsOptions, workerOptions? : Partial\, queueOptions? : Partial\): ClassDecorator --- # Application ### Hierarchy * IMidwayApplication<[Context](/api/bullmq/interface/Context.md)> * *Application* ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L833)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L823)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/bullmq/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L814)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L778)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L794)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L844)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L774)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L799)getConfig * **getConfig\(key? : string): T - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L808)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L782)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L786)getFramework * **getFramework(): IMidwayFramework<[Application](/api/bullmq/interface/Application.md), [Context](/api/bullmq/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L804)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L853)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/bullmq/interface/Context.md), R, N> - Inherited from IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L867)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L790)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L818)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L839)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L828)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L858)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/bullmq/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L863)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/bullmq/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L849)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/bullmq/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # BullMQConfig ## Index[**](#Index) ### Properties * [**clearRepeatJobWhenStart](#clearRepeatJobWhenStart) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**defaultConnection](#defaultConnection) * [**defaultPrefix](#defaultPrefix) * [**defaultQueueOptions](#defaultQueueOptions) * [**defaultWorkerOptions](#defaultWorkerOptions) ## Properties[**](#Properties) ### [**](#clearRepeatJobWhenStart)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L26)optionalclearRepeatJobWhenStart **clearRepeatJobWhenStart? : boolean ### [**](#contextLoggerApplyLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L27)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string ### [**](#contextLoggerFormat)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L28)optionalcontextLoggerFormat **contextLoggerFormat? : (info: any) => string ### [**](#defaultConnection)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L22)optionaldefaultConnection **defaultConnection? : ConnectionOptions ### [**](#defaultPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L23)optionaldefaultPrefix **defaultPrefix? : string ### [**](#defaultQueueOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L24)optionaldefaultQueueOptions **defaultQueueOptions? : Partial\ ### [**](#defaultWorkerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L25)optionaldefaultWorkerOptions **defaultWorkerOptions? : Partial\ --- # Context ### Hierarchy * IMidwayContext * *Context* ## Index[**](#Index) ### Properties * [**from](#from) * [**job](#job) * [**jobId](#jobId) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#from)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L18)from **from: new (...args: any\[]) => [IProcessor](/api/bullmq/interface/IProcessor.md) ### [**](#job)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L17)job **job: Job\ ### [**](#jobId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L16)jobId **jobId: string ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # IProcessor ## Index[**](#Index) ### Methods * [**execute](#execute) ## Methods[**](#Methods) ### [**](#execute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/bullmq/src/interface.ts#L9)execute * **execute(data: any, job: Job\, token? : string): Promise\ --- # @midwayjs/busboy ## Index[**](#Index) ### Classes * [**Configuration](/api/busboy/class/Configuration.md) * [**MultipartError](/api/busboy/class/MultipartError.md) * [**MultipartFieldsLimitError](/api/busboy/class/MultipartFieldsLimitError.md) * [**MultipartFileLimitError](/api/busboy/class/MultipartFileLimitError.md) * [**MultipartFileSizeLimitError](/api/busboy/class/MultipartFileSizeLimitError.md) * [**MultipartInvalidFileTypeError](/api/busboy/class/MultipartInvalidFileTypeError.md) * [**MultipartInvalidFilenameError](/api/busboy/class/MultipartInvalidFilenameError.md) * [**MultipartPartsLimitError](/api/busboy/class/MultipartPartsLimitError.md) * [**UploadMiddleware](/api/busboy/class/UploadMiddleware.md) ### Interfaces * [**UploadFileInfo](/api/busboy/interface/UploadFileInfo.md) * [**UploadOptions](/api/busboy/interface/UploadOptions.md) * [**UploadStreamFieldInfo](/api/busboy/interface/UploadStreamFieldInfo.md) * [**UploadStreamFileInfo](/api/busboy/interface/UploadStreamFileInfo.md) ### Type Aliases * [**UploadMode](/api/busboy.md#UploadMode) ### Variables * [**DefaultUploadFileMimeType](/api/busboy.md#DefaultUploadFileMimeType) * [**EXT\_KEY](/api/busboy.md#EXT_KEY) * [**uploadWhiteList](/api/busboy.md#uploadWhiteList) ## Type Aliases[**](<#Type Aliases>) ### [**](#UploadMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L5)UploadMode **UploadMode: stream | file | asyncIterator ## Variables[**](#Variables) ### [**](#DefaultUploadFileMimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/constants.ts#L36)constDefaultUploadFileMimeType **DefaultUploadFileMimeType: { .avi: string; .bmp: string; .gif: string; .gz: string; .gzip: string; .jpeg: string; .jpg: string; .mp3: string; .mp4: string; .pdf: string; .png: string; .psd: string; .svg: string; .tif: string; .tiff: string; .wbmp: string; .webp: string; .xml: string; .zip: string } = ... ### [**](#EXT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/constants.ts#L58)constEXT\_KEY **EXT\_KEY: typeof [EXT\_KEY](/api/busboy.md#EXT_KEY) = ... ### [**](#uploadWhiteList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/constants.ts#L1)constuploadWhiteList **uploadWhiteList: string\[] = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**uploadConfig](#uploadConfig) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [BusboyConfiguration](/api/busboy/class/Configuration.md) ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/configuration.ts#L32)logger **logger: ILogger ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/configuration.ts#L29)uploadConfig **uploadConfig: [UploadOptions](/api/busboy/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/configuration.ts#L34)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/configuration.ts#L46)onStop * **onStop(): Promise\ --- # MultipartError ### Hierarchy * BadRequestError * *MultipartError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L26)constructor * **new MultipartError(err: Error): [MultipartError](/api/busboy/class/MultipartError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartFieldsLimitError ### Hierarchy * BadRequestError * *MultipartFieldsLimitError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L46)constructor * **new MultipartFieldsLimitError(): [MultipartFieldsLimitError](/api/busboy/class/MultipartFieldsLimitError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartFileLimitError ### Hierarchy * BadRequestError * *MultipartFileLimitError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L32)constructor * **new MultipartFileLimitError(): [MultipartFileLimitError](/api/busboy/class/MultipartFileLimitError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartFileSizeLimitError ### Hierarchy * BadRequestError * *MultipartFileSizeLimitError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L20)constructor * **new MultipartFileSizeLimitError(filename: string): [MultipartFileSizeLimitError](/api/busboy/class/MultipartFileSizeLimitError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartInvalidFilenameError ### Hierarchy * BadRequestError * *MultipartInvalidFilenameError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L4)constructor * **new MultipartInvalidFilenameError(filename: string): [MultipartInvalidFilenameError](/api/busboy/class/MultipartInvalidFilenameError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartInvalidFileTypeError ### Hierarchy * BadRequestError * *MultipartInvalidFileTypeError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L10)constructor * **new MultipartInvalidFileTypeError(filename: string, currentType: string, type: string): [MultipartInvalidFileTypeError](/api/busboy/class/MultipartInvalidFileTypeError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartPartsLimitError ### Hierarchy * BadRequestError * *MultipartPartsLimitError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/error.ts#L39)constructor * **new MultipartPartsLimitError(): [MultipartPartsLimitError](/api/busboy/class/MultipartPartsLimitError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # UploadMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**logger](#logger) * [**match](#match) * [**uploadConfig](#uploadConfig) ### Methods * [**checkAndGetExt](#checkAndGetExt) * [**checkFileType](#checkFileType) * [**getUploadBoundary](#getUploadBoundary) * [**isReadableStream](#isReadableStream) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new UploadMiddleware(): [UploadMiddleware](/api/busboy/class/UploadMiddleware.md) ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L59)ignore **ignore: IgnoreMatcher\\[] Implementation of IMiddleware.ignore ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L46)logger **logger: ILogger ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L58)match **match: IgnoreMatcher\\[] Implementation of IMiddleware.match ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L43)uploadConfig **uploadConfig: [UploadOptions](/api/busboy/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#checkAndGetExt)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L514)checkAndGetExt * **checkAndGetExt(filename: any, whiteListMap? : Map\): string | boolean ### [**](#checkFileType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L534)checkFileType * **checkFileType(ext: string, data: Buffer, uploadFileMimeTypeMap? : Map\): Promise<{ current? : string; mime? : string; passed: boolean }> ### [**](#getUploadBoundary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L579)getUploadBoundary * **getUploadBoundary(request: any): string | false ### [**](#isReadableStream)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L563)isReadableStream * **isReadableStream(req: any, isExpress: any): boolean ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L85)resolve * **resolve(app: IMidwayBaseApplication\, options? : { mode? : [UploadMode](/api/busboy.md#UploadMode) } & BusboyConfig): (ctxOrReq: any, resOrNext: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/middleware.ts#L509)staticgetName * **getName(): string --- # UploadFileInfo ## Index[**](#Index) ### Properties * [**data](#data) * [**fieldName](#fieldName) * [**filename](#filename) * [**mimeType](#mimeType) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L60)data **data: string file data, a string of path ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L64)fieldName **fieldName: string field name ### [**](#filename)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L52)filename **filename: string File name ### [**](#mimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L56)mimeType **mimeType: string file mime type --- # UploadOptions ### Hierarchy * BusboyConfig * *UploadOptions* ## Index[**](#Index) ### Properties * [**allowFieldsDuplication](#allowFieldsDuplication) * [**base64](#base64) * [**cleanTimeout](#cleanTimeout) * [**ignore](#ignore) * [**match](#match) * [**mimeTypeWhiteList](#mimeTypeWhiteList) * [**mode](#mode) * [**tmpdir](#tmpdir) * [**whitelist](#whitelist) ## Properties[**](#Properties) ### [**](#allowFieldsDuplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L45)optionalallowFieldsDuplication **allowFieldsDuplication? : boolean Whether to allow fields duplication, default is `false`, only for `file` and `stream` mode ### [**](#base64)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L27)optionalbase64 **base64? : boolean Whether the uploaded body is base64, for example, apigw of Tencent Cloud ### [**](#cleanTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L23)optionalcleanTimeout **cleanTimeout? : number Temporary file automatic cleanup time, default is 5 minutes ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L31)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Which paths to ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L35)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Match those paths with higher priority than ignore ### [**](#mimeTypeWhiteList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L39)optionalmimeTypeWhiteList **mimeTypeWhiteList? : Record\ | (ctx: any) => string | string\[] Mime type white list ### [**](#mode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L11)optionalmode **mode? : [UploadMode](/api/busboy.md#UploadMode) Upload mode, default is `file` ### [**](#tmpdir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L19)optionaltmpdir **tmpdir? : string Temporary file directory ### [**](#whitelist)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L15)optionalwhitelist **whitelist? : string\[] | (ctx: any) => string\[] The white ext file names --- # UploadStreamFieldInfo ## Index[**](#Index) ### Properties * [**name](#name) * [**value](#value) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L90)name **name: string field name ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L94)value **value: any field value --- # UploadStreamFileInfo ## Index[**](#Index) ### Properties * [**data](#data) * [**fieldName](#fieldName) * [**filename](#filename) * [**mimeType](#mimeType) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L79)data **data: Readable file data, Readable stream ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L83)fieldName **fieldName: string field name ### [**](#filename)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L71)filename **filename: string File name ### [**](#mimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/busboy/src/interface.ts#L75)mimeType **mimeType: string file mime type --- # @midwayjs/cache-manager ## Index[**](#Index) ### Classes * [**CachingFactory](/api/cache-manager/class/CachingFactory.md) * [**Configuration](/api/cache-manager/class/Configuration.md) ### Functions * [**Caching](/api/cache-manager/function/Caching.md) * [**createRedisStore](/api/cache-manager/function/createRedisStore.md) * [**getClassMethodDefaultCacheKey](/api/cache-manager/function/getClassMethodDefaultCacheKey.md) ### Interfaces * [**RedisStore](/api/cache-manager/interface/RedisStore.md) ### Namespaces * [**CacheManager](/api/cache-manager/namespace/CacheManager.md) ### Type Aliases * [**CacheManagerOptions](/api/cache-manager.md#CacheManagerOptions) * [**CachingDecoratorKeyOptions](/api/cache-manager.md#CachingDecoratorKeyOptions) * [**MidwayCache](/api/cache-manager.md#MidwayCache) * [**MidwayMultiCache](/api/cache-manager.md#MidwayMultiCache) * [**MidwayUnionCache](/api/cache-manager.md#MidwayUnionCache) * [**SingleCacheOptions](/api/cache-manager.md#SingleCacheOptions) ### Variables * [**CACHE\_DECORATOR\_KEY](/api/cache-manager.md#CACHE_DECORATOR_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#CacheManagerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/interface.ts#L23)CacheManagerOptions **CacheManagerOptions\: [SingleCacheOptions](/api/cache-manager.md#SingleCacheOptions)\ | { store: (string | [Cache](/api/cache-manager/namespace/CacheManager.md#Cache) | [SingleCacheOptions](/api/cache-manager.md#SingleCacheOptions)\ | () => [Cache](/api/cache-manager/namespace/CacheManager.md#Cache) | Promise<[Cache](/api/cache-manager/namespace/CacheManager.md#Cache)>)\[] } #### Type parameters * **S**: [Store](/api/cache-manager/namespace/CacheManager.md#Store) = any * **T**: object = any ### [**](#CachingDecoratorKeyOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/decorator/cacheKey.ts#L4)CachingDecoratorKeyOptions **CachingDecoratorKeyOptions: string | (options: { ctx? : IMidwayContext; methodArgs: any\[]; target: any }) => string ### [**](#MidwayCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/interface.ts#L37)MidwayCache **MidwayCache: [Cache](/api/cache-manager/namespace/CacheManager.md#Cache) ### [**](#MidwayMultiCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/interface.ts#L39)MidwayMultiCache **MidwayMultiCache: [MultiCache](/api/cache-manager/namespace/CacheManager.md#MultiCache) ### [**](#MidwayUnionCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/interface.ts#L41)MidwayUnionCache **MidwayUnionCache: [MidwayCache](/api/cache-manager.md#MidwayCache) | [MidwayMultiCache](/api/cache-manager.md#MidwayMultiCache) ### [**](#SingleCacheOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/interface.ts#L10)SingleCacheOptions **SingleCacheOptions\: { options? : [MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig); store: memory } | { store: S | () => S | Promise\ } | { options? : [FactoryConfig](/api/cache-manager/namespace/CacheManager.md#FactoryConfig)\>\[0]>; store: [FactoryStore](/api/cache-manager/namespace/CacheManager.md#FactoryStore)\ } #### Type parameters * **S**: [Store](/api/cache-manager/namespace/CacheManager.md#Store) = any * **T**: object = any ## Variables[**](#Variables) ### [**](#CACHE_DECORATOR_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/decorator/cacheKey.ts#L3)constCACHE\_DECORATOR\_KEY **CACHE\_DECORATOR\_KEY: cache-manager:caching = 'cache-manager:caching' --- # CachingFactory ### Hierarchy * ServiceFactory<[MidwayUnionCache](/api/cache-manager.md#MidwayUnionCache)> * *CachingFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getCaching](#getCaching) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getMultiCaching](#getMultiCaching) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CachingFactory(): [CachingFactory](/api/cache-manager/class/CachingFactory.md) - Inherited from ServiceFactory\.constructor ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [MidwayUnionCache](/api/cache-manager.md#MidwayUnionCache) ### [**](#getCaching)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/factory.ts#L178)publicgetCaching * **getCaching(cacheKey: string): [MidwayCache](/api/cache-manager.md#MidwayCache) ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getMultiCaching)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/factory.ts#L182)publicgetMultiCaching * **getMultiCaching(cacheKey: string): [MultiCache](/api/cache-manager/namespace/CacheManager.md#MultiCache) ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/factory.ts#L174)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cacheService](#cacheService) * [**decoratorService](#decoratorService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CacheConfiguration](/api/cache-manager/class/Configuration.md) ## Properties[**](#Properties) ### [**](#cacheService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/configuration.ts#L38)cacheService **cacheService: [CachingFactory](/api/cache-manager/class/CachingFactory.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/configuration.ts#L36)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/configuration.ts#L40)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady --- # Caching ### Callable * **Caching(cacheInstanceName: string, cacheKeyOrTTL? : number | [CachingDecoratorKeyOptions](/api/cache-manager.md#CachingDecoratorKeyOptions), ttl? : number): MethodDecorator --- # createRedisStore ### Callable * **createRedisStore(instanceName: string): (options: [Config](/api/cache-manager/namespace/CacheManager.md#Config), container: IMidwayContainer) => Promise<[RedisStore](/api/cache-manager/interface/RedisStore.md)> --- # getClassMethodDefaultCacheKey ### Callable * **getClassMethodDefaultCacheKey(target: any, methodName: string): string --- # RedisStore ### Hierarchy * [Store](/api/cache-manager/namespace/CacheManager.md#Store) * *RedisStore* ## Index[**](#Index) ### Properties * [**isCacheable](#isCacheable) ### Methods * [**del](#del) * [**get](#get) * [**keys](#keys) * [**mdel](#mdel) * [**mget](#mget) * [**mset](#mset) * [**reset](#reset) * [**set](#set) * [**ttl](#ttl) ## Properties[**](#Properties) ### [**](#isCacheable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/store.ts#L11)readonlyisCacheable **isCacheable: (value: unknown) => boolean ## Methods[**](#Methods) ### [**](#del)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L17)del * **del(key: string): Promise\ - Inherited from Store.del ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L15)get * **get\(key: string): Promise\ - Inherited from Store.get #### Type parameters * **T** ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L22)keys * **keys(pattern? : string): Promise\ - Inherited from Store.keys ### [**](#mdel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L21)mdel * **mdel(...args: string\[]): Promise\ - Inherited from Store.mdel ### [**](#mget)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L20)mget * **mget(...args: string\[]): Promise\ - Inherited from Store.mget ### [**](#mset)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L19)mset * **mset(args: \[string, unknown]\[], ttl? : number): Promise\ - Inherited from Store.mset ### [**](#reset)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L18)reset * **reset(): Promise\ - Inherited from Store.reset ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L16)set * **set\(key: string, data: T, ttl? : number): Promise\ - Inherited from Store.set #### Type parameters * **T** ### [**](#ttl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L23)ttl * **ttl(key: string): Promise\ - Inherited from Store.ttl --- # CacheManager ## Index[**](#Index) ### Type Aliases * [**Cache](/api/cache-manager/namespace/CacheManager.md#Cache) * [**CachingConfig](/api/cache-manager/namespace/CacheManager.md#CachingConfig) * [**Config](/api/cache-manager/namespace/CacheManager.md#Config) * [**FactoryConfig](/api/cache-manager/namespace/CacheManager.md#FactoryConfig) * [**FactoryStore](/api/cache-manager/namespace/CacheManager.md#FactoryStore) * [**LRU](/api/cache-manager/namespace/CacheManager.md#LRU) * [**MemoryCache](/api/cache-manager/namespace/CacheManager.md#MemoryCache) * [**MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig) * [**MemoryStore](/api/cache-manager/namespace/CacheManager.md#MemoryStore) * [**Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds) * [**MultiCache](/api/cache-manager/namespace/CacheManager.md#MultiCache) * [**Store](/api/cache-manager/namespace/CacheManager.md#Store) * [**StoreConfig](/api/cache-manager/namespace/CacheManager.md#StoreConfig) * [**Stores](/api/cache-manager/namespace/CacheManager.md#Stores) * [**WrapTTL](/api/cache-manager/namespace/CacheManager.md#WrapTTL) ### Functions * [**caching](/api/cache-manager/namespace/CacheManager.md#caching) * [**createCache](/api/cache-manager/namespace/CacheManager.md#createCache) * [**memoryStore](/api/cache-manager/namespace/CacheManager.md#memoryStore) * [**multiCaching](/api/cache-manager/namespace/CacheManager.md#multiCaching) ## Type Aliases[**](<#Type Aliases>) ### [**](#Cache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L39)Cache **Cache\: { del: (key: string) => Promise\; get: \(key: string) => Promise\; reset: () => Promise\; set: (key: string, value: unknown, ttl? : [Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds)) => Promise\; store: S; methodWrap: any; wrap: any } #### Type parameters * **S**: [Store](/api/cache-manager/namespace/CacheManager.md#Store) = [Store](/api/cache-manager/namespace/CacheManager.md#Store) ### [**](#CachingConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L37)CachingConfig **CachingConfig\: [MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig) | [StoreConfig](/api/cache-manager/namespace/CacheManager.md#StoreConfig) | [FactoryConfig](/api/cache-manager/namespace/CacheManager.md#FactoryConfig)\ #### Type parameters * **T** ### [**](#Config)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L6)Config **Config: { isCacheable? : (val: unknown) => boolean; refreshThreshold? : [Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds); ttl? : [Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds) } ### [**](#FactoryConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L28)FactoryConfig **FactoryConfig\: T & [Config](/api/cache-manager/namespace/CacheManager.md#Config) #### Type parameters * **T** ### [**](#FactoryStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L29)FactoryStore **FactoryStore\: (config? : [FactoryConfig](/api/cache-manager/namespace/CacheManager.md#FactoryConfig)\) => S | Promise\ #### Type parameters * **S**: [Store](/api/cache-manager/namespace/CacheManager.md#Store) * **T**: object = never ### [**](#LRU)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L54)LRU **LRU: LRUCache\ ### [**](#MemoryCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L70)MemoryCache **MemoryCache: [Cache](/api/cache-manager/namespace/CacheManager.md#Cache)<[MemoryStore](/api/cache-manager/namespace/CacheManager.md#MemoryStore)> ### [**](#MemoryConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L57)MemoryConfig **MemoryConfig: { max? : number; shouldCloneBeforeSet? : boolean; sizeCalculation? : (value: unknown, key: string) => number } & Options & [Config](/api/cache-manager/namespace/CacheManager.md#Config) ### [**](#MemoryStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L64)MemoryStore **MemoryStore: [Store](/api/cache-manager/namespace/CacheManager.md#Store) & { calculatedSize: [LRU](/api/cache-manager/namespace/CacheManager.md#LRU)\[calculatedSize]; dump: [LRU](/api/cache-manager/namespace/CacheManager.md#LRU)\[dump]; load: [LRU](/api/cache-manager/namespace/CacheManager.md#LRU)\[load]; size: any } ### [**](#Milliseconds)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L12)Milliseconds **Milliseconds: number ### [**](#MultiCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L3)MultiCache **MultiCache: Omit<[Cache](/api/cache-manager/namespace/CacheManager.md#Cache), store> & Pick<[Cache](/api/cache-manager/namespace/CacheManager.md#Cache)\[store], mset | mget | mdel> ### [**](#Store)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L14)Store **Store: { del: any; get: any; keys: any; mdel: any; mget: any; mset: any; reset: any; set: any; ttl: any } ### [**](#StoreConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L26)StoreConfig **StoreConfig: [Config](/api/cache-manager/namespace/CacheManager.md#Config) ### [**](#Stores)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L33)Stores **Stores\: memory | [Store](/api/cache-manager/namespace/CacheManager.md#Store) | [FactoryStore](/api/cache-manager/namespace/CacheManager.md#FactoryStore)\ #### Type parameters * **S**: [Store](/api/cache-manager/namespace/CacheManager.md#Store) * **T**: object ### [**](#WrapTTL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/types.ts#L38)WrapTTL **WrapTTL\: [Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds) | (v: T) => [Milliseconds](/api/cache-manager/namespace/CacheManager.md#Milliseconds) #### Type parameters * **T** ## Functions[**](#Functions) ### [**](#caching)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L25)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L29)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L30)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L38)caching * **caching(name: memory, args? : [MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig)): Promise<[MemoryCache](/api/cache-manager/namespace/CacheManager.md#MemoryCache)> * **caching\(store: S): Promise<[Cache](/api/cache-manager/namespace/CacheManager.md#Cache)\> * **caching\(factory: [FactoryStore](/api/cache-manager/namespace/CacheManager.md#FactoryStore)\, args? : [FactoryConfig](/api/cache-manager/namespace/CacheManager.md#FactoryConfig)\): Promise<[Cache](/api/cache-manager/namespace/CacheManager.md#Cache)\> - Generic caching interface that wraps any caching library with a compatible interface. ### [**](#createCache)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L54)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L59)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L64)createCache * **createCache(store: [MemoryStore](/api/cache-manager/namespace/CacheManager.md#MemoryStore), args? : [MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig)): [MemoryCache](/api/cache-manager/namespace/CacheManager.md#MemoryCache) * **createCache(store: [Store](/api/cache-manager/namespace/CacheManager.md#Store), args? : [Config](/api/cache-manager/namespace/CacheManager.md#Config)): [Cache](/api/cache-manager/namespace/CacheManager.md#Cache)<[Store](/api/cache-manager/namespace/CacheManager.md#Store)> - Create cache instance by store (non-async). ### [**](#memoryStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/store.ts#L15)memoryStore * **memoryStore(args? : [MemoryConfig](/api/cache-manager/namespace/CacheManager.md#MemoryConfig)): [MemoryStore](/api/cache-manager/namespace/CacheManager.md#MemoryStore) - Wrapper for lru-cache. ### [**](#multiCaching)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cache-manager/src/base/cacheManager.ts#L139)multiCaching * **multiCaching\(caches: Caches): [MultiCache](/api/cache-manager/namespace/CacheManager.md#MultiCache) - Module that lets you specify a hierarchy of caches. *** #### Type parameters * **Caches**: [Cache](/api/cache-manager/namespace/CacheManager.md#Cache)\[] --- # @midwayjs/captcha ## Index[**](#Index) ### Classes * [**CaptchaService](/api/captcha/class/CaptchaService.md) * [**Configuration](/api/captcha/class/Configuration.md) ### Interfaces * [**CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md) * [**CaptchaOptions](/api/captcha/interface/CaptchaOptions.md) * [**FormulaCaptchaOptions](/api/captcha/interface/FormulaCaptchaOptions.md) * [**ImageCaptchaOptions](/api/captcha/interface/ImageCaptchaOptions.md) * [**TextCaptchaOptions](/api/captcha/interface/TextCaptchaOptions.md) --- # CaptchaService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**check](#check) * [**formula](#formula) * [**image](#image) * [**set](#set) * [**text](#text) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CaptchaService(): [CaptchaService](/api/captcha/class/CaptchaService.md) ## Methods[**](#Methods) ### [**](#check)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/service.ts#L120)check * **check(id: string, value: string, cacheOptions? : [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md)): Promise\ ### [**](#formula)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/service.ts#L58)formula * **formula(options? : [FormulaCaptchaOptions](/api/captcha/interface/FormulaCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; imageBase64: string }> ### [**](#image)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/service.ts#L35)image * **image(options? : [ImageCaptchaOptions](/api/captcha/interface/ImageCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; imageBase64: string }> ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/service.ts#L110)set * **set(text: string, cacheOptions? : [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md)): Promise\ ### [**](#text)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/service.ts#L77)text * **text(options? : [TextCaptchaOptions](/api/captcha/interface/TextCaptchaOptions.md), cacheOption? : [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md)): Promise<{ id: string; text: string }> --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CaptchaConfiguration](/api/captcha/class/Configuration.md) --- # CaptchaCacheOptions ### Hierarchy * *CaptchaCacheOptions* * [CaptchaOptions](/api/captcha/interface/CaptchaOptions.md) ## Index[**](#Index) ### Properties * [**expirationTime](#expirationTime) * [**idPrefix](#idPrefix) ## Properties[**](#Properties) ### [**](#expirationTime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L5)optionalexpirationTime **expirationTime? : number ### [**](#idPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L7)optionalidPrefix **idPrefix? : string --- # CaptchaOptions ### Hierarchy * [CaptchaCacheOptions](/api/captcha/interface/CaptchaCacheOptions.md) * *CaptchaOptions* ## Index[**](#Index) ### Properties * [**default](#default) * [**expirationTime](#expirationTime) * [**formula](#formula) * [**idPrefix](#idPrefix) * [**image](#image) * [**text](#text) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L11)optionaldefault **default? : ConfigObject ### [**](#expirationTime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L5)optionalexpirationTime **expirationTime? : number Inherited from CaptchaCacheOptions.expirationTime ### [**](#formula)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L13)optionalformula **formula? : [FormulaCaptchaOptions](/api/captcha/interface/FormulaCaptchaOptions.md) ### [**](#idPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L7)optionalidPrefix **idPrefix? : string Inherited from CaptchaCacheOptions.idPrefix ### [**](#image)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L12)optionalimage **image? : [ImageCaptchaOptions](/api/captcha/interface/ImageCaptchaOptions.md) ### [**](#text)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L14)optionaltext **text? : [TextCaptchaOptions](/api/captcha/interface/TextCaptchaOptions.md) --- # FormulaCaptchaOptions ### Hierarchy * ConfigObject * *FormulaCaptchaOptions* --- # ImageCaptchaOptions ### Hierarchy * ConfigObject * *ImageCaptchaOptions* ## Index[**](#Index) ### Properties * [**type](#type) ## Properties[**](#Properties) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L18)optionaltype **type? : number | letter | mixed --- # TextCaptchaOptions ## Index[**](#Index) ### Properties * [**size](#size) * [**type](#type) ## Properties[**](#Properties) ### [**](#size)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L24)optionalsize **size? : number ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/captcha/src/interface.ts#L25)optionaltype **type? : number | letter | mixed --- # @midwayjs/casbin ## Index[**](#Index) ### Classes * [**AuthGuard](/api/casbin/class/AuthGuard.md) * [**BaseAdapter](/api/casbin/class/BaseAdapter.md) * [**CasbinEnforcerService](/api/casbin/class/CasbinEnforcerService.md) * [**Configuration](/api/casbin/class/Configuration.md) ### Enumerations * [**AuthAction](/api/casbin/enum/AuthAction.md) * [**AuthActionVerb](/api/casbin/enum/AuthActionVerb.md) * [**AuthPossession](/api/casbin/enum/AuthPossession.md) ### Functions * [**UsePermission](/api/casbin/function/UsePermission.md) ### Interfaces * [**CasbinConfigOptions](/api/casbin/interface/CasbinConfigOptions.md) * [**Permission](/api/casbin/interface/Permission.md) ### Type Aliases * [**CustomAuthActionVerb](/api/casbin.md#CustomAuthActionVerb) ### Variables * [**PERMISSIONS\_METADATA\_KEY](/api/casbin.md#PERMISSIONS_METADATA_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#CustomAuthActionVerb)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L24)CustomAuthActionVerb **CustomAuthActionVerb: string ## Variables[**](#Variables) ### [**](#PERMISSIONS_METADATA_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L1)constPERMISSIONS\_METADATA\_KEY **PERMISSIONS\_METADATA\_KEY: casbin:permission\_metadata = 'casbin:permission\_metadata' --- # @midwayjs/casbin-redis-adapter ## Index[**](#Index) ### Classes * [**BaseWatcher](/api/casbin-redis-adapter/class/BaseWatcher.md) * [**NodeRedisAdapter](/api/casbin-redis-adapter/class/NodeRedisAdapter.md) * [**NodeRedisWatcher](/api/casbin-redis-adapter/class/NodeRedisWatcher.md) ### Functions * [**createAdapter](/api/casbin-redis-adapter/function/createAdapter.md) * [**createWatcher](/api/casbin-redis-adapter/function/createWatcher.md) --- # abstractBaseWatcher \ ### Hierarchy * *BaseWatcher* * [NodeRedisWatcher](/api/casbin-redis-adapter/class/NodeRedisWatcher.md) ### Implements * Watcher ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getDefaultSubscribeKeyName](#getDefaultSubscribeKeyName) * [**publishData](#publishData) * [**setUpdateCallback](#setUpdateCallback) * [**subscribeData](#subscribeData) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L7)constructor * **new BaseWatcher\(options: { pubClient? : Client; subClient: Client; subscribeKeyName? : string }): [BaseWatcher](/api/casbin-redis-adapter/class/BaseWatcher.md)\ - #### Type parameters * **Client** ## Methods[**](#Methods) ### [**](#getDefaultSubscribeKeyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L42)getDefaultSubscribeKeyName * **getDefaultSubscribeKeyName(): string ### [**](#publishData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L38)abstractpublishData * **publishData(): any ### [**](#setUpdateCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L26)setUpdateCallback * **setUpdateCallback(callback: () => void): void - Implementation of Watcher.setUpdateCallback ### [**](#subscribeData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L39)abstractsubscribeData * **subscribeData(callback: any): any ### [**](#update)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L29)update * **update(): Promise\ - Implementation of Watcher.update --- # NodeRedisAdapter ### Hierarchy * BaseAdapter\ * *NodeRedisAdapter* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/adapter.ts#L17)constructor * **new NodeRedisAdapter(redisInstance: any): [NodeRedisAdapter](/api/casbin-redis-adapter/class/NodeRedisAdapter.md) - Overrides BaseAdapter\.constructor ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L17)addPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.addPolicy ### [**](#isFiltered)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L14)isFiltered * **isFiltered(): boolean - Inherited from BaseAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L19)loadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Inherited from BaseAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L15)loadPolicy * **loadPolicy(model: Model): Promise\ - Inherited from BaseAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L20)removeFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Inherited from BaseAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L18)removePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.removePolicy ### [**](#savePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L16)savePolicy * **savePolicy(model: Model): Promise\ - Inherited from BaseAdapter.savePolicy --- # NodeRedisWatcher ### Hierarchy * [BaseWatcher](/api/casbin-redis-adapter/class/BaseWatcher.md)\ * *NodeRedisWatcher* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getDefaultSubscribeKeyName](#getDefaultSubscribeKeyName) * [**publishData](#publishData) * [**setUpdateCallback](#setUpdateCallback) * [**subscribeData](#subscribeData) * [**update](#update) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L7)constructor * **new NodeRedisWatcher(options: { pubClient? : Redis; subClient: Redis; subscribeKeyName? : string }): [NodeRedisWatcher](/api/casbin-redis-adapter/class/NodeRedisWatcher.md) - Inherited from BaseWatcher.constructor ## Methods[**](#Methods) ### [**](#getDefaultSubscribeKeyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L42)getDefaultSubscribeKeyName * **getDefaultSubscribeKeyName(): string - Inherited from BaseWatcher.getDefaultSubscribeKeyName ### [**](#publishData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L48)publishData * **publishData(): Promise\ - Overrides BaseWatcher.publishData ### [**](#setUpdateCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L26)setUpdateCallback * **setUpdateCallback(callback: () => void): void - Inherited from BaseWatcher.setUpdateCallback ### [**](#subscribeData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L55)subscribeData * **subscribeData(callback: any): Promise\ - Overrides BaseWatcher.subscribeData ### [**](#update)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-redis-adapter/src/watcher.ts#L29)update * **update(): Promise\ - Inherited from BaseWatcher.update --- # createAdapter ### Callable * **createAdapter(options: { clientName: string }): (container: IMidwayContainer) => Promise<[NodeRedisAdapter](/api/casbin-redis-adapter/class/NodeRedisAdapter.md)> --- # createWatcher ### Callable * **createWatcher(options: { keyName? : string; pubClientName: string; subClientName: string }): (container: IMidwayContainer) => Promise<[NodeRedisWatcher](/api/casbin-redis-adapter/class/NodeRedisWatcher.md)> --- # @midwayjs/casbin-typeorm-adapter ## Index[**](#Index) ### Classes * [**CasbinMongoRule](/api/casbin-typeorm-adapter/class/CasbinMongoRule.md) * [**CasbinRule](/api/casbin-typeorm-adapter/class/CasbinRule.md) * [**TypeORMAdapter](/api/casbin-typeorm-adapter/class/TypeORMAdapter.md) ### Functions * [**createAdapter](/api/casbin-typeorm-adapter/function/createAdapter.md) --- # CasbinMongoRule ### Hierarchy * BaseEntity * *CasbinMongoRule* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**id](#id) * [**ptype](#ptype) * [**v0](#v0) * [**v1](#v1) * [**v2](#v2) * [**v3](#v3) * [**v4](#v4) * [**v5](#v5) * [**v6](#v6) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinMongoRule(): [CasbinMongoRule](/api/casbin-typeorm-adapter/class/CasbinMongoRule.md) - Inherited from BaseEntity.constructor ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L21)publicid **id: typeof ObjectId ### [**](#ptype)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L26)publicptype **ptype: string ### [**](#v0)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L31)publicv0 **v0: string ### [**](#v1)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L36)publicv1 **v1: string ### [**](#v2)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L41)publicv2 **v2: string ### [**](#v3)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L46)publicv3 **v3: string ### [**](#v4)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L51)publicv4 **v4: string ### [**](#v5)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L56)publicv5 **v5: string ### [**](#v6)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinMongoRule.ts#L61)publicv6 **v6: string --- # CasbinRule ### Hierarchy * BaseEntity * *CasbinRule* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**id](#id) * [**ptype](#ptype) * [**v0](#v0) * [**v1](#v1) * [**v2](#v2) * [**v3](#v3) * [**v4](#v4) * [**v5](#v5) * [**v6](#v6) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinRule(): [CasbinRule](/api/casbin-typeorm-adapter/class/CasbinRule.md) - Inherited from BaseEntity.constructor ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L6)publicid **id: number ### [**](#ptype)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L11)publicptype **ptype: string ### [**](#v0)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L16)publicv0 **v0: string ### [**](#v1)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L21)publicv1 **v1: string ### [**](#v2)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L26)publicv2 **v2: string ### [**](#v3)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L31)publicv3 **v3: string ### [**](#v4)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L36)publicv4 **v4: string ### [**](#v5)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L41)publicv5 **v5: string ### [**](#v6)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/casbinRule.ts#L46)publicv6 **v6: string --- # TypeORMAdapter TypeORMAdapter represents the TypeORM filtered adapter for policy storage. ### Hierarchy * BaseAdapter\ * *TypeORMAdapter* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin-typeorm-adapter/src/adapter.ts#L18)constructor * **new TypeORMAdapter(dataSource: DataSource, options: TypeORMAdapterConfig): [TypeORMAdapter](/api/casbin-typeorm-adapter/class/TypeORMAdapter.md) - Overrides BaseAdapter\.constructor ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L17)addPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.addPolicy ### [**](#isFiltered)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L14)isFiltered * **isFiltered(): boolean - Inherited from BaseAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L19)loadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Inherited from BaseAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L15)loadPolicy * **loadPolicy(model: Model): Promise\ - Inherited from BaseAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L20)removeFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Inherited from BaseAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L18)removePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Inherited from BaseAdapter.removePolicy ### [**](#savePolicy)[**](https://undefined/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.d.ts#L16)savePolicy * **savePolicy(model: Model): Promise\ - Inherited from BaseAdapter.savePolicy --- # createAdapter ### Callable * **createAdapter(options: TypeORMAdapterConfig): (container: IMidwayContainer) => Promise<[TypeORMAdapter](/api/casbin-typeorm-adapter/class/TypeORMAdapter.md)> --- # AuthGuard ### Implements * IGuard ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**casbinConfig](#casbinConfig) * [**enforcer](#enforcer) ### Methods * [**canActivate](#canActivate) * [**asyncEvery](#asyncEvery) * [**asyncSome](#asyncSome) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AuthGuard(): [AuthGuard](/api/casbin/class/AuthGuard.md) ## Properties[**](#Properties) ### [**](#casbinConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/auth.guard.ts#L19)casbinConfig **casbinConfig: [CasbinConfigOptions](/api/casbin/interface/CasbinConfigOptions.md) ### [**](#enforcer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/auth.guard.ts#L16)enforcer **enforcer: [CasbinEnforcerService](/api/casbin/class/CasbinEnforcerService.md) ## Methods[**](#Methods) ### [**](#canActivate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/auth.guard.ts#L21)canActivate * **canActivate(context: Context, supplierClz: any, methodName: string): Promise\ - Implementation of IGuard.canActivate ### [**](#asyncEvery)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/auth.guard.ts#L84)staticasyncEvery * **asyncEvery\(array: T\[], callback: (value: T, index: number, a: T\[]) => Promise\): Promise\ - #### Type parameters * **T** ### [**](#asyncSome)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/auth.guard.ts#L70)staticasyncSome * **asyncSome\(array: T\[], callback: (value: T, index: number, a: T\[]) => Promise\): Promise\ - #### Type parameters * **T** --- # abstractBaseAdapter \ ### Implements * FilteredAdapter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addPolicy](#addPolicy) * [**isFiltered](#isFiltered) * [**loadFilteredPolicy](#loadFilteredPolicy) * [**loadPolicy](#loadPolicy) * [**removeFilteredPolicy](#removeFilteredPolicy) * [**removePolicy](#removePolicy) * [**savePolicy](#savePolicy) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BaseAdapter\(): [BaseAdapter](/api/casbin/class/BaseAdapter.md)\ - #### Type parameters * **AdapterLine**: Line ## Methods[**](#Methods) ### [**](#addPolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L49)publicaddPolicy * **addPolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Implementation of FilteredAdapter.addPolicy ### [**](#isFiltered)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L19)publicisFiltered * **isFiltered(): boolean - Implementation of FilteredAdapter.isFiltered ### [**](#loadFilteredPolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L92)publicloadFilteredPolicy * **loadFilteredPolicy(model: Model, filter: any): Promise\ - Implementation of FilteredAdapter.loadFilteredPolicy ### [**](#loadPolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L23)publicloadPolicy * **loadPolicy(model: Model): Promise\ - Implementation of FilteredAdapter.loadPolicy ### [**](#removeFilteredPolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L101)publicremoveFilteredPolicy * **removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string\[]): Promise\ - Implementation of FilteredAdapter.removeFilteredPolicy ### [**](#removePolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L59)publicremovePolicy * **removePolicy(sec: string, ptype: string, rule: string\[]): Promise\ - Implementation of FilteredAdapter.removePolicy ### [**](#savePolicy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/adapter.ts#L31)publicsavePolicy * **savePolicy(model: Model): Promise\ - Implementation of FilteredAdapter.savePolicy --- # CasbinEnforcerService ### Hierarchy * Enforcer * *CasbinEnforcerService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**getEnforcer](#getEnforcer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CasbinEnforcerService(): [CasbinEnforcerService](/api/casbin/class/CasbinEnforcerService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/enforcer.service.ts#L23)applicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#getEnforcer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/enforcer.service.ts#L49)publicgetEnforcer * **getEnforcer(): Enforcer --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CasbinConfiguration](/api/casbin/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/configuration.ts#L15)onReady * **onReady(container: any): Promise\ --- # AuthAction ## Index[**](#Index) ### Enumeration Members * [**CREATE\_ANY](#CREATE_ANY) * [**CREATE\_OWN](#CREATE_OWN) * [**DELETE\_ANY](#DELETE_ANY) * [**DELETE\_OWN](#DELETE_OWN) * [**READ\_ANY](#READ_ANY) * [**READ\_OWN](#READ_OWN) * [**UPDATE\_ANY](#UPDATE_ANY) * [**UPDATE\_OWN](#UPDATE_OWN) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#CREATE_ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L17)CREATE\_ANY **CREATE\_ANY: create:any ### [**](#CREATE_OWN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L18)CREATE\_OWN **CREATE\_OWN: create:own ### [**](#DELETE_ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L23)DELETE\_ANY **DELETE\_ANY: delete:any ### [**](#DELETE_OWN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L24)DELETE\_OWN **DELETE\_OWN: delete:own ### [**](#READ_ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L26)READ\_ANY **READ\_ANY: read:any ### [**](#READ_OWN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L27)READ\_OWN **READ\_OWN: read:own ### [**](#UPDATE_ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L20)UPDATE\_ANY **UPDATE\_ANY: update:any ### [**](#UPDATE_OWN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L21)UPDATE\_OWN **UPDATE\_OWN: update:own --- # AuthActionVerb ## Index[**](#Index) ### Enumeration Members * [**CREATE](#CREATE) * [**DELETE](#DELETE) * [**READ](#READ) * [**UPDATE](#UPDATE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#CREATE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L4)CREATE **CREATE: create ### [**](#DELETE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L6)DELETE **DELETE: delete ### [**](#READ)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L7)READ **READ: read ### [**](#UPDATE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L5)UPDATE **UPDATE: update --- # AuthPossession ## Index[**](#Index) ### Enumeration Members * [**ANY](#ANY) * [**OWN](#OWN) * [**OWN\_ANY](#OWN_ANY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L11)ANY **ANY: any ### [**](#OWN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L12)OWN **OWN: own ### [**](#OWN_ANY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/constants.ts#L13)OWN\_ANY **OWN\_ANY: own|any --- # UsePermission ### Callable * **UsePermission(...permissions: [Permission](/api/casbin/interface/Permission.md)\[]): MethodDecorator *** * You can define multiple permissions, but only when all of them satisfied, could you access the route. --- # CasbinConfigOptions ## Index[**](#Index) ### Properties * [**modelPath](#modelPath) * [**policyAdapter](#policyAdapter) * [**policyWatcher](#policyWatcher) * [**usernameFromContext](#usernameFromContext) ## Properties[**](#Properties) ### [**](#modelPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L6)modelPath **modelPath: string ### [**](#policyAdapter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L7)policyAdapter **policyAdapter: string | (applicationContext: IMidwayContainer) => Promise\ | Adapter ### [**](#policyWatcher)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L11)optionalpolicyWatcher **policyWatcher? : Watcher | (applicationContext: IMidwayContainer) => Promise\ ### [**](#usernameFromContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L14)usernameFromContext **usernameFromContext: (ctx: Context) => string --- # Permission ## Index[**](#Index) ### Properties * [**action](#action) * [**isOwn](#isOwn) * [**possession](#possession) * [**resource](#resource) ## Properties[**](#Properties) ### [**](#action)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L19)action **action: string ### [**](#isOwn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L21)optionalisOwn **isOwn? : (ctx: Context) => boolean ### [**](#possession)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L20)possession **possession: [AuthPossession](/api/casbin/enum/AuthPossession.md) ### [**](#resource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/casbin/src/interface.ts#L18)resource **resource: string --- # @midwayjs/code-dye ## Index[**](#Index) ### Classes * [**CodeDyeMW](/api/code-dye/class/CodeDyeMW.md) * [**Configuration](/api/code-dye/class/Configuration.md) ### Interfaces * [**CodeDyeOptions](/api/code-dye/interface/CodeDyeOptions.md) --- # CodeDyeMW ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**codeDye](#codeDye) ### Methods * [**check](#check) * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CodeDyeMW(): [CodeDyeMW](/api/code-dye/class/CodeDyeMW.md) ## Properties[**](#Properties) ### [**](#codeDye)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/middleware.ts#L9)codeDye **codeDye: [CodeDyeOptions](/api/code-dye/interface/CodeDyeOptions.md) ## Methods[**](#Methods) ### [**](#check)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/middleware.ts#L23)check * **check(request: any): any ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/middleware.ts#L42)compatibleMiddleware * **compatibleMiddleware(request: any, response: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/middleware.ts#L11)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**codeDye](#codeDye) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CodeDyeConfiguration](/api/code-dye/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ### [**](#codeDye)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/configuration.ts#L23)codeDye **codeDye: any ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/configuration.ts#L25)onReady * **onReady(container: any): Promise\ --- # CodeDyeOptions ## Index[**](#Index) ### Properties * [**matchHeaderKey](#matchHeaderKey) * [**matchQueryKey](#matchQueryKey) ## Properties[**](#Properties) ### [**](#matchHeaderKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/interface.ts#L2)matchHeaderKey **matchHeaderKey: string ### [**](#matchQueryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/code-dye/src/interface.ts#L3)matchQueryKey **matchQueryKey: string --- # @midwayjs/consul ## Index[**](#Index) ### Classes * [**Configuration](/api/consul/class/Configuration.md) * [**ConsulService](/api/consul/class/ConsulService.md) * [**ConsulServiceDiscoverClient](/api/consul/class/ConsulServiceDiscoverClient.md) * [**ConsulServiceDiscovery](/api/consul/class/ConsulServiceDiscovery.md) * [**ConsulServiceFactory](/api/consul/class/ConsulServiceFactory.md) ### Interfaces * [**ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md) * [**ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md) * [**ConsulServiceDiscoveryOptions](/api/consul/interface/ConsulServiceDiscoveryOptions.md) ### Type Aliases * [**ConsulClient](/api/consul.md#ConsulClient) * [**ConsulOptions](/api/consul.md#ConsulOptions) * [**GetHealthServiceOptions](/api/consul.md#GetHealthServiceOptions) * [**RegisterOptions](/api/consul.md#RegisterOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#ConsulClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L8)ConsulClient **ConsulClient: InstanceType\ ### [**](#ConsulOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L7)ConsulOptions **ConsulOptions: ConstructorParameters\\[0] ### [**](#GetHealthServiceOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L25)GetHealthServiceOptions **GetHealthServiceOptions: { dc? : string; filter? : string; near? : string; ns? : string; passing? : boolean; peer? : string; service: string; tag? : string } From ConsulClient\['health']\['service'] ### [**](#RegisterOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L19)RegisterOptions **RegisterOptions: GetFirstParam\> --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ConsulConfiguration](/api/consul/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/configuration.ts#L25)onReady * **onReady(container: IMidwayContainer, app? : IMidwayBaseApplication\): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/configuration.ts#L32)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # ConsulService ### Hierarchy * InstanceType\ * *ConsulService* ### Implements * InstanceType\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ConsulService(): [ConsulService](/api/consul/class/ConsulService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L141)init * **init(): Promise\ --- # ConsulServiceDiscoverClient The adapter for consul service discovery * **@since** 4.0.0 ### Hierarchy * ServiceDiscoveryClient<[ConsulClient](/api/consul.md#ConsulClient), [ConsulServiceDiscoveryOptions](/api/consul/interface/ConsulServiceDiscoveryOptions.md), [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md), [ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)> * *ConsulServiceDiscoverClient* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**defaultMeta](#defaultMeta) ### Methods * [**beforeStop](#beforeStop) * [**deregister](#deregister) * [**getSelfInstance](#getSelfInstance) * [**offline](#offline) * [**online](#online) * [**register](#register) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L101)constructor * **new ConsulServiceDiscoverClient(consul: Consul, serviceDiscoveryOptions: [ConsulServiceDiscoveryOptions](/api/consul/interface/ConsulServiceDiscoveryOptions.md), applicationManager: MidwayApplicationManager, webRouterService: MidwayWebRouterService, logger: ILogger): [ConsulServiceDiscoverClient](/api/consul/class/ConsulServiceDiscoverClient.md) - Overrides ServiceDiscoveryClient< ConsulClient, ConsulServiceDiscoveryOptions, ConsulInstanceMetadata, ConsulHealthItem >.constructor ## Accessors[**](#Accessors) ### [**](#defaultMeta)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L9)defaultMeta * **get defaultMeta(): DefaultInstanceMetadata - Inherited from ServiceDiscoveryClient.defaultMeta ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L219)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscoveryClient.beforeStop ### [**](#deregister)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L173)deregister * **deregister(instance? : [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md)): Promise\ - Overrides ServiceDiscoveryClient.deregister ### [**](#getSelfInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L11)getSelfInstance * **getSelfInstance(): [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md) - Inherited from ServiceDiscoveryClient.getSelfInstance ### [**](#offline)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L215)offline * **offline(): Promise\ - Overrides ServiceDiscoveryClient.offline ### [**](#online)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L211)online * **online(): Promise\ - Overrides ServiceDiscoveryClient.online ### [**](#register)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L111)register * **register(instance: [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md)): Promise\ - Overrides ServiceDiscoveryClient.register ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L16)stop * **stop(): Promise\ - Inherited from ServiceDiscoveryClient.stop 停止服务发现 --- # ConsulServiceDiscovery The service discovery for consul * **@since** 4.0.0 ### Hierarchy * ServiceDiscovery<[ConsulClient](/api/consul.md#ConsulClient), [ConsulServiceDiscoveryOptions](/api/consul/interface/ConsulServiceDiscoveryOptions.md), [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md), [ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md), [GetHealthServiceOptions](/api/consul.md#GetHealthServiceOptions)> * *ConsulServiceDiscovery* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**beforeStop](#beforeStop) * [**createClient](#createClient) * [**getInstance](#getInstance) * [**getInstances](#getInstances) * [**init](#init) * [**setLoadBalancer](#setLoadBalancer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ConsulServiceDiscovery(): [ConsulServiceDiscovery](/api/consul/class/ConsulServiceDiscovery.md) - Inherited from ServiceDiscovery< ConsulClient, ConsulServiceDiscoveryOptions, ConsulInstanceMetadata, ConsulHealthItem, GetHealthServiceOptions >.constructor ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L332)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscovery.beforeStop ### [**](#createClient)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L41)createClient * **createClient(options? : ServiceDiscoveryOptions<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md), Record\>): ServiceDiscoveryClient\ - Inherited from ServiceDiscovery.createClient ### [**](#getInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L52)getInstance * **getInstance(options: [GetHealthServiceOptions](/api/consul.md#GetHealthServiceOptions)): Promise<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)> - Inherited from ServiceDiscovery.getInstance 获取一个可用服务实例(带负载均衡) ### [**](#getInstances)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L322)publicgetInstances * **getInstances(options: [GetHealthServiceOptions](/api/consul.md#GetHealthServiceOptions)): Promise<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)\[]> - Overrides ServiceDiscovery.getInstances ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/extension/serviceDiscovery.ts#L270)init * **init(): Promise\ ### [**](#setLoadBalancer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L56)setLoadBalancer * **setLoadBalancer(type: LoadBalancerType | ILoadBalancer<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)>): void - Inherited from ServiceDiscovery.setLoadBalancer 设置负载均衡策略 --- # ConsulServiceFactory ### Hierarchy * ServiceFactory<[ConsulClient](/api/consul.md#ConsulClient)> * *ConsulServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**consulConfig](#consulConfig) * [**logger](#logger) * [**traceEnabled](#traceEnabled) * [**traceInjector](#traceInjector) * [**traceMetaResolver](#traceMetaResolver) * [**traceService](#traceService) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ConsulServiceFactory(): [ConsulServiceFactory](/api/consul/class/ConsulServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#consulConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L20)consulConfig **consulConfig: ServiceFactoryConfigOption\ ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L39)logger **logger: ILogger ### [**](#traceEnabled)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L26)traceEnabled **traceEnabled: any ### [**](#traceInjector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L29)traceInjector **traceInjector: any ### [**](#traceMetaResolver)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L23)traceMetaResolver **traceMetaResolver: any ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L42)traceService **traceService: MidwayTraceService ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L44)createClient * **createClient(config: ConsulOptions, clientName: string): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L127)destroyClient * **destroyClient(client: Consul, clientName: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Consul ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L123)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/manager.ts#L32)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # ConsulHealthItem ## Index[**](#Index) ### Properties * [**Checks](#Checks) * [**Node](#Node) * [**Service](#Service) ## Properties[**](#Properties) ### [**](#Checks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L72)Checks **Checks: { CheckID: string; CreateIndex: number; Definition: Record\; ExposedPort: number; Interval: string; ModifyIndex: number; Name: string; Node: string; Notes: string; Output: string; ServiceID: string; ServiceName: string; ServiceTags: string\[]; Status: passing | warning | critical; Timeout: string; Type: string }\[] ### [**](#Node)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L46)Node **Node: { Address: string; CreateIndex: number; Datacenter: string; ID: string; Meta: Record\; ModifyIndex: number; Node: string; TaggedAddresses: Record\ } ### [**](#Service)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L56)Service **Service: { Address: string; Connect: Record\; CreateIndex: number; EnableTagOverride: boolean; ID: string; Meta: Record\; ModifyIndex: number; PeerName: string; Port: number; Proxy: Record\; Service: string; TaggedAddresses: Record\; Tags: string\[]; Weights: Record\ } --- # ConsulInstanceMetadata ### Hierarchy * [RegisterOptions](/api/consul.md#RegisterOptions) * *ConsulInstanceMetadata* --- # ConsulServiceDiscoveryOptions ### Hierarchy * ServiceDiscoveryOptions<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)> * *ConsulServiceDiscoveryOptions* ## Index[**](#Index) ### Properties * [**autoHealthCheck](#autoHealthCheck) * [**loadBalancer](#loadBalancer) * [**serviceDiscoveryClient](#serviceDiscoveryClient) * [**serviceOptions](#serviceOptions) ## Properties[**](#Properties) ### [**](#autoHealthCheck)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L42)optionalautoHealthCheck **autoHealthCheck? : boolean ### [**](#loadBalancer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L1139)optionalloadBalancer **loadBalancer? : LoadBalancerType | ILoadBalancer<[ConsulHealthItem](/api/consul/interface/ConsulHealthItem.md)> Inherited from ServiceDiscoveryOptions.loadBalancer ### [**](#serviceDiscoveryClient)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L1137)optionalserviceDiscoveryClient **serviceDiscoveryClient? : string Inherited from ServiceDiscoveryOptions.serviceDiscoveryClient ### [**](#serviceOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/consul/src/interface.ts#L39)optionalserviceOptions **serviceOptions? : [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md) | (meta: DefaultInstanceMetadata) => [ConsulInstanceMetadata](/api/consul/interface/ConsulInstanceMetadata.md) Overrides ServiceDiscoveryOptions.serviceOptions --- # @midwayjs/core ## Index[**](#Index) ### Classes * [**AbstractFileDetector](/api/core/class/AbstractFileDetector.md) * [**BaseFramework](/api/core/class/BaseFramework.md) * [**CommonJSFileDetector](/api/core/class/CommonJSFileDetector.md) * [**ContextMiddlewareManager](/api/core/class/ContextMiddlewareManager.md) * [**CustomModuleDetector](/api/core/class/CustomModuleDetector.md) * [**DataListener](/api/core/class/DataListener.md) * [**DataSourceManager](/api/core/class/DataSourceManager.md) * [**DecoratorManager](/api/core/class/DecoratorManager.md) * [**DefaultConsoleLoggerFactory](/api/core/class/DefaultConsoleLoggerFactory.md) * [**DynamicMidwayContainer](/api/core/class/DynamicMidwayContainer.md) * [**ESModuleFileDetector](/api/core/class/ESModuleFileDetector.md) * [**FilterManager](/api/core/class/FilterManager.md) * [**HttpClient](/api/core/class/HttpClient.md) * [**HttpServerResponse](/api/core/class/HttpServerResponse.md) * [**LoadBalancerFactory](/api/core/class/LoadBalancerFactory.md) * [**LoggerFactory](/api/core/class/LoggerFactory.md) * [**MetadataManager](/api/core/class/MetadataManager.md) * [**MidwayApplicationManager](/api/core/class/MidwayApplicationManager.md) * [**MidwayAspectService](/api/core/class/MidwayAspectService.md) * [**MidwayCodeInvokeTimeoutError](/api/core/class/MidwayCodeInvokeTimeoutError.md) * [**MidwayCommonError](/api/core/class/MidwayCommonError.md) * [**MidwayConfigMissingError](/api/core/class/MidwayConfigMissingError.md) * [**MidwayConfigService](/api/core/class/MidwayConfigService.md) * [**MidwayContainer](/api/core/class/MidwayContainer.md) * [**MidwayDecoratorService](/api/core/class/MidwayDecoratorService.md) * [**MidwayDefinitionNotFoundError](/api/core/class/MidwayDefinitionNotFoundError.md) * [**MidwayDuplicateClassNameError](/api/core/class/MidwayDuplicateClassNameError.md) * [**MidwayDuplicateControllerOptionsError](/api/core/class/MidwayDuplicateControllerOptionsError.md) * [**MidwayDuplicateRouteError](/api/core/class/MidwayDuplicateRouteError.md) * [**MidwayEmptyValueError](/api/core/class/MidwayEmptyValueError.md) * [**MidwayEnvironmentService](/api/core/class/MidwayEnvironmentService.md) * [**MidwayError](/api/core/class/MidwayError.md) * [**MidwayFeatureNoLongerSupportedError](/api/core/class/MidwayFeatureNoLongerSupportedError.md) * [**MidwayFeatureNotImplementedError](/api/core/class/MidwayFeatureNotImplementedError.md) * [**MidwayFrameworkService](/api/core/class/MidwayFrameworkService.md) * [**MidwayHealthService](/api/core/class/MidwayHealthService.md) * [**MidwayHttpError](/api/core/class/MidwayHttpError.md) * [**MidwayInconsistentVersionError](/api/core/class/MidwayInconsistentVersionError.md) * [**MidwayInformationService](/api/core/class/MidwayInformationService.md) * [**MidwayInvalidConfigError](/api/core/class/MidwayInvalidConfigError.md) * [**MidwayInvalidConfigPropertyError](/api/core/class/MidwayInvalidConfigPropertyError.md) * [**MidwayInvokeForbiddenError](/api/core/class/MidwayInvokeForbiddenError.md) * [**MidwayLifeCycleService](/api/core/class/MidwayLifeCycleService.md) * [**MidwayLoggerService](/api/core/class/MidwayLoggerService.md) * [**MidwayMainFrameworkMissingError](/api/core/class/MidwayMainFrameworkMissingError.md) * [**MidwayMiddlewareService](/api/core/class/MidwayMiddlewareService.md) * [**MidwayMissingImportComponentError](/api/core/class/MidwayMissingImportComponentError.md) * [**MidwayMockService](/api/core/class/MidwayMockService.md) * [**MidwayParameterError](/api/core/class/MidwayParameterError.md) * [**MidwayPerformanceManager](/api/core/class/MidwayPerformanceManager.md) * [**MidwayPriorityManager](/api/core/class/MidwayPriorityManager.md) * [**MidwayRequestContainer](/api/core/class/MidwayRequestContainer.md) * [**MidwayRetryExceededMaxTimesError](/api/core/class/MidwayRetryExceededMaxTimesError.md) * [**MidwayServerlessFunctionService](/api/core/class/MidwayServerlessFunctionService.md) * [**MidwaySingletonInjectRequestError](/api/core/class/MidwaySingletonInjectRequestError.md) * [**MidwayTraceService](/api/core/class/MidwayTraceService.md) * [**MidwayUseWrongMethodError](/api/core/class/MidwayUseWrongMethodError.md) * [**MidwayUtilHttpClientTimeoutError](/api/core/class/MidwayUtilHttpClientTimeoutError.md) * [**MidwayWebRouterService](/api/core/class/MidwayWebRouterService.md) * [**RandomLoadBalance](/api/core/class/RandomLoadBalance.md) * [**RoundRobinLoadBalancer](/api/core/class/RoundRobinLoadBalancer.md) * [**ServerResponse](/api/core/class/ServerResponse.md) * [**ServiceDiscovery](/api/core/class/ServiceDiscovery.md) * [**ServiceDiscoveryClient](/api/core/class/ServiceDiscoveryClient.md) * [**ServiceFactory](/api/core/class/ServiceFactory.md) * [**TypedResourceManager](/api/core/class/TypedResourceManager.md) * [**WebControllerGenerator](/api/core/class/WebControllerGenerator.md) ### Enumerations * [**GrpcStreamTypeEnum](/api/core/enum/GrpcStreamTypeEnum.md) * [**HttpStatus](/api/core/enum/HttpStatus.md) * [**InjectModeEnum](/api/core/enum/InjectModeEnum.md) * [**MSListenerType](/api/core/enum/MSListenerType.md) * [**MSProviderType](/api/core/enum/MSProviderType.md) * [**MidwayProcessTypeEnum](/api/core/enum/MidwayProcessTypeEnum.md) * [**ObjectLifeCycleEvent](/api/core/enum/ObjectLifeCycleEvent.md) * [**RouteParamTypes](/api/core/enum/RouteParamTypes.md) * [**ScopeEnum](/api/core/enum/ScopeEnum.md) * [**ServerlessTriggerType](/api/core/enum/ServerlessTriggerType.md) * [**WSEventTypeEnum](/api/core/enum/WSEventTypeEnum.md) ### Functions * [**All](/api/core/function/All.md) * [**AllConfig](/api/core/function/AllConfig.md) * [**App](/api/core/function/App.md) * [**ApplicationContext](/api/core/function/ApplicationContext.md) * [**Aspect](/api/core/function/Aspect.md) * [**Autoload](/api/core/function/Autoload.md) * [**Body](/api/core/function/Body.md) * [**Catch](/api/core/function/Catch.md) * [**Config](/api/core/function/Config.md) * [**Configuration](/api/core/function/Configuration.md) * [**Consumer](/api/core/function/Consumer.md) * [**ContentType](/api/core/function/ContentType.md) * [**Controller](/api/core/function/Controller.md) * [**Del](/api/core/function/Del.md) * [**Destroy](/api/core/function/Destroy.md) * [**DubboMethod](/api/core/function/DubboMethod.md) * [**Emit](/api/core/function/Emit.md) * [**Fields](/api/core/function/Fields.md) * [**File](/api/core/function/File.md) * [**Files](/api/core/function/Files.md) * [**Framework](/api/core/function/Framework.md) * [**Get](/api/core/function/Get.md) * [**GrpcMethod](/api/core/function/GrpcMethod.md) * [**Guard](/api/core/function/Guard.md) * [**Head](/api/core/function/Head.md) * [**Headers](/api/core/function/Headers.md) * [**HttpCode](/api/core/function/HttpCode.md) * [**Init](/api/core/function/Init.md) * [**Inject](/api/core/function/Inject.md) * [**InjectClient](/api/core/function/InjectClient.md) * [**KafkaListener](/api/core/function/KafkaListener.md) * [**LazyInject](/api/core/function/LazyInject.md) * [**Logger](/api/core/function/Logger.md) * [**MainApp](/api/core/function/MainApp.md) * [**Match](/api/core/function/Match.md) * [**Middleware](/api/core/function/Middleware.md) * [**Mock](/api/core/function/Mock.md) * [**OnConnection](/api/core/function/OnConnection.md) * [**OnDisConnection](/api/core/function/OnDisConnection.md) * [**OnMessage](/api/core/function/OnMessage.md) * [**OnWSConnection](/api/core/function/OnWSConnection.md) * [**OnWSDisConnection](/api/core/function/OnWSDisConnection.md) * [**OnWSMessage](/api/core/function/OnWSMessage.md) * [**Options](/api/core/function/Options.md) * [**Param](/api/core/function/Param.md) * [**Patch](/api/core/function/Patch.md) * [**Pipe](/api/core/function/Pipe.md) * [**Plugin](/api/core/function/Plugin.md) * [**Post](/api/core/function/Post.md) * [**Provide](/api/core/function/Provide.md) * [**Provider](/api/core/function/Provider.md) * [**Put](/api/core/function/Put.md) * [**Queries](/api/core/function/Queries.md) * [**Query](/api/core/function/Query.md) * [**Queue](/api/core/function/Queue.md) * [**RabbitMQListener](/api/core/function/RabbitMQListener.md) * [**Redirect](/api/core/function/Redirect.md) * [**RequestIP](/api/core/function/RequestIP.md) * [**RequestMapping](/api/core/function/RequestMapping.md) * [**RequestPath](/api/core/function/RequestPath.md) * [**Schedule](/api/core/function/Schedule.md) * [**Scope](/api/core/function/Scope.md) * [**ServerlessFunction](/api/core/function/ServerlessFunction.md) * [**ServerlessTrigger](/api/core/function/ServerlessTrigger.md) * [**Session](/api/core/function/Session.md) * [**SetHeader](/api/core/function/SetHeader.md) * [**Singleton](/api/core/function/Singleton.md) * [**Task](/api/core/function/Task.md) * [**TaskLocal](/api/core/function/TaskLocal.md) * [**Trace](/api/core/function/Trace.md) * [**UseGuard](/api/core/function/UseGuard.md) * [**WSBroadCast](/api/core/function/WSBroadCast.md) * [**WSController](/api/core/function/WSController.md) * [**WSEmit](/api/core/function/WSEmit.md) * [**attachClassMetadata](/api/core/function/attachClassMetadata.md) * [**attachPropertyDataToClass](/api/core/function/attachPropertyDataToClass.md) * [**attachPropertyMetadata](/api/core/function/attachPropertyMetadata.md) * [**clearAllModule](/api/core/function/clearAllModule.md) * [**createCustomMethodDecorator](/api/core/function/createCustomMethodDecorator.md) * [**createCustomParamDecorator](/api/core/function/createCustomParamDecorator.md) * [**createCustomPropertyDecorator](/api/core/function/createCustomPropertyDecorator.md) * [**createMiddleware](/api/core/function/createMiddleware.md) * [**createRender](/api/core/function/createRender.md) * [**createRequestParamDecorator](/api/core/function/createRequestParamDecorator.md) * [**delegateTargetAllPrototypeMethod](/api/core/function/delegateTargetAllPrototypeMethod.md) * [**delegateTargetMethod](/api/core/function/delegateTargetMethod.md) * [**delegateTargetProperties](/api/core/function/delegateTargetProperties.md) * [**delegateTargetPrototypeMethod](/api/core/function/delegateTargetPrototypeMethod.md) * [**deprecatedOutput](/api/core/function/deprecatedOutput.md) * [**destroyGlobalApplicationContext](/api/core/function/destroyGlobalApplicationContext.md) * [**extend](/api/core/function/extend.md) * [**extractExpressLikeValue](/api/core/function/extractExpressLikeValue.md) * [**extractKoaLikeValue](/api/core/function/extractKoaLikeValue.md) * [**getClassExtendedMetadata](/api/core/function/getClassExtendedMetadata.md) * [**getClassMetadata](/api/core/function/getClassMetadata.md) * [**getCurrentApplicationContext](/api/core/function/getCurrentApplicationContext.md) * [**getCurrentAsyncContextManager](/api/core/function/getCurrentAsyncContextManager.md) * [**getCurrentMainApp](/api/core/function/getCurrentMainApp.md) * [**getCurrentMainFramework](/api/core/function/getCurrentMainFramework.md) * [**getMethodParamTypes](/api/core/function/getMethodParamTypes.md) * [**getObjectDefinition](/api/core/function/getObjectDefinition.md) * [**getPropertyDataFromClass](/api/core/function/getPropertyDataFromClass.md) * [**getPropertyInject](/api/core/function/getPropertyInject.md) * [**getPropertyMetadata](/api/core/function/getPropertyMetadata.md) * [**getPropertyType](/api/core/function/getPropertyType.md) * [**getProviderId](/api/core/function/getProviderId.md) * [**getProviderName](/api/core/function/getProviderName.md) * [**getProviderUUId](/api/core/function/getProviderUUId.md) * [**initializeGlobalApplicationContext](/api/core/function/initializeGlobalApplicationContext.md) * [**isProvide](/api/core/function/isProvide.md) * [**isTypeScriptEnvironment](/api/core/function/isTypeScriptEnvironment.md) * [**listModule](/api/core/function/listModule.md) * [**listPreloadModule](/api/core/function/listPreloadModule.md) * [**listPropertyDataFromClass](/api/core/function/listPropertyDataFromClass.md) * [**loadModule](/api/core/function/loadModule.md) * [**makeHttpRequest](/api/core/function/makeHttpRequest.md) * [**pathMatching](/api/core/function/pathMatching.md) * [**prepareGlobalApplicationContext](/api/core/function/prepareGlobalApplicationContext.md) * [**prepareGlobalApplicationContextAsync](/api/core/function/prepareGlobalApplicationContextAsync.md) * [**providerWrapper](/api/core/function/providerWrapper.md) * [**registerErrorCode](/api/core/function/registerErrorCode.md) * [**resetModule](/api/core/function/resetModule.md) * [**retryWith](/api/core/function/retryWith.md) * [**retryWithAsync](/api/core/function/retryWithAsync.md) * [**safeRequire](/api/core/function/safeRequire.md) * [**safelyGet](/api/core/function/safelyGet.md) * [**saveClassMetadata](/api/core/function/saveClassMetadata.md) * [**saveModule](/api/core/function/saveModule.md) * [**saveObjectDefinition](/api/core/function/saveObjectDefinition.md) * [**savePreloadModule](/api/core/function/savePreloadModule.md) * [**savePropertyDataToClass](/api/core/function/savePropertyDataToClass.md) * [**savePropertyInject](/api/core/function/savePropertyInject.md) * [**savePropertyMetadata](/api/core/function/savePropertyMetadata.md) * [**saveProviderId](/api/core/function/saveProviderId.md) * [**sleep](/api/core/function/sleep.md) * [**transformRequestObjectByType](/api/core/function/transformRequestObjectByType.md) * [**wrapAsync](/api/core/function/wrapAsync.md) * [**wrapMiddleware](/api/core/function/wrapMiddleware.md) ### Interfaces * [**AspectMetadata](/api/core/interface/AspectMetadata.md) * [**AsyncContext](/api/core/interface/AsyncContext.md) * [**AsyncContextManager](/api/core/interface/AsyncContextManager.md) * [**BaseServiceDiscoveryHealthCheckOptions](/api/core/interface/BaseServiceDiscoveryHealthCheckOptions.md) * [**CommonSchedule](/api/core/interface/CommonSchedule.md) * [**ConstructorInjectMetadata](/api/core/interface/ConstructorInjectMetadata.md) * [**Context](/api/core/interface/Context.md) * [**ControllerOption](/api/core/interface/ControllerOption.md) * [**DataSourceManagerConfigOption](/api/core/interface/DataSourceManagerConfigOption.md) * [**DefaultInstanceMetadata](/api/core/interface/DefaultInstanceMetadata.md) * [**DuplicateRouteErrorEntry](/api/core/interface/DuplicateRouteErrorEntry.md) * [**DuplicateRouteErrorPayload](/api/core/interface/DuplicateRouteErrorPayload.md) * [**HTTPServiceDiscoveryHealthCheckOptions](/api/core/interface/HTTPServiceDiscoveryHealthCheckOptions.md) * [**HealthResult](/api/core/interface/HealthResult.md) * [**HealthResults](/api/core/interface/HealthResults.md) * [**HttpClientOptions](/api/core/interface/HttpClientOptions.md) * [**HttpClientResponse](/api/core/interface/HttpClientResponse.md) * [**IComponentInfo](/api/core/interface/IComponentInfo.md) * [**IConfigService](/api/core/interface/IConfigService.md) * [**IConfigurationOptions](/api/core/interface/IConfigurationOptions.md) * [**IDataSourceManager](/api/core/interface/IDataSourceManager.md) * [**IEnvironmentService](/api/core/interface/IEnvironmentService.md) * [**IFileDetector](/api/core/interface/IFileDetector.md) * [**IFilter](/api/core/interface/IFilter.md) * [**IGuard](/api/core/interface/IGuard.md) * [**IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) * [**IInformationService](/api/core/interface/IInformationService.md) * [**ILifeCycle](/api/core/interface/ILifeCycle.md) * [**ILoadBalancer](/api/core/interface/ILoadBalancer.md) * [**ILogger](/api/core/interface/ILogger.md) * [**IMethodAspect](/api/core/interface/IMethodAspect.md) * [**IMiddleware](/api/core/interface/IMiddleware.md) * [**IMiddlewareManager](/api/core/interface/IMiddlewareManager.md) * [**IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md) * [**IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md) * [**IMidwayContainer](/api/core/interface/IMidwayContainer.md) * [**IMidwayFramework](/api/core/interface/IMidwayFramework.md) * [**IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) * [**IMidwayRequestContainer](/api/core/interface/IMidwayRequestContainer.md) * [**IObjectCreator](/api/core/interface/IObjectCreator.md) * [**IObjectDefinition](/api/core/interface/IObjectDefinition.md) * [**IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) * [**IObjectFactory](/api/core/interface/IObjectFactory.md) * [**IObjectLifeCycle](/api/core/interface/IObjectLifeCycle.md) * [**IServiceDiscoveryClient](/api/core/interface/IServiceDiscoveryClient.md) * [**IServiceDiscoveryHealthCheck](/api/core/interface/IServiceDiscoveryHealthCheck.md) * [**IServiceFactory](/api/core/interface/IServiceFactory.md) * [**ISimulation](/api/core/interface/ISimulation.md) * [**InjectionConfigurationOptions](/api/core/interface/InjectionConfigurationOptions.md) * [**JoinPoint](/api/core/interface/JoinPoint.md) * [**KafkaListenerOptions](/api/core/interface/KafkaListenerOptions.md) * [**LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md) * [**MethodDecoratorMetaData](/api/core/interface/MethodDecoratorMetaData.md) * [**MethodDecoratorOptions](/api/core/interface/MethodDecoratorOptions.md) * [**MidwayAppInfo](/api/core/interface/MidwayAppInfo.md) * [**MidwayConfig](/api/core/interface/MidwayConfig.md) * [**MidwayCoreDefaultConfig](/api/core/interface/MidwayCoreDefaultConfig.md) * [**MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md) * [**ObjectBeforeBindOptions](/api/core/interface/ObjectBeforeBindOptions.md) * [**ObjectBeforeCreatedOptions](/api/core/interface/ObjectBeforeCreatedOptions.md) * [**ObjectBeforeDestroyOptions](/api/core/interface/ObjectBeforeDestroyOptions.md) * [**ObjectCreatedOptions](/api/core/interface/ObjectCreatedOptions.md) * [**ObjectDefinitionOptions](/api/core/interface/ObjectDefinitionOptions.md) * [**ObjectInitOptions](/api/core/interface/ObjectInitOptions.md) * [**ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md) * [**ParameterDecoratorMetaData](/api/core/interface/ParameterDecoratorMetaData.md) * [**PipeTransform](/api/core/interface/PipeTransform.md) * [**PropertyDecoratorOptions](/api/core/interface/PropertyDecoratorOptions.md) * [**PropertyInjectMetadata](/api/core/interface/PropertyInjectMetadata.md) * [**RabbitMQListenerOptions](/api/core/interface/RabbitMQListenerOptions.md) * [**ReflectResult](/api/core/interface/ReflectResult.md) * [**RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md) * [**RouterInfo](/api/core/interface/RouterInfo.md) * [**RouterOption](/api/core/interface/RouterOption.md) * [**RouterParamValue](/api/core/interface/RouterParamValue.md) * [**RouterPriority](/api/core/interface/RouterPriority.md) * [**ScheduleOpts](/api/core/interface/ScheduleOpts.md) * [**ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md) * [**ServerSendEventStreamOptions](/api/core/interface/ServerSendEventStreamOptions.md) * [**ServerStreamOptions](/api/core/interface/ServerStreamOptions.md) * [**ServiceDiscoveryBaseInstance](/api/core/interface/ServiceDiscoveryBaseInstance.md) * [**ServiceDiscoveryHealthCheckResult](/api/core/interface/ServiceDiscoveryHealthCheckResult.md) * [**ServiceDiscoveryOptions](/api/core/interface/ServiceDiscoveryOptions.md) * [**TCPServiceDiscoveryHealthCheckOptions](/api/core/interface/TCPServiceDiscoveryHealthCheckOptions.md) * [**TSDesignType](/api/core/interface/TSDesignType.md) * [**TTLServiceDiscoveryHealthCheckOptions](/api/core/interface/TTLServiceDiscoveryHealthCheckOptions.md) * [**TagClsMetadata](/api/core/interface/TagClsMetadata.md) * [**TagPropsMetadata](/api/core/interface/TagPropsMetadata.md) * [**TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md) * [**TransformOptions](/api/core/interface/TransformOptions.md) * [**WSControllerOption](/api/core/interface/WSControllerOption.md) * [**WSEventInfo](/api/core/interface/WSEventInfo.md) ### Namespaces * [**ConsumerMetadata](/api/core/namespace/ConsumerMetadata.md) * [**FaaSMetadata](/api/core/namespace/FaaSMetadata.md) * [**GRPCMetadata](/api/core/namespace/GRPCMetadata.md) ### Type Aliases * [**BaseDataSourceManagerConfigOption](/api/core.md#BaseDataSourceManagerConfigOption) * [**ClassMiddleware](/api/core.md#ClassMiddleware) * [**ClassType](/api/core.md#ClassType) * [**CommonFilterUnion](/api/core.md#CommonFilterUnion) * [**CommonGuardUnion](/api/core.md#CommonGuardUnion) * [**CommonMiddleware](/api/core.md#CommonMiddleware) * [**CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion) * [**CompositionMiddleware](/api/core.md#CompositionMiddleware) * [**ConsumerRunConfig](/api/core.md#ConsumerRunConfig) * [**ConsumerSubscribeTopic](/api/core.md#ConsumerSubscribeTopic) * [**ConsumerSubscribeTopics](/api/core.md#ConsumerSubscribeTopics) * [**CreateDataSourceInstanceOptions](/api/core.md#CreateDataSourceInstanceOptions) * [**CustomParamDecorator](/api/core.md#CustomParamDecorator) * [**DynamicRouterInfo](/api/core.md#DynamicRouterInfo) * [**ExpressLikeCustomParamDecorator](/api/core.md#ExpressLikeCustomParamDecorator) * [**FileConfigOption](/api/core.md#FileConfigOption) * [**FunctionMiddleware](/api/core.md#FunctionMiddleware) * [**FunctionalConfigurationOptions](/api/core.md#FunctionalConfigurationOptions) * [**HandlerFunction](/api/core.md#HandlerFunction) * [**HttpClientMimeType](/api/core.md#HttpClientMimeType) * [**IMidwayApplication](/api/core.md#IMidwayApplication) * [**IMidwayContext](/api/core.md#IMidwayContext) * [**IgnoreMatcher](/api/core.md#IgnoreMatcher) * [**KoaLikeCustomParamDecorator](/api/core.md#KoaLikeCustomParamDecorator) * [**LoadBalancerType](/api/core.md#LoadBalancerType) * [**MatchPattern](/api/core.md#MatchPattern) * [**MethodHandlerFunction](/api/core.md#MethodHandlerFunction) * [**MiddlewareParamArray](/api/core.md#MiddlewareParamArray) * [**MiddlewareRespond](/api/core.md#MiddlewareRespond) * [**ModuleLoadType](/api/core.md#ModuleLoadType) * [**NextFunction](/api/core.md#NextFunction) * [**ObjectIdentifier](/api/core.md#ObjectIdentifier) * [**ParameterHandlerFunction](/api/core.md#ParameterHandlerFunction) * [**PipeTransformFunction](/api/core.md#PipeTransformFunction) * [**PipeUnionTransform](/api/core.md#PipeUnionTransform) * [**PowerPartial](/api/core.md#PowerPartial) * [**ResOrMessage](/api/core.md#ResOrMessage) * [**ServiceDiscoveryHealthCheckOptions](/api/core.md#ServiceDiscoveryHealthCheckOptions) * [**ServiceDiscoveryHealthCheckType](/api/core.md#ServiceDiscoveryHealthCheckType) * [**ServiceFactoryConfigOption](/api/core.md#ServiceFactoryConfigOption) * [**TraceMetaDirection](/api/core.md#TraceMetaDirection) * [**TraceMetaRecord](/api/core.md#TraceMetaRecord) * [**TraceMetaResolver](/api/core.md#TraceMetaResolver) * [**TraceMetaValue](/api/core.md#TraceMetaValue) * [**WithFn](/api/core.md#WithFn) * [**WithoutFn](/api/core.md#WithoutFn) * [**Writable](/api/core.md#Writable) ### Variables * [**ALL](/api/core.md#ALL) * [**ALL\_VALUE\_KEY](/api/core.md#ALL_VALUE_KEY) * [**APPLICATION\_CONTEXT\_KEY](/api/core.md#APPLICATION_CONTEXT_KEY) * [**APPLICATION\_KEY](/api/core.md#APPLICATION_KEY) * [**ASPECT\_KEY](/api/core.md#ASPECT_KEY) * [**ASYNC\_CONTEXT\_KEY](/api/core.md#ASYNC_CONTEXT_KEY) * [**ASYNC\_CONTEXT\_MANAGER\_KEY](/api/core.md#ASYNC_CONTEXT_MANAGER_KEY) * [**ASYNC\_ROOT\_CONTEXT](/api/core.md#ASYNC_ROOT_CONTEXT) * [**CATCH\_KEY](/api/core.md#CATCH_KEY) * [**CLASS\_KEY\_CONSTRUCTOR](/api/core.md#CLASS_KEY_CONSTRUCTOR) * [**CONFIGURATION\_KEY](/api/core.md#CONFIGURATION_KEY) * [**CONFIGURATION\_OBJECT\_KEY](/api/core.md#CONFIGURATION_OBJECT_KEY) * [**CONFIG\_KEY](/api/core.md#CONFIG_KEY) * [**CONSTRUCTOR\_INJECT\_KEY](/api/core.md#CONSTRUCTOR_INJECT_KEY) * [**CONTAINER\_OBJ\_SCOPE](/api/core.md#CONTAINER_OBJ_SCOPE) * [**CONTROLLER\_KEY](/api/core.md#CONTROLLER_KEY) * [**CUSTOM\_METHOD\_INJECT\_KEY](/api/core.md#CUSTOM_METHOD_INJECT_KEY) * [**CUSTOM\_PARAM\_INJECT\_KEY](/api/core.md#CUSTOM_PARAM_INJECT_KEY) * [**CUSTOM\_PROPERTY\_INJECT\_KEY](/api/core.md#CUSTOM_PROPERTY_INJECT_KEY) * [**DEFAULT\_PATTERN](/api/core.md#DEFAULT_PATTERN) * [**DEFAULT\_PRIORITY](/api/core.md#DEFAULT_PRIORITY) * [**FACTORY\_SERVICE\_CLIENT\_KEY](/api/core.md#FACTORY_SERVICE_CLIENT_KEY) * [**FORMAT](/api/core.md#FORMAT) * [**FRAMEWORK\_KEY](/api/core.md#FRAMEWORK_KEY) * [**FUNCTIONAL\_API\_CONTROLLER\_KEY](/api/core.md#FUNCTIONAL_API_CONTROLLER_KEY) * [**FUNCTION\_INJECT\_KEY](/api/core.md#FUNCTION_INJECT_KEY) * [**FUNC\_KEY](/api/core.md#FUNC_KEY) * [**FileUtils](/api/core.md#FileUtils) * [**FrameworkErrorEnum](/api/core.md#FrameworkErrorEnum) * [**GUARD\_KEY](/api/core.md#GUARD_KEY) * [**HTTP\_SERVER\_KEY](/api/core.md#HTTP_SERVER_KEY) * [**IGNORE\_PATTERN](/api/core.md#IGNORE_PATTERN) * [**INJECT\_CUSTOM\_METHOD](/api/core.md#INJECT_CUSTOM_METHOD) * [**INJECT\_CUSTOM\_PARAM](/api/core.md#INJECT_CUSTOM_PARAM) * [**INJECT\_CUSTOM\_PROPERTY](/api/core.md#INJECT_CUSTOM_PROPERTY) * [**INJECT\_TAG](/api/core.md#INJECT_TAG) * [**KEYS](/api/core.md#KEYS) * [**LOGGER\_KEY](/api/core.md#LOGGER_KEY) * [**LoadBalancerType](/api/core.md#LoadBalancerType) * [**MAIN\_APPLICATION\_KEY](/api/core.md#MAIN_APPLICATION_KEY) * [**MAIN\_MODULE\_KEY](/api/core.md#MAIN_MODULE_KEY) * [**MATCH\_KEY](/api/core.md#MATCH_KEY) * [**MIDWAY\_LOGGER\_WRITEABLE\_DIR](/api/core.md#MIDWAY_LOGGER_WRITEABLE_DIR) * [**MOCK\_KEY](/api/core.md#MOCK_KEY) * [**MODULE\_TASK\_KEY](/api/core.md#MODULE_TASK_KEY) * [**MODULE\_TASK\_METADATA](/api/core.md#MODULE_TASK_METADATA) * [**MODULE\_TASK\_QUEUE\_KEY](/api/core.md#MODULE_TASK_QUEUE_KEY) * [**MODULE\_TASK\_QUEUE\_OPTIONS](/api/core.md#MODULE_TASK_QUEUE_OPTIONS) * [**MODULE\_TASK\_TASK\_LOCAL\_KEY](/api/core.md#MODULE_TASK_TASK_LOCAL_KEY) * [**MODULE\_TASK\_TASK\_LOCAL\_OPTIONS](/api/core.md#MODULE_TASK_TASK_LOCAL_OPTIONS) * [**MS\_CONSUMER\_KEY](/api/core.md#MS_CONSUMER_KEY) * [**MS\_DUBBO\_METHOD\_KEY](/api/core.md#MS_DUBBO_METHOD_KEY) * [**MS\_GRPC\_METHOD\_KEY](/api/core.md#MS_GRPC_METHOD_KEY) * [**MS\_HSF\_METHOD\_KEY](/api/core.md#MS_HSF_METHOD_KEY) * [**MS\_PRODUCER\_KEY](/api/core.md#MS_PRODUCER_KEY) * [**MS\_PROVIDER\_KEY](/api/core.md#MS_PROVIDER_KEY) * [**NetworkUtils](/api/core.md#NetworkUtils) * [**OBJECT\_DEFINITION\_KEY](/api/core.md#OBJECT_DEFINITION_KEY) * [**OBJ\_DEF\_CLS](/api/core.md#OBJ_DEF_CLS) * [**PLUGIN\_KEY](/api/core.md#PLUGIN_KEY) * [**PRE\_START\_MODULE\_KEY](/api/core.md#PRE_START_MODULE_KEY) * [**PROPERTY\_INJECT\_KEY](/api/core.md#PROPERTY_INJECT_KEY) * [**PROVIDE\_KEY](/api/core.md#PROVIDE_KEY) * [**PathFileUtils](/api/core.md#PathFileUtils) * [**PathToRegexpUtil](/api/core.md#PathToRegexpUtil) * [**REQUEST\_CTX\_KEY](/api/core.md#REQUEST_CTX_KEY) * [**REQUEST\_CTX\_LOGGER\_CACHE\_KEY](/api/core.md#REQUEST_CTX_LOGGER_CACHE_KEY) * [**REQUEST\_CTX\_UNIQUE\_KEY](/api/core.md#REQUEST_CTX_UNIQUE_KEY) * [**REQUEST\_OBJ\_CTX\_KEY](/api/core.md#REQUEST_OBJ_CTX_KEY) * [**RequestMethod](/api/core.md#RequestMethod) * [**SCHEDULE\_KEY](/api/core.md#SCHEDULE_KEY) * [**SCOPE\_KEY](/api/core.md#SCOPE_KEY) * [**SERVERLESS\_FUNC\_KEY](/api/core.md#SERVERLESS_FUNC_KEY) * [**SINGLETON\_CONTAINER\_CTX](/api/core.md#SINGLETON_CONTAINER_CTX) * [**ServiceDiscoveryHealthCheckType](/api/core.md#ServiceDiscoveryHealthCheckType) * [**TAGGED\_CLS](/api/core.md#TAGGED_CLS) * [**TRACE\_KEY](/api/core.md#TRACE_KEY) * [**Types](/api/core.md#Types) * [**Utils](/api/core.md#Utils) * [**WEB\_RESPONSE\_CONTENT\_TYPE](/api/core.md#WEB_RESPONSE_CONTENT_TYPE) * [**WEB\_RESPONSE\_HEADER](/api/core.md#WEB_RESPONSE_HEADER) * [**WEB\_RESPONSE\_HTTP\_CODE](/api/core.md#WEB_RESPONSE_HTTP_CODE) * [**WEB\_RESPONSE\_KEY](/api/core.md#WEB_RESPONSE_KEY) * [**WEB\_RESPONSE\_REDIRECT](/api/core.md#WEB_RESPONSE_REDIRECT) * [**WEB\_RESPONSE\_RENDER](/api/core.md#WEB_RESPONSE_RENDER) * [**WEB\_ROUTER\_KEY](/api/core.md#WEB_ROUTER_KEY) * [**WEB\_ROUTER\_PARAM\_KEY](/api/core.md#WEB_ROUTER_PARAM_KEY) * [**WS\_CONTROLLER\_KEY](/api/core.md#WS_CONTROLLER_KEY) * [**WS\_EVENT\_KEY](/api/core.md#WS_EVENT_KEY) * [**httpError](/api/core.md#httpError) ## Type Aliases[**](<#Type Aliases>) ### [**](#BaseDataSourceManagerConfigOption)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L515)BaseDataSourceManagerConfigOption **BaseDataSourceManagerConfigOption\: OPTIONS & { customDataSourceClass? : any; validateConnection? : boolean } & { \[ key in ENTITY\_CONFIG\_KEY ]?: any\[] } #### Type parameters * **OPTIONS**: Record\ * **ENTITY\_CONFIG\_KEY**: string = entities ### [**](#ClassMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L888)ClassMiddleware **ClassMiddleware\: new (...args: any) => [IMiddleware](/api/core/interface/IMiddleware.md)\ #### Type parameters * **CTX** * **R** * **N** ### [**](#ClassType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L7)ClassType **ClassType\: new (...args: any\[]) => T #### Type parameters * **T** = any ### [**](#CommonFilterUnion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L917)CommonFilterUnion **CommonFilterUnion\: new (...args: any) => [IFilter](/api/core/interface/IFilter.md)\ | new (...args: any) => [IFilter](/api/core/interface/IFilter.md)\\[] #### Type parameters * **CTX** * **R** * **N** ### [**](#CommonGuardUnion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L932)CommonGuardUnion **CommonGuardUnion\: new (...args: any) => [IGuard](/api/core/interface/IGuard.md)\ | new (...args: any) => [IGuard](/api/core/interface/IGuard.md)\\[] #### Type parameters * **CTX** = unknown ### [**](#CommonMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L897)CommonMiddleware **CommonMiddleware\: [ClassMiddleware](/api/core.md#ClassMiddleware)\ | [FunctionMiddleware](/api/core.md#FunctionMiddleware)\ | [CompositionMiddleware](/api/core.md#CompositionMiddleware)\ #### Type parameters * **CTX** * **R** * **N** ### [**](#CommonMiddlewareUnion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L901)CommonMiddlewareUnion **CommonMiddlewareUnion\: [CommonMiddleware](/api/core.md#CommonMiddleware)\ | [CommonMiddleware](/api/core.md#CommonMiddleware)\\[] #### Type parameters * **CTX** * **R** * **N** ### [**](#CompositionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L892)CompositionMiddleware **CompositionMiddleware\: { middleware: [ClassMiddleware](/api/core.md#ClassMiddleware)\; name? : string; options: any } #### Type parameters * **CTX** * **R** * **N** ### [**](#ConsumerRunConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L14)ConsumerRunConfig **ConsumerRunConfig: { autoCommit? : boolean; autoCommitInterval? : number | null; autoCommitThreshold? : number | null; eachBatchAutoResolve? : boolean; partitionsConsumedConcurrently? : number } ### [**](#ConsumerSubscribeTopic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L7)ConsumerSubscribeTopic **ConsumerSubscribeTopic: { fromBeginning? : boolean } * **@deprecated** Replaced by ConsumerSubscribeTopics ### [**](#ConsumerSubscribeTopics)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L10)ConsumerSubscribeTopics **ConsumerSubscribeTopics: { fromBeginning? : boolean } ### [**](#CreateDataSourceInstanceOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L504)CreateDataSourceInstanceOptions **CreateDataSourceInstanceOptions: { cacheInstance? : boolean; validateConnection? : boolean } ### [**](#CustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L57)CustomParamDecorator **CustomParamDecorator\: [KoaLikeCustomParamDecorator](/api/core.md#KoaLikeCustomParamDecorator)\ | [ExpressLikeCustomParamDecorator](/api/core.md#ExpressLikeCustomParamDecorator)\ #### Type parameters * **T** = unknown ### [**](#DynamicRouterInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L171)DynamicRouterInfo **DynamicRouterInfo: Omit<[RouterInfo](/api/core/interface/RouterInfo.md), id | method | controllerId | controllerMiddleware | responseMetadata> ### [**](#ExpressLikeCustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L52)ExpressLikeCustomParamDecorator **ExpressLikeCustomParamDecorator\: (req: any, res: any) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#FileConfigOption)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L541)FileConfigOption **FileConfigOption\: K extends keyof ConfigType\ ? Pick\, K> : ConfigType\ Get definition from config *** #### Type parameters * **T** * **K** = unknown ### [**](#FunctionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L885)FunctionMiddleware **FunctionMiddleware\: N extends true ? (req: CTX, res: R, next: N) => any : (context: CTX, next: R, options? : any) => any #### Type parameters * **CTX** * **R** * **N** = unknown ### [**](#FunctionalConfigurationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1290)FunctionalConfigurationOptions **FunctionalConfigurationOptions: [InjectionConfigurationOptions](/api/core/interface/InjectionConfigurationOptions.md) & [ILifeCycle](/api/core/interface/ILifeCycle.md) ### [**](#HandlerFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L714)HandlerFunction **HandlerFunction: (key: string, meta: any, instance: any) => any ### [**](#HttpClientMimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L10)HttpClientMimeType **HttpClientMimeType: text | json | undefined ### [**](#IMidwayApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1096)IMidwayApplication **IMidwayApplication\: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)\ & FrameworkApplication #### Type parameters * **T**: [IMidwayContext](/api/core.md#IMidwayContext) = [IMidwayContext](/api/core.md#IMidwayContext) * **FrameworkApplication** = unknown ### [**](#IMidwayContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L862)IMidwayContext **IMidwayContext\: [Context](/api/core/interface/Context.md) & FrameworkContext #### Type parameters * **FrameworkContext** = unknown ### [**](#IgnoreMatcher)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L866)IgnoreMatcher **IgnoreMatcher\: string | RegExp | (ctx: CTX) => boolean #### Type parameters * **CTX** ### [**](#KoaLikeCustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L48)KoaLikeCustomParamDecorator **KoaLikeCustomParamDecorator\: (ctx: [IMidwayContext](/api/core.md#IMidwayContext)) => T | Promise\ #### Type parameters * **T** = unknown ### [**](#LoadBalancerType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1296)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1301)LoadBalancerType **LoadBalancerType: typeof [LoadBalancerType](/api/core.md#LoadBalancerType)\[keyof typeof [LoadBalancerType](/api/core.md#LoadBalancerType)] ### [**](#MatchPattern)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/filter.ts#L29)MatchPattern **MatchPattern\: (ctxOrReq: CtxOrReq, res: Res) => boolean | string | string\[] | boolean #### Type parameters * **CtxOrReq** = any * **Res** = any ### [**](#MethodHandlerFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L726)MethodHandlerFunction **MethodHandlerFunction: (options: { metadata: any; propertyName: string; target: new (...args: any) => any }) => [IMethodAspect](/api/core/interface/IMethodAspect.md) ### [**](#MiddlewareParamArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L54)MiddlewareParamArray **MiddlewareParamArray: (string | any)\[] ### [**](#MiddlewareRespond)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L904)MiddlewareRespond **MiddlewareRespond\: (context: CTX, nextOrRes? : N extends true ? R : [NextFunction](/api/core.md#NextFunction), next? : N) => Promise\ #### Type parameters * **CTX** * **R** * **N** ### [**](#ModuleLoadType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1101)ModuleLoadType **ModuleLoadType: commonjs | esm ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L864)NextFunction **NextFunction: () => Promise\ ### [**](#ObjectIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L55)ObjectIdentifier **ObjectIdentifier: string | Symbol ### [**](#ParameterHandlerFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L732)ParameterHandlerFunction **ParameterHandlerFunction: (options: { metadata: any; originArgs: any\[]; originParamType: any; parameterIndex: number; propertyName: string; target: new (...args: any) => any }) => any ### [**](#PipeTransformFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L355)PipeTransformFunction **PipeTransformFunction\: (value: T) => R #### Type parameters * **T** = any * **R** = any ### [**](#PipeUnionTransform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L357)PipeUnionTransform **PipeUnionTransform\: [PipeTransform](/api/core/interface/PipeTransform.md)\ | new (...args: any) => [PipeTransform](/api/core/interface/PipeTransform.md)\ | [PipeTransformFunction](/api/core.md#PipeTransformFunction)\ #### Type parameters * **T** = any * **R** = any ### [**](#PowerPartial)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L9)PowerPartial **PowerPartial\: { \[ U in keyof T ]?: T\[U] extends {} ? [PowerPartial](/api/core.md#PowerPartial)\ : T\[U] } #### Type parameters * **T** ### [**](#ResOrMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L67)ResOrMessage **ResOrMessage: string | { message: string } | undefined ### [**](#ServiceDiscoveryHealthCheckOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1386)ServiceDiscoveryHealthCheckOptions **ServiceDiscoveryHealthCheckOptions: [TTLServiceDiscoveryHealthCheckOptions](/api/core/interface/TTLServiceDiscoveryHealthCheckOptions.md) | [HTTPServiceDiscoveryHealthCheckOptions](/api/core/interface/HTTPServiceDiscoveryHealthCheckOptions.md) | [TCPServiceDiscoveryHealthCheckOptions](/api/core/interface/TCPServiceDiscoveryHealthCheckOptions.md) 健康检查配置联合类型 ### [**](#ServiceDiscoveryHealthCheckType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1304)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1312)ServiceDiscoveryHealthCheckType **ServiceDiscoveryHealthCheckType: typeof [ServiceDiscoveryHealthCheckType](/api/core.md#ServiceDiscoveryHealthCheckType)\[keyof typeof [ServiceDiscoveryHealthCheckType](/api/core.md#ServiceDiscoveryHealthCheckType)] ### [**](#ServiceFactoryConfigOption)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L492)ServiceFactoryConfigOption **ServiceFactoryConfigOption\: { client? : [PowerPartial](/api/core.md#PowerPartial)\; clientPriority? : {}; clients? : {}; default? : [PowerPartial](/api/core.md#PowerPartial)\; defaultClientName? : string } #### Type parameters * **OPTIONS** ### [**](#TraceMetaDirection)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L458)TraceMetaDirection **TraceMetaDirection: entry | exit ### [**](#TraceMetaRecord)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L462)TraceMetaRecord **TraceMetaRecord: Record\ ### [**](#TraceMetaResolver)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L477)TraceMetaResolver **TraceMetaResolver: [TraceMetaRecord](/api/core.md#TraceMetaRecord) | (args: [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md)) => [TraceMetaRecord](/api/core.md#TraceMetaRecord) | { common? : [TraceMetaRecord](/api/core.md#TraceMetaRecord) | (args: [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md)) => [TraceMetaRecord](/api/core.md#TraceMetaRecord); entry? : [TraceMetaRecord](/api/core.md#TraceMetaRecord) | (args: [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md)) => [TraceMetaRecord](/api/core.md#TraceMetaRecord); exit? : [TraceMetaRecord](/api/core.md#TraceMetaRecord) | (args: [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md)) => [TraceMetaRecord](/api/core.md#TraceMetaRecord) } ### [**](#TraceMetaValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L460)TraceMetaValue **TraceMetaValue: string | number | boolean | undefined | null ### [**](#WithFn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L37)WithFn **WithFn\: { \[ K in keyof T ]: T\[K] extends (...args: infer P) => infer R ? (fn: (...args: P) => R) => void : T\[K] } Utility type that adds a `fn` parameter to each method in the input type `T`, transforming the original method's parameter types and return type into a function type. * **@example** ``` // Input: interface MyInterface { method1(a: string, b: number): boolean; method2(x: Foo, y: Bar): void; } // Output: interface MyInterfaceWithFn { method1(fn: (a: string, b: number) => boolean): void; method2(fn: (x: Foo, y: Bar) => void): void; } ``` *** #### Type parameters * **T** ### [**](#WithoutFn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L48)WithoutFn **WithoutFn\: { \[ K in keyof T ]: T\[K] extends (arg: any, ...args: any\[]) => any ? (...args: Parameters\) => ReturnType\ : T\[K] } Transform an object type `T` with methods that have function-type parameters to a new object type with the same methods, but with the parameters extracted as separate properties. *** #### Type parameters * **T** ### [**](#Writable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L16)Writable **Writable\: { -readonly \[ P in keyof T ]: T\[P] } Make object property writeable *** #### Type parameters * **T** ## Variables[**](#Variables) ### [**](#ALL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L22)constALL **ALL: common:all\_value\_key = ALL\_VALUE\_KEY * **@deprecated** Use ALL\_VALUE\_KEY instead ### [**](#ALL_VALUE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L2)constALL\_VALUE\_KEY **ALL\_VALUE\_KEY: common:all\_value\_key = 'common:all\_value\_key' ### [**](#APPLICATION_CONTEXT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L74)constAPPLICATION\_CONTEXT\_KEY **APPLICATION\_CONTEXT\_KEY: common:application\_context = 'common:application\_context' ### [**](#APPLICATION_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L72)constAPPLICATION\_KEY **APPLICATION\_KEY: common:application = 'common:application' ### [**](#ASPECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L8)constASPECT\_KEY **ASPECT\_KEY: common:aspect = 'common:aspect' ### [**](#ASYNC_CONTEXT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L19)constASYNC\_CONTEXT\_KEY **ASYNC\_CONTEXT\_KEY: typeof [ASYNC\_CONTEXT\_KEY](/api/core.md#ASYNC_CONTEXT_KEY) = ... ### [**](#ASYNC_CONTEXT_MANAGER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L20)constASYNC\_CONTEXT\_MANAGER\_KEY **ASYNC\_CONTEXT\_MANAGER\_KEY: MIDWAY\_ASYNC\_CONTEXT\_MANAGER\_KEY = 'MIDWAY\_ASYNC\_CONTEXT\_MANAGER\_KEY' ### [**](#ASYNC_ROOT_CONTEXT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L138)constASYNC\_ROOT\_CONTEXT **ASYNC\_ROOT\_CONTEXT: [AsyncContext](/api/core/interface/AsyncContext.md) = ... The root context is used as the default parent context when there is no active context ### [**](#CATCH_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L9)constCATCH\_KEY **CATCH\_KEY: common:catch = 'common:catch' ### [**](#CLASS_KEY_CONSTRUCTOR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L79)constCLASS\_KEY\_CONSTRUCTOR **CLASS\_KEY\_CONSTRUCTOR: midway:class\_key\_constructor = 'midway:class\_key\_constructor' ### [**](#CONFIGURATION_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L5)constCONFIGURATION\_KEY **CONFIGURATION\_KEY: common:configuration = 'common:configuration' ### [**](#CONFIGURATION_OBJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L6)constCONFIGURATION\_OBJECT\_KEY **CONFIGURATION\_OBJECT\_KEY: common:configuration\_object = 'common:configuration\_object' ### [**](#CONFIG_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L69)constCONFIG\_KEY **CONFIG\_KEY: config = 'config' ### [**](#CONSTRUCTOR_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L23)constCONSTRUCTOR\_INJECT\_KEY **CONSTRUCTOR\_INJECT\_KEY: common:constructor\_inject = 'common:constructor\_inject' ### [**](#CONTAINER_OBJ_SCOPE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L14)constCONTAINER\_OBJ\_SCOPE **CONTAINER\_OBJ\_SCOPE: \_obj\_scope = '\_obj\_scope' ### [**](#CONTROLLER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L36)constCONTROLLER\_KEY **CONTROLLER\_KEY: web:controller = 'web:controller' ### [**](#CUSTOM_METHOD_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L27)constCUSTOM\_METHOD\_INJECT\_KEY **CUSTOM\_METHOD\_INJECT\_KEY: common:custom\_method\_inject = 'common:custom\_method\_inject' ### [**](#CUSTOM_PARAM_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L29)constCUSTOM\_PARAM\_INJECT\_KEY **CUSTOM\_PARAM\_INJECT\_KEY: common:custom\_param\_inject = 'common:custom\_param\_inject' ### [**](#CUSTOM_PROPERTY_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L25)constCUSTOM\_PROPERTY\_INJECT\_KEY **CUSTOM\_PROPERTY\_INJECT\_KEY: common:custom\_property\_inject = 'common:custom\_property\_inject' ### [**](#DEFAULT_PATTERN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L22)constDEFAULT\_PATTERN **DEFAULT\_PATTERN: string\[] = ... ### [**](#DEFAULT_PRIORITY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L4)constDEFAULT\_PRIORITY **DEFAULT\_PRIORITY: { L1: string; L2: string; L3: string } = ... ### [**](#FACTORY_SERVICE_CLIENT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L13)constFACTORY\_SERVICE\_CLIENT\_KEY **FACTORY\_SERVICE\_CLIENT\_KEY: common:service\_factory:client = 'common:service\_factory:client' ### [**](#FORMAT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/format.ts#L34)constFORMAT **FORMAT: { CRONTAB: { EVERY\_DAY: string; EVERY\_DAY\_ONE\_FIFTEEN: string; EVERY\_DAY\_ZERO\_FIFTEEN: string; EVERY\_HOUR: string; EVERY\_MINUTE: string; EVERY\_PER\_10\_MINUTE: string; EVERY\_PER\_10\_SECOND: string; EVERY\_PER\_30\_MINUTE: string; EVERY\_PER\_30\_SECOND: string; EVERY\_PER\_5\_MINUTE: string; EVERY\_PER\_5\_SECOND: string; EVERY\_SECOND: string }; MS: { ONE\_DAY: number; ONE\_HOUR: number; ONE\_MINUTE: number; ONE\_SECOND: number; ONE\_WEEK: number; ONE\_YEAR: number } } = ... ### [**](#FRAMEWORK_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L7)constFRAMEWORK\_KEY **FRAMEWORK\_KEY: common:framework = 'common:framework' ### [**](#FUNCTIONAL_API_CONTROLLER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L75)constFUNCTIONAL\_API\_CONTROLLER\_KEY **FUNCTIONAL\_API\_CONTROLLER\_KEY: functional:api\_controller = 'functional:api\_controller' ### [**](#FUNCTION_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L10)constFUNCTION\_INJECT\_KEY **FUNCTION\_INJECT\_KEY: midway:function\_inject\_key = 'midway:function\_inject\_key' ### [**](#FUNC_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L32)constFUNC\_KEY **FUNC\_KEY: faas:func = 'faas:func' ### [**](#FileUtils)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/fs.ts#L10)constFileUtils **FileUtils: { exists: (p: any) => Promise\ } = ... ### [**](#FrameworkErrorEnum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L3)constFrameworkErrorEnum **FrameworkErrorEnum: ConvertString<{ CODE\_INVOKE\_TIMEOUT: 10019; COMMON: 10001; DEFINITION\_NOT\_FOUND: 10003; DUPLICATE\_CLASS\_NAME: 10015; DUPLICATE\_CONTROLLER\_PREFIX\_OPTIONS: 10016; DUPLICATE\_ROUTER: 10008; EMPTY\_VALUE: 10022; FEATURE\_NOT\_IMPLEMENTED: 10004; FEATURE\_NO\_LONGER\_SUPPORTED: 10004; INCONSISTENT\_VERSION: 10013; INVALID\_CONFIG: 10014; INVALID\_CONFIG\_PROPERTY: 10021; INVOKE\_METHOD\_FORBIDDEN: 10018; MAIN\_FRAMEWORK\_MISSING: 10020; MISSING\_CONFIG: 10006; MISSING\_IMPORTS: 10011; MISSING\_RESOLVER: 10007; PARAM\_TYPE: 10002; RETRY\_OVER\_MAX\_TIME: 10017; SINGLETON\_INJECT\_REQUEST: 10010; UNKNOWN: 10000; USE\_WRONG\_METHOD: 10009; UTIL\_HTTP\_TIMEOUT: 10012 }, midway> = ... ### [**](#GUARD_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L11)constGUARD\_KEY **GUARD\_KEY: common:guard = 'common:guard' ### [**](#HTTP_SERVER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L15)constHTTP\_SERVER\_KEY **HTTP\_SERVER\_KEY: \_midway\_http\_server = '\_midway\_http\_server' ### [**](#IGNORE_PATTERN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L31)constIGNORE\_PATTERN **IGNORE\_PATTERN: string\[] = ... ### [**](#INJECT_CUSTOM_METHOD)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L30)constINJECT\_CUSTOM\_METHOD **INJECT\_CUSTOM\_METHOD: common:custom\_method\_inject = CUSTOM\_METHOD\_INJECT\_KEY * **@deprecated** Use CUSTOM\_METHOD\_INJECT\_KEY instead ### [**](#INJECT_CUSTOM_PARAM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L34)constINJECT\_CUSTOM\_PARAM **INJECT\_CUSTOM\_PARAM: common:custom\_param\_inject = CUSTOM\_PARAM\_INJECT\_KEY * **@deprecated** Use CUSTOM\_PARAM\_INJECT\_KEY instead ### [**](#INJECT_CUSTOM_PROPERTY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L26)constINJECT\_CUSTOM\_PROPERTY **INJECT\_CUSTOM\_PROPERTY: common:custom\_property\_inject = CUSTOM\_PROPERTY\_INJECT\_KEY * **@deprecated** Use CUSTOM\_PROPERTY\_INJECT\_KEY instead ### [**](#INJECT_TAG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L18)constINJECT\_TAG **INJECT\_TAG: common:property\_inject = PROPERTY\_INJECT\_KEY * **@deprecated** Use PROPERTY\_INJECT\_KEY instead ### [**](#KEYS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L5)constKEYS **KEYS: { REF\_CUSTOM: string; REF\_ELEMENT: string } = ... 静态参数 ### [**](#LOGGER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L71)constLOGGER\_KEY **LOGGER\_KEY: logger = 'logger' ### [**](#LoadBalancerType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1296)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1301)constLoadBalancerType **LoadBalancerType: { RANDOM: random; ROUND\_ROBIN: roundRobin } = ... 负载均衡策略类型 ### [**](#MAIN_APPLICATION_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L73)constMAIN\_APPLICATION\_KEY **MAIN\_APPLICATION\_KEY: common:main\_application = 'common:main\_application' ### [**](#MAIN_MODULE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L81)constMAIN\_MODULE\_KEY **MAIN\_MODULE\_KEY: \_\_main\_\_ = '\_\_main\_\_' ### [**](#MATCH_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L10)constMATCH\_KEY **MATCH\_KEY: common:match = 'common:match' ### [**](#MIDWAY_LOGGER_WRITEABLE_DIR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L11)constMIDWAY\_LOGGER\_WRITEABLE\_DIR **MIDWAY\_LOGGER\_WRITEABLE\_DIR: MIDWAY\_LOGGER\_WRITEABLE\_DIR = 'MIDWAY\_LOGGER\_WRITEABLE\_DIR' ### [**](#MOCK_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L12)constMOCK\_KEY **MOCK\_KEY: common:mock = 'common:mock' ### [**](#MODULE_TASK_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L47)constMODULE\_TASK\_KEY **MODULE\_TASK\_KEY: task:task = 'task:task' ### [**](#MODULE_TASK_METADATA)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L48)constMODULE\_TASK\_METADATA **MODULE\_TASK\_METADATA: task:task:options = 'task:task:options' ### [**](#MODULE_TASK_QUEUE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L51)constMODULE\_TASK\_QUEUE\_KEY **MODULE\_TASK\_QUEUE\_KEY: task:task:queue = 'task:task:queue' ### [**](#MODULE_TASK_QUEUE_OPTIONS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L52)constMODULE\_TASK\_QUEUE\_OPTIONS **MODULE\_TASK\_QUEUE\_OPTIONS: task:task:queue:options = 'task:task:queue:options' ### [**](#MODULE_TASK_TASK_LOCAL_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L49)constMODULE\_TASK\_TASK\_LOCAL\_KEY **MODULE\_TASK\_TASK\_LOCAL\_KEY: task:task:task\_local = 'task:task:task\_local' ### [**](#MODULE_TASK_TASK_LOCAL_OPTIONS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L50)constMODULE\_TASK\_TASK\_LOCAL\_OPTIONS **MODULE\_TASK\_TASK\_LOCAL\_OPTIONS: task:task:task\_local:options = 'task:task:task\_local:options' ### [**](#MS_CONSUMER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L59)constMS\_CONSUMER\_KEY **MS\_CONSUMER\_KEY: ms:consumer = 'ms:consumer' ### [**](#MS_DUBBO_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L65)constMS\_DUBBO\_METHOD\_KEY **MS\_DUBBO\_METHOD\_KEY: ms:dubbo:method = 'ms:dubbo:method' ### [**](#MS_GRPC_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L64)constMS\_GRPC\_METHOD\_KEY **MS\_GRPC\_METHOD\_KEY: ms:grpc:method = 'ms:grpc:method' ### [**](#MS_HSF_METHOD_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L66)constMS\_HSF\_METHOD\_KEY **MS\_HSF\_METHOD\_KEY: ms:hsf:method = 'ms:hsf:method' ### [**](#MS_PRODUCER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L60)constMS\_PRODUCER\_KEY **MS\_PRODUCER\_KEY: ms:producer = 'ms:producer' ### [**](#MS_PROVIDER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L61)constMS\_PROVIDER\_KEY **MS\_PROVIDER\_KEY: ms:provider = 'ms:provider' ### [**](#NetworkUtils)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/network.ts#L36)constNetworkUtils **NetworkUtils: { getHostname: () => string; getIpv4Address: () => string; getIpv6Address: () => string } = ... ### [**](#OBJECT_DEFINITION_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L15)constOBJECT\_DEFINITION\_KEY **OBJECT\_DEFINITION\_KEY: common:object\_definition = 'common:object\_definition' ### [**](#OBJ_DEF_CLS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L14)constOBJ\_DEF\_CLS **OBJ\_DEF\_CLS: common:object\_definition = OBJECT\_DEFINITION\_KEY * **@deprecated** Use OBJECT\_DEFINITION\_KEY instead ### [**](#PLUGIN_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L70)constPLUGIN\_KEY **PLUGIN\_KEY: plugin = 'plugin' ### [**](#PRE_START_MODULE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L14)constPRE\_START\_MODULE\_KEY **PRE\_START\_MODULE\_KEY: common:pre\_start\_module = 'common:pre\_start\_module' ### [**](#PROPERTY_INJECT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L21)constPROPERTY\_INJECT\_KEY **PROPERTY\_INJECT\_KEY: common:property\_inject = 'common:property\_inject' ### [**](#PROVIDE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L17)constPROVIDE\_KEY **PROVIDE\_KEY: common:provide = 'common:provide' ### [**](#PathFileUtils)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/pathFileUtil.ts#L75)constPathFileUtils **PathFileUtils: { getFileContentSync: (filePath: any, encoding? : BufferEncoding) => any; isPath: (p: any) => boolean; isPathEqual: (one: string, two: string) => boolean } = ... ### [**](#PathToRegexpUtil)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/pathToRegexp.ts#L621)constPathToRegexpUtil **PathToRegexpUtil: { compile: \

(str: string, options? : ParseOptions & TokensToFunctionOptions) => PathFunction\

; match: \

(str: Path, options? : ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions) => MatchFunction\

; parse: (str: string, options? : ParseOptions) => Token\[]; toRegexp: (path: Path, keys? : Key\[], options? : TokensToRegexpOptions & ParseOptions) => RegExp } = ... ### [**](#REQUEST_CTX_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L12)constREQUEST\_CTX\_KEY **REQUEST\_CTX\_KEY: ctx = 'ctx' ### [**](#REQUEST_CTX_LOGGER_CACHE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L16)constREQUEST\_CTX\_LOGGER\_CACHE\_KEY **REQUEST\_CTX\_LOGGER\_CACHE\_KEY: \_midway\_ctx\_logger\_cache = '\_midway\_ctx\_logger\_cache' ### [**](#REQUEST_CTX_UNIQUE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L17)constREQUEST\_CTX\_UNIQUE\_KEY **REQUEST\_CTX\_UNIQUE\_KEY: \_midway\_ctx\_unique\_key = '\_midway\_ctx\_unique\_key' ### [**](#REQUEST_OBJ_CTX_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L13)constREQUEST\_OBJ\_CTX\_KEY **REQUEST\_OBJ\_CTX\_KEY: \_req\_ctx = '\_req\_ctx' ### [**](#RequestMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L49)constRequestMethod **RequestMethod: { ALL: string; DELETE: string; GET: string; HEAD: string; OPTIONS: string; PATCH: string; POST: string; PUT: string } = ... ### [**](#SCHEDULE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L4)constSCHEDULE\_KEY **SCHEDULE\_KEY: common:schedule = 'common:schedule' ### [**](#SCOPE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L19)constSCOPE\_KEY **SCOPE\_KEY: common:scope = 'common:scope' ### [**](#SERVERLESS_FUNC_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L33)constSERVERLESS\_FUNC\_KEY **SERVERLESS\_FUNC\_KEY: faas:serverless:function = 'faas:serverless:function' ### [**](#SINGLETON_CONTAINER_CTX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/constants.ts#L33)constSINGLETON\_CONTAINER\_CTX **SINGLETON\_CONTAINER\_CTX: { \_MAIN\_CTX\_: boolean } = ... ### [**](#ServiceDiscoveryHealthCheckType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1304)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1312)constServiceDiscoveryHealthCheckType **ServiceDiscoveryHealthCheckType: { CUSTOM: custom; HTTP: http; SELF: self; TCP: tcp; TTL: ttl } = ... ### [**](#TAGGED_CLS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/legacy/constants.ts#L38)constTAGGED\_CLS **TAGGED\_CLS: common:provide = PROVIDE\_KEY * **@deprecated** Use PROVIDE\_KEY instead ### [**](#TRACE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/common/tracer.ts#L6)constTRACE\_KEY **TRACE\_KEY: decorator:open\_telemetry\_key = 'decorator:open\_telemetry\_key' Internal metadata key for trace method decorator. ### [**](#Types)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/types.ts#L98)constTypes **Types: { isAsyncFunction: (value: any) => boolean; isClass: (fn: any) => boolean; isFunction: (value: any) => boolean; isGeneratorFunction: (value: any) => boolean; isMap: (value: any) => boolean; isNull: (value: any) => boolean; isNullOrUndefined: (value: any) => boolean; isNumber: (value: any) => boolean; isObject: (value: any) => boolean; isPlainObject: (obj: any) => any; isPromise: (value: any) => boolean; isProxy: (value: any) => boolean; isRegExp: (value: any) => boolean; isSet: (value: any) => boolean; isString: (value: any) => boolean; isUndefined: (value: any) => boolean } = ... ### [**](#Utils)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/index.ts#L987)constUtils **Utils: { camelCase: (input: string) => string; generateRandomId: () => string; getParamNames: (func: any) => string\[]; isTypeScriptEnvironment: () => boolean; pascalCase: (input: string) => string; randomUUID: (force? : boolean) => string; safeParse: (text: string, reviver? : (this: any, key: string, value: any) => any) => any; safeStringify: (value: any, replacer? : any, space? : string | number) => string; sleep: (sleepTime? : number, abortController? : AbortController) => Promise\; toAsyncFunction: \(method: T) => (...args: Parameters\) => Promise\> } = ... ### [**](#WEB_RESPONSE_CONTENT_TYPE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L43)constWEB\_RESPONSE\_CONTENT\_TYPE **WEB\_RESPONSE\_CONTENT\_TYPE: web:response\_content\_type = 'web:response\_content\_type' ### [**](#WEB_RESPONSE_HEADER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L42)constWEB\_RESPONSE\_HEADER **WEB\_RESPONSE\_HEADER: web:response\_header = 'web:response\_header' ### [**](#WEB_RESPONSE_HTTP_CODE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L40)constWEB\_RESPONSE\_HTTP\_CODE **WEB\_RESPONSE\_HTTP\_CODE: web:response\_http\_code = 'web:response\_http\_code' ### [**](#WEB_RESPONSE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L39)constWEB\_RESPONSE\_KEY **WEB\_RESPONSE\_KEY: web:response = 'web:response' ### [**](#WEB_RESPONSE_REDIRECT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L41)constWEB\_RESPONSE\_REDIRECT **WEB\_RESPONSE\_REDIRECT: web:response\_redirect = 'web:response\_redirect' ### [**](#WEB_RESPONSE_RENDER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L44)constWEB\_RESPONSE\_RENDER **WEB\_RESPONSE\_RENDER: web:response\_render = 'web:response\_render' ### [**](#WEB_ROUTER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L37)constWEB\_ROUTER\_KEY **WEB\_ROUTER\_KEY: web:router = 'web:router' ### [**](#WEB_ROUTER_PARAM_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L38)constWEB\_ROUTER\_PARAM\_KEY **WEB\_ROUTER\_PARAM\_KEY: web:router\_param = 'web:router\_param' ### [**](#WS_CONTROLLER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L55)constWS\_CONTROLLER\_KEY **WS\_CONTROLLER\_KEY: ws:controller = 'ws:controller' ### [**](#WS_EVENT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/constant.ts#L56)constWS\_EVENT\_KEY **WS\_EVENT\_KEY: ws:event = 'ws:event' ### [**](#httpError)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L204)consthttpError **httpError: { BadGatewayError: typeof BadGatewayError; BadRequestError: typeof BadRequestError; ConflictError: typeof ConflictError; ForbiddenError: typeof ForbiddenError; GatewayTimeoutError: typeof GatewayTimeoutError; GoneError: typeof GoneError; InternalServerErrorError: typeof InternalServerErrorError; NotAcceptableError: typeof NotAcceptableError; NotFoundError: typeof NotFoundError; NotImplementedError: typeof NotImplementedError; PayloadTooLargeError: typeof PayloadTooLargeError; RequestTimeoutError: typeof RequestTimeoutError; ServiceUnavailableError: typeof ServiceUnavailableError; TooManyRequestsError: typeof TooManyRequestsError; UnauthorizedError: typeof UnauthorizedError; UnprocessableEntityError: typeof UnprocessableEntityError; UnsupportedMediaTypeError: typeof UnsupportedMediaTypeError } = ... --- # abstractAbstractFileDetector \ ### Hierarchy * *AbstractFileDetector* * [CommonJSFileDetector](/api/core/class/CommonJSFileDetector.md) * [CustomModuleDetector](/api/core/class/CustomModuleDetector.md) ### Implements * [IFileDetector](/api/core/interface/IFileDetector.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**run](#run) * [**runSync](#runSync) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L18)constructor * **new AbstractFileDetector\(options? : T): [AbstractFileDetector](/api/core/class/AbstractFileDetector.md)\ - #### Type parameters * **T** ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L17)options **options: T ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L22)abstractrun * **run(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ - Implementation of IFileDetector.run ### [**](#runSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L27)abstractrunSync * **runSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void - Implementation of IFileDetector.runSync --- # abstractBaseFramework \ ### Implements * [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L79)constructor * **new BaseFramework\(applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)): [BaseFramework](/api/core/class/BaseFramework.md)\ - #### Type parameters * **APP**: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)\ * **CTX**: [Context](/api/core/interface/Context.md) * **OPT**: [IConfigurationOptions](/api/core/interface/IConfigurationOptions.md) * **ResOrNext** = unknown * **Next** = unknown ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L48)publicapp **app: APP Implementation of IMidwayFramework.app ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L79)readonlyapplicationContext **applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ### [**](#configurationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L49)publicconfigurationOptions **configurationOptions: OPT Implementation of IMidwayFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L89)publicabstractapplicationInitialize * **applicationInitialize(options: [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): void | Promise\ ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L314)publicapplyMiddleware * **applyMiddleware\(lastMiddleware? : [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): Promise<[MiddlewareRespond](/api/core.md#MiddlewareRespond)\> - Implementation of IMidwayFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L88)publicabstractconfigure * **configure(options? : OPT): OPT - Implementation of IMidwayFramework.configure ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L394)publiccreateLogger * **createLogger(name: string, option? : [MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)): any - Implementation of IMidwayFramework.createLogger ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L165)publicgetAppDir * **getAppDir(): string - Implementation of IMidwayFramework.getAppDir ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L125)publicgetApplication * **getApplication(): APP - Implementation of IMidwayFramework.getApplication ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L113)publicgetApplicationContext * **getApplicationContext(): [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) - Implementation of IMidwayFramework.getApplicationContext ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L169)publicgetBaseDir * **getBaseDir(): string - Implementation of IMidwayFramework.getBaseDir ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L117)publicgetConfiguration * **getConfiguration(key? : string): any - Implementation of IMidwayFramework.getConfiguration ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L390)publicgetCoreLogger * **getCoreLogger(): [ILogger](/api/core/interface/ILogger.md) - Implementation of IMidwayFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L121)publicgetCurrentEnvironment * **getCurrentEnvironment(): string - Implementation of IMidwayFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L402)publicgetFrameworkName * **getFrameworkName(): string - Implementation of IMidwayFramework.getFrameworkName ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L386)publicgetLogger * **getLogger(name? : string): any - Implementation of IMidwayFramework.getLogger ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L412)publicgetMiddleware * **getMiddleware(): [ContextMiddlewareManager](/api/core/class/ContextMiddlewareManager.md)\ - Implementation of IMidwayFramework.getMiddleware ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L448)publicgetNamespace * **getNamespace(): string - Implementation of IMidwayFramework.getNamespace ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L398)publicgetProjectName * **getProjectName(): string - Implementation of IMidwayFramework.getProjectName ### [**](#initialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L98)publicinitialize * **initialize(options? : [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): Promise\ - Implementation of IMidwayFramework.initialize ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L94)publicisEnable * **isEnable(): boolean - Implementation of IMidwayFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L92)publicabstractrun * **run(): Promise\ - Implementation of IMidwayFramework.run ### [**](#runGuard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L424)publicrunGuard * **runGuard(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Implementation of IMidwayFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L456)publicsetFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Implementation of IMidwayFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L444)publicsetNamespace * **setNamespace(namespace: string): void ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L160)publicstop * **stop(): Promise\ - Implementation of IMidwayFramework.stop ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L416)publicuseFilter * **useFilter(filter: [CommonFilterUnion](/api/core.md#CommonFilterUnion)\): void - Implementation of IMidwayFramework.useFilter ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L420)publicuseGuard * **useGuard(guards: [CommonGuardUnion](/api/core.md#CommonGuardUnion)\): void - Implementation of IMidwayFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.ts#L406)publicuseMiddleware * **useMiddleware(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void - Implementation of IMidwayFramework.useMiddleware --- # CommonJSFileDetector CommonJS module loader ### Hierarchy * [AbstractFileDetector](/api/core/class/AbstractFileDetector.md)<{ conflictCheck? : boolean; ignore? : string | string\[]; importQuery? : boolean | string | () => string; loadDir? : string | string\[]; pattern? : string | string\[] }> * *CommonJSFileDetector* * [ESModuleFileDetector](/api/core/class/ESModuleFileDetector.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**getType](#getType) * [**loadAsync](#loadAsync) * [**loadSync](#loadSync) * [**run](#run) * [**runSync](#runSync) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L18)constructor * **new CommonJSFileDetector(options? : { conflictCheck? : boolean; ignore? : string | string\[]; importQuery? : string | boolean | () => string; loadDir? : string | string\[]; pattern? : string | string\[] }): [CommonJSFileDetector](/api/core/class/CommonJSFileDetector.md) - Inherited from AbstractFileDetector.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L17)options **options: { conflictCheck? : boolean; ignore? : string | string\[]; importQuery? : string | boolean | () => string; loadDir? : string | string\[]; pattern? : string | string\[] } Inherited from AbstractFileDetector.options ## Methods[**](#Methods) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L192)getType * **getType(): commonjs | module ### [**](#loadAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L115)loadAsync * **loadAsync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ ### [**](#loadSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L64)loadSync * **loadSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L56)run * **run(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ - Overrides AbstractFileDetector.run ### [**](#runSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L196)runSync * **runSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void - Overrides AbstractFileDetector.runSync --- # ContextMiddlewareManager \ ### Hierarchy * Array<[CommonMiddleware](/api/core.md#CommonMiddleware)\> * *ContextMiddlewareManager* ### Implements * [IMiddlewareManager](/api/core/interface/IMiddlewareManager.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**findAndInsertAfter](#findAndInsertAfter) * [**findAndInsertBefore](#findAndInsertBefore) * [**findAndInsertFirst](#findAndInsertFirst) * [**findAndInsertLast](#findAndInsertLast) * [**findItem](#findItem) * [**findItemIndex](#findItemIndex) * [**getMiddlewareName](#getMiddlewareName) * [**getNames](#getNames) * [**insertAfter](#insertAfter) * [**insertBefore](#insertBefore) * [**insertFirst](#insertFirst) * [**insertLast](#insertLast) * [**push](#push) * [**remove](#remove) * [**unshift](#unshift) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1499)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1500)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es5.d.ts#L1501)externalconstructor * **new ContextMiddlewareManager\(arrayLength: number): [ContextMiddlewareManager](/api/core/class/ContextMiddlewareManager.md)\ * **new ContextMiddlewareManager\(...items: [CommonMiddleware](/api/core.md#CommonMiddleware)\\[]): [ContextMiddlewareManager](/api/core/class/ContextMiddlewareManager.md)\ - Inherited from Array\>.constructor #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) * **R** * **N** ## Methods[**](#Methods) ### [**](#findAndInsertAfter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L81)publicfindAndInsertAfter * **findAndInsertAfter(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\, afterMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertAfter move a middleware after another middleware ### [**](#findAndInsertBefore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L107)publicfindAndInsertBefore * **findAndInsertBefore(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\, beforeMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertBefore move a middleware before another middleware ### [**](#findAndInsertFirst)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L132)publicfindAndInsertFirst * **findAndInsertFirst(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertFirst find middleware and move to first ### [**](#findAndInsertLast)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L145)publicfindAndInsertLast * **findAndInsertLast(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.findAndInsertLast find middleware and move to last ### [**](#findItem)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L172)publicfindItem * **findItem(middlewareOrName: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): [CommonMiddleware](/api/core.md#CommonMiddleware)\ - Implementation of IMiddlewareManager.findItem ### [**](#findItemIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L158)publicfindItemIndex * **findItemIndex(middlewareOrName: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): number - Implementation of IMiddlewareManager.findItemIndex find a middleware and return index ### [**](#getMiddlewareName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L192)publicgetMiddlewareName * **getMiddlewareName(middleware: [CommonMiddleware](/api/core.md#CommonMiddleware)\): string - Implementation of IMiddlewareManager.getMiddlewareName get name from middleware ### [**](#getNames)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L249)publicgetNames * **getNames(): string\[] - Implementation of IMiddlewareManager.getNames get middleware name list ### [**](#insertAfter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L62)publicinsertAfter * **insertAfter(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\, idxOrAfterMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.insertAfter insert a middleware or middleware array to after another middleware ### [**](#insertBefore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L43)publicinsertBefore * **insertBefore(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\, idxOrBeforeMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void - Implementation of IMiddlewareManager.insertBefore insert a middleware or middleware array to after another middleware ### [**](#insertFirst)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L18)publicinsertFirst * **insertFirst(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void - Implementation of IMiddlewareManager.insertFirst insert a middleware or middleware array to first ### [**](#insertLast)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L30)publicinsertLast * **insertLast(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void - Implementation of IMiddlewareManager.insertLast insert a middleware or middleware array to last ### [**](#push)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L228)publicpush * **push(...items: any\[]): number - Implementation of IMiddlewareManager.push Overrides Array.push ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L210)publicremove * **remove(middlewareOrNameOrIdx: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): [CommonMiddleware](/api/core.md#CommonMiddleware)\ - Implementation of IMiddlewareManager.remove remove a middleware ### [**](#unshift)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/middlewareManager.ts#L237)publicunshift * **unshift(...items: any\[]): number - Implementation of IMiddlewareManager.unshift Overrides Array.unshift --- # CustomModuleDetector ### Hierarchy * [AbstractFileDetector](/api/core/class/AbstractFileDetector.md)<{ modules? : any\[]; namespace? : string }> * *CustomModuleDetector* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**run](#run) * [**runSync](#runSync) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L18)constructor * **new CustomModuleDetector(options? : { modules? : any\[]; namespace? : string }): [CustomModuleDetector](/api/core/class/CustomModuleDetector.md) - Inherited from AbstractFileDetector.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L17)options **options: { modules? : any\[]; namespace? : string } Inherited from AbstractFileDetector.options ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L216)run * **run(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)): Promise\ - Overrides AbstractFileDetector.run ### [**](#runSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L220)runSync * **runSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void - Overrides AbstractFileDetector.runSync --- # abstractDataListener \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getData](#getData) * [**initData](#initData) * [**onData](#onData) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataListener\(): [DataListener](/api/core/class/DataListener.md)\ - #### Type parameters * **T** * **U** = T ## Methods[**](#Methods) ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataListener.ts#L23)publicgetData * **getData(): U ### [**](#initData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataListener.ts#L16)abstractinitData * **initData(): T | Promise\ ### [**](#onData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataListener.ts#L17)abstractonData * **onData(callback: (data: T) => void): any ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataListener.ts#L32)publicstop * **stop(): Promise\ --- # abstractDataSourceManager \ ### Implements * [IDataSourceManager](/api/core/interface/IDataSourceManager.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataSourceManager\(): [DataSourceManager](/api/core/class/DataSourceManager.md)\ - #### Type parameters * **T** * **ConnectionOpts**: [BaseDataSourceManagerConfigOption](/api/core.md#BaseDataSourceManagerConfigOption)\, ENTITY\_CONFIG\_KEY> = [BaseDataSourceManagerConfigOption](/api/core.md#BaseDataSourceManagerConfigOption)\, entities> * **ENTITY\_CONFIG\_KEY**: string = entities ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L180)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L181)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L195)publiccreateInstance * **createInstance(config: ConnectionOpts): Promise\ * **createInstance(config: ConnectionOpts, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Implementation of IDataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L167)publicgetAllDataSources * **getAllDataSources(): Map\ - Implementation of IDataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L151)publicgetDataSource * **getDataSource(dataSourceName: string): T - Implementation of IDataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L282)publicgetDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - get data source name by model or repository ### [**](#getDataSourceNames)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L163)publicgetDataSourceNames * **getDataSourceNames(): string\[] - Implementation of IDataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L322)publicgetDataSourcePriority * **getDataSourcePriority(name: string): string - Implementation of IDataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L307)publicgetDefaultDataSourceName * **getDefaultDataSourceName(): string - Implementation of IDataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L286)publicabstractgetName * **getName(): string ### [**](#hasDataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L159)publichasDataSource * **hasDataSource(dataSourceName: string): boolean - Implementation of IDataSourceManager.hasDataSource check data source has exists ### [**](#isConnected)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L175)publicisConnected * **isConnected(dataSourceName: string): Promise\ - Implementation of IDataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L326)publicisHighPriority * **isHighPriority(name: string): boolean - Implementation of IDataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L334)publicisLowPriority * **isLowPriority(name: string): boolean - Implementation of IDataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L330)publicisMediumPriority * **isMediumPriority(name: string): boolean - Implementation of IDataSourceManager.isMediumPriority ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L297)publicstop * **stop(): Promise\ - Implementation of IDataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L338)staticformatGlobString * **formatGlobString(globString: string): string\[] ### [**](#globModels)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.ts#L356)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : [ModuleLoadType](/api/core.md#ModuleLoadType)): Promise\ --- # DecoratorManager This class is used to manage the decorator data of the class * **@since** 3.0.0 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**clearAllModule](#clearAllModule) * [**createCustomMethodDecorator](#createCustomMethodDecorator) * [**createCustomParamDecorator](#createCustomParamDecorator) * [**createCustomPropertyDecorator](#createCustomPropertyDecorator) * [**getProviderId](#getProviderId) * [**getProviderName](#getProviderName) * [**getProviderUUId](#getProviderUUId) * [**isProvide](#isProvide) * [**listModule](#listModule) * [**listPreStartModule](#listPreStartModule) * [**resetModule](#resetModule) * [**saveModule](#saveModule) * [**savePreStartModule](#savePreStartModule) * [**saveProviderId](#saveProviderId) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DecoratorManager(): [DecoratorManager](/api/core/class/DecoratorManager.md) ## Methods[**](#Methods) ### [**](#clearAllModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L67)publicstaticclearAllModule * **clearAllModule(): void ### [**](#createCustomMethodDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L166)publicstaticcreateCustomMethodDecorator * **createCustomMethodDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [MethodDecoratorOptions](/api/core/interface/MethodDecoratorOptions.md)): MethodDecorator ### [**](#createCustomParamDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L192)publicstaticcreateCustomParamDecorator * **createCustomParamDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md)): ParameterDecorator ### [**](#createCustomPropertyDecorator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L139)publicstaticcreateCustomPropertyDecorator * **createCustomPropertyDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [PropertyDecoratorOptions](/api/core/interface/PropertyDecoratorOptions.md)): PropertyDecorator ### [**](#getProviderId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L105)publicstaticgetProviderId * **getProviderId(module: [ClassType](/api/core.md#ClassType)): string ### [**](#getProviderName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L115)publicstaticgetProviderName * **getProviderName(module: [ClassType](/api/core.md#ClassType)): string ### [**](#getProviderUUId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L125)publicstaticgetProviderUUId * **getProviderUUId(module: [ClassType](/api/core.md#ClassType)): string ### [**](#isProvide)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L135)publicstaticisProvide * **isProvide(target: any): boolean ### [**](#listModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L43)publicstaticlistModule * **listModule(key: [ObjectIdentifier](/api/core.md#ObjectIdentifier), filter? : (module: any) => boolean): any\[] ### [**](#listPreStartModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L59)publicstaticlistPreStartModule * **listPreStartModule(): any\[] ### [**](#resetModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L63)publicstaticresetModule * **resetModule(key: any): void ### [**](#saveModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L33)publicstaticsaveModule * **saveModule(key: [ObjectIdentifier](/api/core.md#ObjectIdentifier), module: any): void ### [**](#savePreStartModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L55)publicstaticsavePreStartModule * **savePreStartModule(module: any): void ### [**](#saveProviderId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/decoratorManager.ts#L71)publicstaticsaveProviderId * **saveProviderId(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: [ClassType](/api/core.md#ClassType)): [ClassType](/api/core.md#ClassType) --- # DefaultConsoleLoggerFactory ### Implements * [LoggerFactory](/api/core/class/LoggerFactory.md)<[ILogger](/api/core/interface/ILogger.md), any> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**createContextLogger](#createContextLogger) * [**createLogger](#createLogger) * [**getClientKeys](#getClientKeys) * [**getClients](#getClients) * [**getDefaultMidwayLoggerConfig](#getDefaultMidwayLoggerConfig) * [**getLogger](#getLogger) * [**removeLogger](#removeLogger) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DefaultConsoleLoggerFactory(): [DefaultConsoleLoggerFactory](/api/core/class/DefaultConsoleLoggerFactory.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L35)close * **close(loggerName? : string): void - Implementation of LoggerFactory.close ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L52)createContextLogger * **createContextLogger(ctx: any, appLogger: [ILogger](/api/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/core/interface/ILogger.md) - Implementation of LoggerFactory.createContextLogger ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L28)createLogger * **createLogger(name: string, options: any): [ILogger](/api/core/interface/ILogger.md) - Implementation of LoggerFactory.createLogger ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L60)publicgetClientKeys * **getClientKeys(): string\[] ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L56)publicgetClients * **getClients(): Map\ ### [**](#getDefaultMidwayLoggerConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L38)getDefaultMidwayLoggerConfig * **getDefaultMidwayLoggerConfig(): { midwayLogger: { clients? : {}; default? : any } } - Implementation of LoggerFactory.getDefaultMidwayLoggerConfig ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L32)getLogger * **getLogger(loggerName: string): [ILogger](/api/core/interface/ILogger.md) - Implementation of LoggerFactory.getLogger ### [**](#removeLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L36)removeLogger * **removeLogger(loggerName: string): void - Implementation of LoggerFactory.removeLogger --- # DynamicMidwayContainer 尝试用于开发时动态更新的 IoC 容器 ### Hierarchy * [MidwayContainer](/api/core/class/MidwayContainer.md) * *DynamicMidwayContainer* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**id](#id) * [**identifierMapping](#identifierMapping) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**registry](#registry) ### Methods * [**addNamespace](#addNamespace) * [**bind](#bind) * [**bindClass](#bindClass) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getManagedResolverFactory](#getManagedResolverFactory) * [**getNamespaceList](#getNamespaceList) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) * [**stop](#stop) * [**updateDefinition](#updateDefinition) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/dynamicContainer.ts#L23)constructor * **new DynamicMidwayContainer(): [DynamicMidwayContainer](/api/core/class/DynamicMidwayContainer.md) - Overrides MidwayContainer.constructor ## Accessors[**](#Accessors) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L53)id * **get id(): string - Inherited from MidwayContainer.id ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L81)identifierMapping * **get identifierMapping(): [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) - Inherited from MidwayContainer.identifierMapping ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L63)objectCreateEventTarget * **get objectCreateEventTarget(): EventEmitter\ - Inherited from MidwayContainer.objectCreateEventTarget ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L77)registry * **get registry(): [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) * **set registry(registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md)): void - Inherited from MidwayContainer.registry - Inherited from MidwayContainer.registry ## Methods[**](#Methods) ### [**](#addNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L88)publicaddNamespace * **addNamespace(ns: string): void - Inherited from MidwayContainer.addNamespace ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L114)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L118)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L123)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) * **bind\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Inherited from MidwayContainer.bind #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L92)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): void - Inherited from MidwayContainer.bindClass ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L346)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - Inherited from MidwayContainer.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L350)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - Inherited from MidwayContainer.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L318)publicgetAttr * **getAttr\(key: string): T - Inherited from MidwayContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L445)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Inherited from MidwayContainer.getDefinition ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/dynamicContainer.ts#L174)getIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)): string - Overrides MidwayContainer.getIdentifier Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L457)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Inherited from MidwayContainer.getInstanceScope Get instance IoC container scope ### [**](#getManagedResolverFactory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L329)publicgetManagedResolverFactory * **getManagedResolverFactory(): ManagedResolverFactory - Inherited from MidwayContainer.getManagedResolverFactory ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L437)getNamespaceList * **getNamespaceList(): string\[] - Inherited from MidwayContainer.getNamespaceList ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L453)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - Inherited from MidwayContainer.getObject #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L441)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from MidwayContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L433)hasNamespace * **hasNamespace(ns: string): boolean - Inherited from MidwayContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L449)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from MidwayContainer.hasObject ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L370)onBeforeBind * **onBeforeBind(fn: (Clzz: any, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md); replaceCallback: (newDefinition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md)) => void }) => void): void - Inherited from MidwayContainer.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L383)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (Clzz: any, options: { constructorArgs: any\[]; context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L421)onBeforeObjectDestroy * **onBeforeObjectDestroy\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L396)onObjectCreated * **onObjectCreated\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md); replaceCallback: (ins: T) => void }) => void): void - Inherited from MidwayContainer.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L409)onObjectInit * **onObjectInit\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Inherited from MidwayContainer.onObjectInit #### Type parameters * **T** ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L362)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void - Inherited from MidwayContainer.registerObject proxy registry.registerObject ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L366)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void - Inherited from MidwayContainer.removeObject ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L314)publicsetAttr * **setAttr(key: string, value: any): void - Inherited from MidwayContainer.setAttr Set value to app attribute map ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L336)stop * **stop(): Promise\ - Inherited from MidwayContainer.stop ### [**](#updateDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/dynamicContainer.ts#L58)updateDefinition * **updateDefinition(modifyFilePath: string): Promise\ --- # ESModuleFileDetector ES module loader ### Hierarchy * [CommonJSFileDetector](/api/core/class/CommonJSFileDetector.md) * *ESModuleFileDetector* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**options](#options) ### Methods * [**getType](#getType) * [**loadAsync](#loadAsync) * [**loadSync](#loadSync) * [**run](#run) * [**runSync](#runSync) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L18)constructor * **new ESModuleFileDetector(options? : { conflictCheck? : boolean; ignore? : string | string\[]; importQuery? : string | boolean | () => string; loadDir? : string | string\[]; pattern? : string | string\[] }): [ESModuleFileDetector](/api/core/class/ESModuleFileDetector.md) - Inherited from CommonJSFileDetector.constructor ## Properties[**](#Properties) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L17)options **options: { conflictCheck? : boolean; ignore? : string | string\[]; importQuery? : string | boolean | () => string; loadDir? : string | string\[]; pattern? : string | string\[] } Inherited from CommonJSFileDetector.options ## Methods[**](#Methods) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L207)getType * **getType(): commonjs | module - Overrides CommonJSFileDetector.getType ### [**](#loadAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L115)loadAsync * **loadAsync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ - Inherited from CommonJSFileDetector.loadAsync ### [**](#loadSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L64)loadSync * **loadSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void - Inherited from CommonJSFileDetector.loadSync ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L56)run * **run(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ - Inherited from CommonJSFileDetector.run ### [**](#runSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/fileDetector.ts#L196)runSync * **runSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void - Inherited from CommonJSFileDetector.runSync --- # FilterManager \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) * [**runErrorFilter](#runErrorFilter) * [**runResultFilter](#runResultFilter) * [**useFilter](#useFilter) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new FilterManager\(): [FilterManager](/api/core/class/FilterManager.md)\ - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) = [Context](/api/core/interface/Context.md) * **R** = any * **N** = any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/filterManager.ts#L45)publicinit * **init(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): Promise\ ### [**](#runErrorFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/filterManager.ts#L91)publicrunErrorFilter * **runErrorFilter(err: Error, ctx: CTX, res? : R, next? : N): Promise<{ error: any; result: any }> ### [**](#runResultFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/filterManager.ts#L138)publicrunResultFilter * **runResultFilter(result: any, ctx: CTX, res? : R, next? : N): Promise<{ error: any; result: any }> ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/filterManager.ts#L31)publicuseFilter * **useFilter(Filters: [CommonFilterUnion](/api/core.md#CommonFilterUnion)\): void --- # HttpClient A simple http client ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**defaultOptions](#defaultOptions) ### Methods * [**request](#request) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L140)constructor * **new HttpClient(defaultOptions? : Pick<[HttpClientOptions](/api/core/interface/HttpClientOptions.md)\, headers | method | timeout>): [HttpClient](/api/core/class/HttpClient.md) ## Properties[**](#Properties) ### [**](#defaultOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L141)readonlydefaultOptions **defaultOptions: Pick<[HttpClientOptions](/api/core/interface/HttpClientOptions.md)\, headers | method | timeout> = {} ## Methods[**](#Methods) ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L147)request * **request(url: string, options? : [HttpClientOptions](/api/core/interface/HttpClientOptions.md)\): Promise<[HttpClientResponse](/api/core/interface/HttpClientResponse.md)\> --- # HttpServerResponse \ ### Hierarchy * [ServerResponse](/api/core/class/ServerResponse.md)\ * *HttpServerResponse* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**blob](#blob) * [**fail](#fail) * [**file](#file) * [**header](#header) * [**headers](#headers) * [**html](#html) * [**json](#json) * [**redirect](#redirect) * [**sse](#sse) * [**status](#status) * [**stream](#stream) * [**success](#success) * [**text](#text) * [**BLOB\_TPL](#BLOB_TPL) * [**FILE\_TPL](#FILE_TPL) * [**HTML\_TPL](#HTML_TPL) * [**JSON\_TPL](#JSON_TPL) * [**SSE\_TPL](#SSE_TPL) * [**STREAM\_TPL](#STREAM_TPL) * [**TEXT\_TPL](#TEXT_TPL) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L17)constructor * **new HttpServerResponse\(ctx: CTX): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ - Overrides ServerResponse.constructor #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ## Methods[**](#Methods) ### [**](#blob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L100)blob * **blob(data: Buffer, mimeType? : string): any - Overrides ServerResponse.blob ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L74)fail * **fail(): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ - Inherited from ServerResponse.fail ### [**](#file)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L87)file * **file(filePath: string, mimeType? : string): any ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L53)header * **header(key: string, value: string): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L58)headers * **headers(headers: Record\): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ ### [**](#html)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L109)html * **html(data: string): any ### [**](#json)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L69)json * **json(data: Record\): any - Overrides ServerResponse.json ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L118)redirect * **redirect(url: string, status? : number): any ### [**](#sse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L129)sse * **sse(options? : [ServerSendEventStreamOptions](/api/core/interface/ServerSendEventStreamOptions.md)\): ServerSendEventStream<[Context](/api/core/interface/Context.md)> ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L48)status * **status(code: number): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ ### [**](#stream)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L136)stream * **stream(options? : [ServerStreamOptions](/api/core/interface/ServerStreamOptions.md)\): HttpStreamResponse<[Context](/api/core/interface/Context.md)> ### [**](#success)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L69)success * **success(): [HttpServerResponse](/api/core/class/HttpServerResponse.md)\ - Inherited from ServerResponse.success ### [**](#text)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L78)text * **text(data: string): any - Overrides ServerResponse.text ### [**](#BLOB_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L37)staticBLOB\_TPL * **BLOB\_TPL\(data: Buffer, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.BLOB\_TPL #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#FILE_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L21)staticFILE\_TPL * **FILE\_TPL\(data: Readable, isSuccess: boolean, ctx: CTX): Readable - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#HTML_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L40)staticHTML\_TPL * **HTML\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#JSON_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L19)staticJSON\_TPL * **JSON\_TPL\(data: Record\, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.JSON\_TPL #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#SSE_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L29)staticSSE\_TPL * **SSE\_TPL\(data: [ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md), ctx: CTX): [ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md) - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#STREAM_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/http.ts#L36)staticSTREAM\_TPL * **STREAM\_TPL\(data: unknown, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#TEXT_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L11)staticTEXT\_TPL * **TEXT\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - Inherited from ServerResponse.TEXT\_TPL #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) --- # LoadBalancerFactory 负载均衡工厂 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**create](#create) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new LoadBalancerFactory(): [LoadBalancerFactory](/api/core/class/LoadBalancerFactory.md) ## Methods[**](#Methods) ### [**](#create)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/loadBalancer.ts#L40)staticcreate * **create\(type: [LoadBalancerType](/api/core.md#LoadBalancerType)): [ILoadBalancer](/api/core/interface/ILoadBalancer.md)\ - #### Type parameters * **ServiceInstance** --- # abstractLoggerFactory \ ### Implemented by * [DefaultConsoleLoggerFactory](/api/core/class/DefaultConsoleLoggerFactory.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**createContextLogger](#createContextLogger) * [**createLogger](#createLogger) * [**getDefaultMidwayLoggerConfig](#getDefaultMidwayLoggerConfig) * [**getLogger](#getLogger) * [**removeLogger](#removeLogger) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new LoggerFactory\(): [LoggerFactory](/api/core/class/LoggerFactory.md)\ - #### Type parameters * **Logger**: [ILogger](/api/core/interface/ILogger.md) * **LoggerOptions** ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L6)abstractclose * **close(loggerName? : string): any ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L16)abstractcreateContextLogger * **createContextLogger(ctx: any, appLogger: [ILogger](/api/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/core/interface/ILogger.md) ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L4)abstractcreateLogger * **createLogger(name: string, options: LoggerOptions): Logger ### [**](#getDefaultMidwayLoggerConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L8)abstractgetDefaultMidwayLoggerConfig * **getDefaultMidwayLoggerConfig(appInfo: [MidwayAppInfo](/api/core/interface/MidwayAppInfo.md)): { midwayLogger: { clients? : {}; default? : LoggerOptions } } ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L5)abstractgetLogger * **getLogger(loggerName: string): Logger ### [**](#removeLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/loggerFactory.ts#L7)abstractremoveLogger * **removeLogger(loggerName: string): any --- # MetadataManager A class that manages metadata for classes and properties This class is a simplified version of the Reflect Metadata API Provides a way to retrieve, define, delete and copy metadata * **@since** 4.0.0 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ObjectType](#ObjectType) * [**emptyValueSymbol](#emptyValueSymbol) ### Methods * [**attachMetadata](#attachMetadata) * [**clear](#clear) * [**copyMetadata](#copyMetadata) * [**copyOwnMetadata](#copyOwnMetadata) * [**defineMetadata](#defineMetadata) * [**deleteMetadata](#deleteMetadata) * [**ensureTargetType](#ensureTargetType) * [**getMetadata](#getMetadata) * [**getMetadataKeys](#getMetadataKeys) * [**getMethodParamTypes](#getMethodParamTypes) * [**getMethodReturnTypes](#getMethodReturnTypes) * [**getOwnMetadata](#getOwnMetadata) * [**getOwnMetadataKeys](#getOwnMetadataKeys) * [**getOwnPropertiesWithMetadata](#getOwnPropertiesWithMetadata) * [**getPropertiesWithMetadata](#getPropertiesWithMetadata) * [**getPropertyType](#getPropertyType) * [**hasMetadata](#hasMetadata) * [**hasOwnMetadata](#hasOwnMetadata) * [**transformTypeFromTSDesign](#transformTypeFromTSDesign) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MetadataManager(): [MetadataManager](/api/core/class/MetadataManager.md) ## Properties[**](#Properties) ### [**](#ObjectType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L38)publicstaticObjectType **ObjectType: typeof ObjectType = ObjectType ### [**](#emptyValueSymbol)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L42)publicstaticreadonlyemptyValueSymbol **emptyValueSymbol: typeof emptyValueSymbol = ... A symbol that represents an empty value ## Methods[**](#Methods) ### [**](#attachMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L67)publicstaticattachMetadata * **attachMetadata(metadataKey: string | symbol, metadataValue: any, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): void - Attaches metadata for a target class or property Value will push to the end of the metadata array and save for own metadata ### [**](#clear)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L681)publicstaticclear * **clear(): void ### [**](#copyMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L237)publicstaticcopyMetadata * **copyMetadata(source: [ClassType](/api/core.md#ClassType), target: [ClassType](/api/core.md#ClassType), options? : { metadataFilter? : (metadataKey: string | symbol, propertyKey? : string | symbol) => boolean; overwrite? : boolean }): void - Copies metadata from a source class or property to a target class or property ### [**](#copyOwnMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L298)publicstaticcopyOwnMetadata * **copyOwnMetadata(source: [ClassType](/api/core.md#ClassType), target: [ClassType](/api/core.md#ClassType), options? : { metadataFilter? : (metadataKey: string | symbol, propertyKey? : string | symbol) => boolean; overwrite? : boolean }): void - Copies own metadata from a source class or property to a target class or property ### [**](#defineMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L47)publicstaticdefineMetadata * **defineMetadata(metadataKey: string | symbol, metadataValue: any, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): void - Defines metadata for a target class or property Value will replace the existing metadata ### [**](#deleteMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L180)publicstaticdeleteMetadata * **deleteMetadata(metadataKey: string | symbol, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): void - Deletes metadata for a target class or property ### [**](#ensureTargetType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L649)publicstaticensureTargetType * **ensureTargetType(target: any, type: ObjectType): void ### [**](#getMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L91)publicstaticgetMetadata * **getMetadata\(metadataKey: string | symbol, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): T - Retrieves metadata for a target class or property *** #### Type parameters * **T** = any ### [**](#getMetadataKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L199)publicstaticgetMetadataKeys * **getMetadataKeys(target: [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): string\[] - Get all metadata keys on the entire prototype chain Because we need to get metadata on the entire prototype chain, we do not use cache here, so the performance is poor ### [**](#getMethodParamTypes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L414)publicstaticgetMethodParamTypes * **getMethodParamTypes(target: [ClassType](/api/core.md#ClassType), methodName: string | symbol, parameterIndex? : number): any - Get parameters type by reflect-metadata ### [**](#getMethodReturnTypes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L401)publicstaticgetMethodReturnTypes * **getMethodReturnTypes(target: [ClassType](/api/core.md#ClassType), propertyKey: string | symbol): any - Gets the type of a property from Reflect metadata ### [**](#getOwnMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L140)publicstaticgetOwnMetadata * **getOwnMetadata\(metadataKey: string | symbol, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): T - Retrieves own metadata for a target class or property *** #### Type parameters * **T** = any ### [**](#getOwnMetadataKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L219)publicstaticgetOwnMetadataKeys * **getOwnMetadataKeys(target: [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): string\[] - Get metadata keys on the current class or object ### [**](#getOwnPropertiesWithMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L331)publicstaticgetOwnPropertiesWithMetadata * **getOwnPropertiesWithMetadata\(metadataKey: string | symbol, target: [ClassType](/api/core.md#ClassType)): {} - Retrieves all properties of the current class that have a specific metadata key and their metadata values. *** #### Type parameters * **T** = any ### [**](#getPropertiesWithMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L366)publicstaticgetPropertiesWithMetadata * **getPropertiesWithMetadata\(metadataKey: string | symbol, target: [ClassType](/api/core.md#ClassType)): {} - Retrieves all properties of the class and its prototype chain that have a specific metadata key and their metadata values. *** #### Type parameters * **T** = any ### [**](#getPropertyType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L433)publicstaticgetPropertyType * **getPropertyType(target: [ClassType](/api/core.md#ClassType), propertyKey: string | symbol): any - Get property(method) type from metadata ### [**](#hasMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L157)publicstatichasMetadata * **hasMetadata(metadataKey: string | symbol, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): boolean - Checks if metadata exists for a target class or property ### [**](#hasOwnMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L169)publicstatichasOwnMetadata * **hasOwnMetadata(metadataKey: string | symbol, target: object | [ClassType](/api/core.md#ClassType), propertyKey? : string | symbol): boolean - Checks if own metadata exists for a target class or property ### [**](#transformTypeFromTSDesign)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/metadataManager.ts#L443)publicstatictransformTypeFromTSDesign * **transformTypeFromTSDesign(designFn: any): [TSDesignType](/api/core/interface/TSDesignType.md)\ --- # MidwayApplicationManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addFramework](#addFramework) * [**getApplication](#getApplication) * [**getApplications](#getApplications) * [**getFramework](#getFramework) * [**hasFramework](#hasFramework) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayApplicationManager(): [MidwayApplicationManager](/api/core/class/MidwayApplicationManager.md) ## Methods[**](#Methods) ### [**](#addFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/applicationManager.ts#L12)publicaddFramework * **addFramework(frameworkNameOrNamespace: string, framework: [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\): void ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/applicationManager.ts#L29)publicgetApplication * **getApplication(frameworkNameOrNamespace: string): [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)> ### [**](#getApplications)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/applicationManager.ts#L37)publicgetApplications * **getApplications(frameworkNameOrNamespace? : string\[]): [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>\[] ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/applicationManager.ts#L23)publicgetFramework * **getFramework(frameworkNameOrNamespace: string): [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\ ### [**](#hasFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/applicationManager.ts#L19)publichasFramework * **hasFramework(frameworkNameOrNamespace: string): boolean --- # MidwayAspectService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**addAspect](#addAspect) * [**interceptPrototypeMethod](#interceptPrototypeMethod) * [**loadAspect](#loadAspect) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/aspectService.ts#L16)constructor * **new MidwayAspectService(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): [MidwayAspectService](/api/core/class/MidwayAspectService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/aspectService.ts#L16)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#addAspect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/aspectService.ts#L50)publicaddAspect * **addAspect(aspectIns: [IMethodAspect](/api/core/interface/IMethodAspect.md), aspectData: [AspectMetadata](/api/core/interface/AspectMetadata.md)): Promise\ ### [**](#interceptPrototypeMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/aspectService.ts#L77)publicinterceptPrototypeMethod * **interceptPrototypeMethod(Clz: new (...args: any\[]) => any, methodName: string, aspectObject: [IMethodAspect](/api/core/interface/IMethodAspect.md) | () => [IMethodAspect](/api/core/interface/IMethodAspect.md)): void - intercept class method in prototype ### [**](#loadAspect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/aspectService.ts#L21)publicloadAspect * **loadAspect(): Promise\ - load aspect method for container --- # MidwayCodeInvokeTimeoutError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayCodeInvokeTimeoutError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L209)constructor * **new MidwayCodeInvokeTimeoutError(methodName: string, timeout: number, moduleName? : string): [MidwayCodeInvokeTimeoutError](/api/core/class/MidwayCodeInvokeTimeoutError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayCommonError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayCommonError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L30)constructor * **new MidwayCommonError(message: string): [MidwayCommonError](/api/core/class/MidwayCommonError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayConfigMissingError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayConfigMissingError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L75)constructor * **new MidwayConfigMissingError(configKey: string): [MidwayConfigMissingError](/api/core/class/MidwayConfigMissingError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayConfigService ### Implements * [IConfigService](/api/core/interface/IConfigService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**add](#add) * [**addFilter](#addFilter) * [**addObject](#addObject) * [**clearAllConfig](#clearAllConfig) * [**clearConfigMergeOrder](#clearConfigMergeOrder) * [**getAppInfo](#getAppInfo) * [**getConfigMergeOrder](#getConfigMergeOrder) * [**getConfiguration](#getConfiguration) * [**load](#load) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayConfigService(): [MidwayConfigService](/api/core/class/MidwayConfigService.md) ## Methods[**](#Methods) ### [**](#add)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L57)publicadd * **add(configFilePaths: any\[]): void - Implementation of IConfigService.add ### [**](#addFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L248)publicaddFilter * **addFilter(filter: (config: Record\) => Record\): void - add a config filter ### [**](#addObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L92)publicaddObject * **addObject(obj: Record\, reverse? : boolean): void - Implementation of IConfigService.addObject ### [**](#clearAllConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L236)publicclearAllConfig * **clearAllConfig(): void - Implementation of IConfigService.clearAllConfig ### [**](#clearConfigMergeOrder)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L240)publicclearConfigMergeOrder * **clearConfigMergeOrder(): void ### [**](#getAppInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L267)publicgetAppInfo * **getAppInfo(): [MidwayAppInfo](/api/core/interface/MidwayAppInfo.md) ### [**](#getConfigMergeOrder)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L209)publicgetConfigMergeOrder * **getConfigMergeOrder(): ConfigMergeInfo\[] ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L201)publicgetConfiguration * **getConfiguration\(configKey? : string, defaultValue? : any): T - Implementation of IConfigService.getConfiguration #### Type parameters * **T** = any ### [**](#load)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/configService.ts#L133)publicload * **load(): void - Implementation of IConfigService.load --- # MidwayContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * *MidwayContainer* * [DynamicMidwayContainer](/api/core/class/DynamicMidwayContainer.md) ### Implements * [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**id](#id) * [**identifierMapping](#identifierMapping) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**registry](#registry) ### Methods * [**addNamespace](#addNamespace) * [**bind](#bind) * [**bindClass](#bindClass) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getManagedResolverFactory](#getManagedResolverFactory) * [**getNamespaceList](#getNamespaceList) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L57)constructor * **new MidwayContainer(): [MidwayContainer](/api/core/class/MidwayContainer.md) ## Accessors[**](#Accessors) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L53)id * **get id(): string ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L81)identifierMapping * **get identifierMapping(): [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) - Implementation of IMidwayGlobalContainer.identifierMapping ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L63)objectCreateEventTarget * **get objectCreateEventTarget(): EventEmitter\ - Implementation of IMidwayGlobalContainer.objectCreateEventTarget ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L77)registry * **get registry(): [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) * **set registry(registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md)): void - Implementation of IMidwayGlobalContainer.registry - Implementation of IMidwayGlobalContainer.registry ## Methods[**](#Methods) ### [**](#addNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L88)publicaddNamespace * **addNamespace(ns: string): void - Implementation of IMidwayGlobalContainer.addNamespace ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L114)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L118)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L123)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) * **bind\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Implementation of IMidwayGlobalContainer.bind #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L92)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): void - Implementation of IMidwayGlobalContainer.bindClass ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L346)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - Implementation of IMidwayGlobalContainer.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L350)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - Implementation of IMidwayGlobalContainer.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L318)publicgetAttr * **getAttr\(key: string): T - Implementation of IMidwayGlobalContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L445)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Implementation of IMidwayGlobalContainer.getDefinition ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L322)publicgetIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)): string - Implementation of IMidwayGlobalContainer.getIdentifier Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L457)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Implementation of IMidwayGlobalContainer.getInstanceScope Get instance IoC container scope ### [**](#getManagedResolverFactory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L329)publicgetManagedResolverFactory * **getManagedResolverFactory(): ManagedResolverFactory - Implementation of IMidwayGlobalContainer.getManagedResolverFactory ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L437)getNamespaceList * **getNamespaceList(): string\[] - Implementation of IMidwayGlobalContainer.getNamespaceList ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L453)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - Implementation of IMidwayGlobalContainer.getObject #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L441)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayGlobalContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L433)hasNamespace * **hasNamespace(ns: string): boolean - Implementation of IMidwayGlobalContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L449)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayGlobalContainer.hasObject ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L370)onBeforeBind * **onBeforeBind(fn: (Clzz: any, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md); replaceCallback: (newDefinition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md)) => void }) => void): void - Implementation of IMidwayGlobalContainer.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L383)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (Clzz: any, options: { constructorArgs: any\[]; context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayGlobalContainer.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L421)onBeforeObjectDestroy * **onBeforeObjectDestroy\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayGlobalContainer.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L396)onObjectCreated * **onObjectCreated\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md); replaceCallback: (ins: T) => void }) => void): void - Implementation of IMidwayGlobalContainer.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L409)onObjectInit * **onObjectInit\(fn: (ins: T, options: { context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md); definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) }) => void): void - Implementation of IMidwayGlobalContainer.onObjectInit #### Type parameters * **T** ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L362)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void - Implementation of IMidwayGlobalContainer.registerObject proxy registry.registerObject ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L366)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void - Implementation of IMidwayGlobalContainer.removeObject ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L314)publicsetAttr * **setAttr(key: string, value: any): void - Implementation of IMidwayGlobalContainer.setAttr Set value to app attribute map ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/container.ts#L336)stop * **stop(): Promise\ - Implementation of IMidwayGlobalContainer.stop --- # MidwayDecoratorService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**registerMethodHandler](#registerMethodHandler) * [**registerParameterHandler](#registerParameterHandler) * [**registerParameterPipes](#registerParameterPipes) * [**registerPropertyHandler](#registerPropertyHandler) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L42)constructor * **new MidwayDecoratorService(applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)): [MidwayDecoratorService](/api/core/class/MidwayDecoratorService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L42)readonlyapplicationContext **applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ## Methods[**](#Methods) ### [**](#registerMethodHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L231)publicregisterMethodHandler * **registerMethodHandler(decoratorKey: string, fn: [MethodHandlerFunction](/api/core.md#MethodHandlerFunction)): void ### [**](#registerParameterHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L239)publicregisterParameterHandler * **registerParameterHandler(decoratorKey: string, fn: [ParameterHandlerFunction](/api/core.md#ParameterHandlerFunction)): void ### [**](#registerParameterPipes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L247)publicregisterParameterPipes * **registerParameterPipes(decoratorKey: string, pipes: [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): void ### [**](#registerPropertyHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/decoratorService.ts#L226)publicregisterPropertyHandler * **registerPropertyHandler(decoratorKey: string, fn: [HandlerFunction](/api/core.md#HandlerFunction)): void --- # MidwayDefinitionNotFoundError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayDefinitionNotFoundError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L42)constructor * **new MidwayDefinitionNotFoundError(id: string, name: string, creationPath? : string\[]): [MidwayDefinitionNotFoundError](/api/core/class/MidwayDefinitionNotFoundError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayDuplicateClassNameError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayDuplicateClassNameError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L164)constructor * **new MidwayDuplicateClassNameError(className: string, existPath: string, existPathOther: string): [MidwayDuplicateClassNameError](/api/core/class/MidwayDuplicateClassNameError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayDuplicateControllerOptionsError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayDuplicateControllerOptionsError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L173)constructor * **new MidwayDuplicateControllerOptionsError(prefix: string, existController: string, existControllerOther: string): [MidwayDuplicateControllerOptionsError](/api/core/class/MidwayDuplicateControllerOptionsError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayDuplicateRouteError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayDuplicateRouteError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**payload](#payload) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L108)constructor * **new MidwayDuplicateRouteError(routerUrl: string, existPos: string, existPosOther: string, payload? : [DuplicateRouteErrorPayload](/api/core/interface/DuplicateRouteErrorPayload.md)): [MidwayDuplicateRouteError](/api/core/class/MidwayDuplicateRouteError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code ### [**](#payload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L106)optionalpayload **payload? : [DuplicateRouteErrorPayload](/api/core/interface/DuplicateRouteErrorPayload.md) --- # MidwayEmptyValueError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayEmptyValueError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L242)constructor * **new MidwayEmptyValueError(msg: string): [MidwayEmptyValueError](/api/core/class/MidwayEmptyValueError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayEnvironmentService ### Implements * [IEnvironmentService](/api/core/interface/IEnvironmentService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getModuleLoadType](#getModuleLoadType) * [**isDevelopmentEnvironment](#isDevelopmentEnvironment) * [**isPkgEnvironment](#isPkgEnvironment) * [**setCurrentEnvironment](#setCurrentEnvironment) * [**setModuleLoadType](#setModuleLoadType) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayEnvironmentService(): [MidwayEnvironmentService](/api/core/class/MidwayEnvironmentService.md) ## Methods[**](#Methods) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L11)publicgetCurrentEnvironment * **getCurrentEnvironment(): string - Implementation of IEnvironmentService.getCurrentEnvironment ### [**](#getModuleLoadType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L30)publicgetModuleLoadType * **getModuleLoadType(): [ModuleLoadType](/api/core.md#ModuleLoadType) - Implementation of IEnvironmentService.getModuleLoadType ### [**](#isDevelopmentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L22)publicisDevelopmentEnvironment * **isDevelopmentEnvironment(): boolean - Implementation of IEnvironmentService.isDevelopmentEnvironment ### [**](#isPkgEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L34)publicisPkgEnvironment * **isPkgEnvironment(): boolean ### [**](#setCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L18)publicsetCurrentEnvironment * **setCurrentEnvironment(environment: string): void ### [**](#setModuleLoadType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/environmentService.ts#L26)publicsetModuleLoadType * **setModuleLoadType(moduleLoadType: [ModuleLoadType](/api/core.md#ModuleLoadType)): void --- # MidwayError ### Hierarchy * Error * *MidwayError* * [MidwayHttpError](/api/core/class/MidwayHttpError.md) * [MidwayCommonError](/api/core/class/MidwayCommonError.md) * [MidwayParameterError](/api/core/class/MidwayParameterError.md) * [MidwayDefinitionNotFoundError](/api/core/class/MidwayDefinitionNotFoundError.md) * [MidwayFeatureNoLongerSupportedError](/api/core/class/MidwayFeatureNoLongerSupportedError.md) * [MidwayFeatureNotImplementedError](/api/core/class/MidwayFeatureNotImplementedError.md) * [MidwayConfigMissingError](/api/core/class/MidwayConfigMissingError.md) * [MidwayInvalidConfigError](/api/core/class/MidwayInvalidConfigError.md) * [MidwayDuplicateRouteError](/api/core/class/MidwayDuplicateRouteError.md) * [MidwayUseWrongMethodError](/api/core/class/MidwayUseWrongMethodError.md) * [MidwaySingletonInjectRequestError](/api/core/class/MidwaySingletonInjectRequestError.md) * [MidwayMissingImportComponentError](/api/core/class/MidwayMissingImportComponentError.md) * [MidwayUtilHttpClientTimeoutError](/api/core/class/MidwayUtilHttpClientTimeoutError.md) * [MidwayInconsistentVersionError](/api/core/class/MidwayInconsistentVersionError.md) * [MidwayDuplicateClassNameError](/api/core/class/MidwayDuplicateClassNameError.md) * [MidwayDuplicateControllerOptionsError](/api/core/class/MidwayDuplicateControllerOptionsError.md) * [MidwayRetryExceededMaxTimesError](/api/core/class/MidwayRetryExceededMaxTimesError.md) * [MidwayInvokeForbiddenError](/api/core/class/MidwayInvokeForbiddenError.md) * [MidwayCodeInvokeTimeoutError](/api/core/class/MidwayCodeInvokeTimeoutError.md) * [MidwayMainFrameworkMissingError](/api/core/class/MidwayMainFrameworkMissingError.md) * [MidwayInvalidConfigPropertyError](/api/core/class/MidwayInvalidConfigPropertyError.md) * [MidwayEmptyValueError](/api/core/class/MidwayEmptyValueError.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L53)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L54)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L55)constructor * **new MidwayError(message: string, options? : ErrorOption): [MidwayError](/api/core/class/MidwayError.md) * **new MidwayError(message: string, code: string, options? : ErrorOption): [MidwayError](/api/core/class/MidwayError.md) - Overrides Error.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Overrides Error.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number --- # MidwayFeatureNoLongerSupportedError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayFeatureNoLongerSupportedError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L57)constructor * **new MidwayFeatureNoLongerSupportedError(message? : string): [MidwayFeatureNoLongerSupportedError](/api/core/class/MidwayFeatureNoLongerSupportedError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayFeatureNotImplementedError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayFeatureNotImplementedError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L66)constructor * **new MidwayFeatureNotImplementedError(message? : string): [MidwayFeatureNotImplementedError](/api/core/class/MidwayFeatureNotImplementedError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayFrameworkService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**applicationManager](#applicationManager) * [**aspectService](#aspectService) * [**configService](#configService) * [**decoratorService](#decoratorService) * [**globalOptions](#globalOptions) * [**loggerService](#loggerService) ### Methods * [**getFramework](#getFramework) * [**getMainApp](#getMainApp) * [**getMainFramework](#getMainFramework) * [**runFramework](#runFramework) * [**setMainApp](#setMainApp) * [**stopFramework](#stopFramework) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L52)constructor * **new MidwayFrameworkService(applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), globalOptions: any): [MidwayFrameworkService](/api/core/class/MidwayFrameworkService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L53)readonlyapplicationContext **applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L50)applicationManager **applicationManager: [MidwayApplicationManager](/api/core/class/MidwayApplicationManager.md) ### [**](#aspectService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L44)aspectService **aspectService: [MidwayAspectService](/api/core/class/MidwayAspectService.md) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L38)configService **configService: [MidwayConfigService](/api/core/class/MidwayConfigService.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L47)decoratorService **decoratorService: [MidwayDecoratorService](/api/core/class/MidwayDecoratorService.md) ### [**](#globalOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L54)readonlyglobalOptions **globalOptions: any ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L41)loggerService **loggerService: [MidwayLoggerService](/api/core/class/MidwayLoggerService.md) ## Methods[**](#Methods) ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L256)publicgetFramework * **getFramework(namespace: string): [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\ ### [**](#getMainApp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L244)publicgetMainApp * **getMainApp(): any ### [**](#getMainFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L252)publicgetMainFramework * **getMainFramework(): [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\ ### [**](#runFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L260)publicrunFramework * **runFramework(): Promise\ ### [**](#setMainApp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L248)publicsetMainApp * **setMainApp(namespace: string): void ### [**](#stopFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/frameworkService.ts#L288)publicstopFramework * **stopFramework(): Promise\ --- # MidwayHealthService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getStatus](#getStatus) * [**init](#init) * [**setCheckTimeout](#setCheckTimeout) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayHealthService(): [MidwayHealthService](/api/core/class/MidwayHealthService.md) ## Methods[**](#Methods) ### [**](#getStatus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/healthService.ts#L70)getStatus * **getStatus(): Promise<[HealthResults](/api/core/interface/HealthResults.md)> ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/healthService.ts#L42)init * **init(lifeCycleInstanceList: { instance? : any; namespace: string; target: any }\[]): Promise\ ### [**](#setCheckTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/healthService.ts#L125)setCheckTimeout * **setCheckTimeout(timeout: number): void --- # MidwayHttpError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayHttpError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L72)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L73)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L79)constructor * **new MidwayHttpError(resOrMessage: [ResOrMessage](/api/core.md#ResOrMessage), status: number): [MidwayHttpError](/api/core/class/MidwayHttpError.md) * **new MidwayHttpError(resOrMessage: [ResOrMessage](/api/core.md#ResOrMessage), status: number, code: string, options? : ErrorOption): [MidwayHttpError](/api/core/class/MidwayHttpError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L70)status **status: number --- # MidwayInconsistentVersionError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayInconsistentVersionError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L156)constructor * **new MidwayInconsistentVersionError(): [MidwayInconsistentVersionError](/api/core/class/MidwayInconsistentVersionError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInformationService ### Implements * [IInformationService](/api/core/interface/IInformationService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getAppDir](#getAppDir) * [**getBaseDir](#getBaseDir) * [**getHome](#getHome) * [**getHostname](#getHostname) * [**getIpv4Address](#getIpv4Address) * [**getIpv6Address](#getIpv6Address) * [**getPkg](#getPkg) * [**getProjectName](#getProjectName) * [**getRoot](#getRoot) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayInformationService(): [MidwayInformationService](/api/core/class/MidwayInformationService.md) ## Methods[**](#Methods) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L43)getAppDir * **getAppDir(): string - Implementation of IInformationService.getAppDir ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L47)getBaseDir * **getBaseDir(): string - Implementation of IInformationService.getBaseDir ### [**](#getHome)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L51)getHome * **getHome(): string - Implementation of IInformationService.getHome ### [**](#getHostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L68)getHostname * **getHostname(): string ### [**](#getIpv4Address)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L72)getIpv4Address * **getIpv4Address(): string ### [**](#getIpv6Address)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L76)getIpv6Address * **getIpv6Address(): string ### [**](#getPkg)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L55)getPkg * **getPkg(): any - Implementation of IInformationService.getPkg ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L59)getProjectName * **getProjectName(): string - Implementation of IInformationService.getProjectName ### [**](#getRoot)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/informationService.ts#L63)getRoot * **getRoot(): string - Implementation of IInformationService.getRoot --- # MidwayInvalidConfigError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayInvalidConfigError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L84)constructor * **new MidwayInvalidConfigError(message? : string): [MidwayInvalidConfigError](/api/core/class/MidwayInvalidConfigError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInvalidConfigPropertyError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayInvalidConfigPropertyError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L229)constructor * **new MidwayInvalidConfigPropertyError(propertyName: string, allowTypes? : string\[]): [MidwayInvalidConfigPropertyError](/api/core/class/MidwayInvalidConfigPropertyError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayInvokeForbiddenError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayInvokeForbiddenError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L198)constructor * **new MidwayInvokeForbiddenError(methodName: string, module? : any): [MidwayInvokeForbiddenError](/api/core/class/MidwayInvokeForbiddenError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayLifeCycleService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**getLifecycleInstanceList](#getLifecycleInstanceList) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/lifeCycleService.ts#L45)constructor * **new MidwayLifeCycleService(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): [MidwayLifeCycleService](/api/core/class/MidwayLifeCycleService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/lifeCycleService.ts#L45)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#getLifecycleInstanceList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/lifeCycleService.ts#L241)publicgetLifecycleInstanceList * **getLifecycleInstanceList(): LifecycleInstanceItem\[] ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/lifeCycleService.ts#L137)publicstop * **stop(): Promise\ --- # MidwayLoggerService 多客户端工厂实现 ### Hierarchy * [ServiceFactory](/api/core/class/ServiceFactory.md)<[ILogger](/api/core/interface/ILogger.md)> * *MidwayLoggerService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**configService](#configService) * [**globalOptions](#globalOptions) ### Methods * [**createContextLogger](#createContextLogger) * [**createInstance](#createInstance) * [**createLogger](#createLogger) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getCurrentLoggerFactory](#getCurrentLoggerFactory) * [**getDefaultClientName](#getDefaultClientName) * [**getLogger](#getLogger) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L29)constructor * **new MidwayLoggerService(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), globalOptions? : {}): [MidwayLoggerService](/api/core/class/MidwayLoggerService.md) - Overrides ServiceFactory.constructor ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L30)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L21)publicconfigService **configService: [MidwayConfigService](/api/core/class/MidwayConfigService.md) ### [**](#globalOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L31)readonlyglobalOptions **globalOptions: {} = {} ## Methods[**](#Methods) ### [**](#createContextLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L113)publiccreateContextLogger * **createContextLogger(ctx: [Context](/api/core/interface/Context.md), appLogger: [ILogger](/api/core/interface/ILogger.md), contextOptions? : any): [ILogger](/api/core/interface/ILogger.md) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L64)publiccreateInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L86)publiccreateLogger * **createLogger(name: string, config: [MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)): any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L56)publicget * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [ILogger](/api/core/interface/ILogger.md) ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L129)publicgetClientKeys * **getClientKeys(): string\[] - Overrides ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L137)publicgetClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L125)publicgetClients * **getClients(): Map\ - Overrides ServiceFactory.getClients ### [**](#getCurrentLoggerFactory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L109)publicgetCurrentLoggerFactory * **getCurrentLoggerFactory(): [LoggerFactory](/api/core/class/LoggerFactory.md)\ ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L125)publicgetDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L91)publicgetLogger * **getLogger(name: string): any ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/loggerService.ts#L82)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L60)publichas * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L141)publicisHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L149)publicisLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L145)publicisMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L118)publicstop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # MidwayMainFrameworkMissingError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayMainFrameworkMissingError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L220)constructor * **new MidwayMainFrameworkMissingError(): [MidwayMainFrameworkMissingError](/api/core/class/MidwayMainFrameworkMissingError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayMiddlewareService \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**compose](#compose) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/middlewareService.ts#L19)constructor * **new MidwayMiddlewareService\(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): [MidwayMiddlewareService](/api/core/class/MidwayMiddlewareService.md)\ - #### Type parameters * **T** * **R** * **N** = unknown ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/middlewareService.ts#L19)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ## Methods[**](#Methods) ### [**](#compose)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/middlewareService.ts#L21)compose * **compose(middleware: (string | [CommonMiddleware](/api/core.md#CommonMiddleware)\)\[], app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, name? : string): Promise<{ \_name: string }> --- # MidwayMissingImportComponentError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayMissingImportComponentError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L143)constructor * **new MidwayMissingImportComponentError(originName: string): [MidwayMissingImportComponentError](/api/core/class/MidwayMissingImportComponentError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayMockService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**prepareMocks](#prepareMocks) ### Methods * [**applyContextMocks](#applyContextMocks) * [**getContextMocksSize](#getContextMocksSize) * [**init](#init) * [**initSimulation](#initSimulation) * [**isMocked](#isMocked) * [**mockClassProperty](#mockClassProperty) * [**mockContext](#mockContext) * [**mockProperty](#mockProperty) * [**restore](#restore) * [**restoreAll](#restoreAll) * [**runSimulatorAppSetup](#runSimulatorAppSetup) * [**runSimulatorAppTearDown](#runSimulatorAppTearDown) * [**runSimulatorContextSetup](#runSimulatorContextSetup) * [**runSimulatorContextTearDown](#runSimulatorContextTearDown) * [**runSimulatorSetup](#runSimulatorSetup) * [**runSimulatorTearDown](#runSimulatorTearDown) * [**mockClassProperty](#mockClassProperty) * [**mockProperty](#mockProperty) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L46)constructor * **new MidwayMockService(applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): [MidwayMockService](/api/core/class/MidwayMockService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L46)readonlyapplicationContext **applicationContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ### [**](#prepareMocks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L61)staticprepareMocks **prepareMocks: any\[] = \[] Prepare mocks before the service is initialized ## Methods[**](#Methods) ### [**](#applyContextMocks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L195)applyContextMocks * **applyContextMocks(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, ctx: [Context](/api/core/interface/Context.md)): void ### [**](#getContextMocksSize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L210)getContextMocksSize * **getContextMocksSize(): number ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L49)init * **init(): Promise\ ### [**](#initSimulation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L236)publicinitSimulation * **initSimulation(group? : string): Promise\ ### [**](#isMocked)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L186)publicisMocked * **isMocked(obj: any, key: any, group? : string): boolean ### [**](#mockClassProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L86)publicmockClassProperty * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void ### [**](#mockContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L133)publicmockContext * **mockContext(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, key: string | (ctx: [Context](/api/core/interface/Context.md)) => void, value? : any, group? : string): void ### [**](#mockProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L95)publicmockProperty * **mockProperty(obj: any, key: string, value: any, group? : string): void ### [**](#restore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L149)publicrestore * **restore(group? : string): void ### [**](#restoreAll)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L154)publicrestoreAll * **restoreAll(): void ### [**](#runSimulatorAppSetup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L263)publicrunSimulatorAppSetup * **runSimulatorAppSetup(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorAppTearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L269)publicrunSimulatorAppTearDown * **runSimulatorAppTearDown(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorContextSetup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L277)publicrunSimulatorContextSetup * **runSimulatorContextSetup(ctx: [Context](/api/core/interface/Context.md), app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorContextTearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L286)publicrunSimulatorContextTearDown * **runSimulatorContextTearDown(ctx: [Context](/api/core/interface/Context.md), app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#runSimulatorSetup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L249)publicrunSimulatorSetup * **runSimulatorSetup(): Promise\ ### [**](#runSimulatorTearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L255)publicrunSimulatorTearDown * **runSimulatorTearDown(): Promise\ ### [**](#mockClassProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L63)staticmockClassProperty * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void ### [**](#mockProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/mockService.ts#L72)staticmockProperty * **mockProperty(obj: new (...args: any\[]) => any, key: string, value: any, group? : string): void --- # MidwayParameterError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayParameterError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L36)constructor * **new MidwayParameterError(message? : string): [MidwayParameterError](/api/core/class/MidwayParameterError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayPerformanceManager ## Index[**](#Index) ### Properties * [**DEFAULT\_GROUP](#DEFAULT_GROUP) ### Methods * [**clean](#clean) * [**disconnect](#disconnect) * [**markEnd](#markEnd) * [**markStart](#markStart) * [**observeMeasure](#observeMeasure) * [**cleanAll](#cleanAll) * [**getInitialPerformanceEntries](#getInitialPerformanceEntries) * [**getInstance](#getInstance) ## Properties[**](#Properties) ### [**](#DEFAULT_GROUP)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L9)publicstaticDEFAULT\_GROUP **DEFAULT\_GROUP: { INITIALIZE: string } = ... ## Methods[**](#Methods) ### [**](#clean)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L76)publicclean * **clean(): void ### [**](#disconnect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L69)publicdisconnect * **disconnect(): void ### [**](#markEnd)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L35)publicmarkEnd * **markEnd(key: string): void ### [**](#markStart)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L29)publicmarkStart * **markStart(key: string): void ### [**](#observeMeasure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L47)publicobserveMeasure * **observeMeasure(callback: (list: PerformanceObserverEntryList) => void): PerformanceObserver ### [**](#cleanAll)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L98)publicstaticcleanAll * **cleanAll(): void ### [**](#getInitialPerformanceEntries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L103)publicstaticgetInitialPerformanceEntries * **getInitialPerformanceEntries(): any\[] ### [**](#getInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/performanceManager.ts#L18)staticgetInstance * **getInstance(group: string): [MidwayPerformanceManager](/api/core/class/MidwayPerformanceManager.md) --- # MidwayPriorityManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getCurrentPriorityList](#getCurrentPriorityList) * [**getDefaultPriority](#getDefaultPriority) * [**getPriority](#getPriority) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayPriorityManager(): [MidwayPriorityManager](/api/core/class/MidwayPriorityManager.md) ## Methods[**](#Methods) ### [**](#getCurrentPriorityList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L16)publicgetCurrentPriorityList * **getCurrentPriorityList(): Record\ ### [**](#getDefaultPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L20)publicgetDefaultPriority * **getDefaultPriority(): string ### [**](#getPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L34)publicgetPriority * **getPriority(priority: string): string ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L24)publicisHighPriority * **isHighPriority(priority? : string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L30)publicisLowPriority * **isLowPriority(priority? : string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/priorityManager.ts#L27)publicisMediumPriority * **isMediumPriority(priority? : string): boolean --- # MidwayRequestContainer Abstract Object Factory 对象容器抽象 ### Implements * [IMidwayRequestContainer](/api/core/interface/IMidwayRequestContainer.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**parent](#parent) * [**registry](#registry) ### Methods * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getContext](#getContext) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L16)constructor * **new MidwayRequestContainer(ctx: any, applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)): [MidwayRequestContainer](/api/core/class/MidwayRequestContainer.md) ## Properties[**](#Properties) ### [**](#parent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L12)publicparent **parent: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) Implementation of IMidwayRequestContainer.parent ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L13)publicregistry **registry: ObjectDefinitionRegistry = ... Implementation of IMidwayRequestContainer.registry ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L38)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any): T - Implementation of IMidwayRequestContainer.get #### Type parameters * **T** = any ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L44)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any): Promise\ - Implementation of IMidwayRequestContainer.getAsync #### Type parameters * **T** = any ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L85)getAttr * **getAttr\(key: string): T - Implementation of IMidwayRequestContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L53)getContext * **getContext(): any - Implementation of IMidwayRequestContainer.getContext ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L61)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Implementation of IMidwayRequestContainer.getDefinition ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L89)getIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)): string - Implementation of IMidwayRequestContainer.getIdentifier Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L93)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Implementation of IMidwayRequestContainer.getInstanceScope Get instance IoC container scope ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L77)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - Implementation of IMidwayRequestContainer.getObject #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L57)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayRequestContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L97)hasNamespace * **hasNamespace(namespace: string): boolean - Implementation of IMidwayRequestContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L73)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Implementation of IMidwayRequestContainer.hasObject ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L65)registerObject * **registerObject(identifier: string, obj: any): void - Implementation of IMidwayRequestContainer.registerObject ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L69)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void - Implementation of IMidwayRequestContainer.removeObject ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/context/requestContainer.ts#L81)setAttr * **setAttr(key: string, value: any): void - Implementation of IMidwayRequestContainer.setAttr Set value to app attribute map --- # MidwayRetryExceededMaxTimesError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayRetryExceededMaxTimesError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L186)constructor * **new MidwayRetryExceededMaxTimesError(methodName: any, times: number, err: Error): [MidwayRetryExceededMaxTimesError](/api/core/class/MidwayRetryExceededMaxTimesError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayServerlessFunctionService ### Hierarchy * [MidwayWebRouterService](/api/core/class/MidwayWebRouterService.md) * *MidwayServerlessFunctionService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**loggerService](#loggerService) * [**options](#options) ### Methods * [**addController](#addController) * [**addRouter](#addRouter) * [**addServerlessFunction](#addServerlessFunction) * [**getFlattenRouterTable](#getFlattenRouterTable) * [**getFunctionList](#getFunctionList) * [**getMatchedRouterInfo](#getMatchedRouterInfo) * [**getRouteManifest](#getRouteManifest) * [**getRoutePriorityList](#getRoutePriorityList) * [**getRouterTable](#getRouterTable) * [**sortRouter](#sortRouter) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/slsFunctionService.ts#L21)constructor * **new MidwayServerlessFunctionService(options? : [RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md)): [MidwayServerlessFunctionService](/api/core/class/MidwayServerlessFunctionService.md) - Overrides MidwayWebRouterService.constructor ## Properties[**](#Properties) ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L201)loggerService **loggerService: [MidwayLoggerService](/api/core/class/MidwayLoggerService.md) Inherited from MidwayWebRouterService.loggerService ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/slsFunctionService.ts#L21)readonlyoptions **options: [RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md) = {} Inherited from MidwayWebRouterService.options ## Methods[**](#Methods) ### [**](#addController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L309)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L314)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L322)publicaddController * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/core/interface/ControllerOption.md), functionMeta? : boolean): any * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/core/interface/ControllerOption.md), resourceOptions? : { resourceFilter: (routerInfo: [RouterInfo](/api/core/interface/RouterInfo.md)) => boolean }, functionMeta? : boolean): any - Inherited from MidwayWebRouterService.addController dynamically add a controller ### [**](#addRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L530)publicaddRouter * **addRouter(routerFunction: (...args: any\[]) => void, routerInfoOption: [DynamicRouterInfo](/api/core.md#DynamicRouterInfo)): void - Inherited from MidwayWebRouterService.addRouter dynamically add a route to root prefix ### [**](#addServerlessFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/slsFunctionService.ts#L189)publicaddServerlessFunction * **addServerlessFunction(func: (...args: any\[]) => Promise\, triggerOptions: [TriggerMetadata](/api/core/namespace/FaaSMetadata.md#TriggerMetadata), functionOptions? : [ServerlessFunctionOptions](/api/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions)): void ### [**](#getFlattenRouterTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L647)publicgetFlattenRouterTable * **getFlattenRouterTable(options? : { compileUrlPattern? : boolean }): Promise<[RouterInfo](/api/core/interface/RouterInfo.md)\[]> - Inherited from MidwayWebRouterService.getFlattenRouterTable ### [**](#getFunctionList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/slsFunctionService.ts#L183)publicgetFunctionList * **getFunctionList(): Promise<[RouterInfo](/api/core/interface/RouterInfo.md)\[]> ### [**](#getMatchedRouterInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L673)publicgetMatchedRouterInfo * **getMatchedRouterInfo(routerUrl: string, method: string): Promise<[RouterInfo](/api/core/interface/RouterInfo.md)> - Inherited from MidwayWebRouterService.getMatchedRouterInfo ### [**](#getRouteManifest)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L697)publicgetRouteManifest * **getRouteManifest(): Promise\ - Inherited from MidwayWebRouterService.getRouteManifest ### [**](#getRoutePriorityList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L631)publicgetRoutePriorityList * **getRoutePriorityList(): Promise<[RouterPriority](/api/core/interface/RouterPriority.md)\[]> - Inherited from MidwayWebRouterService.getRoutePriorityList ### [**](#getRouterTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L639)publicgetRouterTable * **getRouterTable(): Promise\> - Inherited from MidwayWebRouterService.getRouterTable ### [**](#sortRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L562)publicsortRouter * **sortRouter(urlMatchList: [RouterInfo](/api/core/interface/RouterInfo.md)\[]): { \_category: number; \_level: number; \_paramString: string; \_pureRouter: string; \_weight: number; controllerClz? : new (...args: any\[]) => any; controllerId? : string; controllerMiddleware? : any\[]; description? : string; fullUrl? : string; fullUrlCompiledRegexp? : RegExp; fullUrlFlattenString? : string; funcHandlerName? : string; functionMetadata? : any; functionName? : string; functionTriggerMetadata? : any; functionTriggerName? : string; handlerName? : string; id? : string; ignoreGlobalPrefix? : boolean; method: string | (...args: any\[]) => void; middleware? : any\[]; prefix? : string; requestMetadata? : any\[]; requestMethod: string; responseMetadata? : any\[]; routerName? : string; source? : functional | decorator; summary? : string; url: string | RegExp; version? : string | string\[]; versionPrefix? : string; versionType? : URI | HEADER | MEDIA\_TYPE | CUSTOM }\[] - Inherited from MidwayWebRouterService.sortRouter --- # MidwaySingletonInjectRequestError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwaySingletonInjectRequestError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L136)constructor * **new MidwaySingletonInjectRequestError(singletonScopeName: string, requestScopeName: string): [MidwaySingletonInjectRequestError](/api/core/class/MidwaySingletonInjectRequestError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayTraceService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createSpan](#createSpan) * [**getTraceId](#getTraceId) * [**injectContext](#injectContext) * [**resolveTraceMeta](#resolveTraceMeta) * [**runWithEntrySpan](#runWithEntrySpan) * [**runWithExitSpan](#runWithExitSpan) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayTraceService(): [MidwayTraceService](/api/core/class/MidwayTraceService.md) ## Methods[**](#Methods) ### [**](#createSpan)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L101)createSpan * **createSpan(name: string, callback: (span: Span) => unknown): unknown ### [**](#getTraceId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L97)getTraceId * **getTraceId(): string ### [**](#injectContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L401)injectContext * **injectContext(carrier: any, setter? : TextMapSetter\): any ### [**](#resolveTraceMeta)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L193)resolveTraceMeta * **resolveTraceMeta(resolver: [TraceMetaResolver](/api/core.md#TraceMetaResolver), args: [TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md)): [TraceMetaRecord](/api/core.md#TraceMetaRecord) ### [**](#runWithEntrySpan)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L247)runWithEntrySpan * **runWithEntrySpan\(name: string, options: { attributes? : Record\; carrier? : any; enable? : boolean; getter? : TextMapGetter\; kind? : SpanKind; meta? : [TraceMetaResolver](/api/core.md#TraceMetaResolver); metaArgs? : Omit<[TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md), direction | protocol | spanName>; responseCarrier? : any; setter? : TextMapSetter\ }, callback: (span: Span) => T | Promise\): Promise\ - #### Type parameters * **T** = unknown ### [**](#runWithExitSpan)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/traceService.ts#L334)runWithExitSpan * **runWithExitSpan\(name: string, options: { attributes? : Record\; carrier? : any; enable? : boolean; getter? : TextMapGetter\; kind? : SpanKind; meta? : [TraceMetaResolver](/api/core.md#TraceMetaResolver); metaArgs? : Omit<[TraceMetaResolverArgs](/api/core/interface/TraceMetaResolverArgs.md), direction | protocol | spanName>; setter? : TextMapSetter\ }, callback: (span: Span) => T | Promise\): Promise\ - #### Type parameters * **T** = unknown --- # MidwayUseWrongMethodError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayUseWrongMethodError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L123)constructor * **new MidwayUseWrongMethodError(wrongMethod: string, replacedMethod: string, describeKey? : string): [MidwayUseWrongMethodError](/api/core/class/MidwayUseWrongMethodError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayUtilHttpClientTimeoutError ### Hierarchy * [MidwayError](/api/core/class/MidwayError.md) * *MidwayUtilHttpClientTimeoutError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L150)constructor * **new MidwayUtilHttpClientTimeoutError(message: string): [MidwayUtilHttpClientTimeoutError](/api/core/class/MidwayUtilHttpClientTimeoutError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L51)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/base.ts#L50)code **code: string | number Inherited from MidwayError.code --- # MidwayWebRouterService ### Hierarchy * *MidwayWebRouterService* * [MidwayServerlessFunctionService](/api/core/class/MidwayServerlessFunctionService.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**loggerService](#loggerService) * [**options](#options) ### Methods * [**addController](#addController) * [**addRouter](#addRouter) * [**getFlattenRouterTable](#getFlattenRouterTable) * [**getMatchedRouterInfo](#getMatchedRouterInfo) * [**getRouteManifest](#getRouteManifest) * [**getRoutePriorityList](#getRoutePriorityList) * [**getRouterTable](#getRouterTable) * [**sortRouter](#sortRouter) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L203)constructor * **new MidwayWebRouterService(options? : [RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md)): [MidwayWebRouterService](/api/core/class/MidwayWebRouterService.md) ## Properties[**](#Properties) ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L201)loggerService **loggerService: [MidwayLoggerService](/api/core/class/MidwayLoggerService.md) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L203)readonlyoptions **options: [RouterCollectorOptions](/api/core/interface/RouterCollectorOptions.md) = {} ## Methods[**](#Methods) ### [**](#addController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L309)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L314)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L322)publicaddController * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/core/interface/ControllerOption.md), functionMeta? : boolean): any * **addController(controllerClz: any, controllerOption: [ControllerOption](/api/core/interface/ControllerOption.md), resourceOptions? : { resourceFilter: (routerInfo: [RouterInfo](/api/core/interface/RouterInfo.md)) => boolean }, functionMeta? : boolean): any - dynamically add a controller ### [**](#addRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L530)publicaddRouter * **addRouter(routerFunction: (...args: any\[]) => void, routerInfoOption: [DynamicRouterInfo](/api/core.md#DynamicRouterInfo)): void - dynamically add a route to root prefix ### [**](#getFlattenRouterTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L647)publicgetFlattenRouterTable * **getFlattenRouterTable(options? : { compileUrlPattern? : boolean }): Promise<[RouterInfo](/api/core/interface/RouterInfo.md)\[]> ### [**](#getMatchedRouterInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L673)publicgetMatchedRouterInfo * **getMatchedRouterInfo(routerUrl: string, method: string): Promise<[RouterInfo](/api/core/interface/RouterInfo.md)> ### [**](#getRouteManifest)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L697)publicgetRouteManifest * **getRouteManifest(): Promise\ ### [**](#getRoutePriorityList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L631)publicgetRoutePriorityList * **getRoutePriorityList(): Promise<[RouterPriority](/api/core/interface/RouterPriority.md)\[]> ### [**](#getRouterTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L639)publicgetRouterTable * **getRouterTable(): Promise\> ### [**](#sortRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L562)publicsortRouter * **sortRouter(urlMatchList: [RouterInfo](/api/core/interface/RouterInfo.md)\[]): { \_category: number; \_level: number; \_paramString: string; \_pureRouter: string; \_weight: number; controllerClz? : new (...args: any\[]) => any; controllerId? : string; controllerMiddleware? : any\[]; description? : string; fullUrl? : string; fullUrlCompiledRegexp? : RegExp; fullUrlFlattenString? : string; funcHandlerName? : string; functionMetadata? : any; functionName? : string; functionTriggerMetadata? : any; functionTriggerName? : string; handlerName? : string; id? : string; ignoreGlobalPrefix? : boolean; method: string | (...args: any\[]) => void; middleware? : any\[]; prefix? : string; requestMetadata? : any\[]; requestMethod: string; responseMetadata? : any\[]; routerName? : string; source? : functional | decorator; summary? : string; url: string | RegExp; version? : string | string\[]; versionPrefix? : string; versionType? : URI | HEADER | MEDIA\_TYPE | CUSTOM }\[] --- # RandomLoadBalance \ 随机负载均衡策略 ### Implements * [ILoadBalancer](/api/core/interface/ILoadBalancer.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**select](#select) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RandomLoadBalance\(): [RandomLoadBalance](/api/core/class/RandomLoadBalance.md)\ - #### Type parameters * **ServiceInstance** ## Methods[**](#Methods) ### [**](#select)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/loadBalancer.ts#L9)select * **select(instances: ServiceInstance\[]): ServiceInstance - Implementation of ILoadBalancer.select 从服务实例列表中选择一个实例 --- # RoundRobinLoadBalancer \ 轮询负载均衡策略 ### Implements * [ILoadBalancer](/api/core/interface/ILoadBalancer.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**select](#select) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RoundRobinLoadBalancer\(): [RoundRobinLoadBalancer](/api/core/class/RoundRobinLoadBalancer.md)\ - #### Type parameters * **ServiceInstance** ## Methods[**](#Methods) ### [**](#select)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/loadBalancer.ts#L26)select * **select(instances: ServiceInstance\[]): ServiceInstance - Implementation of ILoadBalancer.select 从服务实例列表中选择一个实例 --- # ServerResponse \ ### Hierarchy * *ServerResponse* * [HttpServerResponse](/api/core/class/HttpServerResponse.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**blob](#blob) * [**fail](#fail) * [**json](#json) * [**success](#success) * [**text](#text) * [**BLOB\_TPL](#BLOB_TPL) * [**JSON\_TPL](#JSON_TPL) * [**TEXT\_TPL](#TEXT_TPL) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L7)constructor * **new ServerResponse\(ctx: CTX): [ServerResponse](/api/core/class/ServerResponse.md)\ - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) = [Context](/api/core/interface/Context.md) ## Methods[**](#Methods) ### [**](#blob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L61)blob * **blob(data: Buffer): any ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L74)fail * **fail(): [ServerResponse](/api/core/class/ServerResponse.md)\ ### [**](#json)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L45)json * **json(data: Record\): any ### [**](#success)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L69)success * **success(): [ServerResponse](/api/core/class/ServerResponse.md)\ ### [**](#text)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L53)text * **text(data: string): any ### [**](#BLOB_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L37)staticBLOB\_TPL * **BLOB\_TPL\(data: Buffer, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#JSON_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L19)staticJSON\_TPL * **JSON\_TPL\(data: Record\, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) ### [**](#TEXT_TPL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/response/base.ts#L11)staticTEXT\_TPL * **TEXT\_TPL\(data: string, isSuccess: boolean, ctx: CTX): unknown - #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) --- # abstractServiceDiscovery \ 服务发现抽象类 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createClient](#createClient) * [**getInstance](#getInstance) * [**getInstances](#getInstances) * [**setLoadBalancer](#setLoadBalancer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ServiceDiscovery\(): [ServiceDiscovery](/api/core/class/ServiceDiscovery.md)\ - #### Type parameters * **Client** * **ServiceDiscoveryConfigOptions**: [ServiceDiscoveryOptions](/api/core/interface/ServiceDiscoveryOptions.md)\> * **RegisterServiceInstance** * **QueryServiceInstance** = RegisterServiceInstance * **GetInstanceOptions** = RegisterServiceInstance ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L112)publiccreateClient * **createClient(options? : [ServiceDiscoveryOptions](/api/core/interface/ServiceDiscoveryOptions.md)\>): [ServiceDiscoveryClient](/api/core/class/ServiceDiscoveryClient.md)\ ### [**](#getInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L154)publicgetInstance * **getInstance(options: GetInstanceOptions): Promise\ - 获取一个可用服务实例(带负载均衡) ### [**](#getInstances)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L147)publicabstractgetInstances * **getInstances(options: GetInstanceOptions): Promise\ - 获取可用服务列表 ### [**](#setLoadBalancer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L170)publicsetLoadBalancer * **setLoadBalancer(type: [LoadBalancerType](/api/core.md#LoadBalancerType) | [ILoadBalancer](/api/core/interface/ILoadBalancer.md)\): void - 设置负载均衡策略 --- # abstractServiceDiscoveryClient \ ### Implements * [IServiceDiscoveryClient](/api/core/interface/IServiceDiscoveryClient.md)\ ## Index[**](#Index) ### Accessors * [**defaultMeta](#defaultMeta) ### Methods * [**beforeStop](#beforeStop) * [**deregister](#deregister) * [**getSelfInstance](#getSelfInstance) * [**offline](#offline) * [**online](#online) * [**register](#register) * [**stop](#stop) ## Accessors[**](#Accessors) ### [**](#defaultMeta)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L34)defaultMeta * **get defaultMeta(): [DefaultInstanceMetadata](/api/core/interface/DefaultInstanceMetadata.md) ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L55)abstractbeforeStop * **beforeStop(): Promise\ ### [**](#deregister)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L75)abstractderegister * **deregister(): Promise\ - 注销服务实例 ### [**](#getSelfInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L51)publicgetSelfInstance * **getSelfInstance(): RegisterServiceInstance ### [**](#offline)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L85)abstractoffline * **offline(): Promise\ - Implementation of IServiceDiscoveryClient.offline 下线服务实例 ### [**](#online)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L80)abstractonline * **online(): Promise\ - Implementation of IServiceDiscoveryClient.online 上线服务实例 ### [**](#register)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L70)abstractregister * **register(instance: RegisterServiceInstance): Promise\ - Implementation of IServiceDiscoveryClient.register 注册服务实例 ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.ts#L60)stop * **stop(): Promise\ - 停止服务发现 --- # abstractServiceFactory \ 多客户端工厂实现 ### Hierarchy * *ServiceFactory* * [MidwayLoggerService](/api/core/class/MidwayLoggerService.md) ### Implements * [IServiceFactory](/api/core/interface/IServiceFactory.md)\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ServiceFactory\(): [ServiceFactory](/api/core/class/ServiceFactory.md)\ - #### Type parameters * **T** ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L64)publiccreateInstance * **createInstance(config: any, clientName? : string): Promise\ - Implementation of IServiceFactory.createInstance ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L56)publicget * **get\(id? : string): U - Implementation of IServiceFactory.get #### Type parameters * **U** = T ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L133)publicgetClientKeys * **getClientKeys(): string\[] - Implementation of IServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L137)publicgetClientPriority * **getClientPriority(name: string): string - Implementation of IServiceFactory.getClientPriority ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L129)publicgetClients * **getClients(): Map\ - Implementation of IServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L125)publicgetDefaultClientName * **getDefaultClientName(): string - Implementation of IServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L108)publicabstractgetName * **getName(): string - Implementation of IServiceFactory.getName ### [**](#has)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L60)publichas * **has(id: string): boolean - Implementation of IServiceFactory.has ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L141)publicisHighPriority * **isHighPriority(name: string): boolean - Implementation of IServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L149)publicisLowPriority * **isLowPriority(name: string): boolean - Implementation of IServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L145)publicisMediumPriority * **isMediumPriority(name: string): boolean - Implementation of IServiceFactory.isMediumPriority ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.ts#L118)publicstop * **stop(): Promise\ - Implementation of IServiceFactory.stop --- # TypedResourceManager \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createResource](#createResource) * [**destroy](#destroy) * [**destroyParallel](#destroyParallel) * [**getResource](#getResource) * [**init](#init) * [**start](#start) * [**startParallel](#startParallel) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L10)constructor * **new TypedResourceManager\(typedResourceInitializerOptions: { initializeClzProvider: {}; initializeValue: {}; resourceBinding: (ClzProvider: [ClassType](/api/core.md#ClassType)\, resourceInitializeConfig: ResourceInitializeConfig, resource: Resource, resourceName: string) => Promise\; resourceDestroy: (resource: Resource, resourceInitializeConfig: ResourceInitializeConfig) => Promise\; resourceInitialize: (resourceInitializeConfig: ResourceInitializeConfig, resourceName: string) => Promise\; resourceStart: (resource: Resource, resourceInitializeConfig: ResourceInitializeConfig, resourceBindingResult? : any) => Promise\ }): [TypedResourceManager](/api/core/class/TypedResourceManager.md)\ - #### Type parameters * **Resource** = any * **ResourceInitializeConfig** = any * **ResourceProviderType** = any ## Methods[**](#Methods) ### [**](#createResource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L40)publiccreateResource * **createResource(resourceName: string, resourceInitializeConfig: ResourceInitializeConfig): Promise\ ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L119)publicdestroy * **destroy(): Promise\ ### [**](#destroyParallel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L106)publicdestroyParallel * **destroyParallel(): Promise\ ### [**](#getResource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L130)publicgetResource * **getResource(resourceName: string): any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L53)publicinit * **init(): Promise\ ### [**](#start)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L96)publicstart * **start(): Promise\ ### [**](#startParallel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/typedResourceManager.ts#L82)publicstartParallel * **startParallel(): Promise\ --- # abstractWebControllerGenerator \ ## Index[**](#Index) ### Properties * [**app](#app) * [**midwayWebRouterService](#midwayWebRouterService) ### Methods * [**createRouter](#createRouter) * [**generateController](#generateController) * [**generateKoaController](#generateKoaController) * [**loadMidwayController](#loadMidwayController) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L28)readonlyapp **app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)> ### [**](#midwayWebRouterService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L29)readonlymidwayWebRouterService **midwayWebRouterService: [MidwayWebRouterService](/api/core/class/MidwayWebRouterService.md) ## Methods[**](#Methods) ### [**](#createRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L190)abstractcreateRouter * **createRouter(routerOptions: any): Router ### [**](#generateController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L191)abstractgenerateController * **generateController(routeInfo: [RouterInfo](/api/core/interface/RouterInfo.md)): any ### [**](#generateKoaController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L36)publicgenerateKoaController * **generateKoaController(routeInfo: [RouterInfo](/api/core/interface/RouterInfo.md)): (ctx: any, next: any) => Promise\ - wrap controller string to middleware function ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/webGenerator.ts#L98)publicloadMidwayController * **loadMidwayController(routerHandler? : (newRouter: Router) => void): Promise\ --- # GrpcStreamTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BASE](#BASE) * [**DUPLEX](#DUPLEX) * [**READABLE](#READABLE) * [**WRITEABLE](#WRITEABLE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BASE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.ts#L40)BASE **BASE: base ### [**](#DUPLEX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.ts#L41)DUPLEX **DUPLEX: ServerDuplexStream ### [**](#READABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.ts#L42)READABLE **READABLE: ServerReadableStream ### [**](#WRITEABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/provider.ts#L43)WRITEABLE **WRITEABLE: ServerWritableStream --- # HttpStatus ## Index[**](#Index) ### Enumeration Members * [**ACCEPTED](#ACCEPTED) * [**AMBIGUOUS](#AMBIGUOUS) * [**BAD\_GATEWAY](#BAD_GATEWAY) * [**BAD\_REQUEST](#BAD_REQUEST) * [**CONFLICT](#CONFLICT) * [**CONTINUE](#CONTINUE) * [**CREATED](#CREATED) * [**EARLYHINTS](#EARLYHINTS) * [**EXPECTATION\_FAILED](#EXPECTATION_FAILED) * [**FAILED\_DEPENDENCY](#FAILED_DEPENDENCY) * [**FORBIDDEN](#FORBIDDEN) * [**FOUND](#FOUND) * [**GATEWAY\_TIMEOUT](#GATEWAY_TIMEOUT) * [**GONE](#GONE) * [**HTTP\_VERSION\_NOT\_SUPPORTED](#HTTP_VERSION_NOT_SUPPORTED) * [**INTERNAL\_SERVER\_ERROR](#INTERNAL_SERVER_ERROR) * [**I\_AM\_A\_TEAPOT](#I_AM_A_TEAPOT) * [**LENGTH\_REQUIRED](#LENGTH_REQUIRED) * [**METHOD\_NOT\_ALLOWED](#METHOD_NOT_ALLOWED) * [**MISDIRECTED](#MISDIRECTED) * [**MOVED\_PERMANENTLY](#MOVED_PERMANENTLY) * [**NON\_AUTHORITATIVE\_INFORMATION](#NON_AUTHORITATIVE_INFORMATION) * [**NOT\_ACCEPTABLE](#NOT_ACCEPTABLE) * [**NOT\_FOUND](#NOT_FOUND) * [**NOT\_IMPLEMENTED](#NOT_IMPLEMENTED) * [**NOT\_MODIFIED](#NOT_MODIFIED) * [**NO\_CONTENT](#NO_CONTENT) * [**OK](#OK) * [**PARTIAL\_CONTENT](#PARTIAL_CONTENT) * [**PAYLOAD\_TOO\_LARGE](#PAYLOAD_TOO_LARGE) * [**PAYMENT\_REQUIRED](#PAYMENT_REQUIRED) * [**PERMANENT\_REDIRECT](#PERMANENT_REDIRECT) * [**PRECONDITION\_FAILED](#PRECONDITION_FAILED) * [**PRECONDITION\_REQUIRED](#PRECONDITION_REQUIRED) * [**PROCESSING](#PROCESSING) * [**PROXY\_AUTHENTICATION\_REQUIRED](#PROXY_AUTHENTICATION_REQUIRED) * [**REQUESTED\_RANGE\_NOT\_SATISFIABLE](#REQUESTED_RANGE_NOT_SATISFIABLE) * [**REQUEST\_TIMEOUT](#REQUEST_TIMEOUT) * [**RESET\_CONTENT](#RESET_CONTENT) * [**SEE\_OTHER](#SEE_OTHER) * [**SERVICE\_UNAVAILABLE](#SERVICE_UNAVAILABLE) * [**SWITCHING\_PROTOCOLS](#SWITCHING_PROTOCOLS) * [**TEMPORARY\_REDIRECT](#TEMPORARY_REDIRECT) * [**TOO\_MANY\_REQUESTS](#TOO_MANY_REQUESTS) * [**UNAUTHORIZED](#UNAUTHORIZED) * [**UNPROCESSABLE\_ENTITY](#UNPROCESSABLE_ENTITY) * [**UNSUPPORTED\_MEDIA\_TYPE](#UNSUPPORTED_MEDIA_TYPE) * [**URI\_TOO\_LONG](#URI_TOO_LONG) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#ACCEPTED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L10)ACCEPTED **ACCEPTED: 202 ### [**](#AMBIGUOUS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L15)AMBIGUOUS **AMBIGUOUS: 300 ### [**](#BAD_GATEWAY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L48)BAD\_GATEWAY **BAD\_GATEWAY: 502 ### [**](#BAD_REQUEST)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L22)BAD\_REQUEST **BAD\_REQUEST: 400 ### [**](#CONFLICT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L31)CONFLICT **CONFLICT: 409 ### [**](#CONTINUE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L4)CONTINUE **CONTINUE: 100 ### [**](#CREATED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L9)CREATED **CREATED: 201 ### [**](#EARLYHINTS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L7)EARLYHINTS **EARLYHINTS: 103 ### [**](#EXPECTATION_FAILED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L39)EXPECTATION\_FAILED **EXPECTATION\_FAILED: 417 ### [**](#FAILED_DEPENDENCY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L43)FAILED\_DEPENDENCY **FAILED\_DEPENDENCY: 424 ### [**](#FORBIDDEN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L25)FORBIDDEN **FORBIDDEN: 403 ### [**](#FOUND)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L17)FOUND **FOUND: 302 ### [**](#GATEWAY_TIMEOUT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L50)GATEWAY\_TIMEOUT **GATEWAY\_TIMEOUT: 504 ### [**](#GONE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L32)GONE **GONE: 410 ### [**](#HTTP_VERSION_NOT_SUPPORTED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L51)HTTP\_VERSION\_NOT\_SUPPORTED **HTTP\_VERSION\_NOT\_SUPPORTED: 505 ### [**](#INTERNAL_SERVER_ERROR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L46)INTERNAL\_SERVER\_ERROR **INTERNAL\_SERVER\_ERROR: 500 ### [**](#I_AM_A_TEAPOT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L40)I\_AM\_A\_TEAPOT **I\_AM\_A\_TEAPOT: 418 ### [**](#LENGTH_REQUIRED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L33)LENGTH\_REQUIRED **LENGTH\_REQUIRED: 411 ### [**](#METHOD_NOT_ALLOWED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L27)METHOD\_NOT\_ALLOWED **METHOD\_NOT\_ALLOWED: 405 ### [**](#MISDIRECTED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L41)MISDIRECTED **MISDIRECTED: 421 ### [**](#MOVED_PERMANENTLY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L16)MOVED\_PERMANENTLY **MOVED\_PERMANENTLY: 301 ### [**](#NON_AUTHORITATIVE_INFORMATION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L11)NON\_AUTHORITATIVE\_INFORMATION **NON\_AUTHORITATIVE\_INFORMATION: 203 ### [**](#NOT_ACCEPTABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L28)NOT\_ACCEPTABLE **NOT\_ACCEPTABLE: 406 ### [**](#NOT_FOUND)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L26)NOT\_FOUND **NOT\_FOUND: 404 ### [**](#NOT_IMPLEMENTED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L47)NOT\_IMPLEMENTED **NOT\_IMPLEMENTED: 501 ### [**](#NOT_MODIFIED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L19)NOT\_MODIFIED **NOT\_MODIFIED: 304 ### [**](#NO_CONTENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L12)NO\_CONTENT **NO\_CONTENT: 204 ### [**](#OK)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L8)OK **OK: 200 ### [**](#PARTIAL_CONTENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L14)PARTIAL\_CONTENT **PARTIAL\_CONTENT: 206 ### [**](#PAYLOAD_TOO_LARGE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L35)PAYLOAD\_TOO\_LARGE **PAYLOAD\_TOO\_LARGE: 413 ### [**](#PAYMENT_REQUIRED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L24)PAYMENT\_REQUIRED **PAYMENT\_REQUIRED: 402 ### [**](#PERMANENT_REDIRECT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L21)PERMANENT\_REDIRECT **PERMANENT\_REDIRECT: 308 ### [**](#PRECONDITION_FAILED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L34)PRECONDITION\_FAILED **PRECONDITION\_FAILED: 412 ### [**](#PRECONDITION_REQUIRED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L44)PRECONDITION\_REQUIRED **PRECONDITION\_REQUIRED: 428 ### [**](#PROCESSING)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L6)PROCESSING **PROCESSING: 102 ### [**](#PROXY_AUTHENTICATION_REQUIRED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L29)PROXY\_AUTHENTICATION\_REQUIRED **PROXY\_AUTHENTICATION\_REQUIRED: 407 ### [**](#REQUESTED_RANGE_NOT_SATISFIABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L38)REQUESTED\_RANGE\_NOT\_SATISFIABLE **REQUESTED\_RANGE\_NOT\_SATISFIABLE: 416 ### [**](#REQUEST_TIMEOUT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L30)REQUEST\_TIMEOUT **REQUEST\_TIMEOUT: 408 ### [**](#RESET_CONTENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L13)RESET\_CONTENT **RESET\_CONTENT: 205 ### [**](#SEE_OTHER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L18)SEE\_OTHER **SEE\_OTHER: 303 ### [**](#SERVICE_UNAVAILABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L49)SERVICE\_UNAVAILABLE **SERVICE\_UNAVAILABLE: 503 ### [**](#SWITCHING_PROTOCOLS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L5)SWITCHING\_PROTOCOLS **SWITCHING\_PROTOCOLS: 101 ### [**](#TEMPORARY_REDIRECT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L20)TEMPORARY\_REDIRECT **TEMPORARY\_REDIRECT: 307 ### [**](#TOO_MANY_REQUESTS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L45)TOO\_MANY\_REQUESTS **TOO\_MANY\_REQUESTS: 429 ### [**](#UNAUTHORIZED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L23)UNAUTHORIZED **UNAUTHORIZED: 401 ### [**](#UNPROCESSABLE_ENTITY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L42)UNPROCESSABLE\_ENTITY **UNPROCESSABLE\_ENTITY: 422 ### [**](#UNSUPPORTED_MEDIA_TYPE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L37)UNSUPPORTED\_MEDIA\_TYPE **UNSUPPORTED\_MEDIA\_TYPE: 415 ### [**](#URI_TOO_LONG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/http.ts#L36)URI\_TOO\_LONG **URI\_TOO\_LONG: 414 --- # InjectModeEnum ## Index[**](#Index) ### Enumeration Members * [**Class](#Class) * [**Identifier](#Identifier) * [**SelfName](#SelfName) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Class)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L65)Class **Class: Class ### [**](#Identifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L64)Identifier **Identifier: Identifier ### [**](#SelfName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L66)SelfName **SelfName: SelfName --- # MidwayProcessTypeEnum ## Index[**](#Index) ### Enumeration Members * [**AGENT](#AGENT) * [**APPLICATION](#APPLICATION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AGENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L833)AGENT **AGENT: AGENT ### [**](#APPLICATION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L832)APPLICATION **APPLICATION: APPLICATION --- # MSListenerType ## Index[**](#Index) ### Enumeration Members * [**KAFKA](#KAFKA) * [**MQTT](#MQTT) * [**RABBITMQ](#RABBITMQ) * [**REDIS](#REDIS) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#KAFKA)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L124)KAFKA **KAFKA: kafka ### [**](#MQTT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L123)MQTT **MQTT: mqtt ### [**](#RABBITMQ)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L122)RABBITMQ **RABBITMQ: rabbitmq ### [**](#REDIS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L125)REDIS **REDIS: redis --- # MSProviderType ## Index[**](#Index) ### Enumeration Members * [**DUBBO](#DUBBO) * [**GRPC](#GRPC) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DUBBO)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L117)DUBBO **DUBBO: dubbo ### [**](#GRPC)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L118)GRPC **GRPC: gRPC --- # ObjectLifeCycleEvent ## Index[**](#Index) ### Enumeration Members * [**AFTER\_CREATED](#AFTER_CREATED) * [**AFTER\_INIT](#AFTER_INIT) * [**BEFORE\_BIND](#BEFORE_BIND) * [**BEFORE\_CREATED](#BEFORE_CREATED) * [**BEFORE\_DESTROY](#BEFORE_DESTROY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AFTER_CREATED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L595)AFTER\_CREATED **AFTER\_CREATED: afterObjectCreated ### [**](#AFTER_INIT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L596)AFTER\_INIT **AFTER\_INIT: afterObjectInit ### [**](#BEFORE_BIND)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L593)BEFORE\_BIND **BEFORE\_BIND: beforeBind ### [**](#BEFORE_CREATED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L594)BEFORE\_CREATED **BEFORE\_CREATED: beforeObjectCreated ### [**](#BEFORE_DESTROY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L597)BEFORE\_DESTROY **BEFORE\_DESTROY: beforeObjectDestroy --- # RouteParamTypes ## Index[**](#Index) ### Enumeration Members * [**BODY](#BODY) * [**CUSTOM](#CUSTOM) * [**FIELDS](#FIELDS) * [**FILESSTREAM](#FILESSTREAM) * [**FILESTREAM](#FILESTREAM) * [**HEADERS](#HEADERS) * [**NEXT](#NEXT) * [**PARAM](#PARAM) * [**QUERIES](#QUERIES) * [**QUERY](#QUERY) * [**REQUEST\_IP](#REQUEST_IP) * [**REQUEST\_PATH](#REQUEST_PATH) * [**SESSION](#SESSION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BODY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L10)BODY **BODY: body ### [**](#CUSTOM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L21)CUSTOM **CUSTOM: custom ### [**](#FIELDS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L20)FIELDS **FIELDS: fields ### [**](#FILESSTREAM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L15)FILESSTREAM **FILESSTREAM: files\_stream ### [**](#FILESTREAM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L14)FILESTREAM **FILESTREAM: file\_stream ### [**](#HEADERS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L12)HEADERS **HEADERS: headers ### [**](#NEXT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L16)NEXT **NEXT: next ### [**](#PARAM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L11)PARAM **PARAM: param ### [**](#QUERIES)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L19)QUERIES **QUERIES: queries ### [**](#QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L9)QUERY **QUERY: query ### [**](#REQUEST_IP)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L18)REQUEST\_IP **REQUEST\_IP: request\_ip ### [**](#REQUEST_PATH)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L17)REQUEST\_PATH **REQUEST\_PATH: request\_path ### [**](#SESSION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L13)SESSION **SESSION: session --- # ScopeEnum ## Index[**](#Index) ### Enumeration Members * [**Prototype](#Prototype) * [**Request](#Request) * [**Singleton](#Singleton) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#Prototype)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L60)Prototype **Prototype: Prototype ### [**](#Request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L59)Request **Request: Request ### [**](#Singleton)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L58)Singleton **Singleton: Singleton --- # ServerlessTriggerType ## Index[**](#Index) ### Enumeration Members * [**API\_GATEWAY](#API_GATEWAY) * [**CDN](#CDN) * [**EVENT](#EVENT) * [**HSF](#HSF) * [**HTTP](#HTTP) * [**KAFKA](#KAFKA) * [**LOG](#LOG) * [**MQ](#MQ) * [**MTOP](#MTOP) * [**OS](#OS) * [**SSR](#SSR) * [**TIMER](#TIMER) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#API_GATEWAY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L298)API\_GATEWAY **API\_GATEWAY: apigw ### [**](#CDN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L300)CDN **CDN: cdn ### [**](#EVENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L296)EVENT **EVENT: event ### [**](#HSF)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L305)HSF **HSF: hsf ### [**](#HTTP)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L297)HTTP **HTTP: http ### [**](#KAFKA)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L304)KAFKA **KAFKA: kafka ### [**](#LOG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L301)LOG **LOG: log ### [**](#MQ)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L303)MQ **MQ: mq ### [**](#MTOP)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L306)MTOP **MTOP: mtop ### [**](#OS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L299)OS **OS: os ### [**](#SSR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L307)SSR **SSR: ssr ### [**](#TIMER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L302)TIMER **TIMER: timer --- # WSEventTypeEnum ## Index[**](#Index) ### Enumeration Members * [**BROADCAST](#BROADCAST) * [**EMIT](#EMIT) * [**ON\_CONNECTION](#ON_CONNECTION) * [**ON\_DISCONNECTION](#ON_DISCONNECTION) * [**ON\_MESSAGE](#ON_MESSAGE) * [**ON\_SOCKET\_ERROR](#ON_SOCKET_ERROR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BROADCAST)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L11)BROADCAST **BROADCAST: ws:broadcast ### [**](#EMIT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L10)EMIT **EMIT: ws:Emit ### [**](#ON_CONNECTION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L6)ON\_CONNECTION **ON\_CONNECTION: ws:onConnection ### [**](#ON_DISCONNECTION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L7)ON\_DISCONNECTION **ON\_DISCONNECTION: ws:onDisconnection ### [**](#ON_MESSAGE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L8)ON\_MESSAGE **ON\_MESSAGE: ws:onMessage ### [**](#ON_SOCKET_ERROR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L9)ON\_SOCKET\_ERROR **ON\_SOCKET\_ERROR: ws:onSocketError --- # All ### Callable * **All(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes all HTTP requests to the specified path. --- # AllConfig ### Callable * **AllConfig(): PropertyDecorator *** * Config decorator, use to get all config * **@since** 4.0.0 --- # App ### Callable * **App(): PropertyDecorator * **App(namespace: string): PropertyDecorator *** * * **@deprecated** Use @MainApp() instead --- # ApplicationContext ### Callable * **ApplicationContext(): PropertyDecorator *** * ApplicationContext decorator, use to get global IoC container instance * **@since** 3.0.0 --- # Aspect ### Callable * **Aspect(aspectTarget: any, match? : string | () => boolean, priority? : number): (target: any) => void --- # attachClassMetadata ### Callable * **attachClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, groupBy? : string): void *** * attach data to class * **@since** 2.3.0 * **@deprecated** Use MetadataManager.attachMetadata instead --- # attachPropertyDataToClass ### Callable * **attachPropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * attach property data to class * **@since** 2.3.0 * **@deprecated** --- # attachPropertyMetadata ### Callable * **attachPropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * attach property data * **@since** 2.3.0 * **@deprecated** --- # Autoload ### Callable * **Autoload(): (target: any) => void --- # Body ### Callable * **Body(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Catch ### Callable * **Catch(catchTarget? : any, options? : { matchPrototype? : boolean }): (target: any) => void --- # clearAllModule ### Callable * **clearAllModule(): void *** * clear all module * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.clearAllModule instead --- # Config ### Callable * **Config(): PropertyDecorator * **Config(identifier: string): PropertyDecorator *** * * **@deprecated** Use @AllConfig() instead * **@since** 2.0.0 --- # Configuration ### Callable * **Configuration(options? : [InjectionConfigurationOptions](/api/core/interface/InjectionConfigurationOptions.md)): ClassDecorator --- # Consumer ### Callable * **Consumer(type: MQTT): ClassDecorator * **Consumer(type: RABBITMQ, options? : any): ClassDecorator * **Consumer(type: KAFKA, options? : any): ClassDecorator --- # ContentType ### Callable * **ContentType(contentType: string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Controller ### Callable * **Controller(prefix? : string, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string; version? : string | string\[]; versionPrefix? : string; versionType? : URI | HEADER | MEDIA\_TYPE | CUSTOM }): ClassDecorator --- # createCustomMethodDecorator ### Callable * **createCustomMethodDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [MethodDecoratorOptions](/api/core/interface/MethodDecoratorOptions.md)): MethodDecorator *** * Create a custom method decorator * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.createCustomMethodDecorator instead --- # createCustomParamDecorator ### Callable * **createCustomParamDecorator(decoratorKey: string, metadata: any, implOrOptions? : boolean | [ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md)): ParameterDecorator *** * Create a custom param decorator * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.createCustomParamDecorator instead --- # createCustomPropertyDecorator ### Callable * **createCustomPropertyDecorator(decoratorKey: string, metadata: any, impl? : boolean): PropertyDecorator *** * Create a custom property inject * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.createCustomPropertyDecorator instead --- # createMiddleware ### Callable * **createMiddleware\(middleware: M, options: MiddlewareResolveOptions\, name? : string): [CompositionMiddleware](/api/core.md#CompositionMiddleware)\ *** * wrap a middleware with options and composition a new middleware *** #### Type parameters * **CTX**: [Context](/api/core/interface/Context.md) * **R** * **N** * **M**: [ClassMiddleware](/api/core.md#ClassMiddleware)\ --- # createRender ### Callable * **createRender(RenderEngine: { render: () => string; renderString: () => string }): (templateName: string) => (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # createRequestParamDecorator ### Callable * **createRequestParamDecorator(transform: [CustomParamDecorator](/api/core.md#CustomParamDecorator)\, pipesOrOptions? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[] | [ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md)): ParameterDecorator --- # Del ### Callable * **Del(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP DELETE requests to the specified path. --- # delegateTargetAllPrototypeMethod ### Callable * **delegateTargetAllPrototypeMethod(derivedCtor: any, constructor: any): void *** * 代理目标所有的原型方法,包括原型链,不包括构造器和内部隐藏方法 * **@since** 3.0.0 --- # delegateTargetMethod ### Callable * **delegateTargetMethod(derivedCtor: any, methods: string\[]): void *** * 代理目标原型上的特定方法 * **@since** 2.0.0 --- # delegateTargetProperties ### Callable * **delegateTargetProperties(derivedCtor: any, properties: string\[]): void *** * 代理目标原型属性 * **@since** 2.0.0 --- # delegateTargetPrototypeMethod ### Callable * **delegateTargetPrototypeMethod(derivedCtor: any, constructors: any\[], otherMethods? : string\[]): void *** * 代理目标所有的原型方法,不包括构造器和内部隐藏方法 * **@since** 2.0.0 --- # deprecatedOutput ### Callable * **deprecatedOutput(message: string): void *** * * **@since** 3.0.0 --- # Destroy ### Callable * **Destroy(): MethodDecorator --- # destroyGlobalApplicationContext ### Callable * **destroyGlobalApplicationContext(applicationContext: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)): Promise\ --- # DubboMethod ### Callable * **DubboMethod(methodName? : string): MethodDecorator --- # Emit ### Callable * **Emit(messageName: string, roomName? : string | string\[]): MethodDecorator *** * * **@deprecated** please use * **@WSEmit** --- # extend ### Callable * **extend(...args: any\[]): any --- # extractExpressLikeValue ### Callable * **extractExpressLikeValue(key: any, data: any, paramType? : any): (req: any, res: any, next: any) => any --- # extractKoaLikeValue ### Callable * **extractKoaLikeValue(key: any, data: any, paramType? : any): (ctx: any, next: any) => any --- # Fields ### Callable * **Fields(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # File ### Callable * **File(propertyOrPipes? : any, pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Files ### Callable * **Files(propertyOrPipes? : any, pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Framework ### Callable * **Framework(): ClassDecorator *** * Framework decorator, use to define the framework module * **@since** 2.0.0 --- # Get ### Callable * **Get(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP GET requests to the specified path. --- # getClassExtendedMetadata ### Callable * **getClassExtendedMetadata\(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any, propertyName? : string, useCache? : boolean): T *** * get data from class and proto * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getMetadata instead *** #### Type parameters * **T** = any --- # getClassMetadata ### Callable * **getClassMetadata\(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): T *** * get data from class * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getOwnMetadata instead *** #### Type parameters * **T** = any --- # getCurrentApplicationContext ### Callable * **getCurrentApplicationContext(): [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) --- # getCurrentAsyncContextManager ### Callable * **getCurrentAsyncContextManager(): [AsyncContextManager](/api/core/interface/AsyncContextManager.md) --- # getCurrentMainApp ### Callable * **getCurrentMainApp\(): APP *** * #### Type parameters * **APP**: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)> --- # getCurrentMainFramework ### Callable * **getCurrentMainFramework\(): [IMidwayFramework](/api/core/interface/IMidwayFramework.md)\ *** * #### Type parameters * **APP**: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)\ * **CTX**: [Context](/api/core/interface/Context.md) * **CONFIG**: [IConfigurationOptions](/api/core/interface/IConfigurationOptions.md) --- # getMethodParamTypes ### Callable * **getMethodParamTypes(target: any, methodName: string | symbol): any *** * get parameters type by reflect-metadata * **@since** 3.0.0 * **@deprecated** Use MetadataManager.getMethodParamTypes instead --- # getObjectDefinition ### Callable * **getObjectDefinition(target: any): [ObjectDefinitionOptions](/api/core/interface/ObjectDefinitionOptions.md) *** * get class object definition from metadata * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getPropertiesWithMetadata instead --- # getPropertyDataFromClass ### Callable * **getPropertyDataFromClass\(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data from class * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getOwnMetadata instead *** #### Type parameters * **T** = any --- # getPropertyInject ### Callable * **getPropertyInject(target: any, useCache? : boolean): {} *** * get property inject args * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getMetadata instead --- # getPropertyMetadata ### Callable * **getPropertyMetadata\(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any, propertyName: any): T *** * get property data * **@since** 2.3.0 * **@deprecated** Use MetadataManager.getOwnMetadata instead *** #### Type parameters * **T** = any --- # getPropertyType ### Callable * **getPropertyType(target: any, methodName: string | symbol): [TSDesignType](/api/core/interface/TSDesignType.md)\ *** * get property(method) type from metadata * **@since** 3.0.0 * **@deprecated** Use MetadataManager.getPropertyType instead --- # getProviderId ### Callable * **getProviderId(module: any): string *** * get provider id from module * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.getProviderId instead --- # getProviderName ### Callable * **getProviderName(module: any): string *** * * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.getProviderName instead --- # getProviderUUId ### Callable * **getProviderUUId(module: any): string *** * get provider uuid from module * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.getProviderUUId instead --- # GrpcMethod ### Callable * **GrpcMethod(methodOptions? : { methodName? : string; onEnd? : string; type? : [GrpcStreamTypeEnum](/api/core/enum/GrpcStreamTypeEnum.md) }): MethodDecorator --- # Guard ### Callable * **Guard(): ClassDecorator --- # Head ### Callable * **Head(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP HEAD requests to the specified path. --- # Headers ### Callable * **Headers(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # HttpCode ### Callable * **HttpCode(code: number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Init ### Callable * **Init(): MethodDecorator --- # initializeGlobalApplicationContext ### Callable * **initializeGlobalApplicationContext(globalOptions: [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): Promise<[IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md)> *** * midway framework main entry, this method bootstrap all service and framework. --- # Inject ### Callable * **Inject(identifier? : [ObjectIdentifier](/api/core.md#ObjectIdentifier)): PropertyDecorator & ParameterDecorator --- # InjectClient ### Callable * **InjectClient(serviceFactoryClz: new (...args: any\[]) => [IServiceFactory](/api/core/interface/IServiceFactory.md)\, clientName? : string): PropertyDecorator --- # isProvide ### Callable * **isProvide(target: any): boolean *** * use * **@Provide** decorator or not * **@since** 3.0.0 * **@deprecated** Use DecoratorManager.isProvide instead --- # isTypeScriptEnvironment ### Callable * **isTypeScriptEnvironment(): boolean --- # KafkaListener ### Callable * **KafkaListener(topic: string, options? : [KafkaListenerOptions](/api/core/interface/KafkaListenerOptions.md)): MethodDecorator --- # LazyInject ### Callable * **LazyInject(identifier? : [ObjectIdentifier](/api/core.md#ObjectIdentifier) | () => ObjectIdentifier | ClassType): PropertyDecorator & ParameterDecorator --- # listModule ### Callable * **listModule(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), filter? : (module: any) => boolean): any\[] *** * list module from decorator key * **@since** 2.0.0 * **@deprecated** Use DecoratorManager.listModule instead --- # listPreloadModule ### Callable * **listPreloadModule(): any\[] *** * list preload module * **@since** 2.0.0 * **@deprecated** Use DecoratorManager.listPreStartModule instead --- # listPropertyDataFromClass ### Callable * **listPropertyDataFromClass(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): any\[] *** * list property data from class * **@since** 2.3.0 * **@deprecated** --- # loadModule ### Callable * **loadModule(p: string, options? : { enableCache? : boolean; extraModuleRoot? : string\[]; importQuery? : string; loadMode? : commonjs | esm; safeLoad? : boolean; warnOnLoadError? : boolean }): Promise\ *** * load module, and it can be chosen commonjs or esm mode * **@since** 3.12.0 --- # Logger ### Callable * **Logger(identifier? : string): PropertyDecorator *** * Logger decorator, use to get logger instance * **@since** 2.0.0 --- # MainApp ### Callable * **MainApp(): PropertyDecorator *** * Get the main application instance * **@since** 4.0.0 --- # makeHttpRequest ### Callable * **makeHttpRequest\(url: string, options? : [HttpClientOptions](/api/core/interface/HttpClientOptions.md)\): Promise<[HttpClientResponse](/api/core/interface/HttpClientResponse.md)\> *** * #### Type parameters * **ResType** --- # Match ### Callable * **Match(matchPattern? : [MatchPattern](/api/core.md#MatchPattern)\): (target: any) => void --- # Middleware ### Callable * **Middleware(): ClassDecorator --- # Mock ### Callable * **Mock(): ClassDecorator --- # OnConnection ### Callable * **OnConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSConnection** --- # OnDisConnection ### Callable * **OnDisConnection(): MethodDecorator *** * * **@deprecated** please use * **@OnWSDisConnection** --- # OnMessage ### Callable * **OnMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) }): MethodDecorator *** * * **@deprecated** please use * **@OnWSMessage** --- # OnWSConnection ### Callable * **OnWSConnection(eventOptions? : { middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) }): MethodDecorator --- # OnWSDisConnection ### Callable * **OnWSDisConnection(): MethodDecorator --- # OnWSMessage ### Callable * **OnWSMessage(eventName: string, eventOptions? : { middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) }): MethodDecorator --- # Options ### Callable * **Options(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP OPTIONS requests to the specified path. --- # Param ### Callable * **Param(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Patch ### Callable * **Patch(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PATCH requests to the specified path. --- # pathMatching ### Callable * **pathMatching(options: { ignore? : [IgnoreMatcher](/api/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/core.md#IgnoreMatcher)\\[]; match? : [IgnoreMatcher](/api/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/core.md#IgnoreMatcher)\\[]; thisResolver? : any }): (ctx? : any) => boolean --- # Pipe ### Callable * **Pipe(): ClassDecorator --- # Plugin ### Callable * **Plugin(identifier? : string): PropertyDecorator *** * Plugin decorator, use to get egg plugin instance * **@since** 2.0.0 --- # Post ### Callable * **Post(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP POST requests to the specified path. --- # prepareGlobalApplicationContext ### Callable * **prepareGlobalApplicationContext(globalOptions: [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) | [MidwayContainer](/api/core/class/MidwayContainer.md) *** * prepare applicationContext, it use in egg framework, hooks and serverless function generator --- # prepareGlobalApplicationContextAsync ### Callable * **prepareGlobalApplicationContextAsync(globalOptions: [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): Promise<[IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) | [MidwayContainer](/api/core/class/MidwayContainer.md)> *** * prepare applicationContext --- # Provide ### Callable * **Provide(identifier? : [ObjectIdentifier](/api/core.md#ObjectIdentifier)): (target: any) => void --- # Provider ### Callable * **Provider(type: GRPC, metadata? : [ProviderOptions](/api/core/namespace/GRPCMetadata.md#ProviderOptions)): ClassDecorator * **Provider(type: DUBBO, metadata? : any): ClassDecorator --- # providerWrapper ### Callable * **providerWrapper(wrapperInfo: { id: [ObjectIdentifier](/api/core.md#ObjectIdentifier); provider: (context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), args? : any) => any; scope? : [ScopeEnum](/api/core/enum/ScopeEnum.md) }\[]): void --- # Put ### Callable * **Put(path? : string | RegExp, routerOptions? : { description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); routerName? : string; summary? : string }): MethodDecorator *** * Routes HTTP PUT requests to the specified path. --- # Queries ### Callable * **Queries(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Query ### Callable * **Query(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # Queue ### Callable * **Queue(options? : any): ClassDecorator --- # RabbitMQListener ### Callable * **RabbitMQListener(queueName: string, options? : [RabbitMQListenerOptions](/api/core/interface/RabbitMQListenerOptions.md)): MethodDecorator --- # Redirect ### Callable * **Redirect(url: string, code? : number): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # registerErrorCode ### Callable * **registerErrorCode\(errorGroup: G, errorCodeMapping: T): ConvertString\ *** * Register error group and code, return the standard ErrorCode *** #### Type parameters * **T**: Convertable * **G**: string --- # RequestIP ### Callable * **RequestIP(pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # RequestMapping ### Callable * **RequestMapping(metadata? : [RouterOption](/api/core/interface/RouterOption.md)): MethodDecorator --- # RequestPath ### Callable * **RequestPath(pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # resetModule ### Callable * **resetModule(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void *** * reset module * **@since** 2.0.0 * **@deprecated** Use DecoratorManager.resetModule instead --- # retryWith ### Callable * **retryWith\(retryFn: T, retryTimes? : number, options? : { receiver? : any; throwOriginError? : boolean }): (...args: Parameters\) => ReturnType\ *** * wrap sync function with retry *** #### Type parameters * **T**: (...args: any\[]) => unknown --- # retryWithAsync ### Callable * **retryWithAsync\(retryFn: T, retryTimes? : number, options? : { receiver? : any; retryInterval? : number; throwOriginError? : boolean }): (...args: Parameters\) => ReturnType\ *** * wrap async function with retry *** #### Type parameters * **T**: (...args: any\[]) => Promise\ --- # safelyGet ### Callable * **safelyGet(list: string | string\[], obj? : Record\): any *** * * **@example** ``` safelyGet(['a','b'],{a: {b: 2}}) // => 2 safelyGet(['a','b'],{c: {b: 2}}) // => undefined safelyGet(['a','1'],{a: {"1": 2}}) // => 2 safelyGet(['a','1'],{a: {b: 2}}) // => undefined safelyGet('a.b',{a: {b: 2}}) // => 2 safelyGet('a.b',{c: {b: 2}}) // => undefined ``` * **@since** 2.0.0 --- # safeRequire ### Callable * **safeRequire(p: any, enabledCache? : boolean): any *** * * **@since** 2.0.0 --- # saveClassMetadata ### Callable * **saveClassMetadata(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, mergeIfExist? : boolean): void *** * save data to class * **@since** 2.3.0 * **@deprecated** Use MetadataManager.defineMetadata instead --- # saveModule ### Callable * **saveModule(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void *** * save module to inner map * **@since** 2.0.0 * **@deprecated** Use DecoratorManager.saveModule instead --- # saveObjectDefinition ### Callable * **saveObjectDefinition(target: any, props? : {}): any *** * save class object definition * **@since** 2.3.0 * **@deprecated** Use MetadataManager.attachMetadata instead --- # savePreloadModule ### Callable * **savePreloadModule(target: any): void *** * save preload module by target * **@since** 2.0.0 * **@deprecated** Use DecoratorManager.savePreStartModule instead --- # savePropertyDataToClass ### Callable * **savePropertyDataToClass(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data to class * **@since** 2.3.0 * **@deprecated** Use MetadataManager.defineMetadata instead --- # savePropertyInject ### Callable * **savePropertyInject(opts: { args? : any; identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier); target: any; targetKey: string }): void *** * save property inject args * **@since** 2.3.0 * **@deprecated** Use MetadataManager.attachMetadata instead --- # savePropertyMetadata ### Callable * **savePropertyMetadata(decoratorNameKey: [ObjectIdentifier](/api/core.md#ObjectIdentifier), data: any, target: any, propertyName: any): void *** * save property data * **@since** 2.3.0 * **@deprecated** Use MetadataManager.defineMetadata instead --- # saveProviderId ### Callable * **saveProviderId(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): [ClassType](/api/core.md#ClassType) *** * class provider id * **@since** 2.3.0 * **@deprecated** Use DecoratorManager.saveProviderId instead --- # Schedule ### Callable * **Schedule(scheduleOpts: string | [ScheduleOpts](/api/core/interface/ScheduleOpts.md)): (target: any) => void --- # Scope ### Callable * **Scope(scope: [ScopeEnum](/api/core/enum/ScopeEnum.md), scopeOptions? : { allowDowngrade? : boolean }): ClassDecorator --- # ServerlessFunction ### Callable * **ServerlessFunction(options: [ServerlessFunctionOptions](/api/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions) & Record\): MethodDecorator --- # ServerlessTrigger ### Callable * **ServerlessTrigger(type: HTTP, metadata: [HTTPTriggerOptions](/api/core/namespace/FaaSMetadata.md#HTTPTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: OS, metadata: [OSTriggerOptions](/api/core/namespace/FaaSMetadata.md#OSTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: LOG, metadata: [LogTriggerOptions](/api/core/namespace/FaaSMetadata.md#LogTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: TIMER, metadata: [TimerTriggerOptions](/api/core/namespace/FaaSMetadata.md#TimerTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MQ, metadata: [MQTriggerOptions](/api/core/namespace/FaaSMetadata.md#MQTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: CDN, metadata? : [CDNTriggerOptions](/api/core/namespace/FaaSMetadata.md#CDNTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: API\_GATEWAY, metadata? : [APIGatewayTriggerOptions](/api/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: HSF, metadata? : [HSFTriggerOptions](/api/core/namespace/FaaSMetadata.md#HSFTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: MTOP, metadata? : [MTopTriggerOptions](/api/core/namespace/FaaSMetadata.md#MTopTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: SSR, metadata? : [SSRTriggerOptions](/api/core/namespace/FaaSMetadata.md#SSRTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: EVENT, metadata? : [EventTriggerOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerOptions)): MethodDecorator * **ServerlessTrigger(type: string, metadata? : [EventTriggerOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerOptions) & Record\): MethodDecorator --- # Session ### Callable * **Session(propertyOrPipes? : string | [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[], pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\[]): ParameterDecorator --- # SetHeader ### Callable * **SetHeader(headerKey: string | Record\, value? : string): (target: any, key: any, descriptor: PropertyDescriptor) => PropertyDescriptor --- # Singleton ### Callable * **Singleton(): ClassDecorator --- # sleep ### Callable * **sleep(sleepTime? : number, abortController? : AbortController): Promise\ --- # Task ### Callable * **Task(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # TaskLocal ### Callable * **TaskLocal(options: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void --- # Trace ### Callable * **Trace(spanName: string): MethodDecorator *** * Mark a method to create an OpenTelemetry span for its invocation. --- # transformRequestObjectByType ### Callable * **transformRequestObjectByType(originValue: any, targetType? : any): any *** * transform request object to definition type * **@since** 3.0.0 --- # UseGuard ### Callable * **UseGuard(guardOrArr: [CommonGuardUnion](/api/core.md#CommonGuardUnion)): ClassDecorator & MethodDecorator --- # wrapAsync ### Callable * **wrapAsync(handler: any): (...args: any\[]) => any --- # wrapMiddleware ### Callable * **wrapMiddleware(mw: (context: any, next: any, options? : any) => any, options: any): (context: any, next: any, options? : any) => any *** * wrap function middleware with match and ignore --- # WSBroadCast ### Callable * **WSBroadCast(messageName? : string, roomName? : string | string\[]): MethodDecorator --- # WSController ### Callable * **WSController(namespace? : string | RegExp, routerOptions? : { connectionMiddleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) }): ClassDecorator --- # WSEmit ### Callable * **WSEmit(messageName: string, roomName? : string | string\[]): MethodDecorator --- # AspectMetadata ## Index[**](#Index) ### Properties * [**aspectTarget](#aspectTarget) * [**match](#match) * [**priority](#priority) ## Properties[**](#Properties) ### [**](#aspectTarget)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L319)aspectTarget **aspectTarget: any ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L320)optionalmatch **match? : string | () => boolean ### [**](#priority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L321)optionalpriority **priority? : number --- # AsyncContext ## Index[**](#Index) ### Methods * [**deleteValue](#deleteValue) * [**getValue](#getValue) * [**setValue](#setValue) ## Methods[**](#Methods) ### [**](#deleteValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L41)deleteValue * **deleteValue(key: symbol): [AsyncContext](/api/core/interface/AsyncContext.md) - Return a new context which inherits from this context but does not contain a value for the given key. ### [**](#getValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L24)getValue * **getValue(key: symbol): unknown - Get a value from the context. ### [**](#setValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L33)setValue * **setValue(key: symbol, value: unknown): [AsyncContext](/api/core/interface/AsyncContext.md) - Create a new context which inherits from this context and has the given key set to the given value. --- # AsyncContextManager ## Index[**](#Index) ### Methods * [**active](#active) * [**bind](#bind) * [**disable](#disable) * [**enable](#enable) * [**with](#with) ## Methods[**](#Methods) ### [**](#active)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L48)active * **active(): [AsyncContext](/api/core/interface/AsyncContext.md) - Get the current active context ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L69)bind * **bind\(context? : [AsyncContext](/api/core/interface/AsyncContext.md), target: T): T - Bind an object as the current context (or a specific one) *** #### Type parameters * **T** ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L79)disable * **disable(): this - Disable context management ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L74)enable * **enable(): this - Enable context management ### [**](#with)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/common/asyncContextManager.ts#L57)with * **with\(context: [AsyncContext](/api/core/interface/AsyncContext.md), fn: F, thisArg? : ThisParameterType\, ...args: A): ReturnType\ - Run the fn callback with object set as the current active context *** #### Type parameters * **A**: unknown\[] * **F**: (...args: A) => ReturnType\ --- # BaseServiceDiscoveryHealthCheckOptions 基础健康检查配置 ### Hierarchy * *BaseServiceDiscoveryHealthCheckOptions* * [TTLServiceDiscoveryHealthCheckOptions](/api/core/interface/TTLServiceDiscoveryHealthCheckOptions.md) * [HTTPServiceDiscoveryHealthCheckOptions](/api/core/interface/HTTPServiceDiscoveryHealthCheckOptions.md) * [TCPServiceDiscoveryHealthCheckOptions](/api/core/interface/TCPServiceDiscoveryHealthCheckOptions.md) ## Index[**](#Index) ### Properties * [**interval](#interval) * [**maxRetries](#maxRetries) * [**retryInterval](#retryInterval) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1322)optionalinterval **interval? : number 检查间隔(毫秒) ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1330)optionalmaxRetries **maxRetries? : number 最大重试次数 ### [**](#retryInterval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1334)optionalretryInterval **retryInterval? : number 重试间隔(毫秒) ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1326)optionaltimeout **timeout? : number 检查超时时间(毫秒) --- # CommonSchedule ## Index[**](#Index) ### Methods * [**exec](#exec) ## Methods[**](#Methods) ### [**](#exec)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L6)exec * **exec(ctx? : any): any --- # ConstructorInjectMetadata Metadata when using * **@Inject** constructor injection ### Hierarchy * [PropertyInjectMetadata](/api/core/interface/PropertyInjectMetadata.md) * *ConstructorInjectMetadata* ## Index[**](#Index) ### Properties * [**args](#args) * [**id](#id) * [**injectMode](#injectMode) * [**isLazyInject](#isLazyInject) * [**name](#name) * [**parameterIndex](#parameterIndex) * [**targetKey](#targetKey) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L73)args **args: any\[] Inherited from PropertyInjectMetadata.args ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L74)id **id: [ObjectIdentifier](/api/core.md#ObjectIdentifier) | () => ObjectIdentifier | ClassType\ Inherited from PropertyInjectMetadata.id ### [**](#injectMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L76)injectMode **injectMode: [InjectModeEnum](/api/core/enum/InjectModeEnum.md) Inherited from PropertyInjectMetadata.injectMode ### [**](#isLazyInject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L78)isLazyInject **isLazyInject: boolean Inherited from PropertyInjectMetadata.isLazyInject ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L75)name **name: string Inherited from PropertyInjectMetadata.name ### [**](#parameterIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L85)parameterIndex **parameterIndex: number ### [**](#targetKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L77)targetKey **targetKey: string Inherited from PropertyInjectMetadata.targetKey --- # Context ## Index[**](#Index) ### Properties * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L842)logger **logger: [ILogger](/api/core/interface/ILogger.md) ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L840)requestContext **requestContext: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Custom properties. ### [**](#startTime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L844)startTime **startTime: number ### [**](#traceId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L841)optionaltraceId **traceId? : string ## Methods[**](#Methods) ### [**](#getApp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L859)getApp * **getApp(): [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)> - Get current related application instance. ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L855)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L843)getLogger * **getLogger(name? : string): [ILogger](/api/core/interface/ILogger.md) ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L850)setAttr * **setAttr(key: string, value: any): any - Set value to app attribute map --- # ControllerOption ## Index[**](#Index) ### Properties * [**prefix](#prefix) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/controller.ts#L6)prefix **prefix: string ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/controller.ts#L7)optionalrouterOptions **routerOptions? : { alias? : string\[]; description? : string; ignoreGlobalPrefix? : boolean; middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); sensitive? : boolean; tagName? : string; version? : string | string\[]; versionPrefix? : string; versionType? : URI | HEADER | MEDIA\_TYPE | CUSTOM } --- # DataSourceManagerConfigOption \ ### Hierarchy * [CreateDataSourceInstanceOptions](/api/core.md#CreateDataSourceInstanceOptions) * *DataSourceManagerConfigOption* ## Index[**](#Index) ### Properties * [**cacheInstance](#cacheInstance) * [**dataSource](#dataSource) * [**default](#default) * [**defaultDataSourceName](#defaultDataSourceName) * [**validateConnection](#validateConnection) ## Properties[**](#Properties) ### [**](#cacheInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L512)optionalcacheInstance **cacheInstance? : boolean Inherited from CreateDataSourceInstanceOptions.cacheInstance * **@deprecated** ### [**](#dataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L531)optionaldataSource **dataSource? : [BaseDataSourceManagerConfigOption](/api/core.md#BaseDataSourceManagerConfigOption)\ ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L529)optionaldefault **default? : [BaseDataSourceManagerConfigOption](/api/core.md#BaseDataSourceManagerConfigOption)\ ### [**](#defaultDataSourceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L530)optionaldefaultDataSourceName **defaultDataSourceName? : string ### [**](#validateConnection)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L508)optionalvalidateConnection **validateConnection? : boolean Inherited from CreateDataSourceInstanceOptions.validateConnection * **@deprecated** --- # DefaultInstanceMetadata ## Index[**](#Index) ### Properties * [**host](#host) * [**id](#id) * [**metadata](#metadata) * [**port](#port) * [**serviceName](#serviceName) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1396)host **host: string ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1394)id **id: string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1398)metadata **metadata: Record\ ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1397)port **port: number ### [**](#serviceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1395)serviceName **serviceName: string --- # DuplicateRouteErrorEntry ## Index[**](#Index) ### Properties * [**handler](#handler) * [**source](#source) ## Properties[**](#Properties) ### [**](#handler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L94)handler **handler: string ### [**](#source)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L93)source **source: functional | decorator --- # DuplicateRouteErrorPayload ## Index[**](#Index) ### Properties * [**code](#code) * [**current](#current) * [**existing](#existing) * [**fullPath](#fullPath) * [**method](#method) ## Properties[**](#Properties) ### [**](#code)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L98)code **code: MIDWAY\_DUPLICATE\_ROUTE ### [**](#current)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L101)current **current: [DuplicateRouteErrorEntry](/api/core/interface/DuplicateRouteErrorEntry.md) ### [**](#existing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L102)existing **existing: [DuplicateRouteErrorEntry](/api/core/interface/DuplicateRouteErrorEntry.md) ### [**](#fullPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L100)fullPath **fullPath: string ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/error/framework.ts#L99)method **method: string --- # HealthResult ## Index[**](#Index) ### Properties * [**reason](#reason) * [**status](#status) ## Properties[**](#Properties) ### [**](#reason)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1231)optionalreason **reason? : string failed reason ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1227)status **status: boolean health status --- # HealthResults ## Index[**](#Index) ### Properties * [**namespace](#namespace) * [**reason](#reason) * [**results](#results) * [**status](#status) ## Properties[**](#Properties) ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1242)namespace **namespace: string first failed namespace ### [**](#reason)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1246)optionalreason **reason? : string first failed reason ### [**](#results)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1247)optionalresults **results? : { namespace: string; reason? : string; status: boolean }\[] ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1238)status **status: boolean health status --- # HttpClientOptions \ ### Hierarchy * RequestOptions * *HttpClientOptions* ## Index[**](#Index) ### Properties * [**contentType](#contentType) * [**data](#data) * [**dataType](#dataType) * [**headers](#headers) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#contentType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L19)optionalcontentType **contentType? : [HttpClientMimeType](/api/core.md#HttpClientMimeType) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L21)optionaldata **data? : Data ### [**](#dataType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L20)optionaldataType **dataType? : [HttpClientMimeType](/api/core.md#HttpClientMimeType) ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L18)optionalheaders **headers? : any Overrides https.RequestOptions.headers ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L22)optionaltimeout **timeout? : number Overrides https.RequestOptions.timeout --- # HttpClientResponse \ ### Hierarchy * IncomingMessage * *HttpClientResponse* ## Index[**](#Index) ### Properties * [**data](#data) * [**status](#status) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L28)data **data: string | Buffer | ResType ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/util/httpclient.ts#L27)status **status: number --- # HTTPServiceDiscoveryHealthCheckOptions HTTP 健康检查配置 ### Hierarchy * [BaseServiceDiscoveryHealthCheckOptions](/api/core/interface/BaseServiceDiscoveryHealthCheckOptions.md) * *HTTPServiceDiscoveryHealthCheckOptions* ## Index[**](#Index) ### Properties * [**expectedStatus](#expectedStatus) * [**headers](#headers) * [**interval](#interval) * [**maxRetries](#maxRetries) * [**method](#method) * [**retryInterval](#retryInterval) * [**timeout](#timeout) * [**url](#url) ## Properties[**](#Properties) ### [**](#expectedStatus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1366)optionalexpectedStatus **expectedStatus? : number 期望的 HTTP 状态码 ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1362)optionalheaders **headers? : Record\ HTTP 请求头 ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1322)optionalinterval **interval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.interval 检查间隔(毫秒) ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1330)optionalmaxRetries **maxRetries? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.maxRetries 最大重试次数 ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1358)optionalmethod **method? : string HTTP 方法 ### [**](#retryInterval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1334)optionalretryInterval **retryInterval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.retryInterval 重试间隔(毫秒) ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1326)optionaltimeout **timeout? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.timeout 检查超时时间(毫秒) ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1354)url **url: string 健康检查 URL --- # IComponentInfo ## Index[**](#Index) ### Properties * [**component](#component) * [**enabledEnvironment](#enabledEnvironment) ## Properties[**](#Properties) ### [**](#component)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1271)component **component: { Configuration: [ClassType](/api/core.md#ClassType)<[ILifeCycle](/api/core/interface/ILifeCycle.md)> } | FunctionalConfiguration ### [**](#enabledEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1272)optionalenabledEnvironment **enabledEnvironment? : string\[] --- # IConfigService ### Implemented by * [MidwayConfigService](/api/core/class/MidwayConfigService.md) ## Index[**](#Index) ### Methods * [**add](#add) * [**addObject](#addObject) * [**clearAllConfig](#clearAllConfig) * [**getConfiguration](#getConfiguration) * [**load](#load) ## Methods[**](#Methods) ### [**](#add)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L809)add * **add(configFilePaths: any\[]): any ### [**](#addObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L810)addObject * **addObject(obj: object, reverse? : boolean): any ### [**](#clearAllConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L813)clearAllConfig * **clearAllConfig(): any ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L812)getConfiguration * **getConfiguration(configKey? : string): any ### [**](#load)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L811)load * **load(): any --- # IConfigurationOptions ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1120)optionalappLogger **appLogger? : [ILogger](/api/core/interface/ILogger.md) ### [**](#contextLoggerApplyLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1121)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string ### [**](#contextLoggerFormat)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1122)optionalcontextLoggerFormat **contextLoggerFormat? : any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1119)optionallogger **logger? : [ILogger](/api/core/interface/ILogger.md) --- # IDataSourceManager \ ### Implemented by * [DataSourceManager](/api/core/class/DataSourceManager.md) ## Index[**](#Index) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**hasDataSource](#hasDataSource) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1199)createInstance * **createInstance(config: DataSourceConfig): Promise\ ### [**](#getAllDataSources)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1202)getAllDataSources * **getAllDataSources(): Map\ ### [**](#getDataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1200)getDataSource * **getDataSource(dataSourceName: string): DataSource ### [**](#getDataSourceNames)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1201)getDataSourceNames * **getDataSourceNames(): string\[] ### [**](#getDataSourcePriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1207)getDataSourcePriority * **getDataSourcePriority(dataSourceName: string): string ### [**](#getDefaultDataSourceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1205)getDefaultDataSourceName * **getDefaultDataSourceName(): string ### [**](#hasDataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1203)hasDataSource * **hasDataSource(dataSourceName: string): boolean ### [**](#isConnected)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1204)isConnected * **isConnected(dataSourceName: string): Promise\ ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1208)isHighPriority * **isHighPriority(dataSourceName: string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1210)isLowPriority * **isLowPriority(dataSourceName: string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1209)isMediumPriority * **isMediumPriority(dataSourceName: string): boolean ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1206)stop * **stop(): Promise\ --- # IEnvironmentService ### Implemented by * [MidwayEnvironmentService](/api/core/class/MidwayEnvironmentService.md) ## Index[**](#Index) ### Methods * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getModuleLoadType](#getModuleLoadType) * [**isDevelopmentEnvironment](#isDevelopmentEnvironment) ## Methods[**](#Methods) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L826)getCurrentEnvironment * **getCurrentEnvironment(): string ### [**](#getModuleLoadType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L828)getModuleLoadType * **getModuleLoadType(): [ModuleLoadType](/api/core.md#ModuleLoadType) ### [**](#isDevelopmentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L827)isDevelopmentEnvironment * **isDevelopmentEnvironment(): boolean --- # IFileDetector ### Implemented by * [AbstractFileDetector](/api/core/class/AbstractFileDetector.md) ## Index[**](#Index) ### Methods * [**run](#run) * [**runSync](#runSync) ## Methods[**](#Methods) ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L804)run * **run(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): Promise\ ### [**](#runSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L805)runSync * **runSync(container: [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md), namespace: string): void --- # IFilter \ Common Exception Filter definition ## Index[**](#Index) ### Methods * [**catch](#catch) * [**match](#match) ## Methods[**](#Methods) ### [**](#catch)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L914)optionalcatch * **catch(err: Error, ctx: CTX, res? : R, next? : N): any ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L915)optionalmatch * **match(result: any, ctx: CTX, res? : R, next? : N): any --- # IGuard \ Guard definition ## Index[**](#Index) ### Methods * [**canActivate](#canActivate) ## Methods[**](#Methods) ### [**](#canActivate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L925)canActivate * **canActivate(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): boolean | Promise\ --- # IIdentifierRelationShip ## Index[**](#Index) ### Methods * [**getRelation](#getRelation) * [**hasRelation](#hasRelation) * [**saveClassRelation](#saveClassRelation) * [**saveFunctionRelation](#saveFunctionRelation) ## Methods[**](#Methods) ### [**](#getRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L745)getRelation * **getRelation(id: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): string ### [**](#hasRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L744)hasRelation * **hasRelation(id: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#saveClassRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L742)saveClassRelation * **saveClassRelation(module: any, namespace? : string): void ### [**](#saveFunctionRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L743)saveFunctionRelation * **saveFunctionRelation(id: [ObjectIdentifier](/api/core.md#ObjectIdentifier), uuid: string): void --- # IInformationService ### Implemented by * [MidwayInformationService](/api/core/class/MidwayInformationService.md) ## Index[**](#Index) ### Methods * [**getAppDir](#getAppDir) * [**getBaseDir](#getBaseDir) * [**getHome](#getHome) * [**getPkg](#getPkg) * [**getProjectName](#getProjectName) * [**getRoot](#getRoot) ## Methods[**](#Methods) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L820)getAppDir * **getAppDir(): string ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L819)getBaseDir * **getBaseDir(): string ### [**](#getHome)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L821)getHome * **getHome(): string ### [**](#getPkg)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L817)getPkg * **getPkg(): any ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L818)getProjectName * **getProjectName(): any ### [**](#getRoot)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L822)getRoot * **getRoot(): string --- # ILifeCycle Lifecycle Definition 生命周期定义 ### Hierarchy * Partial<[IObjectLifeCycle](/api/core/interface/IObjectLifeCycle.md)> * *ILifeCycle* ## Index[**](#Index) ### Methods * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onConfigLoad](#onConfigLoad) * [**onHealthCheck](#onHealthCheck) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**onReady](#onReady) * [**onServerReady](#onServerReady) * [**onStop](#onStop) ## Methods[**](#Methods) ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L626)optionalonBeforeBind * **onBeforeBind(Clzz: any, options: [ObjectBeforeBindOptions](/api/core/interface/ObjectBeforeBindOptions.md)): void - Inherited from Partial.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L627)optionalonBeforeObjectCreated * **onBeforeObjectCreated(Clzz: any, options: [ObjectBeforeCreatedOptions](/api/core/interface/ObjectBeforeCreatedOptions.md)): void - Inherited from Partial.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L630)optionalonBeforeObjectDestroy * **onBeforeObjectDestroy\(ins: T, options: [ObjectBeforeDestroyOptions](/api/core/interface/ObjectBeforeDestroyOptions.md)): void - Inherited from Partial.onBeforeObjectDestroy #### Type parameters * **T** ### [**](#onConfigLoad)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L555)optionalonConfigLoad * **onConfigLoad(container: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), mainApp: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options: [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md)): Promise\ ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L570)optionalonHealthCheck * **onHealthCheck(container: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), mainApp: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options: [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md)): Promise<[HealthResult](/api/core/interface/HealthResult.md)> ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L628)optionalonObjectCreated * **onObjectCreated\(ins: T, options: [ObjectCreatedOptions](/api/core/interface/ObjectCreatedOptions.md)\): void - Inherited from Partial.onObjectCreated #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L629)optionalonObjectInit * **onObjectInit\(ins: T, options: [ObjectInitOptions](/api/core/interface/ObjectInitOptions.md)): void - Inherited from Partial.onObjectInit #### Type parameters * **T** ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L560)optionalonReady * **onReady(container: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), mainApp: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options: [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md)): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L565)optionalonServerReady * **onServerReady(container: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), mainApp: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options: [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md)): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L575)optionalonStop * **onStop(container: [IMidwayContainer](/api/core/interface/IMidwayContainer.md), mainApp: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options: [LifeCycleInvokeOptions](/api/core/interface/LifeCycleInvokeOptions.md)): Promise\ --- # ILoadBalancer \ 负载均衡策略接口 ### Implemented by * [RandomLoadBalance](/api/core/class/RandomLoadBalance.md) * [RoundRobinLoadBalancer](/api/core/class/RoundRobinLoadBalancer.md) ## Index[**](#Index) ### Methods * [**select](#select) ## Methods[**](#Methods) ### [**](#select)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1431)select * **select(instances: ServiceInstance\[]): ServiceInstance - 从服务实例列表中选择一个实例 --- # ILogger Logger Options for midway, you can merge this interface in package * **@example** ``` import { IMidwayLogger } from '@midwayjs/logger'; declare module '@midwayjs/core' { interface ILogger extends IMidwayLogger { } } ``` ## Index[**](#Index) ### Methods * [**debug](#debug) * [**error](#error) * [**info](#info) * [**warn](#warn) ## Methods[**](#Methods) ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L409)debug * **debug(msg: any, ...args: any\[]): void ### [**](#error)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L410)error * **error(msg: any, ...args: any\[]): void ### [**](#info)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L408)info * **info(msg: any, ...args: any\[]): void ### [**](#warn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L411)warn * **warn(msg: any, ...args: any\[]): void --- # IMethodAspect ## Index[**](#Index) ### Methods * [**after](#after) * [**afterReturn](#afterReturn) * [**afterThrow](#afterThrow) * [**around](#around) * [**before](#before) ## Methods[**](#Methods) ### [**](#after)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L325)optionalafter * **after(joinPoint: [JoinPoint](/api/core/interface/JoinPoint.md), result: any, error: Error): any ### [**](#afterReturn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L326)optionalafterReturn * **afterReturn(joinPoint: [JoinPoint](/api/core/interface/JoinPoint.md), result: any): any ### [**](#afterThrow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L327)optionalafterThrow * **afterThrow(joinPoint: [JoinPoint](/api/core/interface/JoinPoint.md), error: Error): void ### [**](#around)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L329)optionalaround * **around(joinPoint: [JoinPoint](/api/core/interface/JoinPoint.md)): any ### [**](#before)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L328)optionalbefore * **before(joinPoint: [JoinPoint](/api/core/interface/JoinPoint.md)): void --- # IMiddleware \ Common middleware definition ## Index[**](#Index) ### Properties * [**ignore](#ignore) * [**match](#match) * [**resolve](#resolve) ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L883)optionalignore **ignore? : [IgnoreMatcher](/api/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/core.md#IgnoreMatcher)\\[] Match those paths with higher priority than ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L879)optionalmatch **match? : [IgnoreMatcher](/api/core.md#IgnoreMatcher)\ | [IgnoreMatcher](/api/core.md#IgnoreMatcher)\\[] Which paths to ignore ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L872)resolve **resolve: (app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>, options? : any) => [FunctionMiddleware](/api/core.md#FunctionMiddleware)\ | Promise<[FunctionMiddleware](/api/core.md#FunctionMiddleware)\> --- # IMiddlewareManager \ ### Implemented by * [ContextMiddlewareManager](/api/core/class/ContextMiddlewareManager.md) ## Index[**](#Index) ### Methods * [**findAndInsertAfter](#findAndInsertAfter) * [**findAndInsertBefore](#findAndInsertBefore) * [**findAndInsertFirst](#findAndInsertFirst) * [**findAndInsertLast](#findAndInsertLast) * [**findItem](#findItem) * [**findItemIndex](#findItemIndex) * [**getMiddlewareName](#getMiddlewareName) * [**getNames](#getNames) * [**insertAfter](#insertAfter) * [**insertBefore](#insertBefore) * [**insertFirst](#insertFirst) * [**insertLast](#insertLast) * [**push](#push) * [**remove](#remove) * [**unshift](#unshift) ## Methods[**](#Methods) ### [**](#findAndInsertAfter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L947)findAndInsertAfter * **findAndInsertAfter(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\, afterMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#findAndInsertBefore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L951)findAndInsertBefore * **findAndInsertBefore(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\, beforeMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#findAndInsertFirst)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L955)findAndInsertFirst * **findAndInsertFirst(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#findAndInsertLast)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L958)findAndInsertLast * **findAndInsertLast(middlewareOrName: string | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#findItem)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L964)findItem * **findItem(middlewareOrName: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): [CommonMiddleware](/api/core.md#CommonMiddleware)\ ### [**](#findItemIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L961)findItemIndex * **findItemIndex(middlewareOrName: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): number ### [**](#getMiddlewareName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L967)getMiddlewareName * **getMiddlewareName(middleware: [CommonMiddleware](/api/core.md#CommonMiddleware)\): string ### [**](#getNames)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L973)getNames * **getNames(): string\[] ### [**](#insertAfter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L943)insertAfter * **insertAfter(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\, idxOrAfterMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#insertBefore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L939)insertBefore * **insertBefore(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\, idxOrBeforeMiddleware: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): void ### [**](#insertFirst)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L937)insertFirst * **insertFirst(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void ### [**](#insertLast)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L938)insertLast * **insertLast(middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void ### [**](#push)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L971)push * **push(...items: [CommonMiddleware](/api/core.md#CommonMiddleware)\\[]): number ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L968)remove * **remove(middlewareOrNameOrIdx: string | number | [CommonMiddleware](/api/core.md#CommonMiddleware)\): [CommonMiddleware](/api/core.md#CommonMiddleware)\ ### [**](#unshift)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L972)unshift * **unshift(...items: [CommonMiddleware](/api/core.md#CommonMiddleware)\\[]): number --- # IMidwayBaseApplication \ ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1052)addConfigObject * **addConfigObject(obj: any): any - Add new value to current config ### [**](#createAnonymousContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1040)createAnonymousContext * **createAnonymousContext(...args: any\[]): CTX - create a context with RequestContainer ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1029)createLogger * **createLogger(name: string, options: [MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)): [ILogger](/api/core/interface/ILogger.md) - Create a logger by name and options ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L985)getAppDir * **getAppDir(): string - Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1005)getApplicationContext * **getApplicationContext(): [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) - Get global Midway IoC Container ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1065)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L980)getBaseDir * **getBaseDir(): string - Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1011)getConfig * **getConfig\(key? : string): T - Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1022)getCoreLogger * **getCoreLogger(): [ILogger](/api/core/interface/ILogger.md) - Get core logger ### [**](#getEnv)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L990)getEnv * **getEnv(): string - Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L995)getFramework * **getFramework(): [IMidwayFramework](/api/core/interface/IMidwayFramework.md)<[IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)\, CTX, unknown, unknown, unknown> - get current related framework ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1017)getLogger * **getLogger(name? : string): [ILogger](/api/core/interface/ILogger.md) - Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1076)getMiddleware * **getMiddleware\(): [IMiddlewareManager](/api/core/interface/IMiddlewareManager.md)\ - get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1093)getNamespace * **getNamespace(): string - get current namespace ### [**](#getProcessType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1000)getProcessType * **getProcessType(): [MidwayProcessTypeEnum](/api/core/enum/MidwayProcessTypeEnum.md) - Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1034)getProjectName * **getProjectName(): string - Get project name, just package.json name ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1059)setAttr * **setAttr(key: string, value: any): any - Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1046)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1082)useFilter * **useFilter\(Filter: [CommonFilterUnion](/api/core.md#CommonFilterUnion)\): void - add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1088)useGuard * **useGuard(guard: [CommonGuardUnion](/api/core.md#CommonGuardUnion)\): void - add global guard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1071)useMiddleware * **useMiddleware\(Middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void - add global filter to app *** #### Type parameters * **R** * **N** --- # IMidwayBootstrapOptions ## Index[**](#Index) ### Properties * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**asyncContextManager](#asyncContextManager) * [**baseDir](#baseDir) * [**globalConfig](#globalConfig) * [**imports](#imports) * [**logger](#logger) * [**loggerFactory](#loggerFactory) * [**moduleLoadType](#moduleLoadType) * [**preloadModules](#preloadModules) ## Properties[**](#Properties) ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1105)optionalappDir **appDir? : string ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1106)optionalapplicationContext **applicationContext? : [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1114)optionalasyncContextManager **asyncContextManager? : [AsyncContextManager](/api/core/interface/AsyncContextManager.md) ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1104)optionalbaseDir **baseDir? : string ### [**](#globalConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1111)optionalglobalConfig **globalConfig? : Record\ | {}\[] ### [**](#imports)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1108)optionalimports **imports? : any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1110)optionallogger **logger? : boolean | [ILogger](/api/core/interface/ILogger.md) ### [**](#loggerFactory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1115)optionalloggerFactory **loggerFactory? : [LoggerFactory](/api/core/class/LoggerFactory.md)\ ### [**](#moduleLoadType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1109)optionalmoduleLoadType **moduleLoadType? : [ModuleLoadType](/api/core.md#ModuleLoadType) ### [**](#preloadModules)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1107)optionalpreloadModules **preloadModules? : any\[] --- # IMidwayContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * [IObjectFactory](/api/core/interface/IObjectFactory.md) * *IMidwayContainer* * [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) * [IMidwayRequestContainer](/api/core/interface/IMidwayRequestContainer.md) ## Index[**](#Index) ### Properties * [**registry](#registry) ### Methods * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L587)registry **registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) Inherited from IObjectFactory.registry ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L588)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - Inherited from IObjectFactory.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L589)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - Inherited from IObjectFactory.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L790)getAttr * **getAttr\(key: string): T - Get value from app attribute map *** #### Type parameters * **T** ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L776)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L794)getIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)\): string - Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L799)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Get instance IoC container scope ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L778)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L775)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L800)hasNamespace * **hasNamespace(namespace: string): boolean ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L777)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L774)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L779)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L785)setAttr * **setAttr(key: string, value: any): void - Set value to app attribute map --- # IMidwayFramework \ ### Implemented by * [BaseFramework](/api/core/class/BaseFramework.md) ## Index[**](#Index) ### Properties * [**app](#app) * [**configurationOptions](#configurationOptions) ### Methods * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1132)app **app: APP ### [**](#configurationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1133)configurationOptions **configurationOptions: CONFIG ## Methods[**](#Methods) ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1152)applyMiddleware * **applyMiddleware(lastMiddleware? : [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): Promise<[MiddlewareRespond](/api/core.md#MiddlewareRespond)\> ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1134)configure * **configure(options? : CONFIG): CONFIG ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1148)createLogger * **createLogger(name: string, options: [MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)): [ILogger](/api/core/interface/ILogger.md) ### [**](#getAppDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1144)getAppDir * **getAppDir(): string ### [**](#getApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1139)getApplication * **getApplication(): APP ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1140)getApplicationContext * **getApplicationContext(): [IMidwayGlobalContainer](/api/core/interface/IMidwayGlobalContainer.md) ### [**](#getBaseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1145)getBaseDir * **getBaseDir(): string ### [**](#getConfiguration)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1141)getConfiguration * **getConfiguration(key? : string): any ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1147)getCoreLogger * **getCoreLogger(): [ILogger](/api/core/interface/ILogger.md) ### [**](#getCurrentEnvironment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1142)getCurrentEnvironment * **getCurrentEnvironment(): string ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1143)getFrameworkName * **getFrameworkName(): string ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1146)getLogger * **getLogger(name? : string): [ILogger](/api/core/interface/ILogger.md) ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1151)getMiddleware * **getMiddleware(): [IMiddlewareManager](/api/core/interface/IMiddlewareManager.md)\ ### [**](#getNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1162)getNamespace * **getNamespace(): string ### [**](#getProjectName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1149)getProjectName * **getProjectName(): string ### [**](#initialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1136)initialize * **initialize(options: [IMidwayBootstrapOptions](/api/core/interface/IMidwayBootstrapOptions.md)): Promise\ ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1135)isEnable * **isEnable(): boolean ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1137)run * **run(): Promise\ ### [**](#runGuard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1157)runGuard * **runGuard(ctx: CTX, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ ### [**](#setFrameworkLoggerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1163)setFrameworkLoggerName * **setFrameworkLoggerName(name: string): void ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1138)stop * **stop(): Promise\ ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1155)useFilter * **useFilter(Filter: [CommonFilterUnion](/api/core.md#CommonFilterUnion)\): void ### [**](#useGuard)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1156)useGuard * **useGuard(guard: [CommonGuardUnion](/api/core.md#CommonGuardUnion)\): void ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1150)useMiddleware * **useMiddleware(Middleware: [CommonMiddlewareUnion](/api/core.md#CommonMiddlewareUnion)\): void --- # IMidwayGlobalContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * [IMidwayContainer](/api/core/interface/IMidwayContainer.md) * [WithFn](/api/core.md#WithFn)<[IObjectLifeCycle](/api/core/interface/IObjectLifeCycle.md)> * *IMidwayGlobalContainer* ### Implemented by * [MidwayContainer](/api/core/class/MidwayContainer.md) ## Index[**](#Index) ### Properties * [**identifierMapping](#identifierMapping) * [**objectCreateEventTarget](#objectCreateEventTarget) * [**registry](#registry) ### Methods * [**addNamespace](#addNamespace) * [**bind](#bind) * [**bindClass](#bindClass) * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getManagedResolverFactory](#getManagedResolverFactory) * [**getNamespaceList](#getNamespaceList) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) * [**stop](#stop) ## Properties[**](#Properties) ### [**](#identifierMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L750)identifierMapping **identifierMapping: [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) ### [**](#objectCreateEventTarget)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L751)objectCreateEventTarget **objectCreateEventTarget: EventEmitter\ ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L587)registry **registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) Inherited from IMidwayContainer.registry ## Methods[**](#Methods) ### [**](#addNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L753)addNamespace * **addNamespace(namespace: string): void ### [**](#bind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L754)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L758)bind * **bind\(target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) * **bind\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: T, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - #### Type parameters * **T** ### [**](#bindClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L763)bindClass * **bindClass(exports: any, options? : Partial<[IObjectDefinition](/api/core/interface/IObjectDefinition.md)>): void ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L588)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - Inherited from IMidwayContainer.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L589)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - Inherited from IMidwayContainer.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L790)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L776)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Inherited from IMidwayContainer.getDefinition ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L794)getIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)\): string - Inherited from IMidwayContainer.getIdentifier Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L799)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Inherited from IMidwayContainer.getInstanceScope Get instance IoC container scope ### [**](#getManagedResolverFactory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L765)getManagedResolverFactory * **getManagedResolverFactory(): ManagedResolverFactory ### [**](#getNamespaceList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L752)getNamespaceList * **getNamespaceList(): string\[] ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L778)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - Inherited from IMidwayContainer.getObject #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L775)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from IMidwayContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L800)hasNamespace * **hasNamespace(namespace: string): boolean - Inherited from IMidwayContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L777)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from IMidwayContainer.hasObject ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L626)onBeforeBind * **onBeforeBind(fn: (...args: \[Clzz: any, options: [ObjectBeforeBindOptions](/api/core/interface/ObjectBeforeBindOptions.md)]) => void): void - Inherited from WithFn.onBeforeBind ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L627)onBeforeObjectCreated * **onBeforeObjectCreated(fn: (...args: \[Clzz: any, options: [ObjectBeforeCreatedOptions](/api/core/interface/ObjectBeforeCreatedOptions.md)]) => void): void - Inherited from WithFn.onBeforeObjectCreated ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L630)onBeforeObjectDestroy * **onBeforeObjectDestroy(fn: (...args: \[ins: unknown, options: [ObjectBeforeDestroyOptions](/api/core/interface/ObjectBeforeDestroyOptions.md)]) => void): void - Inherited from WithFn.onBeforeObjectDestroy ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L628)onObjectCreated * **onObjectCreated(fn: (...args: \[ins: unknown, options: [ObjectCreatedOptions](/api/core/interface/ObjectCreatedOptions.md)\]) => void): void - Inherited from WithFn.onObjectCreated ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L629)onObjectInit * **onObjectInit(fn: (...args: \[ins: unknown, options: [ObjectInitOptions](/api/core/interface/ObjectInitOptions.md)]) => void): void - Inherited from WithFn.onObjectInit ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L774)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void - Inherited from IMidwayContainer.registerObject ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L779)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void - Inherited from IMidwayContainer.removeObject ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L785)setAttr * **setAttr(key: string, value: any): void - Inherited from IMidwayContainer.setAttr Set value to app attribute map ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L764)stop * **stop(): Promise\ --- # IMidwayRequestContainer Abstract Object Factory 对象容器抽象 ### Hierarchy * [IMidwayContainer](/api/core/interface/IMidwayContainer.md) * *IMidwayRequestContainer* ### Implemented by * [MidwayRequestContainer](/api/core/class/MidwayRequestContainer.md) ## Index[**](#Index) ### Properties * [**parent](#parent) * [**registry](#registry) ### Methods * [**get](#get) * [**getAsync](#getAsync) * [**getAttr](#getAttr) * [**getContext](#getContext) * [**getDefinition](#getDefinition) * [**getIdentifier](#getIdentifier) * [**getInstanceScope](#getInstanceScope) * [**getObject](#getObject) * [**hasDefinition](#hasDefinition) * [**hasNamespace](#hasNamespace) * [**hasObject](#hasObject) * [**registerObject](#registerObject) * [**removeObject](#removeObject) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#parent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L769)parent **parent: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L587)registry **registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) Inherited from IMidwayContainer.registry ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L588)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - Inherited from IMidwayContainer.get #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L589)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - Inherited from IMidwayContainer.getAsync #### Type parameters * **T** ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L790)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContainer.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L770)getContext * **getContext(): [Context](/api/core/interface/Context.md) ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L776)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) - Inherited from IMidwayContainer.getDefinition ### [**](#getIdentifier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L794)getIdentifier * **getIdentifier(identifier: string | [ClassType](/api/core.md#ClassType)\): string - Inherited from IMidwayContainer.getIdentifier Get IoC identifier ### [**](#getInstanceScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L799)getInstanceScope * **getInstanceScope(instance: any): [ScopeEnum](/api/core/enum/ScopeEnum.md) - Inherited from IMidwayContainer.getInstanceScope Get instance IoC container scope ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L778)getObject * **getObject\(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): T - Inherited from IMidwayContainer.getObject #### Type parameters * **T** ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L775)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from IMidwayContainer.hasDefinition ### [**](#hasNamespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L800)hasNamespace * **hasNamespace(namespace: string): boolean - Inherited from IMidwayContainer.hasNamespace ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L777)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean - Inherited from IMidwayContainer.hasObject ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L774)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): void - Inherited from IMidwayContainer.registerObject ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L779)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void - Inherited from IMidwayContainer.removeObject ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L785)setAttr * **setAttr(key: string, value: any): void - Inherited from IMidwayContainer.setAttr Set value to app attribute map --- # InjectionConfigurationOptions ## Index[**](#Index) ### Properties * [**detector](#detector) * [**importConfigFilter](#importConfigFilter) * [**importConfigs](#importConfigs) * [**importObjects](#importObjects) * [**imports](#imports) * [**namespace](#namespace) ## Properties[**](#Properties) ### [**](#detector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1287)optionaldetector **detector? : false | [IFileDetector](/api/core/interface/IFileDetector.md) ### [**](#importConfigFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1285)optionalimportConfigFilter **importConfigFilter? : (config: Record\) => Record\ ### [**](#importConfigs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1282)optionalimportConfigs **importConfigs? : Record\ | {}\[] ### [**](#importObjects)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1281)optionalimportObjects **importObjects? : Record\ ### [**](#imports)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1276)optionalimports **imports? : ([IComponentInfo](/api/core/interface/IComponentInfo.md) | FunctionalConfiguration | { Configuration: [ClassType](/api/core.md#ClassType)<[ILifeCycle](/api/core/interface/ILifeCycle.md)> })\[] ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1286)optionalnamespace **namespace? : string --- # IObjectCreator ## Index[**](#Index) ### Properties * [**type](#type) ### Methods * [**doConstruct](#doConstruct) * [**doDestroy](#doDestroy) * [**doDestroyAsync](#doDestroyAsync) * [**doInit](#doInit) * [**doInitAsync](#doInitAsync) * [**load](#load) ## Properties[**](#Properties) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L681)type **type: string ## Methods[**](#Methods) ### [**](#doConstruct)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L683)doConstruct * **doConstruct(Clzz: any, args? : any\[]): any ### [**](#doDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L686)doDestroy * **doDestroy(obj: any): void ### [**](#doDestroyAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L687)doDestroyAsync * **doDestroyAsync(obj: any): Promise\ ### [**](#doInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L684)doInit * **doInit(obj: any, context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): any ### [**](#doInitAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L685)doInitAsync * **doInitAsync(obj: any, context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md)): Promise\ ### [**](#load)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L682)load * **load(): any --- # IObjectDefinition Object Definition 对象描述定义 ## Index[**](#Index) ### Properties * [**allowDowngrade](#allowDowngrade) * [**bindHook](#bindHook) * [**constructMethod](#constructMethod) * [**constructorArgs](#constructorArgs) * [**createFrom](#createFrom) * [**creator](#creator) * [**dependsOn](#dependsOn) * [**destroyMethod](#destroyMethod) * [**export](#export) * [**handlerProps](#handlerProps) * [**id](#id) * [**initMethod](#initMethod) * [**name](#name) * [**namespace](#namespace) * [**path](#path) * [**properties](#properties) * [**scope](#scope) * [**srcPath](#srcPath) ### Methods * [**getAttr](#getAttr) * [**hasAttr](#hasAttr) * [**hasConstructorArgs](#hasConstructorArgs) * [**hasDependsOn](#hasDependsOn) * [**isAsync](#isAsync) * [**isRequestScope](#isRequestScope) * [**isSingletonScope](#isSingletonScope) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#allowDowngrade)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L676)allowDowngrade **allowDowngrade: boolean ### [**](#bindHook)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L677)optionalbindHook **bindHook? : (module: any, options? : [IObjectDefinition](/api/core/interface/IObjectDefinition.md)) => void ### [**](#constructMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L644)constructMethod **constructMethod: string ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L649)constructorArgs **constructorArgs: [ConstructorInjectMetadata](/api/core/interface/ConstructorInjectMetadata.md)\[] ### [**](#createFrom)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L675)createFrom **createFrom: file | framework | module ### [**](#creator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L639)creator **creator: [IObjectCreator](/api/core/interface/IObjectCreator.md) ### [**](#dependsOn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L648)dependsOn **dependsOn: [ObjectIdentifier](/api/core.md#ObjectIdentifier)\[] ### [**](#destroyMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L643)destroyMethod **destroyMethod: string ### [**](#export)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L647)export **export: string ### [**](#handlerProps)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L661)handlerProps **handlerProps: { key: string; metadata: any; propertyName: string }\[] ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L640)id **id: string ### [**](#initMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L642)initMethod **initMethod: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L641)name **name: string ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L638)optionalnamespace **namespace? : string ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L646)path **path: any ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L650)properties **properties: Map\ ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L651)scope **scope: [ScopeEnum](/api/core/enum/ScopeEnum.md) ### [**](#srcPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L645)srcPath **srcPath: string ## Methods[**](#Methods) ### [**](#getAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L657)getAttr * **getAttr(key: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): any ### [**](#hasAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L658)hasAttr * **hasAttr(key: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#hasConstructorArgs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L656)hasConstructorArgs * **hasConstructorArgs(): boolean ### [**](#hasDependsOn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L655)hasDependsOn * **hasDependsOn(): boolean ### [**](#isAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L652)isAsync * **isAsync(): boolean ### [**](#isRequestScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L654)isRequestScope * **isRequestScope(): boolean ### [**](#isSingletonScope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L653)isSingletonScope * **isSingletonScope(): boolean ### [**](#setAttr)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L659)setAttr * **setAttr(key: [ObjectIdentifier](/api/core.md#ObjectIdentifier), value: any): void --- # IObjectDefinitionRegistry Object Definition Registry 对象定义存储容器 ## Index[**](#Index) ### Properties * [**count](#count) * [**identifiers](#identifiers) ### Methods * [**clearAll](#clearAll) * [**getDefinition](#getDefinition) * [**getDefinitionByName](#getDefinitionByName) * [**getIdentifierRelation](#getIdentifierRelation) * [**getObject](#getObject) * [**getSingletonDefinitionIds](#getSingletonDefinitionIds) * [**hasDefinition](#hasDefinition) * [**hasObject](#hasObject) * [**registerDefinition](#registerDefinition) * [**registerObject](#registerObject) * [**removeDefinition](#removeDefinition) * [**removeObject](#removeObject) * [**setIdentifierRelation](#setIdentifierRelation) ## Properties[**](#Properties) ### [**](#count)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L695)readonlycount **count: number ### [**](#identifiers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L694)readonlyidentifiers **identifiers: [ObjectIdentifier](/api/core.md#ObjectIdentifier)\[] ## Methods[**](#Methods) ### [**](#clearAll)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L705)clearAll * **clearAll(): void ### [**](#getDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L701)getDefinition * **getDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): [IObjectDefinition](/api/core/interface/IObjectDefinition.md) ### [**](#getDefinitionByName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L702)getDefinitionByName * **getDefinitionByName(name: string): [IObjectDefinition](/api/core/interface/IObjectDefinition.md)\[] ### [**](#getIdentifierRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L710)getIdentifierRelation * **getIdentifierRelation(): [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md) ### [**](#getObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L709)getObject * **getObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): any ### [**](#getSingletonDefinitionIds)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L700)getSingletonDefinitionIds * **getSingletonDefinitionIds(): [ObjectIdentifier](/api/core.md#ObjectIdentifier)\[] ### [**](#hasDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L704)hasDefinition * **hasDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#hasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L706)hasObject * **hasObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): boolean ### [**](#registerDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L696)registerDefinition * **registerDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md)): any ### [**](#registerObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L707)registerObject * **registerObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier), target: any): any ### [**](#removeDefinition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L703)removeDefinition * **removeDefinition(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void ### [**](#removeObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L708)removeObject * **removeObject(identifier: [ObjectIdentifier](/api/core.md#ObjectIdentifier)): void ### [**](#setIdentifierRelation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L711)setIdentifierRelation * **setIdentifierRelation(identifierRelation: [IIdentifierRelationShip](/api/core/interface/IIdentifierRelationShip.md)): any --- # IObjectFactory Abstract Object Factory 对象容器抽象 ### Hierarchy * *IObjectFactory* * [IMidwayContainer](/api/core/interface/IMidwayContainer.md) ## Index[**](#Index) ### Properties * [**registry](#registry) ### Methods * [**get](#get) * [**getAsync](#getAsync) ## Properties[**](#Properties) ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L587)registry **registry: [IObjectDefinitionRegistry](/api/core/interface/IObjectDefinitionRegistry.md) ## Methods[**](#Methods) ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L588)get * **get\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): T - #### Type parameters * **T** ### [**](#getAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L589)getAsync * **getAsync\(identifier: string | [ClassType](/api/core.md#ClassType)\, args? : any\[]): Promise\ - #### Type parameters * **T** --- # IObjectLifeCycle Object Lifecycle 对象生命周期 ## Index[**](#Index) ### Methods * [**onBeforeBind](#onBeforeBind) * [**onBeforeObjectCreated](#onBeforeObjectCreated) * [**onBeforeObjectDestroy](#onBeforeObjectDestroy) * [**onObjectCreated](#onObjectCreated) * [**onObjectInit](#onObjectInit) ## Methods[**](#Methods) ### [**](#onBeforeBind)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L626)onBeforeBind * **onBeforeBind(Clzz: any, options: [ObjectBeforeBindOptions](/api/core/interface/ObjectBeforeBindOptions.md)): void ### [**](#onBeforeObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L627)onBeforeObjectCreated * **onBeforeObjectCreated(Clzz: any, options: [ObjectBeforeCreatedOptions](/api/core/interface/ObjectBeforeCreatedOptions.md)): void ### [**](#onBeforeObjectDestroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L630)onBeforeObjectDestroy * **onBeforeObjectDestroy\(ins: T, options: [ObjectBeforeDestroyOptions](/api/core/interface/ObjectBeforeDestroyOptions.md)): void - #### Type parameters * **T** ### [**](#onObjectCreated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L628)onObjectCreated * **onObjectCreated\(ins: T, options: [ObjectCreatedOptions](/api/core/interface/ObjectCreatedOptions.md)\): void - #### Type parameters * **T** ### [**](#onObjectInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L629)onObjectInit * **onObjectInit\(ins: T, options: [ObjectInitOptions](/api/core/interface/ObjectInitOptions.md)): void - #### Type parameters * **T** --- # IServiceDiscoveryClient \ ### Implemented by * [ServiceDiscoveryClient](/api/core/class/ServiceDiscoveryClient.md) ## Index[**](#Index) ### Methods * [**offline](#offline) * [**online](#online) * [**register](#register) ## Methods[**](#Methods) ### [**](#offline)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1446)offline * **offline(): Promise\ - 下线服务实例 ### [**](#online)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1442)online * **online(): Promise\ - 上线服务实例 ### [**](#register)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1438)register * **register(instance: unknown): Promise\ - 注册服务实例 --- # IServiceDiscoveryHealthCheck \ ## Index[**](#Index) ### Methods * [**check](#check) ## Methods[**](#Methods) ### [**](#check)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1411)check * **check(instance: ServiceInstance): Promise<[ServiceDiscoveryHealthCheckResult](/api/core/interface/ServiceDiscoveryHealthCheckResult.md)> --- # IServiceFactory \ ### Implemented by * [ServiceFactory](/api/core/class/ServiceFactory.md) ## Index[**](#Index) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1186)createInstance * **createInstance(config: any, clientId? : string): Promise\ ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1184)get * **get(clientId: string): Client ### [**](#getClientKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1191)getClientKeys * **getClientKeys(): string\[] ### [**](#getClientPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1192)getClientPriority * **getClientPriority(clientName: string): string ### [**](#getClients)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1190)getClients * **getClients(): Map\ ### [**](#getDefaultClientName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1189)getDefaultClientName * **getDefaultClientName(): string ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1187)getName * **getName(): string ### [**](#has)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1185)has * **has(clientId: string): boolean ### [**](#isHighPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1193)isHighPriority * **isHighPriority(clientName: string): boolean ### [**](#isLowPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1195)isLowPriority * **isLowPriority(clientName: string): boolean ### [**](#isMediumPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1194)isMediumPriority * **isMediumPriority(clientName: string): boolean ### [**](#stop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1188)stop * **stop(): Promise\ --- # ISimulation ## Index[**](#Index) ### Methods * [**appSetup](#appSetup) * [**appTearDown](#appTearDown) * [**contextSetup](#contextSetup) * [**contextTearDown](#contextTearDown) * [**enableCondition](#enableCondition) * [**setup](#setup) * [**tearDown](#tearDown) ## Methods[**](#Methods) ### [**](#appSetup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1216)optionalappSetup * **appSetup(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#appTearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1219)optionalappTearDown * **appTearDown(app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#contextSetup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1217)optionalcontextSetup * **contextSetup(ctx: [Context](/api/core/interface/Context.md), app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#contextTearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1218)optionalcontextTearDown * **contextTearDown(ctx: [Context](/api/core/interface/Context.md), app: [IMidwayBaseApplication](/api/core/interface/IMidwayBaseApplication.md)<[Context](/api/core/interface/Context.md)>): Promise\ ### [**](#enableCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1220)enableCondition * **enableCondition(): boolean | Promise\ ### [**](#setup)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1214)optionalsetup * **setup(): Promise\ ### [**](#tearDown)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1215)optionaltearDown * **tearDown(): Promise\ --- # JoinPoint ## Index[**](#Index) ### Properties * [**args](#args) * [**methodName](#methodName) * [**proceedIsAsyncFunction](#proceedIsAsyncFunction) * [**target](#target) ### Methods * [**proceed](#proceed) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L313)args **args: any\[] ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L311)methodName **methodName: string ### [**](#proceedIsAsyncFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L315)optionalproceedIsAsyncFunction **proceedIsAsyncFunction? : boolean ### [**](#target)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L312)target **target: any ## Methods[**](#Methods) ### [**](#proceed)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L314)optionalproceed * **proceed(...args: any\[]): any --- # KafkaListenerOptions ## Index[**](#Index) ### Properties * [**propertyKey](#propertyKey) * [**runConfig](#runConfig) * [**subscription](#subscription) * [**topic](#topic) ## Properties[**](#Properties) ### [**](#propertyKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L23)optionalpropertyKey **propertyKey? : string ### [**](#runConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L27)optionalrunConfig **runConfig? : [ConsumerRunConfig](/api/core.md#ConsumerRunConfig) ### [**](#subscription)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L26)optionalsubscription **subscription? : [ConsumerSubscribeTopic](/api/core.md#ConsumerSubscribeTopic) | [ConsumerSubscribeTopics](/api/core.md#ConsumerSubscribeTopics) ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/kafkaListener.ts#L24)optionaltopic **topic? : string --- # LifeCycleInvokeOptions ## Index[**](#Index) ### Properties * [**abortController](#abortController) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#abortController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L546)abortController **abortController: AbortController ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L547)timeout **timeout: number --- # MethodDecoratorMetaData \ ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**options](#options) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L370)key **key: string decorator key ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L371)metadata **metadata: Metadata ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L372)options **options: [MethodDecoratorOptions](/api/core/interface/MethodDecoratorOptions.md) ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L368)propertyName **propertyName: string --- # MethodDecoratorOptions ## Index[**](#Index) ### Properties * [**impl](#impl) ## Properties[**](#Properties) ### [**](#impl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L376)optionalimpl **impl? : boolean --- # MidwayAppInfo ## Index[**](#Index) ### Properties * [**HOME](#HOME) * [**appDir](#appDir) * [**baseDir](#baseDir) * [**env](#env) * [**name](#name) * [**pkg](#pkg) * [**root](#root) ## Properties[**](#Properties) ### [**](#HOME)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1171)HOME **HOME: string ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1170)appDir **appDir: string ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1169)baseDir **baseDir: string ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1173)env **env: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1168)name **name: string ### [**](#pkg)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1167)pkg **pkg: Record\ ### [**](#root)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1172)root **root: string --- # MidwayConfig midway global config definition ### Hierarchy * [FileConfigOption](/api/core.md#FileConfigOption)<[MidwayCoreDefaultConfig](/api/core/interface/MidwayCoreDefaultConfig.md)> * *MidwayConfig* ### Indexable **\[customConfigKey : string]: unknown ## Index[**](#Index) ### Properties * [**asyncContextManager](#asyncContextManager) * [**core](#core) * [**debug](#debug) * [**midwayLogger](#midwayLogger) * [**tracing](#tracing) ## Properties[**](#Properties) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L441)optionalasyncContextManager **asyncContextManager? : [PowerPartial](/api/core.md#PowerPartial)<{ enable? : boolean }> Inherited from FileConfigOption.asyncContextManager ### [**](#core)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L444)optionalcore **core? : [PowerPartial](/api/core.md#PowerPartial)<{ configLoadTimeout? : number; healthCheckTimeout? : number; readyTimeout? : number; serverReadyTimeout? : number; stopTimeout? : number }> Inherited from FileConfigOption.core ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L438)optionaldebug **debug? : [PowerPartial](/api/core.md#PowerPartial)<{ recordConfigMergeOrder? : boolean }> Inherited from FileConfigOption.debug ### [**](#midwayLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L437)optionalmidwayLogger **midwayLogger? : [PowerPartial](/api/core.md#PowerPartial)<[ServiceFactoryConfigOption](/api/core.md#ServiceFactoryConfigOption)<[MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)>> Inherited from FileConfigOption.midwayLogger ### [**](#tracing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L451)optionaltracing **tracing? : [PowerPartial](/api/core.md#PowerPartial)<{ enable? : boolean; logOnError? : boolean; onError? : throw | ignore }> Inherited from FileConfigOption.tracing --- # MidwayCoreDefaultConfig ## Index[**](#Index) ### Properties * [**asyncContextManager](#asyncContextManager) * [**core](#core) * [**debug](#debug) * [**midwayLogger](#midwayLogger) * [**tracing](#tracing) ## Properties[**](#Properties) ### [**](#asyncContextManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L441)optionalasyncContextManager **asyncContextManager? : { enable? : boolean } ### [**](#core)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L444)optionalcore **core? : { configLoadTimeout? : number; healthCheckTimeout? : number; readyTimeout? : number; serverReadyTimeout? : number; stopTimeout? : number } ### [**](#debug)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L438)optionaldebug **debug? : { recordConfigMergeOrder? : boolean } ### [**](#midwayLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L437)optionalmidwayLogger **midwayLogger? : [ServiceFactoryConfigOption](/api/core.md#ServiceFactoryConfigOption)<[MidwayLoggerOptions](/api/core/interface/MidwayLoggerOptions.md)> ### [**](#tracing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L451)optionaltracing **tracing? : { enable? : boolean; logOnError? : boolean; onError? : throw | ignore } --- # MidwayLoggerOptions Logger Options for midway, you can merge this interface in package * **@example** ``` import { LoggerOptions } from '@midwayjs/logger'; declare module '@midwayjs/core' { interface MidwayLoggerOptions extends LoggerOptions { logDir?: string; level?: string; } } ``` ### Indexable **\[key : string]: any ## Index[**](#Index) ### Properties * [**aliasName](#aliasName) * [**lazyLoad](#lazyLoad) ## Properties[**](#Properties) ### [**](#aliasName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L432)optionalaliasName **aliasName? : string ### [**](#lazyLoad)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L431)optionallazyLoad **lazyLoad? : boolean --- # ObjectBeforeBindOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeBindOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) * [**replaceCallback](#replaceCallback) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L601)context **context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L602)definition **definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition ### [**](#replaceCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L606)replaceCallback **replaceCallback: (newDefinition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md)) => void --- # ObjectBeforeCreatedOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeCreatedOptions* ## Index[**](#Index) ### Properties * [**constructorArgs](#constructorArgs) * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L610)constructorArgs **constructorArgs: any\[] ### [**](#context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L601)context **context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L602)definition **definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ObjectBeforeDestroyOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectBeforeDestroyOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L601)context **context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L602)definition **definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ObjectCreatedOptions \ ### Hierarchy * ObjectLifeCycleOptions * *ObjectCreatedOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) * [**replaceCallback](#replaceCallback) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L601)context **context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L602)definition **definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition ### [**](#replaceCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L614)replaceCallback **replaceCallback: (ins: T) => void --- # ObjectDefinitionOptions ## Index[**](#Index) ### Properties * [**allowDowngrade](#allowDowngrade) * [**constructorArgs](#constructorArgs) * [**destroyMethod](#destroyMethod) * [**initMethod](#initMethod) * [**isAsync](#isAsync) * [**namespace](#namespace) * [**scope](#scope) * [**srcPath](#srcPath) ## Properties[**](#Properties) ### [**](#allowDowngrade)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L96)optionalallowDowngrade **allowDowngrade? : boolean ### [**](#constructorArgs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L93)optionalconstructorArgs **constructorArgs? : any\[] ### [**](#destroyMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L91)optionaldestroyMethod **destroyMethod? : string ### [**](#initMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L90)optionalinitMethod **initMethod? : string ### [**](#isAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L89)optionalisAsync **isAsync? : boolean ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L94)optionalnamespace **namespace? : string ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L92)optionalscope **scope? : [ScopeEnum](/api/core/enum/ScopeEnum.md) ### [**](#srcPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L95)optionalsrcPath **srcPath? : string --- # ObjectInitOptions ### Hierarchy * ObjectLifeCycleOptions * *ObjectInitOptions* ## Index[**](#Index) ### Properties * [**context](#context) * [**definition](#definition) ## Properties[**](#Properties) ### [**](#context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L601)context **context: [IMidwayContainer](/api/core/interface/IMidwayContainer.md) Inherited from ObjectLifeCycleOptions.context ### [**](#definition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L602)definition **definition: [IObjectDefinition](/api/core/interface/IObjectDefinition.md) Inherited from ObjectLifeCycleOptions.definition --- # ParamDecoratorOptions ## Index[**](#Index) ### Properties * [**impl](#impl) * [**pipes](#pipes) * [**throwError](#throwError) ## Properties[**](#Properties) ### [**](#impl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L388)optionalimpl **impl? : boolean ### [**](#pipes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L390)optionalpipes **pipes? : [PipeUnionTransform](/api/core.md#PipeUnionTransform)\\[] ### [**](#throwError)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L389)optionalthrowError **throwError? : boolean --- # ParameterDecoratorMetaData \ ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**options](#options) * [**parameterIndex](#parameterIndex) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L380)key **key: string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L383)metadata **metadata: Metadata ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L384)options **options: [ParamDecoratorOptions](/api/core/interface/ParamDecoratorOptions.md) ### [**](#parameterIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L381)parameterIndex **parameterIndex: number ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L382)propertyName **propertyName: string --- # PipeTransform \ ## Index[**](#Index) ### Methods * [**transform](#transform) ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L352)transform * **transform(value: T, transformOptions: [TransformOptions](/api/core/interface/TransformOptions.md)\): R --- # PropertyDecoratorOptions ## Index[**](#Index) ### Properties * [**allowMulti](#allowMulti) * [**impl](#impl) ## Properties[**](#Properties) ### [**](#allowMulti)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L364)optionalallowMulti **allowMulti? : boolean ### [**](#impl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L363)optionalimpl **impl? : boolean --- # PropertyInjectMetadata Metadata when using * **@Inject** property injection ### Hierarchy * *PropertyInjectMetadata* * [ConstructorInjectMetadata](/api/core/interface/ConstructorInjectMetadata.md) ## Index[**](#Index) ### Properties * [**args](#args) * [**id](#id) * [**injectMode](#injectMode) * [**isLazyInject](#isLazyInject) * [**name](#name) * [**targetKey](#targetKey) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L73)args **args: any\[] ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L74)id **id: [ObjectIdentifier](/api/core.md#ObjectIdentifier) | () => ObjectIdentifier | ClassType\ ### [**](#injectMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L76)injectMode **injectMode: [InjectModeEnum](/api/core/enum/InjectModeEnum.md) ### [**](#isLazyInject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L78)isLazyInject **isLazyInject: boolean ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L75)name **name: string ### [**](#targetKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L77)targetKey **targetKey: string --- # RabbitMQListenerOptions ## Index[**](#Index) ### Properties * [**autoDelete](#autoDelete) * [**consumeOptions](#consumeOptions) * [**deadLetterExchange](#deadLetterExchange) * [**deadLetterRoutingKey](#deadLetterRoutingKey) * [**durable](#durable) * [**exchange](#exchange) * [**exchangeOptions](#exchangeOptions) * [**exclusive](#exclusive) * [**expires](#expires) * [**maxLength](#maxLength) * [**maxPriority](#maxPriority) * [**messageTtl](#messageTtl) * [**pattern](#pattern) * [**prefetch](#prefetch) * [**propertyKey](#propertyKey) * [**queueName](#queueName) * [**routingKey](#routingKey) ## Properties[**](#Properties) ### [**](#autoDelete)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L13)optionalautoDelete **autoDelete? : boolean ### [**](#consumeOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L43)optionalconsumeOptions **consumeOptions? : { arguments? : any; consumerTag? : string; exclusive? : boolean; noAck? : boolean; noLocal? : boolean; priority? : number } consumeOptions ### [**](#deadLetterExchange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L16)optionaldeadLetterExchange **deadLetterExchange? : string ### [**](#deadLetterRoutingKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L17)optionaldeadLetterRoutingKey **deadLetterRoutingKey? : string ### [**](#durable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L12)optionaldurable **durable? : boolean ### [**](#exchange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L7)optionalexchange **exchange? : string ### [**](#exchangeOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L32)optionalexchangeOptions **exchangeOptions? : { alternateExchange? : string; arguments? : any; autoDelete? : boolean; durable? : boolean; internal? : boolean; type? : string } exchange options ### [**](#exclusive)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L11)optionalexclusive **exclusive? : boolean queue options ### [**](#expires)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L15)optionalexpires **expires? : number ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L18)optionalmaxLength **maxLength? : number ### [**](#maxPriority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L19)optionalmaxPriority **maxPriority? : number ### [**](#messageTtl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L14)optionalmessageTtl **messageTtl? : number ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L20)optionalpattern **pattern? : string ### [**](#prefetch)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L24)optionalprefetch **prefetch? : number prefetch ### [**](#propertyKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L5)optionalpropertyKey **propertyKey? : string ### [**](#queueName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L6)optionalqueueName **queueName? : string ### [**](#routingKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/microservice/rabbitmqListener.ts#L28)optionalroutingKey **routingKey? : string router --- # ReflectResult ### Indexable **\[key : string]: any\[] --- # RouterCollectorOptions ## Index[**](#Index) ### Properties * [**globalPrefix](#globalPrefix) * [**includeFunctionRouter](#includeFunctionRouter) ## Properties[**](#Properties) ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L190)optionalglobalPrefix **globalPrefix? : string ### [**](#includeFunctionRouter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L189)optionalincludeFunctionRouter **includeFunctionRouter? : boolean --- # RouterInfo ## Index[**](#Index) ### Properties * [**controllerClz](#controllerClz) * [**controllerId](#controllerId) * [**controllerMiddleware](#controllerMiddleware) * [**description](#description) * [**fullUrl](#fullUrl) * [**fullUrlCompiledRegexp](#fullUrlCompiledRegexp) * [**fullUrlFlattenString](#fullUrlFlattenString) * [**funcHandlerName](#funcHandlerName) * [**functionMetadata](#functionMetadata) * [**functionName](#functionName) * [**functionTriggerMetadata](#functionTriggerMetadata) * [**functionTriggerName](#functionTriggerName) * [**handlerName](#handlerName) * [**id](#id) * [**ignoreGlobalPrefix](#ignoreGlobalPrefix) * [**method](#method) * [**middleware](#middleware) * [**prefix](#prefix) * [**requestMetadata](#requestMetadata) * [**requestMethod](#requestMethod) * [**responseMetadata](#responseMetadata) * [**routerName](#routerName) * [**source](#source) * [**summary](#summary) * [**url](#url) * [**version](#version) * [**versionPrefix](#versionPrefix) * [**versionType](#versionType) ## Properties[**](#Properties) ### [**](#controllerClz)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L78)optionalcontrollerClz **controllerClz? : new (...args: any\[]) => any controller class ### [**](#controllerId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L74)optionalcontrollerId **controllerId? : string controller provideId ### [**](#controllerMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L86)optionalcontrollerMiddleware **controllerMiddleware? : any\[] controller middleware in this router ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L58)optionaldescription **description? : string router description ### [**](#fullUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L115)optionalfullUrl **fullUrl? : string url with prefix ### [**](#fullUrlCompiledRegexp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L120)optionalfullUrlCompiledRegexp **fullUrlCompiledRegexp? : RegExp pattern after path-regexp compile ### [**](#fullUrlFlattenString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L125)optionalfullUrlFlattenString **fullUrlFlattenString? : string url after wildcard and can be path-to-regexp by path-to-regexp v6 ### [**](#funcHandlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L70)optionalfuncHandlerName **funcHandlerName? : string serverless func load key, will be override by * **@ServerlessTrigger** and * **@ServerlessFunction** ### [**](#functionMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L110)optionalfunctionMetadata **functionMetadata? : any serverless function metadata ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L98)optionalfunctionName **functionName? : string serverless function name, will be override by * **@ServerlessTrigger** and * **@ServerlessFunction** ### [**](#functionTriggerMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L106)optionalfunctionTriggerMetadata **functionTriggerMetadata? : any serverless function trigger metadata ### [**](#functionTriggerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L102)optionalfunctionTriggerName **functionTriggerName? : string serverless trigger name ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L66)optionalhandlerName **handlerName? : string router handler function key,for IoC container load ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L34)optionalid **id? : string uuid ### [**](#ignoreGlobalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L150)optionalignoreGlobalPrefix **ignoreGlobalPrefix? : boolean route-level ignore global prefix ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L54)method **method: string | (...args: any\[]) => void invoke function method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L82)optionalmiddleware **middleware? : any\[] router middleware ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L38)optionalprefix **prefix? : string router prefix from controller ### [**](#requestMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L90)optionalrequestMetadata **requestMetadata? : any\[] request args metadata ### [**](#requestMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L50)requestMethod **requestMethod: string request method for http, like get/post/delete ### [**](#responseMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L94)optionalresponseMetadata **responseMetadata? : any\[] response data metadata ### [**](#routerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L42)optionalrouterName **routerName? : string router alias name ### [**](#source)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L145)optionalsource **source? : functional | decorator route definition source ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L62)optionalsummary **summary? : string * **@deprecated** ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L46)url **url: string | RegExp router path, without prefix ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L130)optionalversion **version? : string | string\[] version information for API versioning ### [**](#versionPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L140)optionalversionPrefix **versionPrefix? : string version prefix for URI versioning ### [**](#versionType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L135)optionalversionType **versionType? : URI | HEADER | MEDIA\_TYPE | CUSTOM version type for API versioning --- # RouterOption ## Index[**](#Index) ### Properties * [**\_\_ignoreGlobalPrefixConfigured](#__ignoreGlobalPrefixConfigured) * [**description](#description) * [**ignoreGlobalPrefix](#ignoreGlobalPrefix) * [**method](#method) * [**middleware](#middleware) * [**path](#path) * [**requestMethod](#requestMethod) * [**routerName](#routerName) * [**summary](#summary) ## Properties[**](#Properties) ### [**](#__ignoreGlobalPrefixConfigured)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L46)optional\_\_ignoreGlobalPrefixConfigured **\_\_ignoreGlobalPrefixConfigured? : boolean internal flag for whether ignoreGlobalPrefix is explicitly configured on route ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L38)optionaldescription **description? : string router description, for swagger * **@deprecated** ### [**](#ignoreGlobalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L42)optionalignoreGlobalPrefix **ignoreGlobalPrefix? : boolean ignore global prefix ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L24)optionalmethod **method? : string which method decorator attached ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L28)optionalmiddleware **middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) middleware array in router ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L12)optionalpath **path? : string | RegExp router path, like "/api" ### [**](#requestMethod)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L16)requestMethod **requestMethod: string http method, like "get", "post" ### [**](#routerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L20)optionalrouterName **routerName? : string router alias name ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/requestMapping.ts#L33)optionalsummary **summary? : string router summary, for swagger * **@deprecated** --- # RouterParamValue ## Index[**](#Index) ### Properties * [**index](#index) * [**propertyData](#propertyData) * [**type](#type) ## Properties[**](#Properties) ### [**](#index)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L25)index **index: number ### [**](#propertyData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L27)optionalpropertyData **propertyData? : any ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/web/paramMapping.ts#L26)type **type: [RouteParamTypes](/api/core/enum/RouteParamTypes.md) --- # RouterPriority ## Index[**](#Index) ### Properties * [**controllerId](#controllerId) * [**middleware](#middleware) * [**prefix](#prefix) * [**priority](#priority) * [**routerModule](#routerModule) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#controllerId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L181)controllerId **controllerId: string ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L179)middleware **middleware: any\[] ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L177)prefix **prefix: string ### [**](#priority)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L178)priority **priority: number ### [**](#routerModule)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L185)routerModule **routerModule: any 路由控制器或者函数 module 本身 ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/service/webRouterService.ts#L180)routerOptions **routerOptions: any --- # ScheduleOpts ## Index[**](#Index) ### Properties * [**cron](#cron) * [**cronOptions](#cronOptions) * [**disable](#disable) * [**env](#env) * [**immediate](#immediate) * [**interval](#interval) * [**type](#type) ## Properties[**](#Properties) ### [**](#cron)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L11)optionalcron **cron? : string ### [**](#cronOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L16)optionalcronOptions **cronOptions? : { currentDate? : string | number | Date; endDate? : string | number | Date; iterator? : boolean; startDate? : string | number | Date; tz? : string; utc? : boolean } ### [**](#disable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L14)optionaldisable **disable? : boolean ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L15)optionalenv **env? : string\[] ### [**](#immediate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L13)optionalimmediate **immediate? : boolean ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L12)optionalinterval **interval? : string | number ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/task/schedule.ts#L10)type **type: string --- # ServerSendEventMessage ## Index[**](#Index) ### Properties * [**data](#data) * [**event](#event) * [**id](#id) * [**retry](#retry) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1255)optionaldata **data? : string | object ### [**](#event)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1256)optionalevent **event? : string ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1257)optionalid **id? : string ### [**](#retry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1258)optionalretry **retry? : number --- # ServerSendEventStreamOptions \ ## Index[**](#Index) ### Properties * [**closeEvent](#closeEvent) * [**tpl](#tpl) ## Properties[**](#Properties) ### [**](#closeEvent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1266)optionalcloseEvent **closeEvent? : string ### [**](#tpl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1267)optionaltpl **tpl? : (data: [ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md), ctx: CTX) => [ServerSendEventMessage](/api/core/interface/ServerSendEventMessage.md) --- # ServerStreamOptions \ ## Index[**](#Index) ### Properties * [**tpl](#tpl) ## Properties[**](#Properties) ### [**](#tpl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1262)optionaltpl **tpl? : (data: unknown, ctx: CTX) => unknown --- # ServiceDiscoveryBaseInstance --- # ServiceDiscoveryHealthCheckResult 健康检查结果 ## Index[**](#Index) ### Properties * [**message](#message) * [**status](#status) * [**timestamp](#timestamp) ## Properties[**](#Properties) ### [**](#message)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1406)optionalmessage **message? : string ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1405)status **status: passing | warning | critical | unknown ### [**](#timestamp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1407)timestamp **timestamp: number --- # ServiceDiscoveryOptions \ ## Index[**](#Index) ### Properties * [**loadBalancer](#loadBalancer) * [**serviceDiscoveryClient](#serviceDiscoveryClient) * [**serviceOptions](#serviceOptions) ## Properties[**](#Properties) ### [**](#loadBalancer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1420)optionalloadBalancer **loadBalancer? : [LoadBalancerType](/api/core.md#LoadBalancerType) | [ILoadBalancer](/api/core/interface/ILoadBalancer.md)\ ### [**](#serviceDiscoveryClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1418)optionalserviceDiscoveryClient **serviceDiscoveryClient? : string ### [**](#serviceOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1416)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1419)serviceOptions **serviceOptions: serviceOptions --- # TagClsMetadata ## Index[**](#Index) ### Properties * [**id](#id) * [**name](#name) * [**originName](#originName) * [**uuid](#uuid) ## Properties[**](#Properties) ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L106)id **id: string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L109)name **name: string ### [**](#originName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L107)originName **originName: string ### [**](#uuid)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L108)uuid **uuid: string --- # TagPropsMetadata ## Index[**](#Index) ### Properties * [**args](#args) * [**key](#key) * [**value](#value) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L102)optionalargs **args? : any ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L100)key **key: string | number | symbol ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L101)value **value: any --- # TCPServiceDiscoveryHealthCheckOptions TCP 健康检查配置 ### Hierarchy * [BaseServiceDiscoveryHealthCheckOptions](/api/core/interface/BaseServiceDiscoveryHealthCheckOptions.md) * *TCPServiceDiscoveryHealthCheckOptions* ## Index[**](#Index) ### Properties * [**host](#host) * [**interval](#interval) * [**maxRetries](#maxRetries) * [**port](#port) * [**retryInterval](#retryInterval) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1376)host **host: string 主机地址 ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1322)optionalinterval **interval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.interval 检查间隔(毫秒) ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1330)optionalmaxRetries **maxRetries? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.maxRetries 最大重试次数 ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1380)port **port: number 端口号 ### [**](#retryInterval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1334)optionalretryInterval **retryInterval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.retryInterval 重试间隔(毫秒) ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1326)optionaltimeout **timeout? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.timeout 检查超时时间(毫秒) --- # TraceMetaResolverArgs ## Index[**](#Index) ### Properties * [**carrier](#carrier) * [**ctx](#ctx) * [**custom](#custom) * [**direction](#direction) * [**error](#error) * [**protocol](#protocol) * [**request](#request) * [**response](#response) * [**span](#span) * [**spanName](#spanName) ## Properties[**](#Properties) ### [**](#carrier)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L470)optionalcarrier **carrier? : unknown ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L469)optionalctx **ctx? : unknown ### [**](#custom)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L474)optionalcustom **custom? : Record\ ### [**](#direction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L465)direction **direction: [TraceMetaDirection](/api/core.md#TraceMetaDirection) ### [**](#error)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L473)optionalerror **error? : Error ### [**](#protocol)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L466)protocol **protocol: string ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L471)optionalrequest **request? : unknown ### [**](#response)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L472)optionalresponse **response? : unknown ### [**](#span)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L468)optionalspan **span? : unknown ### [**](#spanName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L467)spanName **spanName: string --- # TransformOptions \ ## Index[**](#Index) ### Properties * [**metaType](#metaType) * [**metadata](#metadata) * [**methodName](#methodName) * [**target](#target) ## Properties[**](#Properties) ### [**](#metaType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L339)metaType **metaType: [TSDesignType](/api/core/interface/TSDesignType.md)\ ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L340)metadata **metadata: any ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L348)methodName **methodName: string the name of method ### [**](#target)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L344)target **target: any current instance --- # TSDesignType \ ## Index[**](#Index) ### Properties * [**isBaseType](#isBaseType) * [**name](#name) * [**originDesign](#originDesign) ## Properties[**](#Properties) ### [**](#isBaseType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L335)isBaseType **isBaseType: boolean ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L333)name **name: string ### [**](#originDesign)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L334)originDesign **originDesign: OriginType --- # TTLServiceDiscoveryHealthCheckOptions TTL 健康检查配置 ### Hierarchy * [BaseServiceDiscoveryHealthCheckOptions](/api/core/interface/BaseServiceDiscoveryHealthCheckOptions.md) * *TTLServiceDiscoveryHealthCheckOptions* ## Index[**](#Index) ### Properties * [**interval](#interval) * [**maxRetries](#maxRetries) * [**retryInterval](#retryInterval) * [**timeout](#timeout) * [**ttl](#ttl) ## Properties[**](#Properties) ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1322)optionalinterval **interval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.interval 检查间隔(毫秒) ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1330)optionalmaxRetries **maxRetries? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.maxRetries 最大重试次数 ### [**](#retryInterval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1334)optionalretryInterval **retryInterval? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.retryInterval 重试间隔(毫秒) ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1326)optionaltimeout **timeout? : number Inherited from BaseServiceDiscoveryHealthCheckOptions.timeout 检查超时时间(毫秒) ### [**](#ttl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L1344)ttl **ttl: number TTL 时间(秒) --- # WSControllerOption ## Index[**](#Index) ### Properties * [**namespace](#namespace) * [**routerOptions](#routerOptions) ## Properties[**](#Properties) ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketController.ts#L6)namespace **namespace: string ### [**](#routerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketController.ts#L7)routerOptions **routerOptions: { connectionMiddleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray); middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) } --- # WSEventInfo ## Index[**](#Index) ### Properties * [**descriptor](#descriptor) * [**eventOptions](#eventOptions) * [**eventType](#eventType) * [**messageEventName](#messageEventName) * [**propertyName](#propertyName) * [**roomName](#roomName) ## Properties[**](#Properties) ### [**](#descriptor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L23)descriptor **descriptor: PropertyDescriptor ### [**](#eventOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L35)optionaleventOptions **eventOptions? : { middleware? : [MiddlewareParamArray](/api/core.md#MiddlewareParamArray) } event options, like middleware ### [**](#eventType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L18)eventType **eventType: [WSEventTypeEnum](/api/core/enum/WSEventTypeEnum.md) web socket event name in enum ### [**](#messageEventName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L27)optionalmessageEventName **messageEventName? : string the event name by user definition ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L22)propertyName **propertyName: string decorator method name ### [**](#roomName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/decorator/ws/webSocketEvent.ts#L31)optionalroomName **roomName? : string\[] the room name to emit --- # ConsumerMetadata ## Index[**](#Index) ### Interfaces * [**ConsumerMetadata](/api/core/namespace/ConsumerMetadata.md#ConsumerMetadata) ## Interfaces[**](#Interfaces) ### [**](#ConsumerMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L129)ConsumerMetadata **ConsumerMetadata: ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L131)metadata **metadata: any ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L130)type **type: [MSListenerType](/api/core/enum/MSListenerType.md) --- # FaaSMetadata ## Index[**](#Index) ### Interfaces * [**APIGatewayTriggerOptions](/api/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) * [**CDNTriggerOptions](/api/core/namespace/FaaSMetadata.md#CDNTriggerOptions) * [**EventTriggerOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerOptions) * [**HSFTriggerOptions](/api/core/namespace/FaaSMetadata.md#HSFTriggerOptions) * [**HTTPTriggerOptions](/api/core/namespace/FaaSMetadata.md#HTTPTriggerOptions) * [**LogTriggerOptions](/api/core/namespace/FaaSMetadata.md#LogTriggerOptions) * [**MQTriggerOptions](/api/core/namespace/FaaSMetadata.md#MQTriggerOptions) * [**MTopTriggerOptions](/api/core/namespace/FaaSMetadata.md#MTopTriggerOptions) * [**OSTriggerOptions](/api/core/namespace/FaaSMetadata.md#OSTriggerOptions) * [**SSRTriggerOptions](/api/core/namespace/FaaSMetadata.md#SSRTriggerOptions) * [**ServerlessFunctionOptions](/api/core/namespace/FaaSMetadata.md#ServerlessFunctionOptions) * [**TimerTriggerOptions](/api/core/namespace/FaaSMetadata.md#TimerTriggerOptions) * [**TriggerMetadata](/api/core/namespace/FaaSMetadata.md#TriggerMetadata) ### Type Aliases * [**EventTriggerUnionOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ## Interfaces[**](#Interfaces) ### [**](#APIGatewayTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L232)APIGatewayTriggerOptions **APIGatewayTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L229)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L228)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#CDNTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L271)CDNTriggerOptions **CDNTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#EventTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L225)EventTriggerOptions **EventTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HSFTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L265)HSFTriggerOptions **HSFTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#HTTPTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L227)HTTPTriggerOptions **HTTPTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L229)optionalmethod **method? : get | delete | head | post | put | patch | all ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L228)path **path: string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#LogTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L243)LogTriggerOptions **LogTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#interval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L248)optionalinterval **interval? : number ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#log)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L246)log **log: string ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#project)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L245)project **project: string ### [**](#retryTime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L247)optionalretryTime **retryTime? : number ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#source)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L244)source **source: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MQTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L258)MQTriggerOptions **MQTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#region)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L261)optionalregion **region? : string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#strategy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L262)optionalstrategy **strategy? : BACKOFF\_RETRY | EXPONENTIAL\_DECAY\_RETRY ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L260)optionaltags **tags? : string ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L259)topic **topic: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#MTopTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L267)MTopTriggerOptions **MTopTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#OSTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L234)OSTriggerOptions **OSTriggerOptions: ### [**](#bucket)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L235)bucket **bucket: string ### [**](#events)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L236)events **events: string | string\[] ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L237)optionalfilter **filter? : { prefix: string; suffix: string } ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#SSRTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L269)SSRTriggerOptions **SSRTriggerOptions: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from HTTPTriggerOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from HTTPTriggerOptions.isDeploy deploy or not ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L229)optionalmethod **method? : get | delete | head | post | put | patch | all Inherited from HTTPTriggerOptions.method ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from HTTPTriggerOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from HTTPTriggerOptions.name serverless event name ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L228)path **path: string Inherited from HTTPTriggerOptions.path ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from HTTPTriggerOptions.role function invoke role, just for aliyun ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from HTTPTriggerOptions.version function publish version, just for aliyun ### [**](#ServerlessFunctionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L151)ServerlessFunctionOptions **ServerlessFunctionOptions: ### [**](#concurrency)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L179)optionalconcurrency **concurrency? : number invoke concurrency, just for aliyun ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L159)optionaldescription **description? : string function description ### [**](#environment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L187)optionalenvironment **environment? : any environment variable, key-value ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L155)optionalfunctionName **functionName? : string function name ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L195)optionalhandlerName **handlerName? : string function handler name, like 'index.handler' ### [**](#initTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L171)optionalinitTimeout **initTimeout? : number function init timeout, just for aliyun ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L191)optionalisDeploy **isDeploy? : boolean deploy or not ### [**](#memorySize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L163)optionalmemorySize **memorySize? : number function memory size, unit: M ### [**](#runtime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L175)optionalruntime **runtime? : string function runtime, nodejs10, nodejs12, nodejs14 ### [**](#stage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L183)optionalstage **stage? : string function invoke stage, like env, just for tencent ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L167)optionaltimeout **timeout? : number function timeout value, unit: seconds ### [**](#TimerTriggerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L251)TimerTriggerOptions **TimerTriggerOptions: ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L255)optionalenable **enable? : boolean ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L202)optionalfunctionName **functionName? : string Inherited from TriggerCommonOptions.functionName function name ### [**](#isDeploy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L218)optionalisDeploy **isDeploy? : boolean Inherited from TriggerCommonOptions.isDeploy deploy or not ### [**](#middleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L222)optionalmiddleware **middleware? : any\[] Inherited from TriggerCommonOptions.middleware function middleware ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L206)optionalname **name? : string Inherited from TriggerCommonOptions.name serverless event name ### [**](#payload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L254)optionalpayload **payload? : string ### [**](#role)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L210)optionalrole **role? : string Inherited from TriggerCommonOptions.role function invoke role, just for aliyun ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L252)type **type: every | cron | interval ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L253)value **value: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L214)optionalversion **version? : string Inherited from TriggerCommonOptions.version function publish version, just for aliyun ### [**](#TriggerMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L286)TriggerMetadata **TriggerMetadata: ### [**](#functionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L288)optionalfunctionName **functionName? : string ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L289)optionalhandlerName **handlerName? : string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L291)metadata **metadata: [EventTriggerUnionOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerUnionOptions) ### [**](#methodName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L290)optionalmethodName **methodName? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L287)type **type: string ## Type Aliases[**](<#Type Aliases>) ### [**](#EventTriggerUnionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L273)EventTriggerUnionOptions **EventTriggerUnionOptions: [EventTriggerOptions](/api/core/namespace/FaaSMetadata.md#EventTriggerOptions) | [HTTPTriggerOptions](/api/core/namespace/FaaSMetadata.md#HTTPTriggerOptions) | [APIGatewayTriggerOptions](/api/core/namespace/FaaSMetadata.md#APIGatewayTriggerOptions) | [OSTriggerOptions](/api/core/namespace/FaaSMetadata.md#OSTriggerOptions) | [CDNTriggerOptions](/api/core/namespace/FaaSMetadata.md#CDNTriggerOptions) | [LogTriggerOptions](/api/core/namespace/FaaSMetadata.md#LogTriggerOptions) | [TimerTriggerOptions](/api/core/namespace/FaaSMetadata.md#TimerTriggerOptions) | [MQTriggerOptions](/api/core/namespace/FaaSMetadata.md#MQTriggerOptions) | [HSFTriggerOptions](/api/core/namespace/FaaSMetadata.md#HSFTriggerOptions) | [MTopTriggerOptions](/api/core/namespace/FaaSMetadata.md#MTopTriggerOptions) | [SSRTriggerOptions](/api/core/namespace/FaaSMetadata.md#SSRTriggerOptions) --- # GRPCMetadata grpc decorator metadata format ## Index[**](#Index) ### Interfaces * [**ProviderMetadata](/api/core/namespace/GRPCMetadata.md#ProviderMetadata) * [**ProviderOptions](/api/core/namespace/GRPCMetadata.md#ProviderOptions) ## Interfaces[**](#Interfaces) ### [**](#ProviderMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L144)ProviderMetadata **ProviderMetadata: ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L146)metadata **metadata: [ProviderOptions](/api/core/namespace/GRPCMetadata.md#ProviderOptions) ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L145)type **type: [MSProviderType](/api/core/enum/MSProviderType.md) ### [**](#ProviderOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L139)ProviderOptions **ProviderOptions: ### [**](#package)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L141)optionalpackage **package? : string ### [**](#serviceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/core/src/interface.ts#L140)optionalserviceName **serviceName? : string --- # @midwayjs/cos ## Index[**](#Index) ### Classes * [**COSService](/api/cos/class/COSService.md) * [**COSServiceFactory](/api/cos/class/COSServiceFactory.md) * [**Configuration](/api/cos/class/Configuration.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [COSConfiguration](/api/cos/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/configuration.ts#L14)onReady * **onReady(container: any): Promise\ --- # COSService ### Hierarchy * COS * *COSService* ### Implements * COS ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new COSService(): [COSService](/api/cos/class/COSService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L123)init * **init(): Promise\ --- # COSServiceFactory ### Hierarchy * ServiceFactory\ * *COSServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cosConfig](#cosConfig) * [**logger](#logger) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new COSServiceFactory(): [COSServiceFactory](/api/cos/class/COSServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#cosConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L21)cosConfig **cosConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L31)logger **logger: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L45)createClient * **createClient(config: COSOptions): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = COS ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L109)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cos/src/manager.ts#L24)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # @midwayjs/cron ## Index[**](#Index) ### Classes * [**Configuration](/api/cron/class/Configuration.md) * [**Framework](/api/cron/class/Framework.md) ### Functions * [**InjectJob](/api/cron/function/InjectJob.md) * [**Job](/api/cron/function/Job.md) ### Interfaces * [**Application](/api/cron/interface/Application.md) * [**Context](/api/cron/interface/Context.md) * [**CronOptions](/api/cron/interface/CronOptions.md) * [**IJob](/api/cron/interface/IJob.md) ### Type Aliases * [**CronJobOptions](/api/cron.md#CronJobOptions) * [**JobNameOrClz](/api/cron.md#JobNameOrClz) * [**NextFunction](/api/cron.md#NextFunction) ### Variables * [**CRON\_JOB\_KEY](/api/cron.md#CRON_JOB_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#CronJobOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L10)CronJobOptions **CronJobOptions: Omit\ ### [**](#JobNameOrClz)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L27)JobNameOrClz **JobNameOrClz: string | new (...args: any) => [IJob](/api/cron/interface/IJob.md) ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L30)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#CRON_JOB_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/constants.ts#L2)constCRON\_JOB\_KEY **CRON\_JOB\_KEY: cron:job = 'cron:job' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CronConfiguration](/api/cron/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/configuration.ts#L38)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/configuration.ts#L35)framework **framework: [CronFramework](/api/cron/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/configuration.ts#L41)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/configuration.ts#L55)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/cron/interface/Application.md), [Context](/api/cron/interface/Context.md), any> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**addJob](#addJob) * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**deleteJob](#deleteJob) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getJob](#getJob) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadConfig](#loadConfig) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [CronFramework](/api/cron/class/Framework.md) - Inherited from BaseFramework\.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/cron/interface/Application.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#addJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L60)publicaddJob * **addJob(name: [JobNameOrClz](/api/cron.md#JobNameOrClz), jobOptions? : Partial\): CronJob\ ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L28)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/cron/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L38)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#deleteJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L164)publicdeleteJob * **deleteJob(name: [JobNameOrClz](/api/cron.md#JobNameOrClz)): Promise\ ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [Application](/api/cron/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L42)getFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getJob)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L160)publicgetJob * **getJob(name: [JobNameOrClz](/api/cron.md#JobNameOrClz)): CronJob\ ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/cron/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L32)publicloadConfig * **loadConfig(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/framework.ts#L46)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/cron/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/cron/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/cron/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/cron/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # InjectJob ### Callable * **InjectJob(jobName: string | new (...args: any\[]) => [IJob](/api/cron/interface/IJob.md)): PropertyDecorator --- # Job ### Callable * **Job(jobOptions? : [CronJobOptions](/api/cron.md#CronJobOptions)): ClassDecorator * **Job(jobName: string, jobOptions? : [CronJobOptions](/api/cron.md#CronJobOptions)): ClassDecorator --- # Application ### Hierarchy * IMidwayApplication<[Context](/api/cron/interface/Context.md)> * *Application* ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L833)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L823)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/cron/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L814)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L778)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L794)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L844)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L774)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L799)getConfig * **getConfig\(key? : string): T - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L808)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L782)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L786)getFramework * **getFramework(): IMidwayFramework<[Application](/api/cron/interface/Application.md), [Context](/api/cron/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L804)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L853)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/cron/interface/Context.md), R, N> - Inherited from IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L867)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L790)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L818)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L839)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L828)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L858)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/cron/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L863)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/cron/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L849)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/cron/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * IMidwayContext * *Context* ## Index[**](#Index) ### Properties * [**job](#job) * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#job)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L33)job **job: CronJob\ ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # CronOptions ## Index[**](#Index) ### Properties * [**defaultCronJobOptions](#defaultCronJobOptions) ## Properties[**](#Properties) ### [**](#defaultCronJobOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L12)optionaldefaultCronJobOptions **defaultCronJobOptions? : [CronJobOptions](/api/cron.md#CronJobOptions) --- # IJob ## Index[**](#Index) ### Methods * [**onComplete](#onComplete) * [**onTick](#onTick) ## Methods[**](#Methods) ### [**](#onComplete)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L24)optionalonComplete * **onComplete(result: any): any - A function that will fire when the job is stopped with job.stop(), and may also be called by onTick at the end of each run. ### [**](#onTick)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cron/src/interface.ts#L19)onTick * **onTick(): any - The function to fire at the specified time. If an onComplete callback was provided, onTick will receive it as an argument. onTick may call onComplete when it has finished its work. --- # @midwayjs/cross-domain ## Index[**](#Index) ### Classes * [**Configuration](/api/cross-domain/class/Configuration.md) * [**CorsMiddleware](/api/cross-domain/class/CorsMiddleware.md) * [**JSONPFilter](/api/cross-domain/class/JSONPFilter.md) * [**JSONPMiddleware](/api/cross-domain/class/JSONPMiddleware.md) * [**JSONPService](/api/cross-domain/class/JSONPService.md) ### Interfaces * [**CORSOptions](/api/cross-domain/interface/CORSOptions.md) * [**JSONPOptions](/api/cross-domain/interface/JSONPOptions.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [CrossDomainConfiguration](/api/cross-domain/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/configuration.ts#L18)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/configuration.ts#L20)onReady * **onReady(): Promise\ --- # CorsMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cors](#cors) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CorsMiddleware(): [CorsMiddleware](/api/cross-domain/class/CorsMiddleware.md) ## Properties[**](#Properties) ### [**](#cors)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/cors.ts#L7)cors **cors: [CORSOptions](/api/cross-domain/interface/CORSOptions.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/cors.ts#L21)compatibleMiddleware * **compatibleMiddleware(request: any, response: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/cors.ts#L9)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/cors.ts#L118)staticgetName * **getName(): string --- # JSONPFilter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**match](#match) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPFilter(): [JSONPFilter](/api/cross-domain/class/JSONPFilter.md) ## Methods[**](#Methods) ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/jsonp.ts#L8)match * **match(value: any, req: any): Promise\ --- # JSONPMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**jsonp](#jsonp) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPMiddleware(): [JSONPMiddleware](/api/cross-domain/class/JSONPMiddleware.md) ## Properties[**](#Properties) ### [**](#jsonp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/jsonp.ts#L17)jsonp **jsonp: [JSONPOptions](/api/cross-domain/interface/JSONPOptions.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/jsonp.ts#L34)compatibleMiddleware * **compatibleMiddleware(context: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/jsonp.ts#L19)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/middleware/jsonp.ts#L47)staticgetName * **getName(): string --- # JSONPService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) * [**jsonpConfig](#jsonpConfig) * [**res](#res) ### Methods * [**jsonp](#jsonp) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JSONPService(): [JSONPService](/api/cross-domain/class/JSONPService.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/jsonp.ts#L6)ctx **ctx: any ### [**](#jsonpConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/jsonp.ts#L9)jsonpConfig **jsonpConfig: any ### [**](#res)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/jsonp.ts#L12)res **res: any ## Methods[**](#Methods) ### [**](#jsonp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/jsonp.ts#L14)jsonp * **jsonp(body: any, config? : [JSONPOptions](/api/cross-domain/interface/JSONPOptions.md)): string --- # CORSOptions ## Index[**](#Index) ### Properties * [**allowHeaders](#allowHeaders) * [**allowMethods](#allowMethods) * [**credentials](#credentials) * [**exposeHeaders](#exposeHeaders) * [**keepHeadersOnError](#keepHeadersOnError) * [**maxAge](#maxAge) * [**origin](#origin) ## Properties[**](#Properties) ### [**](#allowHeaders)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L5)allowHeaders **allowHeaders: string | string\[] ### [**](#allowMethods)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L2)allowMethods **allowMethods: string | string\[] ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L6)credentials **credentials: boolean | (...args: any\[]) => any ### [**](#exposeHeaders)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L4)exposeHeaders **exposeHeaders: string | string\[] ### [**](#keepHeadersOnError)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L7)keepHeadersOnError **keepHeadersOnError: boolean ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L8)maxAge **maxAge: number ### [**](#origin)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L3)origin **origin: string | (...args: any\[]) => any --- # JSONPOptions ## Index[**](#Index) ### Properties * [**callback](#callback) * [**csrf](#csrf) * [**limit](#limit) ## Properties[**](#Properties) ### [**](#callback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L11)callback **callback: string ### [**](#csrf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L13)csrf **csrf: boolean ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/cross-domain/src/interface.ts#L12)limit **limit: number --- # @midwayjs/etcd ## Index[**](#Index) ### Classes * [**Configuration](/api/etcd/class/Configuration.md) * [**ETCDService](/api/etcd/class/ETCDService.md) * [**ETCDServiceFactory](/api/etcd/class/ETCDServiceFactory.md) * [**EtcdServiceDiscoverClient](/api/etcd/class/EtcdServiceDiscoverClient.md) * [**EtcdServiceDiscovery](/api/etcd/class/EtcdServiceDiscovery.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ETCDConfiguration](/api/etcd/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/configuration.ts#L14)onReady * **onReady(container: any): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/configuration.ts#L18)onStop * **onStop(container: IMidwayContainer): Promise\ --- # ETCDService ### Hierarchy * Etcd3 * *ETCDService* ### Implements * Etcd3 ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ETCDService(): [ETCDService](/api/etcd/class/ETCDService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L125)init * **init(): Promise\ --- # EtcdServiceDiscoverClient ### Hierarchy * ServiceDiscoveryClient\ * *EtcdServiceDiscoverClient* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**defaultMeta](#defaultMeta) ### Methods * [**beforeStop](#beforeStop) * [**deregister](#deregister) * [**getSelfInstance](#getSelfInstance) * [**offline](#offline) * [**online](#online) * [**register](#register) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L86)constructor * **new EtcdServiceDiscoverClient(client: Etcd3, serviceDiscoveryOptions: EtcdServiceDiscoveryOptions, logger: ILogger): [EtcdServiceDiscoverClient](/api/etcd/class/EtcdServiceDiscoverClient.md) - Overrides ServiceDiscoveryClient< Etcd3, EtcdServiceDiscoveryOptions, EtcdInstanceMetadata >.constructor ## Accessors[**](#Accessors) ### [**](#defaultMeta)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L9)defaultMeta * **get defaultMeta(): DefaultInstanceMetadata - Inherited from ServiceDiscoveryClient.defaultMeta ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L221)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscoveryClient.beforeStop ### [**](#deregister)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L162)deregister * **deregister(): Promise\ - Overrides ServiceDiscoveryClient.deregister ### [**](#getSelfInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L11)getSelfInstance * **getSelfInstance(): EtcdInstanceMetadata - Inherited from ServiceDiscoveryClient.getSelfInstance ### [**](#offline)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L204)offline * **offline(): Promise\ - Overrides ServiceDiscoveryClient.offline ### [**](#online)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L180)online * **online(): Promise\ - Overrides ServiceDiscoveryClient.online ### [**](#register)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L156)register * **register(instance: EtcdInstanceMetadata): Promise\ - Overrides ServiceDiscoveryClient.register ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L16)stop * **stop(): Promise\ - Inherited from ServiceDiscoveryClient.stop 停止服务发现 --- # EtcdServiceDiscovery ### Hierarchy * ServiceDiscovery\ * *EtcdServiceDiscovery* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**beforeStop](#beforeStop) * [**createClient](#createClient) * [**getInstance](#getInstance) * [**getInstances](#getInstances) * [**init](#init) * [**setLoadBalancer](#setLoadBalancer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new EtcdServiceDiscovery(): [EtcdServiceDiscovery](/api/etcd/class/EtcdServiceDiscovery.md) - Inherited from ServiceDiscovery< Etcd3, EtcdServiceDiscoveryOptions, EtcdInstanceMetadata, EtcdInstanceMetadata, string >.constructor ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L302)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscovery.beforeStop ### [**](#createClient)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L41)createClient * **createClient(options? : ServiceDiscoveryOptions\>): ServiceDiscoveryClient\ - Inherited from ServiceDiscovery.createClient ### [**](#getInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L52)getInstance * **getInstance(options: string): Promise\ - Inherited from ServiceDiscovery.getInstance 获取一个可用服务实例(带负载均衡) ### [**](#getInstances)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L295)publicgetInstances * **getInstances(serviceName: string): Promise\ - Overrides ServiceDiscovery.getInstances ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/extension/serviceDiscovery.ts#L254)init * **init(): Promise\ ### [**](#setLoadBalancer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L56)setLoadBalancer * **setLoadBalancer(type: LoadBalancerType | ILoadBalancer\): void - Inherited from ServiceDiscovery.setLoadBalancer 设置负载均衡策略 --- # ETCDServiceFactory ### Hierarchy * ServiceFactory\ * *ETCDServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**etcdConfig](#etcdConfig) * [**logger](#logger) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ETCDServiceFactory(): [ETCDServiceFactory](/api/etcd/class/ETCDServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#etcdConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L20)etcdConfig **etcdConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L30)logger **logger: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L44)createClient * **createClient(config: IOptions): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L111)destroyClient * **destroyClient(client: Etcd3): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Etcd3 ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L107)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/etcd/src/manager.ts#L23)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # @midwayjs/event-emitter ## Index[**](#Index) ### Classes * [**Configuration](/api/event-emitter/class/Configuration.md) * [**EventEmitterService](/api/event-emitter/class/EventEmitterService.md) ### Functions * [**OnEvent](/api/event-emitter/function/OnEvent.md) ### Interfaces * [**EventEmitterConfigOptions](/api/event-emitter/interface/EventEmitterConfigOptions.md) ### Type Aliases * [**OnEventOptions](/api/event-emitter.md#OnEventOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#OnEventOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/interface.ts#L5)OnEventOptions **OnEventOptions: OnOptions & { prependListener? : boolean; suppressErrors? : boolean } --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [EventEmitterConfiguration](/api/event-emitter/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/configuration.ts#L8)onReady * **onReady(container: IMidwayContainer): Promise\ --- # EventEmitterService ### Hierarchy * EventEmitter2 * *EventEmitterService* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**emit](#emit) * [**emitAsync](#emitAsync) * [**getEventEmitter](#getEventEmitter) * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new EventEmitterService(): [EventEmitterService](/api/event-emitter/class/EventEmitterService.md) ## Methods[**](#Methods) ### [**](#emit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/service.ts#L109)emit * **emit(event: string | symbol | string\[], ...args: any\[]): boolean ### [**](#emitAsync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/service.ts#L84)emitAsync * **emitAsync(event: string | symbol | string\[], ...args: any\[]): Promise\ ### [**](#getEventEmitter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/service.ts#L80)getEventEmitter * **getEventEmitter(): EventEmitter2 ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/event-emitter/src/service.ts#L26)init * **init(): Promise\ --- # OnEvent ### Callable * **OnEvent(event: string, options? : [OnEventOptions](/api/event-emitter.md#OnEventOptions)): MethodDecorator --- # EventEmitterConfigOptions ### Hierarchy * ConstructorOptions * *EventEmitterConfigOptions* --- # @midwayjs/express-session ## Index[**](#Index) ### Classes * [**Configuration](/api/express-session/class/Configuration.md) * [**SessionMiddleware](/api/express-session/class/SessionMiddleware.md) * [**SessionStoreManager](/api/express-session/class/SessionStoreManager.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SessionConfiguration](/api/express-session/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/configuration.ts#L22)onReady * **onReady(): Promise\ --- # SessionMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**logger](#logger) * [**sessionConfig](#sessionConfig) * [**sessionStoreManager](#sessionStoreManager) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionMiddleware(): [SessionMiddleware](/api/express-session/class/SessionMiddleware.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L26)configService **configService: MidwayConfigService ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L20)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L17)sessionConfig **sessionConfig: any ### [**](#sessionStoreManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L23)sessionStoreManager **sessionStoreManager: [SessionStoreManager](/api/express-session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L28)resolve * **resolve(): any - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/middleware/session.ts#L60)staticgetName * **getName(): string --- # SessionStoreManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSessionStore](#getSessionStore) * [**setSessionStore](#setSessionStore) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStoreManager(): [SessionStoreManager](/api/express-session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#getSessionStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/store.ts#L15)getSessionStore * **getSessionStore(session? : any): any ### [**](#setSessionStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/express-session/src/store.ts#L11)setSessionStore * **setSessionStore(sessionStore: any, options? : {}): void --- # @midwayjs/faas ## Index[**](#Index) ### Classes * [**AbstractBootstrapStarter](/api/faas/class/AbstractBootstrapStarter.md) * [**Configuration](/api/faas/class/Configuration.md) * [**Framework](/api/faas/class/Framework.md) ### Functions * [**Event](/api/faas/function/Event.md) ### Interfaces * [**Application](/api/faas/interface/Application.md) * [**Context](/api/faas/interface/Context.md) * [**FaaSContext](/api/faas/interface/FaaSContext.md) * [**FaaSHTTPContext](/api/faas/interface/FaaSHTTPContext.md) * [**FaaSHTTPRequest](/api/faas/interface/FaaSHTTPRequest.md) * [**FaaSHTTPResponse](/api/faas/interface/FaaSHTTPResponse.md) * [**FormatResponseOptions](/api/faas/interface/FormatResponseOptions.md) * [**HandlerOptions](/api/faas/interface/HandlerOptions.md) * [**HttpResponseFormat](/api/faas/interface/HttpResponseFormat.md) * [**IFaaSConfigurationOptions](/api/faas/interface/IFaaSConfigurationOptions.md) * [**IWebMiddleware](/api/faas/interface/IWebMiddleware.md) * [**ServerlessStarterOptions](/api/faas/interface/ServerlessStarterOptions.md) * [**State](/api/faas/interface/State.md) * [**wrapHttpRequestOptions](/api/faas/interface/wrapHttpRequestOptions.md) ### Type Aliases * [**FaaSMiddleware](/api/faas.md#FaaSMiddleware) * [**IMidwayFaaSApplication](/api/faas.md#IMidwayFaaSApplication) * [**NextFunction](/api/faas.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#FaaSMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L412)FaaSMiddleware **FaaSMiddleware: (context: [Context](/api/faas/interface/Context.md), next: () => Promise\) => any | string * **@deprecated** ### [**](#IMidwayFaaSApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L425)IMidwayFaaSApplication **IMidwayFaaSApplication: IMidwayApplication<[Context](/api/faas/interface/Context.md), { generateMiddleware: any; getEventMiddleware: any; getFunctionName: any; getFunctionServiceName: any; getInitializeContext: any; getServerlessInstance: any; invokeTriggerFunction: any; use: any; useEventMiddleware: any }> & ServerlessHttpApplication ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L471)NextFunction **NextFunction: BaseNextFunction --- # abstractAbstractBootstrapStarter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**getApplicationContext](#getApplicationContext) * [**initFramework](#initFramework) * [**onClose](#onClose) * [**onInit](#onInit) * [**onRequest](#onRequest) * [**onStart](#onStart) * [**start](#start) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L14)constructor * **new AbstractBootstrapStarter(options? : [ServerlessStarterOptions](/api/faas/interface/ServerlessStarterOptions.md)): [AbstractBootstrapStarter](/api/faas/class/AbstractBootstrapStarter.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L22)publicclose * **close(): Promise\ ### [**](#getApplicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L18)publicgetApplicationContext * **getApplicationContext(): any ### [**](#initFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L57)publicinitFramework * **initFramework(bootstrapOptions? : IMidwayBootstrapOptions): Promise\ ### [**](#onClose)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L77)abstractonClose * **onClose(): any ### [**](#onInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L75)abstractonInit * **onInit(...args: unknown\[]): any ### [**](#onRequest)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L76)abstractonRequest * **onRequest(...args: unknown\[]): any ### [**](#onStart)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L74)abstractonStart * **onStart(): unknown ### [**](#start)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/starter.ts#L37)publicstart * **start(options? : [ServerlessStarterOptions](/api/faas/interface/ServerlessStarterOptions.md)): Record\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**decoratorService](#decoratorService) * [**framework](#framework) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onServerReady](#onServerReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [FaaSConfiguration](/api/faas/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L32)applicationContext **applicationContext: any ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L29)decoratorService **decoratorService: MidwayDecoratorService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L26)framework **framework: [MidwayFaaSFramework](/api/faas/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L35)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L67)onReady * **onReady(container: any): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/configuration.ts#L69)onServerReady * **onServerReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[Application](/api/faas/interface/Application.md), [Context](/api/faas/interface/Context.md), [IFaaSConfigurationOptions](/api/faas/interface/IFaaSConfigurationOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**formatHttpResponse](#formatHttpResponse) * [**generateMiddleware](#generateMiddleware) * [**getAllHandlerNames](#getAllHandlerNames) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getContext](#getContext) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getEventMiddleware](#getEventMiddleware) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**handleInvokeWrapper](#handleInvokeWrapper) * [**initialize](#initialize) * [**invokeTriggerFunction](#invokeTriggerFunction) * [**isEnable](#isEnable) * [**loadFunction](#loadFunction) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useEventMiddleware](#useEventMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) * [**wrapHttpRequest](#wrapHttpRequest) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayFaaSFramework](/api/faas/class/Framework.md) - Inherited from BaseFramework< Application, Context, IFaaSConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L53)publicapp **app: [Application](/api/faas/interface/Application.md) Overrides BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IFaaSConfigurationOptions](/api/faas/interface/IFaaSConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L80)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/faas/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L596)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L66)configure * **configure(options: [IFaaSConfigurationOptions](/api/faas/interface/IFaaSConfigurationOptions.md)): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L583)publiccreateLogger * **createLogger(name: string, option? : LoggerOptions): ILogger - Overrides BaseFramework.createLogger ### [**](#formatHttpResponse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L412)publicformatHttpResponse * **formatHttpResponse(context: any, options? : { supportBufferResponse? : boolean }): [HttpResponseFormat](/api/faas/interface/HttpResponseFormat.md)\ ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L491)publicgenerateMiddleware * **generateMiddleware(middlewareId: string): Promise<(context: [Context](/api/faas/interface/Context.md), next: any, options? : any) => any> - - **@deprecated** ### [**](#getAllHandlerNames)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L630)publicgetAllHandlerNames * **getAllHandlerNames(): string\[] ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [Application](/api/faas/interface/Application.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L499)publicgetContext * **getContext(context? : any): any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getEventMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L622)publicgetEventMiddleware * **getEventMiddleware(): ContextMiddlewareManager<[Context](/api/faas/interface/Context.md), NextFunction, undefined> ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L588)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/faas/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L592)publicgetServer * **getServer(): Server\ ### [**](#handleInvokeWrapper)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L197)publichandleInvokeWrapper * **handleInvokeWrapper(handlerMapping: string): (...args: any\[]) => Promise\ - - **@deprecated** ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#invokeTriggerFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L270)publicinvokeTriggerFunction * **invokeTriggerFunction(context: any, handlerMapping: string, options: [HandlerOptions](/api/faas/interface/HandlerOptions.md)): Promise\ ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L76)isEnable * **isEnable(): boolean - Overrides BaseFramework.isEnable ### [**](#loadFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L165)publicloadFunction * **loadFunction(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L159)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/faas/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useEventMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L616)publicuseEventMiddleware * **useEventMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/faas/interface/Context.md), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/faas/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/faas/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L610)publicuseMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/faas/interface/Context.md), NextFunction, undefined>): void - Overrides BaseFramework.useMiddleware ### [**](#wrapHttpRequest)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/framework.ts#L477)publicwrapHttpRequest * **wrapHttpRequest(req: Record\ | IncomingMessage, res? : Record\ | ServerResponse\, options? : [wrapHttpRequestOptions](/api/faas/interface/wrapHttpRequestOptions.md)): Promise\ --- # Event ### Callable * **Event(pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Application ### Hierarchy * [IMidwayFaaSApplication](/api/faas.md#IMidwayFaaSApplication) * *Application* ## Index[**](#Index) ### Properties * [**context](#context) * [**keys](#keys) * [**maxIpsCount](#maxIpsCount) * [**middleware](#middleware) * [**proxy](#proxy) * [**proxyIpHeader](#proxyIpHeader) * [**request](#request) * [**response](#response) * [**subdomainOffset](#subdomainOffset) ### Methods * [**addConfigObject](#addConfigObject) * [**callback](#callback) * [**createAnonymousContext](#createAnonymousContext) * [**createContext](#createContext) * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getEventMiddleware](#getEventMiddleware) * [**getFramework](#getFramework) * [**getFunctionName](#getFunctionName) * [**getFunctionServiceName](#getFunctionServiceName) * [**getInitializeContext](#getInitializeContext) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**getServerlessInstance](#getServerlessInstance) * [**inspect](#inspect) * [**invokeTriggerFunction](#invokeTriggerFunction) * [**onerror](#onerror) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**toJSON](#toJSON) * [**use](#use) * [**useEventMiddleware](#useEventMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Properties[**](#Properties) ### [**](#context)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L9)context **context: any Inherited from IMidwayFaaSApplication.context ### [**](#keys)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L8)keys **keys: any Inherited from IMidwayFaaSApplication.keys ### [**](#maxIpsCount)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L6)maxIpsCount **maxIpsCount: number Inherited from IMidwayFaaSApplication.maxIpsCount ### [**](#middleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L7)middleware **middleware: any\[] Inherited from IMidwayFaaSApplication.middleware ### [**](#proxy)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L3)proxy **proxy: boolean Inherited from IMidwayFaaSApplication.proxy ### [**](#proxyIpHeader)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L5)proxyIpHeader **proxyIpHeader: string Inherited from IMidwayFaaSApplication.proxyIpHeader ### [**](#request)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L10)request **request: any Inherited from IMidwayFaaSApplication.request ### [**](#response)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L11)response **response: any Inherited from IMidwayFaaSApplication.response ### [**](#subdomainOffset)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L4)subdomainOffset **subdomainOffset: number Inherited from IMidwayFaaSApplication.subdomainOffset ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L833)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayFaaSApplication.addConfigObject Add new value to current config ### [**](#callback)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L34)callback * **callback(): (req: any, res: any, respond: any) => any - Inherited from IMidwayFaaSApplication.callback Return a request handler callback for node's native http server. * **@api** public ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L823)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/faas/interface/Context.md) - Inherited from IMidwayFaaSApplication.createAnonymousContext create a context with RequestContainer ### [**](#createContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L16)createContext * **createContext(req: any, res: any): any - Inherited from IMidwayFaaSApplication.createContext Initialize a new context. ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L814)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayFaaSApplication.createLogger Create a logger by name and options ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L437)generateMiddleware * **generateMiddleware(middlewareId: any): Promise<[FaaSMiddleware](/api/faas.md#FaaSMiddleware)> - Inherited from IMidwayFaaSApplication.generateMiddleware * **@deprecated** ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L778)getAppDir * **getAppDir(): string - Inherited from IMidwayFaaSApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L794)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from IMidwayFaaSApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L844)getAttr * **getAttr\(key: string): T - Inherited from IMidwayFaaSApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L774)getBaseDir * **getBaseDir(): string - Inherited from IMidwayFaaSApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L799)getConfig * **getConfig\(key? : string): T - Inherited from IMidwayFaaSApplication.getConfig Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L808)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayFaaSApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L782)getEnv * **getEnv(): string - Inherited from IMidwayFaaSApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getEventMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L450)getEventMiddleware * **getEventMiddleware(): ContextMiddlewareManager<[Context](/api/faas/interface/Context.md), NextFunction, undefined> - Inherited from IMidwayFaaSApplication.getEventMiddleware ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L786)getFramework * **getFramework(): IMidwayFramework<[Application](/api/faas/interface/Application.md), [Context](/api/faas/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayFaaSApplication.getFramework get current related framework ### [**](#getFunctionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L441)getFunctionName * **getFunctionName(): string - Inherited from IMidwayFaaSApplication.getFunctionName Get function name in serverless environment ### [**](#getFunctionServiceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L445)getFunctionServiceName * **getFunctionServiceName(): string - Inherited from IMidwayFaaSApplication.getFunctionServiceName Get function service name in serverless environment ### [**](#getInitializeContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L428)getInitializeContext * **getInitializeContext(): any - Inherited from IMidwayFaaSApplication.getInitializeContext ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L804)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayFaaSApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L853)getMiddleware * **getMiddleware\(): IMiddlewareManager<[Context](/api/faas/interface/Context.md), R, N> - Inherited from IMidwayFaaSApplication.getMiddleware get global middleware *** #### Type parameters * **R** * **N** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L867)getNamespace * **getNamespace(): string - Inherited from IMidwayFaaSApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L790)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayFaaSApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L818)getProjectName * **getProjectName(): string - Inherited from IMidwayFaaSApplication.getProjectName Get project name, just package.json name ### [**](#getServerlessInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L460)getServerlessInstance * **getServerlessInstance\(serviceClass: ObjectIdentifier | new (...args: any\[]) => T, customContext? : Record\): Promise\ - Inherited from IMidwayFaaSApplication.getServerlessInstance #### Type parameters * **T** ### [**](#inspect)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L49)inspect * **inspect(): any - Inherited from IMidwayFaaSApplication.inspect Inspect implementation. * **@api** public ### [**](#invokeTriggerFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L455)invokeTriggerFunction * **invokeTriggerFunction(context: any, handler: string, options: [HandlerOptions](/api/faas/interface/HandlerOptions.md)): Promise\ - Inherited from IMidwayFaaSApplication.invokeTriggerFunction ### [**](#onerror)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L56)onerror * **onerror(err: any): void - Inherited from IMidwayFaaSApplication.onerror Default error handler. * **@api** private ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L839)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayFaaSApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L828)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayFaaSApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#toJSON)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L42)toJSON * **toJSON(): any - Inherited from IMidwayFaaSApplication.toJSON Return JSON representation. We only bother showing settings. * **@api** public ### [**](#use)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L432)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/application.d.ts#L26)use * **use(middleware: [FaaSMiddleware](/api/faas.md#FaaSMiddleware)): any * **use(fn: (...args: any\[]) => Promise\): this - Inherited from IMidwayFaaSApplication.use * **@deprecated** use useMiddleware instead ### [**](#useEventMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L447)useEventMiddleware * **useEventMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/faas/interface/Context.md), NextFunction, undefined>): void - Inherited from IMidwayFaaSApplication.useEventMiddleware ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L858)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/faas/interface/Context.md), R, N>): void - Inherited from IMidwayFaaSApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L863)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/faas/interface/Context.md)>): void - Inherited from IMidwayFaaSApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L849)useMiddleware * **useMiddleware\(Middleware: CommonMiddlewareUnion<[Context](/api/faas/interface/Context.md), R, N>): void - Inherited from IMidwayFaaSApplication.useMiddleware add global filter to app *** #### Type parameters * **R** * **N** --- # Context ### Hierarchy * [FaaSContext](/api/faas/interface/FaaSContext.md) * *Context* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**env](#env) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**logger](#logger) * [**method](#method) * [**originContext](#originContext) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**requestContext](#requestContext) * [**res](#res) * [**response](#response) * [**startTime](#startTime) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**traceId](#traceId) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**setAttr](#setAttr) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L157)accept **accept: any Inherited from FaaSContext.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L204)body **body: any Inherited from FaaSContext.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L374)cookies **cookies: Cookies Inherited from FaaSContext.cookies FaaS Cookies Object ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L405)env **env: string Inherited from FaaSContext.env ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L249)etag **etag: string Inherited from FaaSContext.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L169)header **header: {} Inherited from FaaSContext.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L173)headers **headers: {} Inherited from FaaSContext.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L143)host **host: string Inherited from FaaSContext.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L147)hostname **hostname: string Inherited from FaaSContext.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L151)ip **ip: string Inherited from FaaSContext.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L236)lastModified **lastModified: Date Inherited from FaaSContext.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L210)length **length: number Inherited from FaaSContext.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L404)logger **logger: ILogger Inherited from FaaSContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L165)method **method: string Inherited from FaaSContext.method Get request method. ### [**](#originContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L407)originContext **originContext: any Inherited from FaaSContext.originContext ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L370)originEvent **originEvent: Record\ Inherited from FaaSContext.originEvent FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L156)originalUrl **originalUrl: string Inherited from FaaSContext.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L182)params **params: {} Inherited from FaaSContext.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L161)path **path: string Inherited from FaaSContext.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L177)query **query: {} Inherited from FaaSContext.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L354)req **req: any Inherited from FaaSContext.req It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L362)request **request: [FaaSHTTPRequest](/api/faas/interface/FaaSHTTPRequest.md) Inherited from FaaSContext.request FaaS http request object ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L406)requestContext **requestContext: MidwayRequestContainer Inherited from FaaSContext.requestContext ### [**](#res)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L358)res **res: any Inherited from FaaSContext.res It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L366)response **response: [FaaSHTTPResponse](/api/faas/interface/FaaSHTTPResponse.md) Inherited from FaaSContext.response FaaS http response object ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from FaaSContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L378)state **state: [State](/api/faas/interface/State.md) Inherited from FaaSContext.state FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L200)status **status: number Inherited from FaaSContext.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L304)streaming **streaming: boolean Inherited from FaaSContext.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from FaaSContext.traceId ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L227)type **type: string Inherited from FaaSContext.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L155)url **url: string Inherited from FaaSContext.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L57)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L58)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L59)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from FaaSContext.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L81)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L82)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L83)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from FaaSContext.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L69)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L71)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from FaaSContext.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L93)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L94)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L95)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from FaaSContext.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L275)append * **append(field: string, val: string | string\[]): void - Inherited from FaaSContext.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L139)get * **get(field: string): string - Inherited from FaaSContext.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from FaaSContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from FaaSContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from FaaSContext.getLogger ### [**](#is)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L119)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L120)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from FaaSContext.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L295)redirect * **redirect(url: string, alt? : string): void - Inherited from FaaSContext.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L280)remove * **remove(field: string): void - Inherited from FaaSContext.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L261)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L262)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from FaaSContext.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from FaaSContext.setAttr Set value to app attribute map ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L394)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L399)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L400)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Inherited from FaaSContext.throw Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSContext ### Hierarchy * IMidwayContext<[FaaSHTTPContext](/api/faas/interface/FaaSHTTPContext.md)> * *FaaSContext* * [Context](/api/faas/interface/Context.md) ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**env](#env) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**logger](#logger) * [**method](#method) * [**originContext](#originContext) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**requestContext](#requestContext) * [**res](#res) * [**response](#response) * [**startTime](#startTime) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**traceId](#traceId) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**setAttr](#setAttr) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L157)accept **accept: any Inherited from IMidwayContext.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L204)body **body: any Inherited from IMidwayContext.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L374)cookies **cookies: Cookies Inherited from IMidwayContext.cookies FaaS Cookies Object ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L405)env **env: string ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L249)etag **etag: string Inherited from IMidwayContext.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L169)header **header: {} Inherited from IMidwayContext.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L173)headers **headers: {} Inherited from IMidwayContext.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L143)host **host: string Inherited from IMidwayContext.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L147)hostname **hostname: string Inherited from IMidwayContext.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L151)ip **ip: string Inherited from IMidwayContext.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L236)lastModified **lastModified: Date Inherited from IMidwayContext.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L210)length **length: number Inherited from IMidwayContext.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L404)logger **logger: ILogger Overrides IMidwayContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L165)method **method: string Inherited from IMidwayContext.method Get request method. ### [**](#originContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L407)originContext **originContext: any ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L370)originEvent **originEvent: Record\ Inherited from IMidwayContext.originEvent FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L156)originalUrl **originalUrl: string Inherited from IMidwayContext.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L182)params **params: {} Inherited from IMidwayContext.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L161)path **path: string Inherited from IMidwayContext.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L177)query **query: {} Inherited from IMidwayContext.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L354)req **req: any Inherited from IMidwayContext.req It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L362)request **request: [FaaSHTTPRequest](/api/faas/interface/FaaSHTTPRequest.md) Inherited from IMidwayContext.request FaaS http request object ### [**](#requestContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L406)requestContext **requestContext: MidwayRequestContainer Overrides IMidwayContext.requestContext ### [**](#res)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L358)res **res: any Inherited from IMidwayContext.res It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L366)response **response: [FaaSHTTPResponse](/api/faas/interface/FaaSHTTPResponse.md) Inherited from IMidwayContext.response FaaS http response object ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L378)state **state: [State](/api/faas/interface/State.md) Inherited from IMidwayContext.state FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L200)status **status: number Inherited from IMidwayContext.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L304)streaming **streaming: boolean Inherited from IMidwayContext.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L227)type **type: string Inherited from IMidwayContext.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L155)url **url: string Inherited from IMidwayContext.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L57)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L58)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L59)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from IMidwayContext.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L81)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L82)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L83)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from IMidwayContext.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L69)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L71)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from IMidwayContext.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L93)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L94)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L95)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from IMidwayContext.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L275)append * **append(field: string, val: string | string\[]): void - Inherited from IMidwayContext.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L139)get * **get(field: string): string - Inherited from IMidwayContext.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#is)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L119)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L120)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from IMidwayContext.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L295)redirect * **redirect(url: string, alt? : string): void - Inherited from IMidwayContext.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L280)remove * **remove(field: string): void - Inherited from IMidwayContext.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L261)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L262)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from IMidwayContext.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L394)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L399)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L400)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Inherited from IMidwayContext.throw Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSHTTPContext ### Hierarchy * ContextDelegatedRequest * ContextDelegatedResponse * *FaaSHTTPContext* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**cookies](#cookies) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**lastModified](#lastModified) * [**length](#length) * [**method](#method) * [**originEvent](#originEvent) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**query](#query) * [**req](#req) * [**request](#request) * [**res](#res) * [**response](#response) * [**state](#state) * [**status](#status) * [**streaming](#streaming) * [**type](#type) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**append](#append) * [**get](#get) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) * [**throw](#throw) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L157)accept **accept: any Inherited from ContextDelegatedRequest.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L204)body **body: any Inherited from ContextDelegatedResponse.body Get/Set response body. ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L374)cookies **cookies: Cookies FaaS Cookies Object ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L249)etag **etag: string Inherited from ContextDelegatedResponse.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L169)header **header: {} Inherited from ContextDelegatedRequest.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L173)headers **headers: {} Inherited from ContextDelegatedRequest.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L143)host **host: string Inherited from ContextDelegatedRequest.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L147)hostname **hostname: string Inherited from ContextDelegatedRequest.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L151)ip **ip: string Inherited from ContextDelegatedRequest.ip Request remote address. ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L236)lastModified **lastModified: Date Inherited from ContextDelegatedResponse.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L210)length **length: number Inherited from ContextDelegatedResponse.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L165)method **method: string Inherited from ContextDelegatedRequest.method Get request method. ### [**](#originEvent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L370)originEvent **originEvent: Record\ FaaS original event object. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L156)originalUrl **originalUrl: string Inherited from ContextDelegatedRequest.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L182)params **params: {} Inherited from ContextDelegatedRequest.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L161)path **path: string Inherited from ContextDelegatedRequest.path Get request pathname. ### [**](#query)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L177)query **query: {} Inherited from ContextDelegatedRequest.query Get parsed query-string. ### [**](#req)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L354)req **req: any It's a http request mock object, please don't use it directly. ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L362)request **request: [FaaSHTTPRequest](/api/faas/interface/FaaSHTTPRequest.md) FaaS http request object ### [**](#res)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L358)res **res: any It's a http response mock object, please don't use it directly. ### [**](#response)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L366)response **response: [FaaSHTTPResponse](/api/faas/interface/FaaSHTTPResponse.md) FaaS http response object ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L378)state **state: [State](/api/faas/interface/State.md) FaaS Context State ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L200)status **status: number Inherited from ContextDelegatedResponse.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L304)streaming **streaming: boolean Inherited from ContextDelegatedResponse.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L227)type **type: string Inherited from ContextDelegatedResponse.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L155)url **url: string Inherited from ContextDelegatedRequest.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L57)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L58)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L59)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L81)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L82)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L83)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L69)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L71)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L93)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L94)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L95)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#append)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L275)append * **append(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L139)get * **get(field: string): string - Inherited from ContextDelegatedRequest.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L119)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L120)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L295)redirect * **redirect(url: string, alt? : string): void - Inherited from ContextDelegatedResponse.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L280)remove * **remove(field: string): void - Inherited from ContextDelegatedResponse.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L261)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L262)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); ### [**](#throw)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L394)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L399)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L400)throw * **throw(message: string, code? : number, properties? : Record\): never * **throw(status: number): never * **throw(...properties: (string | number | Record\)\[]): never - Throw an error with `msg` and optional `status` defaulting to 500. Note that these are user-level errors, and the message may be exposed to the client. this.throw(403) this.throw('name required', 400) this.throw(400, 'name required') this.throw('something exploded') this.throw(new Error('invalid'), 400); this.throw(400, new Error('invalid')); See: --- # FaaSHTTPRequest ### Hierarchy * ContextDelegatedRequest * *FaaSHTTPRequest* ## Index[**](#Index) ### Properties * [**accept](#accept) * [**body](#body) * [**header](#header) * [**headers](#headers) * [**host](#host) * [**hostname](#hostname) * [**ip](#ip) * [**method](#method) * [**originalUrl](#originalUrl) * [**params](#params) * [**path](#path) * [**pathParameters](#pathParameters) * [**query](#query) * [**url](#url) ### Methods * [**accepts](#accepts) * [**acceptsCharsets](#acceptsCharsets) * [**acceptsEncodings](#acceptsEncodings) * [**acceptsLanguages](#acceptsLanguages) * [**get](#get) * [**is](#is) ## Properties[**](#Properties) ### [**](#accept)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L157)accept **accept: any Inherited from ContextDelegatedRequest.accept ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L189)body **body: any Get parsed request body from event ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L169)header **header: {} Inherited from ContextDelegatedRequest.header Return request header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L173)headers **headers: {} Inherited from ContextDelegatedRequest.headers Return request header, alias as request.header ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L143)host **host: string Inherited from ContextDelegatedRequest.host Get parsed host from event ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L147)hostname **hostname: string Inherited from ContextDelegatedRequest.hostname Get parsed host from event ### [**](#ip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L151)ip **ip: string Inherited from ContextDelegatedRequest.ip Request remote address. ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L165)method **method: string Inherited from ContextDelegatedRequest.method Get request method. ### [**](#originalUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L156)originalUrl **originalUrl: string Inherited from ContextDelegatedRequest.originalUrl ### [**](#params)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L182)params **params: {} Inherited from ContextDelegatedRequest.params Get parsed params ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L161)path **path: string Inherited from ContextDelegatedRequest.path Get request pathname. ### [**](#pathParameters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L193)pathParameters **pathParameters: any Get Parsed path parameters from event ### [**](#query)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L177)query **query: {} Inherited from ContextDelegatedRequest.query Get parsed query-string. ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L155)url **url: string Inherited from ContextDelegatedRequest.url Get/Set request URL. ## Methods[**](#Methods) ### [**](#accepts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L57)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L58)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L59)accepts * **accepts(): boolean | string\[] * **accepts(...types: string\[]): string | boolean * **accepts(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.accepts Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `undefined`, in which case you should respond with 406 "Not Acceptable". The `type` value may be a single mime type string such as "application/json", the extension name such as "json" or an array `["json", "html", "text/plain"]`. When a list or array is given the *best* match, if any is returned. Examples: ``` // Accept: text/html this.accepts('html'); // => "html" // Accept: text/*, application/json this.accepts('html'); // => "html" this.accepts('text/html'); // => "text/html" this.accepts('json', 'text'); // => "json" this.accepts('application/json'); // => "application/json" // Accept: text/*, application/json this.accepts('image/png'); this.accepts('png'); // => undefined // Accept: text/*;q=.5, application/json this.accepts(['html', 'json']); this.accepts('html', 'json'); // => "json" ``` ### [**](#acceptsCharsets)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L81)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L82)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L83)acceptsCharsets * **acceptsCharsets(): boolean | string\[] * **acceptsCharsets(...charsets: string\[]): string | boolean * **acceptsCharsets(charsets: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsCharsets Return accepted charsets or best fit based on `charsets`. Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` an array sorted by quality is returned: ``` ['utf-8', 'utf-7', 'iso-8859-1'] ``` ### [**](#acceptsEncodings)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L69)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L70)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L71)acceptsEncodings * **acceptsEncodings(): boolean | string\[] * **acceptsEncodings(...encodings: string\[]): string | boolean * **acceptsEncodings(encodings: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsEncodings Return accepted encodings or best fit based on `encodings`. Given `Accept-Encoding: gzip, deflate` an array sorted by quality is returned: ``` ['gzip', 'deflate'] ``` ### [**](#acceptsLanguages)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L93)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L94)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L95)acceptsLanguages * **acceptsLanguages(): boolean | string\[] * **acceptsLanguages(...langs: string\[]): string | boolean * **acceptsLanguages(langs: string\[]): string | boolean - Inherited from ContextDelegatedRequest.acceptsLanguages Return accepted languages or best fit based on `langs`. Given `Accept-Language: en;q=0.8, es, pt` an array sorted by quality is returned: ``` ['es', 'pt', 'en'] ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L139)get * **get(field: string): string - Inherited from ContextDelegatedRequest.get Return request header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L119)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L120)is * **is(...types: string\[]): string | boolean * **is(types: string\[]): string | boolean - Inherited from ContextDelegatedRequest.is Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. If there is no request body, `null` is returned. If there is no content type, `false` is returned. Otherwise, it returns the first `type` that matches. Examples: ``` // With Content-Type: text/html; charset=utf-8 this.is('html'); // => 'html' this.is('text/html'); // => 'text/html' this.is('text/*', 'application/json'); // => 'text/html' // When Content-Type is application/json this.is('json', 'urlencoded'); // => 'json' this.is('application/json'); // => 'application/json' this.is('html', 'application/*'); // => 'application/json' this.is('html'); // => false ``` --- # FaaSHTTPResponse ### Hierarchy * ContextDelegatedResponse * Pick\ * *FaaSHTTPResponse* ## Index[**](#Index) ### Properties * [**body](#body) * [**etag](#etag) * [**header](#header) * [**headers](#headers) * [**lastModified](#lastModified) * [**length](#length) * [**status](#status) * [**streaming](#streaming) * [**type](#type) ### Methods * [**append](#append) * [**get](#get) * [**is](#is) * [**redirect](#redirect) * [**remove](#remove) * [**set](#set) ## Properties[**](#Properties) ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L204)body **body: any Inherited from ContextDelegatedResponse.body Get/Set response body. ### [**](#etag)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L249)etag **etag: string Inherited from ContextDelegatedResponse.etag Get/Set the ETag of a response. This will normalize the quotes if necessary. ``` this.response.etag = 'md5hashsum'; this.response.etag = '"md5hashsum"'; this.response.etag = 'W/"123456789"'; ``` * **@param** * **@api** public ### [**](#header)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L312)header **header: {} Return response header. ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L316)headers **headers: {} Return response header, alias as response.header ### [**](#lastModified)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L236)lastModified **lastModified: Date Inherited from ContextDelegatedResponse.lastModified Get the Last-Modified date in Date form, if it exists. Set the Last-Modified date using a string or a Date. ``` this.response.lastModified = new Date(); this.response.lastModified = '2013-09-13'; ``` ### [**](#length)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L210)length **length: number Inherited from ContextDelegatedResponse.length Return parsed response Content-Length when present. Set Content-Length field to `n`. ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L200)status **status: number Inherited from ContextDelegatedResponse.status Get/Set response status code. ### [**](#streaming)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L304)streaming **streaming: boolean Inherited from ContextDelegatedResponse.streaming Get/Set streaming response. ``` this.streaming = true; ``` * **@api** public ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L227)type **type: string Inherited from ContextDelegatedResponse.type Return the response mime type void of parameters such as "charset". Set Content-Type response header with `type` through `mime.lookup()` when it does not contain a charset. Examples: ``` this.type = '.html'; this.type = 'html'; this.type = 'json'; this.type = 'application/json'; this.type = 'png'; ``` ## Methods[**](#Methods) ### [**](#append)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L275)append * **append(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.append Append additional header `field` with value `val`. Examples: ``` this.append('Link', ['', '']); this.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); this.append('Warning', '199 Miscellaneous warning'); ``` ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L346)get * **get(field: string): string - Return response header. If the header is not set, will return an empty string. The `Referrer` header field is special-cased, both `Referrer` and `Referer` are interchangeable. Examples: ``` this.get('Content-Type'); // => "text/plain" this.get('content-type'); // => "text/plain" this.get('Something'); // => '' ``` ### [**](#is)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L326)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L327)is * **is(...types: string\[]): string * **is(types: string\[]): string - Check whether the response is one of the listed types. Pretty much the same as `this.request.is()`. * **@api** public ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L295)redirect * **redirect(url: string, alt? : string): void - Inherited from ContextDelegatedResponse.redirect Perform a 302 redirect to `url`. The string "back" is special-cased to provide Referrer support, when Referrer is not present `alt` or "/" is used. Examples: this.redirect('back'); this.redirect('back', '/index.html'); this.redirect('/login'); this.redirect(''); ### [**](#remove)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L280)remove * **remove(field: string): void - Inherited from ContextDelegatedResponse.remove Remove header `field`. ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L261)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L262)set * **set(field: {}): void * **set(field: string, val: string | string\[]): void - Inherited from ContextDelegatedResponse.set Set header `field` to `val`, or pass an object of header fields. Examples: this.set('Foo', \['bar', 'baz']); this.set('Accept', 'application/json'); this.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); --- # FormatResponseOptions ### Hierarchy * *FormatResponseOptions* * [HandlerOptions](/api/faas/interface/HandlerOptions.md) ## Index[**](#Index) ### Properties * [**supportBufferResponse](#supportBufferResponse) ## Properties[**](#Properties) ### [**](#supportBufferResponse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L417)optionalsupportBufferResponse **supportBufferResponse? : boolean --- # HandlerOptions ### Hierarchy * [FormatResponseOptions](/api/faas/interface/FormatResponseOptions.md) * *HandlerOptions* ## Index[**](#Index) ### Properties * [**isCustomHttpResponse](#isCustomHttpResponse) * [**isHttpFunction](#isHttpFunction) * [**supportBufferResponse](#supportBufferResponse) ## Properties[**](#Properties) ### [**](#isCustomHttpResponse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L422)optionalisCustomHttpResponse **isCustomHttpResponse? : boolean ### [**](#isHttpFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L421)optionalisHttpFunction **isHttpFunction? : boolean ### [**](#supportBufferResponse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L417)optionalsupportBufferResponse **supportBufferResponse? : boolean Inherited from FormatResponseOptions.supportBufferResponse --- # HttpResponseFormat \ ## Index[**](#Index) ### Properties * [**body](#body) * [**headers](#headers) * [**isBase64Encoded](#isBase64Encoded) * [**statusCode](#statusCode) ## Properties[**](#Properties) ### [**](#body)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L517)body **body: T ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L516)headers **headers: Record\ ### [**](#isBase64Encoded)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L514)isBase64Encoded **isBase64Encoded: boolean ### [**](#statusCode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L515)statusCode **statusCode: number --- # IFaaSConfigurationOptions ### Hierarchy * IConfigurationOptions * *IFaaSConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**applicationAdapter](#applicationAdapter) * [**config](#config) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**initializeContext](#initializeContext) * [**logger](#logger) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#applicationAdapter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L476)optionalapplicationAdapter **applicationAdapter? : { getApplication: any; getFunctionName: any; getFunctionServiceName: any; runAppHook? : any; runContextHook? : any } ### [**](#config)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L474)optionalconfig **config? : object ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#initializeContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L475)optionalinitializeContext **initializeContext? : object ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger --- # IWebMiddleware * **@deprecated** ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L492)resolve * **resolve(): [FaaSMiddleware](/api/faas.md#FaaSMiddleware) --- # ServerlessStarterOptions ### Hierarchy * IMidwayBootstrapOptions * *ServerlessStarterOptions* ## Index[**](#Index) ### Properties * [**aggregationHandlerName](#aggregationHandlerName) * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**asyncContextManager](#asyncContextManager) * [**baseDir](#baseDir) * [**createAdapter](#createAdapter) * [**globalConfig](#globalConfig) * [**handlerName](#handlerName) * [**handlerNameMapping](#handlerNameMapping) * [**imports](#imports) * [**initializeMethodName](#initializeMethodName) * [**logger](#logger) * [**loggerFactory](#loggerFactory) * [**moduleLoadType](#moduleLoadType) * [**performance](#performance) * [**preloadModules](#preloadModules) ## Properties[**](#Properties) ### [**](#aggregationHandlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L498)optionalaggregationHandlerName **aggregationHandlerName? : string ### [**](#appDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L873)optionalappDir **appDir? : string Inherited from IMidwayBootstrapOptions.appDir ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L874)optionalapplicationContext **applicationContext? : IMidwayGlobalContainer Inherited from IMidwayBootstrapOptions.applicationContext ### [**](#asyncContextManager)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L882)optionalasyncContextManager **asyncContextManager? : AsyncContextManager Inherited from IMidwayBootstrapOptions.asyncContextManager ### [**](#baseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L872)optionalbaseDir **baseDir? : string Inherited from IMidwayBootstrapOptions.baseDir ### [**](#createAdapter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L503)optionalcreateAdapter **createAdapter? : () => Promise<{ close: any; createAppHook: any }> ### [**](#globalConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L879)optionalglobalConfig **globalConfig? : Record\ | {}\[] Inherited from IMidwayBootstrapOptions.globalConfig ### [**](#handlerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L497)optionalhandlerName **handlerName? : string ### [**](#handlerNameMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L499)optionalhandlerNameMapping **handlerNameMapping? : (handlerName: string, ...args: unknown\[]) => \[string, ...unknown\[]] ### [**](#imports)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L876)optionalimports **imports? : any Inherited from IMidwayBootstrapOptions.imports ### [**](#initializeMethodName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L496)optionalinitializeMethodName **initializeMethodName? : string ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L878)optionallogger **logger? : boolean | ILogger Inherited from IMidwayBootstrapOptions.logger ### [**](#loggerFactory)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L883)optionalloggerFactory **loggerFactory? : LoggerFactory\ Inherited from IMidwayBootstrapOptions.loggerFactory ### [**](#moduleLoadType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L877)optionalmoduleLoadType **moduleLoadType? : ModuleLoadType Inherited from IMidwayBootstrapOptions.moduleLoadType ### [**](#performance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/faas/src/interface.ts#L507)optionalperformance **performance? : { end: any; mark: any } ### [**](#preloadModules)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L875)optionalpreloadModules **preloadModules? : any\[] Inherited from IMidwayBootstrapOptions.preloadModules --- # State --- # wrapHttpRequestOptions ### Hierarchy * HttpResponseOptions * *wrapHttpRequestOptions* ## Index[**](#Index) ### Properties * [**writeableImpl](#writeableImpl) ## Properties[**](#Properties) ### [**](#writeableImpl)[**](https://undefined/midwayjs/midway/blob/3.x/packages-serverless/serverless-http-parser/src/interface.d.ts#L2)optionalwriteableImpl **writeableImpl? : { end: (chunk? : any, encoding? : string) => void; write: (chunk: any, encoding? : string) => void } Inherited from HttpResponseOptions.writeableImpl --- # @midwayjs/grpc ## Index[**](#Index) ### Classes * [**Clients](/api/grpc/class/Clients.md) * [**Configuration](/api/grpc/class/Configuration.md) * [**Framework](/api/grpc/class/Framework.md) ### Functions * [**createGRPCConsumer](/api/grpc/function/createGRPCConsumer.md) * [**loadProto](/api/grpc/function/loadProto.md) ### Interfaces * [**Context](/api/grpc/interface/Context.md) * [**DefaultConfig](/api/grpc/interface/DefaultConfig.md) * [**IClientDuplexStreamService](/api/grpc/interface/IClientDuplexStreamService.md) * [**IClientOptions](/api/grpc/interface/IClientOptions.md) * [**IClientReadableStreamService](/api/grpc/interface/IClientReadableStreamService.md) * [**IClientUnaryService](/api/grpc/interface/IClientUnaryService.md) * [**IClientWritableStreamService](/api/grpc/interface/IClientWritableStreamService.md) * [**IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md) * [**IGRPCServiceOptions](/api/grpc/interface/IGRPCServiceOptions.md) * [**IMidwayGRPFrameworkOptions](/api/grpc/interface/IMidwayGRPFrameworkOptions.md) ### Type Aliases * [**Application](/api/grpc.md#Application) * [**IMidwayGRPCApplication](/api/grpc.md#IMidwayGRPCApplication) * [**NextFunction](/api/grpc.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L39)Application **Application: [IMidwayGRPCApplication](/api/grpc.md#IMidwayGRPCApplication) ### [**](#IMidwayGRPCApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L37)IMidwayGRPCApplication **IMidwayGRPCApplication: IMidwayApplication<[Context](/api/grpc/interface/Context.md), Server> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L40)NextFunction **NextFunction: BaseNextFunction --- # Clients ### Hierarchy * Map * *Clients* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**grpcConfig](#grpcConfig) * [**logger](#logger) * [**traceEnabled](#traceEnabled) * [**traceInjector](#traceInjector) * [**traceService](#traceService) ### Methods * [**createClient](#createClient) * [**getClientRequestImpl](#getClientRequestImpl) * [**getService](#getService) * [**initService](#initService) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L51)externalconstructor * **new Clients(): [GRPCClients](/api/grpc/class/Clients.md) * **new Clients(): [GRPCClients](/api/grpc/class/Clients.md) - Inherited from Map.constructor ## Properties[**](#Properties) ### [**](#grpcConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L30)grpcConfig **grpcConfig: [DefaultConfig](/api/grpc/interface/DefaultConfig.md) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L42)logger **logger: ILogger ### [**](#traceEnabled)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L33)traceEnabled **traceEnabled: boolean ### [**](#traceInjector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L36)traceInjector **traceInjector: (args: { custom? : Record\; request? : unknown }) => any ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L45)traceService **traceService: MidwayTraceService ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L58)createClient * **createClient\(options: [IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md)): Promise\ - #### Type parameters * **T** ### [**](#getClientRequestImpl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L127)getClientRequestImpl * **getClientRequestImpl(client: any, originalFunction: any, options? : {}): any ### [**](#getService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L123)getService * **getService\(serviceName: string): T - #### Type parameters * **T** ### [**](#initService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/comsumer/clients.ts#L48)initService * **initService(): Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**clientConfig](#clientConfig) * [**logger](#logger) * [**providerConfig](#providerConfig) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [GrpcConfiguration](/api/grpc/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L33)applicationContext **applicationContext: IMidwayContainer ### [**](#clientConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L39)clientConfig **clientConfig: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L42)logger **logger: ILogger ### [**](#providerConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L36)providerConfig **providerConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L45)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/configuration.ts#L49)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayGRPCApplication](/api/grpc.md#IMidwayGRPCApplication), [Context](/api/grpc/interface/Context.md), [IMidwayGRPFrameworkOptions](/api/grpc/interface/IMidwayGRPFrameworkOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayGRPCFramework](/api/grpc/class/Framework.md) - Inherited from BaseFramework< IMidwayGRPCApplication, Context, IMidwayGRPFrameworkOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayGRPCApplication](/api/grpc.md#IMidwayGRPCApplication) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayGRPFrameworkOptions](/api/grpc/interface/IMidwayGRPFrameworkOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L52)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/grpc/interface/Context.md)\, R, N>): Promise\, R, N>> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L287)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L44)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [IMidwayGRPCApplication](/api/grpc.md#IMidwayGRPCApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L319)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/grpc/interface/Context.md)\, unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L315)publicgetServer * **getServer(): Server ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L48)isEnable * **isEnable(): boolean - Overrides BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/provider/framework.ts#L269)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/grpc/interface/Context.md)\, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/grpc/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/grpc/interface/Context.md)\>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/grpc/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # createGRPCConsumer ### Callable * **createGRPCConsumer\(options: [IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md)): Promise\ *** * #### Type parameters * **T** --- # loadProto ### Callable * **loadProto(options: { loaderOptions? : any; protoPath: string }): PackageDefinition --- # Context \ ### Hierarchy * IMidwayContext\> * *Context* ## Index[**](#Index) ### Properties * [**logger](#logger) * [**method](#method) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#method)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L34)method **method: string ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # DefaultConfig ### Hierarchy * IConfigurationOptions * *DefaultConfig* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) * [**services](#services) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#services)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L99)services **services: [IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md)\[] --- # IClientDuplexStreamService \ ## Index[**](#Index) ### Methods * [**end](#end) * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#end)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L130)end * **end(): void ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L128)getCall * **getCall(): ClientDuplexStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L126)sendMessage * **sendMessage(reqData: reqType): Promise\ --- # IClientOptions ## Index[**](#Index) ### Properties * [**messageKey](#messageKey) * [**metadata](#metadata) * [**timeout](#timeout) * [**timeoutMessage](#timeoutMessage) ## Properties[**](#Properties) ### [**](#messageKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L137)optionalmessageKey **messageKey? : string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L134)optionalmetadata **metadata? : Metadata ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L135)optionaltimeout **timeout? : number ### [**](#timeoutMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L136)optionaltimeoutMessage **timeoutMessage? : number --- # IClientReadableStreamService \ ## Index[**](#Index) ### Methods * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L114)getCall * **getCall(): ClientReadableStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L112)sendMessage * **sendMessage(reqData: reqType): Promise\ --- # IClientUnaryService \ ## Index[**](#Index) ### Methods * [**sendMessage](#sendMessage) * [**sendMessageWithCallback](#sendMessageWithCallback) ## Methods[**](#Methods) ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L103)sendMessage * **sendMessage(reqData: reqType, handler? : (call: SurfaceCall) => void): Promise\ ### [**](#sendMessageWithCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L108)sendMessageWithCallback * **sendMessageWithCallback(content: reqType, callback: any): SurfaceCall --- # IClientWritableStreamService \ ## Index[**](#Index) ### Methods * [**end](#end) * [**getCall](#getCall) * [**sendMessage](#sendMessage) ## Methods[**](#Methods) ### [**](#end)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L120)end * **end(): Promise\ ### [**](#getCall)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L122)getCall * **getCall(): ClientWritableStream\ ### [**](#sendMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L118)sendMessage * **sendMessage(reqData: reqType): [IClientWritableStreamService](/api/grpc/interface/IClientWritableStreamService.md)\ --- # IGRPCClientServiceOptions ### Hierarchy * [IGRPCServiceOptions](/api/grpc/interface/IGRPCServiceOptions.md) * *IGRPCClientServiceOptions* ## Index[**](#Index) ### Properties * [**clientOptions](#clientOptions) * [**credentials](#credentials) * [**loaderOptions](#loaderOptions) * [**package](#package) * [**protoPath](#protoPath) * [**service](#service) * [**url](#url) ## Properties[**](#Properties) ### [**](#clientOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L71)optionalclientOptions **clientOptions? : ClientOptions Client options. Optional. ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L67)optionalcredentials **credentials? : ServerCredentials Server credentials. Optional. ### [**](#loaderOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L62)optionalloaderOptions **loaderOptions? : object proto file loader options. Optional ### [**](#package)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L51)optionalpackage **package? : string Inherited from IGRPCServiceOptions.package protobuf package name ### [**](#protoPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L46)optionalprotoPath **protoPath? : string Inherited from IGRPCServiceOptions.protoPath proto path ### [**](#service)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L75)optionalservice **service? : string Service name. Optional. ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L58)url **url: string application gRPC connection string --- # IGRPCServiceOptions ### Hierarchy * *IGRPCServiceOptions* * [IGRPCClientServiceOptions](/api/grpc/interface/IGRPCClientServiceOptions.md) ## Index[**](#Index) ### Properties * [**package](#package) * [**protoPath](#protoPath) ## Properties[**](#Properties) ### [**](#package)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L51)optionalpackage **package? : string protobuf package name ### [**](#protoPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L46)optionalprotoPath **protoPath? : string proto path --- # IMidwayGRPFrameworkOptions ### Hierarchy * IConfigurationOptions * *IMidwayGRPFrameworkOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**credentials](#credentials) * [**loaderOptions](#loaderOptions) * [**logger](#logger) * [**serverOptions](#serverOptions) * [**services](#services) * [**url](#url) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#credentials)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L91)optionalcredentials **credentials? : ServerCredentials Server credentials. Optional. ### [**](#loaderOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L87)optionalloaderOptions **loaderOptions? : object proto file loader options. Optional ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L95)optionalserverOptions **serverOptions? : ChannelOptions grpc server options ### [**](#services)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L83)optionalservices **services? : [IGRPCServiceOptions](/api/grpc/interface/IGRPCServiceOptions.md)\[] ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/grpc/src/interface.ts#L82)optionalurl **url? : string gRPC Server connection url, like 'localhost:6565' --- # @midwayjs/http-proxy ## Index[**](#Index) ### Classes * [**Configuration](/api/http-proxy/class/Configuration.md) * [**HttpProxyMiddleware](/api/http-proxy/class/HttpProxyMiddleware.md) ### Interfaces * [**HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md) * [**HttpProxyStrategy](/api/http-proxy/interface/HttpProxyStrategy.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**httpProxy](#httpProxy) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [HttpProxyConfiguration](/api/http-proxy/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#httpProxy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/configuration.ts#L24)httpProxy **httpProxy: Partial<[HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md)> ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/configuration.ts#L26)onReady * **onReady(): Promise\ --- # HttpProxyMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**httpProxy](#httpProxy) * [**logger](#logger) ### Methods * [**execProxy](#execProxy) * [**getProxyList](#getProxyList) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HttpProxyMiddleware(): [HttpProxyMiddleware](/api/http-proxy/class/HttpProxyMiddleware.md) ## Properties[**](#Properties) ### [**](#httpProxy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L15)httpProxy **httpProxy: [HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L18)logger **logger: ILogger ## Methods[**](#Methods) ### [**](#execProxy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L34)execProxy * **execProxy(ctx: any, req: any, res: any, next: any, isServerless: any): Promise\ ### [**](#getProxyList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L119)getProxyList * **getProxyList(url: any): { proxy: [HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md); url: URL } ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L20)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/middleware.ts#L160)staticgetName * **getName(): string --- # HttpProxyConfig ### Hierarchy * [HttpProxyStrategy](/api/http-proxy/interface/HttpProxyStrategy.md) * *HttpProxyConfig* ## Index[**](#Index) ### Properties * [**default](#default) * [**enable](#enable) * [**host](#host) * [**ignoreHeaders](#ignoreHeaders) * [**match](#match) * [**proxyTimeout](#proxyTimeout) * [**strategy](#strategy) * [**target](#target) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L13)optionaldefault **default? : [HttpProxyStrategy](/api/http-proxy/interface/HttpProxyStrategy.md) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L12)optionalenable **enable? : boolean ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L3)optionalhost **host? : string Inherited from HttpProxyStrategy.host ### [**](#ignoreHeaders)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L6)optionalignoreHeaders **ignoreHeaders? : {} Inherited from HttpProxyStrategy.ignoreHeaders ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L2)optionalmatch **match? : RegExp Inherited from HttpProxyStrategy.match ### [**](#proxyTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L5)optionalproxyTimeout **proxyTimeout? : number Inherited from HttpProxyStrategy.proxyTimeout ### [**](#strategy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L14)optionalstrategy **strategy? : {} ### [**](#target)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L4)optionaltarget **target? : string Inherited from HttpProxyStrategy.target --- # HttpProxyStrategy ### Hierarchy * *HttpProxyStrategy* * [HttpProxyConfig](/api/http-proxy/interface/HttpProxyConfig.md) ## Index[**](#Index) ### Properties * [**host](#host) * [**ignoreHeaders](#ignoreHeaders) * [**match](#match) * [**proxyTimeout](#proxyTimeout) * [**target](#target) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L3)optionalhost **host? : string ### [**](#ignoreHeaders)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L6)optionalignoreHeaders **ignoreHeaders? : {} ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L2)optionalmatch **match? : RegExp ### [**](#proxyTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L5)optionalproxyTimeout **proxyTimeout? : number ### [**](#target)[**](https://github.com/midwayjs/midway/blob/3.x/packages/http-proxy/src/interface.ts#L4)optionaltarget **target? : string --- # @midwayjs/i18n ## Index[**](#Index) ### Classes * [**Configuration](/api/i18n/class/Configuration.md) * [**I18nFilter](/api/i18n/class/I18nFilter.md) * [**I18nMiddleware](/api/i18n/class/I18nMiddleware.md) * [**MidwayI18nService](/api/i18n/class/MidwayI18nService.md) * [**MidwayI18nServiceSingleton](/api/i18n/class/MidwayI18nServiceSingleton.md) ### Functions * [**formatLocale](/api/i18n/function/formatLocale.md) ### Interfaces * [**I18nOptions](/api/i18n/interface/I18nOptions.md) * [**RequestResolver](/api/i18n/interface/RequestResolver.md) * [**TranslateOptions](/api/i18n/interface/TranslateOptions.md) ### Variables * [**I18N\_ATTR\_KEY](/api/i18n.md#I18N_ATTR_KEY) ## Variables[**](#Variables) ### [**](#I18N_ATTR_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L26)constI18N\_ATTR\_KEY **I18N\_ATTR\_KEY: i18n:locale = 'i18n:locale' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [I18nConfiguration](/api/i18n/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/configuration.ts#L19)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/configuration.ts#L20)onReady * **onReady(): Promise\ --- # I18nFilter ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**i18nConfig](#i18nConfig) * [**resolverConfig](#resolverConfig) ### Methods * [**match](#match) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new I18nFilter(): [I18nFilter](/api/i18n/class/I18nFilter.md) ## Properties[**](#Properties) ### [**](#i18nConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L18)i18nConfig **i18nConfig: [I18nOptions](/api/i18n/interface/I18nOptions.md) ### [**](#resolverConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L15)resolverConfig **resolverConfig: false | [RequestResolver](/api/i18n/interface/RequestResolver.md) ## Methods[**](#Methods) ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L20)match * **match(value: any, req: any, res: any): any --- # I18nMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**i18nConfig](#i18nConfig) * [**resolverConfig](#resolverConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new I18nMiddleware(): [I18nMiddleware](/api/i18n/class/I18nMiddleware.md) ## Properties[**](#Properties) ### [**](#i18nConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L52)i18nConfig **i18nConfig: [I18nOptions](/api/i18n/interface/I18nOptions.md) ### [**](#resolverConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L49)resolverConfig **resolverConfig: false | [RequestResolver](/api/i18n/interface/RequestResolver.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L54)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/middleware.ts#L196)staticgetName * **getName(): string --- # MidwayI18nService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) ### Methods * [**addLocale](#addLocale) * [**getAvailableLocale](#getAvailableLocale) * [**getDefaultLocale](#getDefaultLocale) * [**getLocaleMapping](#getLocaleMapping) * [**hasAvailableLocale](#hasAvailableLocale) * [**saveRequestLocale](#saveRequestLocale) * [**translate](#translate) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayI18nService(): [MidwayI18nService](/api/i18n/class/MidwayI18nService.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L249)ctx **ctx: Context ## Methods[**](#Methods) ### [**](#addLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L263)publicaddLocale * **addLocale(locale: string, localeTextMapping: Record\): void - add a language text mapping ### [**](#getAvailableLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L299)publicgetAvailableLocale * **getAvailableLocale(locale: string, group? : string): any - get locale string by find fallback and default, ignore match message ### [**](#getDefaultLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L279)publicgetDefaultLocale * **getDefaultLocale(): string - get current default language ### [**](#getLocaleMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L272)publicgetLocaleMapping * **getLocaleMapping(locale: any, group? : string): Map\ - get mapping by lang ### [**](#hasAvailableLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L307)publichasAvailableLocale * **hasAvailableLocale(locale: string): boolean - get available local in locale text map, include fallbacks ### [**](#saveRequestLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L286)publicsaveRequestLocale * **saveRequestLocale(locale? : string): void - save current context lang to flag, middleware will be set it to cookie ### [**](#translate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L251)publictranslate * **translate(message: string, options? : [TranslateOptions](/api/i18n/interface/TranslateOptions.md)): any --- # MidwayI18nServiceSingleton ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addLocale](#addLocale) * [**getAvailableLocale](#getAvailableLocale) * [**getDefaultLocale](#getDefaultLocale) * [**getLocaleList](#getLocaleList) * [**getLocaleMapping](#getLocaleMapping) * [**getOriginLocaleJSON](#getOriginLocaleJSON) * [**hasAvailableLocale](#hasAvailableLocale) * [**translate](#translate) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MidwayI18nServiceSingleton(): [MidwayI18nServiceSingleton](/api/i18n/class/MidwayI18nServiceSingleton.md) ## Methods[**](#Methods) ### [**](#addLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L50)publicaddLocale * **addLocale(locale: string, localeTextMapping: Record\): void - add a language text mapping ### [**](#getAvailableLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L125)publicgetAvailableLocale * **getAvailableLocale(locale: string, group? : string): any - get locale string by find fallback and default, ignore match message ### [**](#getDefaultLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L225)publicgetDefaultLocale * **getDefaultLocale(): string - get current default language ### [**](#getLocaleList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L203)publicgetLocaleList * **getLocaleList(group? : string): any\[] - get locale list by group * **@since** 4.0.0 ### [**](#getLocaleMapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L188)publicgetLocaleMapping * **getLocaleMapping(locale: string, group? : string): Map\ - get mapping by locale ### [**](#getOriginLocaleJSON)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L217)publicgetOriginLocaleJSON * **getOriginLocaleJSON(locale: string, group? : string): any - get origin locale json * **@since** 4.0.0 ### [**](#hasAvailableLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L163)publichasAvailableLocale * **hasAvailableLocale(locale: string): boolean - get available local in locale text map, include fallbacks ### [**](#translate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/i18nService.ts#L79)publictranslate * **translate(message: string, options? : [TranslateOptions](/api/i18n/interface/TranslateOptions.md)): any - translate a message --- # formatLocale ### Callable * **formatLocale(locale: string): string --- # I18nOptions ## Index[**](#Index) ### Properties * [**defaultLocale](#defaultLocale) * [**fallbacks](#fallbacks) * [**localeTable](#localeTable) * [**localsField](#localsField) * [**missingKeyHandler](#missingKeyHandler) * [**resolver](#resolver) * [**writeCookie](#writeCookie) ## Properties[**](#Properties) ### [**](#defaultLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L17)defaultLocale **defaultLocale: string ### [**](#fallbacks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L19)fallbacks **fallbacks: Record\ ### [**](#localeTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L18)localeTable **localeTable: Record\> ### [**](#localsField)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L22)localsField **localsField: string ### [**](#missingKeyHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L23)optionalmissingKeyHandler **missingKeyHandler? : (message: string, options? : [TranslateOptions](/api/i18n/interface/TranslateOptions.md)) => string ### [**](#resolver)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L21)resolver **resolver: false | [RequestResolver](/api/i18n/interface/RequestResolver.md) ### [**](#writeCookie)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L20)writeCookie **writeCookie: boolean --- # RequestResolver ## Index[**](#Index) ### Properties * [**cookieField](#cookieField) * [**queryField](#queryField) ## Properties[**](#Properties) ### [**](#cookieField)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L9)cookieField **cookieField: { cookieDomain: string; cookieMaxAge: number; fieldName: string } ### [**](#queryField)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L8)queryField **queryField: string --- # TranslateOptions ## Index[**](#Index) ### Properties * [**args](#args) * [**group](#group) * [**locale](#locale) ## Properties[**](#Properties) ### [**](#args)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L4)optionalargs **args? : any ### [**](#group)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L3)optionalgroup **group? : string ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/i18n/src/interface.ts#L2)optionallocale **locale? : string --- # @midwayjs/info ## Index[**](#Index) ### Classes * [**Configuration](/api/info/class/Configuration.md) * [**InfoMiddleware](/api/info/class/InfoMiddleware.md) * [**InfoService](/api/info/class/InfoService.md) ### Enumerations * [**InfoType](/api/info/enum/InfoType.md) ### Interfaces * [**InfoConfigOptions](/api/info/interface/InfoConfigOptions.md) * [**TypeInfo](/api/info/interface/TypeInfo.md) ### Type Aliases * [**InfoValueType](/api/info.md#InfoValueType) ### Variables * [**DefaultHiddenKey](/api/info.md#DefaultHiddenKey) ## Type Aliases[**](<#Type Aliases>) ### [**](#InfoValueType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L1)InfoValueType **InfoValueType: html | json ## Variables[**](#Variables) ### [**](#DefaultHiddenKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L3)constDefaultHiddenKey **DefaultHiddenKey: string\[] = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [InfoConfiguration](/api/info/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/configuration.ts#L19)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # InfoMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new InfoMiddleware(): [InfoMiddleware](/api/info/class/InfoMiddleware.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/middleware/info.middleware.ts#L12)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ | (ctx: any, next: any) => Promise\ ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/middleware/info.middleware.ts#L34)staticgetName * **getName(): string --- # InfoService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**container](#container) * [**defaultHiddenKey](#defaultHiddenKey) * [**environment](#environment) * [**ignoreKey](#ignoreKey) * [**midwayInformationService](#midwayInformationService) * [**secretMatchList](#secretMatchList) * [**titleConfig](#titleConfig) ### Methods * [**dependenciesInfo](#dependenciesInfo) * [**envInfo](#envInfo) * [**info](#info) * [**init](#init) * [**midwayConfig](#midwayConfig) * [**midwayService](#midwayService) * [**networkInfo](#networkInfo) * [**projectInfo](#projectInfo) * [**resourceOccupationInfo](#resourceOccupationInfo) * [**softwareInfo](#softwareInfo) * [**systemInfo](#systemInfo) * [**timeInfo](#timeInfo) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new InfoService(): [InfoService](/api/info/class/InfoService.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L36)configService **configService: MidwayConfigService ### [**](#container)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L53)container **container: IMidwayContainer ### [**](#defaultHiddenKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L45)defaultHiddenKey **defaultHiddenKey: string\[] ### [**](#environment)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L39)environment **environment: MidwayEnvironmentService ### [**](#ignoreKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L48)ignoreKey **ignoreKey: string\[] ### [**](#midwayInformationService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L33)midwayInformationService **midwayInformationService: MidwayInformationService ### [**](#secretMatchList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L50)secretMatchList **secretMatchList: any\[] ### [**](#titleConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L42)titleConfig **titleConfig: string ## Methods[**](#Methods) ### [**](#dependenciesInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L237)dependenciesInfo * **dependenciesInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#envInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L179)envInfo * **envInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L64)info * **info(infoValueType? : [InfoValueType](/api/info.md#InfoValueType)): string | { info: {}; type: string }\[] ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L56)init * **init(): Promise\ ### [**](#midwayConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L271)midwayConfig * **midwayConfig(): { info: {}; type: [InfoType](/api/info/enum/InfoType.md) } ### [**](#midwayService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L253)midwayService * **midwayService(): { info: {}; type: [InfoType](/api/info/enum/InfoType.md) } ### [**](#networkInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L206)networkInfo * **networkInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#projectInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L94)projectInfo * **projectInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#resourceOccupationInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L125)resourceOccupationInfo * **resourceOccupationInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#softwareInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L160)softwareInfo * **softwareInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#systemInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L107)systemInfo * **systemInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) ### [**](#timeInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/infoService.ts#L190)timeInfo * **timeInfo(): [TypeInfo](/api/info/interface/TypeInfo.md) --- # InfoType ## Index[**](#Index) ### Enumeration Members * [**DEPENDENCIES](#DEPENDENCIES) * [**ENVIRONMENT\_VARIABLE](#ENVIRONMENT_VARIABLE) * [**MEMORY\_CPU](#MEMORY_CPU) * [**MIDWAY\_CONFIG](#MIDWAY_CONFIG) * [**MIDWAY\_SERVICE](#MIDWAY_SERVICE) * [**NETWORK](#NETWORK) * [**PROJECT](#PROJECT) * [**RESOURCE](#RESOURCE) * [**SOFTWARE](#SOFTWARE) * [**SYSTEM](#SYSTEM) * [**TIME](#TIME) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DEPENDENCIES)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L28)DEPENDENCIES **DEPENDENCIES: Dependencies ### [**](#ENVIRONMENT_VARIABLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L24)ENVIRONMENT\_VARIABLE **ENVIRONMENT\_VARIABLE: Environment Variable ### [**](#MEMORY_CPU)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L22)MEMORY\_CPU **MEMORY\_CPU: Memory & CPU ### [**](#MIDWAY_CONFIG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L30)MIDWAY\_CONFIG **MIDWAY\_CONFIG: Midway Config ### [**](#MIDWAY_SERVICE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L29)MIDWAY\_SERVICE **MIDWAY\_SERVICE: Midway Service ### [**](#NETWORK)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L26)NETWORK **NETWORK: Network ### [**](#PROJECT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L20)PROJECT **PROJECT: Project ### [**](#RESOURCE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L27)RESOURCE **RESOURCE: Resource ### [**](#SOFTWARE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L23)SOFTWARE **SOFTWARE: Software ### [**](#SYSTEM)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L21)SYSTEM **SYSTEM: System ### [**](#TIME)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L25)TIME **TIME: Time --- # InfoConfigOptions ## Index[**](#Index) ### Properties * [**hiddenKey](#hiddenKey) * [**ignoreKey](#ignoreKey) * [**infoPath](#infoPath) * [**title](#title) ## Properties[**](#Properties) ### [**](#hiddenKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L15)hiddenKey **hiddenKey: string\[] ### [**](#ignoreKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L16)ignoreKey **ignoreKey: string\[] ### [**](#infoPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L14)infoPath **infoPath: string ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L13)title **title: string --- # TypeInfo ## Index[**](#Index) ### Properties * [**info](#info) * [**type](#type) ## Properties[**](#Properties) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L7)info **info: {} ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/info/src/interface.ts#L6)type **type: string --- # @midwayjs/jwt ## Index[**](#Index) ### Classes * [**Configuration](/api/jwt/class/Configuration.md) * [**JwtService](/api/jwt/class/JwtService.md) ### Type Aliases * [**JwtConfig](/api/jwt.md#JwtConfig) * [**JwtUserConfig](/api/jwt.md#JwtUserConfig) ## Type Aliases[**](<#Type Aliases>) ### [**](#JwtConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/interface.ts#L9)JwtConfig **JwtConfig: { decode? : DecodeOptions; secret? : string; sign? : SignOptions; verify? : VerifyOptions } ### [**](#JwtUserConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/interface.ts#L3)JwtUserConfig **JwtUserConfig: (SignOptions & { secret? : string }) | [JwtConfig](/api/jwt.md#JwtConfig) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [JwtConfiguration](/api/jwt/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/configuration.ts#L15)publiconReady * **onReady(container: IMidwayContainer): Promise\ --- # JwtService @see ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**decode](#decode) * [**decodeSync](#decodeSync) * [**getDecodeOptions](#getDecodeOptions) * [**getSignOptions](#getSignOptions) * [**getVerifyOptions](#getVerifyOptions) * [**isSecret](#isSecret) * [**sign](#sign) * [**signSync](#signSync) * [**verify](#verify) * [**verifySync](#verifySync) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new JwtService(): [JwtService](/api/jwt/class/JwtService.md) ## Methods[**](#Methods) ### [**](#decode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L194)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L198)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L202)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L206)publicdecode * **decode(token: string, options: DecodeOptions & { complete: true }): Jwt * **decode(token: string, options: DecodeOptions & { json: true }): JwtPayload * **decode(token: string, options? : DecodeOptions): JwtPayload - Returns the decoded payload without verifying if the signature is valid. token - JWT string to decode \[options] - Options for decoding returns - The decoded Token ### [**](#decodeSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L215)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L219)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L223)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L227)publicdecodeSync * **decodeSync(token: string, options: DecodeOptions & { complete: true }): Jwt * **decodeSync(token: string, options: DecodeOptions & { json: true }): JwtPayload * **decodeSync(token: string, options? : DecodeOptions): JwtPayload - alias decode method ### [**](#getDecodeOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L249)getDecodeOptions * **getDecodeOptions(options? : DecodeOptions): DecodeOptions ### [**](#getSignOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L231)getSignOptions * **getSignOptions(options? : SignOptions): SignOptions | [JwtConfig](/api/jwt.md#JwtConfig) ### [**](#getVerifyOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L242)getVerifyOptions * **getVerifyOptions(options? : VerifyOptions): VerifyOptions ### [**](#isSecret)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L256)isSecret * **isSecret(secret: any): secret is Secret ### [**](#sign)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L69)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L73)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L78)publicsign * **sign(payload: JwtPayload, options? : SignOptions): Promise\ * **sign(payload: JwtPayload, secretOrPrivateKey: Secret, options? : SignOptions): Promise\ - Asynchronous sign the given payload into a JSON Web Token string payload - Payload to sign, could be an literal, buffer or string secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA. \[options] - Options for the signature returns - The JSON Web Token string ### [**](#signSync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L39)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L40)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L45)publicsignSync * **signSync(payload: JwtPayload, options? : SignOptions): string * **signSync(payload: JwtPayload, secretOrPrivateKey: Secret, options? : SignOptions): string - Synchronously sign the given payload into a JSON Web Token string payload - Payload to sign, could be an literal, buffer or string secretOrPrivateKey - Either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA. \[options] - Options for the signature returns - The JSON Web Token string ### [**](#verify)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L145)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L149)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L153)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L158)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L163)publicverify * **verify(token: string, options? : VerifyOptions & { complete: true }): Promise\ * **verify(token: string, options? : VerifyOptions): Promise\ * **verify(token: string, secretOrPublicKey: Secret | GetPublicKeyOrSecret, options? : VerifyOptions & { complete: true }): Promise\ * **verify(token: string, secretOrPublicKey: Secret | GetPublicKeyOrSecret, options? : VerifyOptions): Promise\ - Asynchronous verify given token using a secret or a public key to get a decoded token token - JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. \[options] - Options for the verification returns - The decoded token. ### [**](#verifySync)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L110)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L114)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L115)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L120)[**](https://github.com/midwayjs/midway/blob/3.x/packages/jwt/src/jwt.ts#L125)publicverifySync * **verifySync(token: string, options: VerifyOptions & { complete: true }): string | Jwt * **verifySync(token: string, options: VerifyOptions): JwtPayload * **verifySync(token: string, secretOrPublicKey: Secret, options? : VerifyOptions & { complete: true }): string | Jwt * **verifySync(token: string, secretOrPublicKey: Secret, options? : VerifyOptions): JwtPayload - Synchronously verify given token using a secret or a public key to get a decoded token token - JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA. \[options] - Options for the verification returns - The decoded token. --- # @midwayjs/kafka ## Index[**](#Index) ### Classes * [**Configuration](/api/kafka/class/Configuration.md) * [**Framework](/api/kafka/class/Framework.md) * [**KafkaAdminFactory](/api/kafka/class/KafkaAdminFactory.md) * [**KafkaProducerFactory](/api/kafka/class/KafkaProducerFactory.md) ### Functions * [**KafkaConsumer](/api/kafka/function/KafkaConsumer.md) ### Interfaces * [**Context](/api/kafka/interface/Context.md) * [**IKafkaApplication](/api/kafka/interface/IKafkaApplication.md) * [**IKafkaConsumer](/api/kafka/interface/IKafkaConsumer.md) * [**IKafkaConsumerInitOptions](/api/kafka/interface/IKafkaConsumerInitOptions.md) * [**IMidwayConsumerConfig](/api/kafka/interface/IMidwayConsumerConfig.md) * [**IMidwayKafkaAdminInitOptions](/api/kafka/interface/IMidwayKafkaAdminInitOptions.md) * [**IMidwayKafkaConfigurationOptions](/api/kafka/interface/IMidwayKafkaConfigurationOptions.md) * [**IMidwayKafkaProducerInitOptions](/api/kafka/interface/IMidwayKafkaProducerInitOptions.md) ### Type Aliases * [**Application](/api/kafka.md#Application) * [**DefaultConfig](/api/kafka.md#DefaultConfig) * [**IMidwayKafkaApplication](/api/kafka.md#IMidwayKafkaApplication) * [**IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext) * [**NextFunction](/api/kafka.md#NextFunction) ### Variables * [**KAFKA\_DECORATOR\_KEY](/api/kafka.md#KAFKA_DECORATOR_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L50)Application **Application: [IMidwayKafkaApplication](/api/kafka.md#IMidwayKafkaApplication) ### [**](#DefaultConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L53)DefaultConfig **DefaultConfig: string | Kafka ### [**](#IMidwayKafkaApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L26)IMidwayKafkaApplication **IMidwayKafkaApplication: IMidwayApplication<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext)> & [IKafkaApplication](/api/kafka/interface/IKafkaApplication.md) ### [**](#IMidwayKafkaContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L29)IMidwayKafkaContext **IMidwayKafkaContext: IMidwayContext<{ consumer: Consumer; message? : any; partition? : any; payload: EachMessagePayload | EachBatchPayload; topic? : any; commitOffsets? : any }> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L52)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#KAFKA_DECORATOR_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/decorator.ts#L8)constKAFKA\_DECORATOR\_KEY **KAFKA\_DECORATOR\_KEY: rpc:kafka = 'rpc:kafka' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [KafkaConfiguration](/api/kafka/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/configuration.ts#L22)onReady * **onReady(container: IMidwayContainer): Promise\ --- # Framework ### Hierarchy * BaseFramework\ * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConsumer](#getConsumer) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getKafka](#getKafka) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayKafkaFramework](/api/kafka/class/Framework.md) - Inherited from BaseFramework< any, IMidwayKafkaContext, any >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: any Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: any Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L52)applicationInitialize * **applicationInitialize(): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L48)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): any - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConsumer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L185)publicgetConsumer * **getConsumer(subscriberNameOrInstanceName: string): any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L197)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getKafka)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L193)publicgetKafka * **getKafka(instanceName: string): Kafka ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/framework.ts#L66)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # KafkaAdminFactory ### Hierarchy * ServiceFactory\ * *KafkaAdminFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**adminConfig](#adminConfig) * [**logger](#logger) ### Methods * [**createInstance](#createInstance) * [**destroy](#destroy) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new KafkaAdminFactory(): [KafkaAdminFactory](/api/kafka/class/KafkaAdminFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#adminConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L149)adminConfig **adminConfig: ServiceFactoryConfigOption<[IMidwayKafkaProducerInitOptions](/api/kafka/interface/IMidwayKafkaProducerInitOptions.md)> ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L146)logger **logger: ILogger ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L190)destroy * **destroy(): Promise\ ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L184)destroyClient * **destroyClient(admin: Admin, name: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Admin ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L151)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L156)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # KafkaProducerFactory ### Hierarchy * ServiceFactory\ * *KafkaProducerFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**pubConfig](#pubConfig) * [**traceEnabled](#traceEnabled) * [**traceInjector](#traceInjector) * [**traceService](#traceService) ### Methods * [**createInstance](#createInstance) * [**destroy](#destroy) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new KafkaProducerFactory(): [KafkaProducerFactory](/api/kafka/class/KafkaProducerFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L24)logger **logger: ILogger ### [**](#pubConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L27)pubConfig **pubConfig: ServiceFactoryConfigOption<[IMidwayKafkaProducerInitOptions](/api/kafka/interface/IMidwayKafkaProducerInitOptions.md)> ### [**](#traceEnabled)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L33)traceEnabled **traceEnabled: boolean ### [**](#traceInjector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L36)traceInjector **traceInjector: (args: { custom? : Record\; request? : unknown }) => any ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L30)traceService **traceService: MidwayTraceService ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L138)destroy * **destroy(): Promise\ ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L132)destroyClient * **destroyClient(producer: Producer, name: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Producer ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L41)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/service.ts#L46)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # KafkaConsumer ### Callable * **KafkaConsumer(consumerName: string): ClassDecorator --- # Context ### Hierarchy * [IMidwayKafkaContext](/api/kafka.md#IMidwayKafkaContext) * *Context* ## Index[**](#Index) ### Properties * [**consumer](#consumer) * [**logger](#logger) * [**message](#message) * [**partition](#partition) * [**payload](#payload) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**topic](#topic) * [**traceId](#traceId) ### Methods * [**commitOffsets](#commitOffsets) * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#consumer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L47)consumer **consumer: Consumer Inherited from IMidwayKafkaContext.consumer ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayKafkaContext.logger ### [**](#message)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L41)optionalmessage **message? : any Inherited from IMidwayKafkaContext.message * **@deprecated** please use `ctx.payload` instead ### [**](#partition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L37)optionalpartition **partition? : any Inherited from IMidwayKafkaContext.partition * **@deprecated** please use `ctx.payload` instead ### [**](#payload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L46)payload **payload: EachMessagePayload | EachBatchPayload Inherited from IMidwayKafkaContext.payload ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayKafkaContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayKafkaContext.startTime ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L33)optionaltopic **topic? : any Inherited from IMidwayKafkaContext.topic * **@deprecated** please use `ctx.payload` instead ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayKafkaContext.traceId ## Methods[**](#Methods) ### [**](#commitOffsets)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L45)optionalcommitOffsets * **commitOffsets(data: any): void - Inherited from IMidwayKafkaContext.commitOffsets * **@deprecated** please use `ctx.consumer.commitOffsets` instead ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayKafkaContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayKafkaContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayKafkaContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayKafkaContext.setAttr Set value to app attribute map --- # IKafkaApplication --- # IKafkaConsumer ## Index[**](#Index) ### Properties * [**eachBatch](#eachBatch) * [**eachMessage](#eachMessage) ## Properties[**](#Properties) ### [**](#eachBatch)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L114)optionaleachBatch **eachBatch? : EachBatchHandler ### [**](#eachMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L115)optionaleachMessage **eachMessage? : EachMessageHandler --- # IKafkaConsumerInitOptions The options for the kafka consumer initialization in midway ## Index[**](#Index) ### Properties * [**connectionOptions](#connectionOptions) * [**consumerOptions](#consumerOptions) * [**consumerRunConfig](#consumerRunConfig) * [**kafkaInstanceRef](#kafkaInstanceRef) * [**subscribeOptions](#subscribeOptions) ## Properties[**](#Properties) ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L72)connectionOptions **connectionOptions: KafkaConfig The connection options for the kafka instance ### [**](#consumerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L76)consumerOptions **consumerOptions: ConsumerConfig The consumer options for the kafka consumer ### [**](#consumerRunConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L78)consumerRunConfig **consumerRunConfig: ConsumerRunConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L79)optionalkafkaInstanceRef **kafkaInstanceRef? : string ### [**](#subscribeOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L77)subscribeOptions **subscribeOptions: ConsumerSubscribeTopics | ConsumerSubscribeTopic --- # IMidwayConsumerConfig 客户端的相关配置,在midwayjs的自定义配置项 * **@deprecated** ## Index[**](#Index) ### Properties * [**runConfig](#runConfig) * [**subscription](#subscription) * [**topic](#topic) ## Properties[**](#Properties) ### [**](#runConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L62)runConfig **runConfig: any ### [**](#subscription)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L61)subscription **subscription: any ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L60)topic **topic: string --- # IMidwayKafkaAdminInitOptions The options for the kafka admin initialization in midway ## Index[**](#Index) ### Properties * [**adminOptions](#adminOptions) * [**connectionOptions](#connectionOptions) * [**kafkaInstanceRef](#kafkaInstanceRef) ## Properties[**](#Properties) ### [**](#adminOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L100)adminOptions **adminOptions: AdminConfig The options for the kafka admin initialization ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L96)connectionOptions **connectionOptions: KafkaConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L95)optionalkafkaInstanceRef **kafkaInstanceRef? : string --- # IMidwayKafkaConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayKafkaConfigurationOptions* ## Index[**](#Index) ### Properties * [**admin](#admin) * [**appLogger](#appLogger) * [**consumer](#consumer) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) * [**producer](#producer) ## Properties[**](#Properties) ### [**](#admin)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L110)admin **admin: ServiceFactoryConfigOption\> ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#consumer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L104)consumer **consumer: {} ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#producer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L107)producer **producer: ServiceFactoryConfigOption\> --- # IMidwayKafkaProducerInitOptions The options for the kafka producer initialization in midway ## Index[**](#Index) ### Properties * [**connectionOptions](#connectionOptions) * [**kafkaInstanceRef](#kafkaInstanceRef) * [**producerOptions](#producerOptions) ## Properties[**](#Properties) ### [**](#connectionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L86)connectionOptions **connectionOptions: KafkaConfig ### [**](#kafkaInstanceRef)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L88)optionalkafkaInstanceRef **kafkaInstanceRef? : string ### [**](#producerOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/kafka/src/interface.ts#L87)producerOptions **producerOptions: ProducerConfig --- # @midwayjs/leoric ## Index[**](#Index) ### Classes * [**Configuration](/api/leoric/class/Configuration.md) * [**LeoricDataSourceManager](/api/leoric/class/LeoricDataSourceManager.md) ### Functions * [**InjectDataSource](/api/leoric/function/InjectDataSource.md) * [**InjectModel](/api/leoric/function/InjectModel.md) ### Type Aliases * [**ClassLikeBone](/api/leoric.md#ClassLikeBone) * [**LeoricConfigOption](/api/leoric.md#LeoricConfigOption) ## Type Aliases[**](<#Type Aliases>) ### [**](#ClassLikeBone)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/interface.ts#L9)ClassLikeBone **ClassLikeBone: new (...args: any) => Bone ### [**](#LeoricConfigOption)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/interface.ts#L4)LeoricConfigOption **LeoricConfigOption: DataSourceManagerConfigOption\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [LeoricConfiguration](/api/leoric/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L36)applicationContext **applicationContext: IMidwayContainer ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L38)dataSourceManager **dataSourceManager: [LeoricDataSourceManager](/api/leoric/class/LeoricDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L33)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L41)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L94)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/configuration.ts#L98)onStop * **onStop(): Promise\ --- # LeoricDataSourceManager ### Hierarchy * DataSourceManager\ * *LeoricDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**coreLogger](#coreLogger) * [**leoricConfig](#leoricConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new LeoricDataSourceManager(): [LeoricDataSourceManager](/api/leoric/class/LeoricDataSourceManager.md) - Inherited from DataSourceManager< Realm, ConnectOptions >.constructor ## Properties[**](#Properties) ### [**](#coreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/dataSourceManager.ts#L24)coreLogger **coreLogger: ILogger ### [**](#leoricConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/dataSourceManager.ts#L21)leoricConfig **leoricConfig: [LeoricConfigOption](/api/leoric.md#LeoricConfigOption) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L36)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L37)createInstance * **createInstance(config: ConnectOptions): Promise\ * **createInstance(config: ConnectOptions, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L30)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L23)getDataSource * **getDataSource(dataSourceName: string): default - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L29)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L61)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L60)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/dataSourceManager.ts#L39)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/leoric/src/dataSourceManager.ts#L27)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L35)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L62)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L64)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L63)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L59)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L65)staticformatGlobString * **formatGlobString(globString: string): string\[] - Inherited from DataSourceManager.formatGlobString ### [**](#globModels)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L66)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : ModuleLoadType): Promise\ - Inherited from DataSourceManager.globModels --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectModel ### Callable * **InjectModel(modelName? : string | [ClassLikeBone](/api/leoric.md#ClassLikeBone), dataSourceName? : string): (target: object, propertyKey: string | symbol) => void --- # @midwayjs/mcp ## Index[**](#Index) ### Classes * [**Configuration](/api/mcp/class/Configuration.md) * [**MCPAuthInfoMiddleware](/api/mcp/class/MCPAuthInfoMiddleware.md) * [**MidwayMCPFramework](/api/mcp/class/MidwayMCPFramework.md) ### Functions * [**Prompt](/api/mcp/function/Prompt.md) * [**Resource](/api/mcp/function/Resource.md) * [**Tool](/api/mcp/function/Tool.md) ### Interfaces * [**Context](/api/mcp/interface/Context.md) * [**IMcpPrompt](/api/mcp/interface/IMcpPrompt.md) * [**IMcpResource](/api/mcp/interface/IMcpResource.md) * [**IMcpTool](/api/mcp/interface/IMcpTool.md) * [**IMidwayMCPConfigurationOptions](/api/mcp/interface/IMidwayMCPConfigurationOptions.md) * [**IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md) ### References * [**Framework](/api/mcp.md#Framework) ### Type Aliases * [**Application](/api/mcp.md#Application) * [**IMidwayMCPApplication](/api/mcp.md#IMidwayMCPApplication) * [**NextFunction](/api/mcp.md#NextFunction) * [**PromptConfig](/api/mcp.md#PromptConfig) * [**ResourceConfig](/api/mcp.md#ResourceConfig) * [**ToolConfig](/api/mcp.md#ToolConfig) ### Variables * [**MCP\_PROMPT\_KEY](/api/mcp.md#MCP_PROMPT_KEY) * [**MCP\_RESOURCE\_KEY](/api/mcp.md#MCP_RESOURCE_KEY) * [**MCP\_TOOL\_KEY](/api/mcp.md#MCP_TOOL_KEY) ## References[**](#References) ### [**](#Framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/index.ts#L4)Framework Renames and re-exports [MidwayMCPFramework](/api/mcp/class/MidwayMCPFramework.md) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L60)Application **Application: [IMidwayMCPApplication](/api/mcp.md#IMidwayMCPApplication) ### [**](#IMidwayMCPApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L58)IMidwayMCPApplication **IMidwayMCPApplication: IMidwayApplication<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md)> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L62)NextFunction **NextFunction: BaseNextFunction ### [**](#PromptConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L25)PromptConfig **PromptConfig\: { argsSchema? : Args; description? : string; title? : string } #### Type parameters * **Args**: PromptArgsRawShape = any ### [**](#ResourceConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L45)ResourceConfig **ResourceConfig: { \_meta? : Record\; description? : string; mimeType? : string; template? : ResourceTemplate; title? : string; uri? : string } ### [**](#ToolConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L32)ToolConfig **ToolConfig\: { \_meta? : Record\; annotations? : ToolAnnotations; description? : string; inputSchema? : InputArgs; outputSchema? : OutputArgs; title? : string } #### Type parameters * **InputArgs**: ZodRawShape = any * **OutputArgs**: ZodRawShape = any ## Variables[**](#Variables) ### [**](#MCP_PROMPT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L13)constMCP\_PROMPT\_KEY **MCP\_PROMPT\_KEY: mcp:prompt = 'mcp:prompt' ### [**](#MCP_RESOURCE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L11)constMCP\_RESOURCE\_KEY **MCP\_RESOURCE\_KEY: mcp:resource = 'mcp:resource' ### [**](#MCP_TOOL_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/decorator.ts#L12)constMCP\_TOOL\_KEY **MCP\_TOOL\_KEY: mcp:tool = 'mcp:tool' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) * [**framework](#framework) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MCPConfiguration](/api/mcp/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/configuration.ts#L44)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/configuration.ts#L41)configService **configService: MidwayConfigService ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/configuration.ts#L38)framework **framework: [MidwayMCPFramework](/api/mcp/class/MidwayMCPFramework.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/configuration.ts#L46)onReady * **onReady(): Promise\ - Implementation of ILifeCycle.onReady --- # MCPAuthInfoMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MCPAuthInfoMiddleware(): [MCPAuthInfoMiddleware](/api/mcp/class/MCPAuthInfoMiddleware.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/middleware/auth.middleware.ts#L23)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve --- # MidwayMCPFramework ### Hierarchy * BaseFramework<[IMidwayMCPApplication](/api/mcp.md#IMidwayMCPApplication), [IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), [IMidwayMCPConfigurationOptions](/api/mcp/interface/IMidwayMCPConfigurationOptions.md)> * *MidwayMCPFramework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**initialize](#initialize) * [**initializeMCPTransport](#initializeMCPTransport) * [**isEnable](#isEnable) * [**loadPrompts](#loadPrompts) * [**loadResources](#loadResources) * [**loadTools](#loadTools) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new MidwayMCPFramework(applicationContext: IMidwayGlobalContainer): [MidwayMCPFramework](/api/mcp/class/MidwayMCPFramework.md) - Inherited from BaseFramework< IMidwayMCPApplication, IMidwayMCPContext, IMidwayMCPConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: IMidwayBaseApplication<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md)> Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayMCPConfigurationOptions](/api/mcp/interface/IMidwayMCPConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L172)applicationInitialize * **applicationInitialize(): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L168)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): IMidwayBaseApplication<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md)> - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L533)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L519)publicgetServer * **getServer(): McpServer ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#initializeMCPTransport)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L188)publicinitializeMCPTransport * **initializeMCPTransport(webApp: IMidwayBaseApplication\): Promise\ ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadPrompts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L421)publicloadPrompts * **loadPrompts(): void ### [**](#loadResources)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L468)publicloadResources * **loadResources(): void ### [**](#loadTools)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L373)publicloadTools * **loadTools(): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/framework.ts#L362)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # Prompt ### Callable * **Prompt\(promptName: string, promptConfig: [PromptConfig](/api/mcp.md#PromptConfig)\): ClassDecorator *** * #### Type parameters * **Args**: PromptArgsRawShape = any --- # Resource ### Callable * **Resource(resourceName: string, resourceConfig: string | ResourceTemplate | [ResourceConfig](/api/mcp.md#ResourceConfig)): ClassDecorator --- # Tool ### Callable * **Tool\(toolName: string, toolConfig: [ToolConfig](/api/mcp.md#ToolConfig)\): ClassDecorator *** * #### Type parameters * **InputArgs**: ZodRawShape = any * **OutputArgs**: ZodRawShape = any --- # Context ### Hierarchy * [IMidwayMCPContext](/api/mcp/interface/IMidwayMCPContext.md) * *Context* ## Index[**](#Index) ### Properties * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayMCPContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayMCPContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayMCPContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayMCPContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayMCPContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayMCPContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayMCPContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayMCPContext.setAttr Set value to app attribute map --- # IMcpPrompt ## Index[**](#Index) ### Methods * [**generate](#generate) ## Methods[**](#Methods) ### [**](#generate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L73)generate * **generate(...args: any\[]): Promise<{}> --- # IMcpResource ## Index[**](#Index) ### Methods * [**handle](#handle) ## Methods[**](#Methods) ### [**](#handle)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L65)handle * **handle(...args: any\[]): Promise<{}> --- # IMcpTool ## Index[**](#Index) ### Methods * [**execute](#execute) ## Methods[**](#Methods) ### [**](#execute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L69)execute * **execute(...args: any\[]): Promise<{}> --- # IMidwayMCPConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayMCPConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**enableJwtAuthHelper](#enableJwtAuthHelper) * [**endpoints](#endpoints) * [**jwtAuthCustomPayloadTransformer](#jwtAuthCustomPayloadTransformer) * [**logger](#logger) * [**serverInfo](#serverInfo) * [**serverOptions](#serverOptions) * [**transportOptions](#transportOptions) * [**transportType](#transportType) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#enableJwtAuthHelper)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L50)optionalenableJwtAuthHelper **enableJwtAuthHelper? : boolean Enable built-in JWT authentication middleware (default: false) ### [**](#endpoints)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L32)optionalendpoints **endpoints? : { messages? : string; sse? : string; streamHttp? : string } Endpoint paths for different transport types ### [**](#jwtAuthCustomPayloadTransformer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L52)optionaljwtAuthCustomPayloadTransformer **jwtAuthCustomPayloadTransformer? : (payload: any, token: string) => AuthInfo Custom JWT payload transformer function ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#serverInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L20)serverInfo **serverInfo: {} ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L21)optionalserverOptions **serverOptions? : ServerOptions ### [**](#transportOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L43)optionaltransportOptions **transportOptions? : { sse? : SSEServerTransportOptions; streamHttp? : WebStandardStreamableHTTPServerTransportOptions } Transport-specific options using SDK types ### [**](#transportType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mcp/src/interface.ts#L28)transportType **transportType: stdio | sse | stream-http Transport type for MCP communication * 'stdio': Standard input/output transport for CLI applications * 'stream-http': HTTP-based transport with streaming support and backward compatibility with SSE * 'sse': Legacy SSE transport (deprecated, use 'stream-http' instead which provides backward compatibility) --- # IMidwayMCPContext ### Hierarchy * IMidwayContext * Partial\> * *IMidwayMCPContext* * [Context](/api/mcp/interface/Context.md) ## Index[**](#Index) ### Properties * [**logger](#logger) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayContext.logger ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayContext.setAttr Set value to app attribute map --- # @midwayjs/mikro ## Index[**](#Index) ### Classes * [**Configuration](/api/mikro/class/Configuration.md) * [**MikroDataSourceManager](/api/mikro/class/MikroDataSourceManager.md) ### Functions * [**InjectDataSource](/api/mikro/function/InjectDataSource.md) * [**InjectEntityManager](/api/mikro/function/InjectEntityManager.md) * [**InjectRepository](/api/mikro/function/InjectRepository.md) ### Type Aliases * [**MikroConfigOptions](/api/mikro.md#MikroConfigOptions) ### Variables * [**DATA\_SOURCE\_KEY](/api/mikro.md#DATA_SOURCE_KEY) * [**ENTITY\_MANAGER\_KEY](/api/mikro.md#ENTITY_MANAGER_KEY) * [**ENTITY\_MODEL\_KEY](/api/mikro.md#ENTITY_MODEL_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#MikroConfigOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/interface.ts#L4)MikroConfigOptions **MikroConfigOptions\: DataSourceManagerConfigOption<(Options\ | Configuration\) & { logger? : string | (message: string) => void }> #### Type parameters * **D**: IDatabaseDriver = IDatabaseDriver ## Variables[**](#Variables) ### [**](#DATA_SOURCE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/decorator.ts#L6)constDATA\_SOURCE\_KEY **DATA\_SOURCE\_KEY: mikro:data\_source\_key = 'mikro:data\_source\_key' ### [**](#ENTITY_MANAGER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/decorator.ts#L5)constENTITY\_MANAGER\_KEY **ENTITY\_MANAGER\_KEY: mikro:entity\_manager\_key = 'mikro:entity\_manager\_key' ### [**](#ENTITY_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/decorator.ts#L4)constENTITY\_MODEL\_KEY **ENTITY\_MODEL\_KEY: mikro:entity\_model\_key = 'mikro:entity\_model\_key' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationManager](#applicationManager) * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MikroConfiguration](/api/mikro/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L32)app **app: IMidwayBaseApplication\ ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L38)applicationManager **applicationManager: MidwayApplicationManager ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L40)dataSourceManager **dataSourceManager: [MikroDataSourceManager](/api/mikro/class/MikroDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L35)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L43)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L99)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/configuration.ts#L122)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # MikroDataSourceManager ### Hierarchy * DataSourceManager\>> * *MikroDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**loggerService](#loggerService) * [**mikroConfig](#mikroConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MikroDataSourceManager(): [MikroDataSourceManager](/api/mikro/class/MikroDataSourceManager.md) - Inherited from DataSourceManager< MikroORM\> >.constructor ## Properties[**](#Properties) ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/dataSourceManager.ts#L22)loggerService **loggerService: MidwayLoggerService ### [**](#mikroConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/dataSourceManager.ts#L19)mikroConfig **mikroConfig: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L36)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L37)createInstance * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>): Promise\, EntityManager\>>> * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\, EntityManager\>>> - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L30)getAllDataSources * **getAllDataSources(): Map\, EntityManager\>>> - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L23)getDataSource * **getDataSource(dataSourceName: string): MikroORM\, EntityManager\>> - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L29)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L61)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L60)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/dataSourceManager.ts#L31)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mikro/src/dataSourceManager.ts#L25)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L35)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L62)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L64)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L63)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L59)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L65)staticformatGlobString * **formatGlobString(globString: string): string\[] - Inherited from DataSourceManager.formatGlobString ### [**](#globModels)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L66)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : ModuleLoadType): Promise\ - Inherited from DataSourceManager.globModels --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectEntityManager ### Callable * **InjectEntityManager(connectionName? : string): PropertyDecorator --- # InjectRepository ### Callable * **InjectRepository(modelKey: EntityName\, connectionName? : string): PropertyDecorator --- # @midwayjs/mock ## Index[**](#Index) ### Classes * [**SSEClient](/api/mock/class/SSEClient.md) * [**SocketIOWrapperClient](/api/mock/class/SocketIOWrapperClient.md) ### Functions * [**close](/api/mock/function/close.md) * [**create](/api/mock/function/create.md) * [**createApp](/api/mock/function/createApp.md) * [**createBootstrap](/api/mock/function/createBootstrap.md) * [**createFunctionApp](/api/mock/function/createFunctionApp.md) * [**createHttpRequest](/api/mock/function/createHttpRequest.md) * [**createKafkaProducer](/api/mock/function/createKafkaProducer.md) * [**createLegacyApp](/api/mock/function/createLegacyApp.md) * [**createLegacyFunctionApp](/api/mock/function/createLegacyFunctionApp.md) * [**createLegacyLightApp](/api/mock/function/createLegacyLightApp.md) * [**createLightApp](/api/mock/function/createLightApp.md) * [**createRabbitMQProducer](/api/mock/function/createRabbitMQProducer.md) * [**createSSEClient](/api/mock/function/createSSEClient.md) * [**createSocketIOClient](/api/mock/function/createSocketIOClient.md) * [**createWebSocketClient](/api/mock/function/createWebSocketClient.md) * [**mockClassProperty](/api/mock/function/mockClassProperty.md) * [**mockContext](/api/mock/function/mockContext.md) * [**mockHeader](/api/mock/function/mockHeader.md) * [**mockProperty](/api/mock/function/mockProperty.md) * [**mockSession](/api/mock/function/mockSession.md) * [**processArgsParser](/api/mock/function/processArgsParser.md) * [**restoreAllMocks](/api/mock/function/restoreAllMocks.md) * [**restoreMocks](/api/mock/function/restoreMocks.md) * [**transformFrameworkToConfiguration](/api/mock/function/transformFrameworkToConfiguration.md) ### Interfaces * [**MidwaySocketIOClientOptions](/api/mock/interface/MidwaySocketIOClientOptions.md) * [**SSEClientOptions](/api/mock/interface/SSEClientOptions.md) --- # SocketIOWrapperClient ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**connect](#connect) * [**emit](#emit) * [**getSocket](#getSocket) * [**on](#on) * [**once](#once) * [**removeListener](#removeListener) * [**send](#send) * [**sendWithAck](#sendWithAck) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L15)constructor * **new SocketIOWrapperClient(socket: any): [SocketIOWrapperClient](/api/mock/class/SocketIOWrapperClient.md) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L56)close * **close(): void ### [**](#connect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L18)connect * **connect(): Promise\ ### [**](#emit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L46)emit * **emit(eventName: string, ...args: any\[]): any ### [**](#getSocket)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L26)getSocket * **getSocket(): any ### [**](#on)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L34)on * **on(eventName: string, handler: any): void ### [**](#once)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L38)once * **once(eventName: string, handler: any): any ### [**](#removeListener)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L42)removeListener * **removeListener(event: string, fn? : any): any ### [**](#send)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L30)send * **send(eventName: string, ...args: any\[]): void ### [**](#sendWithAck)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L50)sendWithAck * **sendWithAck(eventName: string, ...args: any\[]): Promise\ --- # SSEClient ### Hierarchy * EventEmitter * *SSEClient* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**close](#close) * [**connect](#connect) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L18)constructor * **new SSEClient(url: string, options? : [SSEClientOptions](/api/mock/interface/SSEClientOptions.md)): [SSEClient](/api/mock/class/SSEClient.md) - Overrides EventEmitter.constructor ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L155)close * **close(): void ### [**](#connect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L31)connect * **connect(): Promise\ --- # close ### Callable * **close(app: IMidwayBaseApplication\ | { close: (...args: any\[]) => void }, options? : { cleanLogsDir? : boolean; cleanTempDir? : boolean; sleep? : number }): Promise\ --- # create ### Callable * **create\(appDir: string | MockBootstrapOptions, options? : MockBootstrapOptions): Promise\ *** * #### Type parameters * **T**: IMidwayFramework\ --- # createApp ### Callable * **createApp\(baseDir: string | MockBootstrapOptions, options? : MockBootstrapOptions): Promise\> *** * #### Type parameters * **T**: IMidwayFramework\ --- # createBootstrap ### Callable * **createBootstrap(entryFile: string, options? : MockBootstrapOptions): Promise\ --- # createFunctionApp ### Callable * **createFunctionApp\(baseDir? : string | MockBootstrapOptions, options? : MockBootstrapOptions, customFrameworkModule? : new (...args: any\[]) => T | ComponentModule): Promise\ *** * #### Type parameters * **T**: IMidwayFramework\ * **Y** = ReturnType\ --- # createHttpRequest ### Callable * **createHttpRequest\(app: T): request.SuperTest\ *** * #### Type parameters * **T**: IMidwayBaseApplication\ --- # createKafkaProducer ### Callable * **createKafkaProducer(options: { kafkaConfig: KafkaConfig; mock? : boolean; producerConfig? : ProducerConfig }): Promise\ --- # createLegacyApp ### Callable * **createLegacyApp\(...args: \[baseDir: string | MockBootstrapOptions, options?: MockBootstrapOptions]): Promise\> *** * #### Type parameters * **T**: IMidwayFramework\ --- # createLegacyFunctionApp ### Callable * **createLegacyFunctionApp\(...args: \[baseDir?: string | MockBootstrapOptions, options: MockBootstrapOptions, customFrameworkModule?: ComponentModule | new (...args: any\[]) => IMidwayFramework\]): Promise\> *** * #### Type parameters * **T**: IMidwayFramework\ --- # createLegacyLightApp ### Callable * **createLegacyLightApp(...args: any\[]): Promise\> --- # createLightApp ### Callable * **createLightApp(baseDirOrOptions: string | MockBootstrapOptions, options? : MockBootstrapOptions): Promise\ *** * Create a real project but not ready or a virtual project --- # createRabbitMQProducer ### Callable * **createRabbitMQProducer(options: { url? : string }): Promise\ * **createRabbitMQProducer(queueName: string, options: { isConfirmChannel? : boolean; mock? : boolean; url? : string }): Promise\ --- # createSocketIOClient ### Callable * **createSocketIOClient(opts: [MidwaySocketIOClientOptions](/api/mock/interface/MidwaySocketIOClientOptions.md)): Promise<[SocketIOWrapperClient](/api/mock/class/SocketIOWrapperClient.md) & NodeJS.EventEmitter> --- # createSSEClient ### Callable * **createSSEClient(url: string, options? : [SSEClientOptions](/api/mock/interface/SSEClientOptions.md)): [SSEClient](/api/mock/class/SSEClient.md) --- # createWebSocketClient ### Callable * **createWebSocketClient(address: string | URL, options? : any): Promise\ --- # mockClassProperty ### Callable * **mockClassProperty(clzz: new (...args: any\[]) => any, propertyName: string, value: any, group? : string): void --- # mockContext ### Callable * **mockContext(app: IMidwayBaseApplication\, key: string | (ctx: Context) => void, value? : any, group? : string): void --- # mockHeader ### Callable * **mockHeader(app: IMidwayBaseApplication\, headerKey: string, headerValue: string, group? : string): void --- # mockProperty ### Callable * **mockProperty(obj: any, key: string, value: any, group? : string): void --- # mockSession ### Callable * **mockSession(app: IMidwayBaseApplication\, key: string, value: any, group? : string): void --- # processArgsParser ### Callable * **processArgsParser(argv: string\[]): {} *** * 解析命令行参数的函数。 它接受一个字符串数组作为输入,然后解析这个数组, 将形如 `--key value` 或 `--key=value` 的参数转换为对象的键值对, 形如 `--key` 的参数转换为 `{ key: true }`。 --- # restoreAllMocks ### Callable * **restoreAllMocks(): void --- # restoreMocks ### Callable * **restoreMocks(group? : string): void --- # transformFrameworkToConfiguration ### Callable * **transformFrameworkToConfiguration\(Framework: any, loadMode: commonjs | esm): Promise<{ Configuration: any }> *** * transform a framework component or framework module to configuration class *** #### Type parameters * **T**: IMidwayFramework\ --- # MidwaySocketIOClientOptions ### Hierarchy * Partial\ * *MidwaySocketIOClientOptions* ## Index[**](#Index) ### Properties * [**host](#host) * [**namespace](#namespace) * [**port](#port) * [**protocol](#protocol) * [**url](#url) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L8)optionalhost **host? : string Overrides Partial.host ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L9)optionalnamespace **namespace? : string ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L10)optionalport **port? : any Overrides Partial.port ### [**](#protocol)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L7)optionalprotocol **protocol? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/socketio.ts#L6)optionalurl **url? : string --- # SSEClientOptions ## Index[**](#Index) ### Properties * [**headers](#headers) * [**maxReconnectAttempts](#maxReconnectAttempts) * [**reconnectInterval](#reconnectInterval) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L6)optionalheaders **headers? : Record\ ### [**](#maxReconnectAttempts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L9)optionalmaxReconnectAttempts **maxReconnectAttempts? : number ### [**](#reconnectInterval)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L8)optionalreconnectInterval **reconnectInterval? : number ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mock/src/client/sse.ts#L7)optionaltimeout **timeout? : number --- # @midwayjs/mongoose ## Index[**](#Index) ### Classes * [**Configuration](/api/mongoose/class/Configuration.md) * [**MongooseConnectionService](/api/mongoose/class/MongooseConnectionService.md) * [**MongooseConnectionServiceFactory](/api/mongoose/class/MongooseConnectionServiceFactory.md) * [**MongooseDataSourceManager](/api/mongoose/class/MongooseDataSourceManager.md) ### Type Aliases * [**ConnectionOptions](/api/mongoose.md#ConnectionOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#ConnectionOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/interface.ts#L27)ConnectionOptions **ConnectionOptions: ExtractConnectionOptions\ --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**mongooseDataSourceManager](#mongooseDataSourceManager) ### Methods * [**onHealthCheck](#onHealthCheck) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MongooseConfiguration](/api/mongoose/class/Configuration.md) ## Properties[**](#Properties) ### [**](#mongooseDataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/configuration.ts#L36)mongooseDataSourceManager **mongooseDataSourceManager: [MongooseDataSourceManager](/api/mongoose/class/MongooseDataSourceManager.md) ## Methods[**](#Methods) ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/configuration.ts#L47)optionalonHealthCheck * **onHealthCheck(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onHealthCheck ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/configuration.ts#L37)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/configuration.ts#L43)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # MongooseConnectionService * **@deprecated** ### Hierarchy * Connection * *MongooseConnectionService* ### Implements * Connection ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseConnectionService(): [MongooseConnectionService](/api/mongoose/class/MongooseConnectionService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L132)init * **init(): Promise\ --- # MongooseConnectionServiceFactory * **@deprecated** ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**mongooseDataSourceManager](#mongooseDataSourceManager) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getName](#getName) * [**has](#has) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseConnectionServiceFactory(): [MongooseConnectionServiceFactory](/api/mongoose/class/MongooseConnectionServiceFactory.md) ## Properties[**](#Properties) ### [**](#mongooseDataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L98)mongooseDataSourceManager **mongooseDataSourceManager: [MongooseDataSourceManager](/api/mongoose/class/MongooseDataSourceManager.md) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L100)createInstance * **createInstance(config: any, clientName: any): Promise\ ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L107)get * **get(id: string): Connection ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L111)getName * **getName(): string ### [**](#has)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L115)has * **has(id: string): boolean --- # MongooseDataSourceManager ### Hierarchy * DataSourceManager\ * *MongooseDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**config](#config) * [**logger](#logger) ### Methods * [**createInstance](#createInstance) * [**destroyDataSource](#destroyDataSource) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MongooseDataSourceManager(): [MongooseDataSourceManager](/api/mongoose/class/MongooseDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#config)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L20)config **config: any ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L23)logger **logger: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L36)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L37)createInstance * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>): Promise\ * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#destroyDataSource)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L80)destroyDataSource * **destroyDataSource(dataSource: Connection): Promise\ - Overrides DataSourceManager.destroyDataSource ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L30)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L23)getDataSource * **getDataSource(dataSourceName: string): Connection - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L29)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L61)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L60)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L76)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mongoose/src/manager.ts#L26)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L35)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L62)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L64)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L63)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L59)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L65)staticformatGlobString * **formatGlobString(globString: string): string\[] - Inherited from DataSourceManager.formatGlobString ### [**](#globModels)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L66)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : ModuleLoadType): Promise\ - Inherited from DataSourceManager.globModels --- # @midwayjs/mqtt ## Index[**](#Index) ### Classes * [**Configuration](/api/mqtt/class/Configuration.md) * [**DefaultMqttProducer](/api/mqtt/class/DefaultMqttProducer.md) * [**Framework](/api/mqtt/class/Framework.md) * [**MqttProducerFactory](/api/mqtt/class/MqttProducerFactory.md) ### Functions * [**MqttSubscriber](/api/mqtt/function/MqttSubscriber.md) ### Interfaces * [**Context](/api/mqtt/interface/Context.md) * [**IMidwayMQTTConfigurationOptions](/api/mqtt/interface/IMidwayMQTTConfigurationOptions.md) * [**IMqttSubscriber](/api/mqtt/interface/IMqttSubscriber.md) * [**MqttSubscriberOptions](/api/mqtt/interface/MqttSubscriberOptions.md) ### Type Aliases * [**Application](/api/mqtt.md#Application) * [**IMidwayMQTTApplication](/api/mqtt.md#IMidwayMQTTApplication) * [**IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext) * [**NextFunction](/api/mqtt.md#NextFunction) ### Variables * [**MQTT\_DECORATOR\_KEY](/api/mqtt.md#MQTT_DECORATOR_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L39)Application **Application: [IMidwayMQTTApplication](/api/mqtt.md#IMidwayMQTTApplication) ### [**](#IMidwayMQTTApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L21)IMidwayMQTTApplication **IMidwayMQTTApplication: IMidwayApplication<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext)> ### [**](#IMidwayMQTTContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L33)IMidwayMQTTContext **IMidwayMQTTContext: IMidwayContext<{ message: Buffer; packet: IPublishPacket; topic: string }> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L41)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#MQTT_DECORATOR_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/decorator.ts#L8)constMQTT\_DECORATOR\_KEY **MQTT\_DECORATOR\_KEY: rpc:mqtt = 'rpc:mqtt' --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**factory](#factory) * [**framework](#framework) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [MQTTConfiguration](/api/mqtt/class/Configuration.md) ## Properties[**](#Properties) ### [**](#factory)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/configuration.ts#L28)factory **factory: [MqttProducerFactory](/api/mqtt/class/MqttProducerFactory.md) ### [**](#framework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/configuration.ts#L27)framework **framework: [MidwayMQTTFramework](/api/mqtt/class/Framework.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/configuration.ts#L29)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/configuration.ts#L33)onStop * **onStop(): Promise\ --- # DefaultMqttProducer ### Hierarchy * default * *DefaultMqttProducer* ### Implements * default ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DefaultMqttProducer(): [DefaultMqttProducer](/api/mqtt/class/DefaultMqttProducer.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L125)init * **init(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayMQTTApplication](/api/mqtt.md#IMidwayMQTTApplication), [IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), [IMidwayMQTTConfigurationOptions](/api/mqtt/interface/IMidwayMQTTConfigurationOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**createSubscriber](#createSubscriber) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getSubscriber](#getSubscriber) * [**getSubscribers](#getSubscribers) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayMQTTFramework](/api/mqtt/class/Framework.md) - Inherited from BaseFramework< IMidwayMQTTApplication, IMidwayMQTTContext, IMidwayMQTTConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: IMidwayBaseApplication<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext)> Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayMQTTConfigurationOptions](/api/mqtt/interface/IMidwayMQTTConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L31)applicationInitialize * **applicationInitialize(options: any): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L27)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#createSubscriber)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L75)publiccreateSubscriber * **createSubscriber(connectionOptions: IClientOptions, subscribeOptions: [MqttSubscriberOptions](/api/mqtt/interface/MqttSubscriberOptions.md), ClzProvider: new () => [IMqttSubscriber](/api/mqtt/interface/IMqttSubscriber.md), clientName? : string): Promise\ - dynamic create subscriber ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): IMidwayBaseApplication<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext)> - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L173)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getSubscriber)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L165)publicgetSubscriber * **getSubscriber(name: string): default ### [**](#getSubscribers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L169)publicgetSubscribers * **getSubscribers(): default\[] ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/framework.ts#L35)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # MqttProducerFactory ### Hierarchy * ServiceFactory\ * *MqttProducerFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**pubConfig](#pubConfig) * [**traceEnabled](#traceEnabled) * [**traceInjector](#traceInjector) * [**traceService](#traceService) ### Methods * [**createInstance](#createInstance) * [**destroyClient](#destroyClient) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new MqttProducerFactory(): [MqttProducerFactory](/api/mqtt/class/MqttProducerFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L22)logger **logger: ILogger ### [**](#pubConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L25)pubConfig **pubConfig: ServiceFactoryConfigOption\ ### [**](#traceEnabled)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L31)traceEnabled **traceEnabled: boolean ### [**](#traceInjector)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L34)traceInjector **traceInjector: (args: { custom? : Record\; request? : unknown }) => any ### [**](#traceService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L28)traceService **traceService: MidwayTraceService ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#destroyClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L110)destroyClient * **destroyClient(producer: default, name: string): Promise\ - Overrides ServiceFactory.destroyClient ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = default ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L39)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/service.ts#L44)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # MqttSubscriber ### Callable * **MqttSubscriber(subscriberName: string): ClassDecorator --- # Context ### Hierarchy * [IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext) * *Context* ## Index[**](#Index) ### Properties * [**logger](#logger) * [**message](#message) * [**packet](#packet) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**topic](#topic) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayMQTTContext.logger ### [**](#message)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L35)message **message: Buffer Inherited from IMidwayMQTTContext.message ### [**](#packet)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L36)packet **packet: IPublishPacket Inherited from IMidwayMQTTContext.packet ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayMQTTContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayMQTTContext.startTime ### [**](#topic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L34)topic **topic: string Inherited from IMidwayMQTTContext.topic ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayMQTTContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayMQTTContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayMQTTContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayMQTTContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayMQTTContext.setAttr Set value to app attribute map --- # IMidwayMQTTConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayMQTTConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**logger](#logger) * [**pub](#pub) * [**sub](#sub) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#pub)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L30)pub **pub: ServiceFactoryConfigOption\ ### [**](#sub)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L24)sub **sub: {} --- # IMqttSubscriber ## Index[**](#Index) ### Methods * [**subscribe](#subscribe) ## Methods[**](#Methods) ### [**](#subscribe)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L44)subscribe * **subscribe(ctx: [IMidwayMQTTContext](/api/mqtt.md#IMidwayMQTTContext)): Promise\ --- # MqttSubscriberOptions ## Index[**](#Index) ### Properties * [**opts](#opts) * [**topicObject](#topicObject) ## Properties[**](#Properties) ### [**](#opts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L18)optionalopts **opts? : IClientSubscribeOptions | IClientSubscribeProperties ### [**](#topicObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/mqtt/src/interface.ts#L17)topicObject **topicObject: string | string\[] | ISubscriptionMap --- # @midwayjs/nextjs ## Index[**](#Index) ### Classes * [**Configuration](/api/nextjs/class/Configuration.md) * [**NextJSMiddleware](/api/nextjs/class/NextJSMiddleware.md) ### Functions * [**createClient](/api/nextjs/function/createClient.md) * [**createNextjsApiClient](/api/nextjs/function/createNextjsApiClient.md) * [**createNextjsApiClientFromOperations](/api/nextjs/function/createNextjsApiClientFromOperations.md) * [**resolveNextjsApiBridgeOptions](/api/nextjs/function/resolveNextjsApiBridgeOptions.md) ### Type Aliases * [**NextjsApiBridgeOptions](/api/nextjs.md#NextjsApiBridgeOptions) * [**NextjsCreateClientOptions](/api/nextjs.md#NextjsCreateClientOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#NextjsApiBridgeOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/bridge.ts#L14)NextjsApiBridgeOptions **NextjsApiBridgeOptions: ApiBridgeOptions ### [**](#NextjsCreateClientOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/bridge.ts#L40)NextjsCreateClientOptions **NextjsCreateClientOptions: CreateClientOptions --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [NextJSConfiguration](/api/nextjs/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/configuration.ts#L13)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/configuration.ts#L15)onReady * **onReady(): Promise\ --- # NextJSMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**appDir](#appDir) * [**env](#env) ### Methods * [**init](#init) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NextJSMiddleware(): [NextJSMiddleware](/api/nextjs/class/NextJSMiddleware.md) ## Properties[**](#Properties) ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/middleware.ts#L31)appDir **appDir: string ### [**](#env)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/middleware.ts#L21)env **env: MidwayEnvironmentService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/middleware.ts#L34)init * **init(): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/middleware.ts#L43)resolve * **resolve(app: IMidwayBaseApplication\): (ctx: Context, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/nextjs/src/middleware.ts#L73)staticgetName * **getName(): string --- # createClient ### Callable * **createClient\(modules: TModules, options? : CreateClientOptions): ClientFromApiModules\ *** * #### Type parameters * **TModules**: ApiModulesMap --- # createNextjsApiClient ### Callable * **createNextjsApiClient\(definition: ApiClientDefinition, options? : ApiBridgeOptions): ApiClient\ *** * #### Type parameters * **TInput** = unknown * **TOutput** = unknown --- # createNextjsApiClientFromOperations ### Callable * **createNextjsApiClientFromOperations\(operations: ApiBridgeOperation\[], options? : ApiBridgeOptions): ApiClient\ *** * #### Type parameters * **TInput** = unknown * **TOutput** = unknown --- # resolveNextjsApiBridgeOptions ### Callable * **resolveNextjsApiBridgeOptions(options? : ApiBridgeOptions): Required\> & Pick<[NextjsApiBridgeOptions](/api/nextjs.md#NextjsApiBridgeOptions), adapter> --- # @midwayjs/oss ## Index[**](#Index) ### Classes * [**Configuration](/api/oss/class/Configuration.md) * [**OSSSTSService](/api/oss/class/OSSSTSService.md) * [**OSSService](/api/oss/class/OSSService.md) * [**OSSServiceFactory](/api/oss/class/OSSServiceFactory.md) ### Interfaces * [**MWOSSClusterOptions](/api/oss/interface/MWOSSClusterOptions.md) * [**MWOSSOptions](/api/oss/interface/MWOSSOptions.md) * [**MWOSSSTSOptions](/api/oss/interface/MWOSSSTSOptions.md) ### Type Aliases * [**OSSServiceFactoryCreateClientConfigType](/api/oss.md#OSSServiceFactoryCreateClientConfigType) * [**OSSServiceFactoryReturnType](/api/oss.md#OSSServiceFactoryReturnType) * [**Without](/api/oss.md#Without) * [**XOR](/api/oss.md#XOR) ## Type Aliases[**](<#Type Aliases>) ### [**](#OSSServiceFactoryCreateClientConfigType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L24)OSSServiceFactoryCreateClientConfigType **OSSServiceFactoryCreateClientConfigType: [XOR](/api/oss.md#XOR)<[XOR](/api/oss.md#XOR)<[MWOSSOptions](/api/oss/interface/MWOSSOptions.md), [MWOSSClusterOptions](/api/oss/interface/MWOSSClusterOptions.md)>, [MWOSSSTSOptions](/api/oss/interface/MWOSSSTSOptions.md)> ### [**](#OSSServiceFactoryReturnType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L19)OSSServiceFactoryReturnType **OSSServiceFactoryReturnType: [XOR](/api/oss.md#XOR)<[XOR](/api/oss.md#XOR)\, OSS.ClusterClient> ### [**](#Without)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L5)Without **Without\: { \[ P in Exclude\ T, keyof U> ]?: never } #### Type parameters * **T** * **U** ### [**](#XOR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L6)XOR **XOR\: ([Without](/api/oss.md#Without)\ & U) | ([Without](/api/oss.md#Without)\ & T) #### Type parameters * **T** * **U** --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [OSSConfiguration](/api/oss/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/configuration.ts#L19)onReady * **onReady(container: any): Promise\ --- # OSSService ### Hierarchy * OSS * *OSSService* ### Implements * OSS ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new OSSService(): [OSSService](/api/oss/class/OSSService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L148)init * **init(): Promise\ --- # OSSServiceFactory \ ### Hierarchy * ServiceFactory\ * *OSSServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ossConfig](#ossConfig) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new OSSServiceFactory\(): [OSSServiceFactory](/api/oss/class/OSSServiceFactory.md)\ - Inherited from ServiceFactory\.constructor #### Type parameters * **T**: [OSSServiceFactoryReturnType](/api/oss.md#OSSServiceFactoryReturnType) = [OSSServiceFactoryReturnType](/api/oss.md#OSSServiceFactoryReturnType) ## Properties[**](#Properties) ### [**](#ossConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L38)ossConfig **ossConfig: [OSSServiceFactoryCreateClientConfigType](/api/oss.md#OSSServiceFactoryCreateClientConfigType) ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L59)createClient * **createClient(config: [OSSServiceFactoryCreateClientConfigType](/api/oss.md#OSSServiceFactoryCreateClientConfigType)): Promise\ - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = T ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L134)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L53)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # OSSSTSService ### Implements * STS ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**assumeRole](#assumeRole) * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new OSSSTSService(): [OSSSTSService](/api/oss/class/OSSSTSService.md) ## Methods[**](#Methods) ### [**](#assumeRole)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L182)assumeRole * **assumeRole(roleArn: string, policy? : string | Record\, expirationSeconds? : number, session? : string, options? : { ctx: any; timeout: number }): Promise<{ credentials: Credentials }> - Implementation of OSS.STS.assumeRole ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/manager.ts#L173)init * **init(): Promise\ --- # MWOSSClusterOptions ### Hierarchy * ClusterOptions * *MWOSSClusterOptions* ## Index[**](#Index) ### Properties * [**clusters](#clusters) * [**timeout](#timeout) ## Properties[**](#Properties) ### [**](#clusters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L11)clusters **clusters: (ClusterType & { endpoint: string })\[] Overrides OSS.ClusterOptions.clusters ### [**](#timeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L12)optionaltimeout **timeout? : string --- # MWOSSOptions ### Hierarchy * Options * *MWOSSOptions* --- # MWOSSSTSOptions ### Hierarchy * STSOptions * *MWOSSSTSOptions* ## Index[**](#Index) ### Properties * [**sts](#sts) ## Properties[**](#Properties) ### [**](#sts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/oss/src/interface.ts#L16)sts **sts: boolean --- # @midwayjs/passport ## Index[**](#Index) ### Classes * [**AbstractPassportMiddleware](/api/passport/class/AbstractPassportMiddleware.md) * [**Configuration](/api/passport/class/Configuration.md) * [**PassportAuthenticator](/api/passport/class/PassportAuthenticator.md) ### Functions * [**CustomStrategy](/api/passport/function/CustomStrategy.md) * [**PassportMiddleware](/api/passport/function/PassportMiddleware.md) * [**PassportStrategy](/api/passport/function/PassportStrategy.md) ### Interfaces * [**AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md) * [**IPassportMiddleware](/api/passport/interface/IPassportMiddleware.md) * [**IPassportStrategy](/api/passport/interface/IPassportStrategy.md) * [**StrategyCreatedStatic](/api/passport/interface/StrategyCreatedStatic.md) ### Type Aliases * [**StrategyClass](/api/passport.md#StrategyClass) ## Type Aliases[**](<#Type Aliases>) ### [**](#StrategyClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/passport.service.ts#L73)StrategyClass **StrategyClass: new (...args: any) => AbstractStrategyWrapper --- # abstractAbstractPassportMiddleware ### Implements * Pick<[IPassportMiddleware](/api/passport/interface/IPassportMiddleware.md), authenticate> ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**authenticate](#authenticate) * [**getAuthenticateOptions](#getAuthenticateOptions) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AbstractPassportMiddleware(): [AbstractPassportMiddleware](/api/passport/class/AbstractPassportMiddleware.md) ## Methods[**](#Methods) ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L45)optionalauthenticate * **authenticate(options: [AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md), callback? : (...args: any\[]) => any): any - Implementation of Pick.authenticate ### [**](#getAuthenticateOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L42)abstractgetAuthenticateOptions * **getAuthenticateOptions(): [AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md) | Promise<[AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md)> ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L49)resolve * **resolve(): any --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PassportConfiguration](/api/passport/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/configuration.ts#L24)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/configuration.ts#L26)onReady * **onReady(container: IMidwayContainer): Promise\ --- # PassportAuthenticator ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**\_deserializers](#_deserializers) * [**\_infoTransformers](#_infoTransformers) * [**\_key](#_key) * [**\_serializers](#_serializers) * [**applicationContext](#applicationContext) * [**passportConfig](#passportConfig) ### Methods * [**addDeserializer](#addDeserializer) * [**addInfoTransformer](#addInfoTransformer) * [**addSerializer](#addSerializer) * [**authenticate](#authenticate) * [**deserializeUser](#deserializeUser) * [**getSessionUserProperty](#getSessionUserProperty) * [**getUserProperty](#getUserProperty) * [**isEnableSession](#isEnableSession) * [**isExpressMode](#isExpressMode) * [**logInToSession](#logInToSession) * [**logOutFromSession](#logOutFromSession) * [**serializeUser](#serializeUser) * [**transformAuthInfo](#transformAuthInfo) * [**unuse](#unuse) * [**use](#use) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new PassportAuthenticator(): [PassportAuthenticator](/api/passport/class/PassportAuthenticator.md) ## Properties[**](#Properties) ### [**](#_deserializers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L24)\_deserializers **\_deserializers: any\[] = \[] ### [**](#_infoTransformers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L25)\_infoTransformers **\_infoTransformers: any\[] = \[] ### [**](#_key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L22)\_key **\_key: string = 'passport' ### [**](#_serializers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L23)\_serializers **\_serializers: any\[] = \[] ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L28)applicationContext **applicationContext: IMidwayContainer ### [**](#passportConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L31)passportConfig **passportConfig: any ## Methods[**](#Methods) ### [**](#addDeserializer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L479)publicaddDeserializer * **addDeserializer(fn: any): void ### [**](#addInfoTransformer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L483)publicaddInfoTransformer * **addInfoTransformer(fn: any): void ### [**](#addSerializer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L475)publicaddSerializer * **addSerializer(fn: any): void ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L110)publicauthenticate * **authenticate(strategies: Strategy\[], options? : [AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md)): (req: any) => Promise<{ failResult? : { failures: { challenge: string; status: number }\[] }; redirectResult? : { status: number; url: string }; successResult? : { info: any; user: any } }> - Authenticates requests. Applies the `name`ed strategy (or strategies) to the incoming request, in order to authenticate the request. If authentication is successful, the user will be logged in and populated at `req.user` and a session will be established by default. If authentication fails, an unauthorized response will be sent. Options: * `session` Save login state in session, defaults to *true* * `successRedirect` After successful login, redirect to given URL * `successMessage` True to store success message in req.session.messages, or a string to use as override message for success. * `successFlash` True to flash success messages or a string to use as a flash message for success (overrides any from the strategy itself). * `failureRedirect` After failed login, redirect to given URL * `failureMessage` True to store failure message in req.session.messages, or a string to use as override message for failure. * `failureFlash` True to flash failure messages or a string to use as a flash message for failures (overrides any from the strategy itself). * `assignProperty` Assign the object provided by the verify callback to given property ### [**](#deserializeUser)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L293)publicdeserializeUser * **deserializeUser(obj: any, req: any, done: any): void - Registers a function used to deserialize user objects out of the session. Examples: ``` passport.deserializeUser(function(id, done) { User.findById(id, function (err, user) { done(err, user); }); }); ``` * **@api** public ### [**](#getSessionUserProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L63)publicgetSessionUserProperty * **getSessionUserProperty(): string ### [**](#getUserProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L59)publicgetUserProperty * **getUserProperty(): string ### [**](#isEnableSession)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L55)publicisEnableSession * **isEnableSession(): boolean ### [**](#isExpressMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L51)publicisExpressMode * **isExpressMode(): boolean ### [**](#logInToSession)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L410)publiclogInToSession * **logInToSession(req: IncomingMessage & { session: any }, user: any): Promise\ ### [**](#logOutFromSession)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L436)publiclogOutFromSession * **logOutFromSession(req: any, options? : { keepSessionInfo? : boolean }): Promise\ ### [**](#serializeUser)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L246)publicserializeUser * **serializeUser(user: any, req: any, done: any): void ### [**](#transformAuthInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L370)publictransformAuthInfo * **transformAuthInfo(info: any, req: any, done: any): void - Registers a function used to transform auth info. In some circumstances authorization details are contained in authentication credentials or loaded as part of verification. For example, when using bearer tokens for API authentication, the tokens may encode (either directly or indirectly in a database), details such as scope of access or the client to which the token was issued. Such authorization details should be enforced separately from authentication. Because Passport deals only with the latter, this is the responsiblity of middleware or routes further along the chain. However, it is not optimal to decode the same data or execute the same database query later. To avoid this, Passport accepts optional `info` along with the authenticated `user` in a strategy's `success()` action. This info is set at `req.authInfo`, where said later middlware or routes can access it. Optionally, applications can register transforms to proccess this info, which take effect prior to `req.authInfo` being set. This is useful, for example, when the info contains a client ID. The transform can load the client from the database and include the instance in the transformed info, allowing the full set of client properties to be convieniently accessed. If no transforms are registered, `info` supplied by the strategy will be left unmodified. Examples: ``` passport.transformAuthInfo(function(info, done) { Client.findById(info.clientID, function (err, client) { info.client = client; done(err, info); }); }); ``` * **@api** public ### [**](#unuse)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L80)publicunuse * **unuse(name: string): [PassportAuthenticator](/api/passport/class/PassportAuthenticator.md) ### [**](#use)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/passport/authenticator.ts#L67)publicuse * **use(name: string | Strategy, strategy? : Strategy): [PassportAuthenticator](/api/passport/class/PassportAuthenticator.md) --- # CustomStrategy ### Callable * **CustomStrategy(): ClassDecorator --- # PassportMiddleware ### Callable * **PassportMiddleware(strategy: [StrategyClass](/api/passport.md#StrategyClass) | [StrategyClass](/api/passport.md#StrategyClass)\[]): new (...args: any) => [AbstractPassportMiddleware](/api/passport/class/AbstractPassportMiddleware.md) --- # PassportStrategy ### Callable * **PassportStrategy(Strategy: new (...args: any\[]) => Strategy, name? : string): new (...args: any) => AbstractStrategyWrapper --- # AuthenticateOptions ## Index[**](#Index) ### Properties * [**assignProperty](#assignProperty) * [**authInfo](#authInfo) * [**failureMessage](#failureMessage) * [**failureRedirect](#failureRedirect) * [**passReqToCallback](#passReqToCallback) * [**pauseStream](#pauseStream) * [**prompt](#prompt) * [**scope](#scope) * [**session](#session) * [**state](#state) * [**successMessage](#successMessage) * [**successRedirect](#successRedirect) * [**successReturnToOrRedirect](#successReturnToOrRedirect) * [**userProperty](#userProperty) ## Properties[**](#Properties) ### [**](#assignProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L5)optionalassignProperty **assignProperty? : string ### [**](#authInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L4)optionalauthInfo **authInfo? : boolean ### [**](#failureMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L7)optionalfailureMessage **failureMessage? : string | boolean ### [**](#failureRedirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L8)optionalfailureRedirect **failureRedirect? : string ### [**](#passReqToCallback)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L19)optionalpassReqToCallback **passReqToCallback? : boolean ### [**](#pauseStream)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L17)optionalpauseStream **pauseStream? : boolean ### [**](#prompt)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L20)optionalprompt **prompt? : string ### [**](#scope)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L11)optionalscope **scope? : string | string\[] ### [**](#session)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L10)optionalsession **session? : boolean ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L16)optionalstate **state? : string ### [**](#successMessage)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L13)optionalsuccessMessage **successMessage? : string | boolean ### [**](#successRedirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L14)optionalsuccessRedirect **successRedirect? : string ### [**](#successReturnToOrRedirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L15)optionalsuccessReturnToOrRedirect **successReturnToOrRedirect? : string ### [**](#userProperty)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L18)optionaluserProperty **userProperty? : string --- # IPassportMiddleware ### Hierarchy * IMiddleware\ * *IPassportMiddleware* ## Index[**](#Index) ### Properties * [**ignore](#ignore) * [**match](#match) * [**resolve](#resolve) ### Methods * [**authenticate](#authenticate) ## Properties[**](#Properties) ### [**](#ignore)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L726)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from IMiddleware.ignore Match those paths with higher priority than ignore ### [**](#match)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L722)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from IMiddleware.match Which paths to ignore ### [**](#resolve)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L718)resolve **resolve: (app: IMidwayBaseApplication\, options? : any) => (context: any, next: any, options? : any) => any | Promise<(context: any, next: any, options? : any) => any> Inherited from IMiddleware.resolve ## Methods[**](#Methods) ### [**](#authenticate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L32)optionalauthenticate * **authenticate(options: [AuthenticateOptions](/api/passport/interface/AuthenticateOptions.md), callback: (...args: any\[]) => any): any --- # IPassportStrategy ## Index[**](#Index) ### Methods * [**deserializeUser](#deserializeUser) * [**getStrategyOptions](#getStrategyOptions) * [**serializeUser](#serializeUser) * [**transformAuthInfo](#transformAuthInfo) * [**validate](#validate) ## Methods[**](#Methods) ### [**](#deserializeUser)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L27)optionaldeserializeUser * **deserializeUser(id: any, done: (err: any, user? : any) => void): void ### [**](#getStrategyOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L25)getStrategyOptions * **getStrategyOptions(): any ### [**](#serializeUser)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L26)optionalserializeUser * **serializeUser(user: any, done: (err: any, id? : any) => void): void ### [**](#transformAuthInfo)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L28)optionaltransformAuthInfo * **transformAuthInfo(info: any, done: (err: any, info: any) => void): void ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L24)validate * **validate(...args: any\[]): any --- # StrategyCreatedStatic ## Index[**](#Index) ### Methods * [**error](#error) * [**fail](#fail) * [**pass](#pass) * [**redirect](#redirect) * [**success](#success) ## Methods[**](#Methods) ### [**](#error)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L93)error * **error(err: any): void - Internal error while performing authentication. Strategies should call this function when an internal error occurs during the process of performing authentication; for example, if the user directory is not available. ### [**](#fail)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L70)fail * **fail(challenge? : string | number, status? : number): void - Fail authentication, with optional `challenge` and `status`, defaulting to 401. Strategies should call this function to fail an authentication attempt. ### [**](#pass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L85)pass * **pass(): void - Pass without making a success or fail decision. Under most circumstances, Strategies should not need to call this function. It exists primarily to allow previous authentication state to be restored, for example from an HTTP session. ### [**](#redirect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L77)redirect * **redirect(url: string, status? : number): void - Redirect to `url` with optional `status`, defaulting to 302. Strategies should call this function to redirect the user (via their user agent) to a third-party website for authentication. ### [**](#success)[**](https://github.com/midwayjs/midway/blob/3.x/packages/passport/src/interface.ts#L63)success * **success(user: any, info? : Record\): void - Authenticate `user`, with optional `info`. Strategies should call this function to successfully authenticate a user. `user` should be an object supplied by the application after it has been given an opportunity to verify credentials. `info` is an optional argument containing additional user information. This is useful for third-party authentication strategies to pass profile details. --- # @midwayjs/prometheus ## Index[**](#Index) ### Classes * [**Configuration](/api/prometheus/class/Configuration.md) * [**DataService](/api/prometheus/class/DataService.md) --- # @midwayjs/prometheus-socket-io ## Index[**](#Index) ### Classes * [**Configuration](/api/prometheus-socket-io/class/Configuration.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**dataService](#dataService) * [**socketApp](#socketApp) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PrometheusSocketIOConfiguration](/api/prometheus-socket-io/class/Configuration.md) ## Properties[**](#Properties) ### [**](#dataService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus-socket-io/src/configuration.ts#L15)dataService **dataService: DataService ### [**](#socketApp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus-socket-io/src/configuration.ts#L12)socketApp **socketApp: Application ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus-socket-io/src/configuration.ts#L17)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus-socket-io/src/configuration.ts#L141)onStop * **onStop(): Promise\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**http\_server](#http_server) * [**prometheusConfig](#prometheusConfig) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [PrometheusConfiguration](/api/prometheus/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/configuration.ts#L32)app **app: any ### [**](#http_server)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/configuration.ts#L34)http\_server **http\_server: any ### [**](#prometheusConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/configuration.ts#L29)prometheusConfig **prometheusConfig: DefaultMetricsCollectorConfiguration ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/configuration.ts#L36)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/configuration.ts#L101)onStop * **onStop(): Promise\ --- # DataService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**bInit](#bInit) * [**metrics](#metrics) * [**prometheusConfig](#prometheusConfig) * [**responseHistogram](#responseHistogram) * [**responseSummary](#responseSummary) * [**userDefinedMetrics](#userDefinedMetrics) ### Methods * [**define](#define) * [**getData](#getData) * [**getUser](#getUser) * [**inc](#inc) * [**init](#init) * [**observe](#observe) * [**set](#set) * [**setDiff](#setDiff) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DataService(): [DataService](/api/prometheus/class/DataService.md) ## Properties[**](#Properties) ### [**](#bInit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L20)bInit **bInit: boolean = false ### [**](#metrics)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L15)metrics **metrics: any ### [**](#prometheusConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L18)prometheusConfig **prometheusConfig: any ### [**](#responseHistogram)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L11)responseHistogram **responseHistogram: Histogram\ ### [**](#responseSummary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L9)responseSummary **responseSummary: Summary\ ### [**](#userDefinedMetrics)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L13)userDefinedMetrics **userDefinedMetrics: any = {} ## Methods[**](#Methods) ### [**](#define)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L70)define * **define(name: any, type: any, options: any): void ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L117)getData * **getData(): Promise\ ### [**](#getUser)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L47)getUser * **getUser(method: any, status: any, path: any, time: any): Promise\ ### [**](#inc)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L78)inc * **inc(name: any, labels: any, value? : number): Promise\ ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L22)init * **init(): Promise\ ### [**](#observe)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L86)observe * **observe(name: any, labels: any, value: any): Promise\ ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L96)set * **set(name: any, value: any): Promise\ ### [**](#setDiff)[**](https://github.com/midwayjs/midway/blob/3.x/packages/prometheus/src/service/dataService.ts#L104)setDiff * **setDiff(name: any, diff: any): Promise\ --- # @midwayjs/rabbitmq ## Index[**](#Index) ### Classes * [**Configuration](/api/rabbitmq/class/Configuration.md) * [**Framework](/api/rabbitmq/class/Framework.md) ### Interfaces * [**Context](/api/rabbitmq/interface/Context.md) * [**IMidwayRabbitMQConfigurationOptions](/api/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) * [**IRabbitMQApplication](/api/rabbitmq/interface/IRabbitMQApplication.md) * [**IRabbitMQExchange](/api/rabbitmq/interface/IRabbitMQExchange.md) ### Type Aliases * [**Application](/api/rabbitmq.md#Application) * [**DefaultConfig](/api/rabbitmq.md#DefaultConfig) * [**IMidwayRabbitMQApplication](/api/rabbitmq.md#IMidwayRabbitMQApplication) * [**IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext) * [**NextFunction](/api/rabbitmq.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L49)Application **Application: [IMidwayRabbitMQApplication](/api/rabbitmq.md#IMidwayRabbitMQApplication) ### [**](#DefaultConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L52)DefaultConfig **DefaultConfig: string | AmqpOptions.Connect ### [**](#IMidwayRabbitMQApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L25)IMidwayRabbitMQApplication **IMidwayRabbitMQApplication: IMidwayApplication<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext)> & [IRabbitMQApplication](/api/rabbitmq/interface/IRabbitMQApplication.md) ### [**](#IMidwayRabbitMQContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L42)IMidwayRabbitMQContext **IMidwayRabbitMQContext: IMidwayContext<{ ack: (data: any) => void; channel: Channel; data: ConsumeMessage; queueName: string }> ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L51)NextFunction **NextFunction: BaseNextFunction --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [RabbitMQConfiguration](/api/rabbitmq/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/configuration.ts#L14)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayRabbitMQApplication](/api/rabbitmq.md#IMidwayRabbitMQApplication), [IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), [IMidwayRabbitMQConfigurationOptions](/api/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayRabbitMQFramework](/api/rabbitmq/class/Framework.md) - Inherited from BaseFramework< IMidwayRabbitMQApplication, IMidwayRabbitMQContext, IMidwayRabbitMQConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayRabbitMQApplication](/api/rabbitmq.md#IMidwayRabbitMQApplication) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayRabbitMQConfigurationOptions](/api/rabbitmq/interface/IMidwayRabbitMQConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/framework.ts#L32)applicationInitialize * **applicationInitialize(options: any): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/framework.ts#L28)configure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [IMidwayRabbitMQApplication](/api/rabbitmq.md#IMidwayRabbitMQApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/framework.ts#L163)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/framework.ts#L42)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # Context ### Hierarchy * [IMidwayRabbitMQContext](/api/rabbitmq.md#IMidwayRabbitMQContext) * *Context* ## Index[**](#Index) ### Properties * [**ack](#ack) * [**channel](#channel) * [**data](#data) * [**logger](#logger) * [**queueName](#queueName) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#ack)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L46)ack **ack: (data: any) => void Inherited from IMidwayRabbitMQContext.ack ### [**](#channel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L44)channel **channel: Channel Inherited from IMidwayRabbitMQContext.channel ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L43)data **data: ConsumeMessage Inherited from IMidwayRabbitMQContext.data ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayRabbitMQContext.logger ### [**](#queueName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L45)queueName **queueName: string Inherited from IMidwayRabbitMQContext.queueName ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayRabbitMQContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayRabbitMQContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayRabbitMQContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayRabbitMQContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayRabbitMQContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayRabbitMQContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayRabbitMQContext.setAttr Set value to app attribute map --- # IMidwayRabbitMQConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayRabbitMQConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**exchanges](#exchanges) * [**logger](#logger) * [**reconnectTime](#reconnectTime) * [**socketOptions](#socketOptions) * [**url](#url) * [**useConfirmChannel](#useConfirmChannel) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#exchanges)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L38)optionalexchanges **exchanges? : [IRabbitMQExchange](/api/rabbitmq/interface/IRabbitMQExchange.md)\[] ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#reconnectTime)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L37)optionalreconnectTime **reconnectTime? : number ### [**](#socketOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L36)optionalsocketOptions **socketOptions? : any ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L35)url **url: string | Connect ### [**](#useConfirmChannel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L39)optionaluseConfirmChannel **useConfirmChannel? : boolean --- # IRabbitMQApplication ## Index[**](#Index) ### Methods * [**close](#close) * [**connect](#connect) * [**createChannel](#createChannel) * [**createConsumer](#createConsumer) ## Methods[**](#Methods) ### [**](#close)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L22)close * **close(): Promise\ ### [**](#connect)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L12)connect * **connect(...args: any\[]): Promise\ ### [**](#createChannel)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L13)createChannel * **createChannel(): Promise\ ### [**](#createConsumer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L14)createConsumer * **createConsumer(listenerOptions: RabbitMQListenerOptions, listenerCallback: (msg: ConsumeMessage, channel: Channel, channelWrapper: any) => Promise\): Promise\ --- # IRabbitMQExchange ## Index[**](#Index) ### Properties * [**name](#name) * [**options](#options) * [**type](#type) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L29)name **name: string ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L31)optionaloptions **options? : AssertExchange ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/rabbitmq/src/interface.ts#L30)type **type: string --- # @midwayjs/redis ## Index[**](#Index) ### Classes * [**Configuration](/api/redis/class/Configuration.md) * [**RedisService](/api/redis/class/RedisService.md) * [**RedisServiceDiscoverClient](/api/redis/class/RedisServiceDiscoverClient.md) * [**RedisServiceDiscovery](/api/redis/class/RedisServiceDiscovery.md) * [**RedisServiceFactory](/api/redis/class/RedisServiceFactory.md) ### Interfaces * [**RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md) * [**RedisServiceDiscoveryOptions](/api/redis/interface/RedisServiceDiscoveryOptions.md) ### Type Aliases * [**MidwayRedisConfigOptions](/api/redis.md#MidwayRedisConfigOptions) * [**RedisConfigOptions](/api/redis.md#RedisConfigOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#MidwayRedisConfigOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L76)MidwayRedisConfigOptions **MidwayRedisConfigOptions: ServiceFactoryConfigOption<[RedisConfigOptions](/api/redis.md#RedisConfigOptions)> & { serviceDiscovery? : [RedisServiceDiscoveryOptions](/api/redis/interface/RedisServiceDiscoveryOptions.md) } ### [**](#RedisConfigOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L10)RedisConfigOptions **RedisConfigOptions: Redis.RedisOptions | ({ nodes? : ClusterNode\[] } & ClusterOptions) --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onHealthCheck](#onHealthCheck) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [RedisConfiguration](/api/redis/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onHealthCheck)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/configuration.ts#L29)onHealthCheck * **onHealthCheck(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onHealthCheck ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/configuration.ts#L20)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/configuration.ts#L24)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # RedisService ### Hierarchy * Redis * *RedisService* ### Implements * Redis ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RedisService(): [RedisService](/api/redis/class/RedisService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/manager.ts#L191)init * **init(): Promise\ --- # RedisServiceDiscoverClient ### Hierarchy * ServiceDiscoveryClient\ * *RedisServiceDiscoverClient* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**defaultMeta](#defaultMeta) ### Methods * [**beforeStop](#beforeStop) * [**deregister](#deregister) * [**getSelfInstance](#getSelfInstance) * [**offline](#offline) * [**online](#online) * [**register](#register) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L215)constructor * **new RedisServiceDiscoverClient(redis: Redis, serviceDiscoveryOptions: [RedisServiceDiscoveryOptions](/api/redis/interface/RedisServiceDiscoveryOptions.md), logger: ILogger, getListener: (serviceName: string) => Promise\): [RedisServiceDiscoverClient](/api/redis/class/RedisServiceDiscoverClient.md) - Overrides ServiceDiscoveryClient< Redis, RedisServiceDiscoveryOptions, RedisInstanceMetadata >.constructor ## Accessors[**](#Accessors) ### [**](#defaultMeta)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L9)defaultMeta * **get defaultMeta(): DefaultInstanceMetadata - Inherited from ServiceDiscoveryClient.defaultMeta ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L327)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscoveryClient.beforeStop ### [**](#deregister)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L238)deregister * **deregister(): Promise\ - Overrides ServiceDiscoveryClient.deregister ### [**](#getSelfInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L11)getSelfInstance * **getSelfInstance(): [RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md) - Inherited from ServiceDiscoveryClient.getSelfInstance ### [**](#offline)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L296)offline * **offline(): Promise\ - Overrides ServiceDiscoveryClient.offline ### [**](#online)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L259)online * **online(): Promise\ - Overrides ServiceDiscoveryClient.online ### [**](#register)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L224)register * **register(instance: [RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)): Promise\ - Overrides ServiceDiscoveryClient.register ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L16)stop * **stop(): Promise\ - Inherited from ServiceDiscoveryClient.stop 停止服务发现 --- # RedisServiceDiscovery ### Hierarchy * ServiceDiscovery\ * *RedisServiceDiscovery* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**beforeStop](#beforeStop) * [**createClient](#createClient) * [**getInstance](#getInstance) * [**getInstances](#getInstances) * [**getServiceClient](#getServiceClient) * [**init](#init) * [**setLoadBalancer](#setLoadBalancer) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RedisServiceDiscovery(): [RedisServiceDiscovery](/api/redis/class/RedisServiceDiscovery.md) - Inherited from ServiceDiscovery< Redis, RedisServiceDiscoveryOptions, RedisInstanceMetadata, RedisInstanceMetadata, string >.constructor ## Methods[**](#Methods) ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L434)beforeStop * **beforeStop(): Promise\ - Overrides ServiceDiscovery.beforeStop ### [**](#createClient)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L41)createClient * **createClient(options? : ServiceDiscoveryOptions<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md), Record\>): ServiceDiscoveryClient\ - Inherited from ServiceDiscovery.createClient ### [**](#getInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L52)getInstance * **getInstance(options: string): Promise<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)> - Inherited from ServiceDiscovery.getInstance 获取一个可用服务实例(带负载均衡) ### [**](#getInstances)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L426)publicgetInstances * **getInstances(serviceName: string): Promise<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)\[]> - Overrides ServiceDiscovery.getInstances ### [**](#getServiceClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L363)getServiceClient * **getServiceClient(): Redis - Overrides ServiceDiscovery.getServiceClient ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/extension/serviceDiscovery.ts#L354)init * **init(): Promise\ ### [**](#setLoadBalancer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceDiscovery/serviceDiscovery.d.ts#L56)setLoadBalancer * **setLoadBalancer(type: LoadBalancerType | ILoadBalancer<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)>): void - Inherited from ServiceDiscovery.setLoadBalancer 设置负载均衡策略 --- # RedisServiceFactory ### Hierarchy * ServiceFactory\ * *RedisServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new RedisServiceFactory(): [RedisServiceFactory](/api/redis/class/RedisServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = Redis ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/manager.ts#L160)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # RedisInstanceMetadata ### Hierarchy * ServiceDiscoveryBaseInstance * *RedisInstanceMetadata* ## Index[**](#Index) ### Properties * [**host](#host) * [**id](#id) * [**meta](#meta) * [**port](#port) * [**serviceName](#serviceName) * [**status](#status) * [**tags](#tags) * [**ttl](#ttl) ## Properties[**](#Properties) ### [**](#host)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L28)host **host: string 服务实例的地址 ### [**](#id)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L24)id **id: string 服务实例 ID ### [**](#meta)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L44)optionalmeta **meta? : Record\ 服务实例的元数据 ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L32)port **port: number 服务实例的端口 ### [**](#serviceName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L20)serviceName **serviceName: string 服务名称 ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L48)optionalstatus **status? : UP | DOWN 服务实例的状态 ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L40)optionaltags **tags? : string\[] 服务实例的标签 ### [**](#ttl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L36)optionalttl **ttl? : number 服务实例的过期时间(秒) --- # RedisServiceDiscoveryOptions ### Hierarchy * ServiceDiscoveryOptions<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)> * *RedisServiceDiscoveryOptions* ## Index[**](#Index) ### Properties * [**downTTL](#downTTL) * [**loadBalancer](#loadBalancer) * [**prefix](#prefix) * [**scanCount](#scanCount) * [**serviceDiscoveryClient](#serviceDiscoveryClient) * [**serviceOptions](#serviceOptions) * [**ttl](#ttl) ## Properties[**](#Properties) ### [**](#downTTL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L69)optionaldownTTL **downTTL? : number 下线状态的 TTL(秒) ### [**](#loadBalancer)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L1139)optionalloadBalancer **loadBalancer? : LoadBalancerType | ILoadBalancer<[RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md)> Inherited from ServiceDiscoveryOptions.loadBalancer ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L59)optionalprefix **prefix? : string 服务信息的 key 前缀 ### [**](#scanCount)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L73)optionalscanCount **scanCount? : number SCAN 命令每次遍历的数量,默认 100 ### [**](#serviceDiscoveryClient)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L1137)optionalserviceDiscoveryClient **serviceDiscoveryClient? : string Inherited from ServiceDiscoveryOptions.serviceDiscoveryClient ### [**](#serviceOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L63)optionalserviceOptions **serviceOptions? : [RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md) | (meta: DefaultInstanceMetadata) => [RedisInstanceMetadata](/api/redis/interface/RedisInstanceMetadata.md) Overrides ServiceDiscoveryOptions.serviceOptions 服务实例配置 ### [**](#ttl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/redis/src/interface.ts#L55)optionalttl **ttl? : number 服务信息的过期时间(秒) --- # @midwayjs/security ## Index[**](#Index) ### Classes * [**CSPMiddleware](/api/security/class/CSPMiddleware.md) * [**Configuration](/api/security/class/Configuration.md) * [**CsrfMiddleware](/api/security/class/CsrfMiddleware.md) * [**HSTSMiddleware](/api/security/class/HSTSMiddleware.md) * [**NoOpenMiddleware](/api/security/class/NoOpenMiddleware.md) * [**NoSniffMiddleware](/api/security/class/NoSniffMiddleware.md) * [**SecurityHelper](/api/security/class/SecurityHelper.md) * [**XFrameMiddleware](/api/security/class/XFrameMiddleware.md) * [**XSSProtectionMiddleware](/api/security/class/XSSProtectionMiddleware.md) ### Interfaces * [**SecurityCSPOptions](/api/security/interface/SecurityCSPOptions.md) * [**SecurityCSRFOptions](/api/security/interface/SecurityCSRFOptions.md) * [**SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * [**SecurityHSTSOptions](/api/security/interface/SecurityHSTSOptions.md) * [**SecurityOptions](/api/security/interface/SecurityOptions.md) * [**SecurityXFrameOptions](/api/security/interface/SecurityXFrameOptions.md) * [**SecurityXSSProtectionOptions](/api/security/interface/SecurityXSSProtectionOptions.md) ### Type Aliases * [**SecurityCSRFType](/api/security.md#SecurityCSRFType) ## Type Aliases[**](<#Type Aliases>) ### [**](#SecurityCSRFType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L97)SecurityCSRFType **SecurityCSRFType: all | any | ctoken | referer --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**security](#security) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SecurityConfiguration](/api/security/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/configuration.ts#L27)applicationManager **applicationManager: MidwayApplicationManager ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/configuration.ts#L30)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/configuration.ts#L32)onReady * **onReady(): Promise\ --- # CSPMiddleware ### Hierarchy * BaseMiddleware * *CSPMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CSPMiddleware(): [CSPMiddleware](/api/security/class/CSPMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csp.middleware.ts#L15)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csp.middleware.ts#L74)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # CsrfMiddleware ### Hierarchy * BaseMiddleware * *CsrfMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**assertCsrf](#assertCsrf) * [**compatibleMiddleware](#compatibleMiddleware) * [**getCSRFSecret](#getCSRFSecret) * [**getInputToken](#getInputToken) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new CsrfMiddleware(): [CsrfMiddleware](/api/security/class/CsrfMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#assertCsrf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csrf.middleware.ts#L45)assertCsrf * **assertCsrf(context: any, request: any): void ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csrf.middleware.ts#L12)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#getCSRFSecret)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csrf.middleware.ts#L64)getCSRFSecret * **getCSRFSecret(context: any): any ### [**](#getInputToken)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csrf.middleware.ts#L91)getInputToken * **getInputToken(context: any, request: any): any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/csrf.middleware.ts#L157)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # HSTSMiddleware ### Hierarchy * BaseMiddleware * *HSTSMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new HSTSMiddleware(): [HSTSMiddleware](/api/security/class/HSTSMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/hsts.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/hsts.middleware.ts#L15)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # NoOpenMiddleware ### Hierarchy * BaseMiddleware * *NoOpenMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NoOpenMiddleware(): [NoOpenMiddleware](/api/security/class/NoOpenMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/noopen.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/noopen.middleware.ts#L11)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # NoSniffMiddleware ### Hierarchy * BaseMiddleware * *NoSniffMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NoSniffMiddleware(): [NoSniffMiddleware](/api/security/class/NoSniffMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/nosniff.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/nosniff.middleware.ts#L14)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # SecurityHelper ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**resolve](#resolve) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SecurityHelper(): [SecurityHelper](/api/security/class/SecurityHelper.md) ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/helper.ts#L19)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/helper.ts#L7)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve --- # XFrameMiddleware ### Hierarchy * BaseMiddleware * *XFrameMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new XFrameMiddleware(): [XFrameMiddleware](/api/security/class/XFrameMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/xframe.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/xframe.middleware.ts#L13)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # XSSProtectionMiddleware ### Hierarchy * BaseMiddleware * *XSSProtectionMiddleware* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**match](#match) * [**security](#security) ### Methods * [**compatibleMiddleware](#compatibleMiddleware) * [**init](#init) * [**resolve](#resolve) * [**securityName](#securityName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new XSSProtectionMiddleware(): [XSSProtectionMiddleware](/api/security/class/XSSProtectionMiddleware.md) - Inherited from BaseMiddleware.constructor ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L8)ignore **ignore: IgnoreMatcher\\[] Inherited from BaseMiddleware.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L7)match **match: IgnoreMatcher\\[] Inherited from BaseMiddleware.match ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L6)security **security: [SecurityOptions](/api/security/interface/SecurityOptions.md) Inherited from BaseMiddleware.security ## Methods[**](#Methods) ### [**](#compatibleMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/xssProtection.middleware.ts#L6)compatibleMiddleware * **compatibleMiddleware(context: any, req: any, res: any, next: any): Promise\ - Overrides BaseMiddleware.compatibleMiddleware ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L11)init * **init(): Promise\ - Inherited from BaseMiddleware.init ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/base.ts#L20)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Inherited from BaseMiddleware.resolve ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/middleware/xssProtection.middleware.ts#L12)securityName * **securityName(): string - Overrides BaseMiddleware.securityName --- # SecurityCSPOptions ### Hierarchy * [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * *SecurityCSPOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**policy](#policy) * [**reportOnly](#reportOnly) * [**supportIE](#supportIE) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#policy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L85)policy **policy: {} ### [**](#reportOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L88)reportOnly **reportOnly: boolean ### [**](#supportIE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L89)supportIE **supportIE: boolean --- # SecurityCSRFOptions ### Hierarchy * [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * *SecurityCSRFOptions* ## Index[**](#Index) ### Properties * [**bodyName](#bodyName) * [**cookieDomain](#cookieDomain) * [**cookieName](#cookieName) * [**enable](#enable) * [**headerName](#headerName) * [**ignore](#ignore) * [**match](#match) * [**queryName](#queryName) * [**refererWhiteList](#refererWhiteList) * [**sessionName](#sessionName) * [**type](#type) * [**useSession](#useSession) ## Properties[**](#Properties) ### [**](#bodyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L62)bodyName **bodyName: string The name of the csrf token in the body. ### [**](#cookieDomain)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L68)cookieDomain **cookieDomain: (context: any) => string ### [**](#cookieName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L50)cookieName **cookieName: string | string\[] The key name stored in the cookie by the token of csrf ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#headerName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L58)headerName **headerName: string The name of the csrf token in the header ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#queryName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L66)queryName **queryName: string The name of the csrf token in the query. ### [**](#refererWhiteList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L67)refererWhiteList **refererWhiteList: string\[] ### [**](#sessionName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L54)sessionName **sessionName: string The key name of the CSRF token stored in the session. ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L42)type **type: [SecurityCSRFType](/api/security.md#SecurityCSRFType) ### [**](#useSession)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L46)useSession **useSession: boolean If set to true, the secret will be stored in the session instead of the cookie. --- # SecurityEnableOptions ### Hierarchy * *SecurityEnableOptions* * [SecurityCSRFOptions](/api/security/interface/SecurityCSRFOptions.md) * [SecurityXFrameOptions](/api/security/interface/SecurityXFrameOptions.md) * [SecurityHSTSOptions](/api/security/interface/SecurityHSTSOptions.md) * [SecurityXSSProtectionOptions](/api/security/interface/SecurityXSSProtectionOptions.md) * [SecurityCSPOptions](/api/security/interface/SecurityCSPOptions.md) ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] --- # SecurityHSTSOptions ### Hierarchy * [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * *SecurityHSTSOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**includeSubdomains](#includeSubdomains) * [**match](#match) * [**maxAge](#maxAge) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#includeSubdomains)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L77)includeSubdomains **includeSubdomains: boolean ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L76)maxAge **maxAge: number --- # SecurityOptions ## Index[**](#Index) ### Properties * [**csp](#csp) * [**csrf](#csrf) * [**hsts](#hsts) * [**noopen](#noopen) * [**nosniff](#nosniff) * [**xframe](#xframe) * [**xssProtection](#xssProtection) ## Properties[**](#Properties) ### [**](#csp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L13)csp **csp: Partial<[SecurityCSPOptions](/api/security/interface/SecurityCSPOptions.md)> content security policy config default not enable ### [**](#csrf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L8)csrf **csrf: Partial<[SecurityCSRFOptions](/api/security/interface/SecurityCSRFOptions.md)> whether defend csrf attack default enable and use cookie ### [**](#hsts)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L23)hsts **hsts: Partial<[SecurityHSTSOptions](/api/security/interface/SecurityHSTSOptions.md)> whether enable Strict-Transport-Security response header default not enable and maxAge equals one year ### [**](#noopen)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L28)noopen **noopen: Partial<[SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md)> whether enable IE automaticlly download open default not enable ### [**](#nosniff)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L33)nosniff **nosniff: Partial<[SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md)> whether enable IE8 automaticlly dedect mime default not enable ### [**](#xframe)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L18)xframe **xframe: Partial<[SecurityXFrameOptions](/api/security/interface/SecurityXFrameOptions.md)> whether enable X-Frame-Options response header default enable and value equals SAMEORIGIN ### [**](#xssProtection)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L38)xssProtection **xssProtection: Partial<[SecurityXSSProtectionOptions](/api/security/interface/SecurityXSSProtectionOptions.md)> whether enable IE8 XSS Filter, default is open default enable --- # SecurityXFrameOptions ### Hierarchy * [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * *SecurityXFrameOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**value](#value) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L72)value **value: string --- # SecurityXSSProtectionOptions ### Hierarchy * [SecurityEnableOptions](/api/security/interface/SecurityEnableOptions.md) * *SecurityXSSProtectionOptions* ## Index[**](#Index) ### Properties * [**enable](#enable) * [**ignore](#ignore) * [**match](#match) * [**value](#value) ## Properties[**](#Properties) ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L92)enable **enable: boolean Inherited from SecurityEnableOptions.enable ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L94)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L93)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Inherited from SecurityEnableOptions.match ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/security/src/interface.ts#L81)value **value: string --- # @midwayjs/sequelize ## Index[**](#Index) ### Classes * [**Configuration](/api/sequelize/class/Configuration.md) * [**SequelizeDataSourceManager](/api/sequelize/class/SequelizeDataSourceManager.md) ### Functions * [**InjectDataSource](/api/sequelize/function/InjectDataSource.md) * [**InjectRepository](/api/sequelize/function/InjectRepository.md) ### Type Aliases * [**SequelizeConfigOptions](/api/sequelize.md#SequelizeConfigOptions) ## Type Aliases[**](<#Type Aliases>) ### [**](#SequelizeConfigOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/interface.ts#L4)SequelizeConfigOptions **SequelizeConfigOptions: DataSourceManagerConfigOption\ --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) * [**sequelizeConfig](#sequelizeConfig) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SequelizeConfiguration](/api/sequelize/class/Configuration.md) ## Properties[**](#Properties) ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L30)dataSourceManager **dataSourceManager: [SequelizeDataSourceManager](/api/sequelize/class/SequelizeDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L28)decoratorService **decoratorService: MidwayDecoratorService ### [**](#sequelizeConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L25)sequelizeConfig **sequelizeConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L33)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L69)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/configuration.ts#L75)onStop * **onStop(): Promise\ --- # SequelizeDataSourceManager ### Hierarchy * DataSourceManager\ * *SequelizeDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**coreLogger](#coreLogger) * [**sequelizeConfig](#sequelizeConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SequelizeDataSourceManager(): [SequelizeDataSourceManager](/api/sequelize/class/SequelizeDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#coreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/dataSourceManager.ts#L20)coreLogger **coreLogger: ILogger ### [**](#sequelizeConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/dataSourceManager.ts#L17)sequelizeConfig **sequelizeConfig: any ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L36)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L37)createInstance * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>): Promise\ * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L30)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L23)getDataSource * **getDataSource(dataSourceName: string): Sequelize - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L29)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L61)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L60)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/dataSourceManager.ts#L29)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/sequelize/src/dataSourceManager.ts#L23)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L35)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L62)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L64)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L63)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L59)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L65)staticformatGlobString * **formatGlobString(globString: string): string\[] - Inherited from DataSourceManager.formatGlobString ### [**](#globModels)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L66)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : ModuleLoadType): Promise\ - Inherited from DataSourceManager.globModels --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectRepository ### Callable * **InjectRepository(modelKey: new () => Model\, connectionName? : string): PropertyDecorator --- # @midwayjs/session ## Index[**](#Index) ### Classes * [**Configuration](/api/session/class/Configuration.md) * [**SessionMiddleware](/api/session/class/SessionMiddleware.md) * [**SessionStore](/api/session/class/SessionStore.md) * [**SessionStoreManager](/api/session/class/SessionStoreManager.md) ### Interfaces * [**ISession](/api/session/interface/ISession.md) * [**SessionOptions](/api/session/interface/SessionOptions.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**logger](#logger) * [**sessionConfig](#sessionConfig) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SessionConfiguration](/api/session/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/configuration.ts#L21)applicationManager **applicationManager: MidwayApplicationManager ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/configuration.ts#L24)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/configuration.ts#L27)sessionConfig **sessionConfig: any ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/configuration.ts#L29)onReady * **onReady(): Promise\ --- # SessionMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**logger](#logger) * [**sessionConfig](#sessionConfig) * [**sessionStoreManager](#sessionStoreManager) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionMiddleware(): [SessionMiddleware](/api/session/class/SessionMiddleware.md) ## Properties[**](#Properties) ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/middleware/session.ts#L147)logger **logger: any ### [**](#sessionConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/middleware/session.ts#L144)sessionConfig **sessionConfig: any ### [**](#sessionStoreManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/middleware/session.ts#L150)sessionStoreManager **sessionStoreManager: [SessionStoreManager](/api/session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/middleware/session.ts#L152)resolve * **resolve(app: any): (ctx: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/middleware/session.ts#L181)staticgetName * **getName(): string --- # abstractSessionStore ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**destroy](#destroy) * [**get](#get) * [**set](#set) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStore(): [SessionStore](/api/session/class/SessionStore.md) ## Methods[**](#Methods) ### [**](#destroy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L134)abstractdestroy * **destroy(key: any): any ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L132)abstractget * **get(key: string): any ### [**](#set)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L133)abstractset * **set(key: string, value: string, maxAge: number): any --- # SessionStoreManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSessionStore](#getSessionStore) * [**setSessionStore](#setSessionStore) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SessionStoreManager(): [SessionStoreManager](/api/session/class/SessionStoreManager.md) ## Methods[**](#Methods) ### [**](#getSessionStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/lib/store.ts#L11)getSessionStore * **getSessionStore(): [SessionStore](/api/session/class/SessionStore.md) ### [**](#setSessionStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/lib/store.ts#L8)setSessionStore * **setSessionStore(sessionStore: any): void --- # ISession ### Indexable **\[\_ : string]: any allow to put any value on session object ## Index[**](#Index) ### Properties * [**length](#length) * [**maxAge](#maxAge) * [**populated](#populated) ### Methods * [**manuallyCommit](#manuallyCommit) * [**regenerate](#regenerate) * [**save](#save) * [**toJSON](#toJSON) ## Properties[**](#Properties) ### [**](#length)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L13)readonlylength **length: number Return how many values there are in the session object. Used to see if it"s "populated". ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L23)maxAge **maxAge: number | session get/set session maxAge ### [**](#populated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L18)readonlypopulated **populated: boolean populated flag, which is just a boolean alias of .length. ## Methods[**](#Methods) ### [**](#manuallyCommit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L28)manuallyCommit * **manuallyCommit(): Promise\ - commit this session's headers if autoCommit is set to false. ### [**](#regenerate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L33)regenerate * **regenerate(callback? : () => void): void - regenerate this session ### [**](#save)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L38)save * **save(callback? : () => void): void - save this session no matter whether it is populated ### [**](#toJSON)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L7)toJSON * **toJSON(): object - JSON representation of the session. --- # SessionOptions ### Hierarchy * Omit\ * *SessionOptions* ## Index[**](#Index) ### Properties * [**ContextStore](#ContextStore) * [**autoCommit](#autoCommit) * [**decode](#decode) * [**enable](#enable) * [**encode](#encode) * [**externalKey](#externalKey) * [**genid](#genid) * [**key](#key) * [**maxAge](#maxAge) * [**prefix](#prefix) * [**renew](#renew) * [**rolling](#rolling) ### Methods * [**beforeSave](#beforeSave) * [**valid](#valid) ## Properties[**](#Properties) ### [**](#ContextStore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L108)optionalContextStore **ContextStore? : new (ctx: any) => [SessionStore](/api/session/class/SessionStore.md) If your session store requires data or utilities from context, opts.ContextStore is alse supported. ContextStore must be a class which claims three instance methods demonstrated above. new ContextStore(ctx) will be executed on every request. ### [**](#autoCommit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L128)optionalautoCommit **autoCommit? : boolean (boolean) automatically commit headers (default true). ### [**](#decode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L80)decode **decode: (obj: Record\) => string custom decode method ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L59)enable **enable: boolean ### [**](#encode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L75)encode **encode: (str: string) => Record\ custom encode method ### [**](#externalKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L101)optionalexternalKey **externalKey? : ExternalKeys External key is used the cookie by default, but you can use options.externalKey to customize your own external key methods. ### [**](#genid)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L85)genid **genid: () => string The way of generating external session id is controlled by the options.genid, which defaults to Date.now() + "-" + uid.sync(24). ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L63)key **key: string cookie key (default is koa:sess) ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L70)optionalmaxAge **maxAge? : number | session maxAge in ms (default is 1 days) "session" will result in a cookie that expires when session/browser is closed Warning: If a session cookie is stolen, this cookie will never expire ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L113)optionalprefix **prefix? : string If you want to add prefix for all external session id, you can use options.prefix, it will not work if options.genid present. ### [**](#renew)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L95)optionalrenew **renew? : boolean Renew session when session is nearly expired, so we can always keep user logged in. (default is false) ### [**](#rolling)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L90)optionalrolling **rolling? : boolean Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. default is false ## Methods[**](#Methods) ### [**](#beforeSave)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L123)optionalbeforeSave * **beforeSave(ctx: any, session: [ISession](/api/session/interface/ISession.md)): void - Hook: before save session ### [**](#valid)[**](https://github.com/midwayjs/midway/blob/3.x/packages/session/src/interface.ts#L118)optionalvalid * **valid(ctx: any, session: Partial<[ISession](/api/session/interface/ISession.md)>): void - Hook: valid session value before use it --- # @midwayjs/socketio ## Index[**](#Index) ### Classes * [**Configuration](/api/socketio/class/Configuration.md) * [**Framework](/api/socketio/class/Framework.md) ### Type Aliases * [**Application](/api/socketio.md#Application) * [**Context](/api/socketio.md#Context) * [**IMidwaySocketIOOptions](/api/socketio.md#IMidwaySocketIOOptions) * [**NextFunction](/api/socketio.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/interface.ts#L11)Application **Application: IMidwayApplication<[Context](/api/socketio.md#Context), { getConnectionMiddleware: ContextMiddlewareManager<[Context](/api/socketio.md#Context), [NextFunction](/api/socketio.md#NextFunction), undefined>; useConnectionMiddleware: (middleware: CommonMiddlewareUnion<[Context](/api/socketio.md#Context), [NextFunction](/api/socketio.md#NextFunction), undefined>) => void; use: any } & SocketIO.Server> ### [**](#Context)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/interface.ts#L35)Context **Context: IMidwayContext\ ### [**](#IMidwaySocketIOOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/interface.ts#L28)IMidwaySocketIOOptions **IMidwaySocketIOOptions: { port? : number; pubClient? : any; subClient? : any } & Partial\ & IConfigurationOptions ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/interface.ts#L41)NextFunction **NextFunction: BaseNextFunction --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SocketIOConfiguration](/api/socketio/class/Configuration.md) --- # Framework ### Hierarchy * BaseFramework<[Application](/api/socketio.md#Application), [Context](/api/socketio.md#Context), [IMidwaySocketIOOptions](/api/socketio.md#IMidwaySocketIOOptions)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConnectionMiddleware](#getConnectionMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**getSocketServerPort](#getSocketServerPort) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useConnectionMiddleware](#useConnectionMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwaySocketIOFramework](/api/socketio/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwaySocketIOOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [Application](/api/socketio.md#Application) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwaySocketIOOptions](/api/socketio.md#IMidwaySocketIOOptions) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L45)applicationInitialize * **applicationInitialize(): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/socketio.md#Context), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L41)configure * **configure(): [IMidwaySocketIOOptions](/api/socketio.md#IMidwaySocketIOOptions) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [Application](/api/socketio.md#Application) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L567)publicgetConnectionMiddleware * **getConnectionMiddleware(): ContextMiddlewareManager<[Context](/api/socketio.md#Context), NextFunction, undefined> ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L557)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/socketio.md#Context), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getSocketServerPort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L97)publicgetSocketServerPort * **getSocketServerPort(): number ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L63)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/socketio.md#Context), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/socketio/src/framework.ts#L561)publicuseConnectionMiddleware * **useConnectionMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/socketio.md#Context), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/socketio.md#Context), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/socketio.md#Context)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/socketio.md#Context), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # @midwayjs/static-file ## Index[**](#Index) ### Classes * [**Configuration](/api/static-file/class/Configuration.md) * [**DirectoryNotFoundError](/api/static-file/class/DirectoryNotFoundError.md) * [**StaticMiddleware](/api/static-file/class/StaticMiddleware.md) ### Interfaces * [**StaticFileOption](/api/static-file/interface/StaticFileOption.md) * [**StaticFileOptions](/api/static-file/interface/StaticFileOptions.md) ### Variables * [**StaticFileErrorEnum](/api/static-file.md#StaticFileErrorEnum) ## Variables[**](#Variables) ### [**](#StaticFileErrorEnum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/error.ts#L3)constStaticFileErrorEnum **StaticFileErrorEnum: ConvertString<{ DIRECTORY\_NOT\_EXISTS: 10000 }, static\_file> = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onConfigLoad](#onConfigLoad) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [StaticFileConfiguration](/api/static-file/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/configuration.ts#L20)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onConfigLoad)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/configuration.ts#L22)onConfigLoad * **onConfigLoad(): Promise<{ staticFile: { buffer: boolean } }> ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/configuration.ts#L32)onReady * **onReady(container: IMidwayContainer): Promise\ --- # DirectoryNotFoundError ### Hierarchy * MidwayError * *DirectoryNotFoundError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/error.ts#L8)constructor * **new DirectoryNotFoundError(p: string): [DirectoryNotFoundError](/api/static-file/class/DirectoryNotFoundError.md) - Overrides MidwayError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayError.code --- # StaticMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**environmentService](#environmentService) * [**logger](#logger) * [**middlewareService](#middlewareService) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new StaticMiddleware(): [StaticMiddleware](/api/static-file/class/StaticMiddleware.md) ## Properties[**](#Properties) ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/middleware/static.middleware.ts#L27)environmentService **environmentService: MidwayEnvironmentService ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/middleware/static.middleware.ts#L30)logger **logger: any ### [**](#middlewareService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/middleware/static.middleware.ts#L24)middlewareService **middlewareService: MidwayMiddlewareService\ ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/middleware/static.middleware.ts#L32)resolve * **resolve(app: any): Promise<{ \_name: string }> ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/middleware/static.middleware.ts#L89)staticgetName * **getName(): string --- # StaticFileOption ## Index[**](#Index) ### Properties * [**alias](#alias) * [**buffer](#buffer) * [**cacheControl](#cacheControl) * [**dir](#dir) * [**dynamic](#dynamic) * [**filter](#filter) * [**gzip](#gzip) * [**maxAge](#maxAge) * [**maxFiles](#maxFiles) * [**prefix](#prefix) * [**preload](#preload) ## Properties[**](#Properties) ### [**](#alias)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L41)optionalalias **alias? : {} object map of aliases ### [**](#buffer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L21)optionalbuffer **buffer? : boolean store the files in memory instead of streaming from the filesystem on each request. ### [**](#cacheControl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L33)optionalcacheControl **cacheControl? : string optional cache control header. Overrides options.maxAge. ### [**](#dir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L9)optionaldir **dir? : string the directory you wish to serve ### [**](#dynamic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L13)optionaldynamic **dynamic? : boolean dynamic load file which not cached on initialization. ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L47)optionalfilter **filter? : string\[] | (...args: any\[]) => any filter files at init dir, for example - skip non build (source) files. If array set - allow only listed files ### [**](#gzip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L37)optionalgzip **gzip? : boolean when request's accept-encoding include gzip, files will compressed by gzip. ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L29)optionalmaxAge **maxAge? : number cache control max age for the files, 0 by default. ### [**](#maxFiles)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L25)optionalmaxFiles **maxFiles? : number cache control max age for the files, 0 by default. ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L5)optionalprefix **prefix? : string url prefix ### [**](#preload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L17)optionalpreload **preload? : boolean caches the assets on initialization or not, default to true. always work together with options.dynamic. --- # StaticFileOptions ### Hierarchy * Omit<[StaticFileOption](/api/static-file/interface/StaticFileOption.md), prefix | dir> * *StaticFileOptions* ## Index[**](#Index) ### Properties * [**alias](#alias) * [**buffer](#buffer) * [**cacheControl](#cacheControl) * [**dirs](#dirs) * [**dynamic](#dynamic) * [**filter](#filter) * [**gzip](#gzip) * [**maxAge](#maxAge) * [**maxFiles](#maxFiles) * [**preload](#preload) ## Properties[**](#Properties) ### [**](#alias)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L41)optionalalias **alias? : {} Inherited from Omit.alias object map of aliases ### [**](#buffer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L21)optionalbuffer **buffer? : boolean Inherited from Omit.buffer store the files in memory instead of streaming from the filesystem on each request. ### [**](#cacheControl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L33)optionalcacheControl **cacheControl? : string Inherited from Omit.cacheControl optional cache control header. Overrides options.maxAge. ### [**](#dirs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L54)optionaldirs **dirs? : {} ### [**](#dynamic)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L13)optionaldynamic **dynamic? : boolean Inherited from Omit.dynamic dynamic load file which not cached on initialization. ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L47)optionalfilter **filter? : string\[] | (...args: any\[]) => any Inherited from Omit.filter filter files at init dir, for example - skip non build (source) files. If array set - allow only listed files ### [**](#gzip)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L37)optionalgzip **gzip? : boolean Inherited from Omit.gzip when request's accept-encoding include gzip, files will compressed by gzip. ### [**](#maxAge)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L29)optionalmaxAge **maxAge? : number Inherited from Omit.maxAge cache control max age for the files, 0 by default. ### [**](#maxFiles)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L25)optionalmaxFiles **maxFiles? : number Inherited from Omit.maxFiles cache control max age for the files, 0 by default. ### [**](#preload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/static-file/src/interface.ts#L17)optionalpreload **preload? : boolean Inherited from Omit.preload caches the assets on initialization or not, default to true. always work together with options.dynamic. --- # @midwayjs/swagger ## Index[**](#Index) ### Classes * [**Configuration](/api/swagger/class/Configuration.md) * [**SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md) * [**SwaggerMiddleware](/api/swagger/class/SwaggerMiddleware.md) ### Enumerations * [**BodyContentType](/api/swagger/enum/BodyContentType.md) ### Functions * [**ApiAcceptedResponse](/api/swagger/function/ApiAcceptedResponse.md) * [**ApiBadGatewayResponse](/api/swagger/function/ApiBadGatewayResponse.md) * [**ApiBadRequestResponse](/api/swagger/function/ApiBadRequestResponse.md) * [**ApiBasicAuth](/api/swagger/function/ApiBasicAuth.md) * [**ApiBearerAuth](/api/swagger/function/ApiBearerAuth.md) * [**ApiBody](/api/swagger/function/ApiBody.md) * [**ApiConflictResponse](/api/swagger/function/ApiConflictResponse.md) * [**ApiCookieAuth](/api/swagger/function/ApiCookieAuth.md) * [**ApiCreatedResponse](/api/swagger/function/ApiCreatedResponse.md) * [**ApiDefaultResponse](/api/swagger/function/ApiDefaultResponse.md) * [**ApiExcludeController](/api/swagger/function/ApiExcludeController.md) * [**ApiExcludeEndpoint](/api/swagger/function/ApiExcludeEndpoint.md) * [**ApiExcludeSecurity](/api/swagger/function/ApiExcludeSecurity.md) * [**ApiExtension](/api/swagger/function/ApiExtension.md) * [**ApiExtraModel](/api/swagger/function/ApiExtraModel.md) * [**ApiForbiddenResponse](/api/swagger/function/ApiForbiddenResponse.md) * [**ApiFoundResponse](/api/swagger/function/ApiFoundResponse.md) * [**ApiGatewayTimeoutResponse](/api/swagger/function/ApiGatewayTimeoutResponse.md) * [**ApiGoneResponse](/api/swagger/function/ApiGoneResponse.md) * [**ApiHeader](/api/swagger/function/ApiHeader.md) * [**ApiHeaders](/api/swagger/function/ApiHeaders.md) * [**ApiInternalServerErrorResponse](/api/swagger/function/ApiInternalServerErrorResponse.md) * [**ApiMethodNotAllowedResponse](/api/swagger/function/ApiMethodNotAllowedResponse.md) * [**ApiMovedPermanentlyResponse](/api/swagger/function/ApiMovedPermanentlyResponse.md) * [**ApiNoContentResponse](/api/swagger/function/ApiNoContentResponse.md) * [**ApiNotAcceptableResponse](/api/swagger/function/ApiNotAcceptableResponse.md) * [**ApiNotFoundResponse](/api/swagger/function/ApiNotFoundResponse.md) * [**ApiNotImplementedResponse](/api/swagger/function/ApiNotImplementedResponse.md) * [**ApiOAuth2](/api/swagger/function/ApiOAuth2.md) * [**ApiOkResponse](/api/swagger/function/ApiOkResponse.md) * [**ApiOperation](/api/swagger/function/ApiOperation.md) * [**ApiParam](/api/swagger/function/ApiParam.md) * [**ApiPayloadTooLargeResponse](/api/swagger/function/ApiPayloadTooLargeResponse.md) * [**ApiPreconditionFailedResponse](/api/swagger/function/ApiPreconditionFailedResponse.md) * [**ApiProperty](/api/swagger/function/ApiProperty.md) * [**ApiPropertyOptional](/api/swagger/function/ApiPropertyOptional.md) * [**ApiQuery](/api/swagger/function/ApiQuery.md) * [**ApiRequestTimeoutResponse](/api/swagger/function/ApiRequestTimeoutResponse.md) * [**ApiResponse](/api/swagger/function/ApiResponse.md) * [**ApiResponseProperty](/api/swagger/function/ApiResponseProperty.md) * [**ApiSecurity](/api/swagger/function/ApiSecurity.md) * [**ApiServiceUnavailableResponse](/api/swagger/function/ApiServiceUnavailableResponse.md) * [**ApiTags](/api/swagger/function/ApiTags.md) * [**ApiTooManyRequestsResponse](/api/swagger/function/ApiTooManyRequestsResponse.md) * [**ApiUnauthorizedResponse](/api/swagger/function/ApiUnauthorizedResponse.md) * [**ApiUnprocessableEntityResponse](/api/swagger/function/ApiUnprocessableEntityResponse.md) * [**ApiUnsupportedMediaTypeResponse](/api/swagger/function/ApiUnsupportedMediaTypeResponse.md) * [**getSchemaPath](/api/swagger/function/getSchemaPath.md) * [**renderJSON](/api/swagger/function/renderJSON.md) * [**renderSwaggerUIDist](/api/swagger/function/renderSwaggerUIDist.md) * [**renderSwaggerUIRemote](/api/swagger/function/renderSwaggerUIRemote.md) ### Interfaces * [**ApiHeaderOptions](/api/swagger/interface/ApiHeaderOptions.md) * [**ApiPropertyOptions](/api/swagger/interface/ApiPropertyOptions.md) * [**ApiResponseMetadata](/api/swagger/interface/ApiResponseMetadata.md) * [**ApiResponseSchemaHost](/api/swagger/interface/ApiResponseSchemaHost.md) * [**AuthOptions](/api/swagger/interface/AuthOptions.md) * [**BaseParameterObject](/api/swagger/interface/BaseParameterObject.md) * [**ComponentsObject](/api/swagger/interface/ComponentsObject.md) * [**ContactObject](/api/swagger/interface/ContactObject.md) * [**DiscriminatorObject](/api/swagger/interface/DiscriminatorObject.md) * [**EncodingPropertyObject](/api/swagger/interface/EncodingPropertyObject.md) * [**ExampleObject](/api/swagger/interface/ExampleObject.md) * [**ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) * [**InfoObject](/api/swagger/interface/InfoObject.md) * [**LicenseObject](/api/swagger/interface/LicenseObject.md) * [**LinkObject](/api/swagger/interface/LinkObject.md) * [**MediaTypeObject](/api/swagger/interface/MediaTypeObject.md) * [**MixDecoratorMetadata](/api/swagger/interface/MixDecoratorMetadata.md) * [**OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) * [**OAuthFlowsObject](/api/swagger/interface/OAuthFlowsObject.md) * [**OpenAPIObject](/api/swagger/interface/OpenAPIObject.md) * [**OperationObject](/api/swagger/interface/OperationObject.md) * [**ParameterObject](/api/swagger/interface/ParameterObject.md) * [**PathItemObject](/api/swagger/interface/PathItemObject.md) * [**ReferenceObject](/api/swagger/interface/ReferenceObject.md) * [**RequestBodyObject](/api/swagger/interface/RequestBodyObject.md) * [**ResponseObject](/api/swagger/interface/ResponseObject.md) * [**ResponsesObject](/api/swagger/interface/ResponsesObject.md) * [**SchemaObject](/api/swagger/interface/SchemaObject.md) * [**SchemaObjectMetadata](/api/swagger/interface/SchemaObjectMetadata.md) * [**SecuritySchemeObject](/api/swagger/interface/SecuritySchemeObject.md) * [**ServerObject](/api/swagger/interface/ServerObject.md) * [**ServerVariableObject](/api/swagger/interface/ServerVariableObject.md) * [**SwaggerOptions](/api/swagger/interface/SwaggerOptions.md) * [**TagObject](/api/swagger/interface/TagObject.md) * [**Type](/api/swagger/interface/Type.md) * [**XmlObject](/api/swagger/interface/XmlObject.md) ### Type Aliases * [**ApiBodyOptions](/api/swagger.md#ApiBodyOptions) * [**ApiOperationOptions](/api/swagger.md#ApiOperationOptions) * [**ApiParamOptions](/api/swagger.md#ApiParamOptions) * [**ApiQueryOptions](/api/swagger.md#ApiQueryOptions) * [**ApiResponseOptions](/api/swagger.md#ApiResponseOptions) * [**AuthType](/api/swagger.md#AuthType) * [**CallbackObject](/api/swagger.md#CallbackObject) * [**CallbacksObject](/api/swagger.md#CallbacksObject) * [**ContentObject](/api/swagger.md#ContentObject) * [**EncodingObject](/api/swagger.md#EncodingObject) * [**ExamplesObject](/api/swagger.md#ExamplesObject) * [**HeaderObject](/api/swagger.md#HeaderObject) * [**HeadersObject](/api/swagger.md#HeadersObject) * [**LinkParametersObject](/api/swagger.md#LinkParametersObject) * [**LinksObject](/api/swagger.md#LinksObject) * [**ParameterLocation](/api/swagger.md#ParameterLocation) * [**ParameterStyle](/api/swagger.md#ParameterStyle) * [**PathsObject](/api/swagger.md#PathsObject) * [**SchemasObject](/api/swagger.md#SchemasObject) * [**ScopesObject](/api/swagger.md#ScopesObject) * [**SecurityRequirementObject](/api/swagger.md#SecurityRequirementObject) * [**SecuritySchemeType](/api/swagger.md#SecuritySchemeType) * [**SwaggerEnumType](/api/swagger.md#SwaggerEnumType) ### Variables * [**DECORATORS](/api/swagger.md#DECORATORS) * [**DECORATORS\_CLASS\_METADATA](/api/swagger.md#DECORATORS_CLASS_METADATA) * [**DECORATORS\_METHOD\_METADATA](/api/swagger.md#DECORATORS_METHOD_METADATA) * [**DECORATORS\_PREFIX](/api/swagger.md#DECORATORS_PREFIX) ## Type Aliases[**](<#Type Aliases>) ### [**](#ApiBodyOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L40)ApiBodyOptions **ApiBodyOptions: ApiBodyMetadata | ApiBodySchemaHost ### [**](#ApiOperationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-operation.decorator.ts#L5)ApiOperationOptions **ApiOperationOptions: Partial<[OperationObject](/api/swagger/interface/OperationObject.md)> ### [**](#ApiParamOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-param.decorator.ts#L23)ApiParamOptions **ApiParamOptions: ApiParamMetadata | ApiParamSchemaHost ### [**](#ApiQueryOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-query.decorator.ts#L31)ApiQueryOptions **ApiQueryOptions: ApiQueryMetadata | ApiQuerySchemaHost ### [**](#ApiResponseOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L30)ApiResponseOptions **ApiResponseOptions: [ApiResponseMetadata](/api/swagger/interface/ApiResponseMetadata.md) | [ApiResponseSchemaHost](/api/swagger/interface/ApiResponseSchemaHost.md) ### [**](#AuthType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L311)AuthType **AuthType: basic | bearer | cookie | oauth2 | apikey | custom ### [**](#CallbackObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L168)CallbackObject **CallbackObject: Record\ ### [**](#CallbacksObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L167)CallbacksObject **CallbacksObject: Record\ ### [**](#ContentObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L136)ContentObject **ContentObject: Record\ ### [**](#EncodingObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L144)EncodingObject **EncodingObject: Record\ ### [**](#ExamplesObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L196)ExamplesObject **ExamplesObject: Record\ ### [**](#HeaderObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L189)HeaderObject **HeaderObject: [BaseParameterObject](/api/swagger/interface/BaseParameterObject.md) ### [**](#HeadersObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L169)HeadersObject **HeadersObject: Record\ ### [**](#LinkParametersObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L188)LinkParametersObject **LinkParametersObject: Record\ ### [**](#LinksObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L178)LinksObject **LinksObject: Record\ ### [**](#ParameterLocation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L101)ParameterLocation **ParameterLocation: query | header | path | cookie ### [**](#ParameterStyle)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L102)ParameterStyle **ParameterStyle: matrix | label | form | simple | spaceDelimited | pipeDelimited | deepObject ### [**](#PathsObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L64)PathsObject **PathsObject: Record\ ### [**](#SchemasObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L242)SchemasObject **SchemasObject: Record\ ### [**](#ScopesObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L284)ScopesObject **ScopesObject: Record\ ### [**](#SecurityRequirementObject)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L285)SecurityRequirementObject **SecurityRequirementObject: Record\ ### [**](#SecuritySchemeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L257)SecuritySchemeType **SecuritySchemeType: apiKey | http | oauth2 | openIdConnect ### [**](#SwaggerEnumType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L290)SwaggerEnumType **SwaggerEnumType: string\[] | number\[] | (string | number)\[] | Record\ 非 open api spec ## Variables[**](#Variables) ### [**](#DECORATORS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/constants.ts#L6)constDECORATORS **DECORATORS: { API\_EXCLUDE\_CONTROLLER: string; API\_EXCLUDE\_ENDPOINT: string; API\_EXCLUDE\_SECURITY: string; API\_EXTENSION: string; API\_EXTRA\_MODEL: string; API\_HEADERS: string; API\_MODEL\_PROPERTIES: string; API\_MODEL\_PROPERTIES\_ARRAY: string; API\_OPERATION: string; API\_PARAMETERS: string; API\_RESPONSE: string; API\_SECURITY: string; API\_TAGS: string } = ... ### [**](#DECORATORS_CLASS_METADATA)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/constants.ts#L3)constDECORATORS\_CLASS\_METADATA **DECORATORS\_CLASS\_METADATA: swagger:class\_metadata = 'swagger:class\_metadata' ### [**](#DECORATORS_METHOD_METADATA)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/constants.ts#L4)constDECORATORS\_METHOD\_METADATA **DECORATORS\_METHOD\_METADATA: swagger:method\_metadata = 'swagger:method\_metadata' ### [**](#DECORATORS_PREFIX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/constants.ts#L1)constDECORATORS\_PREFIX **DECORATORS\_PREFIX: swagger = 'swagger' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**configService](#configService) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [SwaggerConfiguration](/api/swagger/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/configuration.ts#L22)applicationManager **applicationManager: MidwayApplicationManager ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/configuration.ts#L25)configService **configService: MidwayConfigService ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/configuration.ts#L27)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady --- # SwaggerExplorer ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addGlobalPrefix](#addGlobalPrefix) * [**getData](#getData) * [**getDocumentBuilder](#getDocumentBuilder) * [**getOperationId](#getOperationId) * [**init](#init) * [**scanApp](#scanApp) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SwaggerExplorer(): [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md) ## Methods[**](#Methods) ### [**](#addGlobalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L128)publicaddGlobalPrefix * **addGlobalPrefix(globalPrefix: string): void ### [**](#getData)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L159)publicgetData * **getData(): Omit<[OpenAPIObject](/api/swagger/interface/OpenAPIObject.md), paths> ### [**](#getDocumentBuilder)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L163)publicgetDocumentBuilder * **getDocumentBuilder(): DocumentBuilder ### [**](#getOperationId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L860)getOperationId * **getOperationId(controllerKey: string, webRouter: RouterOption): string ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L60)init * **init(): Promise\ ### [**](#scanApp)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerExplorer.ts#L147)publicscanApp * **scanApp(): void --- # SwaggerMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**environmentService](#environmentService) ### Methods * [**init](#init) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SwaggerMiddleware(): [SwaggerMiddleware](/api/swagger/class/SwaggerMiddleware.md) ## Properties[**](#Properties) ### [**](#environmentService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerMiddleware.ts#L36)environmentService **environmentService: MidwayEnvironmentService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerMiddleware.ts#L39)init * **init(): Promise\ ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerMiddleware.ts#L49)resolve * **resolve(app: IMidwayBaseApplication\): (req: any, res: any, next: NextFunction) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/swaggerMiddleware.ts#L96)staticgetName * **getName(): string --- # BodyContentType ## Index[**](#Index) ### Enumeration Members * [**FormUrlEncoded](#FormUrlEncoded) * [**JSON](#JSON) * [**Multipart](#Multipart) * [**MultipartMixed](#MultipartMixed) * [**OctetStream](#OctetStream) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#FormUrlEncoded)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L20)FormUrlEncoded **FormUrlEncoded: application/x-www-form-urlencoded ### [**](#JSON)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L21)JSON **JSON: application/json ### [**](#Multipart)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L22)Multipart **Multipart: multipart/form-data ### [**](#MultipartMixed)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L23)MultipartMixed **MultipartMixed: multipart/mixed ### [**](#OctetStream)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-body.decorator.ts#L24)OctetStream **OctetStream: application/octet-stream --- # ApiAcceptedResponse ### Callable * **ApiAcceptedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiBadGatewayResponse ### Callable * **ApiBadGatewayResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiBadRequestResponse ### Callable * **ApiBadRequestResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiBasicAuth ### Callable * **ApiBasicAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiBearerAuth ### Callable * **ApiBearerAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiBody ### Callable * **ApiBody(options: [ApiBodyOptions](/api/swagger.md#ApiBodyOptions)): MethodDecorator --- # ApiConflictResponse ### Callable * **ApiConflictResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiCookieAuth ### Callable * **ApiCookieAuth(name? : string): ClassDecorator & MethodDecorator --- # ApiCreatedResponse ### Callable * **ApiCreatedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiDefaultResponse ### Callable * **ApiDefaultResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiExcludeController ### Callable * **ApiExcludeController(disable? : boolean): ClassDecorator --- # ApiExcludeEndpoint ### Callable * **ApiExcludeEndpoint(disable? : boolean): MethodDecorator --- # ApiExcludeSecurity ### Callable * **ApiExcludeSecurity(): ClassDecorator & MethodDecorator --- # ApiExtension ### Callable * **ApiExtension(extensionKey: string, extensionProperties: any): ClassDecorator & MethodDecorator --- # ApiExtraModel ### Callable * **ApiExtraModel(models: [Type](/api/swagger/interface/Type.md)\ | [Type](/api/swagger/interface/Type.md)\\[]): ClassDecorator --- # ApiForbiddenResponse ### Callable * **ApiForbiddenResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiFoundResponse ### Callable * **ApiFoundResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiGatewayTimeoutResponse ### Callable * **ApiGatewayTimeoutResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiGoneResponse ### Callable * **ApiGoneResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiHeader ### Callable * **ApiHeader(options: [ApiHeaderOptions](/api/swagger/interface/ApiHeaderOptions.md)): any --- # ApiHeaders ### Callable * **ApiHeaders(headers: [ApiHeaderOptions](/api/swagger/interface/ApiHeaderOptions.md)\[]): MethodDecorator & ClassDecorator --- # ApiInternalServerErrorResponse ### Callable * **ApiInternalServerErrorResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiMethodNotAllowedResponse ### Callable * **ApiMethodNotAllowedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiMovedPermanentlyResponse ### Callable * **ApiMovedPermanentlyResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiNoContentResponse ### Callable * **ApiNoContentResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiNotAcceptableResponse ### Callable * **ApiNotAcceptableResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiNotFoundResponse ### Callable * **ApiNotFoundResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiNotImplementedResponse ### Callable * **ApiNotImplementedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiOAuth2 ### Callable * **ApiOAuth2(scopes: string\[], name? : string): ClassDecorator & MethodDecorator --- # ApiOkResponse ### Callable * **ApiOkResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiOperation ### Callable * **ApiOperation(options: Partial<[OperationObject](/api/swagger/interface/OperationObject.md)>): MethodDecorator --- # ApiParam ### Callable * **ApiParam(options: [ApiParamOptions](/api/swagger.md#ApiParamOptions)): MethodDecorator --- # ApiPayloadTooLargeResponse ### Callable * **ApiPayloadTooLargeResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiPreconditionFailedResponse ### Callable * **ApiPreconditionFailedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiProperty ### Callable * **ApiProperty(options? : [ApiPropertyOptions](/api/swagger/interface/ApiPropertyOptions.md)): PropertyDecorator --- # ApiPropertyOptional ### Callable * **ApiPropertyOptional(options? : [ApiPropertyOptions](/api/swagger/interface/ApiPropertyOptions.md)): PropertyDecorator --- # ApiQuery ### Callable * **ApiQuery(options: [ApiQueryOptions](/api/swagger.md#ApiQueryOptions)): MethodDecorator --- # ApiRequestTimeoutResponse ### Callable * **ApiRequestTimeoutResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiResponse ### Callable * **ApiResponse(options: [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiResponseProperty ### Callable * **ApiResponseProperty(options? : Pick<[ApiPropertyOptions](/api/swagger/interface/ApiPropertyOptions.md), type | enum | example | deprecated | format>): PropertyDecorator --- # ApiSecurity ### Callable * **ApiSecurity(name: string | [SecurityRequirementObject](/api/swagger.md#SecurityRequirementObject), requirements? : string\[]): ClassDecorator & MethodDecorator --- # ApiServiceUnavailableResponse ### Callable * **ApiServiceUnavailableResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiTags ### Callable * **ApiTags(tags: string | string\[]): ClassDecorator & MethodDecorator --- # ApiTooManyRequestsResponse ### Callable * **ApiTooManyRequestsResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiUnauthorizedResponse ### Callable * **ApiUnauthorizedResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiUnprocessableEntityResponse ### Callable * **ApiUnprocessableEntityResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # ApiUnsupportedMediaTypeResponse ### Callable * **ApiUnsupportedMediaTypeResponse(options? : [ApiResponseOptions](/api/swagger.md#ApiResponseOptions)): any --- # getSchemaPath ### Callable * **getSchemaPath(clzz: string | [Type](/api/swagger/interface/Type.md)\): string --- # renderJSON ### Callable * **renderJSON(swaggerConfig: [SwaggerOptions](/api/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: Omit<[OpenAPIObject](/api/swagger/interface/OpenAPIObject.md), paths>; ext: string }> --- # renderSwaggerUIDist ### Callable * **renderSwaggerUIDist(swaggerConfig: [SwaggerOptions](/api/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: any; ext: string }> --- # renderSwaggerUIRemote ### Callable * **renderSwaggerUIRemote(swaggerConfig: [SwaggerOptions](/api/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md)): (pathname: string) => Promise<{ content: Omit<[OpenAPIObject](/api/swagger/interface/OpenAPIObject.md), paths>; ext: string } | { content: string; ext: string }> --- # ApiHeaderOptions ### Hierarchy * Omit<[ParameterObject](/api/swagger/interface/ParameterObject.md), in> * *ApiHeaderOptions* ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**enum](#enum) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**name](#name) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean Inherited from Omit.allowEmptyValue ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean Inherited from Omit.allowReserved ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) Inherited from Omit.content ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string Inherited from Omit.description ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-header.decorator.ts#L7)optionalenum **enum? : [SwaggerEnumType](/api/swagger.md#SwaggerEnumType) ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ Inherited from Omit.examples ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean Inherited from Omit.explode ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L126)name **name: string Inherited from Omit.name ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean Inherited from Omit.required ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.schema ### [**](#style)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/swagger.md#ParameterStyle) Inherited from Omit.style --- # ApiPropertyOptions ### Hierarchy * Omit<[SchemaObjectMetadata](/api/swagger/interface/SchemaObjectMetadata.md), name | enum> * *ApiPropertyOptions* ## Index[**](#Index) ### Properties * [**$ref](#$ref) * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**enumName](#enumName) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**isArray](#isArray) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**name](#name) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-property.decorator.ts#L13)optional$ref **$ref? : string ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L219)optionaladditionalProperties **additionalProperties? : boolean | [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.additionalProperties ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L213)optionalallOf **allOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.allOf ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L215)optionalanyOf **anyOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.anyOf ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L223)optionaldefault **default? : any Inherited from Omit.default ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L211)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L221)optionaldescription **description? : string Inherited from Omit.description ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L204)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/swagger/interface/DiscriminatorObject.md) Inherited from Omit.discriminator ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-property.decorator.ts#L11)optionalenum **enum? : any\[] | Record\ ### [**](#enumName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-property.decorator.ts#L12)optionalenumName **enumName? : string Overrides Omit.enumName ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L209)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L210)optionalexamples **examples? : any\[] | Record\ Inherited from Omit.examples ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMaximum **exclusiveMaximum? : boolean Inherited from Omit.exclusiveMaximum ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L229)optionalexclusiveMinimum **exclusiveMinimum? : boolean Inherited from Omit.exclusiveMinimum ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L208)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) Inherited from Omit.externalDocs ### [**](#format)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L222)optionalformat **format? : string Inherited from Omit.format ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L305)optionalisArray **isArray? : boolean Inherited from Omit.isArray ### [**](#items)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L217)optionalitems **items? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.items ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L233)optionalmaxItems **maxItems? : number Inherited from Omit.maxItems ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L230)optionalmaxLength **maxLength? : number Inherited from Omit.maxLength ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L236)optionalmaxProperties **maxProperties? : number Inherited from Omit.maxProperties ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L226)optionalmaximum **maximum? : number Inherited from Omit.maximum ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L234)optionalminItems **minItems? : number Inherited from Omit.minItems ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L231)optionalminLength **minLength? : number Inherited from Omit.minLength ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L237)optionalminProperties **minProperties? : number Inherited from Omit.minProperties ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L228)optionalminimum **minimum? : number Inherited from Omit.minimum ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L225)optionalmultipleOf **multipleOf? : number Inherited from Omit.multipleOf ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-property.decorator.ts#L10)optionalname **name? : string ### [**](#not)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L216)optionalnot **not? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.not ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L203)optionalnullable **nullable? : boolean Inherited from Omit.nullable ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L214)optionaloneOf **oneOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.oneOf ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L232)optionalpattern **pattern? : string Inherited from Omit.pattern ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L220)optionalpatternProperties **patternProperties? : any Inherited from Omit.patternProperties ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L218)optionalproperties **properties? : Record\ Inherited from Omit.properties ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L205)optionalreadOnly **readOnly? : boolean Inherited from Omit.readOnly ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L306)optionalrequired **required? : boolean Inherited from Omit.required ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L224)optionaltitle **title? : string Inherited from Omit.title ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L304)optionaltype **type? : string | Record\ | [Type](/api/swagger/interface/Type.md)\ | \[[Type](/api/swagger/interface/Type.md)\] Inherited from Omit.type ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L235)optionaluniqueItems **uniqueItems? : boolean Inherited from Omit.uniqueItems ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L206)optionalwriteOnly **writeOnly? : boolean Inherited from Omit.writeOnly ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L207)optionalxml **xml? : [XmlObject](/api/swagger/interface/XmlObject.md) Inherited from Omit.xml --- # ApiResponseMetadata ### Hierarchy * Omit<[ResponseObject](/api/swagger/interface/ResponseObject.md), description> * *ApiResponseMetadata* ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**isArray](#isArray) * [**links](#links) * [**status](#status) * [**type](#type) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L163)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) Inherited from Omit.content ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L18)optionaldescription **description? : string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L162)optionalheaders **headers? : [HeadersObject](/api/swagger.md#HeadersObject) Inherited from Omit.headers ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L17)optionalisArray **isArray? : boolean ### [**](#links)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L164)optionallinks **links? : [LinksObject](/api/swagger.md#LinksObject) Inherited from Omit.links ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L15)optionalstatus **status? : number | default ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L16)optionaltype **type? : string | Record\ | [Type](/api/swagger/interface/Type.md)\ --- # ApiResponseSchemaHost ### Hierarchy * Omit<[ResponseObject](/api/swagger/interface/ResponseObject.md), description> * *ApiResponseSchemaHost* ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**links](#links) * [**schema](#schema) * [**status](#status) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L163)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) Inherited from Omit.content ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L27)optionaldescription **description? : string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L162)optionalheaders **headers? : [HeadersObject](/api/swagger.md#HeadersObject) Inherited from Omit.headers ### [**](#links)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L164)optionallinks **links? : [LinksObject](/api/swagger.md#LinksObject) Inherited from Omit.links ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L25)schema **schema: [SchemaObject](/api/swagger/interface/SchemaObject.md) & Partial<[ReferenceObject](/api/swagger/interface/ReferenceObject.md)> ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/decorators/api-response.decorator.ts#L26)optionalstatus **status? : number --- # AuthOptions 继承自 ### Hierarchy * Omit<[SecuritySchemeObject](/api/swagger/interface/SecuritySchemeObject.md), type> * *AuthOptions* ## Index[**](#Index) ### Properties * [**addSecurityRequirements](#addSecurityRequirements) * [**authType](#authType) * [**bearerFormat](#bearerFormat) * [**cookieName](#cookieName) * [**description](#description) * [**flows](#flows) * [**in](#in) * [**name](#name) * [**openIdConnectUrl](#openIdConnectUrl) * [**scheme](#scheme) * [**securityName](#securityName) * [**type](#type) ## Properties[**](#Properties) ### [**](#addSecurityRequirements)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L348)optionaladdSecurityRequirements **addSecurityRequirements? : boolean 添加全局默认要求 ### [**](#authType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L332)authType **authType: [AuthType](/api/swagger.md#AuthType) 验权类型 basic => http basic 验证 bearer => http jwt 验证 cookie => cookie 方式验证 oauth2 => 使用 oauth2 apikey => apiKey custom => 自定义方式 ### [**](#bearerFormat)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L265)optionalbearerFormat **bearerFormat? : string Inherited from Omit.bearerFormat ### [**](#cookieName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L344)optionalcookieName **cookieName? : string authType = cookie 时可以修改,cookie 的名称 ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L261)optionaldescription **description? : string Inherited from Omit.description ### [**](#flows)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L266)optionalflows **flows? : [OAuthFlowsObject](/api/swagger/interface/OAuthFlowsObject.md) Inherited from Omit.flows ### [**](#in)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L263)optionalin **in? : string Inherited from Omit.in ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L262)optionalname **name? : string Inherited from Omit.name ### [**](#openIdConnectUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L267)optionalopenIdConnectUrl **openIdConnectUrl? : string Inherited from Omit.openIdConnectUrl ### [**](#scheme)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L264)optionalscheme **scheme? : string Inherited from Omit.scheme ### [**](#securityName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L340)optionalsecurityName **securityName? : string authType = cookie 时可以修改,通过 ApiCookie 装饰器关联的名称 ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L336)optionaltype **type? : [SecuritySchemeType](/api/swagger.md#SecuritySchemeType) type 字段 --- # BaseParameterObject ### Hierarchy * *BaseParameterObject* * [ParameterObject](/api/swagger/interface/ParameterObject.md) ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) ### [**](#style)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/swagger.md#ParameterStyle) --- # ComponentsObject ## Index[**](#Index) ### Properties * [**callbacks](#callbacks) * [**examples](#examples) * [**headers](#headers) * [**links](#links) * [**parameters](#parameters) * [**requestBodies](#requestBodies) * [**responses](#responses) * [**schemas](#schemas) * [**securitySchemes](#securitySchemes) ## Properties[**](#Properties) ### [**](#callbacks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L61)optionalcallbacks **callbacks? : Record\ ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L56)optionalexamples **examples? : Record\ ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L58)optionalheaders **headers? : Record\ ### [**](#links)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L60)optionallinks **links? : Record\ ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L55)optionalparameters **parameters? : Record\ ### [**](#requestBodies)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L57)optionalrequestBodies **requestBodies? : Record\ ### [**](#responses)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L54)optionalresponses **responses? : Record\ ### [**](#schemas)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L53)optionalschemas **schemas? : Record\ ### [**](#securitySchemes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L59)optionalsecuritySchemes **securitySchemes? : Record\ --- # ContactObject ## Index[**](#Index) ### Properties * [**email](#email) * [**name](#name) * [**url](#url) ## Properties[**](#Properties) ### [**](#email)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L32)optionalemail **email? : string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L30)optionalname **name? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L31)optionalurl **url? : string --- # DiscriminatorObject ## Index[**](#Index) ### Properties * [**mapping](#mapping) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#mapping)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L246)optionalmapping **mapping? : Record\ ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L245)propertyName **propertyName: string --- # EncodingPropertyObject ## Index[**](#Index) ### Properties * [**allowReserved](#allowReserved) * [**contentType](#contentType) * [**explode](#explode) * [**headers](#headers) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L150)optionalallowReserved **allowReserved? : boolean ### [**](#contentType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L146)optionalcontentType **contentType? : string ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L149)optionalexplode **explode? : boolean ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L147)optionalheaders **headers? : Record\ ### [**](#style)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L148)optionalstyle **style? : string --- # ExampleObject ## Index[**](#Index) ### Properties * [**description](#description) * [**externalValue](#externalValue) * [**summary](#summary) * [**value](#value) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L173)optionaldescription **description? : string ### [**](#externalValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L175)optionalexternalValue **externalValue? : string ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L172)optionalsummary **summary? : string ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L174)optionalvalue **value? : any --- # ExternalDocumentationObject ## Index[**](#Index) ### Properties * [**description](#description) * [**url](#url) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L97)optionaldescription **description? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L98)url **url: string --- # InfoObject ## Index[**](#Index) ### Properties * [**contact](#contact) * [**description](#description) * [**license](#license) * [**termsOfService](#termsOfService) * [**title](#title) * [**version](#version) ## Properties[**](#Properties) ### [**](#contact)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L24)optionalcontact **contact? : [ContactObject](/api/swagger/interface/ContactObject.md) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L22)optionaldescription **description? : string ### [**](#license)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L25)optionallicense **license? : [LicenseObject](/api/swagger/interface/LicenseObject.md) ### [**](#termsOfService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L23)optionaltermsOfService **termsOfService? : string ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L21)title **title: string ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L26)version **version: string --- # LicenseObject ## Index[**](#Index) ### Properties * [**name](#name) * [**url](#url) ## Properties[**](#Properties) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L36)name **name: string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L37)optionalurl **url? : string --- # LinkObject ## Index[**](#Index) ### Properties * [**description](#description) * [**operationId](#operationId) * [**operationRef](#operationRef) * [**parameters](#parameters) * [**requestBody](#requestBody) * [**server](#server) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L184)optionaldescription **description? : string ### [**](#operationId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L181)optionaloperationId **operationId? : string ### [**](#operationRef)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L180)optionaloperationRef **operationRef? : string ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L182)optionalparameters **parameters? : [LinkParametersObject](/api/swagger.md#LinkParametersObject) ### [**](#requestBody)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L183)optionalrequestBody **requestBody? : any ### [**](#server)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L185)optionalserver **server? : [ServerObject](/api/swagger/interface/ServerObject.md) --- # MediaTypeObject ## Index[**](#Index) ### Properties * [**encoding](#encoding) * [**example](#example) * [**examples](#examples) * [**schema](#schema) ## Properties[**](#Properties) ### [**](#encoding)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L141)optionalencoding **encoding? : [EncodingObject](/api/swagger.md#EncodingObject) ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L140)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L139)optionalexamples **examples? : [ExamplesObject](/api/swagger.md#ExamplesObject) ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L138)optionalschema **schema? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) --- # MixDecoratorMetadata ## Index[**](#Index) ### Properties * [**key](#key) * [**metadata](#metadata) * [**propertyName](#propertyName) ## Properties[**](#Properties) ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L461)key **key: string ### [**](#metadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L462)metadata **metadata: any ### [**](#propertyName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L463)optionalpropertyName **propertyName? : string --- # OAuthFlowObject ## Index[**](#Index) ### Properties * [**authorizationUrl](#authorizationUrl) * [**refreshUrl](#refreshUrl) * [**scopes](#scopes) * [**tokenUrl](#tokenUrl) ## Properties[**](#Properties) ### [**](#authorizationUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L278)optionalauthorizationUrl **authorizationUrl? : string ### [**](#refreshUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L280)optionalrefreshUrl **refreshUrl? : string ### [**](#scopes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L281)scopes **scopes: [ScopesObject](/api/swagger.md#ScopesObject) ### [**](#tokenUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L279)optionaltokenUrl **tokenUrl? : string --- # OAuthFlowsObject ## Index[**](#Index) ### Properties * [**authorizationCode](#authorizationCode) * [**clientCredentials](#clientCredentials) * [**implicit](#implicit) * [**password](#password) ## Properties[**](#Properties) ### [**](#authorizationCode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L274)optionalauthorizationCode **authorizationCode? : [OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) ### [**](#clientCredentials)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L273)optionalclientCredentials **clientCredentials? : [OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) ### [**](#implicit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L271)optionalimplicit **implicit? : [OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) ### [**](#password)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L272)optionalpassword **password? : [OAuthFlowObject](/api/swagger/interface/OAuthFlowObject.md) --- # OpenAPIObject ## Index[**](#Index) ### Properties * [**components](#components) * [**externalDocs](#externalDocs) * [**info](#info) * [**openapi](#openapi) * [**paths](#paths) * [**security](#security) * [**servers](#servers) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#components)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L14)optionalcomponents **components? : [ComponentsObject](/api/swagger/interface/ComponentsObject.md) ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L17)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) ### [**](#info)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L11)info **info: [InfoObject](/api/swagger/interface/InfoObject.md) ### [**](#openapi)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L10)openapi **openapi: string ### [**](#paths)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L13)paths **paths: [PathsObject](/api/swagger.md#PathsObject) ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L15)optionalsecurity **security? : [SecurityRequirementObject](/api/swagger.md#SecurityRequirementObject)\[] ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L12)optionalservers **servers? : [ServerObject](/api/swagger/interface/ServerObject.md)\[] ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L16)optionaltags **tags? : [TagObject](/api/swagger/interface/TagObject.md)\[] --- # OperationObject ## Index[**](#Index) ### Properties * [**callbacks](#callbacks) * [**deprecated](#deprecated) * [**description](#description) * [**externalDocs](#externalDocs) * [**operationId](#operationId) * [**parameters](#parameters) * [**requestBody](#requestBody) * [**responses](#responses) * [**security](#security) * [**servers](#servers) * [**summary](#summary) * [**tags](#tags) ## Properties[**](#Properties) ### [**](#callbacks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L90)optionalcallbacks **callbacks? : [CallbacksObject](/api/swagger.md#CallbacksObject) ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L91)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L84)optionaldescription **description? : string ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L85)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) ### [**](#operationId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L86)optionaloperationId **operationId? : string ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L87)optionalparameters **parameters? : ([ParameterObject](/api/swagger/interface/ParameterObject.md) | [ReferenceObject](/api/swagger/interface/ReferenceObject.md))\[] ### [**](#requestBody)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L88)optionalrequestBody **requestBody? : [RequestBodyObject](/api/swagger/interface/RequestBodyObject.md) | [ReferenceObject](/api/swagger/interface/ReferenceObject.md) ### [**](#responses)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L89)responses **responses: [ResponsesObject](/api/swagger/interface/ResponsesObject.md) ### [**](#security)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L92)optionalsecurity **security? : [SecurityRequirementObject](/api/swagger.md#SecurityRequirementObject)\[] ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L93)optionalservers **servers? : [ServerObject](/api/swagger/interface/ServerObject.md)\[] ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L83)optionalsummary **summary? : string ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L82)optionaltags **tags? : string\[] --- # ParameterObject ### Hierarchy * [BaseParameterObject](/api/swagger/interface/BaseParameterObject.md) * *ParameterObject* ## Index[**](#Index) ### Properties * [**allowEmptyValue](#allowEmptyValue) * [**allowReserved](#allowReserved) * [**content](#content) * [**deprecated](#deprecated) * [**description](#description) * [**example](#example) * [**examples](#examples) * [**explode](#explode) * [**in](#in) * [**name](#name) * [**required](#required) * [**schema](#schema) * [**style](#style) ## Properties[**](#Properties) ### [**](#allowEmptyValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L115)optionalallowEmptyValue **allowEmptyValue? : boolean Inherited from BaseParameterObject.allowEmptyValue ### [**](#allowReserved)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L118)optionalallowReserved **allowReserved? : boolean Inherited from BaseParameterObject.allowReserved ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L122)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) Inherited from BaseParameterObject.content ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L114)optionaldeprecated **deprecated? : boolean Inherited from BaseParameterObject.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L112)optionaldescription **description? : string Inherited from BaseParameterObject.description ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L121)optionalexample **example? : any Inherited from BaseParameterObject.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L120)optionalexamples **examples? : Record\ Inherited from BaseParameterObject.examples ### [**](#explode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L117)optionalexplode **explode? : boolean Inherited from BaseParameterObject.explode ### [**](#in)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L127)in **in: [ParameterLocation](/api/swagger.md#ParameterLocation) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L126)name **name: string ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L113)optionalrequired **required? : boolean Inherited from BaseParameterObject.required ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L119)optionalschema **schema? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from BaseParameterObject.schema ### [**](#style)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L116)optionalstyle **style? : [ParameterStyle](/api/swagger.md#ParameterStyle) Inherited from BaseParameterObject.style --- # PathItemObject ## Index[**](#Index) ### Properties * [**$ref](#$ref) * [**delete](#delete) * [**description](#description) * [**get](#get) * [**head](#head) * [**options](#options) * [**parameters](#parameters) * [**patch](#patch) * [**post](#post) * [**put](#put) * [**servers](#servers) * [**summary](#summary) * [**trace](#trace) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L66)optional$ref **$ref? : string ### [**](#delete)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L72)optionaldelete **delete? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L68)optionaldescription **description? : string ### [**](#get)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L69)optionalget **get? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#head)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L74)optionalhead **head? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#options)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L73)optionaloptions **options? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#parameters)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L78)optionalparameters **parameters? : ([ParameterObject](/api/swagger/interface/ParameterObject.md) | [ReferenceObject](/api/swagger/interface/ReferenceObject.md))\[] ### [**](#patch)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L75)optionalpatch **patch? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#post)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L71)optionalpost **post? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#put)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L70)optionalput **put? : [OperationObject](/api/swagger/interface/OperationObject.md) ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L77)optionalservers **servers? : [ServerObject](/api/swagger/interface/ServerObject.md)\[] ### [**](#summary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L67)optionalsummary **summary? : string ### [**](#trace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L76)optionaltrace **trace? : [OperationObject](/api/swagger/interface/OperationObject.md) --- # ReferenceObject ## Index[**](#Index) ### Properties * [**$ref](#$ref) ## Properties[**](#Properties) ### [**](#$ref)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L199)$ref **$ref: string | () => string --- # RequestBodyObject ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**required](#required) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L132)content **content: [ContentObject](/api/swagger.md#ContentObject) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L131)optionaldescription **description? : string ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L133)optionalrequired **required? : boolean --- # ResponseObject ## Index[**](#Index) ### Properties * [**content](#content) * [**description](#description) * [**headers](#headers) * [**links](#links) ## Properties[**](#Properties) ### [**](#content)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L163)optionalcontent **content? : [ContentObject](/api/swagger.md#ContentObject) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L161)description **description: string ### [**](#headers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L162)optionalheaders **headers? : [HeadersObject](/api/swagger.md#HeadersObject) ### [**](#links)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L164)optionallinks **links? : [LinksObject](/api/swagger.md#LinksObject) --- # ResponsesObject ### Hierarchy * Record\ * *ResponsesObject* ## Index[**](#Index) ### Properties * [**default](#default) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L157)optionaldefault **default? : [ResponseObject](/api/swagger/interface/ResponseObject.md) | [ReferenceObject](/api/swagger/interface/ReferenceObject.md) --- # SchemaObject ## Index[**](#Index) ### Properties * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L219)optionaladditionalProperties **additionalProperties? : boolean | [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L213)optionalallOf **allOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L215)optionalanyOf **anyOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L223)optionaldefault **default? : any ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L211)optionaldeprecated **deprecated? : boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L221)optionaldescription **description? : string ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L204)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/swagger/interface/DiscriminatorObject.md) ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L239)optionalenum **enum? : any\[] ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L209)optionalexample **example? : any ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L210)optionalexamples **examples? : any\[] | Record\ ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMaximum **exclusiveMaximum? : boolean ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L229)optionalexclusiveMinimum **exclusiveMinimum? : boolean ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L208)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) ### [**](#format)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L222)optionalformat **format? : string ### [**](#items)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L217)optionalitems **items? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L233)optionalmaxItems **maxItems? : number ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L230)optionalmaxLength **maxLength? : number ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L236)optionalmaxProperties **maxProperties? : number ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L226)optionalmaximum **maximum? : number ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L234)optionalminItems **minItems? : number ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L231)optionalminLength **minLength? : number ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L237)optionalminProperties **minProperties? : number ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L228)optionalminimum **minimum? : number ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L225)optionalmultipleOf **multipleOf? : number ### [**](#not)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L216)optionalnot **not? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L203)optionalnullable **nullable? : boolean ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L214)optionaloneOf **oneOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L232)optionalpattern **pattern? : string ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L220)optionalpatternProperties **patternProperties? : any ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L218)optionalproperties **properties? : Record\ ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L205)optionalreadOnly **readOnly? : boolean ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L238)optionalrequired **required? : string\[] ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L224)optionaltitle **title? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L212)optionaltype **type? : string | new (...args: any\[]) => any | () => new (...args: any\[]) => any ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L235)optionaluniqueItems **uniqueItems? : boolean ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L206)optionalwriteOnly **writeOnly? : boolean ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L207)optionalxml **xml? : [XmlObject](/api/swagger/interface/XmlObject.md) --- # SchemaObjectMetadata ### Hierarchy * Omit<[SchemaObject](/api/swagger/interface/SchemaObject.md), type | required> * *SchemaObjectMetadata* ## Index[**](#Index) ### Properties * [**additionalProperties](#additionalProperties) * [**allOf](#allOf) * [**anyOf](#anyOf) * [**default](#default) * [**deprecated](#deprecated) * [**description](#description) * [**discriminator](#discriminator) * [**enum](#enum) * [**enumName](#enumName) * [**example](#example) * [**examples](#examples) * [**exclusiveMaximum](#exclusiveMaximum) * [**exclusiveMinimum](#exclusiveMinimum) * [**externalDocs](#externalDocs) * [**format](#format) * [**isArray](#isArray) * [**items](#items) * [**maxItems](#maxItems) * [**maxLength](#maxLength) * [**maxProperties](#maxProperties) * [**maximum](#maximum) * [**minItems](#minItems) * [**minLength](#minLength) * [**minProperties](#minProperties) * [**minimum](#minimum) * [**multipleOf](#multipleOf) * [**name](#name) * [**not](#not) * [**nullable](#nullable) * [**oneOf](#oneOf) * [**pattern](#pattern) * [**patternProperties](#patternProperties) * [**properties](#properties) * [**readOnly](#readOnly) * [**required](#required) * [**title](#title) * [**type](#type) * [**uniqueItems](#uniqueItems) * [**writeOnly](#writeOnly) * [**xml](#xml) ## Properties[**](#Properties) ### [**](#additionalProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L219)optionaladditionalProperties **additionalProperties? : boolean | [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.additionalProperties ### [**](#allOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L213)optionalallOf **allOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.allOf ### [**](#anyOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L215)optionalanyOf **anyOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.anyOf ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L223)optionaldefault **default? : any Inherited from Omit.default ### [**](#deprecated)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L211)optionaldeprecated **deprecated? : boolean Inherited from Omit.deprecated ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L221)optionaldescription **description? : string Inherited from Omit.description ### [**](#discriminator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L204)optionaldiscriminator **discriminator? : [DiscriminatorObject](/api/swagger/interface/DiscriminatorObject.md) Inherited from Omit.discriminator ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L239)optionalenum **enum? : any\[] Inherited from Omit.enum ### [**](#enumName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L308)optionalenumName **enumName? : string ### [**](#example)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L209)optionalexample **example? : any Inherited from Omit.example ### [**](#examples)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L210)optionalexamples **examples? : any\[] | Record\ Inherited from Omit.examples ### [**](#exclusiveMaximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L227)optionalexclusiveMaximum **exclusiveMaximum? : boolean Inherited from Omit.exclusiveMaximum ### [**](#exclusiveMinimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L229)optionalexclusiveMinimum **exclusiveMinimum? : boolean Inherited from Omit.exclusiveMinimum ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L208)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) Inherited from Omit.externalDocs ### [**](#format)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L222)optionalformat **format? : string Inherited from Omit.format ### [**](#isArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L305)optionalisArray **isArray? : boolean ### [**](#items)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L217)optionalitems **items? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.items ### [**](#maxItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L233)optionalmaxItems **maxItems? : number Inherited from Omit.maxItems ### [**](#maxLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L230)optionalmaxLength **maxLength? : number Inherited from Omit.maxLength ### [**](#maxProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L236)optionalmaxProperties **maxProperties? : number Inherited from Omit.maxProperties ### [**](#maximum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L226)optionalmaximum **maximum? : number Inherited from Omit.maximum ### [**](#minItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L234)optionalminItems **minItems? : number Inherited from Omit.minItems ### [**](#minLength)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L231)optionalminLength **minLength? : number Inherited from Omit.minLength ### [**](#minProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L237)optionalminProperties **minProperties? : number Inherited from Omit.minProperties ### [**](#minimum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L228)optionalminimum **minimum? : number Inherited from Omit.minimum ### [**](#multipleOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L225)optionalmultipleOf **multipleOf? : number Inherited from Omit.multipleOf ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L307)optionalname **name? : string ### [**](#not)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L216)optionalnot **not? : [ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md) Inherited from Omit.not ### [**](#nullable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L203)optionalnullable **nullable? : boolean Inherited from Omit.nullable ### [**](#oneOf)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L214)optionaloneOf **oneOf? : ([ReferenceObject](/api/swagger/interface/ReferenceObject.md) | [SchemaObject](/api/swagger/interface/SchemaObject.md))\[] Inherited from Omit.oneOf ### [**](#pattern)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L232)optionalpattern **pattern? : string Inherited from Omit.pattern ### [**](#patternProperties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L220)optionalpatternProperties **patternProperties? : any Inherited from Omit.patternProperties ### [**](#properties)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L218)optionalproperties **properties? : Record\ Inherited from Omit.properties ### [**](#readOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L205)optionalreadOnly **readOnly? : boolean Inherited from Omit.readOnly ### [**](#required)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L306)optionalrequired **required? : boolean ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L224)optionaltitle **title? : string Inherited from Omit.title ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L304)optionaltype **type? : string | Record\ | [Type](/api/swagger/interface/Type.md)\ | \[[Type](/api/swagger/interface/Type.md)\] ### [**](#uniqueItems)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L235)optionaluniqueItems **uniqueItems? : boolean Inherited from Omit.uniqueItems ### [**](#writeOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L206)optionalwriteOnly **writeOnly? : boolean Inherited from Omit.writeOnly ### [**](#xml)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L207)optionalxml **xml? : [XmlObject](/api/swagger/interface/XmlObject.md) Inherited from Omit.xml --- # SecuritySchemeObject ## Index[**](#Index) ### Properties * [**bearerFormat](#bearerFormat) * [**description](#description) * [**flows](#flows) * [**in](#in) * [**name](#name) * [**openIdConnectUrl](#openIdConnectUrl) * [**scheme](#scheme) * [**type](#type) ## Properties[**](#Properties) ### [**](#bearerFormat)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L265)optionalbearerFormat **bearerFormat? : string ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L261)optionaldescription **description? : string ### [**](#flows)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L266)optionalflows **flows? : [OAuthFlowsObject](/api/swagger/interface/OAuthFlowsObject.md) ### [**](#in)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L263)optionalin **in? : string ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L262)optionalname **name? : string ### [**](#openIdConnectUrl)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L267)optionalopenIdConnectUrl **openIdConnectUrl? : string ### [**](#scheme)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L264)optionalscheme **scheme? : string ### [**](#type)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L260)type **type: [SecuritySchemeType](/api/swagger.md#SecuritySchemeType) --- # ServerObject ## Index[**](#Index) ### Properties * [**description](#description) * [**url](#url) * [**variables](#variables) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L42)optionaldescription **description? : string ### [**](#url)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L41)url **url: string ### [**](#variables)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L43)optionalvariables **variables? : Record\ --- # ServerVariableObject ## Index[**](#Index) ### Properties * [**default](#default) * [**description](#description) * [**enum](#enum) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L48)default **default: string | number | boolean ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L49)optionaldescription **description? : string ### [**](#enum)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L47)optionalenum **enum? : string\[] | number\[] | boolean\[] --- # SwaggerOptions see ## Index[**](#Index) ### Properties * [**auth](#auth) * [**contact](#contact) * [**description](#description) * [**displayOptions](#displayOptions) * [**documentOptions](#documentOptions) * [**externalDocs](#externalDocs) * [**isGenerateTagForController](#isGenerateTagForController) * [**license](#license) * [**routerFilter](#routerFilter) * [**servers](#servers) * [**swaggerPath](#swaggerPath) * [**swaggerUIRender](#swaggerUIRender) * [**swaggerUIRenderOptions](#swaggerUIRenderOptions) * [**tagSortable](#tagSortable) * [**tags](#tags) * [**termsOfService](#termsOfService) * [**title](#title) * [**useValidationSchema](#useValidationSchema) * [**version](#version) ## Properties[**](#Properties) ### [**](#auth)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L396)optionalauth **auth? : [AuthOptions](/api/swagger/interface/AuthOptions.md) | [AuthOptions](/api/swagger/interface/AuthOptions.md)\[] 可以参考 ### [**](#contact)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L372)optionalcontact **contact? : [ContactObject](/api/swagger/interface/ContactObject.md) contact 字段 ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L363)optionaldescription **description? : string 默认值: This is a swagger-ui for midwayjs project description 字段 ### [**](#displayOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L411)optionaldisplayOptions **displayOptions? : { deepLinking? : boolean; defaultModelExpandDepth? : number; defaultModelRendering? : example | model; defaultModelsExpandDepth? : number; displayOperationId? : boolean; displayRequestDuration? : boolean; docExpansion? : none | list | full; filter? : string | boolean; maxDisplayedTags? : number; showCommonExtensions? : boolean; showExtensions? : boolean; tryItOutEnabled? : boolean; useUnsafeMarkdown? : boolean } UI 展示中需要用到的配置 可以参考 ### [**](#documentOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L426)optionaldocumentOptions **documentOptions? : { operationIdFactory? : (controllerKey: string, webRouter: RouterOption) => string } ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L384)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) externalDocs 字段 ### [**](#isGenerateTagForController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L451)optionalisGenerateTagForController **isGenerateTagForController? : boolean Weather to generate the Tag for controller ### [**](#license)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L376)optionallicense **license? : [LicenseObject](/api/swagger/interface/LicenseObject.md) license 字段 ### [**](#routerFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L447)optionalrouterFilter **routerFilter? : (url: string, options: RouterOption) => boolean 自定义路由过滤器 ### [**](#servers)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L388)optionalservers **servers? : [ServerObject](/api/swagger/interface/ServerObject.md)\[] servers 字段 ### [**](#swaggerPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L401)optionalswaggerPath **swaggerPath? : string 默认值: /swagger-ui 访问 swagger ui 的路径 ### [**](#swaggerUIRender)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L437)optionalswaggerUIRender **swaggerUIRender? : (config: [SwaggerOptions](/api/swagger/interface/SwaggerOptions.md), swaggerExplorer: [SwaggerExplorer](/api/swagger/class/SwaggerExplorer.md)) => (pathname: string) => Promise<{ content: any; ext: string }> ### [**](#swaggerUIRenderOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L442)optionalswaggerUIRenderOptions **swaggerUIRenderOptions? : Record\ ### [**](#tagSortable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L406)optionaltagSortable **tagSortable? : boolean 对路由 tag 进行 ascii 排序 可以使用 1-xxx、2-xxx、3-xxx 来定义 tag ### [**](#tags)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L392)optionaltags **tags? : [TagObject](/api/swagger/interface/TagObject.md)\[] tags 字段 ### [**](#termsOfService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L380)optionaltermsOfService **termsOfService? : string termsOfService 字段 ### [**](#title)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L358)optionaltitle **title? : string 默认值: My Project title 字段 ### [**](#useValidationSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L457)optionaluseValidationSchema **useValidationSchema? : boolean Enable inferring schema metadata from @midwayjs/validation DTO rules. When enabled, inferred metadata only fills fields that are not explicitly defined by @ApiProperty. ### [**](#version)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L368)optionalversion **version? : string 默认值: 1.0.0 version 字段 --- # TagObject ## Index[**](#Index) ### Properties * [**description](#description) * [**externalDocs](#externalDocs) * [**name](#name) ## Properties[**](#Properties) ### [**](#description)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L192)optionaldescription **description? : string ### [**](#externalDocs)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L193)optionalexternalDocs **externalDocs? : [ExternalDocumentationObject](/api/swagger/interface/ExternalDocumentationObject.md) ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L191)name **name: string --- # Type \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L296)constructor * **new Type(...args: any\[]): T --- # XmlObject ## Index[**](#Index) ### Properties * [**attribute](#attribute) * [**name](#name) * [**namespace](#namespace) * [**prefix](#prefix) * [**wrapped](#wrapped) ## Properties[**](#Properties) ### [**](#attribute)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L253)optionalattribute **attribute? : boolean ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L250)optionalname **name? : string ### [**](#namespace)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L251)optionalnamespace **namespace? : string ### [**](#prefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L252)optionalprefix **prefix? : string ### [**](#wrapped)[**](https://github.com/midwayjs/midway/blob/3.x/packages/swagger/src/interfaces/index.ts#L254)optionalwrapped **wrapped? : boolean --- # @midwayjs/tablestore ## Index[**](#Index) ### Classes * [**CompositeCondition](/api/tablestore/class/CompositeCondition.md) * [**Condition](/api/tablestore/class/Condition.md) * [**Configuration](/api/tablestore/class/Configuration.md) * [**SingleColumnCondition](/api/tablestore/class/SingleColumnCondition.md) * [**TableStoreService](/api/tablestore/class/TableStoreService.md) * [**TableStoreServiceFactory](/api/tablestore/class/TableStoreServiceFactory.md) ### Enumerations * [**ColumnConditionType](/api/tablestore/enum/ColumnConditionType.md) * [**ColumnReturnType](/api/tablestore/enum/ColumnReturnType.md) * [**ComparatorType](/api/tablestore/enum/ComparatorType.md) * [**DefinedColumnType](/api/tablestore/enum/DefinedColumnType.md) * [**Direction](/api/tablestore/enum/Direction.md) * [**FieldType](/api/tablestore/enum/FieldType.md) * [**FilterType](/api/tablestore/enum/FilterType.md) * [**GeoDistanceType](/api/tablestore/enum/GeoDistanceType.md) * [**IndexOptions](/api/tablestore/enum/IndexOptions.md) * [**IndexType](/api/tablestore/enum/IndexType.md) * [**IndexUpdateMode](/api/tablestore/enum/IndexUpdateMode.md) * [**LogicalOperator](/api/tablestore/enum/LogicalOperator.md) * [**PrimaryKeyOption](/api/tablestore/enum/PrimaryKeyOption.md) * [**PrimaryKeyType](/api/tablestore/enum/PrimaryKeyType.md) * [**QueryOperator](/api/tablestore/enum/QueryOperator.md) * [**QueryType](/api/tablestore/enum/QueryType.md) * [**ReturnType](/api/tablestore/enum/ReturnType.md) * [**RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md) * [**ScoreMode](/api/tablestore/enum/ScoreMode.md) * [**SortMode](/api/tablestore/enum/SortMode.md) * [**SortOrder](/api/tablestore/enum/SortOrder.md) * [**UpdateType](/api/tablestore/enum/UpdateType.md) ### Functions * [**formatRow](/api/tablestore/function/formatRow.md) * [**formatRows](/api/tablestore/function/formatRows.md) ### Interfaces * [**BatchGetRowParams](/api/tablestore/interface/BatchGetRowParams.md) * [**BatchWriteRowParams](/api/tablestore/interface/BatchWriteRowParams.md) * [**ColumnCondition](/api/tablestore/interface/ColumnCondition.md) * [**CreateIndexParams](/api/tablestore/interface/CreateIndexParams.md) * [**CreateSearchIndexParams](/api/tablestore/interface/CreateSearchIndexParams.md) * [**CreateTableParams](/api/tablestore/interface/CreateTableParams.md) * [**DeleteRowParams](/api/tablestore/interface/DeleteRowParams.md) * [**DeleteSearchIndexParams](/api/tablestore/interface/DeleteSearchIndexParams.md) * [**DeleteTableParams](/api/tablestore/interface/DeleteTableParams.md) * [**DescribeSearchIndexParams](/api/tablestore/interface/DescribeSearchIndexParams.md) * [**DescribeTableParams](/api/tablestore/interface/DescribeTableParams.md) * [**DropIndexParams](/api/tablestore/interface/DropIndexParams.md) * [**GetRangeParams](/api/tablestore/interface/GetRangeParams.md) * [**GetRowParams](/api/tablestore/interface/GetRowParams.md) * [**ListSearchIndexParams](/api/tablestore/interface/ListSearchIndexParams.md) * [**PutRowParams](/api/tablestore/interface/PutRowParams.md) * [**SearchIndexFieldSchema](/api/tablestore/interface/SearchIndexFieldSchema.md) * [**SearchIndexNestedFilter](/api/tablestore/interface/SearchIndexNestedFilter.md) * [**SearchIndexSchema](/api/tablestore/interface/SearchIndexSchema.md) * [**SearchIndexSetting](/api/tablestore/interface/SearchIndexSetting.md) * [**SearchIndexSorter](/api/tablestore/interface/SearchIndexSorter.md) * [**SearchParams](/api/tablestore/interface/SearchParams.md) * [**SearchQuery](/api/tablestore/interface/SearchQuery.md) * [**StartLocalTransactionParams](/api/tablestore/interface/StartLocalTransactionParams.md) * [**TableStoreClient](/api/tablestore/interface/TableStoreClient.md) * [**TableStoreCompositeCondition](/api/tablestore/interface/TableStoreCompositeCondition.md) * [**TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) * [**TableStoreConfig](/api/tablestore/interface/TableStoreConfig.md) * [**TableStoreLong](/api/tablestore/interface/TableStoreLong.md) * [**TableStoreResult](/api/tablestore/interface/TableStoreResult.md) * [**TableStoreSingleColumnCondition](/api/tablestore/interface/TableStoreSingleColumnCondition.md) * [**UpdateRowParams](/api/tablestore/interface/UpdateRowParams.md) * [**UpdateTableParams](/api/tablestore/interface/UpdateTableParams.md) ### Type Aliases * [**AbortTransactionParams](/api/tablestore.md#AbortTransactionParams) * [**AttributeColumn](/api/tablestore.md#AttributeColumn) * [**BatchWriteRowItem](/api/tablestore.md#BatchWriteRowItem) * [**ColumnValue](/api/tablestore.md#ColumnValue) * [**CommitTransactionParams](/api/tablestore.md#CommitTransactionParams) * [**ExtraMetadata](/api/tablestore.md#ExtraMetadata) * [**ListTableParams](/api/tablestore.md#ListTableParams) * [**PrimaryKey](/api/tablestore.md#PrimaryKey) * [**PrimaryKeyValue](/api/tablestore.md#PrimaryKeyValue) * [**SearchIndexQuery](/api/tablestore.md#SearchIndexQuery) * [**UpdateColumn](/api/tablestore.md#UpdateColumn) ### Variables * [**INF\_MAX](/api/tablestore.md#INF_MAX) * [**INF\_MIN](/api/tablestore.md#INF_MIN) * [**Long](/api/tablestore.md#Long) * [**PK\_AUTO\_INCR](/api/tablestore.md#PK_AUTO_INCR) ## Type Aliases[**](<#Type Aliases>) ### [**](#AbortTransactionParams)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L598)AbortTransactionParams **AbortTransactionParams: string | { transactionId: string } ### [**](#AttributeColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L237)AttributeColumn **AttributeColumn: { timestamp? : number } ### [**](#BatchWriteRowItem)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L318)BatchWriteRowItem **BatchWriteRowItem: ({ attributeColumns? : [AttributeColumn](/api/tablestore.md#AttributeColumn)\[]; type: PUT | DELETE } | { type: UPDATE; updateOfAttributeColumns: [UpdateColumn](/api/tablestore.md#UpdateColumn)\[] }) & { condition? : [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) | null; primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[]; returnContent? : { returnColumns? : string\[]; returnType? : [ReturnType](/api/tablestore/enum/ReturnType.md) } } ### [**](#ColumnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L12)ColumnValue **ColumnValue: number | boolean | [PrimaryKeyValue](/api/tablestore.md#PrimaryKeyValue) ### [**](#CommitTransactionParams)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L597)CommitTransactionParams **CommitTransactionParams: string | { transactionId: string } ### [**](#ExtraMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L8)ExtraMetadata **ExtraMetadata: typeof [INF\_MIN](/api/tablestore.md#INF_MIN) & typeof [INF\_MAX](/api/tablestore.md#INF_MAX) & typeof [PK\_AUTO\_INCR](/api/tablestore.md#PK_AUTO_INCR) protocol/proto\_buffer ### [**](#ListTableParams)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L198)ListTableParams **ListTableParams: undefined | null | {} ### [**](#PrimaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L13)PrimaryKey **PrimaryKey: {} ### [**](#PrimaryKeyValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L11)PrimaryKeyValue **PrimaryKeyValue: Int64LE | string | Buffer ### [**](#SearchIndexQuery)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L376)SearchIndexQuery **SearchIndexQuery: { query? : { fieldName: string; minimumShouldMatch? : number; operator? : [QueryOperator](/api/tablestore/enum/QueryOperator.md); text? : string }; queryType? : QueryType.MATCH\_QUERY } | { query? : { fieldName: string; text? : string }; queryType? : QueryType.MATCH\_PHRASE\_QUERY } | { query? : { fieldName: string; term: [ColumnValue](/api/tablestore.md#ColumnValue) }; queryType? : QueryType.TERM\_QUERY } | { query? : { fieldName: string; includeLower? : boolean; includeUpper? : boolean; rangeFrom? : [ColumnValue](/api/tablestore.md#ColumnValue); rangeTo? : [ColumnValue](/api/tablestore.md#ColumnValue) }; queryType? : QueryType.RANGE\_QUERY } | { query? : { fieldName: string; prefix? : string }; queryType? : QueryType.PREFIX\_QUERY } | { query? : { filterQueries? : [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery)\[]; minimumShouldMatch? : number; mustNotQueries? : [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery)\[]; mustQueries? : [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery)\[]; shouldQueries? : [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery)\[] }; queryType? : QueryType.BOOL\_QUERY } | { query? : { filter: [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery) }; queryType? : QueryType.CONST\_SCORE\_QUERY } | { query? : { fieldValueFactor: { fieldName: string }; query: [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery) }; queryType? : QueryType.FUNCTION\_SCORE\_QUERY } | { query? : { path: string; query: [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery); scoreMode? : [ScoreMode](/api/tablestore/enum/ScoreMode.md) }; type? : QueryType.NESTED\_QUERY } | { query? : { fieldName: string; value? : string }; queryType? : QueryType.WILDCARD\_QUERY } | { query? : {}; queryType? : QueryType.MATCH\_ALL\_QUERY } | { query? : { bottomRight? : string; fieldName: string; topLeft? : string }; queryType? : QueryType.GEO\_BOUNDING\_BOX\_QUERY } | { query? : { centerPoint? : string; distance? : number; fieldName: string }; queryType? : QueryType.GEO\_DISTANCE\_QUERY } | { query? : { fieldName: string; points? : string\[] }; queryType? : QueryType.GEO\_POLYGON\_QUERY } | { query? : { fieldName: string; terms? : [ColumnValue](/api/tablestore.md#ColumnValue)\[] }; queryType? : QueryType.TERMS\_QUERY } | { query? : { fieldName: string }; queryType? : QueryType.EXISTS\_QUERY } ### [**](#UpdateColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L242)UpdateColumn **UpdateColumn: { \[ key in UpdateType.DELETE\_ALL ]?: string\[] } & { \[ key in Exclude<[UpdateType](/api/tablestore/enum/UpdateType.md), UpdateType.DELETE\_ALL> ]?: [AttributeColumn](/api/tablestore.md#AttributeColumn)\[] } ## Variables[**](#Variables) ### [**](#INF_MAX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L72)constINF\_MAX **INF\_MAX: any = TableStore.INF\_MAX ### [**](#INF_MIN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L71)constINF\_MIN **INF\_MIN: any = TableStore.INF\_MIN ### [**](#Long)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/proxy.ts#L60)constLong **Long: [TableStoreLong](/api/tablestore/interface/TableStoreLong.md) = ... ### [**](#PK_AUTO_INCR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L73)constPK\_AUTO\_INCR **PK\_AUTO\_INCR: any = TableStore.PK\_AUTO\_INCR --- # CompositeCondition ### Hierarchy * unknown * [TableStoreCompositeCondition](/api/tablestore/interface/TableStoreCompositeCondition.md) * *CompositeCondition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**sub\_conditions](#sub_conditions) ### Methods * [**addSubCondition](#addSubCondition) * [**clearSubCondition](#clearSubCondition) * [**getCombinator](#getCombinator) * [**getType](#getType) * [**setCombinator](#setCombinator) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/proxy.ts#L14)constructor * **new CompositeCondition(combinator: [LogicalOperator](/api/tablestore/enum/LogicalOperator.md)): [CompositeCondition](/api/tablestore/class/CompositeCondition.md) - Overrides TableStore.CompositeCondition.constructor ## Properties[**](#Properties) ### [**](#sub_conditions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L754)sub\_conditions **sub\_conditions: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)\[] Inherited from TableStoreCompositeCondition.sub\_conditions ## Methods[**](#Methods) ### [**](#addSubCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L762)addSubCondition * **addSubCondition(condition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)): void - Inherited from TableStoreCompositeCondition.addSubCondition ### [**](#clearSubCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L764)clearSubCondition * **clearSubCondition(): void - Inherited from TableStoreCompositeCondition.clearSubCondition ### [**](#getCombinator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L760)getCombinator * **getCombinator(): [LogicalOperator](/api/tablestore/enum/LogicalOperator.md) - Inherited from TableStoreCompositeCondition.getCombinator ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L756)getType * **getType(): FT\_COMPOSITE\_COLUMN\_VALUE - Inherited from TableStoreCompositeCondition.getType ### [**](#setCombinator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L758)setCombinator * **setCombinator(combinator: [LogicalOperator](/api/tablestore/enum/LogicalOperator.md)): void - Inherited from TableStoreCompositeCondition.setCombinator --- # Condition ### Hierarchy * unknown * [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) * *Condition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**columnCondition](#columnCondition) * [**rowExistenceExpectation](#rowExistenceExpectation) ### Methods * [**getColumnCondition](#getColumnCondition) * [**getRowExistenceExpectation](#getRowExistenceExpectation) * [**setColumnCondition](#setColumnCondition) * [**setRowExistenceExpectation](#setRowExistenceExpectation) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/proxy.ts#L24)constructor * **new Condition(rowExistenceExpectation: [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md), columnCondition? : [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)): [Condition](/api/tablestore/class/Condition.md) - Overrides TableStore.Condition.constructor ## Properties[**](#Properties) ### [**](#columnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L768)columnCondition **columnCondition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) Inherited from TableStoreCondition.columnCondition ### [**](#rowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L769)rowExistenceExpectation **rowExistenceExpectation: [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md) Inherited from TableStoreCondition.rowExistenceExpectation ## Methods[**](#Methods) ### [**](#getColumnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L779)getColumnCondition * **getColumnCondition(): [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) - Inherited from TableStoreCondition.getColumnCondition ### [**](#getRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L775)getRowExistenceExpectation * **getRowExistenceExpectation(): [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md) - Inherited from TableStoreCondition.getRowExistenceExpectation ### [**](#setColumnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L777)setColumnCondition * **setColumnCondition(columnCondition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)): void - Inherited from TableStoreCondition.setColumnCondition ### [**](#setRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L771)setRowExistenceExpectation * **setRowExistenceExpectation(rowExistenceExpectation: [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md)): void - Inherited from TableStoreCondition.setRowExistenceExpectation --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TableStoreConfiguration](/api/tablestore/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/configuration.ts#L8)onReady * **onReady(container: any): Promise\ --- # SingleColumnCondition \ ### Hierarchy * unknown * [TableStoreSingleColumnCondition](/api/tablestore/interface/TableStoreSingleColumnCondition.md) * *SingleColumnCondition* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**columnName](#columnName) * [**columnValue](#columnValue) * [**comparator](#comparator) * [**latestVersionOnly](#latestVersionOnly) * [**passIfMissing](#passIfMissing) ### Methods * [**getColumnName](#getColumnName) * [**getColumnValue](#getColumnValue) * [**getLatestVersionOnly](#getLatestVersionOnly) * [**getPassIfMissing](#getPassIfMissing) * [**getType](#getType) * [**setColumnName](#setColumnName) * [**setColumnValue](#setColumnValue) * [**setComparator](#setComparator) * [**setLatestVersionOnly](#setLatestVersionOnly) * [**setPassIfMissing](#setPassIfMissing) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/proxy.ts#L37)constructor * **new SingleColumnCondition\(columnName: string, columnValue: T, comparator: [ComparatorType](/api/tablestore/enum/ComparatorType.md), passIfMissing? : boolean, latestVersionOnly? : boolean): [SingleColumnCondition](/api/tablestore/class/SingleColumnCondition.md)\ - Overrides TableStore.SingleColumnCondition.constructor #### Type parameters * **T** ## Properties[**](#Properties) ### [**](#columnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L797)columnName **columnName: string Inherited from TableStoreSingleColumnCondition.columnName ### [**](#columnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L798)columnValue **columnValue: [ColumnValue](/api/tablestore.md#ColumnValue) Inherited from TableStoreSingleColumnCondition.columnValue ### [**](#comparator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L799)comparator **comparator: [ComparatorType](/api/tablestore/enum/ComparatorType.md) Inherited from TableStoreSingleColumnCondition.comparator ### [**](#latestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L801)latestVersionOnly **latestVersionOnly: boolean Inherited from TableStoreSingleColumnCondition.latestVersionOnly ### [**](#passIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L800)passIfMissing **passIfMissing: boolean Inherited from TableStoreSingleColumnCondition.passIfMissing ## Methods[**](#Methods) ### [**](#getColumnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L823)getColumnName * **getColumnName(): string - Inherited from TableStoreSingleColumnCondition.getColumnName ### [**](#getColumnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L827)getColumnValue * **getColumnValue(): [ColumnValue](/api/tablestore.md#ColumnValue) - Inherited from TableStoreSingleColumnCondition.getColumnValue ### [**](#getLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L819)getLatestVersionOnly * **getLatestVersionOnly(): boolean - Inherited from TableStoreSingleColumnCondition.getLatestVersionOnly ### [**](#getPassIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L815)getPassIfMissing * **getPassIfMissing(): boolean - Inherited from TableStoreSingleColumnCondition.getPassIfMissing ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L803)getType * **getType(): FT\_SINGLE\_COLUMN\_VALUE - Inherited from TableStoreSingleColumnCondition.getType ### [**](#setColumnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L821)setColumnName * **setColumnName(columnName: string): void - Inherited from TableStoreSingleColumnCondition.setColumnName ### [**](#setColumnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L825)setColumnValue * **setColumnValue(columnValue: [ColumnValue](/api/tablestore.md#ColumnValue)): void - Inherited from TableStoreSingleColumnCondition.setColumnValue ### [**](#setComparator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L829)setComparator * **setComparator(comparator: [ComparatorType](/api/tablestore/enum/ComparatorType.md)): void - Inherited from TableStoreSingleColumnCondition.setComparator ### [**](#setLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L817)setLatestVersionOnly * **setLatestVersionOnly(latestVersionOnly: boolean): void - Inherited from TableStoreSingleColumnCondition.setLatestVersionOnly ### [**](#setPassIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L813)setPassIfMissing * **setPassIfMissing(passIfMissing: boolean): void - Inherited from TableStoreSingleColumnCondition.setPassIfMissing 设置 `passIfMissing` 由于OTS一行的属性列不固定,有可能存在有condition条件的列在该行不存在的情况,这时 参数控制在这种情况下对该行的检查结果。 如果设置为True,则若列在该行中不存在,则检查条件通过。 如果设置为False,则若列在该行中不存在,则检查条件失败。 默认值为True。 --- # TableStoreService ### Hierarchy * [TableStoreClient](/api/tablestore/interface/TableStoreClient.md) * *TableStoreService* ### Implements * [TableStoreClient](/api/tablestore/interface/TableStoreClient.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**abortTransaction](#abortTransaction) * [**batchGetRow](#batchGetRow) * [**batchWriteRow](#batchWriteRow) * [**commitTransaction](#commitTransaction) * [**createIndex](#createIndex) * [**createSearchIndex](#createSearchIndex) * [**createTable](#createTable) * [**deleteRow](#deleteRow) * [**deleteSearchIndex](#deleteSearchIndex) * [**deleteTable](#deleteTable) * [**describeSearchIndex](#describeSearchIndex) * [**describeTable](#describeTable) * [**dropIndex](#dropIndex) * [**getRange](#getRange) * [**getRow](#getRow) * [**init](#init) * [**listSearchIndex](#listSearchIndex) * [**listTable](#listTable) * [**putRow](#putRow) * [**search](#search) * [**startLocalTransaction](#startLocalTransaction) * [**updateRow](#updateRow) * [**updateTable](#updateTable) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TableStoreService(): [TableStoreService](/api/tablestore/class/TableStoreService.md) ## Methods[**](#Methods) ### [**](#abortTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L724)abortTransaction * **abortTransaction\(params: [AbortTransactionParams](/api/tablestore.md#AbortTransactionParams)): Promise\ - Implementation of TableStoreClient.abortTransaction Inherited from TableStoreClient.abortTransaction 丢弃事务 *** #### Type parameters * **R** = any ### [**](#batchGetRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L667)batchGetRow * **batchGetRow\(params: [BatchGetRowParams](/api/tablestore/interface/BatchGetRowParams.md)): Promise\ - Implementation of TableStoreClient.batchGetRow Inherited from TableStoreClient.batchGetRow 批量读取一个或多个表中的若干行数据。 *** #### Type parameters * **R** = any ### [**](#batchWriteRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L672)batchWriteRow * **batchWriteRow\(params: [BatchWriteRowParams](/api/tablestore/interface/BatchWriteRowParams.md)): Promise\ - Implementation of TableStoreClient.batchWriteRow Inherited from TableStoreClient.batchWriteRow 批量修改行 *** #### Type parameters * **R** = any ### [**](#commitTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L719)commitTransaction * **commitTransaction\(params: [CommitTransactionParams](/api/tablestore.md#CommitTransactionParams)): Promise\ - Implementation of TableStoreClient.commitTransaction Inherited from TableStoreClient.commitTransaction 提交事务 *** #### Type parameters * **R** = any ### [**](#createIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L702)createIndex * **createIndex\(params: [CreateIndexParams](/api/tablestore/interface/CreateIndexParams.md)): Promise\ - Implementation of TableStoreClient.createIndex Inherited from TableStoreClient.createIndex 创建GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#createSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L687)createSearchIndex * **createSearchIndex\(params: [CreateSearchIndexParams](/api/tablestore/interface/CreateSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.createSearchIndex Inherited from TableStoreClient.createSearchIndex SearchIndex创建新索引。 *** #### Type parameters * **R** = any ### [**](#createTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L614)createTable * **createTable\(params: [CreateTableParams](/api/tablestore/interface/CreateTableParams.md)): Promise\ - Implementation of TableStoreClient.createTable Inherited from TableStoreClient.createTable 根据给定的表结构信息创建相应的表。 *** #### Type parameters * **R** = any ### [**](#deleteRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L657)deleteRow * **deleteRow\(params: [DeleteRowParams](/api/tablestore/interface/DeleteRowParams.md)): Promise\ - Implementation of TableStoreClient.deleteRow Inherited from TableStoreClient.deleteRow 删除一行数据。 *** #### Type parameters * **R** = any ### [**](#deleteSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L692)deleteSearchIndex * **deleteSearchIndex\(params: [DeleteSearchIndexParams](/api/tablestore/interface/DeleteSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.deleteSearchIndex Inherited from TableStoreClient.deleteSearchIndex SearchIndex删除索引。 *** #### Type parameters * **R** = any ### [**](#deleteTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L624)deleteTable * **deleteTable\(params: [DeleteTableParams](/api/tablestore/interface/DeleteTableParams.md)): Promise\ - Implementation of TableStoreClient.deleteTable Inherited from TableStoreClient.deleteTable 删除本实例下指定的表。 *** #### Type parameters * **R** = any ### [**](#describeSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L682)describeSearchIndex * **describeSearchIndex\(params: [DescribeSearchIndexParams](/api/tablestore/interface/DescribeSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.describeSearchIndex Inherited from TableStoreClient.describeSearchIndex 获取SearchIndex索引描述信息。 *** #### Type parameters * **R** = any ### [**](#describeTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L634)describeTable * **describeTable\(params: [DescribeTableParams](/api/tablestore/interface/DescribeTableParams.md)): Promise\ - Implementation of TableStoreClient.describeTable Inherited from TableStoreClient.describeTable 查询指定表的结构信息和预留读/写吞吐量设置信息。 *** #### Type parameters * **R** = any ### [**](#dropIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L707)dropIndex * **dropIndex\(params: [DropIndexParams](/api/tablestore/interface/DropIndexParams.md)): Promise\ - Implementation of TableStoreClient.dropIndex Inherited from TableStoreClient.dropIndex 删除GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#getRange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L662)getRange * **getRange\(params: [GetRangeParams](/api/tablestore/interface/GetRangeParams.md)): Promise\ - Implementation of TableStoreClient.getRange Inherited from TableStoreClient.getRange 读取指定主键范围内的数据。 *** #### Type parameters * **R** = any ### [**](#getRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L642)getRow * **getRow\(params: [GetRowParams](/api/tablestore/interface/GetRowParams.md)): Promise\ - Implementation of TableStoreClient.getRow Inherited from TableStoreClient.getRow 根据给定的主键读取单行数据。 *** #### Type parameters * **R** = any ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/manager.ts#L112)init * **init(): Promise\ ### [**](#listSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L677)listSearchIndex * **listSearchIndex\(params: [ListSearchIndexParams](/api/tablestore/interface/ListSearchIndexParams.md)): Promise\ - Implementation of TableStoreClient.listSearchIndex Inherited from TableStoreClient.listSearchIndex 获取表下所有SearchIndex索引名。 *** #### Type parameters * **R** = any ### [**](#listTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L619)listTable * **listTable\(params: {}): Promise\ - Implementation of TableStoreClient.listTable Inherited from TableStoreClient.listTable 获取当前实例下已创建的所有表的表名。 *** #### Type parameters * **R** = any ### [**](#putRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L647)putRow * **putRow\(params: [PutRowParams](/api/tablestore/interface/PutRowParams.md)): Promise\ - Implementation of TableStoreClient.putRow Inherited from TableStoreClient.putRow 插入数据到指定的行,如果该行不存在,则新增一行;若该行存在,则覆盖原有行。 *** #### Type parameters * **R** = any ### [**](#search)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L697)search * **search\(params: [SearchParams](/api/tablestore/interface/SearchParams.md)): Promise\ - Implementation of TableStoreClient.search Inherited from TableStoreClient.search SearchIndex搜索。 *** #### Type parameters * **R** = any ### [**](#startLocalTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L712)startLocalTransaction * **startLocalTransaction\(params: [StartLocalTransactionParams](/api/tablestore/interface/StartLocalTransactionParams.md)): Promise\ - Implementation of TableStoreClient.startLocalTransaction Inherited from TableStoreClient.startLocalTransaction 创建局部事务 *** #### Type parameters * **R** = any ### [**](#updateRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L652)updateRow * **updateRow\(params: [UpdateRowParams](/api/tablestore/interface/UpdateRowParams.md)): Promise\ - Implementation of TableStoreClient.updateRow Inherited from TableStoreClient.updateRow 更新指定行的数据。如果该行不存在,则新增一行;若该行存在,则根据请求的内容在这一行中新增、修改或者删除指定列的值。 *** #### Type parameters * **R** = any ### [**](#updateTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L629)updateTable * **updateTable\(params: [UpdateTableParams](/api/tablestore/interface/UpdateTableParams.md)): Promise\ - Implementation of TableStoreClient.updateTable Inherited from TableStoreClient.updateTable 更新指定表的预留读吞吐量或预留写吞吐量设置。 *** #### Type parameters * **R** = any --- # TableStoreServiceFactory ### Hierarchy * ServiceFactory<[TableStoreClient](/api/tablestore/interface/TableStoreClient.md)> * *TableStoreServiceFactory* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**tableStoreConfig](#tableStoreConfig) ### Methods * [**createClient](#createClient) * [**createInstance](#createInstance) * [**get](#get) * [**getClientKeys](#getClientKeys) * [**getClientPriority](#getClientPriority) * [**getClients](#getClients) * [**getDefaultClientName](#getDefaultClientName) * [**getName](#getName) * [**has](#has) * [**init](#init) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TableStoreServiceFactory(): [TableStoreServiceFactory](/api/tablestore/class/TableStoreServiceFactory.md) - Inherited from ServiceFactory\.constructor ## Properties[**](#Properties) ### [**](#tableStoreConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/manager.ts#L20)tableStoreConfig **tableStoreConfig: any ## Methods[**](#Methods) ### [**](#createClient)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/manager.ts#L41)createClient * **createClient(config: any): Promise<[TableStoreClient](/api/tablestore/interface/TableStoreClient.md)> - Overrides ServiceFactory.createClient ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L17)createInstance * **createInstance(config: any, clientName? : string): Promise\ - Inherited from ServiceFactory.createInstance ### [**](#get)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L15)get * **get\(id? : string): U - Inherited from ServiceFactory.get #### Type parameters * **U** = [TableStoreClient](/api/tablestore/interface/TableStoreClient.md) ### [**](#getClientKeys)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L24)getClientKeys * **getClientKeys(): string\[] - Inherited from ServiceFactory.getClientKeys ### [**](#getClientPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L25)getClientPriority * **getClientPriority(name: string): string - Inherited from ServiceFactory.getClientPriority ### [**](#getClients)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L23)getClients * **getClients(): Map\ - Inherited from ServiceFactory.getClients ### [**](#getDefaultClientName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L22)getDefaultClientName * **getDefaultClientName(): string - Inherited from ServiceFactory.getDefaultClientName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/manager.ts#L98)getName * **getName(): string - Overrides ServiceFactory.getName ### [**](#has)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L16)has * **has(id: string): boolean - Inherited from ServiceFactory.has ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/manager.ts#L35)init * **init(): Promise\ ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L26)isHighPriority * **isHighPriority(name: string): boolean - Inherited from ServiceFactory.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L28)isLowPriority * **isLowPriority(name: string): boolean - Inherited from ServiceFactory.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L27)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from ServiceFactory.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/serviceFactory.d.ts#L21)stop * **stop(): Promise\ - Inherited from ServiceFactory.stop --- # ColumnConditionType ## Index[**](#Index) ### Enumeration Members * [**COMPOSITE\_COLUMN\_CONDITION](#COMPOSITE_COLUMN_CONDITION) * [**SINGLE\_COLUMN\_CONDITION](#SINGLE_COLUMN_CONDITION) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#COMPOSITE_COLUMN_CONDITION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L740)COMPOSITE\_COLUMN\_CONDITION **COMPOSITE\_COLUMN\_CONDITION: 0 ### [**](#SINGLE_COLUMN_CONDITION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L741)SINGLE\_COLUMN\_CONDITION **SINGLE\_COLUMN\_CONDITION: 1 --- # ColumnReturnType ## Index[**](#Index) ### Enumeration Members * [**RETURN\_ALL](#RETURN_ALL) * [**RETURN\_NONE](#RETURN_NONE) * [**RETURN\_SPECIFIED](#RETURN_SPECIFIED) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#RETURN_ALL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L128)RETURN\_ALL **RETURN\_ALL: 1 ### [**](#RETURN_NONE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L130)RETURN\_NONE **RETURN\_NONE: 3 ### [**](#RETURN_SPECIFIED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L129)RETURN\_SPECIFIED **RETURN\_SPECIFIED: 2 --- # ComparatorType ## Index[**](#Index) ### Enumeration Members * [**EQUAL](#EQUAL) * [**GREATER\_EQUAL](#GREATER_EQUAL) * [**GREATER\_THAN](#GREATER_THAN) * [**LESS\_EQUAL](#LESS_EQUAL) * [**LESS\_THAN](#LESS_THAN) * [**NOT\_EQUAL](#NOT_EQUAL) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#EQUAL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L745)EQUAL **EQUAL: 1 ### [**](#GREATER_EQUAL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L748)GREATER\_EQUAL **GREATER\_EQUAL: 4 ### [**](#GREATER_THAN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L747)GREATER\_THAN **GREATER\_THAN: 3 ### [**](#LESS_EQUAL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L750)LESS\_EQUAL **LESS\_EQUAL: 6 ### [**](#LESS_THAN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L749)LESS\_THAN **LESS\_THAN: 5 ### [**](#NOT_EQUAL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L746)NOT\_EQUAL **NOT\_EQUAL: 2 --- # DefinedColumnType ## Index[**](#Index) ### Enumeration Members * [**DCT\_BOOLEAN](#DCT_BOOLEAN) * [**DCT\_DOUBLE](#DCT_DOUBLE) * [**DCT\_INTEGER](#DCT_INTEGER) * [**DCT\_STRING](#DCT_STRING) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DCT_BOOLEAN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L47)DCT\_BOOLEAN **DCT\_BOOLEAN: 3 ### [**](#DCT_DOUBLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L46)DCT\_DOUBLE **DCT\_DOUBLE: 2 ### [**](#DCT_INTEGER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L45)DCT\_INTEGER **DCT\_INTEGER: 1 ### [**](#DCT_STRING)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L48)DCT\_STRING **DCT\_STRING: 4 --- # Direction ## Index[**](#Index) ### Enumeration Members * [**BACKWARD](#BACKWARD) * [**FORWARD](#FORWARD) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BACKWARD)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L28)BACKWARD **BACKWARD: BACKWARD ### [**](#FORWARD)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L27)FORWARD **FORWARD: FORWARD --- # FieldType ## Index[**](#Index) ### Enumeration Members * [**BOOLEAN](#BOOLEAN) * [**DOUBLE](#DOUBLE) * [**GEO\_POINT](#GEO_POINT) * [**KEYWORD](#KEYWORD) * [**LONG](#LONG) * [**NESTED](#NESTED) * [**TEXT](#TEXT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BOOLEAN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L120)BOOLEAN **BOOLEAN: 3 ### [**](#DOUBLE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L119)DOUBLE **DOUBLE: 2 ### [**](#GEO_POINT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L124)GEO\_POINT **GEO\_POINT: 7 ### [**](#KEYWORD)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L121)KEYWORD **KEYWORD: 4 ### [**](#LONG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L118)LONG **LONG: 1 ### [**](#NESTED)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L123)NESTED **NESTED: 6 ### [**](#TEXT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L122)TEXT **TEXT: 5 --- # FilterType ## Index[**](#Index) ### Enumeration Members * [**FT\_COLUMN\_PAGINATION](#FT_COLUMN_PAGINATION) * [**FT\_COMPOSITE\_COLUMN\_VALUE](#FT_COMPOSITE_COLUMN_VALUE) * [**FT\_SINGLE\_COLUMN\_VALUE](#FT_SINGLE_COLUMN_VALUE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#FT_COLUMN_PAGINATION)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L730)FT\_COLUMN\_PAGINATION **FT\_COLUMN\_PAGINATION: 3 ### [**](#FT_COMPOSITE_COLUMN_VALUE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L729)FT\_COMPOSITE\_COLUMN\_VALUE **FT\_COMPOSITE\_COLUMN\_VALUE: 2 ### [**](#FT_SINGLE_COLUMN_VALUE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L728)FT\_SINGLE\_COLUMN\_VALUE **FT\_SINGLE\_COLUMN\_VALUE: 1 --- # GeoDistanceType ## Index[**](#Index) ### Enumeration Members * [**GEO\_DISTANCE\_ARC](#GEO_DISTANCE_ARC) * [**GEO\_DISTANCE\_PLANE](#GEO_DISTANCE_PLANE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#GEO_DISTANCE_ARC)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L134)GEO\_DISTANCE\_ARC **GEO\_DISTANCE\_ARC: 0 ### [**](#GEO_DISTANCE_PLANE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L135)GEO\_DISTANCE\_PLANE **GEO\_DISTANCE\_PLANE: 1 --- # IndexOptions ## Index[**](#Index) ### Enumeration Members * [**DOCS](#DOCS) * [**FREQS](#FREQS) * [**OFFSETS](#OFFSETS) * [**POSITIONS](#POSITIONS) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DOCS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L139)DOCS **DOCS: 1 ### [**](#FREQS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L140)FREQS **FREQS: 2 ### [**](#OFFSETS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L142)OFFSETS **OFFSETS: 4 ### [**](#POSITIONS)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L141)POSITIONS **POSITIONS: 3 --- # IndexType ## Index[**](#Index) ### Enumeration Members * [**IT\_GLOBAL\_INDEX](#IT_GLOBAL_INDEX) * [**IT\_LOCAL\_INDEX](#IT_LOCAL_INDEX) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#IT_GLOBAL_INDEX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L67)IT\_GLOBAL\_INDEX **IT\_GLOBAL\_INDEX: 0 ### [**](#IT_LOCAL_INDEX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L68)IT\_LOCAL\_INDEX **IT\_LOCAL\_INDEX: 1 --- # IndexUpdateMode ## Index[**](#Index) ### Enumeration Members * [**IUM\_ASYNC\_INDEX](#IUM_ASYNC_INDEX) * [**IUM\_SYNC\_INDEX](#IUM_SYNC_INDEX) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#IUM_ASYNC_INDEX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L62)IUM\_ASYNC\_INDEX **IUM\_ASYNC\_INDEX: 0 ### [**](#IUM_SYNC_INDEX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L63)IUM\_SYNC\_INDEX **IUM\_SYNC\_INDEX: 1 --- # LogicalOperator ## Index[**](#Index) ### Enumeration Members * [**AND](#AND) * [**NOT](#NOT) * [**OR](#OR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AND)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L735)AND **AND: 2 ### [**](#NOT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L734)NOT **NOT: 1 ### [**](#OR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L736)OR **OR: 3 --- # PrimaryKeyOption ## Index[**](#Index) ### Enumeration Members * [**AUTO\_INCREMENT](#AUTO_INCREMENT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AUTO_INCREMENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L58)AUTO\_INCREMENT **AUTO\_INCREMENT: 1 --- # PrimaryKeyType ## Index[**](#Index) ### Enumeration Members * [**BINARY](#BINARY) * [**INTEGER](#INTEGER) * [**STRING](#STRING) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BINARY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L54)BINARY **BINARY: 3 ### [**](#INTEGER)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L52)INTEGER **INTEGER: 1 ### [**](#STRING)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L53)STRING **STRING: 2 --- # QueryOperator ## Index[**](#Index) ### Enumeration Members * [**AND](#AND) * [**OR](#OR) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AND)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L147)AND **AND: 2 ### [**](#OR)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L146)OR **OR: 1 --- # QueryType search ## Index[**](#Index) ### Enumeration Members * [**BOOL\_QUERY](#BOOL_QUERY) * [**CONST\_SCORE\_QUERY](#CONST_SCORE_QUERY) * [**EXISTS\_QUERY](#EXISTS_QUERY) * [**FUNCTION\_SCORE\_QUERY](#FUNCTION_SCORE_QUERY) * [**GEO\_BOUNDING\_BOX\_QUERY](#GEO_BOUNDING_BOX_QUERY) * [**GEO\_DISTANCE\_QUERY](#GEO_DISTANCE_QUERY) * [**GEO\_POLYGON\_QUERY](#GEO_POLYGON_QUERY) * [**MATCH\_ALL\_QUERY](#MATCH_ALL_QUERY) * [**MATCH\_PHRASE\_QUERY](#MATCH_PHRASE_QUERY) * [**MATCH\_QUERY](#MATCH_QUERY) * [**NESTED\_QUERY](#NESTED_QUERY) * [**PREFIX\_QUERY](#PREFIX_QUERY) * [**RANGE\_QUERY](#RANGE_QUERY) * [**TERMS\_QUERY](#TERMS_QUERY) * [**TERM\_QUERY](#TERM_QUERY) * [**WILDCARD\_QUERY](#WILDCARD_QUERY) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#BOOL_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L85)BOOL\_QUERY **BOOL\_QUERY: 6 ### [**](#CONST_SCORE_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L86)CONST\_SCORE\_QUERY **CONST\_SCORE\_QUERY: 7 ### [**](#EXISTS_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L95)EXISTS\_QUERY **EXISTS\_QUERY: 16 ### [**](#FUNCTION_SCORE_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L87)FUNCTION\_SCORE\_QUERY **FUNCTION\_SCORE\_QUERY: 8 ### [**](#GEO_BOUNDING_BOX_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L91)GEO\_BOUNDING\_BOX\_QUERY **GEO\_BOUNDING\_BOX\_QUERY: 12 ### [**](#GEO_DISTANCE_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L92)GEO\_DISTANCE\_QUERY **GEO\_DISTANCE\_QUERY: 13 ### [**](#GEO_POLYGON_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L93)GEO\_POLYGON\_QUERY **GEO\_POLYGON\_QUERY: 14 ### [**](#MATCH_ALL_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L90)MATCH\_ALL\_QUERY **MATCH\_ALL\_QUERY: 11 ### [**](#MATCH_PHRASE_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L81)MATCH\_PHRASE\_QUERY **MATCH\_PHRASE\_QUERY: 2 ### [**](#MATCH_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L80)MATCH\_QUERY **MATCH\_QUERY: 1 ### [**](#NESTED_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L88)NESTED\_QUERY **NESTED\_QUERY: 9 ### [**](#PREFIX_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L84)PREFIX\_QUERY **PREFIX\_QUERY: 5 ### [**](#RANGE_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L83)RANGE\_QUERY **RANGE\_QUERY: 4 ### [**](#TERMS_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L94)TERMS\_QUERY **TERMS\_QUERY: 15 ### [**](#TERM_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L82)TERM\_QUERY **TERM\_QUERY: 3 ### [**](#WILDCARD_QUERY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L89)WILDCARD\_QUERY **WILDCARD\_QUERY: 10 --- # ReturnType ## Index[**](#Index) ### Enumeration Members * [**AfterModify](#AfterModify) * [**NONE](#NONE) * [**Primarykey](#Primarykey) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#AfterModify)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L41)AfterModify **AfterModify: 2 ### [**](#NONE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L39)NONE **NONE: 0 ### [**](#Primarykey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L40)Primarykey **Primarykey: 1 --- # RowExistenceExpectation metadata ## Index[**](#Index) ### Enumeration Members * [**EXPECT\_EXIST](#EXPECT_EXIST) * [**EXPECT\_NOT\_EXIST](#EXPECT_NOT_EXIST) * [**IGNORE](#IGNORE) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#EXPECT_EXIST)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L22)EXPECT\_EXIST **EXPECT\_EXIST: 1 ### [**](#EXPECT_NOT_EXIST)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L23)EXPECT\_NOT\_EXIST **EXPECT\_NOT\_EXIST: 2 ### [**](#IGNORE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L21)IGNORE **IGNORE: 0 --- # ScoreMode ## Index[**](#Index) ### Enumeration Members * [**SCORE\_MODE\_AVG](#SCORE_MODE_AVG) * [**SCORE\_MODE\_MAX](#SCORE_MODE_MAX) * [**SCORE\_MODE\_MIN](#SCORE_MODE_MIN) * [**SCORE\_MODE\_NONE](#SCORE_MODE_NONE) * [**SCORE\_MODE\_TOTAL](#SCORE_MODE_TOTAL) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SCORE_MODE_AVG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L100)SCORE\_MODE\_AVG **SCORE\_MODE\_AVG: 2 ### [**](#SCORE_MODE_MAX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L101)SCORE\_MODE\_MAX **SCORE\_MODE\_MAX: 3 ### [**](#SCORE_MODE_MIN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L103)SCORE\_MODE\_MIN **SCORE\_MODE\_MIN: 5 ### [**](#SCORE_MODE_NONE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L99)SCORE\_MODE\_NONE **SCORE\_MODE\_NONE: 1 ### [**](#SCORE_MODE_TOTAL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L102)SCORE\_MODE\_TOTAL **SCORE\_MODE\_TOTAL: 4 --- # SortMode ## Index[**](#Index) ### Enumeration Members * [**SORT\_MODE\_AVG](#SORT_MODE_AVG) * [**SORT\_MODE\_MAX](#SORT_MODE_MAX) * [**SORT\_MODE\_MIN](#SORT_MODE_MIN) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SORT_MODE_AVG)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L114)SORT\_MODE\_AVG **SORT\_MODE\_AVG: 2 ### [**](#SORT_MODE_MAX)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L113)SORT\_MODE\_MAX **SORT\_MODE\_MAX: 1 ### [**](#SORT_MODE_MIN)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L112)SORT\_MODE\_MIN **SORT\_MODE\_MIN: 0 --- # SortOrder ## Index[**](#Index) ### Enumeration Members * [**SORT\_ORDER\_ASC](#SORT_ORDER_ASC) * [**SORT\_ORDER\_DESC](#SORT_ORDER_DESC) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#SORT_ORDER_ASC)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L107)SORT\_ORDER\_ASC **SORT\_ORDER\_ASC: 0 ### [**](#SORT_ORDER_DESC)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L108)SORT\_ORDER\_DESC **SORT\_ORDER\_DESC: 1 --- # UpdateType ## Index[**](#Index) ### Enumeration Members * [**DELETE](#DELETE) * [**DELETE\_ALL](#DELETE_ALL) * [**INCREMENT](#INCREMENT) * [**PUT](#PUT) ## Enumeration Members[**](<#Enumeration Members>) ### [**](#DELETE)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L33)DELETE **DELETE: DELETE ### [**](#DELETE_ALL)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L34)DELETE\_ALL **DELETE\_ALL: DELETE\_ALL ### [**](#INCREMENT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L35)INCREMENT **INCREMENT: INCREMENT ### [**](#PUT)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L32)PUT **PUT: PUT --- # formatRow ### Callable * **formatRow(row: any, filterColumn: any): {} --- # formatRows ### Callable * **formatRows(result: any, filterColumn: any): { list: any\[]; next: any } --- # BatchGetRowParams ## Index[**](#Index) ### Properties * [**tables](#tables) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#tables)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L301)tables **tables: { columnFilter? : [ColumnCondition](/api/tablestore/interface/ColumnCondition.md); columnsToGet? : string\[]; endColumn? : string; maxVersions? : number; primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[]\[]; startColumn? : string; tableName: string; timeRange? : { endTime? : string; specificTime? : string; startTime? : string } }\[] ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L315)optionaltransactionId **transactionId? : string --- # BatchWriteRowParams ## Index[**](#Index) ### Properties * [**tables](#tables) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#tables)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L337)tables **tables: { rows: [BatchWriteRowItem](/api/tablestore.md#BatchWriteRowItem)\[]; tableName: string }\[] ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L341)optionaltransactionId **transactionId? : string --- # ColumnCondition ### Hierarchy * *ColumnCondition* * [TableStoreSingleColumnCondition](/api/tablestore/interface/TableStoreSingleColumnCondition.md) --- # CreateIndexParams ## Index[**](#Index) ### Properties * [**indexMeta](#indexMeta) * [**mainTableName](#mainTableName) ## Properties[**](#Properties) ### [**](#indexMeta)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L577)indexMeta **indexMeta: { definedColumn: string\[]; includeBaseData? : boolean; indexType? : [IndexType](/api/tablestore/enum/IndexType.md); indexUpdateMode? : [IndexUpdateMode](/api/tablestore/enum/IndexUpdateMode.md); name: string; primaryKey: string\[] } ### [**](#mainTableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L576)mainTableName **mainTableName: string --- # CreateSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**schema](#schema) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L538)indexName **indexName: string ### [**](#schema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L539)schema **schema: [SearchIndexSchema](/api/tablestore/interface/SearchIndexSchema.md) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L537)tableName **tableName: string --- # CreateTableParams params ## Index[**](#Index) ### Properties * [**indexMetas](#indexMetas) * [**reservedThroughput](#reservedThroughput) * [**streamSpecification](#streamSpecification) * [**tableMeta](#tableMeta) * [**tableOptions](#tableOptions) ## Properties[**](#Properties) ### [**](#indexMetas)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L191)optionalindexMetas **indexMetas? : { definedColumn: string\[]; name: string; primaryKey: string\[] }\[] ### [**](#reservedThroughput)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L167)reservedThroughput **reservedThroughput: { capacityUnit: { read: number; write: number } } ### [**](#streamSpecification)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L184)optionalstreamSpecification **streamSpecification? : { enableStream? : boolean; expirationTime? : number } ### [**](#tableMeta)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L155)tableMeta **tableMeta: { definedColumn? : { name: string; type: [DefinedColumnType](/api/tablestore/enum/DefinedColumnType.md) }\[]; primaryKey: { name: string; option? : AUTO\_INCREMENT; type: [PrimaryKeyType](/api/tablestore/enum/PrimaryKeyType.md) }\[]; tableName: string } ### [**](#tableOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L173)optionaltableOptions **tableOptions? : { maxTimeDeviation? : number; maxVersions? : number; timeToLive? : number } --- # DeleteRowParams ## Index[**](#Index) ### Properties * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L274)optionalcondition **condition? : [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L273)primaryKey **primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L275)optionalreturnContent **returnContent? : { returnType? : [ReturnType](/api/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L272)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L278)optionaltransactionId **transactionId? : string --- # DeleteSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L544)indexName **indexName: string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L543)tableName **tableName: string --- # DeleteTableParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L201)tableName **tableName: string --- # DescribeSearchIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L350)indexName **indexName: string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L349)tableName **tableName: string --- # DescribeTableParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L212)tableName **tableName: string --- # DropIndexParams ## Index[**](#Index) ### Properties * [**indexName](#indexName) * [**mainTableName](#mainTableName) ## Properties[**](#Properties) ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L589)indexName **indexName: string ### [**](#mainTableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L588)mainTableName **mainTableName: string --- # GetRangeParams ## Index[**](#Index) ### Properties * [**columnFilter](#columnFilter) * [**columnsToGet](#columnsToGet) * [**direction](#direction) * [**endColumn](#endColumn) * [**exclusiveEndPrimaryKey](#exclusiveEndPrimaryKey) * [**inclusiveStartPrimaryKey](#inclusiveStartPrimaryKey) * [**limit](#limit) * [**maxVersions](#maxVersions) * [**startColumn](#startColumn) * [**tableName](#tableName) * [**timeRange](#timeRange) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#columnFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L287)optionalcolumnFilter **columnFilter? : [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) ### [**](#columnsToGet)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L296)optionalcolumnsToGet **columnsToGet? : string\[] ### [**](#direction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L285)direction **direction: [Direction](/api/tablestore/enum/Direction.md) ### [**](#endColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L295)optionalendColumn **endColumn? : string ### [**](#exclusiveEndPrimaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L284)exclusiveEndPrimaryKey **exclusiveEndPrimaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#inclusiveStartPrimaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L283)inclusiveStartPrimaryKey **inclusiveStartPrimaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L288)optionallimit **limit? : number ### [**](#maxVersions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L286)optionalmaxVersions **maxVersions? : number ### [**](#startColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L294)optionalstartColumn **startColumn? : string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L282)tableName **tableName: string ### [**](#timeRange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L289)optionaltimeRange **timeRange? : { endTime? : string; specificTime? : string; startTime? : string } ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L297)optionaltransactionId **transactionId? : string --- # GetRowParams ## Index[**](#Index) ### Properties * [**columnFilter](#columnFilter) * [**columnsToGet](#columnsToGet) * [**endColumn](#endColumn) * [**maxVersions](#maxVersions) * [**primaryKey](#primaryKey) * [**startColumn](#startColumn) * [**tableName](#tableName) * [**timeRange](#timeRange) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#columnFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L225)optionalcolumnFilter **columnFilter? : [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) ### [**](#columnsToGet)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L233)optionalcolumnsToGet **columnsToGet? : string\[] ### [**](#endColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L232)optionalendColumn **endColumn? : string ### [**](#maxVersions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L224)optionalmaxVersions **maxVersions? : number = \`\`\`ts 1 \`\`\` ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L219)primaryKey **primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#startColumn)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L231)optionalstartColumn **startColumn? : string ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L218)tableName **tableName: string ### [**](#timeRange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L226)optionaltimeRange **timeRange? : { endTime? : string; specificTime? : string; startTime? : string } ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L234)optionaltransactionId **transactionId? : string --- # ListSearchIndexParams ## Index[**](#Index) ### Properties * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L345)tableName **tableName: string --- # PutRowParams ## Index[**](#Index) ### Properties * [**attributeColumns](#attributeColumns) * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) ## Properties[**](#Properties) ### [**](#attributeColumns)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L251)optionalattributeColumns **attributeColumns? : [AttributeColumn](/api/tablestore.md#AttributeColumn)\[] ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L252)optionalcondition **condition? : [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L250)primaryKey **primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L253)optionalreturnContent **returnContent? : { returnType? : [ReturnType](/api/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L249)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L256)optionaltransactionId **transactionId? : string --- # SearchIndexFieldSchema ## Index[**](#Index) ### Properties * [**analyzer](#analyzer) * [**enableSortAndAgg](#enableSortAndAgg) * [**fieldName](#fieldName) * [**fieldSchemas](#fieldSchemas) * [**fieldType](#fieldType) * [**index](#index) * [**indexOptions](#indexOptions) * [**isAnArray](#isAnArray) * [**store](#store) ## Properties[**](#Properties) ### [**](#analyzer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L367)optionalanalyzer **analyzer? : string ### [**](#enableSortAndAgg)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L363)optionalenableSortAndAgg **enableSortAndAgg? : boolean 设置开启排序和统计功能 ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L354)fieldName **fieldName: string ### [**](#fieldSchemas)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L368)optionalfieldSchemas **fieldSchemas? : [SearchIndexFieldSchema](/api/tablestore/interface/SearchIndexFieldSchema.md)\[] ### [**](#fieldType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L355)fieldType **fieldType: [FieldType](/api/tablestore/enum/FieldType.md) ### [**](#index)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L359)optionalindex **index? : boolean 设置开启索引 ### [**](#indexOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L366)optionalindexOptions **indexOptions? : [IndexOptions](/api/tablestore/enum/IndexOptions.md) ### [**](#isAnArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L365)optionalisAnArray **isAnArray? : boolean ### [**](#store)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L364)optionalstore **store? : boolean --- # SearchIndexNestedFilter ## Index[**](#Index) ### Properties * [**filter](#filter) * [**path](#path) ## Properties[**](#Properties) ### [**](#filter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L502)optionalfilter **filter? : [SearchIndexQuery](/api/tablestore.md#SearchIndexQuery) ### [**](#path)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L501)optionalpath **path? : string --- # SearchIndexSchema ## Index[**](#Index) ### Properties * [**fieldSchemas](#fieldSchemas) * [**indexSetting](#indexSetting) * [**indexSort](#indexSort) ## Properties[**](#Properties) ### [**](#fieldSchemas)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L529)optionalfieldSchemas **fieldSchemas? : [SearchIndexFieldSchema](/api/tablestore/interface/SearchIndexFieldSchema.md)\[] ### [**](#indexSetting)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L530)optionalindexSetting **indexSetting? : [SearchIndexSetting](/api/tablestore/interface/SearchIndexSetting.md) ### [**](#indexSort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L531)optionalindexSort **indexSort? : { sorters: [SearchIndexSorter](/api/tablestore/interface/SearchIndexSorter.md)\[] } --- # SearchIndexSetting ## Index[**](#Index) ### Properties * [**routingFields](#routingFields) * [**routingPartitionSize](#routingPartitionSize) ## Properties[**](#Properties) ### [**](#routingFields)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L372)optionalroutingFields **routingFields? : string\[] ### [**](#routingPartitionSize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L373)optionalroutingPartitionSize **routingPartitionSize? : number --- # SearchIndexSorter ## Index[**](#Index) ### Properties * [**fieldSort](#fieldSort) * [**geoDistanceSort](#geoDistanceSort) * [**primaryKeySort](#primaryKeySort) * [**scoreSort](#scoreSort) ## Properties[**](#Properties) ### [**](#fieldSort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L506)optionalfieldSort **fieldSort? : { fieldName: string; mode? : [SortMode](/api/tablestore/enum/SortMode.md); nestedFilter? : [SearchIndexNestedFilter](/api/tablestore/interface/SearchIndexNestedFilter.md); order? : [SortOrder](/api/tablestore/enum/SortOrder.md) } ### [**](#geoDistanceSort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L512)optionalgeoDistanceSort **geoDistanceSort? : { distanceType? : [GeoDistanceType](/api/tablestore/enum/GeoDistanceType.md); fieldName: string; mode? : [SortMode](/api/tablestore/enum/SortMode.md); nestedFilter? : [SearchIndexNestedFilter](/api/tablestore/interface/SearchIndexNestedFilter.md); order? : [SortOrder](/api/tablestore/enum/SortOrder.md); points? : string\[] } ### [**](#primaryKeySort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L523)optionalprimaryKeySort **primaryKeySort? : { order? : [SortOrder](/api/tablestore/enum/SortOrder.md) } ### [**](#scoreSort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L520)optionalscoreSort **scoreSort? : { order? : [SortOrder](/api/tablestore/enum/SortOrder.md) } --- # SearchParams ## Index[**](#Index) ### Properties * [**columnToGet](#columnToGet) * [**indexName](#indexName) * [**routingValues](#routingValues) * [**searchQuery](#searchQuery) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#columnToGet)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L564)columnToGet **columnToGet: { returnNames: string\[]; returnType: [ColumnReturnType](/api/tablestore/enum/ColumnReturnType.md) } | { returnType: RETURN\_ALL | RETURN\_NONE } ### [**](#indexName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L562)indexName **indexName: string ### [**](#routingValues)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L572)optionalroutingValues **routingValues? : [PrimaryKey](/api/tablestore.md#PrimaryKey)\[]\[] ### [**](#searchQuery)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L563)searchQuery **searchQuery: [SearchQuery](/api/tablestore/interface/SearchQuery.md) ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L561)tableName **tableName: string --- # SearchQuery ## Index[**](#Index) ### Properties * [**getTotalCount](#getTotalCount) * [**limit](#limit) * [**offset](#offset) * [**query](#query) * [**sort](#sort) * [**token](#token) ## Properties[**](#Properties) ### [**](#getTotalCount)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L550)optionalgetTotalCount **getTotalCount? : boolean ### [**](#limit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L549)limit **limit: number ### [**](#offset)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L548)offset **offset: number ### [**](#query)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L555)optionalquery **query? : { queryType: [QueryType](/api/tablestore/enum/QueryType.md) } ### [**](#sort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L552)optionalsort **sort? : { sorters: [SearchIndexSorter](/api/tablestore/interface/SearchIndexSorter.md)\[] } ### [**](#token)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L551)optionaltoken **token? : string --- # StartLocalTransactionParams ## Index[**](#Index) ### Properties * [**primaryKey](#primaryKey) * [**tableName](#tableName) ## Properties[**](#Properties) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L594)primaryKey **primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L593)tableName **tableName: string --- # TableStoreClient ### Hierarchy * *TableStoreClient* * [TableStoreService](/api/tablestore/class/TableStoreService.md) ### Implemented by * [TableStoreService](/api/tablestore/class/TableStoreService.md) ## Index[**](#Index) ### Methods * [**abortTransaction](#abortTransaction) * [**batchGetRow](#batchGetRow) * [**batchWriteRow](#batchWriteRow) * [**commitTransaction](#commitTransaction) * [**createIndex](#createIndex) * [**createSearchIndex](#createSearchIndex) * [**createTable](#createTable) * [**deleteRow](#deleteRow) * [**deleteSearchIndex](#deleteSearchIndex) * [**deleteTable](#deleteTable) * [**describeSearchIndex](#describeSearchIndex) * [**describeTable](#describeTable) * [**dropIndex](#dropIndex) * [**getRange](#getRange) * [**getRow](#getRow) * [**listSearchIndex](#listSearchIndex) * [**listTable](#listTable) * [**putRow](#putRow) * [**search](#search) * [**startLocalTransaction](#startLocalTransaction) * [**updateRow](#updateRow) * [**updateTable](#updateTable) ## Methods[**](#Methods) ### [**](#abortTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L724)abortTransaction * **abortTransaction\(params: [AbortTransactionParams](/api/tablestore.md#AbortTransactionParams)): Promise\ - 丢弃事务 *** #### Type parameters * **R** = any ### [**](#batchGetRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L667)batchGetRow * **batchGetRow\(params: [BatchGetRowParams](/api/tablestore/interface/BatchGetRowParams.md)): Promise\ - 批量读取一个或多个表中的若干行数据。 *** #### Type parameters * **R** = any ### [**](#batchWriteRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L672)batchWriteRow * **batchWriteRow\(params: [BatchWriteRowParams](/api/tablestore/interface/BatchWriteRowParams.md)): Promise\ - 批量修改行 *** #### Type parameters * **R** = any ### [**](#commitTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L719)commitTransaction * **commitTransaction\(params: [CommitTransactionParams](/api/tablestore.md#CommitTransactionParams)): Promise\ - 提交事务 *** #### Type parameters * **R** = any ### [**](#createIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L702)createIndex * **createIndex\(params: [CreateIndexParams](/api/tablestore/interface/CreateIndexParams.md)): Promise\ - 创建GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#createSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L687)createSearchIndex * **createSearchIndex\(params: [CreateSearchIndexParams](/api/tablestore/interface/CreateSearchIndexParams.md)): Promise\ - SearchIndex创建新索引。 *** #### Type parameters * **R** = any ### [**](#createTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L614)createTable * **createTable\(params: [CreateTableParams](/api/tablestore/interface/CreateTableParams.md)): Promise\ - 根据给定的表结构信息创建相应的表。 *** #### Type parameters * **R** = any ### [**](#deleteRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L657)deleteRow * **deleteRow\(params: [DeleteRowParams](/api/tablestore/interface/DeleteRowParams.md)): Promise\ - 删除一行数据。 *** #### Type parameters * **R** = any ### [**](#deleteSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L692)deleteSearchIndex * **deleteSearchIndex\(params: [DeleteSearchIndexParams](/api/tablestore/interface/DeleteSearchIndexParams.md)): Promise\ - SearchIndex删除索引。 *** #### Type parameters * **R** = any ### [**](#deleteTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L624)deleteTable * **deleteTable\(params: [DeleteTableParams](/api/tablestore/interface/DeleteTableParams.md)): Promise\ - 删除本实例下指定的表。 *** #### Type parameters * **R** = any ### [**](#describeSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L682)describeSearchIndex * **describeSearchIndex\(params: [DescribeSearchIndexParams](/api/tablestore/interface/DescribeSearchIndexParams.md)): Promise\ - 获取SearchIndex索引描述信息。 *** #### Type parameters * **R** = any ### [**](#describeTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L634)describeTable * **describeTable\(params: [DescribeTableParams](/api/tablestore/interface/DescribeTableParams.md)): Promise\ - 查询指定表的结构信息和预留读/写吞吐量设置信息。 *** #### Type parameters * **R** = any ### [**](#dropIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L707)dropIndex * **dropIndex\(params: [DropIndexParams](/api/tablestore/interface/DropIndexParams.md)): Promise\ - 删除GlobalIndex索引名。 *** #### Type parameters * **R** = any ### [**](#getRange)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L662)getRange * **getRange\(params: [GetRangeParams](/api/tablestore/interface/GetRangeParams.md)): Promise\ - 读取指定主键范围内的数据。 *** #### Type parameters * **R** = any ### [**](#getRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L642)getRow * **getRow\(params: [GetRowParams](/api/tablestore/interface/GetRowParams.md)): Promise\ - 根据给定的主键读取单行数据。 *** #### Type parameters * **R** = any ### [**](#listSearchIndex)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L677)listSearchIndex * **listSearchIndex\(params: [ListSearchIndexParams](/api/tablestore/interface/ListSearchIndexParams.md)): Promise\ - 获取表下所有SearchIndex索引名。 *** #### Type parameters * **R** = any ### [**](#listTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L619)listTable * **listTable\(params: {}): Promise\ - 获取当前实例下已创建的所有表的表名。 *** #### Type parameters * **R** = any ### [**](#putRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L647)putRow * **putRow\(params: [PutRowParams](/api/tablestore/interface/PutRowParams.md)): Promise\ - 插入数据到指定的行,如果该行不存在,则新增一行;若该行存在,则覆盖原有行。 *** #### Type parameters * **R** = any ### [**](#search)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L697)search * **search\(params: [SearchParams](/api/tablestore/interface/SearchParams.md)): Promise\ - SearchIndex搜索。 *** #### Type parameters * **R** = any ### [**](#startLocalTransaction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L712)startLocalTransaction * **startLocalTransaction\(params: [StartLocalTransactionParams](/api/tablestore/interface/StartLocalTransactionParams.md)): Promise\ - 创建局部事务 *** #### Type parameters * **R** = any ### [**](#updateRow)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L652)updateRow * **updateRow\(params: [UpdateRowParams](/api/tablestore/interface/UpdateRowParams.md)): Promise\ - 更新指定行的数据。如果该行不存在,则新增一行;若该行存在,则根据请求的内容在这一行中新增、修改或者删除指定列的值。 *** #### Type parameters * **R** = any ### [**](#updateTable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L629)updateTable * **updateTable\(params: [UpdateTableParams](/api/tablestore/interface/UpdateTableParams.md)): Promise\ - 更新指定表的预留读吞吐量或预留写吞吐量设置。 *** #### Type parameters * **R** = any --- # TableStoreCompositeCondition ### Hierarchy * *TableStoreCompositeCondition* * [CompositeCondition](/api/tablestore/class/CompositeCondition.md) ## Index[**](#Index) ### Properties * [**sub\_conditions](#sub_conditions) ### Methods * [**addSubCondition](#addSubCondition) * [**clearSubCondition](#clearSubCondition) * [**getCombinator](#getCombinator) * [**getType](#getType) * [**setCombinator](#setCombinator) ## Properties[**](#Properties) ### [**](#sub_conditions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L754)sub\_conditions **sub\_conditions: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)\[] ## Methods[**](#Methods) ### [**](#addSubCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L762)addSubCondition * **addSubCondition(condition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)): void ### [**](#clearSubCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L764)clearSubCondition * **clearSubCondition(): void ### [**](#getCombinator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L760)getCombinator * **getCombinator(): [LogicalOperator](/api/tablestore/enum/LogicalOperator.md) ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L756)getType * **getType(): FT\_COMPOSITE\_COLUMN\_VALUE ### [**](#setCombinator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L758)setCombinator * **setCombinator(combinator: [LogicalOperator](/api/tablestore/enum/LogicalOperator.md)): void --- # TableStoreCondition ### Hierarchy * *TableStoreCondition* * [Condition](/api/tablestore/class/Condition.md) ## Index[**](#Index) ### Properties * [**columnCondition](#columnCondition) * [**rowExistenceExpectation](#rowExistenceExpectation) ### Methods * [**getColumnCondition](#getColumnCondition) * [**getRowExistenceExpectation](#getRowExistenceExpectation) * [**setColumnCondition](#setColumnCondition) * [**setRowExistenceExpectation](#setRowExistenceExpectation) ## Properties[**](#Properties) ### [**](#columnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L768)columnCondition **columnCondition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) ### [**](#rowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L769)rowExistenceExpectation **rowExistenceExpectation: [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md) ## Methods[**](#Methods) ### [**](#getColumnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L779)getColumnCondition * **getColumnCondition(): [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) ### [**](#getRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L775)getRowExistenceExpectation * **getRowExistenceExpectation(): [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md) ### [**](#setColumnCondition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L777)setColumnCondition * **setColumnCondition(columnCondition: [ColumnCondition](/api/tablestore/interface/ColumnCondition.md)): void ### [**](#setRowExistenceExpectation)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L771)setRowExistenceExpectation * **setRowExistenceExpectation(rowExistenceExpectation: [RowExistenceExpectation](/api/tablestore/enum/RowExistenceExpectation.md)): void --- # TableStoreConfig ## Index[**](#Index) ### Properties * [**accessKeyId](#accessKeyId) * [**accessKeySecret](#accessKeySecret) * [**computeChecksums](#computeChecksums) * [**endpoint](#endpoint) * [**httpOptions](#httpOptions) * [**instancename](#instancename) * [**logger](#logger) * [**maxRetries](#maxRetries) * [**secretAccessKey](#secretAccessKey) * [**securityToken](#securityToken) * [**stsToken](#stsToken) ## Properties[**](#Properties) ### [**](#accessKeyId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L833)accessKeyId **accessKeyId: string ### [**](#accessKeySecret)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L835)optionalaccessKeySecret **accessKeySecret? : string ### [**](#computeChecksums)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L854)optionalcomputeChecksums **computeChecksums? : boolean = \`\`\`ts true \`\`\` ### [**](#endpoint)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L839)endpoint **endpoint: string ### [**](#httpOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L840)optionalhttpOptions **httpOptions? : { maxSockets? : number; timeout? : number } ### [**](#instancename)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L849)instancename **instancename: string ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L838)optionallogger **logger? : any ### [**](#maxRetries)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L848)optionalmaxRetries **maxRetries? : number ### [**](#secretAccessKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L834)optionalsecretAccessKey **secretAccessKey? : string ### [**](#securityToken)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L837)optionalsecurityToken **securityToken? : string ### [**](#stsToken)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L836)optionalstsToken **stsToken? : string --- # TableStoreLong ## Index[**](#Index) ### Properties * [**int64](#int64) ### Methods * [**fromNumber](#fromNumber) * [**fromString](#fromString) * [**toBuffer](#toBuffer) * [**toNumber](#toNumber) ## Properties[**](#Properties) ### [**](#int64)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L783)optionalint64 **int64? : Int64LE ## Methods[**](#Methods) ### [**](#fromNumber)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L785)fromNumber * **fromNumber(num: number): Int64LE ### [**](#fromString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L787)fromString * **fromString(str: string): Int64LE ### [**](#toBuffer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L789)toBuffer * **toBuffer(): Buffer ### [**](#toNumber)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L791)toNumber * **toNumber(): number --- # TableStoreResult ## Index[**](#Index) ### Properties * [**primaryKey](#primaryKey) ## Properties[**](#Properties) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L601)primaryKey **primaryKey: \[{ name: string; value: any }] --- # TableStoreSingleColumnCondition \ ### Hierarchy * [ColumnCondition](/api/tablestore/interface/ColumnCondition.md) * *TableStoreSingleColumnCondition* * [SingleColumnCondition](/api/tablestore/class/SingleColumnCondition.md) ## Index[**](#Index) ### Properties * [**columnName](#columnName) * [**columnValue](#columnValue) * [**comparator](#comparator) * [**latestVersionOnly](#latestVersionOnly) * [**passIfMissing](#passIfMissing) ### Methods * [**getColumnName](#getColumnName) * [**getColumnValue](#getColumnValue) * [**getLatestVersionOnly](#getLatestVersionOnly) * [**getPassIfMissing](#getPassIfMissing) * [**getType](#getType) * [**setColumnName](#setColumnName) * [**setColumnValue](#setColumnValue) * [**setComparator](#setComparator) * [**setLatestVersionOnly](#setLatestVersionOnly) * [**setPassIfMissing](#setPassIfMissing) ## Properties[**](#Properties) ### [**](#columnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L797)columnName **columnName: string ### [**](#columnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L798)columnValue **columnValue: T ### [**](#comparator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L799)comparator **comparator: [ComparatorType](/api/tablestore/enum/ComparatorType.md) ### [**](#latestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L801)latestVersionOnly **latestVersionOnly: boolean ### [**](#passIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L800)passIfMissing **passIfMissing: boolean ## Methods[**](#Methods) ### [**](#getColumnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L823)getColumnName * **getColumnName(): string ### [**](#getColumnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L827)getColumnValue * **getColumnValue(): T ### [**](#getLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L819)getLatestVersionOnly * **getLatestVersionOnly(): boolean ### [**](#getPassIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L815)getPassIfMissing * **getPassIfMissing(): boolean ### [**](#getType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L803)getType * **getType(): FT\_SINGLE\_COLUMN\_VALUE ### [**](#setColumnName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L821)setColumnName * **setColumnName(columnName: string): void ### [**](#setColumnValue)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L825)setColumnValue * **setColumnValue(columnValue: T): void ### [**](#setComparator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L829)setComparator * **setComparator(comparator: [ComparatorType](/api/tablestore/enum/ComparatorType.md)): void ### [**](#setLatestVersionOnly)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L817)setLatestVersionOnly * **setLatestVersionOnly(latestVersionOnly: boolean): void ### [**](#setPassIfMissing)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L813)setPassIfMissing * **setPassIfMissing(passIfMissing: boolean): void - 设置 `passIfMissing` 由于OTS一行的属性列不固定,有可能存在有condition条件的列在该行不存在的情况,这时 参数控制在这种情况下对该行的检查结果。 如果设置为True,则若列在该行中不存在,则检查条件通过。 如果设置为False,则若列在该行中不存在,则检查条件失败。 默认值为True。 --- # UpdateRowParams ## Index[**](#Index) ### Properties * [**condition](#condition) * [**primaryKey](#primaryKey) * [**returnContent](#returnContent) * [**tableName](#tableName) * [**transactionId](#transactionId) * [**updateOfAttributeColumns](#updateOfAttributeColumns) ## Properties[**](#Properties) ### [**](#condition)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L263)optionalcondition **condition? : [TableStoreCondition](/api/tablestore/interface/TableStoreCondition.md) ### [**](#primaryKey)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L261)primaryKey **primaryKey: [PrimaryKey](/api/tablestore.md#PrimaryKey)\[] ### [**](#returnContent)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L264)optionalreturnContent **returnContent? : { returnColumns? : string\[]; returnType? : [ReturnType](/api/tablestore/enum/ReturnType.md) } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L260)tableName **tableName: string ### [**](#transactionId)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L268)optionaltransactionId **transactionId? : string ### [**](#updateOfAttributeColumns)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L262)updateOfAttributeColumns **updateOfAttributeColumns: [UpdateColumn](/api/tablestore.md#UpdateColumn)\[] --- # UpdateTableParams ## Index[**](#Index) ### Properties * [**reservedThroughput](#reservedThroughput) * [**streamSpecification](#streamSpecification) * [**tableName](#tableName) * [**tableOptions](#tableOptions) ## Properties[**](#Properties) ### [**](#reservedThroughput)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L206)reservedThroughput **reservedThroughput: { capacityUnit: { read: number; write: number } } ### [**](#streamSpecification)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L208)optionalstreamSpecification **streamSpecification? : { enableStream? : boolean; expirationTime? : number } ### [**](#tableName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L205)tableName **tableName: string ### [**](#tableOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tablestore/src/interface.ts#L207)tableOptions **tableOptions: { maxTimeDeviation? : number; maxVersions? : number; timeToLive? : number } --- # @midwayjs/tenant ## Index[**](#Index) ### Classes * [**Configuration](/api/tenant/class/Configuration.md) * [**TenantManager](/api/tenant/class/TenantManager.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TenantConfiguration](/api/tenant/class/Configuration.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tenant/src/configuration.ts#L17)onReady * **onReady(container: IMidwayContainer): Promise\ --- # TenantManager ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**getCurrentTenant](#getCurrentTenant) * [**setCurrentTenant](#setCurrentTenant) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TenantManager(): [TenantManager](/api/tenant/class/TenantManager.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tenant/src/tenantManager.ts#L17)applicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#getCurrentTenant)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tenant/src/tenantManager.ts#L19)getCurrentTenant * **getCurrentTenant\(): Promise\ - #### Type parameters * **T** = any ### [**](#setCurrentTenant)[**](https://github.com/midwayjs/midway/blob/3.x/packages/tenant/src/tenantManager.ts#L33)setCurrentTenant * **setCurrentTenant\(currentTenant: T): Promise\ - #### Type parameters * **T** = any --- # @midwayjs/typegoose ## Index[**](#Index) ### Classes * [**Configuration](/api/typegoose/class/Configuration.md) ### Functions * [**EntityModel](/api/typegoose/function/EntityModel.md) * [**InjectEntityModel](/api/typegoose/function/InjectEntityModel.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**decoratorService](#decoratorService) * [**legacyMode](#legacyMode) * [**modelMap](#modelMap) * [**oldMongooseConfig](#oldMongooseConfig) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [TypegooseConfiguration](/api/typegoose/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L29)app **app: IMidwayBaseApplication\ ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L32)decoratorService **decoratorService: MidwayDecoratorService ### [**](#legacyMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L26)legacyMode **legacyMode: boolean = false ### [**](#modelMap)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L34)modelMap **modelMap: WeakMap\ = ... ### [**](#oldMongooseConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L24)oldMongooseConfig **oldMongooseConfig: any ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L37)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L52)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typegoose/src/configuration.ts#L92)onStop * **onStop(): Promise\ --- # EntityModel ### Callable * **EntityModel(options? : EntityOptions): ClassDecorator --- # InjectEntityModel ### Callable * **InjectEntityModel(modelKey: any): PropertyDecorator --- # @midwayjs/typeorm ## Index[**](#Index) ### Classes * [**Configuration](/api/typeorm/class/Configuration.md) * [**TypeORMDataSourceManager](/api/typeorm/class/TypeORMDataSourceManager.md) ### Functions * [**EventSubscriberModel](/api/typeorm/function/EventSubscriberModel.md) * [**InjectDataSource](/api/typeorm/function/InjectDataSource.md) * [**InjectEntityModel](/api/typeorm/function/InjectEntityModel.md) ### Type Aliases * [**typeormConfigOptions](/api/typeorm.md#typeormConfigOptions) ### Variables * [**ENTITY\_MODEL\_KEY](/api/typeorm.md#ENTITY_MODEL_KEY) * [**EVENT\_SUBSCRIBER\_KEY](/api/typeorm.md#EVENT_SUBSCRIBER_KEY) * [**ORM\_DATA\_SOURCE\_KEY](/api/typeorm.md#ORM_DATA_SOURCE_KEY) * [**ORM\_MODEL\_KEY](/api/typeorm.md#ORM_MODEL_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#typeormConfigOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/interface.ts#L4)typeormConfigOptions **typeormConfigOptions: DataSourceManagerConfigOption\ & { allowExecuteMigrations: boolean } ## Variables[**](#Variables) ### [**](#ENTITY_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/decorator.ts#L4)constENTITY\_MODEL\_KEY **ENTITY\_MODEL\_KEY: typeorm:entity\_model\_key = 'typeorm:entity\_model\_key' ### [**](#EVENT_SUBSCRIBER_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/decorator.ts#L5)constEVENT\_SUBSCRIBER\_KEY **EVENT\_SUBSCRIBER\_KEY: typeorm:event\_subscriber\_key = 'typeorm:event\_subscriber\_key' ### [**](#ORM_DATA_SOURCE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/decorator.ts#L7)constORM\_DATA\_SOURCE\_KEY **ORM\_DATA\_SOURCE\_KEY: typeorm:data\_source\_key = 'typeorm:data\_source\_key' ### [**](#ORM_MODEL_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/decorator.ts#L6)constORM\_MODEL\_KEY **ORM\_MODEL\_KEY: typeorm:orm\_model\_key = 'typeorm:orm\_model\_key' --- # Configuration ### Implements * ILifeCycle ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**dataSourceManager](#dataSourceManager) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [OrmConfiguration](/api/typeorm/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L47)app **app: IMidwayBaseApplication\ ### [**](#dataSourceManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L52)dataSourceManager **dataSourceManager: [TypeORMDataSourceManager](/api/typeorm/class/TypeORMDataSourceManager.md) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L50)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L55)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L107)onReady * **onReady(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onReady ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/configuration.ts#L112)onStop * **onStop(container: IMidwayContainer): Promise\ - Implementation of ILifeCycle.onStop --- # TypeORMDataSourceManager ### Hierarchy * DataSourceManager\ * *TypeORMDataSourceManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**loggerService](#loggerService) * [**typeormConfig](#typeormConfig) ### Methods * [**createInstance](#createInstance) * [**getAllDataSources](#getAllDataSources) * [**getDataSource](#getDataSource) * [**getDataSourceNameByModel](#getDataSourceNameByModel) * [**getDataSourceNames](#getDataSourceNames) * [**getDataSourcePriority](#getDataSourcePriority) * [**getDefaultDataSourceName](#getDefaultDataSourceName) * [**getName](#getName) * [**hasDataSource](#hasDataSource) * [**init](#init) * [**isConnected](#isConnected) * [**isHighPriority](#isHighPriority) * [**isLowPriority](#isLowPriority) * [**isMediumPriority](#isMediumPriority) * [**stop](#stop) * [**formatGlobString](#formatGlobString) * [**globModels](#globModels) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new TypeORMDataSourceManager(): [TypeORMDataSourceManager](/api/typeorm/class/TypeORMDataSourceManager.md) - Inherited from DataSourceManager\.constructor ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/dataSourceManager.ts#L24)applicationContext **applicationContext: IMidwayContainer ### [**](#loggerService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/dataSourceManager.ts#L27)loggerService **loggerService: MidwayLoggerService ### [**](#typeormConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/dataSourceManager.ts#L21)typeormConfig **typeormConfig: [typeormConfigOptions](/api/typeorm.md#typeormConfigOptions) ## Methods[**](#Methods) ### [**](#createInstance)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L36)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L37)createInstance * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>): Promise\ * **createInstance(config: BaseDataSourceManagerConfigOption\, entities>, clientName: string, options? : { cacheInstance? : boolean; validateConnection? : boolean }): Promise\ - Inherited from DataSourceManager.createInstance ### [**](#getAllDataSources)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L30)getAllDataSources * **getAllDataSources(): Map\ - Inherited from DataSourceManager.getAllDataSources ### [**](#getDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L23)getDataSource * **getDataSource(dataSourceName: string): DataSource - Inherited from DataSourceManager.getDataSource get a data source instance ### [**](#getDataSourceNameByModel)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L51)getDataSourceNameByModel * **getDataSourceNameByModel(modelOrRepository: any): string - Inherited from DataSourceManager.getDataSourceNameByModel get data source name by model or repository ### [**](#getDataSourceNames)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L29)getDataSourceNames * **getDataSourceNames(): string\[] - Inherited from DataSourceManager.getDataSourceNames ### [**](#getDataSourcePriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L61)getDataSourcePriority * **getDataSourcePriority(name: string): string - Inherited from DataSourceManager.getDataSourcePriority ### [**](#getDefaultDataSourceName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L60)getDefaultDataSourceName * **getDefaultDataSourceName(): string - Inherited from DataSourceManager.getDefaultDataSourceName ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/dataSourceManager.ts#L36)getName * **getName(): string - Overrides DataSourceManager.getName ### [**](#hasDataSource)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L28)hasDataSource * **hasDataSource(dataSourceName: string): boolean - Inherited from DataSourceManager.hasDataSource check data source has exists ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/typeorm/src/dataSourceManager.ts#L30)init * **init(): Promise\ ### [**](#isConnected)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L35)isConnected * **isConnected(dataSourceName: string): Promise\ - Inherited from DataSourceManager.isConnected check the data source is connected ### [**](#isHighPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L62)isHighPriority * **isHighPriority(name: string): boolean - Inherited from DataSourceManager.isHighPriority ### [**](#isLowPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L64)isLowPriority * **isLowPriority(name: string): boolean - Inherited from DataSourceManager.isLowPriority ### [**](#isMediumPriority)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L63)isMediumPriority * **isMediumPriority(name: string): boolean - Inherited from DataSourceManager.isMediumPriority ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L59)stop * **stop(): Promise\ - Inherited from DataSourceManager.stop Call destroyDataSource() on all data sources ### [**](#formatGlobString)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L65)staticformatGlobString * **formatGlobString(globString: string): string\[] - Inherited from DataSourceManager.formatGlobString ### [**](#globModels)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/common/dataSourceManager.d.ts#L66)staticglobModels * **globModels(globString: string, baseDir: string, loadMode? : ModuleLoadType): Promise\ - Inherited from DataSourceManager.globModels --- # EventSubscriberModel ### Callable * **EventSubscriberModel(): ClassDecorator *** * EventSubscriber - typeorm implements EntitySubscriberInterface --- # InjectDataSource ### Callable * **InjectDataSource(dataSourceName? : string): PropertyDecorator --- # InjectEntityModel ### Callable * **InjectEntityModel(modelKey: EntityTarget\, connectionName? : string): PropertyDecorator --- # @midwayjs/upload ## Index[**](#Index) ### Classes * [**Configuration](/api/upload/class/Configuration.md) * [**MultipartInvalidFileTypeError](/api/upload/class/MultipartInvalidFileTypeError.md) * [**MultipartInvalidFilenameError](/api/upload/class/MultipartInvalidFilenameError.md) * [**UploadMiddleware](/api/upload/class/UploadMiddleware.md) ### Interfaces * [**UploadFileInfo](/api/upload/interface/UploadFileInfo.md) * [**UploadOptions](/api/upload/interface/UploadOptions.md) ### Type Aliases * [**UploadMode](/api/upload.md#UploadMode) ### Variables * [**DefaultUploadFileMimeType](/api/upload.md#DefaultUploadFileMimeType) * [**EXT\_KEY](/api/upload.md#EXT_KEY) * [**uploadWhiteList](/api/upload.md#uploadWhiteList) ## Type Aliases[**](<#Type Aliases>) ### [**](#UploadMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L4)UploadMode **UploadMode: stream | file ## Variables[**](#Variables) ### [**](#DefaultUploadFileMimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/constants.ts#L36)constDefaultUploadFileMimeType **DefaultUploadFileMimeType: { .avi: string; .bmp: string; .gif: string; .gz: string; .gzip: string; .jpeg: string; .jpg: string; .mp3: string; .mp4: string; .pdf: string; .png: string; .psd: string; .svg: string; .tif: string; .tiff: string; .wbmp: string; .webp: string; .xml: string; .zip: string } = ... ### [**](#EXT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/constants.ts#L58)constEXT\_KEY **EXT\_KEY: typeof [EXT\_KEY](/api/upload.md#EXT_KEY) = ... ### [**](#uploadWhiteList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/constants.ts#L1)constuploadWhiteList **uploadWhiteList: string\[] = ... --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) * [**uploadConfig](#uploadConfig) ### Methods * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [UploadConfiguration](/api/upload/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/configuration.ts#L25)applicationManager **applicationManager: MidwayApplicationManager ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/configuration.ts#L28)uploadConfig **uploadConfig: [UploadOptions](/api/upload/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/configuration.ts#L30)onReady * **onReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/configuration.ts#L45)onStop * **onStop(): Promise\ --- # MultipartInvalidFilenameError ### Hierarchy * BadRequestError * *MultipartInvalidFilenameError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/error.ts#L4)constructor * **new MultipartInvalidFilenameError(filename: string): [MultipartInvalidFilenameError](/api/upload/class/MultipartInvalidFilenameError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # MultipartInvalidFileTypeError ### Hierarchy * BadRequestError * *MultipartInvalidFileTypeError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/error.ts#L10)constructor * **new MultipartInvalidFileTypeError(filename: string, currentType: string, type: string): [MultipartInvalidFileTypeError](/api/upload/class/MultipartInvalidFileTypeError.md) - Overrides httpError.BadRequestError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from httpError.BadRequestError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from httpError.BadRequestError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from httpError.BadRequestError.status --- # UploadMiddleware ### Implements * IMiddleware\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ignore](#ignore) * [**logger](#logger) * [**match](#match) * [**uploadConfig](#uploadConfig) ### Methods * [**checkAndGetExt](#checkAndGetExt) * [**checkFileType](#checkFileType) * [**execUpload](#execUpload) * [**getUploadBoundary](#getUploadBoundary) * [**init](#init) * [**isReadableStream](#isReadableStream) * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new UploadMiddleware(): [UploadMiddleware](/api/upload/class/UploadMiddleware.md) ## Properties[**](#Properties) ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L46)ignore **ignore: IgnoreMatcher\\[] Implementation of IMiddleware.ignore ### [**](#logger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L33)logger **logger: ILogger ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L45)match **match: IgnoreMatcher\\[] Implementation of IMiddleware.match ### [**](#uploadConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L30)uploadConfig **uploadConfig: [UploadOptions](/api/upload/interface/UploadOptions.md) ## Methods[**](#Methods) ### [**](#checkAndGetExt)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L263)checkAndGetExt * **checkAndGetExt(filename: any, whiteListMap? : Map\): string | boolean ### [**](#checkFileType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L283)checkFileType * **checkFileType(ext: string, data: Buffer, uploadFileMimeTypeMap? : Map\): Promise<{ current? : string; mime? : string; passed: boolean }> ### [**](#execUpload)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L84)execUpload * **execUpload(ctx: any, req: any, res: any, next: any, isExpress: any): Promise\ ### [**](#getUploadBoundary)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L221)getUploadBoundary * **getUploadBoundary(request: any): string | false ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L49)init * **init(): Promise\ ### [**](#isReadableStream)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L246)isReadableStream * **isReadableStream(req: any, isExpress: any): boolean ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L57)resolve * **resolve(app: any): (req: any, res: any, next: any) => Promise\ - Implementation of IMiddleware.resolve ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/middleware.ts#L312)staticgetName * **getName(): string --- # UploadFileInfo \ ## Index[**](#Index) ### Properties * [**data](#data) * [**fieldName](#fieldName) * [**filename](#filename) * [**mimeType](#mimeType) ## Properties[**](#Properties) ### [**](#data)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L55)data **data: T extends string ? string : Readable ### [**](#fieldName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L53)fieldName **fieldName: string ### [**](#filename)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L52)filename **filename: string ### [**](#mimeType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L54)mimeType **mimeType: string --- # UploadOptions ## Index[**](#Index) ### Properties * [**allowFieldsDuplication](#allowFieldsDuplication) * [**base64](#base64) * [**cleanTimeout](#cleanTimeout) * [**fileSize](#fileSize) * [**ignore](#ignore) * [**match](#match) * [**mimeTypeWhiteList](#mimeTypeWhiteList) * [**mode](#mode) * [**tmpdir](#tmpdir) * [**whitelist](#whitelist) ## Properties[**](#Properties) ### [**](#allowFieldsDuplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L48)optionalallowFieldsDuplication **allowFieldsDuplication? : boolean Whether to allow fields duplication, default is `false` ### [**](#base64)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L30)optionalbase64 **base64? : boolean Whether the uploaded body is base64, for example, apigw of Tencent Cloud ### [**](#cleanTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L26)optionalcleanTimeout **cleanTimeout? : number Temporary file automatic cleanup time, default is 5 minutes ### [**](#fileSize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L14)optionalfileSize **fileSize? : string Max file size (in bytes), default is `10mb` ### [**](#ignore)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L34)optionalignore **ignore? : IgnoreMatcher\ | IgnoreMatcher\\[] Which paths to ignore ### [**](#match)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L38)optionalmatch **match? : IgnoreMatcher\ | IgnoreMatcher\\[] Match those paths with higher priority than ignore ### [**](#mimeTypeWhiteList)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L42)optionalmimeTypeWhiteList **mimeTypeWhiteList? : Record\ | (ctx: any) => string | string\[] Mime type white list ### [**](#mode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L10)optionalmode **mode? : [UploadMode](/api/upload.md#UploadMode) Upload mode, default is `file` ### [**](#tmpdir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L22)optionaltmpdir **tmpdir? : string Temporary file directory ### [**](#whitelist)[**](https://github.com/midwayjs/midway/blob/3.x/packages/upload/src/interface.ts#L18)optionalwhitelist **whitelist? : string\[] | (ctx: any) => string\[] The white ext file names --- # @midwayjs/validate ## Index[**](#Index) ### Classes * [**AbstractValidationPipe](/api/validate/class/AbstractValidationPipe.md) * [**Configuration](/api/validate/class/Configuration.md) * [**DecoratorValidPipe](/api/validate/class/DecoratorValidPipe.md) * [**DefaultValuePipe](/api/validate/class/DefaultValuePipe.md) * [**MidwayValidationError](/api/validate/class/MidwayValidationError.md) * [**ParseBoolPipe](/api/validate/class/ParseBoolPipe.md) * [**ParseFloatPipe](/api/validate/class/ParseFloatPipe.md) * [**ParseIntPipe](/api/validate/class/ParseIntPipe.md) * [**ParsePipe](/api/validate/class/ParsePipe.md) * [**ValidateService](/api/validate/class/ValidateService.md) * [**ValidationPipe](/api/validate/class/ValidationPipe.md) ### Functions * [**OmitDto](/api/validate/function/OmitDto.md) * [**PickDto](/api/validate/function/PickDto.md) * [**Rule](/api/validate/function/Rule.md) * [**Valid](/api/validate/function/Valid.md) * [**Validate](/api/validate/function/Validate.md) * [**getSchema](/api/validate/function/getSchema.md) ### Interfaces * [**Dto](/api/validate/interface/Dto.md) * [**ValidateOptions](/api/validate/interface/ValidateOptions.md) --- # abstractAbstractValidationPipe ### Hierarchy * *AbstractValidationPipe* * [ValidationPipe](/api/validate/class/ValidationPipe.md) * [ParsePipe](/api/validate/class/ParsePipe.md) ### Implements * PipeTransform ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AbstractValidationPipe(): [AbstractValidationPipe](/api/validate/class/AbstractValidationPipe.md) ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L18)abstracttransform * **transform(value: any, options: TransformOptions\): any - Implementation of PipeTransform.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**decoratorService](#decoratorService) * [**validateService](#validateService) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ValidateConfiguration](/api/validate/class/Configuration.md) ## Properties[**](#Properties) ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/configuration.ts#L32)decoratorService **decoratorService: MidwayDecoratorService ### [**](#validateService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/configuration.ts#L35)validateService **validateService: [ValidateService](/api/validate/class/ValidateService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/configuration.ts#L38)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/configuration.ts#L50)onReady * **onReady(container: IMidwayContainer): Promise\ --- # DecoratorValidPipe ### Hierarchy * [ParsePipe](/api/validate/class/ParsePipe.md) * *DecoratorValidPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DecoratorValidPipe(): [DecoratorValidPipe](/api/validate/class/DecoratorValidPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L89)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # DefaultValuePipe \ ### Implements * PipeTransform\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L123)constructor * **new DefaultValuePipe\(defaultValue: R): [DefaultValuePipe](/api/validate/class/DefaultValuePipe.md)\ - #### Type parameters * **T** = any * **R** = any ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L124)transform * **transform(value: any, options: any): any - Implementation of PipeTransform.transform --- # MidwayValidationError ### Hierarchy * MidwayHttpError * *MidwayValidationError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/error.ts#L8)constructor * **new MidwayValidationError(message: any, status: any, cause: any): [MidwayValidationError](/api/validate/class/MidwayValidationError.md) - Overrides MidwayHttpError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayHttpError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayHttpError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from MidwayHttpError.status --- # ParseBoolPipe ### Hierarchy * [ParsePipe](/api/validate/class/ParsePipe.md) * *ParseBoolPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseBoolPipe(): [ParseBoolPipe](/api/validate/class/ParseBoolPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L110)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L89)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # ParseFloatPipe ### Hierarchy * [ParsePipe](/api/validate/class/ParsePipe.md) * *ParseFloatPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseFloatPipe(): [ParseFloatPipe](/api/validate/class/ParseFloatPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L117)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L89)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # ParseIntPipe ### Hierarchy * [ParsePipe](/api/validate/class/ParsePipe.md) * *ParseIntPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseIntPipe(): [ParseIntPipe](/api/validate/class/ParseIntPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L103)getSchema * **getSchema(): AnySchema\ - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L89)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from ParsePipe.validateWithSchema --- # abstractParsePipe ### Hierarchy * [AbstractValidationPipe](/api/validate/class/AbstractValidationPipe.md) * *ParsePipe* * [DecoratorValidPipe](/api/validate/class/DecoratorValidPipe.md) * [ParseIntPipe](/api/validate/class/ParseIntPipe.md) * [ParseBoolPipe](/api/validate/class/ParseBoolPipe.md) * [ParseFloatPipe](/api/validate/class/ParseFloatPipe.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParsePipe(): [ParsePipe](/api/validate/class/ParsePipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L89)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from AbstractValidationPipe.validateWithSchema --- # ValidateService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidateService(): [ValidateService](/api/validate/class/ValidateService.md) ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/service.ts#L100)publicgetSchema * **getSchema\(ClzType: T): ObjectSchema\ - #### Type parameters * **T**: new (...args: any\[]) => any ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/service.ts#L41)publicvalidate * **validate\(ClzType: T, value: any, options? : { errorStatus? : number; locale? : string; validationOptions? : ValidationOptions }): ValidationResult\ - #### Type parameters * **T**: new (...args: any\[]) => any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/service.ts#L54)publicvalidateWithSchema * **validateWithSchema\(schema: AnySchema\, value: any, options? : { errorStatus? : number; locale? : string; validationOptions? : ValidationOptions }): ValidationResult\ - #### Type parameters * **T** --- # ValidationPipe ### Hierarchy * [AbstractValidationPipe](/api/validate/class/AbstractValidationPipe.md) * *ValidationPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidationPipe(): [ValidationPipe](/api/validate/class/ValidationPipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L83)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L37)validate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/pipe.ts#L20)validateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: AnySchema\): any - Inherited from AbstractValidationPipe.validateWithSchema --- # getSchema ### Callable * **getSchema\(ClzType: T): ObjectSchema\ *** * #### Type parameters * **T**: new (...args: any\[]) => any --- # OmitDto ### Callable * **OmitDto\(dto: [Dto](/api/validate/interface/Dto.md)\, keys: K\[]): [Dto](/api/validate/interface/Dto.md)\> *** * #### Type parameters * **T** * **K**: string | number | symbol --- # PickDto ### Callable * **PickDto\(dto: [Dto](/api/validate/interface/Dto.md)\, keys: K\[]): [Dto](/api/validate/interface/Dto.md)\> *** * #### Type parameters * **T** * **K**: string | number | symbol --- # Rule ### Callable * **Rule(rule: AnySchema\): PropertyDecorator --- # Valid ### Callable * **Valid(schemaOrPipes? : PipeUnionTransform\[] | AnySchema\, pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Validate ### Callable * **Validate(options? : [ValidateOptions](/api/validate/interface/ValidateOptions.md)): (target: any, methodName: any, descriptor: any) => void --- # Dto \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/dtoHelper.ts#L4)constructor * **new Dto(): T --- # ValidateOptions ## Index[**](#Index) ### Properties * [**errorStatus](#errorStatus) * [**locale](#locale) * [**validationOptions](#validationOptions) ## Properties[**](#Properties) ### [**](#errorStatus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/decorator/validate.ts#L6)optionalerrorStatus **errorStatus? : number ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/decorator/validate.ts#L7)optionallocale **locale? : string ### [**](#validationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validate/src/decorator/validate.ts#L8)optionalvalidationOptions **validationOptions? : ValidationOptions --- # @midwayjs/validation ## Index[**](#Index) ### Classes * [**AbstractValidationPipe](/api/validation/class/AbstractValidationPipe.md) * [**Configuration](/api/validation/class/Configuration.md) * [**DecoratorValidPipe](/api/validation/class/DecoratorValidPipe.md) * [**DefaultValuePipe](/api/validation/class/DefaultValuePipe.md) * [**MidwayValidationError](/api/validation/class/MidwayValidationError.md) * [**MidwayValidatorNotFoundError](/api/validation/class/MidwayValidatorNotFoundError.md) * [**ParseBoolPipe](/api/validation/class/ParseBoolPipe.md) * [**ParseFloatPipe](/api/validation/class/ParseFloatPipe.md) * [**ParseIntPipe](/api/validation/class/ParseIntPipe.md) * [**ParsePipe](/api/validation/class/ParsePipe.md) * [**ValidationPipe](/api/validation/class/ValidationPipe.md) * [**ValidationService](/api/validation/class/ValidationService.md) ### Functions * [**OmitDto](/api/validation/function/OmitDto.md) * [**PartialDto](/api/validation/function/PartialDto.md) * [**PickDto](/api/validation/function/PickDto.md) * [**RequiredDto](/api/validation/function/RequiredDto.md) * [**Rule](/api/validation/function/Rule.md) * [**Valid](/api/validation/function/Valid.md) * [**Validate](/api/validation/function/Validate.md) * [**getRuleMeta](/api/validation/function/getRuleMeta.md) * [**getSchema](/api/validation/function/getSchema.md) ### Interfaces * [**Dto](/api/validation/interface/Dto.md) * [**IValidationService](/api/validation/interface/IValidationService.md) * [**IValidator](/api/validation/interface/IValidator.md) * [**IValidatorModule](/api/validation/interface/IValidatorModule.md) * [**SchemaHelper](/api/validation/interface/SchemaHelper.md) * [**ValidateResult](/api/validation/interface/ValidateResult.md) * [**ValidationDecoratorOptions](/api/validation/interface/ValidationDecoratorOptions.md) * [**ValidationExtendOptions](/api/validation/interface/ValidationExtendOptions.md) * [**ValidationOptions](/api/validation/interface/ValidationOptions.md) ### Type Aliases * [**ValidatorLike](/api/validation.md#ValidatorLike) ### Variables * [**RULES\_KEY](/api/validation.md#RULES_KEY) * [**VALIDATE\_KEY](/api/validation.md#VALIDATE_KEY) * [**VALID\_KEY](/api/validation.md#VALID_KEY) * [**registry](/api/validation.md#registry) ## Type Aliases[**](<#Type Aliases>) ### [**](#ValidatorLike)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L7)ValidatorLike **ValidatorLike\: [IValidator](/api/validation/interface/IValidator.md)\ | [IValidatorModule](/api/validation/interface/IValidatorModule.md)\ #### Type parameters * **Schema** ## Variables[**](#Variables) ### [**](#RULES_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/constants.ts#L1)constRULES\_KEY **RULES\_KEY: validation:rules = 'validation:rules' ### [**](#VALIDATE_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/constants.ts#L2)constVALIDATE\_KEY **VALIDATE\_KEY: validation:validate = 'validation:validate' ### [**](#VALID_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/constants.ts#L3)constVALID\_KEY **VALID\_KEY: validation:valid = 'validation:valid' ### [**](#registry)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/registry.ts#L71)constregistry **registry: ValidatorRegistry = ... --- # @midwayjs/validation-class-validator ## Index[**](#Index) ### Classes * [**ClassValidatorService](/api/validation-class-validator/class/ClassValidatorService.md) ### Variables * [**default](/api/validation-class-validator.md#default) ## Variables[**](#Variables) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation-class-validator/src/index.ts#L229)default **default: { schemaHelper: { getSwaggerPropertyKeys: (ClzType: any) => string\[]; getSwaggerPropertyMetadata: (ClzType: any, propertyName: string) => Record\; isOptional: (ClzType: any, propertyName: string) => boolean; isRequired: (ClzType: any, propertyName: string) => boolean; setOptional: (ClzType: any, propertyName? : string) => void; setRequired: (ClzType: any, propertyName? : string) => void; getBoolSchema: any; getFloatSchema: any; getIntSchema: any; getSchema: any; getStringSchema: any }; validateServiceHandler: (container: IMidwayContainer) => [ClassValidatorService](/api/validation-class-validator/class/ClassValidatorService.md) } --- # ClassValidatorService ### Implements * IValidationService\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**init](#init) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ClassValidatorService(): [ClassValidatorService](/api/validation-class-validator/class/ClassValidatorService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation-class-validator/src/index.ts#L166)init * **init(container: IMidwayContainer): Promise\ - Implementation of IValidationService.init ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation-class-validator/src/index.ts#L182)validateWithSchema * **validateWithSchema(schema: any, value: any, validationOptions: ValidationExtendOptions, validatorOptions? : ValidatorOptions): ValidateResult - Implementation of IValidationService.validateWithSchema --- # @midwayjs/validation-joi ## Index[**](#Index) ### Variables * [**default](/api/validation-joi.md#default) ## Variables[**](#Variables) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation-joi/src/index.ts#L83)default **default: { schemaHelper: { getBoolSchema: () => BooleanSchema\; getFloatSchema: () => NumberSchema\; getIntSchema: () => NumberSchema\; getSchema: (ClzType: any) => ObjectSchema\; getStringSchema: () => StringSchema\; getSwaggerPropertyKeys: (ClzType: any) => string\[]; getSwaggerPropertyMetadata: (ClzType: any, propertyName: string) => Record\; isOptional: (ClzType: any, propertyName: string) => boolean; isRequired: (ClzType: any, propertyName: string) => boolean; setOptional: (ClzType: any, propertyName? : string) => void; setRequired: (ClzType: any, propertyName? : string) => void }; validateServiceHandler: (container: IMidwayContainer) => \_\_class } --- # @midwayjs/validation-zod ## Index[**](#Index) ### Variables * [**default](/api/validation-zod.md#default) ## Variables[**](#Variables) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation-zod/src/index.ts#L217)default **default: { schemaHelper: { getSwaggerPropertyKeys: (ClzType: any) => string\[]; getSwaggerPropertyMetadata: (ClzType: any, propertyName: string) => Record\; isOptional: (ClzType: any, propertyName: string) => boolean; isRequired: (ClzType: any, propertyName: string) => boolean; setOptional: (ClzType: any, propertyName? : string) => void; setRequired: (ClzType: any, propertyName? : string) => void; getBoolSchema: any; getFloatSchema: any; getIntSchema: any; getSchema: any; getStringSchema: any }; validateServiceHandler: (container: IMidwayContainer) => Promise<\_\_class> } --- # abstractAbstractValidationPipe ### Hierarchy * *AbstractValidationPipe* * [ValidationPipe](/api/validation/class/ValidationPipe.md) * [ParsePipe](/api/validation/class/ParsePipe.md) ### Implements * PipeTransform ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new AbstractValidationPipe(): [AbstractValidationPipe](/api/validation/class/AbstractValidationPipe.md) ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L19)abstracttransform * **transform(value: any, options: TransformOptions\): any - Implementation of PipeTransform.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) * [**configService](#configService) * [**decoratorService](#decoratorService) * [**validateService](#validateService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ValidationConfiguration](/api/validation/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L46)applicationContext **applicationContext: IMidwayContainer ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L43)configService **configService: MidwayConfigService ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L40)decoratorService **decoratorService: MidwayDecoratorService ### [**](#validateService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L48)validateService **validateService: [ValidationService](/api/validation/class/ValidationService.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L51)init * **init(): Promise\ ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L72)onReady * **onReady(container: IMidwayContainer): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/configuration.ts#L91)onStop * **onStop(): Promise\ --- # DecoratorValidPipe ### Hierarchy * [ParsePipe](/api/validation/class/ParsePipe.md) * *DecoratorValidPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new DecoratorValidPipe(): [DecoratorValidPipe](/api/validation/class/DecoratorValidPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L96)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from ParsePipe.validateWithSchema --- # DefaultValuePipe \ ### Implements * PipeTransform\ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L130)constructor * **new DefaultValuePipe\(defaultValue: R): [DefaultValuePipe](/api/validation/class/DefaultValuePipe.md)\ - #### Type parameters * **T** = any * **R** = any ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L131)transform * **transform(value: any, options: any): any - Implementation of PipeTransform.transform --- # MidwayValidationError ### Hierarchy * MidwayHttpError * *MidwayValidationError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/error.ts#L9)constructor * **new MidwayValidationError(message: any, status: any, cause: any): [MidwayValidationError](/api/validation/class/MidwayValidationError.md) - Overrides MidwayHttpError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayHttpError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayHttpError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from MidwayHttpError.status --- # MidwayValidatorNotFoundError ### Hierarchy * MidwayHttpError * *MidwayValidatorNotFoundError* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**cause](#cause) * [**code](#code) * [**status](#status) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/error.ts#L17)constructor * **new MidwayValidatorNotFoundError(name: string, status: number, cause? : Error): [MidwayValidatorNotFoundError](/api/validation/class/MidwayValidatorNotFoundError.md) - Overrides MidwayHttpError.constructor ## Properties[**](#Properties) ### [**](#cause)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L19)cause **cause: Error Inherited from MidwayHttpError.cause ### [**](#code)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L18)code **code: string | number Inherited from MidwayHttpError.code ### [**](#status)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/error/base.d.ts#L27)status **status: number Inherited from MidwayHttpError.status --- # ParseBoolPipe ### Hierarchy * [ParsePipe](/api/validation/class/ParsePipe.md) * *ParseBoolPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseBoolPipe(): [ParseBoolPipe](/api/validation/class/ParseBoolPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L117)getSchema * **getSchema(): any - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L96)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from ParsePipe.validateWithSchema --- # ParseFloatPipe ### Hierarchy * [ParsePipe](/api/validation/class/ParsePipe.md) * *ParseFloatPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseFloatPipe(): [ParseFloatPipe](/api/validation/class/ParseFloatPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L124)getSchema * **getSchema(): any - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L96)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from ParsePipe.validateWithSchema --- # ParseIntPipe ### Hierarchy * [ParsePipe](/api/validation/class/ParsePipe.md) * *ParseIntPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**getSchema](#getSchema) * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParseIntPipe(): [ParseIntPipe](/api/validation/class/ParseIntPipe.md) - Inherited from ParsePipe.constructor ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L110)getSchema * **getSchema(): any - Overrides ParsePipe.getSchema ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L96)transform * **transform(value: any, options: TransformOptions\): any - Inherited from ParsePipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from ParsePipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from ParsePipe.validateWithSchema --- # abstractParsePipe ### Hierarchy * [AbstractValidationPipe](/api/validation/class/AbstractValidationPipe.md) * *ParsePipe* * [DecoratorValidPipe](/api/validation/class/DecoratorValidPipe.md) * [ParseIntPipe](/api/validation/class/ParseIntPipe.md) * [ParseBoolPipe](/api/validation/class/ParseBoolPipe.md) * [ParseFloatPipe](/api/validation/class/ParseFloatPipe.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ParsePipe(): [ParsePipe](/api/validation/class/ParsePipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L96)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from AbstractValidationPipe.validateWithSchema --- # ValidationPipe ### Hierarchy * [AbstractValidationPipe](/api/validation/class/AbstractValidationPipe.md) * *ValidationPipe* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**transform](#transform) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidationPipe(): [ValidationPipe](/api/validation/class/ValidationPipe.md) - Inherited from AbstractValidationPipe.constructor ## Methods[**](#Methods) ### [**](#transform)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L90)transform * **transform(value: any, options: TransformOptions\): any - Overrides AbstractValidationPipe.transform ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L38)publicvalidate * **validate(value: any, options: TransformOptions\): any - Inherited from AbstractValidationPipe.validate ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/pipe.ts#L21)publicvalidateWithSchema * **validateWithSchema(value: any, options: TransformOptions\, schema: any): any - Inherited from AbstractValidationPipe.validateWithSchema --- # ValidationService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**defaultFallbackLocale](#defaultFallbackLocale) ### Methods * [**getSchema](#getSchema) * [**validate](#validate) * [**validateWithSchema](#validateWithSchema) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ValidationService(): [ValidationService](/api/validation/class/ValidationService.md) ## Properties[**](#Properties) ### [**](#defaultFallbackLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/service.ts#L32)defaultFallbackLocale **defaultFallbackLocale: string ## Methods[**](#Methods) ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/service.ts#L124)publicgetSchema * **getSchema(ClzType: any, validatorName? : string): any ### [**](#validate)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/service.ts#L56)publicvalidate * **validate\(ClzType: T, value: any, validationOptions? : [ValidationOptions](/api/validation/interface/ValidationOptions.md), validatorOptions? : any): [ValidateResult](/api/validation/interface/ValidateResult.md) - #### Type parameters * **T**: new (...args: any\[]) => any ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/service.ts#L78)publicvalidateWithSchema * **validateWithSchema\(schema: any, value: any, validationOptions? : [ValidationOptions](/api/validation/interface/ValidationOptions.md), validatorOptions? : any): [ValidateResult](/api/validation/interface/ValidateResult.md) - #### Type parameters * **T** --- # getRuleMeta ### Callable * **getRuleMeta\(ClzType: T): {} *** * #### Type parameters * **T**: new (...args: any\[]) => any --- # getSchema ### Callable * **getSchema(ClzType: any, validatorName? : string): any --- # OmitDto ### Callable * **OmitDto\(dto: [Dto](/api/validation/interface/Dto.md)\, keys: K\[]): [Dto](/api/validation/interface/Dto.md)\> *** * 从一个 DTO 类中排除指定的属性创建新的 DTO 类 *** #### Type parameters * **T** * **K**: string | number | symbol --- # PartialDto ### Callable * **PartialDto\(dto: [Dto](/api/validation/interface/Dto.md)\): [Dto](/api/validation/interface/Dto.md)\> *** * 将一个 DTO 类的所有属性转换为可选属性 *** #### Type parameters * **T** --- # PickDto ### Callable * **PickDto\(dto: [Dto](/api/validation/interface/Dto.md)\, keys: K\[]): [Dto](/api/validation/interface/Dto.md)\> *** * 从一个 DTO 类中选择指定的属性创建新的 DTO 类 *** #### Type parameters * **T** * **K**: string | number | symbol --- # RequiredDto ### Callable * **RequiredDto\(dto: [Dto](/api/validation/interface/Dto.md)\): [Dto](/api/validation/interface/Dto.md)\> *** * 将一个 DTO 类的所有属性转换为必选属性 *** #### Type parameters * **T** --- # Rule ### Callable * **Rule(rule: any): PropertyDecorator --- # Valid ### Callable * **Valid(schemaOrPipes? : any, pipes? : PipeUnionTransform\[]): ParameterDecorator --- # Validate ### Callable * **Validate(options? : [ValidationDecoratorOptions](/api/validation/interface/ValidationDecoratorOptions.md)): (target: any, methodName: any, descriptor: any) => void --- # Dto \ ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/dtoHelper.ts#L4)constructor * **new Dto(): T --- # IValidationService \ ## Index[**](#Index) ### Methods * [**init](#init) * [**validateWithSchema](#validateWithSchema) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L96)init * **init(container: IMidwayContainer): Promise\ ### [**](#validateWithSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L97)validateWithSchema * **validateWithSchema(schema: Schema, value: any, validationOptions: [ValidationExtendOptions](/api/validation/interface/ValidationExtendOptions.md), validatorOptions: any): [ValidateResult](/api/validation/interface/ValidateResult.md) --- # IValidator \ ## Index[**](#Index) ### Properties * [**schemaHelper](#schemaHelper) * [**validateService](#validateService) * [**validateServiceHandler](#validateServiceHandler) ## Properties[**](#Properties) ### [**](#schemaHelper)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L84)schemaHelper **schemaHelper: [SchemaHelper](/api/validation/interface/SchemaHelper.md)\ ### [**](#validateService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L85)optionalvalidateService **validateService? : [IValidationService](/api/validation/interface/IValidationService.md)\ ### [**](#validateServiceHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L90)validateServiceHandler **validateServiceHandler: (container: IMidwayContainer) => [IValidationService](/api/validation/interface/IValidationService.md)\ | Promise<[IValidationService](/api/validation/interface/IValidationService.md)\> Validator adapters may construct their service synchronously or lazily. The registry normalizes both forms with `await`. --- # IValidatorModule \ ## Index[**](#Index) ### Properties * [**default](#default) ## Properties[**](#Properties) ### [**](#default)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L4)default **default: [IValidator](/api/validation/interface/IValidator.md)\ --- # SchemaHelper \ ## Index[**](#Index) ### Methods * [**getBoolSchema](#getBoolSchema) * [**getFloatSchema](#getFloatSchema) * [**getIntSchema](#getIntSchema) * [**getSchema](#getSchema) * [**getStringSchema](#getStringSchema) * [**getSwaggerPropertyKeys](#getSwaggerPropertyKeys) * [**getSwaggerPropertyMetadata](#getSwaggerPropertyMetadata) * [**isOptional](#isOptional) * [**isRequired](#isRequired) * [**setOptional](#setOptional) * [**setRequired](#setRequired) ## Methods[**](#Methods) ### [**](#getBoolSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L112)getBoolSchema * **getBoolSchema(): Schema ### [**](#getFloatSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L113)getFloatSchema * **getFloatSchema(): Schema ### [**](#getIntSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L111)getIntSchema * **getIntSchema(): Schema ### [**](#getSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L110)getSchema * **getSchema(ClzType: any): any ### [**](#getStringSchema)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L114)getStringSchema * **getStringSchema(): Schema ### [**](#getSwaggerPropertyKeys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L119)optionalgetSwaggerPropertyKeys * **getSwaggerPropertyKeys(ClzType: any): string\[] - Optional adapter hook for OpenAPI property inference. Return all property names that can be inferred from current DTO. ### [**](#getSwaggerPropertyMetadata)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L124)optionalgetSwaggerPropertyMetadata * **getSwaggerPropertyMetadata(ClzType: any, propertyName: string): Record\ - Optional adapter hook for OpenAPI property inference. Return inferred OpenAPI metadata for a single DTO property. ### [**](#isOptional)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L107)isOptional * **isOptional(ClzType: any, propertyName: string): boolean ### [**](#isRequired)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L106)isRequired * **isRequired(ClzType: any, propertyName: string): boolean ### [**](#setOptional)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L109)setOptional * **setOptional(ClzType: any, propertyName? : string): void ### [**](#setRequired)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L108)setRequired * **setRequired(ClzType: any, propertyName? : string): void --- # ValidateResult ## Index[**](#Index) ### Properties * [**error](#error) * [**errors](#errors) * [**extra](#extra) * [**message](#message) * [**messages](#messages) * [**status](#status) * [**value](#value) ## Properties[**](#Properties) ### [**](#error)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L63)optionalerror **error? : any If the validation fails, the error or the message will be returned. if has multiple errors, the first error will be used. ### [**](#errors)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L67)optionalerrors **errors? : any\[] The errors to validate. ### [**](#extra)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L80)optionalextra **extra? : any The extra information to validate. ### [**](#message)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L72)optionalmessage **message? : string The message to validate. if has multiple messages, the first message will be used. ### [**](#messages)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L76)optionalmessages **messages? : string\[] The messages to validate. ### [**](#status)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L54)status **status: boolean Whether the validation is successful. ### [**](#value)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L58)optionalvalue **value? : any If the validation is successful, the value will be returned. --- # ValidationDecoratorOptions ### Hierarchy * [ValidationOptions](/api/validation/interface/ValidationOptions.md) * *ValidationDecoratorOptions* ## Index[**](#Index) ### Properties * [**defaultValidator](#defaultValidator) * [**errorStatus](#errorStatus) * [**locale](#locale) * [**throwValidateError](#throwValidateError) * [**validatorOptions](#validatorOptions) * [**validators](#validators) ## Properties[**](#Properties) ### [**](#defaultValidator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L32)optionaldefaultValidator **defaultValidator? : string Inherited from ValidationOptions.defaultValidator The default validator to use for validation. ### [**](#errorStatus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L15)optionalerrorStatus **errorStatus? : number Inherited from ValidationOptions.errorStatus The status code to return when validation fails, default is 422. ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L24)optionallocale **locale? : string Inherited from ValidationOptions.locale The locale to use for validation messages. ### [**](#throwValidateError)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L20)optionalthrowValidateError **throwValidateError? : boolean Inherited from ValidationOptions.throwValidateError Whether to throw a validation error, default is true. If set to false, the validation error will be returned. ### [**](#validatorOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L36)optionalvalidatorOptions **validatorOptions? : any ### [**](#validators)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L28)optionalvalidators **validators? : Record\> Inherited from ValidationOptions.validators The validators to use for validation. --- # ValidationExtendOptions ## Index[**](#Index) ### Properties * [**fallbackLocale](#fallbackLocale) * [**locale](#locale) ## Properties[**](#Properties) ### [**](#fallbackLocale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L47)fallbackLocale **fallbackLocale: string The fallback locale to use for validation messages. ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L43)locale **locale: string The locale to use for validation messages. --- # ValidationOptions ### Hierarchy * *ValidationOptions* * [ValidationDecoratorOptions](/api/validation/interface/ValidationDecoratorOptions.md) ## Index[**](#Index) ### Properties * [**defaultValidator](#defaultValidator) * [**errorStatus](#errorStatus) * [**locale](#locale) * [**throwValidateError](#throwValidateError) * [**validators](#validators) ## Properties[**](#Properties) ### [**](#defaultValidator)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L32)optionaldefaultValidator **defaultValidator? : string The default validator to use for validation. ### [**](#errorStatus)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L15)optionalerrorStatus **errorStatus? : number The status code to return when validation fails, default is 422. ### [**](#locale)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L24)optionallocale **locale? : string The locale to use for validation messages. ### [**](#throwValidateError)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L20)optionalthrowValidateError **throwValidateError? : boolean Whether to throw a validation error, default is true. If set to false, the validation error will be returned. ### [**](#validators)[**](https://github.com/midwayjs/midway/blob/3.x/packages/validation/src/interface.ts#L28)optionalvalidators **validators? : Record\> The validators to use for validation. --- # @midwayjs/view ## Index[**](#Index) ### Classes * [**Configuration](/api/view/class/Configuration.md) * [**ContextView](/api/view/class/ContextView.md) * [**ViewManager](/api/view/class/ViewManager.md) ### Interfaces * [**IViewEngine](/api/view/interface/IViewEngine.md) * [**RenderOptions](/api/view/interface/RenderOptions.md) --- # @midwayjs/view-ejs ## Index[**](#Index) ### Classes * [**Configuration](/api/view-ejs/class/Configuration.md) * [**EjsView](/api/view-ejs/class/EjsView.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**viewManager](#viewManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewEJSConfiguration](/api/view-ejs/class/Configuration.md) ## Properties[**](#Properties) ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/configuration.ts#L19)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # EjsView ### Implements * IViewEngine ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ejsConfig](#ejsConfig) * [**viewManager](#viewManager) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new EjsView(): [EjsView](/api/view-ejs/class/EjsView.md) ## Properties[**](#Properties) ### [**](#ejsConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/view.ts#L8)ejsConfig **ejsConfig: any ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/view.ts#L11)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/view.ts#L25)render * **render(name: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.render ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-ejs/src/view.ts#L41)renderString * **renderString(tpl: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.renderString --- # @midwayjs/view-nunjucks ## Index[**](#Index) ### Classes * [**Configuration](/api/view-nunjucks/class/Configuration.md) * [**NunjucksEnvironment](/api/view-nunjucks/class/NunjucksEnvironment.md) * [**NunjucksView](/api/view-nunjucks/class/NunjucksView.md) --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**viewManager](#viewManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewNunjucksConfiguration](/api/view-nunjucks/class/Configuration.md) ## Properties[**](#Properties) ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/configuration.ts#L19)viewManager **viewManager: ViewManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/configuration.ts#L21)onReady * **onReady(): Promise\ --- # NunjucksEnvironment ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addFilter](#addFilter) * [**addGlobal](#addGlobal) * [**getFilter](#getFilter) * [**hasExtension](#hasExtension) * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NunjucksEnvironment(): [NunjucksEnvironment](/api/view-nunjucks/class/NunjucksEnvironment.md) ## Methods[**](#Methods) ### [**](#addFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L101)addFilter * **addFilter(name: string, callback: (...args: any\[]) => string): any ### [**](#addGlobal)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L113)addGlobal * **addGlobal(name: string, value: any): any ### [**](#getFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L105)getFilter * **getFilter(name: string): any ### [**](#hasExtension)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L109)hasExtension * **hasExtension(name: string): boolean ### [**](#render)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L79)render * **render(name: string, context? : Record\, callback? : TemplateCallback\): any ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/engine.ts#L87)renderString * **renderString(tpl: string, context? : Record\, options? : RenderOptions, callback? : TemplateCallback\): any --- # NunjucksView ### Implements * IViewEngine ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**nunjucks](#nunjucks) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new NunjucksView(): [NunjucksView](/api/view-nunjucks/class/NunjucksView.md) ## Properties[**](#Properties) ### [**](#nunjucks)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/view.ts#L8)nunjucks **nunjucks: [NunjucksEnvironment](/api/view-nunjucks/class/NunjucksEnvironment.md) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/view.ts#L10)render * **render(name: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.render ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view-nunjucks/src/view.ts#L24)renderString * **renderString(tpl: string, locals? : Record\, options? : RenderOptions): Promise\ - Implementation of IViewEngine.renderString --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationManager](#applicationManager) ### Methods * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ViewConfiguration](/api/view/class/Configuration.md) ## Properties[**](#Properties) ### [**](#applicationManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/configuration.ts#L22)applicationManager **applicationManager: MidwayApplicationManager ## Methods[**](#Methods) ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/configuration.ts#L24)onReady * **onReady(container: any): Promise\ --- # ContextView View instance for each request. It will find the view engine, and render it. The view engine should be registered in [ViewManager](/api/view/class/ViewManager.md). ### Implements * [IViewEngine](/api/view/interface/IViewEngine.md) ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**ctx](#ctx) * [**viewConfig](#viewConfig) * [**viewManager](#viewManager) ### Methods * [**render](#render) * [**renderString](#renderString) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new ContextView(): [ContextView](/api/view/class/ContextView.md) ## Properties[**](#Properties) ### [**](#ctx)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/contextView.ts#L22)ctx **ctx: any ### [**](#viewConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/contextView.ts#L19)viewConfig **viewConfig: any ### [**](#viewManager)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/contextView.ts#L16)viewManager **viewManager: [ViewManager](/api/view/class/ViewManager.md) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/contextView.ts#L24)render * **render(name: string, locals? : Record\, options? : [RenderOptions](/api/view/interface/RenderOptions.md)): Promise\ - Implementation of IViewEngine.render Render a file by view engine, then set to body ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/contextView.ts#L54)renderString * **renderString(tpl: string, locals? : Record\, options? : [RenderOptions](/api/view/interface/RenderOptions.md)): Promise\ - Implementation of IViewEngine.renderString Render a template string by view engine --- # ViewManager ### Hierarchy * Map * *ViewManager* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Methods * [**addLocals](#addLocals) * [**findEngine](#findEngine) * [**getLocals](#getLocals) * [**resolve](#resolve) * [**use](#use) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L50)[**](https://undefined/midwayjs/midway/blob/3.x/site/node_modules/typescript/src/lib.es2015.collection.d.ts#L51)externalconstructor * **new ViewManager(): [ViewManager](/api/view/class/ViewManager.md) * **new ViewManager(): [ViewManager](/api/view/class/ViewManager.md) - Inherited from Map.constructor ## Methods[**](#Methods) ### [**](#addLocals)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/viewManager.ts#L111)publicaddLocals * **addLocals(key: any, localValue: any): void - add a global data for all views ### [**](#findEngine)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/viewManager.ts#L122)publicfindEngine * **findEngine(ext: string): string ### [**](#getLocals)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/viewManager.ts#L118)publicgetLocals * **getLocals(): {} - get global locals data ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/viewManager.ts#L87)publicresolve * **resolve(name: string): Promise\ - Resolve the path based on the given name, if the name is `user.html` and root is `view` (by default), it will return `view/user.html` ### [**](#use)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/viewManager.ts#L63)publicuse * **use(name: string, viewEngine: new (...args: any\[]) => [IViewEngine](/api/view/interface/IViewEngine.md)): void - This method can register view engine. You can define a view engine class contains two method, `render` and `renderString` ``` class View { render() {} renderString() {} } ``` --- # IViewEngine ### Implemented by * [ContextView](/api/view/class/ContextView.md) ## Index[**](#Index) ### Methods * [**render](#render) * [**renderString](#renderString) ## Methods[**](#Methods) ### [**](#render)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L16)render * **render(name: string, locals? : Record\, options? : [RenderOptions](/api/view/interface/RenderOptions.md)): Promise\ - Render a file by view engine, then set to body ### [**](#renderString)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L29)renderString * **renderString(tpl: string, locals? : Record\, options? : [RenderOptions](/api/view/interface/RenderOptions.md)): Promise\ - Render a template string by view engine --- # RenderOptions ## Index[**](#Index) ### Properties * [**locals](#locals) * [**name](#name) * [**root](#root) * [**viewEngine](#viewEngine) ## Properties[**](#Properties) ### [**](#locals)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L4)optionallocals **locals? : Record\ ### [**](#name)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L2)optionalname **name? : string ### [**](#root)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L3)optionalroot **root? : string ### [**](#viewEngine)[**](https://github.com/midwayjs/midway/blob/3.x/packages/view/src/interface.ts#L5)optionalviewEngine **viewEngine? : string --- # @midwayjs/web ## Index[**](#Index) ### Classes * [**Agent](/api/web/class/Agent.md) * [**Application](/api/web/class/Application.md) * [**Configuration](/api/web/class/Configuration.md) * [**Framework](/api/web/class/Framework.md) ### Functions * [**AgentApp](/api/web/function/AgentApp.md) * [**RunInEggAgent](/api/web/function/RunInEggAgent.md) * [**createAgentWorkerLoader](/api/web/function/createAgentWorkerLoader.md) * [**createAppWorkerLoader](/api/web/function/createAppWorkerLoader.md) * [**createEggAgent](/api/web/function/createEggAgent.md) * [**createEggApplication](/api/web/function/createEggApplication.md) * [**startCluster](/api/web/function/startCluster.md) ### Interfaces * [**Context](/api/web/interface/Context.md) * [**IMidwayWebBaseApplication](/api/web/interface/IMidwayWebBaseApplication.md) * [**IMidwayWebConfigurationOptions](/api/web/interface/IMidwayWebConfigurationOptions.md) * [**IWebMiddleware](/api/web/interface/IWebMiddleware.md) * [**State](/api/web/interface/State.md) ### Type Aliases * [**IMidwayWebApplication](/api/web.md#IMidwayWebApplication) * [**IMidwayWebContext](/api/web.md#IMidwayWebContext) * [**IMidwayWebNext](/api/web.md#IMidwayWebNext) * [**MidwayWebMiddleware](/api/web.md#MidwayWebMiddleware) * [**NextFunction](/api/web.md#NextFunction) ### Variables * [**EGG\_AGENT\_APP\_KEY](/api/web.md#EGG_AGENT_APP_KEY) * [**RUN\_IN\_AGENT\_KEY](/api/web.md#RUN_IN_AGENT_KEY) ## Type Aliases[**](<#Type Aliases>) ### [**](#IMidwayWebApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L32)IMidwayWebApplication **IMidwayWebApplication: IMidwayApplication<[Context](/api/web/interface/Context.md), EggApplication & [IMidwayWebBaseApplication](/api/web/interface/IMidwayWebBaseApplication.md)> * **@deprecated** since version 3.0.0 Please use Application from '@midwayjs/web' ### [**](#IMidwayWebContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L41)IMidwayWebContext **IMidwayWebContext\: IMidwayContext\> * **@deprecated** since version 3.0.0 Please use Context from '@midwayjs/web' *** #### Type parameters * **ResponseBodyT** = unknown ### [**](#IMidwayWebNext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L92)IMidwayWebNext **IMidwayWebNext: BaseNextFunction * **@deprecated** since version 3.0.0 Please use NextFunction from '@midwayjs/web' ### [**](#MidwayWebMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L186)MidwayWebMiddleware **MidwayWebMiddleware: Middleware<[State](/api/web/interface/State.md), [Context](/api/web/interface/Context.md)> * **@deprecated** since version 3.0.0 Please use IMiddleware from '@midwayjs/core' ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L93)NextFunction **NextFunction: BaseNextFunction ## Variables[**](#Variables) ### [**](#EGG_AGENT_APP_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L14)constEGG\_AGENT\_APP\_KEY **EGG\_AGENT\_APP\_KEY: egg\_agent\_app = 'egg\_agent\_app' ### [**](#RUN_IN_AGENT_KEY)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L13)constRUN\_IN\_AGENT\_KEY **RUN\_IN\_AGENT\_KEY: egg:run\_in\_agent = 'egg:run\_in\_agent' --- # @midwayjs/express ## Index[**](#Index) ### Classes * [**Configuration](/api/web-express/class/Configuration.md) * [**Framework](/api/web-express/class/Framework.md) * [**MidwayExpressMiddlewareService](/api/web-express/class/MidwayExpressMiddlewareService.md) ### Functions * [**wrapAsyncHandler](/api/web-express/function/wrapAsyncHandler.md) * [**wrapMiddleware](/api/web-express/function/wrapMiddleware.md) ### Interfaces * [**Context](/api/web-express/interface/Context.md) * [**IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md) * [**IMidwayExpressConfigurationOptions](/api/web-express/interface/IMidwayExpressConfigurationOptions.md) ### Type Aliases * [**Application](/api/web-express.md#Application) * [**IMidwayExpressContext](/api/web-express.md#IMidwayExpressContext) * [**IMidwayExpressMiddleware](/api/web-express.md#IMidwayExpressMiddleware) * [**IMidwayExpressRequest](/api/web-express.md#IMidwayExpressRequest) * [**NextFunction](/api/web-express.md#NextFunction) * [**Response](/api/web-express.md#Response) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L152)Application **Application: [IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md) ### [**](#IMidwayExpressContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L39)IMidwayExpressContext **IMidwayExpressContext: [Context](/api/web-express/interface/Context.md) * **@deprecated** use Context ### [**](#IMidwayExpressMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L40)IMidwayExpressMiddleware **IMidwayExpressMiddleware: IMiddleware<[Context](/api/web-express/interface/Context.md), ExpressResponse, ExpressNextFunction> ### [**](#IMidwayExpressRequest)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L35)IMidwayExpressRequest **IMidwayExpressRequest: [Context](/api/web-express/interface/Context.md) * **@deprecated** use Context ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L20)NextFunction **NextFunction: ExpressNextFunction ### [**](#Response)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L19)Response **Response: ExpressResponse --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**decoratorService](#decoratorService) * [**expressFramework](#expressFramework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [ExpressConfiguration](/api/web-express/class/Configuration.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/configuration.ts#L33)configService **configService: MidwayConfigService ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/configuration.ts#L27)decoratorService **decoratorService: MidwayDecoratorService ### [**](#expressFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/configuration.ts#L30)expressFramework **expressFramework: [MidwayExpressFramework](/api/web-express/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/configuration.ts#L36)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/configuration.ts#L49)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md), [Context](/api/web-express/interface/Context.md), [IMidwayExpressConfigurationOptions](/api/web-express/interface/IMidwayExpressConfigurationOptions.md), Response, NextFunction> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getPort](#getPort) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) * [**useRouterMiddleware](#useRouterMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayExpressFramework](/api/web-express/class/Framework.md) - Inherited from BaseFramework< IMidwayExpressApplication, Context, IMidwayExpressConfigurationOptions, Response, NextFunction >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayExpressConfigurationOptions](/api/web-express/interface/IMidwayExpressConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L51)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L466)publicapplyMiddleware * **applyMiddleware\(): Promise\> - Overrides BaseFramework.applyMiddleware #### Type parameters * **Response** * **NextFunction** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L479)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L47)configure * **configure(): [IMidwayExpressConfigurationOptions](/api/web-express/interface/IMidwayExpressConfigurationOptions.md) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L497)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/web-express/interface/Context.md), Response\>, NextFunction> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getPort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L493)publicgetPort * **getPort(): string ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L489)publicgetServer * **getServer(): Server ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L379)publicloadMidwayController * **loadMidwayController(): Promise<{ middleware: any; prefix: string }\[]> ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L172)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/web-express/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/web-express/interface/Context.md), Response\>, NextFunction>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/web-express/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/web-express/interface/Context.md), Response\>, NextFunction>): void - Inherited from BaseFramework.useMiddleware ### [**](#useRouterMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/framework.ts#L462)publicuseRouterMiddleware * **useRouterMiddleware(routerPath: string, middleware: any): void --- # MidwayExpressMiddlewareService ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**compose](#compose) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/middlewareService.ts#L31)constructor * **new MidwayExpressMiddlewareService(applicationContext: IMidwayContainer): [MidwayExpressMiddlewareService](/api/web-express/class/MidwayExpressMiddlewareService.md) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/middlewareService.ts#L31)readonlyapplicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#compose)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/middlewareService.ts#L33)compose * **compose(middleware: (string | CommonMiddleware<[Context](/api/web-express/interface/Context.md), Response\>, NextFunction>)\[], app: [IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md), name? : string): Promise<{ \_name: string }> --- # wrapAsyncHandler ### Callable * **wrapAsyncHandler(fn: any): any --- # wrapMiddleware ### Callable * **wrapMiddleware(mw: (context: any, next: any, options? : any) => any | (req: any, res: any, next: any) => any, options: any): (context: any, next: any, options? : any) => any --- # Context ### Hierarchy * Request * *Context* ## Index[**](#Index) ### Properties * [**apiVersion](#apiVersion) * [**logger](#logger) * [**originalPath](#originalPath) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#apiVersion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L25)optionalapiVersion **apiVersion? : string API version extracted from request ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from Request.logger ### [**](#originalPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L29)optionaloriginalPath **originalPath? : string Original path before version processing ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from Request.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from Request.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from Request.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from Request.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from Request.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from Request.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from Request.setAttr Set value to app attribute map --- # IMidwayExpressApplication ### Hierarchy * IMidwayApplication<[Context](/api/web-express/interface/Context.md), ExpressApplication> * *IMidwayExpressApplication* ### Callable * **IMidwayExpressApplication(req: IncomingMessage | Request\>, res: ServerResponse\ | Response\, number>): any * **IMidwayExpressApplication(req: Request\>, res: Response\, number>, next: NextFunction): void *** * Express instance itself is a request handler, which could be invoked without third argument. ## Index[**](#Index) ### Methods * [**addConfigObject](#addConfigObject) * [**createAnonymousContext](#createAnonymousContext) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplicationContext](#getApplicationContext) * [**getAttr](#getAttr) * [**getBaseDir](#getBaseDir) * [**getConfig](#getConfig) * [**getCoreLogger](#getCoreLogger) * [**getEnv](#getEnv) * [**getFramework](#getFramework) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProcessType](#getProcessType) * [**getProjectName](#getProjectName) * [**setAttr](#setAttr) * [**setContextLoggerClass](#setContextLoggerClass) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Methods[**](#Methods) ### [**](#addConfigObject)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L833)addConfigObject * **addConfigObject(obj: any): any - Inherited from IMidwayApplication.addConfigObject Add new value to current config ### [**](#createAnonymousContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L823)createAnonymousContext * **createAnonymousContext(...args: any\[]): [Context](/api/web-express/interface/Context.md) - Inherited from IMidwayApplication.createAnonymousContext create a context with RequestContainer ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L814)createLogger * **createLogger(name: string, options: MidwayLoggerOptions): ILogger - Inherited from IMidwayApplication.createLogger Create a logger by name and options ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L778)getAppDir * **getAppDir(): string - Inherited from IMidwayApplication.getAppDir Get a project root directory, without src or dist ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L794)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from IMidwayApplication.getApplicationContext Get global Midway IoC Container ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L844)getAttr * **getAttr\(key: string): T - Inherited from IMidwayApplication.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L774)getBaseDir * **getBaseDir(): string - Inherited from IMidwayApplication.getBaseDir Get a base directory for project, with src or dist ### [**](#getConfig)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L799)getConfig * **getConfig\(key? : string): T - Inherited from IMidwayApplication.getConfig Get all configuration values or get the specified configuration through parameters *** #### Type parameters * **T** = any ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L808)getCoreLogger * **getCoreLogger(): ILogger - Inherited from IMidwayApplication.getCoreLogger Get core logger ### [**](#getEnv)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L782)getEnv * **getEnv(): string - Inherited from IMidwayApplication.getEnv Get a environment value, read from MIDWAY\_SERVER\_ENV ### [**](#getFramework)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L786)getFramework * **getFramework(): IMidwayFramework<[IMidwayExpressApplication](/api/web-express/interface/IMidwayExpressApplication.md), [Context](/api/web-express/interface/Context.md), unknown, unknown, unknown> - Inherited from IMidwayApplication.getFramework get current related framework ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L804)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayApplication.getLogger Get default logger object or get the specified logger through parameters ### [**](#getMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L69)getMiddleware * **getMiddleware\(): ContextMiddlewareManager<[Context](/api/web-express/interface/Context.md), Response, NextFunction> - Overrides IMidwayApplication.getMiddleware get global middleware *** #### Type parameters * **Response** * **NextFunction** ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L867)getNamespace * **getNamespace(): string - Inherited from IMidwayApplication.getNamespace get current namespace ### [**](#getProcessType)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L790)getProcessType * **getProcessType(): MidwayProcessTypeEnum - Inherited from IMidwayApplication.getProcessType Get current running process type, app or agent, just for egg ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L818)getProjectName * **getProjectName(): string - Inherited from IMidwayApplication.getProjectName Get project name, just package.json name ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L839)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayApplication.setAttr Set value to app attribute map ### [**](#setContextLoggerClass)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L828)setContextLoggerClass * **setContextLoggerClass(BaseContextLoggerClass: any): void - Inherited from IMidwayApplication.setContextLoggerClass Set a context logger class to change default context logger format ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L858)useFilter * **useFilter\(Filter: CommonFilterUnion<[Context](/api/web-express/interface/Context.md), R, N>): void - Inherited from IMidwayApplication.useFilter add exception filter *** #### Type parameters * **R** * **N** ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L863)useGuard * **useGuard(guard: CommonGuardUnion<[Context](/api/web-express/interface/Context.md)>): void - Inherited from IMidwayApplication.useGuard add global guard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L54)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L62)useMiddleware * **useMiddleware\(routerPath: string, ...middleware: FunctionMiddleware<[Context](/api/web-express/interface/Context.md), Response, NextFunction>\[]): void * **useMiddleware\(middleware: CommonMiddlewareUnion<[Context](/api/web-express/interface/Context.md), Response, NextFunction>): void - Overrides IMidwayApplication.useMiddleware mount router and middleware *** #### Type parameters * **Response** * **NextFunction** --- # IMidwayExpressConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayExpressConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**keys](#keys) * [**listenOptions](#listenOptions) * [**logger](#logger) * [**port](#port) * [**serverOptions](#serverOptions) * [**versioning](#versioning) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L100)optionalca **ca? : string | Buffer | (string | Buffer)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L96)optionalcert **cert? : string | Buffer | (string | Buffer)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L108)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L88)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L104)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L92)optionalkey **key? : string | Buffer | (Object | Buffer)\[] https key ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L80)optionalkeys **keys? : string | string\[] session or cookie secret key ### [**](#listenOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L116)optionallistenOptions **listenOptions? : ListenOptions listen options ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L84)optionalport **port? : number application http port ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L112)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options ### [**](#versioning)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-express/src/interface.ts#L120)optionalversioning **versioning? : { defaultVersion? : string; enabled: boolean; extractVersionFn? : (ctx: [Context](/api/web-express/interface/Context.md)) => string; header? : string; mediaTypeParam? : string; prefix? : string; type? : URI | HEADER | MEDIA\_TYPE | CUSTOM } API versioning configuration --- # @midwayjs/koa ## Index[**](#Index) ### Classes * [**BodyParserMiddleware](/api/web-koa/class/BodyParserMiddleware.md) * [**Configuration](/api/web-koa/class/Configuration.md) * [**Framework](/api/web-koa/class/Framework.md) * [**SiteFileMiddleware](/api/web-koa/class/SiteFileMiddleware.md) ### Interfaces * [**BodyParserOptions](/api/web-koa/interface/BodyParserOptions.md) * [**Context](/api/web-koa/interface/Context.md) * [**IMidwayKoaConfigurationOptions](/api/web-koa/interface/IMidwayKoaConfigurationOptions.md) * [**IWebMiddleware](/api/web-koa/interface/IWebMiddleware.md) * [**State](/api/web-koa/interface/State.md) ### Type Aliases * [**Application](/api/web-koa.md#Application) * [**IMidwayKoaApplication](/api/web-koa.md#IMidwayKoaApplication) * [**IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext) * [**IMidwayKoaNext](/api/web-koa.md#IMidwayKoaNext) * [**MiddlewareParamArray](/api/web-koa.md#MiddlewareParamArray) * [**NextFunction](/api/web-koa.md#NextFunction) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L152)Application **Application: [IMidwayKoaApplication](/api/web-koa.md#IMidwayKoaApplication) ### [**](#IMidwayKoaApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L15)IMidwayKoaApplication **IMidwayKoaApplication: IMidwayApplication<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), koa<[State](/api/web-koa/interface/State.md), [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext)> & { generateController: any; getPort: any }> ### [**](#IMidwayKoaContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L14)IMidwayKoaContext **IMidwayKoaContext: IMidwayContext\ ### [**](#IMidwayKoaNext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L33)IMidwayKoaNext **IMidwayKoaNext: Next * **@deprecated** use NextFunction definition ### [**](#MiddlewareParamArray)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L144)MiddlewareParamArray **MiddlewareParamArray: Middleware\\[] ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L34)NextFunction **NextFunction: Next --- # BodyParserMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**bodyparserConfig](#bodyparserConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new BodyParserMiddleware(): [BodyParserMiddleware](/api/web-koa/class/BodyParserMiddleware.md) ## Properties[**](#Properties) ### [**](#bodyparserConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/bodyparser.middleware.ts#L7)bodyparserConfig **bodyparserConfig: any ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/bodyparser.middleware.ts#L9)resolve * **resolve(): any ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/bodyparser.middleware.ts#L16)staticgetName * **getName(): string --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**configService](#configService) * [**decoratorService](#decoratorService) * [**koaFramework](#koaFramework) ### Methods * [**init](#init) * [**onReady](#onReady) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [KoaConfiguration](/api/web-koa/class/Configuration.md) ## Properties[**](#Properties) ### [**](#configService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/configuration.ts#L33)configService **configService: MidwayConfigService ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/configuration.ts#L27)decoratorService **decoratorService: MidwayDecoratorService ### [**](#koaFramework)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/configuration.ts#L30)koaFramework **koaFramework: [MidwayKoaFramework](/api/web-koa/class/Framework.md) ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/configuration.ts#L36)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/configuration.ts#L50)onReady * **onReady(): Promise\ --- # Framework ### Hierarchy * BaseFramework<[IMidwayKoaApplication](/api/web-koa.md#IMidwayKoaApplication), [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), [IMidwayKoaConfigurationOptions](/api/web-koa/interface/IMidwayKoaConfigurationOptions.md), Next> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**generateController](#generateController) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getPort](#getPort) * [**getProjectName](#getProjectName) * [**getServer](#getServer) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayKoaFramework](/api/web-koa/class/Framework.md) - Inherited from BaseFramework< IMidwayKoaApplication, IMidwayKoaContext, IMidwayKoaConfigurationOptions, Next >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayKoaApplication](/api/web-koa.md#IMidwayKoaApplication) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayKoaConfigurationOptions](/api/web-koa/interface/IMidwayKoaConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L69)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L401)publicbeforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L65)configure * **configure(): [IMidwayKoaConfigurationOptions](/api/web-koa/interface/IMidwayKoaConfigurationOptions.md) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#generateController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L309)publicgenerateController * **generateController(routeInfo: RouterInfo): Middleware\ - wrap controller string to middleware function ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [IMidwayKoaApplication](/api/web-koa.md#IMidwayKoaApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L411)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), Next, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getPort)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L419)publicgetPort * **getPort(): string ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#getServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L415)publicgetServer * **getServer(): Server\ ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L296)loadMidwayController * **loadMidwayController(): Promise\ ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L315)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L429)publicuseFilter * **useFilter(Filter: CommonFilterUnion<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), Next, unknown>): void - Overrides BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/framework.ts#L423)publicuseMiddleware * **useMiddleware(Middleware: CommonMiddlewareUnion<[IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext), Next, unknown>): void - Overrides BaseFramework.useMiddleware --- # SiteFileMiddleware ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**siteFileConfig](#siteFileConfig) ### Methods * [**resolve](#resolve) * [**getName](#getName) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new SiteFileMiddleware(): [SiteFileMiddleware](/api/web-koa/class/SiteFileMiddleware.md) ## Properties[**](#Properties) ### [**](#siteFileConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/fav.middleware.ts#L9)siteFileConfig **siteFileConfig: any ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/fav.middleware.ts#L11)resolve * **resolve(): (ctx: any, next: any) => Promise\ ### [**](#getName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/middleware/fav.middleware.ts#L45)staticgetName * **getName(): string --- # BodyParserOptions ## Index[**](#Index) ### Properties * [**detectJSON](#detectJSON) * [**enable](#enable) * [**enableTypes](#enableTypes) * [**encoding](#encoding) * [**extendTypes](#extendTypes) * [**formLimit](#formLimit) * [**jsonLimit](#jsonLimit) * [**onerror](#onerror) * [**strict](#strict) * [**textLimit](#textLimit) * [**xmlLimit](#xmlLimit) ## Properties[**](#Properties) ### [**](#detectJSON)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L201)optionaldetectJSON **detectJSON? : (ctx: [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext)) => boolean custom json request detect function. Default is null ### [**](#enable)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L161)optionalenable **enable? : boolean ### [**](#enableTypes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L165)optionalenableTypes **enableTypes? : string\[] parser will only parse when request type hits enableTypes, default is \['json', 'form']. ### [**](#encoding)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L170)optionalencoding **encoding? : string requested encoding. Default is utf-8 by co-body ### [**](#extendTypes)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L206)optionalextendTypes **extendTypes? : { form? : string | string\[]; json? : string | string\[]; text? : string | string\[] } support extend types ### [**](#formLimit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L176)optionalformLimit **formLimit? : string limit of the urlencoded body. If the body ends up being larger than this limit a 413 error code is returned. Default is 56kb ### [**](#jsonLimit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L181)optionaljsonLimit **jsonLimit? : string limit of the json body. Default is 1mb ### [**](#onerror)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L215)optionalonerror **onerror? : (err: Error, ctx: [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext)) => void support custom error handle ### [**](#strict)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L196)optionalstrict **strict? : boolean when set to true, JSON parser will only accept arrays and objects. Default is true ### [**](#textLimit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L186)optionaltextLimit **textLimit? : string limit of the text body. Default is 1mb. ### [**](#xmlLimit)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L191)optionalxmlLimit **xmlLimit? : string limit of the xml body. Default is 1mb. --- # Context ### Hierarchy * [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext) * *Context* ## Index[**](#Index) ### Properties * [**apiVersion](#apiVersion) * [**app](#app) * [**cookies](#cookies) * [**forward](#forward) * [**logger](#logger) * [**originalPath](#originalPath) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**state](#state) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#apiVersion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L156)optionalapiVersion **apiVersion? : string ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/index.d.ts#L48)app **app: IMidwayKoaApplication Inherited from IMidwayKoaContext.app ### [**](#cookies)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/index.d.ts#L47)cookies **cookies: Cookies Inherited from IMidwayKoaContext.cookies ### [**](#forward)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/index.d.ts#L49)forward **forward: (url: string) => void Inherited from IMidwayKoaContext.forward ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayKoaContext.logger ### [**](#originalPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L157)optionaloriginalPath **originalPath? : string ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayKoaContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayKoaContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L155)state **state: [State](/api/web-koa/interface/State.md) Overrides IMidwayKoaContext.state ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayKoaContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayKoaContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayKoaContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayKoaContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayKoaContext.setAttr Set value to app attribute map --- # IMidwayKoaConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayKoaConfigurationOptions* ## Index[**](#Index) ### Properties * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**keys](#keys) * [**listenOptions](#listenOptions) * [**logger](#logger) * [**maxIpsCount](#maxIpsCount) * [**port](#port) * [**proxy](#proxy) * [**proxyIpHeader](#proxyIpHeader) * [**queryParseMode](#queryParseMode) * [**queryParseOptions](#queryParseOptions) * [**serverOptions](#serverOptions) * [**serverTimeout](#serverTimeout) * [**subdomainOffset](#subdomainOffset) * [**versioning](#versioning) ## Properties[**](#Properties) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L60)optionalca **ca? : string | Buffer | (string | Buffer)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L56)optionalcert **cert? : string | Buffer | (string | Buffer)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L68)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L48)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L64)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L52)optionalkey **key? : string | Buffer | (Object | Buffer)\[] https key ### [**](#keys)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L40)optionalkeys **keys? : string\[] cookies sign keys ### [**](#listenOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L108)optionallistenOptions **listenOptions? : ListenOptions listen options ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#maxIpsCount)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L84)optionalmaxIpsCount **maxIpsCount? : number Max IPs read from proxy IP header, default to 0 (means infinity) ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L44)optionalport **port? : number application http port ### [**](#proxy)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L72)optionalproxy **proxy? : boolean Trust proxy headers ### [**](#proxyIpHeader)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L80)optionalproxyIpHeader **proxyIpHeader? : string Proxy IP header, defaults to X-Forwarded-For ### [**](#queryParseMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L96)optionalqueryParseMode **queryParseMode? : strict | extended | first qs mode ### [**](#queryParseOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L100)optionalqueryParseOptions **queryParseOptions? : IParseOptions\ qs options ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L104)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options ### [**](#serverTimeout)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L92)optionalserverTimeout **serverTimeout? : number server timeout in milliseconds, default to 2 minutes. for special request, just use `ctx.req.setTimeout(ms)` * **@see** ### [**](#subdomainOffset)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L76)optionalsubdomainOffset **subdomainOffset? : number Subdomain offset ### [**](#versioning)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L112)optionalversioning **versioning? : { defaultVersion? : string; enabled? : boolean; extractVersionFn? : (ctx: [IMidwayKoaContext](/api/web-koa.md#IMidwayKoaContext)) => string; header? : string; mediaTypeParam? : string; prefix? : string; type? : URI | HEADER | MEDIA\_TYPE | CUSTOM } 版本控制配置 --- # IWebMiddleware ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web-koa/src/interface.ts#L149)resolve * **resolve(): Middleware\ --- # State ### Hierarchy * DefaultState * *State* --- # Agent ### Hierarchy * BaseEggAgent * *Agent* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**\[EGG\_LOADER\]](#\[EGG_LOADER]) * [**\[EGG\_PATH\]](#\[EGG_PATH]) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Agent(): [EggAgent](/api/web/class/Agent.md) - Inherited from BaseEggAgent.constructor ## Accessors[**](#Accessors) ### [**](#\[EGG_LOADER])[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/application.ts#L31)\[EGG\_LOADER] * **get \[EGG\_LOADER]\(): any ### [**](#\[EGG_PATH])[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/application.ts#L35)\[EGG\_PATH] * **get \[EGG\_PATH]\(): string --- # Application ### Hierarchy * BaseEggApplication * *Application* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Accessors * [**\[EGG\_LOADER\]](#\[EGG_LOADER]) * [**\[EGG\_PATH\]](#\[EGG_PATH]) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Application(): [EggApplication](/api/web/class/Application.md) - Inherited from BaseEggApplication.constructor ## Accessors[**](#Accessors) ### [**](#\[EGG_LOADER])[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/application.ts#L21)\[EGG\_LOADER] * **get \[EGG\_LOADER]\(): any ### [**](#\[EGG_PATH])[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/application.ts#L25)\[EGG\_PATH] * **get \[EGG\_PATH]\(): string --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**appDir](#appDir) * [**baseDir](#baseDir) * [**decoratorService](#decoratorService) ### Methods * [**init](#init) * [**onReady](#onReady) * [**onServerReady](#onServerReady) * [**onStop](#onStop) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [EggConfiguration](/api/web/class/Configuration.md) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L25)app **app: [IMidwayWebApplication](/api/web.md#IMidwayWebApplication) ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L22)appDir **appDir: any ### [**](#baseDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L19)baseDir **baseDir: any ### [**](#decoratorService)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L28)decoratorService **decoratorService: MidwayDecoratorService ## Methods[**](#Methods) ### [**](#init)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L31)init * **init(): void ### [**](#onReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L44)onReady * **onReady(): Promise\ ### [**](#onServerReady)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L53)onServerReady * **onServerReady(): Promise\ ### [**](#onStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/configuration.ts#L60)onStop * **onStop(): Promise\ --- # Framework ### Hierarchy * BaseFramework\ * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**appDir](#appDir) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**beforeStop](#beforeStop) * [**configure](#configure) * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initSingleProcessEgg](#initSingleProcessEgg) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**loadMidwayController](#loadMidwayController) * [**overwriteApplication](#overwriteApplication) * [**run](#run) * [**runGuard](#runGuard) * [**setContextLoggerClass](#setContextLoggerClass) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**setServer](#setServer) * [**stop](#stop) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayWebFramework](/api/web/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwayWebConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: Application Inherited from BaseFramework.app ### [**](#appDir)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L65)appDir **appDir: any ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayWebConfigurationOptions](/api/web/interface/IMidwayWebConfigurationOptions.md) Inherited from BaseFramework.configurationOptions ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L98)applicationInitialize * **applicationInitialize(options: Partial\): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/web/interface/Context.md)\, R, N>): Promise\, R, N>> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#beforeStop)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L337)beforeStop * **beforeStop(): Promise\ - Overrides BaseFramework.beforeStop ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L67)publicconfigure * **configure(): any - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L331)publicgenerateMiddleware * **generateMiddleware(middlewareId: any): Promise\ ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): Application - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L54)getFrameworkName * **getFrameworkName(): string - Inherited from BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L310)publicgetLogger * **getLogger(name? : string): any - Overrides BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/web/interface/Context.md)\, unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#initSingleProcessEgg)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L75)initSingleProcessEgg * **initSingleProcessEgg(): Promise\ ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#loadMidwayController)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L217)loadMidwayController * **loadMidwayController(): Promise\ ### [**](#overwriteApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L162)overwriteApplication * **overwriteApplication(processType: any): void ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L232)run * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/web/interface/Context.md)\, supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setContextLoggerClass)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L317)publicsetContextLoggerClass * **setContextLoggerClass(): void ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#setServer)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/framework/web.ts#L347)publicsetServer * **setServer(server: any): void ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/web/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/web/interface/Context.md)\>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/web/interface/Context.md)\, unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # AgentApp ### Callable * **AgentApp(): PropertyDecorator --- # createAgentWorkerLoader ### Callable * **createAgentWorkerLoader(): any --- # createAppWorkerLoader ### Callable * **createAppWorkerLoader(): any --- # createEggAgent ### Callable * **createEggAgent(): any --- # createEggApplication ### Callable * **createEggApplication(): any --- # RunInEggAgent ### Callable * **RunInEggAgent(): ClassDecorator --- # startCluster ### Callable * **startCluster(serverConfig: any, callback? : any): any --- # Context \ * **@deprecated** since version 3.0.0 Please use Context from '@midwayjs/web' ### Hierarchy * [IMidwayWebContext](/api/web.md#IMidwayWebContext)\ * *Context* ## Index[**](#Index) ### Properties * [**apiVersion](#apiVersion) * [**forward](#forward) * [**originalPath](#originalPath) * [**requestContext](#requestContext) * [**session](#session) * [**startTime](#startTime) * [**state](#state) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#apiVersion)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L82)optionalapiVersion **apiVersion? : string API version extracted from request ### [**](#forward)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/index.d.ts#L32)forward **forward: (url: string) => void Inherited from IMidwayWebContext.forward ### [**](#originalPath)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L86)optionaloriginalPath **originalPath? : string Original path before version processing ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayWebContext.requestContext Custom properties. ### [**](#session)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L47)session **session: { length: number; maxAge: number | session; populated: boolean; manuallyCommit: any; save: any; toJSON: any } ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayWebContext.startTime ### [**](#state)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L78)state **state: [State](/api/web/interface/State.md) Overrides IMidwayWebContext.state ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayWebContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayWebContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayWebContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayWebContext.setAttr Set value to app attribute map --- # IMidwayWebBaseApplication ## Index[**](#Index) ### Properties * [**applicationContext](#applicationContext) ### Methods * [**createLogger](#createLogger) * [**generateMiddleware](#generateMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getLogger](#getLogger) ## Properties[**](#Properties) ### [**](#applicationContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L19)applicationContext **applicationContext: IMidwayContainer ## Methods[**](#Methods) ### [**](#createLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L25)createLogger * **createLogger(name: string, options: LoggerOptions): ILogger ### [**](#generateMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L22)optionalgenerateMiddleware * **generateMiddleware(middlewareId: any): Promise\>> ### [**](#getCoreLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L21)getCoreLogger * **getCoreLogger(): ILogger ### [**](#getLogger)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L20)getLogger * **getLogger(name? : string): ILogger --- # IMidwayWebConfigurationOptions ### Hierarchy * IConfigurationOptions * *IMidwayWebConfigurationOptions* ## Index[**](#Index) ### Properties * [**app](#app) * [**appLogger](#appLogger) * [**ca](#ca) * [**cert](#cert) * [**contextLoggerApplyLogger](#contextLoggerApplyLogger) * [**contextLoggerFormat](#contextLoggerFormat) * [**globalConfig](#globalConfig) * [**globalPrefix](#globalPrefix) * [**hostname](#hostname) * [**http2](#http2) * [**key](#key) * [**logger](#logger) * [**plugins](#plugins) * [**port](#port) * [**processType](#processType) * [**queryParseMode](#queryParseMode) * [**queryParseOptions](#queryParseOptions) * [**serverOptions](#serverOptions) * [**typescript](#typescript) * [**versioning](#versioning) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L96)optionalapp **app? : [IMidwayWebApplication](/api/web.md#IMidwayWebApplication) ### [**](#appLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L887)optionalappLogger **appLogger? : ILogger Inherited from IConfigurationOptions.appLogger ### [**](#ca)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L126)optionalca **ca? : string | Buffer | (string | Buffer)\[] https ca ### [**](#cert)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L122)optionalcert **cert? : string | Buffer | (string | Buffer)\[] https cert ### [**](#contextLoggerApplyLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L888)optionalcontextLoggerApplyLogger **contextLoggerApplyLogger? : string Inherited from IConfigurationOptions.contextLoggerApplyLogger ### [**](#contextLoggerFormat)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L889)optionalcontextLoggerFormat **contextLoggerFormat? : any Inherited from IConfigurationOptions.contextLoggerFormat ### [**](#globalConfig)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L106)optionalglobalConfig **globalConfig? : any ### [**](#globalPrefix)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L134)optionalglobalPrefix **globalPrefix? : string http global prefix ### [**](#hostname)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L114)optionalhostname **hostname? : string application hostname, 127.0.0.1 as default ### [**](#http2)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L130)optionalhttp2 **http2? : boolean http2 support ### [**](#key)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L118)optionalkey **key? : string | Buffer | (Object | Buffer)\[] https key ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L886)optionallogger **logger? : ILogger Inherited from IConfigurationOptions.logger ### [**](#plugins)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L97)optionalplugins **plugins? : {} ### [**](#port)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L110)optionalport **port? : number application http port ### [**](#processType)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L105)optionalprocessType **processType? : agent | application ### [**](#queryParseMode)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L138)optionalqueryParseMode **queryParseMode? : simple | extended http query parser mode, default is extended ### [**](#queryParseOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L142)optionalqueryParseOptions **queryParseOptions? : IParseOptions http query parse options, used when 'simple' mode is used ### [**](#serverOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L146)optionalserverOptions **serverOptions? : Record\ https/https/http2 server options ### [**](#typescript)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L104)optionaltypescript **typescript? : boolean ### [**](#versioning)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L150)optionalversioning **versioning? : { defaultVersion? : string; enabled: boolean; extractVersionFn? : (ctx: [Context](/api/web/interface/Context.md)\) => string; header? : string; mediaTypeParam? : string; prefix? : string; type? : URI | HEADER | MEDIA\_TYPE | CUSTOM } API versioning configuration --- # IWebMiddleware * **@deprecated** since version 3.0.0 Please use IMiddleware from '@midwayjs/core' ## Index[**](#Index) ### Methods * [**resolve](#resolve) ## Methods[**](#Methods) ### [**](#resolve)[**](https://github.com/midwayjs/midway/blob/3.x/packages/web/src/interface.ts#L193)resolve * **resolve(): [MidwayWebMiddleware](/api/web.md#MidwayWebMiddleware) --- # State ### Hierarchy * DefaultState * *State* --- # @midwayjs/ws ## Index[**](#Index) ### Classes * [**Configuration](/api/ws/class/Configuration.md) * [**Framework](/api/ws/class/Framework.md) ### Interfaces * [**Context](/api/ws/interface/Context.md) ### Type Aliases * [**Application](/api/ws.md#Application) * [**IMidwayWSApplication](/api/ws.md#IMidwayWSApplication) * [**IMidwayWSConfigurationOptions](/api/ws.md#IMidwayWSConfigurationOptions) * [**IMidwayWSContext](/api/ws.md#IMidwayWSContext) * [**NextFunction](/api/ws.md#NextFunction) * [**UpgradeAuthHandler](/api/ws.md#UpgradeAuthHandler) ## Type Aliases[**](<#Type Aliases>) ### [**](#Application)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L50)Application **Application: [IMidwayWSApplication](/api/ws.md#IMidwayWSApplication) ### [**](#IMidwayWSApplication)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L12)IMidwayWSApplication **IMidwayWSApplication: IMidwayApplication<[IMidwayWSContext](/api/ws.md#IMidwayWSContext), { getConnectionMiddleware: ContextMiddlewareManager<[Context](/api/ws/interface/Context.md), [NextFunction](/api/ws.md#NextFunction), undefined>; onWebSocketUpgrade: (handler: [UpgradeAuthHandler](/api/ws.md#UpgradeAuthHandler) | null) => void; useConnectionMiddleware: (middleware: CommonMiddlewareUnion<[Context](/api/ws/interface/Context.md), [NextFunction](/api/ws.md#NextFunction), undefined>) => void }> & WebSocket.Server ### [**](#IMidwayWSConfigurationOptions)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L28)IMidwayWSConfigurationOptions **IMidwayWSConfigurationOptions: { enableServerHeartbeatCheck? : boolean; pubClient? : any; serverHeartbeatInterval? : number; subClient? : any } & Partial\ & IConfigurationOptions ### [**](#IMidwayWSContext)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L42)IMidwayWSContext **IMidwayWSContext: IMidwayContext\ ### [**](#NextFunction)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L51)NextFunction **NextFunction: BaseNextFunction ### [**](#UpgradeAuthHandler)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L57)UpgradeAuthHandler **UpgradeAuthHandler: (request: IncomingMessage, socket: any, head: Buffer) => Promise\ WebSocket 升级前鉴权处理函数类型 --- # Configuration ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ## Constructors[**](#Constructors) ### [**](#constructor)constructor * **new Configuration(): [WebSocketConfiguration](/api/ws/class/Configuration.md) --- # Framework ### Hierarchy * BaseFramework<[Application](/api/ws.md#Application), [Context](/api/ws/interface/Context.md), [IMidwayWSConfigurationOptions](/api/ws.md#IMidwayWSConfigurationOptions)> * *Framework* ## Index[**](#Index) ### Constructors * [**constructor](#constructor) ### Properties * [**app](#app) * [**applicationContext](#applicationContext) * [**configurationOptions](#configurationOptions) * [**server](#server) ### Methods * [**applicationInitialize](#applicationInitialize) * [**applyMiddleware](#applyMiddleware) * [**configure](#configure) * [**createLogger](#createLogger) * [**getAppDir](#getAppDir) * [**getApplication](#getApplication) * [**getApplicationContext](#getApplicationContext) * [**getBaseDir](#getBaseDir) * [**getConfiguration](#getConfiguration) * [**getConnectionMiddleware](#getConnectionMiddleware) * [**getCoreLogger](#getCoreLogger) * [**getCurrentEnvironment](#getCurrentEnvironment) * [**getFrameworkName](#getFrameworkName) * [**getLogger](#getLogger) * [**getMiddleware](#getMiddleware) * [**getNamespace](#getNamespace) * [**getProjectName](#getProjectName) * [**initialize](#initialize) * [**isEnable](#isEnable) * [**onWebSocketUpgrade](#onWebSocketUpgrade) * [**run](#run) * [**runGuard](#runGuard) * [**setFrameworkLoggerName](#setFrameworkLoggerName) * [**setNamespace](#setNamespace) * [**startHeartBeat](#startHeartBeat) * [**stop](#stop) * [**useConnectionMiddleware](#useConnectionMiddleware) * [**useFilter](#useFilter) * [**useGuard](#useGuard) * [**useMiddleware](#useMiddleware) ## Constructors[**](#Constructors) ### [**](#constructor)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L32)constructor * **new Framework(applicationContext: IMidwayGlobalContainer): [MidwayWSFramework](/api/ws/class/Framework.md) - Inherited from BaseFramework< Application, Context, IMidwayWSConfigurationOptions >.constructor ## Properties[**](#Properties) ### [**](#app)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L14)app **app: [IMidwayWSApplication](/api/ws.md#IMidwayWSApplication) Inherited from BaseFramework.app ### [**](#applicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L13)readonlyapplicationContext **applicationContext: IMidwayGlobalContainer Inherited from BaseFramework.applicationContext ### [**](#configurationOptions)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L15)configurationOptions **configurationOptions: [IMidwayWSConfigurationOptions](/api/ws.md#IMidwayWSConfigurationOptions) Inherited from BaseFramework.configurationOptions ### [**](#server)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L40)server **server: Server\ ## Methods[**](#Methods) ### [**](#applicationInitialize)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L50)applicationInitialize * **applicationInitialize(options: IMidwayBootstrapOptions): Promise\ - Overrides BaseFramework.applicationInitialize ### [**](#applyMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L49)applyMiddleware * **applyMiddleware\(lastMiddleware? : CommonMiddlewareUnion<[Context](/api/ws/interface/Context.md), R, N>): Promise\> - Inherited from BaseFramework.applyMiddleware #### Type parameters * **R** * **N** ### [**](#configure)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L46)configure * **configure(): [IMidwayWSConfigurationOptions](/api/ws.md#IMidwayWSConfigurationOptions) - Overrides BaseFramework.configure ### [**](#createLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L52)createLogger * **createLogger(name: string, option? : MidwayLoggerOptions): any - Inherited from BaseFramework.createLogger ### [**](#getAppDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L45)getAppDir * **getAppDir(): string - Inherited from BaseFramework.getAppDir ### [**](#getApplication)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L42)getApplication * **getApplication(): [IMidwayWSApplication](/api/ws.md#IMidwayWSApplication) - Inherited from BaseFramework.getApplication ### [**](#getApplicationContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L39)getApplicationContext * **getApplicationContext(): IMidwayGlobalContainer - Inherited from BaseFramework.getApplicationContext ### [**](#getBaseDir)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L46)getBaseDir * **getBaseDir(): string - Inherited from BaseFramework.getBaseDir ### [**](#getConfiguration)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L40)getConfiguration * **getConfiguration(key? : string): any - Inherited from BaseFramework.getConfiguration ### [**](#getConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L535)publicgetConnectionMiddleware * **getConnectionMiddleware(): ContextMiddlewareManager<[Context](/api/ws/interface/Context.md), NextFunction, undefined> ### [**](#getCoreLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L51)getCoreLogger * **getCoreLogger(): ILogger - Inherited from BaseFramework.getCoreLogger ### [**](#getCurrentEnvironment)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L41)getCurrentEnvironment * **getCurrentEnvironment(): string - Inherited from BaseFramework.getCurrentEnvironment ### [**](#getFrameworkName)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L525)publicgetFrameworkName * **getFrameworkName(): string - Overrides BaseFramework.getFrameworkName ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L50)getLogger * **getLogger(name? : string): any - Inherited from BaseFramework.getLogger ### [**](#getMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L56)getMiddleware * **getMiddleware(): ContextMiddlewareManager<[Context](/api/ws/interface/Context.md), unknown, unknown> - Inherited from BaseFramework.getMiddleware ### [**](#getNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L64)getNamespace * **getNamespace(): string - Inherited from BaseFramework.getNamespace ### [**](#getProjectName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L53)getProjectName * **getProjectName(): string - Inherited from BaseFramework.getProjectName ### [**](#initialize)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L38)initialize * **initialize(options? : IMidwayBootstrapOptions): Promise\ - Inherited from BaseFramework.initialize ### [**](#isEnable)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L37)isEnable * **isEnable(): boolean - Inherited from BaseFramework.isEnable ### [**](#onWebSocketUpgrade)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L170)publiconWebSocketUpgrade * **onWebSocketUpgrade(handler: [UpgradeAuthHandler](/api/ws.md#UpgradeAuthHandler)): void - 设置升级前鉴权处理函数 ### [**](#run)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L75)publicrun * **run(): Promise\ - Overrides BaseFramework.run ### [**](#runGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L59)runGuard * **runGuard(ctx: [Context](/api/ws/interface/Context.md), supplierClz: new (...args: any\[]) => any, methodName: string): Promise\ - Inherited from BaseFramework.runGuard ### [**](#setFrameworkLoggerName)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L69)setFrameworkLoggerName * **setFrameworkLoggerName(loggerName: string): void - Inherited from BaseFramework.setFrameworkLoggerName Set the default framework logger name * **@since** 4.0.0 ### [**](#setNamespace)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L63)setNamespace * **setNamespace(namespace: string): void - Inherited from BaseFramework.setNamespace ### [**](#startHeartBeat)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L543)publicstartHeartBeat * **startHeartBeat(): void ### [**](#stop)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L44)stop * **stop(): Promise\ - Inherited from BaseFramework.stop ### [**](#useConnectionMiddleware)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/framework.ts#L529)publicuseConnectionMiddleware * **useConnectionMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/ws/interface/Context.md), NextFunction, undefined>): void ### [**](#useFilter)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L57)useFilter * **useFilter(filter: CommonFilterUnion<[Context](/api/ws/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useFilter ### [**](#useGuard)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L58)useGuard * **useGuard(guards: CommonGuardUnion<[Context](/api/ws/interface/Context.md)>): void - Inherited from BaseFramework.useGuard ### [**](#useMiddleware)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/baseFramework.d.ts#L55)useMiddleware * **useMiddleware(middleware: CommonMiddlewareUnion<[Context](/api/ws/interface/Context.md), unknown, unknown>): void - Inherited from BaseFramework.useMiddleware --- # Context ### Hierarchy * [IMidwayWSContext](/api/ws.md#IMidwayWSContext) * *Context* ## Index[**](#Index) ### Properties * [**app](#app) * [**isAlive](#isAlive) * [**logger](#logger) * [**request](#request) * [**requestContext](#requestContext) * [**startTime](#startTime) * [**traceId](#traceId) ### Methods * [**getApp](#getApp) * [**getAttr](#getAttr) * [**getLogger](#getLogger) * [**setAttr](#setAttr) ## Properties[**](#Properties) ### [**](#app)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L44)app **app: [IMidwayWSApplication](/api/ws.md#IMidwayWSApplication) Inherited from IMidwayWSContext.app ### [**](#isAlive)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L45)isAlive **isAlive: boolean Inherited from IMidwayWSContext.isAlive ### [**](#logger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L692)logger **logger: ILogger Inherited from IMidwayWSContext.logger ### [**](#request)[**](https://github.com/midwayjs/midway/blob/3.x/packages/ws/src/interface.ts#L46)request **request: IncomingMessage Inherited from IMidwayWSContext.request ### [**](#requestContext)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L690)requestContext **requestContext: IMidwayContainer Inherited from IMidwayWSContext.requestContext Custom properties. ### [**](#startTime)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L694)startTime **startTime: number Inherited from IMidwayWSContext.startTime ### [**](#traceId)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L691)optionaltraceId **traceId? : string Inherited from IMidwayWSContext.traceId ## Methods[**](#Methods) ### [**](#getApp)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L709)getApp * **getApp(): IMidwayBaseApplication\ - Inherited from IMidwayWSContext.getApp Get current related application instance. ### [**](#getAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L705)getAttr * **getAttr\(key: string): T - Inherited from IMidwayWSContext.getAttr Get value from app attribute map *** #### Type parameters * **T** ### [**](#getLogger)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L693)getLogger * **getLogger(name? : string): ILogger - Inherited from IMidwayWSContext.getLogger ### [**](#setAttr)[**](https://undefined/midwayjs/midway/blob/3.x/packages/core/src/interface.d.ts#L700)setAttr * **setAttr(key: string, value: any): any - Inherited from IMidwayWSContext.setAttr Set value to app attribute map --- # 路由和控制器 midway 使用 koa-router 作为路由的承载者,同时在 ts 的语法上做了一些简化,我们将路由和控制器放在了一起,使用装饰器来标注路由。 由于 midway 采用了 IoC 自扫描机制,使得在一定程度上弱化了目录结构约定,通过装饰器的机制,可以非常方便的进行解耦,按业务逻辑拆分等。 现在可以在任意目录下创建 controller,不再限定 app/controller 目录,同理,其他装饰器也不限定。 现在可以做到比如 `src/web/controller` 下放 controller,也可以按业务维度分,比如 `user` 目录,包含跟用户相关所有的 controller/service/dao 等,对微服务或者 serverless 比较友好。 ### 路由装饰器[​](#路由装饰器 "路由装饰器的直接链接") 在新的 ts 体系中,我们的控制器目录为 `app/controller` ,我们在其中编写 `*.ts` 文件。例如下面的 `userController.ts` ,我们提供了一个获取用户的接口。 ``` import { provide, controller, inject, get } from 'midway'; @provide() @controller('/user') export class UserController { @inject('userService') service: IUserService; @inject() ctx; @get('/:id') async getUser(): Promise { const id: number = this.ctx.params.id; const user: IUserResult = await this.service.getUser({ id }); this.ctx.body = { success: true, message: 'OK', data: user }; } } ``` 我们创建了 `@controller` 装饰器用来定义这个类为 Controller,同时,提供了方法装饰器用于标注请求的类型。 小贴士 便于大家理解,`@controller` 的参数为字符串 pattern,我们会将这个值传入 `router.prefix(prefix)` 的参数中。 midway 针对 web 请求,提供了和 koa-router 对应的方法装饰器,列表如下。 * [@get](/get) * [@post](/post) * [@del](/del) * [@put](/put) * [@patch](/patch) * [@options](/options) * [@head](/head) * [@all](/all) 这几个装饰器用于修饰不同的异步方法,同时对应到了 koa-router 的相应的方法。和原有提供的控制器一样,每个控制器都为异步方法,默认参数为 koa 上下文。 ``` @get('/:id') async getUser(ctx): Promise { // TODO ctx... } ``` ### 路由绑定[​](#路由绑定 "路由绑定的直接链接") 在以往框架的写法中,提供的 `app/router` 文件,虽然可以直接使用,但是由于控制器被 IoC 管控的关系,会有一些区别。 和以往的写法不同的是,**我们需要从容器中拿到对应的控制器实例,并绑定到路由的 pattern 上**。 假如我们有一个控制器,同时没有提供 `@controller` 装饰器,表明他不是一个控制器,在应用初始化时不会自动绑定到某个路由上,但是由于有 `@provide` 装饰器,他会被 IoC 容器所加载。 ``` // app/controller/api.ts @provide() export class BaseApi { async index(ctx) { ctx.body = 'index'; } } ``` 假如我们希望这个控制器可以被外部的路由使用。 ``` // app/router.ts module.exports = function (app) { app.get('/api/index', app.generateController('baseApi.index')); }; ``` midway 扩展了一个 `app.generateController` 的方法来简化绑定的这个步骤,参数为 `ClassName.methodName` 的字符串形式。 ### 路由优先级[​](#路由优先级 "路由优先级的直接链接") 在单页应用下,经常会出现 `/*` 这种路由,在原本的路由文件中,我们可以通过调整代码的顺序,来使的路由的匹配顺序发生变化。而由于使用了装饰器的关系,在新的体系无法控制文件扫描和加载顺序,这就使得路由匹配的顺序不可控。 midway 提供了 `@priority(priority: number)` 装饰器,用于修饰 class,定义路由的优先级,默认的路由优先级为 `0`,可以设置负数让优先级降低。 ``` @provide() @priority(-1) @controller('/') export class HomeController { @get('/hello') async index(ctx) { ctx.body = 'hello'; } @get('/*') async all(ctx) { ctx.body = 'world'; } } ``` ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 有时候我们会有在特定路由上加载中间件的需求,在之前的版本只能通过定义 `router.ts` 文件来解决部分需求,而在新版本中,我们扩展了装饰器的能力,使之可以在特定场景下增加 web 中间件。 现在可以提供一个 middleware(任意目录),比如 `src/app/middleware/api.ts`。 ``` import { Middleware, WebMiddleware, provide, config } from 'midway'; @provide() export class ApiMiddleware implements WebMiddleware { @config('hello') helloConfig; resolve(): Middleware { return async (ctx, next) => { ctx.api = '222' + this.helloConfig.b; await next(); }; } } ``` 由于是 class,依旧可以使用 inject/plugin/config 等装饰器修饰。 提示 推荐使用 `WebMiddleware` 接口来规范你的 web 中间件。 ``` @provide() @controller('/', { middleware: ['homeMiddleware'] }) export class My { @inject() ctx; @get('/', { middleware: ['apiMiddleware'] }) async index() { this.ctx.body = this.ctx.home + this.ctx.api; } } ``` 在 `@controller` 和 `@get/post` 等路由装饰器上都提供了 middleware 参数。 这里的 middleware 参数是一个数组,可以传多个字符串或者 `koa middleware`,如果是字符串,会从 IoC 容器中获取对应的 `WebMiddleware` 接口实例的 `resolve` 方法的结果。 也可以直接传递 `koa middleware`。 ``` const mw: Middleware = async (ctx, next) => { ctx.home = '4444'; await next(); }; const newMiddleware = (data): Middleware => { return async (ctx, next) => { ctx.api = data; await next(); }; }; @provide() @controller('/', { middleware: ['homeMiddleware', mw] }) export class My { @inject() ctx; @get('/api', { middleware: ['apiMiddleware', newMiddleware('5555')] }) async index() { this.ctx.body = this.ctx.home + this.ctx.api; } } ``` ::: tip 这种方式只用于某个路由下的中间件,如果你希望使用全局中间件,那么请依旧使用 egg 的那种形式。 ::: #### 中间件注入的特殊性[​](#中间件注入的特殊性 "中间件注入的特殊性的直接链接") 由于中间件在生命周期的特殊性,会在应用请求前就被加载(绑定)到路由上,所以无法和上下文关联。 中间件类固定为单例(Singleton),所有注入的内容都为单例,包括但不限于 @config/@logger/[@plugin ](/plugin)等。 这意味着你可以注入一个 service,但是这个 service 中无法注入 ctx 属性。 这个时候,你必须在 `resolve` 方法中,通过调用 `ctx.requestContext.getAsync('xxx')` 的方式来创建请求作用域实例,和上下文绑定。 ``` @provide() export class ApiMiddleware implements WebMiddleware { @inject() myService; // 由于中间件实例属于单例,这个实例即使注入也无法获取到 ctx resolve(): Middleware { return async (ctx, next) => { // 必须通过从请求作用域中获取对象的方式,来绑定上下文 ctx.service = await ctx.requestContext.getAsync('myService'); await next(); }; } } ``` ### 一个方法挂载多个路由[​](#一个方法挂载多个路由 "一个方法挂载多个路由的直接链接") 新版本实现了在同一方法上可以挂载多个路由的能力。 ``` @provide() @controller('/', { middleware: ['homeMiddleware'] }) export class My { @inject() ctx; @get('/', { middleware: ['apiMiddleware'] }) @post('/api/data') async index() { this.ctx.body = this.ctx.home + (this.ctx.api || ''); } } ``` 这样请求进来, post 和 get 拿到的结果是不一样的(get 请求挂载了额外的中间件)。 --- # Debug 一个更简单的 Debug 方案,新版本 VSCode 已经支持了 autoAttach。 第一步,vsc 里按 cmd+shift+p,开启 auto attach。 \[ ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1598343869968-12f6eb2c-a38d-4670-9bc9-dac94f672bcc.png#align=left\&display=inline\&height=171\&margin=%5Bobject%20Object%5D\&originHeight=171\&originWidth=869\&size=0\&status=done\&style=none\&width=869) ]\() 第二步,修改,或者新增命令,其实就是在原来的命令后面传入调试参数。 ``` "test": "npm run lint && midway-bin test --ts --inspect", ``` 第三步,加入断点,在 vsc 的控制台(一定要在 vsc 里启动)执行命令,比如上面的 npm run test 即可断到。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1598343902763-e4ed8e5c-2dbc-48bb-a9f0-fd3cc2105c53.png#align=left\&display=inline\&height=2740\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=2740\&originWidth=3378\&size=1202444\&status=done\&style=none\&width=3378) --- # 高级装饰器 API midway 内部有一套标准的装饰器管理器,用来所有装饰器对接 IoC 容器,扫描和扩展,我们称之为 `decoratorManager` 。 标准的的代码参考为   通过 `decoratorManager` ,我们可以自定义装饰器,并且将元数据附加其中,内部的各种装饰器都是通过该能力实现的。 `decoratorManager`   上有非常多的 get/set 方法,用于不同场景装饰器的处理,常见的有: **装饰器** \*\* * `saveModule`  用于保存某个类到某个装饰器 * `listModule`  获取所有绑定到某类型装饰器的 class **元信息 (对应 **[**reflect-metadata**](https://www.npmjs.com/package/reflect-metadata)**)** \*\* * `saveClassMetadata`  保存元信息到 class * `attachClassMetadata`  附加元信息到 class * `getClassMetadata`  从 class 获取元信息 * `savePropertyDataToClass`   保存属性的元信息到 class * `attachPropertyDataToClass`  附加属性的元信息到 class * `getPropertyDataFromClass`  从 class 获取属性元信息 * `listPropertyDataFromClass`  列出输出所有的元数据 * `savePropertyMetadata`  保存属性元信息到属性本身 * `attachPropertyMetadata`  附加属性元信息到属性本身 * `getPropertyMetadata`   从属性上获取保存的元信息 **快捷操作** * `getProviderId`  获取 class 上 provide 出来的 id * `getObjectDefinition`  获取对象定义(ObjectDefiniton) * `getParamNames`  获取一个函数的所有参数名 * `clearAllModule`  清理装饰器对应的 class map(对应 saveModule) ## 自定义装饰器[​](#自定义装饰器 "自定义装饰器的直接链接") 我们举一个例子,如果我们需要定义一个类装饰器 @Model ,被修饰的 class 则表明是一个 Model class,然后进一步操作。 创建一个装饰器文件,比如 `src/decorator/model` 。 ``` import { scope, ScopeEnum, saveClassMetadata, saveModule } from 'midway'; const MODEL_KEY = 'decorator:model'; export function Model(): ClassDecorator { return (target: any) => { // 将装饰的类,绑定到该装饰器,用于后续能获取到 class saveModule(MODEL_KEY, target); // 保存一些元数据信息,任意你希望存的东西 saveClassMetadata( MODEL_KEY, { test: 'abc', }, target ); // 指定 IoC 容器创建实例的作用域,这里注册为请求作用域,这样能取到 ctx Scope(ScopeEnum.Request)(target); }; } ``` 上面只是定了了这个装饰器,我们还要实现相应的功能,这个功能文件必须在一开始就加载,midway2 开始有生命周期的概念,可以在生命周期中执行。midway1 可以在 `app.ts`  中执行。 ``` // 实现 Model 装饰器功能 import { listModule } from 'midway'; const MODEL_KEY = 'decorator:model'; // 可以获取到所有装饰了 @Model 装饰器的 class const modules = listModule(MODEL_KEY); for (let mod of modules) { // 实现自定义能力 // 从 mod 上拿元数据,做不同的处理 // 提前初始化等 app.applicationContext.getAsync(getProvideId(mod)); } ``` 最后,我们要使用这个装饰器。 ``` import { Model } from '../decorator/model'; // Provide 的作用是暴露出一个 IoC id,能被 IoC 扫描到 @provide() // Model 的作用是我们自己的逻辑能被执行(保存的元数据) @Model() export class UserModel {} ``` ## 清理信息[​](#清理信息 "清理信息的直接链接") 由于 `decoratorManager`  全局唯一,方法都为静态方法,所以在单测或者多 IoC 容器的场景下,需要对其进行清理。 ``` import { clearAllModule } from 'midway'; // 执行即可 clearAllModule(); ``` --- # 部署 ### 构建打包[​](#构建打包 "构建打包的直接链接") 由于 TypeScript 的特殊性,本地开发可以有 ts-node 等类似的工具进行开发,而在服务器端运行的时候,我们希望可以通过 js 来运行,这中间就需要编译工具。 ``` // 类型声明示例 type Config = { typescript: boolean; srcDir: string; } ``` 幸好 TypeScript 官方提供了 tsc 工具来帮助这个过程,而编译时会自动调用 `tsconfig.json` 来做一些编译时处理,midway 默认提供了一份该文件,用户也可以进行自定义。 同时,在脚手架中,我们提供了 `build` 命令帮助用户更好的生成文件。 信息 推荐在发布前本地进行 build,并通过 npm run start\_build 进行启动尝试,减少服务器端构建错误。 ``` "start_build": "npm run build && NODE_ENV=development midway-bin dev" ``` 通过 start\_build 启动的应用,将会自动本地编译,然后启动 dist 目录中的文件。 如果有一些自定义的文件需要在打包时拷贝,可以参考 [自定义打包](/docs/1.0.0/tool_set.md#build-%E5%91%BD%E4%BB%A4) ### 通过内置的启动文件[​](#通过内置的启动文件 "通过内置的启动文件的直接链接") midway 提供了一个内置的 `server.js` 来作为应用的启动入口,在大部分情况下,可以通过直接 require 该文件来进行启动。 比如使用 pm2 的场景下。 ``` // xxx.js require('midway/server'); ``` 或者使用我们 pandora 的场景下,会生成 procfile.js 文件,内容如下。 ``` 'use strict'; module.exports = (pandora) => { pandora.fork('[your app name]', require.resolve('midway/server')); }; ``` 通过内置的 server 文件,可以自动启动应用。 ### egg-scripts 方式[​](#egg-scripts-方式 "egg-scripts 方式的直接链接") 在以往的 egg 应用中,egg-scripts 也可以直接启动,但是不支持 [启动参数传递](#%E5%90%AF%E5%8A%A8%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92) 。 具体的文档请查看 [使用 egg-scripts 应用部署](https://eggjs.org/zh-cn/core/deployment.html)。 ### 启动参数传递[​](#启动参数传递 "启动参数传递的直接链接") 我们设计了一个机制,在 package.json 中配置服务器设置,只有依赖了 `midway/server` 文件才可以使用。 支持的参数见 [启动参数](https://github.com/eggjs/egg-cluster/blob/master/lib/master.js#L33),同时,midway 框架额外增加了几个参数。 * typescript `{boolean}` 如果为 true,则会开启 ts 模式,加载 src 或者 dist 目录,默认内部会进行判断,无需手动处理 * srcDir `{string}` 源码路径,默认为 src * targetDir `{string}` 编译后路径,默认为 dist ``` { "midway-server-options": { "workers": 1, "port": 3000 } } ``` 如果觉得不足,还可以使用 js 或者 json 文件进行定义。 ``` { "midway-server-options": "./server.json" // xxx.js } // in json { "workers": 1 } // in js module.exports = { workers: 1 } ``` ## 其他一些情况[​](#其他一些情况 "其他一些情况的直接链接") ### windows 支持[​](#windows-支持 "windows 支持的直接链接") 由于在 windows 上开发体验不是特别友好,以及一些库缺乏支持,在大部分情况下,我们优先推荐在 mac/linux 下开发 Node.js 应用。 需要注意的是,由于 windows 对设置环境变量的同步,默认生成的脚手架可能需要调整,主要是环境变量的部分。 比如开发命令,在设置环境的时候需要使用 `set` 以及中间需要增加 `&&` 以连接命令。 ``` { "dev": "set NODE_ENV=local && midway-bin dev --ts" } ``` --- # Docker 中进程过多 在 Docker 中部署,由于 egg 体系会根据 cpu 核数来启动进程,而 Docker 中获取的 cpu 数是错误的,就会导致启动非常多的 worker 进程。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588996147772-bb5c173c-e6bf-4412-af85-933ccc70b79d.png#align=left\&display=inline\&height=2474\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=2474\&originWidth=4760\&size=1722162\&status=done\&style=none\&width=4760) 解决方法为修改 workers 数量。 参考: --- # 介绍 组件扩展功能从 2.0 开始,请访问新版本文档。 --- # 框架增强 ## 框架增强注入[​](#框架增强注入 "框架增强注入的直接链接") midway 默认使用 [injection](http://web.npm.alibaba-inc.com/package/injection) 这个包来做依赖注入,虽然 `@inject` 装饰器能满足大多数业务的需求,但是对于框架来说,还有需要扩展和使用的地方,比如插件,配置等等。 ### 框架默认注入[​](#框架默认注入 "框架默认注入的直接链接") 在默认情况下,框架会注入一些属性,方便开发,这些属性都能通过 `@inject` 装饰器来注入。 ``` @inject() appDir; // 当前项目的根目录 @inject() baseDir; // 当前项目基础目录 src 或者 dist,绝对路径 @inject() ctx; // 请求作用域,koa ctx @inject() logger; // 请求作用域,ContextLogger ``` ### 注入插件[​](#注入插件 "注入插件的直接链接") midway 除了支持 eggjs 原本的 app.xx 的插件用法,为了和框架解耦,同时,也可以通过 `@plugin` 装饰器来注入插件。 我们以 `egg-jwt` 插件为例,这个插件提供了 `app.jwt` 对象,而 `@plugin` 装饰器,则是类似于直接从 app 对象上拿属性。 比如 `@plugin('jwt')`,其实就是 `app['jwt']`,这样的写法,就可以和 app 对象进行解耦。 ``` import { provide, plugin } from 'midway'; @provide() export class BaseService { @plugin() jwt; } ``` ### 注入配置[​](#注入配置 "注入配置的直接链接") 在 midway 中不同环境的 config 都会挂载到 app.config 中,但是不是所有的业务逻辑都会依赖 app 对象,所以我们构造了 `@config` 装饰器来获取配置对象。 假如 `config.default.ts` 中有一些代码。 ``` export const hello = 1; ``` ``` import { provide, config } from 'midway'; @provide() export class BaseService { @config('hello') config; // 1 } ``` 通过这样,我们可以把 config 中的值直接注入到业务逻辑中。 ### 注册定时任务[​](#注册定时任务 "注册定时任务的直接链接") midway 的定时任务是基于 [egg 定时任务](https://eggjs.org/zh-cn/basics/schedule.html)提供了更多 typescript 以及装饰器方面的支持。定时任务可以存放在任意目录,例如 src/schedule 目录下,可以配置定时任务的属性和要执行的方法。例如: ``` // src/schedule/hello.ts import { provide, schedule, CommonSchedule } from 'midway'; @provide() @schedule({ interval: 2333, // 2.333s 间隔 type: 'worker', // 指定某一个 worker 执行 }) export class HelloCron implements CommonSchedule { // 定时执行的具体任务 async exec(ctx) { ctx.logger.info(process.pid, 'hello'); } } ``` 信息 推荐使用 `CommonSchedule` 接口来规范你的计划任务类。 ### 注入日志对象[​](#注入日志对象 "注入日志对象的直接链接") 在原有逻辑中,日志对象也都挂载在 app.loggers 中,通过在 config 中配置的 key 来生成不同的日志实例对象,比如插件的日志,链路的日志等。 比如自定义一个日志 `myLogger`,这个时候,日志的 key 则为 `myLogger` 。 ``` module.exports = (appInfo) => { return { customLogger: { myLogger: { file: path.join(appInfo.root, 'logs/xx.log'), }, }, }; }; ``` 这个时候可以用 `@logger` 来获取日志实例。 ``` import { provide, logger } from 'midway'; @provide() export class BaseService { @logger('myLogger') logger; } ``` ### 请求作用域中的日志[​](#请求作用域中的日志 "请求作用域中的日志的直接链接") midway 在新版本中默认对所有对象开启了请求作用域,处于该作用域下的对象,都会包含一个默认的日志对象。 信息 该 logger 对象是在请求链路开始就埋入到 IoC 容器中,所以可以通过 [@inject ](https://www.yuque.com/inject)可以获取该对象, key 就为 logger,如果和属性同名则可以不填。 ``` @provide() export class BaseService { @inject() logger; // 也可以直接传入 key // @inject('logger') // logger; } ``` ## 框架扩展方法[​](#框架扩展方法 "框架扩展方法的直接链接") 抛开 eggjs 对 koa 的 application/context/request/response 的扩展点,midway 在 IoC 方面也做了一些扩展。 ### Application 扩展[​](#application-扩展 "Application 扩展的直接链接") 具体接口见 [API 文档](https://midwayjs.org/midway/api-reference/classes/midwayapplication.html) **baseDir** 由于 typescript 的关系,midway 的 app.baseDir 在开发时期指向了 `/src` 目录,而在构建之后部署阶段指向了 `/dist` 目录。 **appDir** 针对 baseDir 修改的情况,我们引入了一个新的 `app.appDir` 属性,用于指向应用根目录。 **applicationContext** `app.applicationContext` 用于全局作用域的 IoC 容器,所有的单例对象都存放于该属性,可以从中获取到单例对象。 ``` await app.applicationContext.getAsync('xxx'); ``` **pluginContext** 插件容器,用于存在现有的所有挂载在 app 上的插件实例。 ``` await app.pluginContext.getAsync('插件名'); ``` ### Context 扩展[​](#context-扩展 "Context 扩展的直接链接") **requestContext** 针对请求作用域的情况,我们在 context 对象上扩展了一个 `requestContext` 属性。 和 `applicationContext` 相同,也是 IoC 容器,用于存放一次请求链路上的对象,当请求结束后,该容器会被清空。 ``` await ctx.requestContext.getAsync('xxx'); ``` --- # 介绍 一体化功能从 2.0 开始,请访问新版本文档。 --- # 依赖注入手册 Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 ## 背景[​](#背景 "背景的直接链接") midway 默认使用 [injection](https://www.npmjs.com/package/injection) 这个包来做依赖注入,这个包也是 MidwayJs 团队根据业界已有的实现而产出的自研产品,它除了常见的依赖了注入之外,还满足了 Midway 自身的一些特殊需求。 这篇文章不仅仅是 IoC 体系的介绍,也是属于 [injection](https://www.npmjs.com/package/injection) 这个包的一份使用文档。 你不仅可以在 Midway 的开发过程中用到它,如果你希望,它也可以在你的模块开发中帮助到你,它可以单独使用,也可以和现有框架集成,比如 `koa`, `thinkjs` 等。 信息 我们在 midway 包上做了自动导出,所以 injection 包中的模块,都能从 midway 中获取到。 `import {Container} from 'injection'` 和 `import {Container} from 'midway'` 是一样的。 ## IoC 概览[​](#ioc-概览 "IoC 概览的直接链接") IoC([Inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control)) 控制反转,是 Java Spring 中非常重要的思想和核心,有不少人是第一次听说,也不禁会有许多疑问。 * 什么是控制反转? * 什么是依赖注入? * 它们之间有什么关系? 软件中的对象就像齿轮一样,协同工作,但是互相耦合,一个零件不能正常工作,整个系统就崩溃了。这是一个强耦合的系统。 现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。 ``` // 常见的依赖 import { A } from './A'; import { B } from './B'; class C { constructor() { this.a = new A(); this.b = new B(this.a); } } ``` 这里的 A 被 B 和 C 所依赖,而且在构造器需要进行实例化操作,这样的依赖关系在测试中会非常麻烦。这个依赖,一般被叫做 "耦合",而耦合度过高的系统,必然会出现牵一发而动全身的情形。 为了解决对象间耦合度过高的问题,软件专家 Michael Mattson 提出了 IoC 理论,用来实现对象之间的“解耦”。 控制反转(Inversion of Control)是一种是面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度。 ## 使用 injection 解耦[​](#使用-injection-解耦 "使用 injection 解耦的直接链接") 如果你使用了 midway,这些创建的过程将会自动完成,这里为了更好理解,我们将从头开始展示。 首先是安装依赖: ``` npm i injection --save ``` 然后我们将上面的代码进行解耦。 ``` // 使用 IoC import { Container } from 'injection'; import { A } from './A'; import { B } from './B'; const container = new Container(); container.bind(A); container.bind(B); class C { constructor() { this.a = container.get('a'); this.b = container.get('b'); } } ``` 这里的 `container`   就是 IoC 容器,是依赖注入这种设计模式的一种实现,使得 C 和 A, B 没有了强耦合关系,甚至,我们可以把 C 也交给 IoC 容器,所以,IoC 容器成了整个系统的关键核心。 信息 **注意** IoC 容器就像是一个对象池,管理这每个对象实例的信息(Class Definition),所以用户无需关心什么时候创建,当用户希望拿到对象的实例 (Object Instance) 时,可以直接拿到实例,容器会 **自动将所有依赖的对象都自动实例化**。 ## 获取 IoC 容器[​](#获取-ioc-容器 "获取 IoC 容器的直接链接") 所谓的容器就是一个对象池,它会在应用初始化的时候自动处理类的依赖,并将类进行实例化。比如下面的 `UserService` 类,在经过容器初始化之后,会自动实例化,并且对 `userModel` 进行赋值,看不到实例化的过程。 ``` class UserService { private userModel; async getUser(uid) { // TODO } } ``` Midway 内部使用了自动扫描的机制,在应用初始化之前,会扫描所有的文件,包含装饰器的文件会 **自动绑定** 到容器。 injection 的容器有几种: * AppliationContext 基础容器,提供了基础的增加定义和根据定义获取对象实例的能力 * Container 用的最多的容器,做了上层封装,通过 bind 函数能够方便的生成类定义,midway 从此类开始扩展 * RequestContext 用于请求链路上的容器,会自动销毁对象并依赖另一个容器创建实例。 其中 `Container` 是我们最常用的容器,下面的代码就是创建一个容器。 ``` import { Container } from 'injection'; const container = new Container(); ``` ## 对象定义[​](#对象定义 "对象定义的直接链接") 一个对象的基本元信息,比如名字,是否异步,有哪些属性,依赖等等,我们把这些信息组合到一起,形成一个对象定义。 对象定义往往表现在他的基础类型上, injection 内置了名为 `ObjectDefinition` 的对象定义类,它包含一系列属性,比如: * 有哪些属性 * 是否有依赖的对象 * 创建时是否是异步的 * 初始化方法是哪个 * 是否自动装配 以上只是列举了一小部分,通过这个定义,容器就可以将一个对象简单的创建出来。 `ObjectDefinition` 的具体属性文档,可以在 [这里看到](https://midwayjs.org/injection/api-reference/classes/objectdefinition.html) ## 绑定对象定义[​](#绑定对象定义 "绑定对象定义的直接链接") 我们在创建容器之后,将会往这个容器中添加一些对象定义,这样容器才能将对应对象创建出来。 ``` class UserService { private userModel; async getUser(uid) { // TODO } } // 内部代码 const container = new Container(); // 创建容器 container.bind('userService', UserService); // 可以在绑定的时候传一个名字作为 key container.bind(UserService); // 也可以直接传入 Class,自动分析对象的元信息生成对象定义 ``` `bind` 方法通过传入类型,自动分析类型上面包含的元信息,具体的 API 参数可以查看[这里](https://midwayjs.org/injection/api-reference/classes/container.html#bind)。 ## 普通情况下获取对象[​](#普通情况下获取对象 "普通情况下获取对象的直接链接") ``` //... 省略绑定逻辑 const userService = await container.getAsync('userService'); // 这里根据 key 获取对象 const user = await userService.getUser('123'); // 如果对象以及对象的依赖中没有异步的情况,也可以同步获取 const userService = container.get('userService'); const user = userService.getUser('123'); //... ``` 只有绑定过的对象定义才能通过 `get` 和 `getAsync` 方法创建出来。 如果一个对象依赖了另一个对象,那么在创建的时候,依赖的对象都会被自动创建并且在容器中管理起来。 信息 **Tip** 由于 Node.js 中大多对象或者依赖都需要支持异步的情况,所以一般情况下我们都使用 `getAsync` 方法。 ## 使用装饰器注入[​](#使用装饰器注入 "使用装饰器注入的直接链接") 如果每次代码都需要手动绑定,然后通过 `get/getAsync` 方法拿到对应的对象,那将会非常繁琐,由于 在设计之初 midway/injection 体系就基于 ts,参考了业界的 IoC 实现,完成了属于自己的依赖注入能力,主要是通过 `@provide` 和 `@inject` 两个装饰器来完成绑定定义和自动注入属性,大大简化了代码量。 信息 由于使用了依赖注入体系,我们希望所有的业务代码都通过 class 语法来完成 ``` @provide() export class UserService { @inject() userModel; async getUser(userId) { return await this.userModel.get(userId); } } ``` 我们可以看到业务代码的样子和以往有着一些不同。 * 类加了装饰器,同时直接导出,不需要关心如何实例化 * 属性加了装饰器,但是没有任何初始化以及赋值的操作即可使用 ### @provide()[​](#provide "@provide()的直接链接") 有了 `@provide()` 装饰器,就可以简化绑定,被 IoC 容器自动扫描,并绑定定义到容器上,对应的逻辑是 [绑定对象定义](#%E7%BB%91%E5%AE%9A%E5%AF%B9%E8%B1%A1%E5%AE%9A%E4%B9%89)。 `@provide(id?)` 的参数为对象 id,可选。 信息 **注意** [@provide ](https://www.yuque.com/provide)装饰器是用于自动被 IoC 容器装载。 ### @inject()[​](#inject "@inject()的直接链接") `@inject()` 的作用是将容器中的定义实例化成一个对象,并且绑定到属性中,这样,在调用的时候就可以访问到该属性。 注入的时机为构造器(new)之后,所以在构造方法(constructor)中是无法获取注入的属性的,如果要获取注入的内容,可以使用 [构造器注入](#%E6%9E%84%E9%80%A0%E5%99%A8%E6%B3%A8%E5%85%A5)。 父类的属性使用 `@inject()` 装饰器装饰,子类实例会得到装饰后的属性。 ``` class Parent { @inject() katana1; } class Child extends Parent { @inject() katana2; } class Grandson extends Child { @inject() katana3; } ``` `Grandson` 的实例 `gradson` 拥有 `@inject()` 装饰器注入的 `grandson.katana3`, `grandson.katana2`, `grandson.katana1` 属性。 实现时,会查找 `Gradson` 的原型链,遍历原型链上所有用 `@inject()` 装饰的属性,运行装饰器,注入相应的属性。 查找类的原型使用 [reflect-metadata](https://github.com/rbuckton/reflect-metadata) 仓库的 [OrdinaryGetPrototypeOf](https://github.com/rbuckton/reflect-metadata/blob/c2dbe1d02ceb9987f9002eedf0cdb21d74de0019/Reflect.ts#L1553-L1583) 方法,使用 `recursiveGetPrototypeOf` 方法以数组形式返回该类的所有原型。 ``` function recursiveGetPrototypeOf(target: any): any[] { const properties = []; let parent = ordinaryGetPrototypeOf(target); while (parent !== null) { properties.push(parent); parent = ordinaryGetPrototypeOf(parent); } return properties; } ``` ## 对象 id[​](#对象-id "对象 id的直接链接") 在默认情况下,injection 会将类名变为 `驼峰` 形式作为对象 id,这样你可以通过容器获取实例。 ``` container.getAsync('userService'); // 根据字符串 id 获取实例 container.getAsync(UserService); // 传入类名,自动根据类目获取实例 ``` 而默认情况下,Midway 的依赖注入使用的是 `byName` ,只要同名,就会自动进行注入。 而在某些场景下,用户希望注入不同的实例,这个时候可以对默认生成的 id 进行修改。 ``` @provide('uModel') export class UserModel {} @provide('user') export class UserService { @inject('uModel') userModel; async getUser(userId) { return await this.userModel.get(userId); } } // 使用修改之后的 id 获取对象 const userService = await container.getAsync('user'); ``` 同理,在使用 `@inject` 的时候也可以使用不同的 id。 ## 构造器注入[​](#构造器注入 "构造器注入的直接链接") 除了标准的属性注入方法之外,midway 在一定程度上支持了构造器注入的方式,来让一些应用或者三方包平稳过度。 同样还是使用 `@inject` 装饰器。 ``` @provide() export class A { config = { c: 20, }; } @provide() export class B { config = { c: 40, }; } @provide() export class BaseService { config; plugin2; constructor(@inject() a, @config('hello') config, @inject() b, @plugin('plugin2') plugin2) { this.config = Object.assign(config, { c: a.config.c + b.config.c + config.c, }); this.plugin2 = plugin2; } } ``` 在一个类的构造器中,我们可以还可以使用其他的类似 `@config`, `@plugin`, `@logger` 等装饰器。只要是通过 IoC 管理的对象,都能够被自动依赖和注入。 ## 配置作用域[​](#配置作用域 "配置作用域的直接链接") 在 injection 体系中,有三种作用域。 * Singleton 单例,全局唯一(进程级别) * Request  **默认**,请求作用域,生命周期随着请求链路,在请求链路上唯一,请求结束立即销毁 * Prototype 原型作用域,每次调用都会重复创建一个新的对象 在这三种作用域中,midway 的默认作用域为 **请求作用域**,这也意味着,如果我们需要将一个对象定义为其他两种作用域,需要额外的配置。 injection 提供了 `@scope` 装饰器来定义一个类的作用域。 ``` @scope(ScopeEnum.Prototype) @provide('petrol') export class PetrolEngine implements Engine { capacity = 10; } @scope(ScopeEnum.Singleton) @provide('diesel') export class DieselEngine implements Engine { capacity = 20; } // in IoC Container assert(container.getAsync('petrol') === container.getAsync('petrol')); // false assert(container.getAsync('diesel') === container.getAsync('diesel')); // true ``` 插件,在 midway 中为单例,不可配置。 ## 异步初始化[​](#异步初始化 "异步初始化的直接链接") 在某些情况下,我们需要一个实例在被其他依赖调用前需要初始化,如果这个初始化只是读取某个文件,那么可以写成同步方式,而如果这个初始化是从远端拿取数据或者连接某个服务,这个情况下,普通的同步代码就非常的难写。 midway 提供了异步初始化的能力,通过 `@init` 标签来管理初始化方法。 `@init` 方法目前只能是一个。 ``` @provide() export class BaseService { @config('hello') config; @plugin('plugin2') plugin2; @init() async init() { await new Promise((resolve) => { setTimeout(() => { this.config.c = 10; resolve(); }, 100); }); } } ``` [@async ](/async)装饰器已废弃,所有的 init 方法默认都会异步,同步初始化可以直接在构造器执行,此装饰器没有意义。 只要在方法上标记 `@init` 装饰器之后,这个时候会自动在实例化之后,通过异步的来调用 `@init`   标记的方法。 ## 动态函数注入[​](#动态函数注入 "动态函数注入的直接链接") 在某些场景下,我们需要函数作为某个逻辑动态执行,而 IoC 中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。 比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个函数,并且在函数中拿到上下文。 标准的函数注入样例。 ``` export function contextHandler(context) { return async () => { // const xxx = context.getAsync('xxxx'); return true; }; } providerWrapper([ { id: 'contextHandler', provider: contextHandler, }, ]); ``` 使用端。 ``` @provide() export class BaseService { @inject() contextHandler: () => Promise; } ``` midway 通过 `providerWrapper` 函数来包裹一个函数,并且指定提供的 key,供其他 IoC 对象使用。由于函数直接传递了一个 context 对象,可以轻松的通过此对象拿到所需的其他对象,而不需要管理依赖。 函数注入大多数为了创建一个简单的工厂。 ``` export function adapterFactory(context: IApplicationContext) { return async (adapterName: string) => { if (adapterName === 'google') { return await context.getAsync('googleAdapter'); } if (adapterName === 'baidu') { return await context.getAsync('baiduAdapter'); } // return await context.getAsync(adapterName + 'Adapter'); }; } providerWrapper([ { id: 'adapterFactory', provider: adapterFactory, }, ]); ``` 这样在业务中,可以直接来使用了。 ``` @provide() export class BaseService { @config('adapterName') adapterName; @inject('adapterFactory') factory; adapter: Adapter; @init() async init() { this.adapter = await this.factory(this.adapterName); } } ``` 信息 这个函数可以是异步的 (async)。 再举个例子,比如如果应用希望自己使用 sequelize, 而 sequelize 的创建 model 的过程是个异步操作,代码就可以这么写: ``` import { providerWrapper, IApplicationContext } from 'midway'; import * as Sequelize from 'sequelize'; import { Sequelize as SequelizeInstance } from 'sequelize'; // 可以直接写 async 方法 export async function factory(context: IApplicationContext) { const instance = await context.getAsync('coreDB'); const UiKeyTraceModel = instance.define( name, { gmtCreate: { type: Sequelize.DATE, allowNull: true, field: 'gmt_create', }, gmtModified: { type: Sequelize.DATE, allowNull: true, field: 'gmt_modified', }, }, { timestamps: true, createdAt: 'gmt_create', updatedAt: 'gmt_modified', freezeTableName: true, tableName: 'xxxx', } ); return UiKeyTraceModel; } providerWrapper([ { id: 'keyTraceModel', provider: factory, }, ]); ``` 通过 `providerWrapper` 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。 ## 注入已有对象[​](#注入已有对象 "注入已有对象的直接链接") 有时候,应用已经有现有的实例,而不是类,比如引入了一个第三库,这个时候如果希望对象能够被其他 IoC 容器中的实例引用,也可以通过增加对象的方式进行处理。 我们拿常见的 http 请求库 [urllib](https://www.npmjs.com/package/urllib) 来举例。 假如我们希望在不同的类中来使用,并且不通过 require 的方式,你需要在容器的入口通过 [registerobject](https://midwayjs.org/injection/api-reference/classes/container.html#registerobject) 方法添加这个对象。 在添加的时候需要给出一个 key,方便其他类中注入。 ``` // in global file import * as urllib from 'urllib'; container.registerobject('httpclient', urllib); ``` 这个时候就可以在任意的类中通过 `@inject` 来使用了。 ``` @provide() export class BaseService { @inject() httpclient; async getUser() { return await this.httpclient.request('/api/getuser'); } } ``` 信息 在 midway 中可以在 src/app.ts 中进行添加。 ## 通过依赖图排错[​](#通过依赖图排错 "通过依赖图排错的直接链接") 在业务代码中,我们可能会碰到依赖注入不生效或者作用域配置错误的问题,这个时候由于容器管理的问题显得不透明,用户也不太清楚容器里有哪些东西,分别依赖了什么。 我们提供了一个依赖树生成的方法,目前可以通过它生成文本形式的图形。 ``` const container = new Container(); container.bind(UserService); container.bind(UserController); container.bind(DbAPI); const newTree = await container.dumpDependency(); console.log(newTree); ``` 通过 `dumpDependency` 方法生成的文本,可以直接在 [viz-js](http://viz-js.com/) 渲染为图案,方便排查问题。 也可以通过安装 `graphviz` 等工具将文本树转化为图片形式。 信息 midway 在启动时会将依赖树生成到 /run 目录下,方便排错。 --- # 基础介绍 ## 介绍[​](#介绍 "介绍的直接链接") Midway 自 2013 年开始,基本保持着一年一个大版本的迭代速度进行更新,从 express 到 koa1/2,从未缺席。 如今,集团内外的 Node.js 大环境早已脱离原有的前后端分离体系,朝着全栈的方向大步迈进,有着欣喜,有着期待,对此,MidwayJs 团队不仅仅承担着引导,支撑集团 Node.js 应用的责任,也同时通过 `Pandora.js` ,`Sandbox`   等不同形式来让应用变的更加稳定,可靠。 在 2017 年,我们将集团内部的 Midway 5.3 升级到了基于 Koa2 的模型,全面支持了 async/await 的编码风格。 同年年中,我们开始计划将监控和数据采集能力进行抽象剥离,形成了全新 Pandora.js 工具,不仅仅服务于 Midway,也服务于全网,乃至外部所有的 Node.js 应用。 2018 年,MidwayJs 团队将基于 TypeScript,将 Midway6 在新的语言层面进行升级,让用户在开发体验上更近一步,对外部则是从第一个版本开始。 为什么选择 TypeScript ? 相信[ 这篇文章](https://juejin.im/post/59c46bc86fb9a00a4636f939) 会给你一些答案。 ## 关于 Midway[​](#关于-midway "关于 Midway的直接链接") Midway (中途岛) 品牌是淘宝技术部(前淘宝 UED)前端部门研发的一款基于 Node.js 的全栈开发解决方案。它将搭配团队的其他产品,Pandora.js 和 Sandbox,将 Node.js 的开发体验朝着全新的场景发展,让用户在开发过程中享受到前所未有的愉悦感。 --- # 全局中间件 当前,midway v1 的全局中间件为 egg 提供,使用 egg 写法,和路由中间件有所区别,并且**不能使用**注入的形式使用。 ## 写一个全局中间件[​](#写一个全局中间件 "写一个全局中间件的直接链接") 我们先来通过编写一个简单的 report 中间件,来看看中间件的写法。 ``` // src/app/middleware/report.ts module.exports = () => { return async function (ctx, next) { const startTime = Date.now(); await next(); // 上报请求时间 reportTime(Date.now() - startTime); }; }; ``` 可以看到,框架的中间件和 Koa 的中间件写法是一样的,所以任何 Koa 的中间件都可以直接被框架使用。 在 `config.default.ts`  中配置。 ``` module.exports = { middleware: ['report'], }; ``` 这里配置的名字和文件名一致。 ## 直接使用 koa 中间件[​](#直接使用-koa-中间件 "直接使用 koa 中间件的直接链接") 如果希望直接使用 koa 中间件,以 koa-compress 为例,在 Koa 中使用时,我们按照框架的规范来在应用中加载这个 Koa 的中间件: ``` // src/app/middleware/compress.ts // koa-compress 暴露的接口((options) => middleware)和框架对中间件要求一致 module.exports = require('koa-compress'); ``` 配置 ``` // src/config/config.default.js module.exports = { middleware: ['compress'], }; ``` --- # 快速上手 ### 安装 Node 环境[​](#安装-node-环境 "安装 Node 环境的直接链接") 可以访问 Node.js 官网或者使用 nvm 等类似产品,不再赘述。 ### 创建新应用[​](#创建新应用 "创建新应用的直接链接") 使用 [midway-init](https://www.npmjs.com/package/midway-init) 工具自动创建 midway 应用的目录结构: ``` $ npm i midway-init -g $ midway-init ``` 通过生成的 `npm scripts` 来驱动启动命令: ``` $ npm install $ npm run dev ``` ### 了解目录结构[​](#了解目录结构 "了解目录结构的直接链接") midway 的目录和 eggjs 目录非常接近,但也有所区别,不同的地方在于: * ts 源码存放于 `/src` 目录下,编译后代码存放于 `/dist` 下 * 以往的 app 等都迁移至 `/src/app` 下,作为 web 层 * 传统的业务逻辑等,移动到其他目录,比如 `/service` ``` ➜ midway6-test tree -I node_modules . ├── README.md ├── README.zh-CN.md ├── dist ---- 编译后目录 ├── logs ---- 本地日志目录 │   └── midway6-test ---- 日志应用名开头 │   ├── common-error.log ---- 错误日志 │   ├── midway-agent.log ---- agent 输出的日志 │   ├── midway-core.log ---- 框架输出的日志 │   ├── midway-web.log ---- koa 输出的日志 │   └── midway6-test-web.log ├── package.json ├── src ---- 源码目录 │   ├── app ---- web 层目录 │   │   ├── controller ---- web 层 controller 目录 │   │   │   ├── home.ts │   │   │   └── user.ts │   │   ├── middleware (可选) ---- web 层中间件目录 │   │   │   └── trace.ts │   │   ├── public (可选) ---- web 层静态文件目录,可以配置 │ │ ├── view (可选) │ │ | └── home.tpl ---- web 层模板 │   ├── config │   │   ├── config.default.ts │   │   ├── config.local.ts │   │   ├── config.prod.ts │   │   ├── config.unittest.ts │   │   └── plugin.ts │   └── service ---- 业务逻辑层目录,自由定义 │   │   └── user.ts ---- 业务逻辑层,自由定义 │   ├── interface.ts ---- 接口定义文件,自由定义 │   ├── app.ts ---- 应用扩展文件,可选 │   └── agent.ts ---- agent 扩展文件,可选 ├── test │   └── app │   └── controller │   └── home.test.ts ├── tsconfig.json └── tslint.json ``` 如上,由框架约定的目录,Midway 使用 EggJs 作为 Web 层容器,承载请求控制器和传统 MVC 层的工作,这一块由于受到限制,有着一定的目录约定: * `src/app/router.ts` 可选,用于配置 URL 路由规则,具体参见 [Router](https://eggjs.org/zh-cn/basics/router.html)。 * `src/app/controller/**` 用于解析用户的输入,处理后返回相应的结果,具体参见 [Controller](/docs/1.0.0/hController)。 * `src/app/middleware/**` 可选,用于编写中间件,具体参见 [Middleware](https://eggjs.org/zh-cn/basics/middleware.html)。 * `src/app/extend/**` 可选,用于框架的扩展,具体参见[框架扩展](https://eggjs.org/zh-cn/basics/extend.html)。 * `src/config/config.{env}.ts` 用于编写配置文件,具体参见[配置](https://eggjs.org/zh-cn/basics/config.html)。 * `src/config/plugin.ts` 用于配置需要加载的插件,具体参见[插件](https://eggjs.org/zh-cn/basics/plugin.html)。 * `test/**` 用于单元测试,具体参见[单元测试](https://eggjs.org/zh-cn/core/unittest.html)。 * `src/app.ts` 和 `agent.ts` 用于自定义启动时的初始化工作,可选,具体参见[启动自定义](https://eggjs.org/zh-cn/basics/app-start.html)。关于`agent.js`的作用参见[Agent 机制](https://eggjs.org/zh-cn/core/cluster-and-ipc.html#agent-%E6%9C%BA%E5%88%B6)。 而其他由于 Egg 插件的限制,可能有些目录也会有相应的约定,比如: * `src/app/public/**` 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)。 * `src/app/view/**` 用于放置模板文件,可选,由模板插件约定,具体参见[模板渲染](https://eggjs.org/zh-cn/core/view.html)。 我们会发现常见的代码都会存放于 `/src` 目录下,由于 ts 的特殊性,在服务器上会通过打包构建为 `*.js` 文件存放于 `/dist` 目录。将源文件和编译后文件分开是我们最开始的初衷。 而除了 app 目录以外的其他目录,在 midway 体系下并没有严格的规定,大体可以按照逻辑分层,比如按照传统的 `web, biz, service, manager, dao` 等进行分层进行创建目录就非常不错。 ::: tip 由于 Midway 采用了自动扫描装配,依赖注入等特性,无需在特定的目录下受到限制,使得在全栈应用开发的时候,保持了不错的开发体验。 ::: ## 快速开发引导[​](#快速开发引导 "快速开发引导的直接链接") 想要快速上手 midway,除了需要了解一些基础的东西: * 虽然可以直接用 js 的语法书写,但是你最好了解 TypeScript,这里有个 [快速介绍](/docs/1.0.0/ts_start.md)。 * 尽可能使用面向对象的思想来编码,它的经久不衰是有道理的,使用 class 机制能够方便的融入我们的新特性。 * 了解 midway 的依赖注入体系,以及常用的装饰器,这里做了 [依赖注入的介绍](/docs/1.0.0/ioc.md)。 * 如果你在 midway 的文档中没有找到你想要的东西,记住可以去 [Egg 的文档找找](https://eggjs.org/zh-cn/intro/),或者 [向我们提 Issue](https://github.com/midwayjs/midway/issues)。 ## 和 Egg 体系相同的部分[​](#和-egg-体系相同的部分 "和 Egg 体系相同的部分的直接链接") 这部分的内容和 Egg 体系基本是相同的,大体不同的是后缀的区别 `*.ts`,以及根目录(midway 的根目录在 src)。 ### 运行环境[​](#运行环境 "运行环境的直接链接") 目前没有做特殊处理,完全一样,查看[运行环境文档](https://eggjs.org/zh-cn/basics/env.html)。 ### 配置[​](#配置 "配置的直接链接") 框架支持根据环境来加载配置,定义多个环境的配置文件,唯一不同的是后缀的区别,具体环境请查看[运行环境配置](https://eggjs.org/zh-cn/basics/env.html) ``` src/config |- config.default.ts |- config.prod.ts |- config.unittest.ts `- config.local.ts ``` ### Web 中间件[​](#web-中间件 "Web 中间件的直接链接") 除了目录在 `src/app/middleware` 以及后缀名为 `*.ts` ,其余完全一样,查看[中间件文档](https://eggjs.org/zh-cn/basics/middleware.html)。 ### Router 路由[​](#router-路由 "Router 路由的直接链接") `src/app/router.ts` 文件依旧可用,推荐使用 midway 体系的 [路由装饰器](#%E8%B7%AF%E7%94%B1%E8%A3%85%E9%A5%B0%E5%99%A8),egg 的路由文档在[这里](https://eggjs.org/zh-cn/basics/router.html)。 ### 框架扩展[​](#框架扩展 "框架扩展的直接链接") 针对框架自身的扩展点,依旧保留可用,目录变为 `src/app/*.ts`,文档查看 [框架扩展](https://eggjs.org/zh-cn/basics/extend.html)。 ### 启动自定义[​](#启动自定义 "启动自定义的直接链接") 启动自定义依旧保留可用,目录变为 `src/app.ts`,文档查看 [启动自定义](https://eggjs.org/zh-cn/basics/app-start.html)。 如果想在 `app.ts` 中调用 IoC 中的对象,可以通过以下方法。 ``` // app.js module.exports = (app) => { app.beforeStart(async () => { // 从全局作用域拿单例对象 const obj = await app.applicationContext.getAsync('xxx'); // 从请求作用域拿对象 const ctx = app.createAnonymousContext(); const obj = await ctx.requestContext.getAsync('xxx'); }); }; ``` --- # 介绍 Serverless 功能从 2.0 开始,请访问新版本文档。 --- # 应用测试 经过大量的实践,我们沉淀出了一套标准的测试工具集。 * 测试工具包 [midway-bin](https://www.npmjs.com/package/midway-bin) * 测试框架 mocha * 测试断言库 assert/chai * 测试模拟 [midway-mock](https://www.npmjs.com/package/midway-mock) ### 测试目录结构[​](#测试目录结构 "测试目录结构的直接链接") 我们约定 `test` 目录为存放所有测试脚本的目录,测试所使用到的 `fixtures` 和相关辅助脚本都应该放在此目录下。 测试脚本文件统一按 `${filename}.test.ts` 命名,必须以 `.test.ts` 作为文件后缀。 一个应用的测试目录示例: ``` test ├── controller │ └── home.test.ts ├── hello.test.ts └── service └── user.test.ts ``` ### 测试命令[​](#测试命令 "测试命令的直接链接") 在脚手架中,我们已经将常见的命令进行内置,可能略微有些不同,大致代码如下。 ``` { "scripts": { "test": "midway-bin test --ts", "cov": "midway-bin cov --ts" } } ``` 然后就可以按标准的  `npm test`  来运行测试了。 ``` npm test > unittest-example@test /Users/harry/midwayj/examples/unittest > midway-bin test --ts test/hello.test.ts ✓ should work 1 passing (10ms) ``` ### 开始测试[​](#开始测试 "开始测试的直接链接") 在测试运行之前,我们首先要创建应用的一个 app 实例, 通过它来访问需要被测试的 Controller、Middleware、Service 等应用层代码。 通过 `midway-mock`,结合 Mocha 的 `before` 钩子就可以便捷地创建出一个 app 实例。 ``` // test/controller/home.test.js import { mm } from 'midway-mock'; describe('test/controller/home.test.ts', () => { let app; before(() => { // 创建当前应用的 app 实例 app = mm.app(); // 等待 app 启动成功,才能执行测试用例 return app.ready(); }); }); ``` 这样我们就拿到了一个 app 的引用,接下来所有测试用例都会基于这个 app 进行。 更多关于创建 app 的信息请查看 [mm.app(options)](https://github.com/eggjs/egg-mock#options) 文档。 每一个测试文件都需要这样创建一个 app 实例非常冗余,因此 `midway-mock` 提供了一个 bootstrap 文件,可以直接从它上面拿到我们所常用的实例: ``` // test/controller/home.test.ts import { app, mock, assert } from 'midway-mock/bootstrap'; describe('test/controller/home.test.ts', () => { // test cases }); ``` ### Controller 测试[​](#controller-测试 "Controller 测试的直接链接") 我们可以通过 app.httpRequest() [SuperTest](https://github.com/visionmedia/supertest) 发起一个真实的 HTTP 请求来进行测试。app.httpRequest() 是 midway-mock 封装的 SuperTest 请求实例。 例如我们要给 `app/controller/home.ts`: ``` import { controller, get, provide } from 'midway'; @provide() @controller('/') export class HomeController { @get('/') async index(ctx) { ctx.body = `Welcome to midwayjs!`; } } ``` 写一个完整的单元测试,它的测试代码 `test/controller/home.test.ts` 如下: ``` import { app, assert } from 'midway-mock/bootstrap'; describe('test/controller/home.test.ts', () => { it('should GET /', () => { // 对 app 发起 `GET /` 请求 return app .httpRequest() .get('/') .expect('Welcome to midwayjs!') // 期望 body 是 hello world .expect(200); // 期望返回 status 200 }); }); ``` 通过基于 SuperTest 的 app.httpRequest() 可以轻松发起 GET、POST、PUT 等 HTTP 请求,并且它有非常丰富的请求数据构造接口,请查看 [SuperTest](https://github.com/visionmedia/supertest#getting-started) 文档。 ### Service 测试[​](#service-测试 "Service 测试的直接链接") 由于 midway 提倡使用 IoC 的方式来定义 service,所以编码与测试都与 eggjs 有明显的区别。 例如 `src/service/user.ts`: ``` import { provide } from 'midway'; import { IUserService, IUserOptions, IUserResult } from '../../interface'; // 装载 service 到 IoC 容器 @provide('userService') export class UserService implements IUserService { async getUser(options: IUserOptions): Promise { return new Promise((resolve) => { // 10ms 之后返回用户数据 setTimeout(() => { resolve({ id: options.id, username: 'mockedName', phone: '12345678901', email: 'xxx.xxx@xxx.com', }); }, 10); }); } } ``` 编写单元测试 `test/service/user.test.ts`: ``` import { app, assert } from 'midway-mock/bootstrap'; import { IUserService } from '../../src/interface'; describe('test/service/user.test.ts', () => { it('#getUser', async () => { // 取出 userService const user = await app.applicationContext.getAsync('userService'); const data = await user.getUser({ id: 1 }); assert(data.id === 1); assert(data.username === 'mockedName'); }); }); ``` app.applicationContext 是 IoC 容器的应用上下文, 通过它可以异步取出注入的 service,并使用 service 进行测试。完整 demo 可以参见 [midway-test-demo](https://github.com/Lellansin/midway-test-demo)。 ### 使用 Jest[​](#使用-jest "使用 Jest的直接链接") Midway 在单元测试框架上,不仅支持 Mocha,也对 Jest 做了相应支持。具体使用步骤如下: 1.在项目根目录安装以下依赖: ``` $ npm install jest @types/jest ts-jest -D ``` 2. 修改 `tsconfig.json`,避免 Mocha 与 Jest 的类型定义文件冲突 ``` { "compilerOptions": { "types": ["jest"] } } ``` 3. 在项目根目录下新增 `jest.config.js` 文件,内容如下: ``` module.exports = { preset: 'ts-jest', testEnvironment: 'midway-bin/jest/env.js', }; ``` 4. 配置 npm scripts,修改 test 命令 ``` { "scripts": { "test": "jest --forceExit" } } ``` 5. 运行 npm scripts,即可使用 Jest 完成单测 ``` npm run test ``` ::: tip 我们也提供了可运行 demo 供大家参考:[demo-unittest-jest](https://github.com/midwayjs/midway-examples/tree/4a22e07c661a01aa05221fe56e11dce6c9bfc604/demo-unittest-jest) ::: --- # midway 高级测试方案 ### 测试应用[​](#测试应用 "测试应用的直接链接") 普通场景下,从 Controller 开始测试,这个时候需要启动整个应用来测试路由。 ``` import { app, assert } from 'midway-mock/bootstrap'; describe('test/controller/home.test.ts', () => { it('should GET /', () => { // 对 app 发起 `GET /` 请求 return app .httpRequest() .get('/') .expect('Welcome to midwayjs!') // 期望 body 是 hello world .expect(200); // 期望返回 status 200 }); }); ``` ### 测试 Service[​](#测试-service "测试 Service的直接链接") 如果单独测试 Service,分两种情况。 **1、测试单例(无 ctx 关联)** \*\* 直接从 app 上挂载的 `applicationContext`  属性中获取 Service 实例,进而调用方法。 ``` import { app, assert } from 'midway-mock/bootstrap'; import { IUserService } from '../../src/interface'; describe('test/service/user.test.ts', () => { it('#getUser', async () => { // 取出 userService const user = await app.applicationContext.getAsync('userService'); const data = await user.getUser({ id: 1 }); assert(data.id === 1); assert(data.username === 'mockedName'); }); }); ``` **2、测试请求作用域(带有 ctx)** 一般场景下,Service 中可能含有 `@inject() ctx`  的代码,会有从 ctx 取东西,这样的 Service 必须和一个请求相关联,而在 egg 体系中,必须先创建一个匿名上下文才行。 ``` import { app, assert } from 'midway-mock/bootstrap'; import { IUserService } from '../../src/interface'; describe('test/service/user.test.ts', () => { it('#getUser', async () => { // 创建匿名上下文 const ctx = app.mockContext(); // 取出 userService const user = await ctx.requestContext.getAsync('userService'); const data = await user.getUser({ id: 1 }); assert(data.id === 1); assert(data.username === 'mockedName'); }); }); ``` **3、覆盖某些服务的方法** \*\* 如果想在测试时覆盖某些方法的返回值,可以通过 `app.mockClassFunction`  的方式来进行。 ``` import { app, assert } from 'midway-mock/bootstrap'; import { IUserService } from '../../src/interface'; // service,放在文件中 @provide('userService') export class UserService { async getUser() { return 'zhang'; } } describe('test/service/user.test.ts', () => { it('#getUser', async () => { app.mockClassFunction('userService', 'getUser', () => { return 'chen'; }); // 取出 userService const user = await app.applicationContext.getAsync('userService'); const data = await user.getUser(); // chen }); }); ``` **4、使用 IoC 某些服务的方法** 有时候,会有覆盖某些 Service 的特定属性,模拟返回值的需求。利用 IoC 的特性,我们可以做一个假的服务去替换原本的那个,只要**保持 id 相等**。 信息 我们把真的服务放在 src 中,假的放在 test 目录中,这样对线上服务就不会有影响。 ``` // 真正的 service,放在 service/user.ts @provide('userService') export class UserService { async getUser() { return 'zhang'; } } // 假的服务,我们放在 test/service/user.ts 中 // 继承可以方便的只做特定逻辑的覆盖 // 保持 @provide 出原本的 id @provide('userService') export class MockUserService extends UserService { async getUser() { return 'chen'; } } ``` 测试代码 ``` import { mm, assert } from 'midway-mock'; import { IUserService } from '../../src/interface'; import { MockUserService } from '../service/user'; describe('test/service/user.test.ts', () => { it('#getUser', async () => { const app = mm.app(); await app.ready(); // 用同样的 id 替换真的 service,后续逻辑和其他测试相同 app.applicationContext.bindClass(MockUserService); // 创建匿名上下文 const ctx = app.mockContext(); // 取出 userService const user = await ctx.requestContext.getAsync('userService'); const data = await user.getUser({ id: 1 }); assert(data.id === 1); assert(data.username === 'mockedName'); }); }); ``` --- # midway 工具集 ## midway-bin[​](#midway-bin "midway-bin的直接链接") midway-bin 通过继承了 egg-bin,扩展一些跟 ts 相关的命令。 ### 安装[​](#安装 "安装的直接链接") 默认脚手架已经自带。 ``` npm install midway-bin --save-dev ``` ### 常用命令[​](#常用命令 "常用命令的直接链接") 包括 egg-bin 自带的: * midway-bin test 测试命令, ts 使用时需要带上 `--ts` * midway-bin cov 生成覆盖率命令, ts 使用时需要带上 `--ts` * midway-bin debug 调试命令, ts 使用时需要带上 `--ts` * midway-bin autod * midway-bin dev 本地开发命令, ts 使用时需要带上 `--ts` * midway-bin pkgfiles 这些命令都没有特别处理,参数和 egg-bin 相同,具体使用可以查看 [egg-bin 文档](https://github.com/eggjs/egg-bin/) ### build 命令[​](#build-命令 "build 命令的直接链接") 我们增加了一个 build 命令用于增强构建 typescript 项目。 ``` midway-bin build ``` 额外增加了一个 `-c` 参数用于支持打包前清理 `/dist` 目录。 ``` midway-bin build -c ``` 由于 typescript 编译无法拷贝非 `*.ts` 文件,我们特定在对 build 命令做了增强。 在执行 midway-bin build 命令中,会自动调用 `package.json` 的 `midway-bin-build` 段落,配置如下: ``` { "midway-bin-build": { "include": [ "app/public", "app/view", "lib/platform/aone/api.json", "lib/*.json", "lib/*.text", ["pattern/**", "!pattern/**/*.js"] ] } } ``` 信息 这里的路径相对于 src 目录。 你可以在其中使用相对路径或者通配符,乃至任意符合 [glob 语法](https://github.com/isaacs/minimatch#usage) 的 pattern 数组。 这样在打包时会自动将相应的目录或者文件从 `src` 目录拷贝到对应的 `dist` 目录中。 ### clean 命令[​](#clean-命令 "clean 命令的直接链接") 我们增加了一个 clean 命令用于清理一些临时文件。 ``` midway-bin clean ``` 清理的内容包括: * logs 目录 * run 目录 * .nodejs-cache 目录 同时和 build 命令类似,你可以在 `package.json` 的 `midway-bin-clean` 段落增加配置,用于清理自己的目录和文件。 ``` { "midway-bin-clean": ["src/app/public", "resource/temp"] } ``` 信息 这里的路径相对于应用的根目录。 ### doc 命令[​](#doc-命令 "doc 命令的直接链接") midway-bin doc 命令用于通过 typedoc 生成文档,比如 midway 的 api 就是通过此命令生成的。 ``` midway-bin doc ``` 使用的[命令参数](https://typedoc.org/guides/arguments/)和 typedoc 一致。 直接可使用的参数包括以下这些,有些已经指定了默认值。 * `--options [typedoc.js]` Specify a js option file that should be loaded. * `--out -o [outPath]` Specifies the location the documentation should be written to. * `--mode -m` default value is `file`, Specifies the output mode the project is used to be compiled with. * `--exclude` Exclude files by the given pattern when a path is provided as source. * `--theme` default value is `default` Specify the path to the theme that should be used. * `--excludeExternals` default value is `true` Prevent externally resolved TypeScript files from being documented. * `--ignoreCompilerErrors` default value is `true` Generates documentation, even if the project does not TypeScript compile. * `--hideGenerator` default value is `true` Do not print the TypeDoc link at the end of the page. 信息 如果指定了 `--options` 参数,那么其他的参数都会失效,请都在 `--options` 参数指定的文件中进行处理。 ## midway-init[​](#midway-init "midway-init的直接链接") 提供了基础的 midway 应用脚手架,后续会不断增加其他模板。 ``` npm install -g midway-init midway-init ``` 可以通过内建的命令创建脚手架 ``` midway-init -h // 帮助文档 midway-init --dir my_project // 在当前目录下的 my_project 子目录创建脚手架 midway-init --type midway-ts // 从内置脚手架类型 midway-ts 创建目录 midway-init --template ../custom_boilerplate // 从本地的特地目录创建脚手架 midway-init --package midway-boilerplate-typescript // 从 npm 包创建脚手架 midway-init --registry china/npm/registry.cnpmjs.org // 从不同的 registry 获取 npm 包,和 --package 合用 ``` ## tslint-midway-contrib[​](#tslint-midway-contrib "tslint-midway-contrib的直接链接") midway 对 Typescript 应用提供了简单的 tslint 规则包,只需要在 tslint.json 中做简单的继承,如果有其他的需求 ``` // package.json "devDependencies": { "tslint-midway-contrib": "1", } ``` ``` // tslint.json { "extends": ["tslint-midway-contrib"] } ``` --- # TS 新手指南 Typescript 和 Javascript 既相似又有着许多不同,以往的 Node.js 应用和模块大多都是 Javascript 写的。 而 Midway 在阿里沉淀多年,在多人协作和开发的过程中我们发现,Typescript 的接口定义和类型系统,使得应用编码出错的概率大大降低。 在全新的体系中,我们 **推荐使用 TypeScript 语法来编码**。 ## 应用目录结构[​](#应用目录结构 "应用目录结构的直接链接") 虽然 TypeScript 的目录多种多样,但是在统一的编码规范中,我们推荐常用的一种,这里就简单介绍我们常见的目录以及文件。 ``` ├── app    ├── README.md    ├── .gitignore    ├── package.json    ├── src    ├── dist    ├── test    ├── tsconfig.json    └── tslint.json ``` 最常见的目录结构如下,我们一一来介绍。 ### ts 依赖[​](#ts-依赖 "ts 依赖的直接链接") 在介绍目录之前,我们先介绍应用需要安装的依赖,这些依赖已经作为默认内容在脚手架中提供。 ``` // in package.json "devDependencies": { "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "ts-node": "^7.0.1", "tslint": "^5.9.1", "typescript": "^2.8.0" } ``` 这里的依赖有两部分,`@types/*` 开头的定义文件和其他 ts 运行时需要的文件。 * @types/node - Node.js 的定义包,有了它原生内置的模块就有了类型定义,@types/mocha 同理 * typescript - 微软提供的 ts 核心包,提供了高阶的语法糖支持,同时也提供了 tsc 等编译器。 * ts-node - 三方提供的运行环境,由于 js 运行无需编译,只需要 `node index.js` 即可运行,同理,可以用 `ts-node index.ts` 来直接运行 ts,方便开发 ### src 和 dist[​](#src-和-dist "src 和 dist的直接链接") 由于 Typescript 是编译过程中进行类型检查,虽然在开发过程中可以通过类似 [ts-node](https://github.com/TypeStrong/ts-node) 这样的模块来简化,但是最终应用部署前,还是需要打包编译的,midway 提供了 `midway-bin build` 命令进行编译,这一内容将在工具部分来提供。 `src` 目录存放 Typescript 源文件,Typescript 源文件由 `*.ts` 结尾,而编译后的文件为 `*.js`,在一般情况下,和源文件一一对应。 ### tsconfig.json 文件[​](#tsconfigjson-文件 "tsconfig.json 文件的直�接链接") 这是 TypeScript 的核心配置文件,一般在应用根目录,里面的配置项一般是都是指定编译环境。 比如: ``` { "compilerOptions": { "target": "ES2017", "module": "commonjs", "moduleResolution": "node", "experimentalDecorators": true, "noImplicitThis": true, "noUnusedLocals": true, "stripInternal": true, "pretty": true, "declaration": true, "sourceMap": true, "outDir": "dist", "lib": ["es2017", "dom"] }, "exclude": ["dist", "node_modules", "test"] } ``` `experimentalDecorators` 就是用来表示是否启用装饰器,`noUnusedLocals` 表示是否存在没有使用的本地变量编译时报错,这些配置信息都可以在 [这里](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) 查询到。 ### tslint.json[​](#tslintjson "tslint.json的直接链接") Tslint 对应于 Eslint 或者 Jslint,用于在不同时期进行检查,这里的配置也和 Eslint 非常相似。 比如有一些规则,每条有对应了不同的内容,比如使用单引号,不允许 `var` 关键字等,如果觉得开发习惯不同,可以根据 [官方规则](https://github.com/palantir/tslint) 进行调整。 如果你想知道 Tslint 有什么区别,可以查看 [这篇文章](https://ts.xcatliu.com/engineering/lint.html) ## 关于导出和导入[​](#关于导出和导入 "关于导出和导入的直接链接") 我们常用的导出有两种写法。 ### export 变量[​](#export-变量 "export 变量的直接链接") ``` // js 写法 function alert() {} exports.alert = alert; exports.config = { a: 1 }; ``` ``` // ts 写法 export function alert() {} export const config = { a: 1 }; ``` 用 `export` 关键字即可。 ### 默认导出[​](#默认导出 "默认导出的直接链接") 在以前我们很习惯 `module.exports` 来将整个对象进行导出,而切换到 ts 之后,请尽量不要使用这种做法。 ``` // js 写法 module.exports = { a: 1, }; module.exports = () => { console.log(111); }; ``` ``` // ts 写法 export = { a: 1, }; export = () => { console.log(111); }; ``` 两种写法无法并存,请尽量使用 `export` 进行导出。 ### default 导出[​](#default-导出 "default 导出的直接链接") 在很多时候,在代码中会有做 `default 导出的支持`,比如在 `egg-core` 中的加载部分: ``` // require js module const obj = require(filepath); if (!obj) return obj; // it's es module if (obj.__esModule) return 'default' in obj ? obj.default : obj; ``` 这个时候我们将代码写成如下也是可以支持的。 ``` export default {}; ``` 编译成 js,则会变成 ``` Object.defineProperty(exports, '__esModule', { value: true }); exports.default = {}; ``` ### 一般导入[​](#一般导入 "一般导入的直接链接") 一般情况下,我们在 js 上会使用 `require` 关键字进行导入,而在 ts 语法下,这样导入会丢失类型,所以在 ts 下写法有所不同。 ``` // js 写法 const applicatoin = require('midway').application; const { applicatoin } = require('midway'); ``` ``` // ts 写法 import { applicatoin } from 'midway'; ``` 这样写,`midway` 包中的类型定义才可以被正常解析。 只有使用 `export` 进行导出的属性才能被 `import`,不然就需要换一种写法。 ### 默认导入[​](#默认导入 "默认导入的直接链接") 有时候,三方包或者内置模块是通过 `module.exports` 出来的。 ``` // js 写法 const path = require('path'); ``` 这个时候可以使用 `*` 做全部导出。 ``` // ts 写法 import * as path from 'path'; ``` ## 相关链接[​](#相关链接 "相关链接的直接链接") * [Typescript 入门教程](https://ts.xcatliu.com/) * [Typescript Handbook](https://zhongsp.gitbooks.io/typescript-handbook/) --- # 接入 Alinode ## 准备工作[​](#准备工作 "准备工作的直接链接") 需要接入的应用是要部署在独立的服务获取云环境,可以接入互联网服务。 ## 创建服务[​](#创建服务 "创建服务的直接链接") **第一步** 登录阿里云,点击开通 [阿里云的 Node.js 性能平台](https://www.aliyun.com/product/nodejs) 的服务。 **第二步** 创建新应用,获取 APP ID 和 App Secret。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617267785895-dd0fb702-91c7-4b25-9c64-8a9358f2d254.png#align=left\&display=inline\&height=351\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=702\&originWidth=1548\&size=106487\&status=done\&style=none\&width=774) ## 安装监控依赖[​](#安装监控依赖 "安装监控依赖的直接链接") **第一步** 安装 Node.js 性能平台所需的组件 ``` # 安装版本管理工具 tnvm,安装过程出错参考:https://github.com/aliyun-node/tnvm $ wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash $ source ~/.bashrc # tnvm ls-remote alinode # 查看需要的版本 $ tnvm install alinode-v6.5.0 # 安装需要的版本 $ tnvm use alinode-v6.5.0 # 使用需要的版本 $ npm install @alicloud/agenthub -g # 安装 agenthub ``` 这里有三个部分 * 1、安装 tnvm(alinode 源) * 2、使用 tnvm 安装 alinode(替代默认的 node) * 3、安装 alinode 需要的数据采集器 安装完成后,可以检查一下,需要确保 `which node`  和 `which agenthub` 的路径中包括 `.tnvm` 即可。 ``` $ which node /root/.tnvm/versions/alinode/v3.11.4/bin/node $ which agenthub /root/.tnvm/versions/alinode/v3.11.4/bin/agenthub ``` 将 `创建新应用` 中获得的 `App ID`  和  `App Secret`  按如下所示保存为  `yourconfig.json`。比如放在项目根目录。 ``` { "appid": "****", "secret": "****", } ``` 启动插件: ``` agenthub start yourconfig.json ``` ## 启动 node 服务[​](#启动-node-服务 "启动 node 服务的直接链接") 在安装了服务器中,启动 Node 服务时,需要加入 ENABLE\_NODE\_LOG=YES 环境变量。 比如: ``` $ NODE_ENV=production ENABLE_NODE_LOG=YES node bootstrap.js ``` ## Docker 容器的方法[​](#docker-容器的方法 "Docker 容器的方法的直接链接") 关于 docker 容器的方法可以查看 [文档](https://help.aliyun.com/document_detail/66027.html?spm=a2c4g.11186623.6.580.261ba70feI6mWt)。 ## 其他[​](#其他 "其他的直接链接") 更多内容可以查看阿里云 Node.js 性能平台的 [文档](https://help.aliyun.com/document_detail/60338.html?spm=a2c4g.11186623.6.548.599312e6IkGO9v)。 --- # 方法拦截器(切面) 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 Midway 设计了一套通用的方法拦截器(切面),用于在不同场景中,统一编写逻辑。 拦截器和传统的 Web 中间件和装饰器都不同,是由 Midway 框架提供的能力,在执行顺序上,处于中间的位置,这个能力能对任意的 Class 方法做拦截。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600855555973-cd9b43fa-5a7b-4d4f-a6fb-8dfb07ef3816.png#height=133\&id=Ye2oM\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=133\&originWidth=823\&originalType=binary\&ratio=1\&size=13193\&status=done\&style=none\&width=823) ## 使用拦截器(切面)[​](#使用拦截器切面 "使用拦截器(切面)的直接链接") 拦截器一般会放在 `src/aspect`  目录。下面我们写一个对控制器(Controller)方法拦截的示例。创建一个 `src/aspect/report.ts`  文件。 ``` ➜ my_midway_app tree . ├── src │ │── aspect ## 拦截器目录 │ │ └── report.ts │ └── controller ## Web Controller 目录 │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { return 'Hello Midwayjs!'; } } ``` 内容如下: ``` import { Aspect, IMethodAspect, JoinPoint, Provide } from '@midwayjs/decorator'; import { HomeController } from '../controller/home'; @Provide() @Aspect(HomeController) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('before home router run'); } } ``` 启动项目,运行后,在控制台会输出 `before home router run`  的字样。 你会发现,我们不需要去侵入控制器的代码,既没有在业务文件中加装饰器,也没有在主流程前后可见的加代码。 拦截器(切面)的能力非常强大,也非常可怕,我们一定要小心而正确的使用。 拦截器 **固定为单例**。 警告 在继承的情况下,拦截器不会对父类的方法生效。 ## 可切面的生命周期[​](#可切面的生命周期 "可切面的生命周期的直接链接") 方法拦截器可以对整个方法进行拦截,拦截的方式包括几个方面。 ``` export interface IMethodAspect { after?(joinPoint: JoinPoint, result: any, error: Error); afterReturn?(joinPoint: JoinPoint, result: any): any; afterThrow?(joinPoint: JoinPoint, error: Error): void; before?(joinPoint: JoinPoint): void; around?(joinPoint: JoinPoint): any; } ``` | before | 方法调用前执行 | | | ----------- | ---------------------------- | - | | around | 包裹方法的前后执行 | | | afterReturn | 正确返回内容时执行 | | | afterThrow | 抛出异常时执行 | | | after | 最后执行(不管正确还是错误) | | 简单理解如下; ``` try { // before // around or invokeMethod // afterReturn } catch (err) { // afterThrow } finally { // after } ``` | | 修改入参 | 调用原方法 | 获取返回值 | 修改返回值 | 获取错误 | 拦截并抛出错误 | | ----------- | -------- | ---------- | ---------- | ---------- | -------- | -------------- | | before | √ | √ | | | | | | around | √ | √ | √ | √ | √ | √ | | afterReturn | | | √ | √ | | | | afterThrow | | | | | √ | √ | | after | | | √ | | √ | | 我们常会在 `before`  的过程中修改入参、校验,以符合程序执行的逻辑,比如: ``` // src/controller/home.ts export class HomeController { @Get('/') async home(data1, data2) { return data1 + data2; // 因为拦截了方法,这里的返回值是 3 } } // src/aspect/ @Provide() @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log(point.args); // 这里因为对 Controller 方法做切面,原本的参数为 [ctx, next] point.args = [1, 2]; // 修改入参 } } ``` 这里的 `JoinPoint`  就是可以对方法做修改的参数,定义如下。 ``` export interface JoinPoint { methodName: string; target: any; args: any[]; proceed(...args: any[]): any; } ``` | methodName | 拦截到的方法名 | | | ---------- | ---------------- | ------------------------------ | | target | 方法调用时的实例 | | | args | 原方法调用的参数 | | | proceed | 原方法本身 | 只会在 before 和 around 中存在 | | | | | `around`  是比较全能的方法,它可以包裹整个方法调用流程。 ``` // src/controller/home.ts export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async around(point: JoinPoint) { const result = await point.proceed(...point.args); // 执行原方法 return result + ' world'; } } ``` 最终 Controller 会返回 `hello world` 。 `afterReturn`  方法会多一个返回结果参数,如果只需要修改返回结果,可以直接使用它,上面的 `around`  例子用 `afterReturn`  改写会更简单。 ``` // src/controller/home.ts export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async afterReturn(point: JoinPoint, result) { return result + ' world'; } } ``` `afterThrow`  用于拦截错误。 ``` // src/controller/home.ts export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async afterThrow(point: JoinPoint, error) { if (/not found/.test(error.message)) { throw new Error('another error'); } else { console.error('got custom error'); } } } ``` `afterThrow`  能拦截错误,相应的,它不能在流程中返回结果,一般用来记录错误日志。 `after`  用来做最后的处理,不管是成功或者失败,都可以用它执行一些事情,比如记录所有成功或者失败的次数。 ``` // src/controller/home.ts export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async after(point: JoinPoint, result, error) { if (error) { console.error(error); } else { console.log(result); } } } ``` ## 切面的异步问题[​](#切面的异步问题 "切面的异步问题的直接链接") 如果被拦截的方法是异步的,则原则上我们的 `before` 等方法应该都是异步的,反之,则都是同步的。 ``` // src/controller/home.ts export class HomeController { @Get('/') async home() { // 这里是异步的,则下面的 before 是异步的 } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) {} } ``` ``` // src/controller/home.ts export class HomeController { @Get('/') home() { // 这里是同步的,则下面的 before 也是同步的 } } // src/aspect/report.ts @Provide() @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { before(point: JoinPoint) {} } ``` ## 应用到多个 Class[​](#应用到多个-class "应用到多个 Class的直接链接") `@Aspect`  装饰器的参数可以是一个数组,我们可以提供多个 Class,这些 Class 的 \*\*所有方法 \*\*都将被拦截。比如,我们可以将上面的拦截器应用到多个 Controller,这样 \*\*每一个 Class 的每一个方法 \*\*都会被拦截。 ``` @Provide() @Aspect([HomeController, APIController]) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) {} } ``` ## 特定方法匹配[​](#特定方法匹配 "特定方法匹配的直接链接") 一般情况下,我们只需要对某个 Class 特定的方法做拦截。我们提供了一些匹配方法的能力。 `@Aspect`  装饰的第二个参数则是一个通配方法的字符串。使用的规则为 [picomatch](https://github.com/micromatch/picomatch)。 假如我们的方法为: ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/1') async hello1() { return 'Hello Midwayjs!'; } @Get('/2') async hello2() { return 'Hello Midwayjs, too!'; } } ``` 那么,我们如下配置时,只会匹配到 `hello2`  这个方法。 ``` @Provide() @Aspect([HomeController], '*2') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('hello method with suffix 2'); } } ``` ## 切面执行顺序[​](#切面执行顺序 "切面执行顺序的直接链接") 如果多个拦截器(切面)同时针对一个方法做操作,可能会出现顺序错乱的问题,如果在两个文件中,这个顺序是随机的。 `@Aspect`  的第三个参数用于指定拦截器的优先级,默认为 0,数字越大,优先级越高,即先被注册到方法上,**先注册的方法会被后调用,**即洋葱模型**。** 以下面的代码作为示例。 `MyAspect2`  的优先级高于 `MyAspect1` ,所以会优先注册。示意图如下,整个拦截流程分为两部分,先是注册,后是执行。 **注册流程** ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600919962582-e0715385-828e-48c0-9b47-47a2b7018a18.png#height=497\&id=WZ6J3\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=497\&originWidth=924\&originalType=binary\&ratio=1\&size=38903\&status=done\&style=none\&width=924) **执行流程** ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600920671419-2d846c20-514c-4c54-a087-a91a1d42f7ef.png#height=311\&id=nOAew\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=311\&originWidth=769\&originalType=binary\&ratio=1\&size=28489\&status=done\&style=none\&width=769) 代码如下。 ``` @Provide() @Aspect([HomeController]) export class MyAspect1 implements IMethodAspect { before(point: JoinPoint) { console.log('111'); } } @Provide() @Aspect([HomeController], '*', 1) // 这里可以设置优先级 export class MyAspect2 implements IMethodAspect { before(point: JoinPoint) { console.log('222'); } } ``` 执行输出为 ``` 111 222 ``` ## 一些限制[​](#一些限制 "一些限制的直接链接") * 1、拦截器不会对父类生效 --- # BodyParser Bodyparser 一般用来对 post 请求的请求体进行解析,是比较常用的 Web 中间件之一。 HTTP 协议中并不建议在通过 GET、HEAD 方法访问时传递 body,所以我们无法在 GET、HEAD 方法中按照此方法获取到内容。 ## 在 @midwayjs/web 使用[​](#在-midwayjsweb-使用 "在 @midwayjs/web 使用的直接链接") `@midwayjs/web` 默认使用了 Egg.js 基础框架,其中自带了 bodyparser 中间件。我们只需要把需要获取 body 数据的中间件 \*\*放在 Egg.js 框架默认的中间件之后 \*\*即可。 我们这里需要使用 Egg.js 自己的中间件配置方式,在 `src/config/config.{env}.ts` 中编写。 我们举个例子,编写一个我们自己的中间件。 ``` // src/middleware/report.ts import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next: IMidwayWebNext) => { // 这里获取了 body 数据 console.log(ctx.request.body); await next(); }; } } ``` 然后在配置中添加。 ``` // src/config/config.default.ts export default (appInfo: EggAppInfo) => { const config = {} as DefaultConfig; // ... config.middleware = ['reportMiddleware']; return config; }; ``` 信息 在 config 文件中配置全局中间件是 Egg.js 的特殊方式,这里配置的中间件一定会在默认的框架中间件之后加载。 Egg.js 中默认的 bodyparer 库为 [koa-bodyparser](https://github.com/koajs/bodyparser) ,默认配置为: ``` // config.default export const bodyParser = { jsonLimit: '100k', }; ``` 一般来说我们最经常调整的配置项就是变更解析时允许的最大长度,可以在 `src/config/config.default.ts` 中覆盖框架的默认值。 比如可以设置到 1m。 ``` // config.default export const bodyParser = { jsonLimit: '1mb', }; ``` 更多配置可以查看 [koa-bodyparser](https://github.com/koajs/bodyparser) 文档。 ## 在 @midwayjs/koa 使用[​](#在-midwayjskoa-使用 "在 @midwayjs/koa 使用的直接链接") koa 中可以直接引入 [koa-bodyparser](https://github.com/koajs/bodyparser) 。 ``` $ npm i koa-bodyparser --save ``` 比如下面的示例: ``` import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; import * as bodyParser from 'koa-bodyparser'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { // bodyparser options see https://github.com/koajs/bodyparser this.app.use(bodyParser()); } } ``` 更多配置可以查看 [koa-bodyparser](https://github.com/koajs/bodyparser) 文档。 ## 在 @midwayjs/express 使用[​](#在-midwayjsexpress-使用 "在 @midwayjs/express 使用的直接链接") express 中需要使用 [body-parser](https://github.com/expressjs/body-parser) 中间件。 ``` $ npm i body-parser --save ``` 中间件在 configuration 中加载。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as bodyParser from 'body-parser'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use(bodyParser.json()); this.app.use(bodyParser.urlencoded({ extended: false })); } } ``` 更多配置可以查看 [body-parser](https://github.com/expressjs/body-parser) 文档。 ## 在 Serverless 下使用[​](#在-serverless-下使用 "在 Serverless 下使用的直接链接") 在 Serverless 场景已经默认集成了 bodyparser,用户无需引入其他模块。 这个解析行为是固定的,无法修改,并且最大的解析文件大小为 2M。 body 数据可以通过 `ctx.request.body` 拿到。 --- # 使用 cfork 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 文档在此: 由于 bootstrap.js 的特性,有时候不是很适合 pm2 来部署(比如集团内部,全局不安装,需要 API 启动)。 我们可以新增一个 `server.js` 用来做主进程的入口,将 `bootstrap.js` 作为每个子进程的启动入口。 ``` // server.js 'use strict'; const cfork = require('cfork'); const util = require('util'); const path = require('path'); const os = require('os'); // 获取 cpu 核数 const cpuNumbers = os.cpus().length; cfork({ exec: path.join(__dirname, './bootstrap.js'), count: cpuNumbers, }) .on('fork', (worker) => { console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid); }) .on('disconnect', (worker) => { console.warn( '[%s] [master:%s] wroker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state ); }) .on('exit', (worker, code, signal) => { const exitCode = worker.process.exitCode; const err = new Error( util.format( 'worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)', worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state ) ); err.name = 'WorkerDiedError'; console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack); }); ``` 最后启动 `node server.js` 即可。 --- # 修改源码目录 在某些特殊场景下,可以修改源码所在的 `src` 目录。 一些限制: * 1、@midwayjs/web(egg)egg 由于目录固定,无法修改 * 2、只在纯 node 项目下测试通过(非一体化) ## 源码目录的修改[​](#源码目录的修改 "源码目录的修改的直接链接") 下面,我们以将 `src` 目录修改为 `server` 为例。 ### dev 开发[​](#dev-开发 "dev 开发的直接链接") `package.json` 中的 dev 命令需要增加源码目录,方便 dev 查找。 ``` "dev": "cross-env NODE_ENV=local midway-bin dev --sourceDir=./server --ts", ``` ### build 编译[​](#build-编译 "build 编译的直接链接") 为了让 tsc 编译能找到源码目录,需要修改 `tsconfig.json` ,增加 `rootDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "rootDir": "server" }, } ``` 这样,开发和编译就都正常了。 ## 编译目录的修改[​](#编译目录的修改 "编译目录的修改的直接链接") 编译目录影响到部署,也可以修改。我们以将 `dist` 目录修改为 `build` 为例。 ### build 编译[​](#build-编译-1 "build 编译的直接链接") 修改 `tsconfig.json` 中的 `outDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "outDir": "build" }, } ``` 这样编译就正常了。 ### bootstrap 启动[​](#bootstrap-启动 "bootstrap 启动的直接链接") 编译目录修改之后,线上部署会找不到代码,所以如果走 `bootstrap.js` 启动,需要修改代码。 ``` // bootstrap.js const { join } = require('path'); const { Bootstrap } = require('@midwayjs/bootstrap'); //... // 需要用 configure 方法配置 baseDir Bootstrap.configure({ baseDir: join(__dirname, 'build'), }) .load(web) .run(); ``` 对 `Bootstrap` 配置入口目录即可。 --- # 组件开发 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: * 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等 * 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等 组件可以本地加载,也可以打包到一起发布成一个  npm 包。组件可以在 midway v2/Serverless 中使用。你可以将复用的业务代码,或者功能模块都放到组件中进行维护。几乎所有的 Midway 通用能力都可以在组件中使用,包括但不限于配置,生命周期,控制器,拦截器等。 设计组件的时候尽可能的面向所有的上层框架场景,所以我们尽可能只依赖 `@midwayjs/core` 和 `@midwayjs/decorator` 。 ## 脚手架[​](#脚手架 "脚手架的直接链接") 初始化脚手架例子: ``` # 如果是 npm v6 $ npm init midway --type=component hello2 # 如果是 npm v7 $ npm init midway -- --type=component hello2 $ cd hello2 ``` 然后组件开发,并发布。 ``` $ npm run build && npm publish // 编译并发布对应的component ``` ## 组件目录[​](#组件目录 "组件目录的直接链接") 组件的结构和 midway 的推荐目录结构一样,组件的目录结构没有特别明确的规范,和应用或者函数保持一致即可。简单的理解,组件就是一个 “迷你应用"。 一个推荐的组件目录结构如下。 ``` . ├── package.json ├── src │ ├── index.ts // 入口导出文件 │ ├── configuration.ts // 组件行为配置 │ └── service // 逻辑代码 │ └── bookService.ts ├── test └── tsconfig.json ``` 对于组件来说,唯一的规范是入口导出的 `Configuration`  属性,其必须是一个带有 `@Configuration`  装饰器的 Class。 一般来说,我们的代码为 TypeScript 标准目录结构,和 Midway 体系相同。不同的是,由于是一个额外的包,需要使用 `src/index.ts`  文件作为入口导出内容。 ## 组件约定[​](#组件约定 "组件约定的直接链接") 组件和应用本身略微有些不同,差异主要在以下几个方面。 * 1、组件的代码需要导出一个 `Configuration` 属性,其必须是一个带有 `@Configuration` 装饰器的 Class,用于配置组件自身能力 * 2、所有 \*\*显式导出的代码 \*\*才会被依赖注入容器加载 比如: ``` // src/index.ts export { AutoConfiguration as Configuration } from './configuration'; export * from './controller/user'; export * from './controller/api'; export * from './service/user'; ``` 信息 这样项目中只有 `controller/user` , `controller/api` , `service/user` 这三个文件才会被依赖注入容器扫描和加载。 以及在 `package.json`  中指定 main 路径。 ``` "main": "dist/index" ``` 这样组件就可以被上层场景依赖加载了。 ## 开发组件的方式[​](#开发组件的方式 "开发组件的方式的直接链接") 我们可以新建一个项目,将它改造为组件,也可以在原有项目中开发,直到组建完成后再发布到独立的仓库。 ### 新仓库开发组件[​](#新仓库开发组件 "新仓库开发组件的直接链接") 代码结构如下: ``` . ├── src // 源码目录 │ ├── service │ │ └── bookService.ts │ ├── configuration.ts // 组件行为配置 │ └── index.ts // 组件导出入口 └── package.json ├── test └── tsconfig.json ``` 组件行为配置。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; @Configuration() export class BookConfiguration {} ``` 在组件的入口导出 `Configuration` 属性。 ``` // src/index.ts export { BookConfiguration as Configuration } from './configuration`; ``` ### 应用中开发组件[​](#应用中开发组件 "应用中开发组件的直接链接") 推荐使用 [lerna](https://github.com/lerna/lerna),以及开启 lerna 的 hoist 模式来编写组件。如果想在非 lerna 的场景场景下开发组件,请保证组件在 `src`  目录下,否则会出现加载失败的情况。 #### 使用 lerna[​](#使用-lerna "使用 lerna的直接链接") 使用 lerna 开发相对比较简单,具体的目录结构类似如下。 ``` . ├── src ├── packages/ │ ├── component-A │ │ └── package.json │ ├── component-B │ │ └── package.json │ ├── component-C │ │ └── package.json │ └── web │ └── package.json ├── lerna.json └── package.json ``` #### 非 lerna[​](#非-lerna "非 lerna的直接链接") 下面是一种常见的组件开发方式,示例结构为在应用代码开发时同时开发两个组件,当然,你也可以自定义你喜欢的目录结构。 ``` . ├── package.json ├── src // 源码目录 │ ├── components │ │ ├── book // book 组件代码 │ │ │ ├── src │ │ │ │ ├── service │ │ │ │ │ └── bookService.ts │ │ │ │ ├── configuration.ts │ │ │ │ └── index.ts │ │ │ └── package.json │ │ │ │ │ └── school │ │ ├── src │ │ │ ├── service // school 组件代码 │ │ │ │ └── schoolService.ts │ │ │ └── configuration.ts │ │ └── package.json │ │ │ ├── configuration.ts // 应用行为配置文件 │ └── controller // 应用路由目录 ├── test └── tsconfig.json ``` 组件行为配置。 ``` // src/components/book/src/bookConfiguration.ts import { Configuration } from '@midwayjs/decorator'; @Configuration() export class BookConfiguration {} ``` 为了让组件能导出,我们需要在组件的入口 `src/components/book/src/index.ts` 导出 `Configuration` 属性。 ``` // src/components/book/src/index.ts export { BookConfiguration as Configuration } from './bookConfiguration/src`; ``` 信息 注意,这里引用的地方是 "./xxxx/src",是因为一般我们 package.json 中的 main 字段指向了 dist/index,如果希望代码不修改,那么 main 字段要指向 src/index,且在发布时记得修改回 dist。 将组件引入的目录指向 src ,是为了能在保存是自动生效(重启)。 另外,在新版本可能会出现扫描冲突的问题。可以将 `configuration.ts` 中的依赖注入冲突检查功能关闭。 ## 开发组件[​](#开发组件 "开发组件的直接链接") 举一个例子,我们现在要把一个 `BookService` 放到组件中,让其他场景的代码复用。 组件的服务代码如下。 ``` // src/service/bookService import { Provide } from '@midwayjs/decorator'; @Provide() export class BookService { async getBookById(id) {} } ``` 信息 一个组件不会依赖明确的上层框架,为了达到在不同场景复用的目的,只会依赖通用的 `@midwayjs/core` 和 `@midwayjs/decorator` 组件的 npm 包名为 `midway-component-book` , `package.json`  如下。 ``` { "name": "midway-component-book", "version": "1.0.0", "main": "dist/index", "typings": "dist/index.d.ts", "files": [ "dist/**/*.js", "dist/**/*.d.ts" ], "devDependencies": { "@midwayjs/core": "^2.3.0", "@midwayjs/decorator": "^2.3.0" } ... } ``` ### 组件作用域(命名空间)[​](#组件作用域命名空间 "组件作用域(命名空间)的直接链接") 为了避免组件的业务代码和其他的业务代码冲突,组件在导出的时候加入了作用域的概念。默认的作用域为 npm 包名,即 `package.json`  中的 `name`  字段。 可以在 `@Configuration`  装饰器中的 `namespace`  字段修改。 > 后续我们将弱化作用域的概念 ``` // src/bookConfiguration.ts import { Configuration } from '@midwayjs/decorator'; @Configuration({ namespace: 'book', }) export class BookConfiguration {} ``` 引用组件导出的服务时,示例如下。 ``` // in project // 这里直接引入组件包导出的类型 import { BookService } from 'midway-component-book'; @Provide() @Controller('/user') export class HomeControlelr { @Inject() bookService: BookService; // 这里直接注入了 book 这个作用域下的 bookService } ``` ### 组件使用自身服务[​](#组件使用自身服务 "组件使用自身服务的直接链接") #### 1、使用组件自己 `@Provide`  的情况[​](#1使用组件自己-provide-的情况 "1使用组件自己-provide-的情况的直接链接") Midway 使用 `@Inject`  装饰器来注入其他服务,在组件中,只要是同一个组件,我们也可以直接注入,不需要增加作用域前缀。 比如: ``` // src/controller/user.ts // 这里是组件中的 user 控制器 import { BookService } from './service/bookService'; @Provide() @Controller('/user') export class UserController { @Inject() bookService: BookService; // 这里注入不需要组件前缀,会自动处理 @Inject('bookService') bookService: BookService; // 这里注入不需要组件前缀,会自动处理,和上面行为一致 } ``` 所以,组件内部调用组件自己的 `@Provide`  的服务,不需要加作用域前缀。 #### 2、组件使用自己 `registerObject`  的情况[​](#2组件使用自己-registerobject-的情况 "2组件使用自己-registerobject-的情况的直接链接") 如果在 onReady 的时候注入了三方对象,那么该三方对象将属于组件自身。 ``` @Configuration({ namespace: 'book', }) export class BookConfiguration { async onReady(contanier) { contanier.registerObject('aaa', 'bbb'); // 容器内部会绑定到当前的组件 } } ``` 如果组件内部使用时,可以无需增加前缀。 ``` @Provide() @Controller('/user') export class UserController { @Inject() aaa: string; // 这里注入不需要组件前缀,会自动处理 } ``` #### 3、组件使用自己 `providerWrapper`  出来的方法[​](#3组件使用自己-providerwrapper-出来的方法 "3组件使用自己-providerwrapper-出来的方法的直接链接") 如果组件需要使用 `providerWrapper`  来暴露方法,请增加 **组件作用域前缀**。 ``` import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export async function contextHandler(container: IMidwayContainer) {} providerWrapper([ { id: 'book:contextHandler', // 这里务必增加组件前缀 provider: contextHandler, scope: ScopeEnum.Request, }, ]); ``` 组件在使用自己暴露的方法时,可以不需要前缀。 ``` @Provide() @Controller('/user') export class UserController { @Inject() contextHandler; // 这里注入不需要组件前缀,会自动处理 } ``` ### 组件注入全局对象[​](#组件注入全局对象 "组件注入全局对象的直接链接") Midway 上层框架默认会注入一些 [全局对象](/docs/2.0.0/container.md#stYqU)(框架、业务注入的对象),这些全局对象在组件中使用不需要作用域前缀。 比如在组件中: ``` @Configuration() export class ContainerLifeCycle { @Inject() baseDir; // 注入全局对象不需要前缀 async onReady(container) { container.registerObject('aaa', 'bbbb'); } } ``` 组件的普通逻辑中: ``` @Provide() export class Home { @Inject() baseDir: string; @Inject() aaa; // 当前组件注册的属性不需要前缀 @Inject() ccc; // 全局注入的属性不需要前缀 async getData() {} } ``` ### 组件业务配置[​](#组件业务配置 "组件业务配置的直接链接") `@Configuration` 装饰器的 `importConfigs` 属性用于指定配置,这个行为和上层框架通用的[业务配置](/docs/env_config.md)能力一致。 ``` // src/bookConfiguration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ namespace: 'book', importConfigs: [ join(__dirname, 'config'), // 可以指定整个目录 join(__dirname, 'anotherConfig/config.default.ts'), // 可以指定单个文件 ], }) export class BookConfiguration {} ``` 信息 注意: `importConfigs`  的路径都为绝对路径。 ### 组件生命周期[​](#组件生命周期 "组件生命周期的直接链接") 和整个 Midway 通用的 [生命周期扩展](/docs/2.0.0/lifecycle.md) 能力相同。 ## 使用组件[​](#使用组件 "使用组件的直接链接") 在任意的 midway 系列的应用中,可以通过同样的方式引入这个组件。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "midway-component-book": "*" } } ``` 然后,在应用(函数)中引入这个组件。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as book from 'midway-component-book'; @Configuration({ imports: [book], }) export class ContainerLifeCycle {} ``` 至此,我们的准备工作就做完了,下面开始使用。 ### 1、外部使用组件 `@Provide`  的类[​](#1外部使用组��件-provide-的类 "1外部使用组件-provide-的类的直接链接") 假如我们在应用(函数)中需要用组件中的类,由于组件配置了命名空间,通过下面的方式即可导入组件中的代码。 直接引入组件的类注入。 ``` import { Provide, Inject } from '@midwayjs/decorator'; import { BookService } from 'midway-component-book'; @Provide() export class Library { @Inject(); bookService: BookService; } ``` 等价于 “通过作用域 + 名字” 注入 ``` import { Provide, Inject } from '@midwayjs/decorator'; @Provide() export class Library { @Inject('book:bookService'); bookService; } ``` ### 2、外部使用组件 `registerObject`  的对象[​](#2外部使用组件-registerobject-的对象 "2外部使用组件-registerobject-的对象的直接链接") 如果组件中有使用 `registerObject`  将对象注入到容器,那么该实例是属于此组件的,使用时需要增加前缀。 ``` // 组件中 @Configuration({ namespace: 'book', }) export class BookConfiguration { async onReady(contanier) { contanier.registerObject('aaa', 'bbb'); // 容器内部会绑定到当前的组件 } } ``` 应用(函数 )代码中使用: ``` import { Provide, Inject } from '@midwayjs/decorator'; @Provide() export class Library { @Inject('book:aaa'); aaa: string; } ``` ### 3、外部使用组件 `providerWrapper` 的方法[​](#3外部使用组件-providerwrapper-的方法 "3外部使用组件-providerwrapper-的方法的直接链接") 如果组件导出一个方法。 ``` // 组件导出 import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export async function contextHandler(container: IMidwayContainer) {} providerWrapper([ { id: 'book:contextHandler', // 这里务必增加组件前缀 provider: contextHandler, scope: ScopeEnum.Request, }, ]); ``` 应用(函数 )代码中使用: ``` import { Provide, Inject } from '@midwayjs/decorator'; @Provide() export class Library { @Inject('book:contextHandler'); contextHandler; } ``` 其余如果组件有包含特定的能力,请参考组件本身的文档。 ## 组件示例[​](#组件示例 "组件示例的直接链接") [这里](https://github.com/czy88840616/midway-test-component) 有一个组件示例。已经发布到 npm,可以尝试直接引入到项目中启动执行。 --- # 依赖注入 Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 ## 快速理解[​](#快速理解 "快速理解的直接链接") 依赖注入是 Java Spring 体系中非常重要的核心,我们用简单的做法讲解这个能力。 我们举个例子,以下面的函数目录结构为例。 ``` . ├── package.json ├── src │   ├── controller # 控制器目录 │   │ └── userController.ts │   └── service # 服务目录 │   └── userService.ts └── tsconfig.json ``` 在上面的示例中,提供了两个文件, `userController.ts` 和 `userService.ts` 。为了解释方便,我们将它合并到了一起,内容大致如下。 ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; // userController.ts @Provide() @Controller('/') export class UserController { @Inject() userService: UserService; @Get('/') async get() { const user = await this.userService.getUser(); console.log(user); // world } } // userService.ts @Provide() export class UserService { async getUser() { return 'world'; } } ``` 抛开所有装饰器,你可以看到这是标准的 Class 写法,没有其他多余的内容,这也是 Midway 体系的核心能力,依赖注入最迷人的地方。 `@Provide` 的作用是告诉 **依赖注入容器**,我需要被容器所加载。 `@Inject` 装饰器告诉容器,我需要将某个实例注入到属性上。 通过这两个装饰器的搭配,我们可以方便的在任意类中拿到实例对象,就像上面的 `this.userService` 。 ## 依赖注入原理[​](#依赖注入原理 "依赖注入原理的直接链接") 我们以下面的伪代码举例,在 Midway 体系启动阶段,会创建一个依赖注入容器(MidwayContainer),扫描所有用户代码(src)中的文件,将拥有 `@Provide` 装饰器的 Class,保存到容器中。 ``` /***** 下面为 Midway 内部代码 *****/ const container = new MidwayContainer(); container.bind(UserController); container.bind(UserService); ``` 这里的依赖注入容器类似于一个 Map。Map 的 key 是**类名的驼峰形式**,Value 则是**类本身**。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600847625069-c32258a0-9332-4691-896f-27b19d7b2534.png#crop=0\&crop=0\&crop=1\&crop=1\&height=269\&id=Wi3Zx\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=269\&originWidth=623\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=16422\&status=done\&style=none\&title=\&width=623) 在请求时,会动态实例化这些 Class,并且处理属性的赋值,比如下面的伪代码,很容易理解。 ``` /***** 下面为依赖注入容器伪代码 *****/ const userService = new UserService(); const userController = new UserController(); userController.userService = userService; ``` 经过这样,我们就能拿到完整的 `userController`   对象了,实际的代码会稍微不一样。 MidwayContainer 有 `getAsync` 方法,用来异步处理对象的初始化(很多依赖都是有异步初始化的需求),自动属性赋值,缓存,返回对象,将上面的流程合为同一个。 ``` /***** 下面为依赖注入容器内部代码 *****/ // 自动 new UserService(); // 自动 new UserController(); // 自动赋值 userController.userService = await container.getAsync(UserService); const userController = await container.getAsync(UserController); await userController.handler(); // output 'world' ``` 以上就是依赖注入的核心过程,创建实例。 信息 此外,这里还有一篇名为 [《这一次,教你从零开始写一个 IoC 容器》](https://mp.weixin.qq.com/s/g07BByYS6yD3QkLsA7zLYQ)的文章,欢迎扩展阅读。 ## 依赖注入标识符[​](#依赖注入标识符 "依赖注入标识符的直接链接") 在默认情况下,Midway 会将类名变为 `驼峰` 形式作为依赖注入标识符,一般情况下,用户无需改变它。并且在使用时,直接在 Class 中使用 `@Provide` 和 `@Inject` 装饰器即可。 `@Provide` 和 `@Inject` 装饰器是有可选参数的,并且他们是成对出现。 默认情况下: * 1、 `@Provide` 取 \*\*类名的驼峰字符串 \*\*作为依赖注入标识符 * 2、 `@Inject` 根据 **规则** 获取 key 规则如下: * 1、如果装饰器包含参数,则以 \*\*参数字符串 \*\*作为 key * 2、如果没有参数,标注的 TS 类型为 Class,则将类 `@Provide` 的 key 作为 key * 3、如果没有参数,标注的 TS 类型为非 Class,则将 **属性名** 作为 key 两者相互一致即可关联。 ``` export interface IService {} // service @Provide() // <------ 这里暴露的 key 是 userService export class UserService implements IService { //... } // controller @Provide() @Controller('/api/user') export class APIController { @Inject('userService') // <------ 这里注入的 key 是 userService userService1: UserService; @Inject() userService2: UserService; // <------ 这里的类型是 Class,注入的 key 是 userService @Inject() userService: IService; // <------ 这里的类型是 Interface,注入的 key 是 userService //... } ``` 我们可以修改暴露给依赖注入容器的 key,同时,注入的地方也要相应修改。 ``` // service @Provide('bbbService') // <------ 这里暴露的 标识符 是 bbbService export class UserService { //... } // controller @Provide() export class UserController { @Inject('bbbService') // <------ 这里注入的 标识符 是 bbbService userService: UserService; //... } ``` 除了字符串,我们还可以使用 Class 来作为注入的标识符。 ``` @Provide() // <------ 这里暴露的 标识符 是 userService export class UserService { //... } @Provide() export class UserController { @Inject() userService: UserService; // <------ 这里注入的标识符是 UserService 类 (userService) //... } ``` 注意:Midway 使用的驼峰库为 `camelcase` ,在一些情况下,可能和你预想的不同。比如,在碰到两个大写的时候,后一个字母会变成小写。 ``` (ABCD) => abcd; (UserMQController) => userMqController; ``` 如果不确定,你可以在项目下的命令行中临时测试。 ``` ➜ midway_v2_demo git:(master) ✗ node > require('camelCase')('UserMQController') 'userMqController' > ``` ## ## 作用域[​](#作用域 "作用域的直接链接") 默认的未指定或者未声明的情况下,所有的 `@Provide` 出来的 Class 的作用域都为 **请求作用域**。这意味着这些 Class ,会在\*\*每一次请求第一次调用时被实例化(new),请求结束后实例销毁。\*\*我们默认情况下的控制器(Controller)和服务(Service)都是这种作用域。 在 Midway 的依赖注入体系中,有三种作用域。 * Singleton 单例,全局唯一(进程级别) * Request  **默认**,请求作用域,生命周期绑定**请求链路**,实例在请求链路上唯一,请求结束立即销毁 * 例如 http 请求进来的时候,会创建一个请求作用域 ctx,我们通过@Inject()ctx 可以拿到这个请求作用域。 * 例如定时器触发,也相当于创建了请求作用于 ctx,我们可以通过@Inject()ctx 可以拿到这个请求作用域。 * Prototype 原型作用域,每次调用都会重复创建一个新的对象 不同的作用域有不同的作用,\*\*单例 \*\*可以用来做进程级别的数据缓存,或者数据库连接等只需要执行一次的工作,同时单例由于全局唯一,只初始化一次,所以调用的时候速度比较快。而 \*\*请求作用域 \*\*则是大部分需要获取请求参数和数据的服务的选择,\*\*原型作用域 \*\*使用比较少,在一些特殊的场景下也有它独特的作用。 如果我们需要将一个对象定义为其他两种作用域,需要额外的配置。Midway 提供了 `@Scope` 装饰器来定义一个类的作用域。下面的代码就将我们的 user 服务变成了一个全局唯一的实例。 ``` // service import { Scope, ScopeEnum } from '@midwayjs/decorator'; @Provide() @Scope(ScopeEnum.Singleton) export class UserService { //... } ``` 信息 默认为请求作用域的目的是为了和请求上下文关联,可以更好的追踪问题。 我们的 `@Inject`  装饰器也是在**当前类的作用域**下去寻找对象来注入的。比如,在 `Singleton`  作用域下,由于和请求不关联 ,默认没有 `ctx`  对象,所以注入 ctx 是不对的 。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() ctx; // undefined //... } ``` ## 单例的限制[​](#单例的限制 "单例的限制的直接链接") 当作用域被设置为单例(Singleton)之后,整个 Class 注入的对象在第一次实例化之后就已经被固定了,这意味着,单例中注入的内容不能是其他作用域。 我们来举个例子。 ``` // 这个类是默认的请求作用域(Request) @Provide() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { async getUser() { // ... } } ``` 调用的情况如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1606918854743-338c689a-21d1-4ed3-893a-1ac6e0d009a4.png#crop=0\&crop=0\&crop=1\&crop=1\&height=194\&id=7zjMV\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=388\&originWidth=1110\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=32617\&status=done\&style=none\&title=\&width=555) 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 都会固定的那个。 我们再来举个例子演示单例中注入的服务是否还会保留原有作用域。 信息 这里的 `DBManager` 我们特地设置成请求作用域,来演示一下特殊场景。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600597162226-5960d3e5-ac89-47c3-ab27-022005836225.png#crop=0\&crop=0\&crop=1\&crop=1\&height=167\&id=oR5we\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=334\&originWidth=1964\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=44473\&status=done\&style=none\&title=\&width=982) ``` // 这个类是默认的请求作用域(Request) @Provide() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() dbManager: DBManager; async getUser() { // ... } } // 未设置作用域,默认是请求作用域(这里用来验证单例链路下,后续的实例都被缓存的场景) @Provide() export class DBManager {} ``` 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 和 `DBManager` 都会固定的那个。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600597433574-a3c46886-146f-4e54-8659-858f4af307a6.png#crop=0\&crop=0\&crop=1\&crop=1\&height=381\&id=COok3\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=762\&originWidth=1870\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=85746\&status=done\&style=none\&title=\&width=935) 简单的理解为,单例就像一个缓存,**其中依赖的所有对象都将被冻结,不再变化。** ## 异步初始化[​](#异步初始化 "异步初始化的直接链接") 在某些情况下,我们需要一个实例在被其他依赖调用前需要初始化,如果这个初始化只是读取某个文件,那么可以写成同步方式,而如果这个初始化是从远端拿取数据或者连接某个服务,这个情况下,普通的同步代码就非常的难写。 Midway 提供了异步初始化的能力,通过 `@Init` 标签来管理初始化方法。 `@Init` 方法目前只能是一个。 ``` @Provide() export class BaseService { @Config('hello') config; @Plugin('plugin2') plugin2; @Init() async init() { await new Promise((resolve) => { setTimeout(() => { this.config.c = 10; resolve(); }, 100); }); } } ``` 等价于 ``` const service = new BaseService(); await service.init(); ``` 信息 @Init 装饰器标记的方法,一定会以异步方式来调用。一般来说,异步初始化的服务较慢,请尽可能标注为单例(@Scope(ScopeEnum.Singleton))。 ## 获取依赖注入容器[​](#获取依赖注入容器 "获取依赖注入容器的直接链接") 在一般情况下,用户无需关心依赖注入容器,但是在一些特殊场景下,比如 * 需要动态调用服务的,比如 Web 的中间件场景,启动阶段需要调用服务的 * 封装框架或者其他三方 SDK 中需要动态获取服务的 简单来说,任意需要 **通过 API 动态获取服务** 的场景,都需要先拿到依赖注入容器。 Midway 将依赖注入容器挂载在两个地方,框架的 app 以及每次请求的上下文 Context,由于不同上层框架的情况不同,我们这里列举一下常见的示例。 对于不同的上层框架,我们统一提供了 `IMidwayApplication`  定义,所有的上层框架 app 都会实现这个接口,定义如下。 ``` export interface IMidwayApplication { getApplicationContext(): IMidwayContainer; //... } ``` 即通过 `app.getApplicationContext()`  方法,我们都能获取到依赖注入容器。 ``` const container = app.getApplicationContext(); ``` 配合 `@App`  装饰器,我们可以方便的在任意地方拿到当前运行的 app 实例。 ``` import { App } from '@midwayjs/decorator'; import { IMidwayApplication } from '@midwayjs/core'; @Provide() export class BootApp { @App() app: IMidwayApplication; // 这里也可以换成实际的框架的 app 定义 async ready() { // 获取依赖注入容器 const container = this.app.getApplicationContext(); } } ``` 除了普通的依赖注入容器之外,Midway 还提供了一个 \*\*请求链路的依赖注入容器,\*\*这个请求链路的依赖注入容器和全局的依赖注入容器关联,共享一个对象池。但是两者还是有所区别的。 请求链路的依赖注入容器,是为了获取特有的请求作用域的对象,这个容器中获取的对象,都是**和请求绑定**,关联了当前的上下文。这意味着,**如果 Class 代码和请求关联,必须要从这个请求链路的依赖注入容器中获取**。 请求链路的依赖注入容器,必须从请求上下文对象中获取,最常见的场景为 Web 中间件。 ``` @Provide() export class ReportMiddleware { resolve() { return async (ctx, next) => { // ctx.requestContext 请求链路的依赖注入容器 await next(); }; } } ``` Express 的请求链路依赖注入容器挂载在 req 对象上。 ``` @Provide() export class ReportMiddleware { resolve() { return (req, res, next) => { // req.requestContext 请求链路的依赖注入容器 next(); }; } } ``` ## 动态获取服务等实例[​](#动态获取服务等实例 "动态获取服务等实例的直接链接") 拿到 \*\*依赖注入容器 \*\*或者 \*\*请求链路的依赖 \*\*注入容器之后,才可以通过容器的 API 获取到对象。 ``` import { UserService } from './service/user'; @Provide() export class ReportMiddleware { @App() app: IMidwayApplication; resolve() { return async (ctx, next) => { const container = app.getApplicationContext(); // 下面的方法等价,获取的对象和请求不关联,没有 ctx 上下文 const userService1 = await container.getAsync('userService'); const userService2 = await container.getAsync(UserService); // 如果传入 class,这么写也能推导出正确的类型 const userService2 = await container.getAsync(UserService); // 下面的方法获取的服务和请求关联,可以注入上下文 const userService = await ctx.requestContext.getAsync(UserService); await next(); }; } } ``` Express 的写法 ``` import { UserService } from './service/user'; @Provide() export class ReportMiddleware { @App() app: IMidwayApplication; resolve() { return (req, res, next) => { req.requestContext.getAsync(UserService).then((userService) => { // do something next(); }); }; } } ``` ## 注入已有对象[​](#注入已有对象 "注入已有对象的直接链接") 有时候,应用已经有现有的实例,而不是类,比如引入了一个第三库,这个时候如果希望对象能够被其他 IoC 容器中的实例引用,也可以通过增加对象的方式进行处理。 我们拿常见的 http 请求库 [urllib](https://www.npmjs.com/package/urllib) 来举例。 假如我们希望在不同的类中来使用,并且不通过 require 的方式,你需要在业务调用前(一般在启动的生命周期中)通过 `registerObject`  方法添加这个对象。 在添加的时候需要给出一个 **标识符**,方便其他类中注入。 ``` // in global file import * as urllib from 'urllib'; import { Configuration } from '@midwayjs/decorator'; @Configuration() export class AutoConfiguration { @App() app: IMidwayApplication; async onReady() { // 注入一些全局对象 this.app.getApplicationContext().registerObject('httpclient', urllib); } } ``` 这个时候就可以在任意的类中通过 `@Inject` 来使用了。 ``` @Provide() export class BaseService { @Inject() httpclient; async getUser() { return await this.httpclient.request('/api/getuser'); } } ``` ## 动态函数注入[​](#动态函数注入 "动态函数注入的直接链接") 在某些场景下,我们需要函数作为某个逻辑动态执行,而依赖注入容器中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。 比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个工厂方法,并且在函数中拿到上下文,动态去生成实例。 下面是标准的工厂方法注入样例。 一般工厂方法用于返回相同接口的实现,比如我们有两个 `ICacheService`  接口的实现: ``` export interface ICacheService { getData(): any; } @Provide() export class LocalCacheService implements ICacheService { async getData {} } @Provide() export class RemoteCacheService implements ICacheService { async getData {} } ``` 然后可以定义一个动态服务(工厂),根据当前的用户配置返回不同的实现。 ``` // src/service/dynamicCacheService.ts import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export async function dynamicCacheServiceHandler(container: IMidwayContainer) { // 从容器 API 获取全局配置 const config = container.getConfigService().getConfiguration(); if (config['redis']['mode'] === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } } providerWrapper([ { id: 'dynamicCacheService', provider: dynamicCacheServiceHandler, scope: ScopeEnum.Request, // 设置为请求作用域,那么上面传入的容器就为请求作用域容器 // scope: ScopeEnum.Singleton, // 也可以设置为全局作用域,那么里面的调用的逻辑将被缓存 }, ]); ``` 这样在业务中,可以直接来使用了。注意:在注入的时候,方法会**被调用后再注入**。 ``` @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('dynamicCacheServiceHandler') cacheService: ICacheService; @Get('/') async home() { const data = await this.cacheService.getData(); // ... } } ``` 通过 `providerWrapper` 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。 信息 注意,动态方法必须 export,才会被依赖注入扫描到,默认为请求作用域(获取的 Container 是请求作用域容器)。 由于我们能将动态方法绑定到依赖注入容器,那么也能将一个回调方法绑定进去,这样获取的方法是可以被执行的,我们可以根据业务的传参来决定返回的结果。 ``` import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export function cacheServiceHandler(container: IMidwayContainer) { return async (mode: string) => { if (mode === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } }; } providerWrapper([ { id: 'cacheServiceHandler', provider: cacheServiceHandler, scope: ScopeEnum.Singleton, }, ]); @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('cacheServiceHandler') getCacheService; @Get('/') async home() { const data = await this.getCacheService('local'); // ... } } ``` ## 依赖注入容器的默认对象[​](#依赖注入容器的默认对象 "依赖注入容器的默认对象的直接链接") Midway 会默认注入一些值,方便业务直接使用。 | **标识符** | **值类型** | **作用域** | **描述** | | ---------- | ---------- | ---------- | ------------------------------------------------------------------ | | baseDir | string | 全局 | 本地使用 ts-node 开发时为 src 目录,否则为 dist 目录 | | appDir | string | 全局 | 应用的根路径,一般为 process.cwd() | | ctx | object | 请求链路 | 对应框架的上下文类型,比如 EggJS 和 Koa 的 Context,Express 的 req | | logger | object | 请求链路 | 在 EggJS 下等价于 ctx.logger | | req | object | 请求链路 | Express 特有 | | res | object | 请求链路 | Express 特有 | | socket | object | 请求链路 | WebSocket 场景特有 | ``` @Provide() export class BaseService { @Inject() baseDir; @Inject() appDir; async getUser() { console.log(this.baseDir); console.log(this.appDir); } } ``` ## 类名冲突检查[​](#类名冲突检查 "类名冲突检查的直接链接") 在项目比较大的时候,比较容易出现类名重复,Midway 提供同名类重复检查的功能。只需要在入口 `configuration.ts`  文件的 `@Configuration`  装饰器中加入 `conflictCheck`  属性即可。 代码如下: ``` @Configuration({ conflictCheck: true, // 开启命名冲突检查 }) export class AutoConfiguration {} ``` ## 静态 API[​](#静态-api "静态 API的直接链接") 在有些工具类中,我们可以不需要创建 class 实例就能获取到全局的依赖注入容器(**在使用 bootstrap.js 启动之后**)。 ``` import { getCurrentApplicationContext } from '@midwayjs/core'; export const getService = async (serviceName) => { return getCurrentApplicationContext().getAsync(serviceName); }; ``` 获取主框架(**在使用 bootstrap.js 启动之后**)。 ``` import { getCurrentMainFramework } from '@midwayjs/core'; export const framework = () => { return getCurrentMainFramework(); }; ``` 获取主框架的 app 对象(**在使用 bootstrap.js 启动之后**)。 ``` import { getCurrentMainApp } from '@midwayjs/core'; export const getGlobalConfig = () => { return getCurrentMainApp().getConfig(); }; ``` ## 面向接口编程[​](#面向接口编程 "面向接口编程的直接链接") Midway 也可以基于接口进行注入,但是由于 Typescirpt 编译后会移除接口类型,不如使用类作为定义好用。 比如,我们定义一个接口,以及它的实现类。 ``` export interface IPay { payMoney(); } @Provide('WeChatPay') export class WeChatPay implements IPay { async payMoney() { // ... } } @Provide('AlipayPay') export class AlipayPay implements IPay { async payMoney() { // ... } } ``` 这个时候,如果有个服务需要注入,可以使用下面显式声明的方式。 ``` @Provide() export class PaymentService { @Inject('AlipayPay') payService: IPay; // 注意,这里的类型是接口,编译后类型信息会被移除 async orderGood { await this.payService.payMonety(); } } ``` 由于接口类型会被移除,Midway 只能通过 `@Inject` 装饰器的 **参数** 或者 **属性名** 类来匹配注入的对象信息,类似 Java Spring 中的 `Autowire by name` 。 上述就是 \*\*静态 \*\*的面向接口注入的方式。 如果需要动态,也和 [动态函数注入](/docs/2.0.0/动态函数注入) 描述的一致,注入方法来使用。 ## 常见的使用错误[​](#常见的使用错误 "常见的使用错误的直接链接") ### 错误:构造器中获取注入属性[​](#错误构造器中获取注入属性 "错误:构造器中获取注入属性的直接链接") \*\*请不要在构造器中 \*\*获取注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('userManager') userManager; constructor() { console.log(this.userManager); // undefined } @Init() async initMethod() { console.log(this.userManager); // has value } } ``` ## 关于继承[​](#关于继承 "关于继承的直接链接") 为了避免属性错乱,请不要在基类上使用 `@Provide`  装饰器。 现阶段,Midway 支持属性装饰器的继承,不支持类和方法装饰器的继承(会有歧义)。 --- # 扩展上下文定义 在某些场景下,需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 ``` import { Context } from 'egg'; // 或者其他上层框架导出的 Context @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next) { ctx.abc = '123'; await next(); } } } ``` 但是由于 TypeScript 模块定义的关系,我们无法往现有的模块上去附加定义,所以我们使用了一种新的方法来扩展。 ## 项目中扩展定义[​](#项目中扩展定义 "项目中扩展定义的直接链接") 你可以在 `src/interface.ts` 通过下面的代码,在项目中扩展 Midway 通用的 Context。 ``` // src/interface.ts declare module '@midwayjs/core' { interface Context { abc: string; } } ``` ## 组件中扩展定义[​](#组件中扩展定义 "组件中扩展定义的直接链接") 你可以在组件的 `src/index.ts` 或者其他导出的文件出,通过下面的代码,扩展 Midway 通用的 Context。 ``` // src/interface.ts declare module '@midwayjs/core/dist/interface' { interface Context { abc: string; } } ``` 组件中扩展和项目中略有不同(怀疑是 TS 的 bug)。 --- # 控制器(Controller) 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责**解析用户的输入,处理后返回相应的结果。** ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600592027849-679b4cfc-cf11-466a-a467-403907bd6a3e.png#crop=0\&crop=0\&crop=1\&crop=1\&height=317\&id=Hffdy\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=634\&originWidth=1600\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=57905\&status=done\&style=none\&title=\&width=800) 常见的有: * 在 [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) 接口中,控制器接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。 * 在 HTML 页面请求中,控制器根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。 * 在代理服务器中,控制器将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。 一般来说,控制器常用于对用户的请求参数做一些校验,转换,调用复杂的业务逻辑,拿到相应的业务结果后进行数据组装,然后返回。 在 Midway 中,控制器**也承载了路由的能力**,每个控制器可以提供多个路由,不同的路由可以执行不同的操作。 在接下去的示例中,我们将演示如何在控制器中创建路由。 ## 路由[​](#路由 "路由的直接链接") 控制器文件一般来说在 `src/controller`  目录中,我们可以在其中创建控制器文件。Midway 使用 `@Controller()` 装饰器标注控制器,其中装饰器有一个可选参数,用于进行路由前缀(分组),这样这个控制器下面的所有路由都会带上这个前缀。 同时,Midway 提供了方法装饰器用于标注请求的类型。 比如,我们创建一个首页控制器,用于返回一个默认的 `/`  路由的页面。 ``` ➜ my_midway_app tree . ├── src │ └── controller │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { return 'Hello Midwayjs!'; } } ``` `@Controller`  装饰器告诉框架,这是一个 Web 控制器类型的类,而 `@Get`  装饰器告诉框架,被修饰的 `home`  方法,将被暴露为 `/`  这个路由,可以由 `GET`  请求来访问。 整个方法返回了一个字符串,在浏览器中你会收到 `text/plain`  的响应类型,以及一个 `200`  的状态码。 ## 路由方法[​](#路由方法 "路由方法的直接链接") 上面的示例,我们已经创建了一个 **GET**  路由。一般情况下,我们会有其他的 HTTP Method,Midway 提供了更多的路由方法装饰器。 ``` // src/controller/home.ts import { Controller, Get, Post, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { return 'Hello Midwayjs!'; } @Post('/update') async updateData() { return 'This is a post method'; } } ``` Midway 还提供了其他的装饰器, `@Get` 、 `@Post` 、 `@Put()` 、 `@Del()` 、 `@Patch()` 、 `@Options()` 、 `@Head()`  和  `@All()` ,表示各自的  HTTP 请求方法。 `@All`  装饰器比较特殊,表示能接受以上所有类型的 HTTP Method。 你可以将多个路由绑定到同一个方法上。 ``` @Get('/') @Get('/main') async home() { return 'Hello Midwayjs!'; } ``` ## 请求参数[​](#请求参数 "请求参数的直接链接") 接下去,我们将创建一个关于用户的 HTTP API,同样的,创建一个 `src/controller/user.ts`  文件,这次我们会增加一个路由前缀,以及增加更多的请求类型。 我们以用户类型举例,先增加一个用户类型,我们一般会将定义的内容放在 `src/interface.ts`  文件中。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/interface.ts export interface User { id: number; name: string; age: number; } ``` 再添加一个路由前缀以及对应的控制器。 ``` // src/controller/user.ts import { Controller, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/api/user') export class UserController { // xxxx } ``` 接下去,我们要针对不同的请求类型,调用不同的处理逻辑。除了请求类型之外,请求的数据一般都是动态的,会在 HTTP 的不同位置来传递,比如常见的 Query,Body 等。 Midway 添加了常见的动态取值的装饰器,我们以 `@Query`  装饰器举例, `@Query`  装饰器会获取到 URL 中的 Query 参数部分,并将它赋值给函数入参。下面的示例,id 会从路由的 Query 参数上拿,如果 URL 为 `/?id=1` ,则 id 的值为 1,同时,这个路由将会返回 `User`  类型的对象。 ``` // src/controller/user.ts import { Controller, Provide, Get, Query } from '@midwayjs/decorator'; @Provide() @Controller('/api/user') export class UserController { @Get('/') async getUser(@Query() id: string): Promise { // xxxx } } ``` `@Query`  装饰器的有参数,可以传入一个指定的字符串 key,获取对应的值,赋值给入参,如果不传入,则默认的字符串 key 为参数名。 ``` // 下面两种写法相同 async getUser(@Query() id: string) async getUser(@Query('id') id: string) // 可以修改参数名,这个时候为了取到值就必须修改装饰器的参数 // URL = /?id=1 async getUser(@Query('id') uid: string) // uid = 1 ``` 有时候,我们希望拿到整个 Query 对象的值,Midway 提供了一个特殊的 key,用于指定获取整个对象。 ``` import { ALL } from "@midwayjs/decorator"; async getUser(@Query(ALL) queryObject: object) // queryObject = {"id": 1} ``` Midway 提供了更多从 Query、Body 、Header 等位置获取值的装饰器,这些都是开箱即用,并且适配于不同的上层 Web 框架。 下面是这些装饰器,以及对应的等价框架取值方式。 | **装饰器** | **Express** | **Koa/EggJS** | | ----------------------- | -------------------------------- | ----------------------------------------- | | @Session(key?: string) | req.session / req.session\[key] | ctx.session / ctx.session\[key] | | @Param(key?: string) | req.params / req.params\[key] | ctx.params / ctx.params\[key] | | @Body(key?: string) | req.body / req.body\[key] | ctx.request.body / ctx.request.body\[key] | | @Query(key?: string) | req.query / req.query\[key] | ctx.query / ctx.query\[key] | | @Queries(key?: string) | 无 | 无 / ctx.queries\[key] | | @Headers(name?: string) | req.headers / req.headers\[name] | ctx.headers / ctx.headers\[name] | | | | | 信息 注意:ALL 这个 key 这些装饰器都可用, `ALL`  和 `All`  是不同的, `ALL`  用来获取到所有的属性,是一个变量,而 `All`  是一个装饰器,用于匹配所有 method 的请求。 警告 \*\*注意 \*\*@Queries 装饰器和 @Query **有所区别**。 Queries 会将相同的 key 聚合到一起,变为数组。当用户访问的接口参数为 `/?name=a&name=b` 时,@Queries 会返回 `{name: [a, b]}`,而 Query 只会返回 `{name: b}` **示例:获取单个 body** ``` @Post('/') async updateUser(@Body() id: string): Promise { // id 等价于 ctx.request.body.id } ``` **示例:所有 body 参数** ``` @Post('/') async updateUser(@Body(ALL) user: User): Promise { // user 等价于 ctx.request.body 整个 body 对象 } ``` **示例:获取 query 和 body 参数** 装饰器可以组合使用。 ``` @Post('/') async updateUser(@Body(ALL) user: User, @Query() pageIdx: number): Promise { // user 从 body 获取 // pageIdx 从 query 获取 } ``` **示例:获取 param 参数** ``` @Get('/api/user/:uid') async findUser(@Param() uid: string): Promise { // uid 从路由参数中获取 } ``` 还有一些比较常见的参数装饰器,以及它们的对应方法。 | **装饰器** | **Express** | **Koa/EggJS** | | ------------ | ----------- | ------------- | | @RequestPath | req.baseurl | ctx.path | | @RequestIP | req.ip | ctx.ip | | | | | **示例:获取 body 、path 和 ip** ``` @Post('/') async updateUser( @Body() id: string, @RequestPath() p: string, @RequestIP() ip: string): Promise { } ``` ## 状态码[​](#状态码 "状态码的直接链接") 默认情况下,响应的**状态码**总是**200**,我们可以通过在处理程序层添加 `@HttpCode` 装饰器来轻松更改此行为。 ``` import { Controller, Get, Provide, HttpCode } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') @HttpCode(201) async home() { return 'Hello Midwayjs!'; } } ``` 信息 状态码装饰器不能在响应流关闭后(response.end 之后)修改。 ## 响应头[​](#响应头 "响应头的直接链接") Midway 提供 `@SetHeader`  装饰器来简单的设置自定义响应头。 ``` import { Controller, Get, Provide, SetHeader } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') @SetHeader('x-bbb', '123') async home() { return 'Hello Midwayjs!'; } } ``` 当有多个响应头需要修改的时候,你可以直接传入对象。 ``` import { Controller, Get, Provide, SetHeader } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') @SetHeader({ 'x-bbb': '123', 'x-ccc': '234', }) async home() { return 'Hello Midwayjs!'; } } ``` 信息 响应头装饰器不能在响应流关闭后(response.end 之后)修改。 ## 重定向[​](#重定向 "重定向的直接链接") 如果需要简单的将某个路由重定向到另一个路由,可以使用 `@Redirect`  装饰器。 `@Redirect`  装饰器的参数为一个跳转的 URL,以及一个可选的状态码,默认跳转的状态码为 `302` 。 ``` import { Controller, Get, Provide, Redirect } from '@midwayjs/decorator'; @Provide() @Controller('/') export class LoginController { @Get('/login_check') async check() { // TODO } @Get('/login') @Redirect('/login_check') async login() { // TODO } @Get('/login_another') @Redirect('/login_check', 302) async loginAnother() { // TODO } } ``` 信息 重定向装饰器不能在响应流关闭后(response.end 之后)修改。 ## 响应类型[​](#响应类型 "响应类型的直接链接") 虽然浏览器会自动根据内容判断最佳的响应内容,但是我们经常会碰到需要手动设置的情况。我们也提供了 `@ContentType`  装饰器用于设置响应类型。 ``` import { Controller, Get, Provide, ContentType } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') @ContentType('html') async login() { return 'hello world'; } } ``` 信息 响应类型装饰器不能在响应流关闭后(response.end 之后)修改。 ## 优先级[​](#优先级 "优先级的直接链接") midway 已经统一对路由做排序,通配的路径将自动降低优先级,在最后被加载。 规则如下: * 1、绝对路径规则优先级最高如 `/ab/cb/e` * 2、星号只能出现最后且必须在/后面,`如 /ab/cb/**` * 3、如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高,比如 `/abc/*` 和 `/abc/d`,那么请求 `/abc/d` 时,会匹配到后一个绝对的路由 * 4、有多个通配能匹配一个路径时,最长的规则匹配,如 `/ab/**` 和 `/ab/cd/**` 在匹配 `/ab/cd/f` 时命中 `/ab/cd/**` * 5、如果 `/` 与 `/*` 都能匹配 `/` ,但 `/` 的优先级高于 `/*` * 6、如果都为通配,但是其余权重都一样,比如 `/:page/page` 和 `/page/:page` ,那么两者权重等价,以编码加载顺序为准 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如: ``` @Controller('/api') export class APIController { @Get('/invoke/*') async invokeAll() {} @Get('/invoke/abc') async invokeABC() {} } ``` 这种情况下,会先注册 `/invoke/abc` ,保证优先级更高。 不同的 Controller 的优先级,我们会以长度进行排序, `/` 根 Controller 我们将会最后加载。 --- # Cookies HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: * 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息) * 个性化设置(如用户自定义设置、主题等) * 浏览器行为跟踪(如跟踪分析用户行为等) ## 在 @midwayjs/web 使用[​](#在-midwayjsweb-使用 "在 @midwayjs/web 使用的直接链接") 通过 `ctx.cookies`,我们可以在有 ctx 的时候便捷、安全的设置和读取 Cookie。 比如 Controller 中。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; import { Context } from 'egg'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 cookie let count = this.ctx.cookies.get('count'); count = count ? Number(count) : 0; // 设置 cookie this.ctx.cookies.set('count', ++count); return count; } } ``` `ctx.cookies`  的方法上有更多的参数,具体可以查阅 [Cookie 与 Session](https://eggjs.org/zh-cn/core/cookie-and-session.html)。 ## 在 @midwayjs/koa 使用[​](#在-midwayjskoa-使用 "在 @midwayjs/koa 使用的直接链接") koa 提供了从上下文直接读取、写入 cookie 的方法 * `ctx.cookies.get(name, [options])` 读取上下文请求中的 cookie * `ctx.cookies.set(name, value, [options])` 在上下文中写入 cookie 操作 cookies 是使用了 [cookies](https://github.com/pillarjs/cookies) 模块。 示例如下: ``` import { Inject, Controller, Get, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.cookies.set('cid', 'hello world', { domain: 'localhost', // 写cookie所在的域名 path: '/index', // 写cookie所在的路径 maxAge: 10 * 60 * 1000, // cookie有效时长 expires: new Date('2017-02-15'), // cookie失效时间 httpOnly: false, // 是否只用于http请求中获取 overwrite: false, // 是否允许重写 }); ctx.body = 'cookie is ok'; } } ``` ## 在 @midwayjs/express 使用[​](#在-midwayjsexpress-使用 "在 @midwayjs/express 使用的直接链接") 首先安装 `cookie-parser`  依赖。 ``` $ npm i cookie-parser --save $ npm i @types/cookie-parser --save-dev ``` 加到中间件中。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as cookieParser from 'cookie-parser'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use(cookieParser()); } } ``` cookieParser 中间件中包含一些参数: * \*\*secret \*\*一个字符串或者数组,用来给 cookie 签名。如果提供了一个数组,将尝试依次使用其元素来作为 secret 解析 cookie。 * **option** 一个作为第二个参数传递给 `cookie.parse`  的对象,参见 [cookie](https://www.npmjs.org/package/cookie) 来了解更多内容。 获取 req 对象获取 Cookie。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() req: Request; @Get('/') async home() { // 获取未加密的 cookie console.log('Cookies: ', this.req.cookies); // 获取加密的 cookie console.log('Signed Cookies: ', this.req.signedCookies); } } ``` 更多 API 可以参考 [cookie-parser](https://github.com/expressjs/cookie-parser)。 ## 在 Serverless 场景使用[​](#在-serverless-场景使用 "在 Serverless 场景使用的直接链接") 当前 Serverless 场景中使用的也是 [cookies](https://github.com/pillarjs/cookies) 模块,和 koa 使用的相同。 即依旧可以从上下文直接读取、写入 cookies。 --- # 跨域 CORS 跨源资源共享([CORS](https://developer.mozilla.org/zh-CN/docs/Glossary/CORS)) (或通俗地译为跨域资源共享)是一种基于[HTTP](https://developer.mozilla.org/zh-CN/docs/Glossary/HTTP)头的机制,该机制通过允许服务器标示除了它自己以外的其它 [origin](https://developer.mozilla.org/zh-CN/docs/Glossary/Origin)(域,协议和端口),这样浏览器可以访问加载这些资源。 简单来说,CORS 的设置会影响前端请求跨域资源。 ## 在 @midwayjs/web 使用[​](#在-midwayjsweb-使用 "在 @midwayjs/web 使用的直接链接") 安装 egg-cors。 ``` $ npm i egg-cors --save  ``` 配置插件启用 ``` // src/config/plugin.ts exports.cors = { enable: true, package: 'egg-cors', }; ``` 配置 cors 插件。 ``` // src/config/config.default.ts export const cors = { // {string|Function} origin: '*', // {string|Array} allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH' }; ``` 如果只想特定域名,需要在 security 插件处配置。 ``` // src/config/config.default.ts export const security = { domainWhiteList: ['http://localhost:4200'], // 允许跨域的域名 }; ``` 具体请参考 [cors 文档](https://github.com/eggjs/egg-cors)。 ## 在 @midwayjs/koa 使用[​](#在-midwayjskoa-使用 "在 @midwayjs/koa 使用的直接链接") koa 当前使用 [@koa/cors](https://github.com/koajs/cors) 包来做。 ``` $ npm i @koa/cors --save ``` 然后在 `configuration.ts` 中直接加入中间件即可。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import * as cors from '@koa/cors'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( cors({ origin: '*', }) ); } } ``` 更多配置,请参考 [@koa/cors 文档](https://github.com/koajs/cors)。 ## 在 @midwayjs/express 使用[​](#在-midwayjsexpress-使用 "在 @midwayjs/express 使用的直接链接") 使用 cors 包。 ``` $ npm install cors --save ``` 然后在 `configuration.ts` 中直接加入中间件即可。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as cors from 'cors'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( cors({ origin: '*', }) ); } } ``` 更多配置,请参考 [cors 文档](https://expressjs.com/en/resources/middleware/cors.html)。 ## 在 Serverless 场景使用[​](#在-serverless-场景使用 "在 Serverless 场景使用的直接链接") **在 FC 的 HTTP 触发器下,无需配置 cors,网关自动支持 OPTIONS。** 其余平台或者触发器,可以适当使用下面的代码。 函数的 CORS 可以复用 koa 的 CORS 能力。 ``` $ npm i @koa/cors --save ``` 然后在 `configuration.ts` 中直接加入中间件即可。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/faas'; import * as cors from '@koa/cors'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( cors({ origin: '*', }) ); } } ``` 更多配置,请参考 [@koa/cors 文档](https://github.com/koajs/cors)。 --- # 自定义 EggJS 框架接入 在 Midway 体系中,我们通过 `@midwayjs/web` ,支持了 EggJS 作为上层框架,并将 Web 层传统的控制器、服务等分层,以及依赖注入带到了 EggJS 体系。 在社区中,有不少公司已经基于 EggJS 封装了自己的插件和框架,如果这个时候基于 MidwayJS 需要重写原有的框架体系,就显得很不切实际。为此,Midway 开发了一套让 EggJS 上层框架快速接入 Midway 体系,使用到 Midway 依赖注入能力的方式。 ## 上层框架要求[​](#上层框架要求 "上层框架要求的直接链接") 我们以一个名为 `fake-egg`  的上层框架举例。 EggJS 的上层框架,按照文档会有一些要求,会导出一些固定的属性,比如 `Application` 、 `Agent` 、 `AppWorkerLoader`  以及 `AgentWorkerLoader`  这四个属性,**这四个属性必须导出**,示例如下。 ``` 'use strict'; const egg = require('egg'); const framework = {}; /** * @member {Application} Egg#Application * @since 1.0.0 */ framework.Application = require('./lib/application'); /** * @member {Agent} Egg#Agent * @since 1.0.0 */ framework.Agent = require('./lib/agent'); /** * @member {Agent} Egg#AppWorkerLoader * @since 1.0.0 */ framework.AppWorkerLoader = require('./lib/core/loader/app_worker_loader'); /** * @member {Agent} Egg#AgentWorkerLoader * @since 1.0.0 */ framework.AgentWorkerLoader = require('./lib/core/loader/agent_worker_loader'); module.exports = exports = Object.assign(egg, framework); ``` ## 接入 MidwayJS[​](#接入-midwayjs "接入 MidwayJS的直接链接") 接入 MidwayJS 的方式很简单。只需要沿用 EggJS 的自定义框架接入方式,在实际业务的 `package.json`  中增加字段即可。 ``` { "name": "ali-demo", "egg": { "framework": "fake-egg" } } ``` 这样, `@midwayjs/web`  会自动加载该框架,并将其作为基础的上层框架增加依赖注入,装饰器等能力。这样既可以享受到该上层框架的 EggJS 扩展能力,又能使用现有的 Midway 体系的能力。 扩展之后,整个目录结构会沿用 Midway 体系,并将 EggJS 默认的 baseDir 修改为 `src`  中。 完整的用户的 `package.json`  如下。 ``` { "name": "{{name}}", "private": true, "dependencies": { "@midwayjs/web": "^2.3.0", "@midwayjs/decorator": "^2.3.0", "fake-egg": "^1.0.0", // 这里增加了上层框架 "egg": "^2.0.0", "egg-scripts": "^2.10.0", "midway": "^2.3.0" }, "devDependencies": { ... // 开发依赖没有变化 }, "egg": { "framework": "fake-egg" // 额外增加一个配置指定上层框架 } } ``` 其他关于如何实现一个 EggJS 自定义框架,请参考 [EggJS 文档](https://eggjs.org/zh-cn/advanced/framework.html)。 --- # 本地调试 ## 在 VSCode 中调试[​](#在-vscode-中调试 "在 VSCode 中调试的直接链接") ### 方法一:使用 JavaScript Debug Teminal[​](#方法一使用-javascript-debug-teminal "方法一:使用 JavaScript Debug Teminal的直接链接") 在 VSCode 的终端下拉出,隐藏着一个 `JavaScript Debug Terminal` ,点击它,创建出来的终端将自带调试能力。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600961364664-67885e44-3308-4c98-95ff-1af398dba9ae.png#crop=0\&crop=0\&crop=1\&crop=1\&height=182\&id=UBgAF\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=364\&originWidth=1030\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=141353\&status=done\&style=none\&title=\&width=515) 输入任意的命令都将自动开启 Debug,比如输入 `npm run dev`  后。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600961451349-29b4b0a7-5863-4ff3-a66c-db58eb1cc199.png#crop=0\&crop=0\&crop=1\&crop=1\&height=522\&id=NkQPJ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1044\&originWidth=2746\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=212246\&status=done\&style=none\&title=\&width=1373) ### 方法二:配置调试文件[​](#方法二配置调试文件 "方法二:配置调试文件的直接链接") 创建一个 vscode 的启动文件。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612503130603-a83b5e41-e6b9-49e6-be5a-4bfb993b48b7.png#crop=0\&crop=0\&crop=1\&crop=1\&height=344\&id=kRdF4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=344\&originWidth=645\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=28531\&status=done\&style=none\&title=\&width=645) 随便选一个,会创建 `.vscode/launch.json` 文件, ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612503193927-26976931-b53a-4144-bd57-c4d178d2d8ec.png#crop=0\&crop=0\&crop=1\&crop=1\&height=231\&id=nIc4g\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=231\&originWidth=655\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=21494\&status=done\&style=none\&title=\&width=655) 将下面内容复制进去。 ``` { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Midway Local", "type": "node", "request": "launch", "cwd": "${workspaceRoot}", "runtimeExecutable": "npm", "windows": { "runtimeExecutable": "npm.cmd" }, "runtimeArgs": ["run", "dev"], "env": { "NODE_ENV": "local" }, "console": "integratedTerminal", "protocol": "auto", "restart": true, "port": 7001, "autoAttachChildProcesses": true } ] } ``` 启动断点即可。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612503389173-0f8e3219-0fe7-43d7-89c2-f0283bc249a9.png#crop=0\&crop=0\&crop=1\&crop=1\&height=1020\&id=uw08t\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1020\&originWidth=1470\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=199463\&status=done\&style=none\&title=\&width=1470) ## 在 WebStorm/Idea 中调试[​](#在-webstormidea-中调试 "在 WebStorm/Idea 中调试的直接链接") 开始配置 IDE。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1587031125652-b33f5a18-8ae1-405f-b1a9-bd6ea923e099.png#crop=0\&crop=0\&crop=1\&crop=1\&height=346\&id=jq74g\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=692\&originWidth=1110\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=83457\&status=done\&style=none\&title=\&width=555) 配置 npm 命令。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1608369067606-9bd2faf2-757c-44e6-8ce1-c2d32508aedf.png#crop=0\&crop=0\&crop=1\&crop=1\&height=473\&id=qhCMB\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=946\&originWidth=620\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=146092\&status=done\&style=none\&title=\&width=310) 选择你的 `package.json`  后,下拉选择 `Scrips` ,其中是你 `package.json`  中配置好的 `scripts`  中的命令,选择你要的命令,比如 `dev`  或者 `test`  等即可 。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1608369181502-5d1fabff-595a-4dd2-90a4-69e4d5963062.png#crop=0\&crop=0\&crop=1\&crop=1\&height=533\&id=TJViO\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1066\&originWidth=1572\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=189712\&status=done\&style=none\&title=\&width=786) 在代码上断点后执行调试即可。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1587031866061-68fa841d-6030-45b3-ab74-adfa4264df74.png#crop=0\&crop=0\&crop=1\&crop=1\&height=454\&id=VKEnS\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=907\&originWidth=1327\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=193255\&status=done\&style=none\&title=\&width=663.5) ### ## 在 Chrome 中调试[​](#在-chrome-中调试 "在 Chrome 中调试的直接链接") 如果您使用 vim 或其他代码编辑器,可以使用此方式,通过 `@midwayjs/cli` 的 `dev` 命令,添加 `--debug` 参数启动 debug 模式,可以通过 `chrome devtools` 进行单步代码调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994136312-f1eda8ba-165d-4322-82b8-b21d3b9c6beb.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=317\&id=z4u1f\&margin=%5Bobject%20Object%5D\&name=69456694-513D-4388-B52F-001562D4A520.png\&originHeight=666\&originWidth=1538\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=276022\&status=done\&style=none\&taskId=ud161d835-1e96-4246-8061-c795e9a0ff1\&title=\&width=731) 您可以通过 `chrome://inspect/` 打开 `nodejs devtools` 进行断点调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995391144-a9ec0d4a-c6fb-4638-a292-615a3588d33d.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=354\&id=u4986bfa4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=1948\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=572568\&status=done\&style=none\&taskId=u07555349-8e09-42b2-bd94-f93160b0431\&title=\&width=732) ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995418427-282d256a-de65-4eba-9a83-b474d3d74f9f.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=445\&id=u83271ad1\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1280\&originWidth=2280\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=710504\&status=done\&style=none\&taskId=uc2614db9-dea9-48d7-b87d-8cb608c8770\&title=\&width=792) 您也可以直接通过 chrome 浏览器打开命令行中输出的 `devtools` 协议的链接,给对应代码添加断点后调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994137067-f663409a-483d-41f5-bc86-4798182edb38.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=243\&id=GooAh\&margin=%5Bobject%20Object%5D\&name=10016148-385E-46A4-8B3A-0A0110BECD18.png\&originHeight=950\&originWidth=2878\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=744085\&status=done\&style=none\&taskId=u892d9925-9206-4946-a1ed-cb6043c557d\&title=\&width=737) --- # 高级装饰器 API Midway 内部有一套标准的装饰器管理 API,用来将装饰器对接依赖注入容器,实现扫描和扩展,这些 API 方法我们都从 `@midwayjs/decorator`  包进行导出。 通过装饰器高级 API,我们可以自定义装饰器,并且将元数据附加其中,内部的各种装饰器都是通过该能力实现的。 常见的扩展 API 有: **装饰器** * `saveModule`  用于保存某个类到某个装饰器 * `listModule`  获取所有绑定到某类型装饰器的 class **元信息 (对应 **[**reflect-metadata**](https://www.npmjs.com/package/reflect-metadata)**)** * `saveClassMetadata`  保存元信息到 class * `attachClassMetadata`  附加元信息到 class * `getClassMetadata`  从 class 获取元信息 * `savePropertyDataToClass`   保存属性的元信息到 class * `attachPropertyDataToClass`  附加属性的元信息到 class * `getPropertyDataFromClass`  从 class 获取属性元信息 * `listPropertyDataFromClass`  列出 class 上保存的所有的属性的元信息 * `savePropertyMetadata`  保存属性元信息到属性本身 * `attachPropertyMetadata`  附加属性元信息到属性本身 * `getPropertyMetadata`   从属性上获取保存的元信息 **快捷操作** * `getProviderId`  获取 class 上 provide 出来的 id * `getObjectDefinition`  获取对象定义(ObjectDefiniton) * `getParamNames`  获取一个函数的所有参数名 * `clearAllModule`  清理装饰器对应的 class map(对应 saveModule) ## 自定义装饰器[​](#自定义装饰器 "自定义装饰器的直接链接") 我们举一个例子,如果我们需要定义一个类装饰器 @Model ,被修饰的 class 则表明是一个 Model class,然后进一步操作。 创建一个装饰器文件,比如 `src/decorator/model` 。 ``` import { Scope, ScopeEnum, saveClassMetadata, saveModule } from '@midwayjs/decorator'; const MODEL_KEY = 'decorator:model'; export function Model(): ClassDecorator { return (target: any) => { // 将装饰的类,绑定到该装饰器,用于后续能获取到 class saveModule(MODEL_KEY, target); // 保存一些元数据信息,任意你希望存的东西 saveClassMetadata( MODEL_KEY, { test: 'abc', }, target ); // 指定 IoC 容器创建实例的作用域,这里注册为请求作用域,这样能取到 ctx Scope(ScopeEnum.Request)(target); }; } ``` 上面只是定了了这个装饰器,我们还要实现相应的功能,这个功能文件必须在一开始就加载,midway v2 开始有生命周期的概念,可以在 `configuration`  中的生命周期中执行。midway1 可以在 `app.ts`  中执行。 ``` // 实现 Model 装饰器功能 import { listModule } from '@midwayjs/decorator'; const MODEL_KEY = 'decorator:model'; // 可以获取到所有装饰了 @Model 装饰器的 class const modules = listModule(MODEL_KEY); for (let mod of modules) { // 实现自定义能力 // 从 mod 上拿元数据,做不同的处理 // 提前初始化等 app.applicationContext.getAsync(getProviderId(mod)); } ``` 最后,我们要使用这个装饰器。 ``` import { Model } from '../decorator/model'; // Provide 的作用是暴露出一个 IoC id,能被 IoC 扫描到 @Provide() // Model 的作用是我们自己的逻辑能被执行(保存的元数据) @Model() export class UserModel {} ``` ## 清理信息[​](#清理信息 "清理信息的直接链接") 由于这些装饰器保存的元数据是全局唯一的,方法都为静态方法,所以在单测或者多 IoC 容器的场景下,需要对其进行清理。 ``` import { clearAllModule } from '@midwayjs/decorator'; // 执行即可 clearAllModule(); ``` ## 方法装饰器获取上下文[​](#方法装饰器获取上下文 "方法装饰器获取上下文的直接链接") 在请求链路上,如果自定义了装饰器要获取上下文往往比较困难,如果代码没有显示的注入上下文,装饰器中获取会非常困难。 在 Midway 的依赖注入的请求作用域中,我们将上下文绑定到了每个实例上,从实例的特定属性 `REQUEST_OBJ_CTX_KEY`  上即可获取当前的上下文,从而进一步对请求做操作。 ``` import { REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; export function MyCustomDecorator(): MethodDecorator { return (target: object, propertyKey: string, descriptor: PropertyDescriptor) => { const method = descriptor.value; descriptor.value = function (...args) { // 指向当前上层框架的上下文对象,上层框架的上下文对象请参考各上层框架文档。 console.log(this[REQUEST_OBJ_CTX_KEY]); return method.apply(this, [...args]); }; return descriptor; }; } ``` --- # 现有装饰器索引 | | 场景 | 作用 | | ---------------------------- | ------------ | ----------------------------------------- | | **@midwayjs/decorator 提供** | | | | @Provide | 基础依赖注入 | 暴露一个 class,让 IoC 容器能够获取元数据 | | @Inject | | 注入一个 IoC 容器中的对象 | | @Scope | 实例管理 | 指定作用域 | | @Init | | 标注对象初始化时自动执行的方法 | | @Destroy | | 标注对象销毁时执行的方法 | | @Async | | 【已废弃】表明为异步函数 | | @Autowire | | 【已废弃】标识类为自动注入属性 | | @Autoload | | 让类可以自加载执行 | | @Configuration | 通用功能扩展 | 标识一个容器入口配置类 | | @Aspect | | 标识拦截器 | | @Validate | | 标识方法,需要被验证 | | @Rule | | 标识 DTO 的校验规则 | | @App | | 注入当前应用实例 | | @Config | | 获取配置 | | @Logger | | 获取日志实例 | | @Controller | Web 场景 | 标识为一个 Web 控制器 | | @Get | | 注册为一个 GET 类型的路由 | | @Post | | 注册为一个 POST 类型的路由 | | @Del | | 注册为一个 DELETE 类型的路由 | | @Put | | 注册为一个 PUT 类型的路由 | | @Patch | | 注册为一个 PATCH 类型的路由 | | @Options | | 注册为一个 OPTIONS 类型的路由 | | @Head | | 注册为一个 HEAD 类型的路由 | | @All | | 注册为一个全类型的路由 | | @Session | | 从参数获取 ctx.session | | @Body | | 从参数获取 ctx.body | | @Query | | 从参数获取 ctx.query | | @Param | | 从参数获取 ctx.param | | @Headers | | 从参数获取 ctx.headers | | @Priority | | 【废弃】路由加载优先级 | | @Redirect | | 修改响应跳转 | | @HttpCode | | 修改响应状态码 | | @SetHeader | | 修改响应头 | | @ContentType | | 修改响应头中的 Content-Type 字段 | | @Schedule | Egg | 标识为一个定时任务 | | @Plugin | | 获取 egg 插件 | | @Provider | 微服务场景 | 暴露微服务提供者(生产者) | | @Consumer | | 暴露微服务调用者(消费者) | | @GrpcMethod | | 标识暴露的 gRPC 方法 | | @Func | 函数场景 | 【逐步废弃】标识为一个函数入口 | | @Handler | | 【逐步废弃】配合标记函数 | | @Match | | 【已废弃】 | | @ServerlessTrigger | | 标识一个函数触发器 | | @Task | 任务模块 | 定义一个分布式任务 | | @TaskLocal | | 定义一个本地任务 | | @Queue | | 定义一个自触发的任务 | | | | | | **@midwayjs/orm 提供** | | | | @EntityModel | | 定义一个实体对象 | | @InjectEntityModel | | 注入一个实体对象 | | @EventSubscriberModel | | 定义事件订阅 | | | | | | **@midwayjs/swagger 提供** | | | | @CreateApiDoc | | 创建一个 API | | @CreateApiPropertyDoc | | 创建一个 API 属性 | | | | | --- # 启动和部署 Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 ## 本地开发[​](#本地开发 "本地开发的直接链接") 这里列举的主要是本地使用 `dev`  命令开发的方式,有两种。 ### 快速启动单个服务[​](#快速启动单个服务 "快速启动单个服务的直接链接") 在本地研发时,Midway 在 `package.json`  中提供了一个 `dev`  命令启动框架,比如: ``` { "script": { "dev": "midway-bin dev --ts" } } ``` 这是一个最精简的命令,他有如下特性: * 1、使用 `--ts`  指定 TypeScript(ts-node)环境启动 * 2、使用内置的(@midwayjs/mock 的 createApp)创建一个\*\*匹配当前框架 \*\*的服务,并返回 app 在命令行运行下面的命令即可执行。 ``` $ npm run dev ``` 所谓匹配当前框架,指的是根据内部的框架列表,和 pkg 的依赖匹配查找到最符合当前的框架并启动。 内部的框架列表如下: ``` const currentFramework = [ '@midwayjs/web', '@midwayjs/koa', '@midwayjs/express', '@midwayjs/serverless-app', '@midwayjs/grpc', '@midwayjs/rabbitmq', '@midwayjs/socketio', '@midwayjs/faas', ]; ``` 这样启动的服务用于本地快速开发测试,使用的是 **框架初始化的默认值**。 比如,你的 `package.json`  中依赖如下; ``` { "@midwayjs/grpc": "xxx", "@midwayjs/web": "xxx" } ``` 按照优先级顺序,默认的 `dev`  依旧会启动 `@midwayjs/web`  服务。 ### 指定入口启动服务[​](#指定入口启动服务 "指定入口启动服务的直接链接") 由于本地的 dev 命令普通情况下和 `bootstrap.js`  启动文件初始化参数不同,有些用户担心本地开发和线上开发不一致,或者希望一次启动多个框架(多种协议)。 这个时候我们可以直接传递一个入口文件给 `dev`  命令,直接使用入口文件启动服务。 ``` { "script": { "dev": "midway-bin dev --ts --entryFile=bootstrap.js" } } ``` 信息 这种情况下,会忽略其余的参数,比如 --port。 ## 部署到普通服务器[​](#部署到普通服务器 "部署到普通服务器的直接链接") ### 部署后和本地开发的区别[​](#部署后和本地开发的区别 "部署后和本地开发的区别的直接链接") 在部署后,有些地方和本地开发有所区别。 **1、node 环境的变化** 最大的不同是,服务器部署后,会直接使用 node 来启动项目,而不是 ts-node,这意味着不再读取 `*.ts` 文件。 **2、加载目录的变化** 服务器部署后,只会加载构建后的 `dist` 目录,而本地开发则是加载 `src` 目录。 | | **本地** | **服务器** | | ------- | ----------------------- | ------------------------ | | appDir | 项目根目录 | 项目根目录 | | baseDir | 项目根目录下的 src 目录 | 项目根目录下的 dist 目录 | | | | | **3、环境的变化** 服务器环境,一般使用 `NODE_ENV=production` ,很多库都会在这个环境下提供性能更好的方式,例如启用缓存,报错处理等。 **4、日志文件** 一般服务器环境,日志不再打印到项目的 logs 目录下,而是其他不会受到项目更新影响的目录,比如 `home/admin/logs` 等等,这样固定的目录,也方便其他工具采集日志。 ### 部署的流程[​](#部署的流程 "部署的流程的直接链接") 整个部署分为几个部分,由于 Midway 是 TypeScript 编写,比传统 JavaScript 代码增加了一个构建的步骤,整个部署的过程如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1607238098956-563e8219-182d-4494-b9b4-311745be32f2.png#height=121\&id=WtwR3\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=242\&originWidth=2212\&originalType=binary\&ratio=1\&size=51328\&status=done\&style=none\&width=1106) 由于部署和平台、环境非常相关,下面我们都将以 Linux 来演示,其他平台可以视情况参考。 ### 编译代码和安装依赖[​](#编译代码和安装依赖 "编译代码和安装依赖的直接链接") 由于 Midway 项目是 TypeScript 编写,在部署前,我们先进行编译。在示例中,我们预先写好了构建脚本,执行 `npm run build`  即可,如果没有,在 `package.json`  中添加下面的 `build`  命令即可。 ``` // package.json { "scripts": { "build": "midway-bin build -c" } } ``` 信息 虽然不是必须,但是推荐大家先执行测试和 lint。 一般来说,部署构建的环境和本地开发的环境是两套,我们推荐在一个干净的环境中构建你的应用。 下面的代码,是一个示例脚本,你可以保存为 `build.sh`  执行。 ``` ## 服务器构建(已经下载好代码) $ npm install # 安装开发期依赖 $ npm run build # 构建项目 $ npm prune --production # 移除开发依赖 ## 本地构建(已经安装好 dev 依赖) $ npm run build $ npm prune --production # 移除开发依赖 ``` 信息 一般安装依赖会指定 `NODE_ENV=production` 或 `npm install --production` ,在构建正式包的时候只安装 dependencies 的依赖。因为 devDependencies 中的模块过大而且在生产环境不会使用,安装后也可能遇到未知问题。 执行完构建后,会出现 Midway 构建产物 `dist`  目录。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── node_modules # Node.js 依赖包目录 ├── test ├── package.json └── tsconfig.json ``` ### 打包压缩[​](#打包压缩 "打包压缩的直接链接") 构建完成后,你可以简单的打包压缩,上传到待发布的环境。 ### 上传和解压[​](#上传和解压 "上传和解压的直接链接") 有很多种方式可以上传到服务器,比如常见的 `ssh/FTP/git`  等。也可以使用 [OSS](https://www.aliyun.com/product/oss) 等在线服务进行中转。 ### 启动方式一:使用纯 Node.js 或者 pm2 等工具启动[​](#启动方式一使用纯-nodejs-或者-pm2-等工具启动 "启动方式一:使用纯 Node.js 或者 pm2 等工具启动的直接链接") Midway 构建出来的项目是单进程的,不管是采用 `fork`  模式还是 `cluster`  模式,单进程的代码总是很容易的兼容到不同的体系中,因此非常容易被社区现有的 pm2/forever 等工具所加载, 我们这里以 pm2 来演示如何部署。 项目一般都需要一个入口文件,比如,我们在根目录创建一个 `bootstrap.js` 作为我们的部署文件。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── test ├── bootstrap.js # 部署启动文件 ├── package.json └── tsconfig.json ``` Midway 提供了一个简单方式以满足不同场景的启动方式,只需要安装我们提供的 `@midwayjs/bootstrap` 模块。 ``` $ npm install @midwayjs/bootstrap --save ``` 然后在入口文件中写入代码,注意,这里的代码使用的是 `JavaScript` 。 ``` // 获取框架 const WebFramework = require('@midwayjs/web').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载框架并执行 Bootstrap.load(web).run(); ``` 我们提供的每个上层框架都将会导出一个 `Framework`  类,而 `Bootstrap`  的作用则是加载这些框架,传入启动参数,运行他们。 信息 启动参数,你可以在不同的框架处查询到。 这个时候,你已经可以直接使用 `NODE_ENV=production node bootstrap.js`  来启动代码了,也可以使用 pm2 来执行启动。 pm2 启动可以参考 [pm2 使用文档](/docs/2.0.0/pm2.md)。 如果你希望把 `bootstrap.js`  文件放到不同的目录,比如 `bin/bootstrap.js` ,你可以修改 Bootstrap 的参数。 ``` // bin/bootstrap.js const { join } = require('path'); // 获取框架 const WebFramework = require('@midwayjs/web').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载框架并执行 Bootstrap.configure({ appDir: join(__dirname, '../'), }) .load(web) .run(); ``` ### 启动方式二:EggJS 特有的启动形式[​](#启动方式二eggjs-特有的启动形式 "启动方式二:EggJS 特有的启动形式的直接链接") 由于 EggJS 提供了默认的多进程部署工具 `egg-scripts` ,Midway 也继续支持这种方式,如果上层是 EggJS,推荐这种部署方式。 首先在依赖中,确保安装 `egg-scripts`  包和 `midway`  包。 ``` $ npm i egg-scripts --save ``` 添加 `npm scripts` 到 `package.json`: 在上面的代码构建之后,使用我们的 `start`  和 `stop`  命令即可完成启动和停止。 ``` "scripts": { "start": "egg-scripts start --daemon --title=********* --framework=@midwayjs/web", "stop": "egg-scripts stop --title=*********", } ``` 信息 `*********`  的地方是你的项目名。 > 注意:`egg-scripts` 对 Windows 系统的支持有限,参见 [#22](https://github.com/eggjs/egg-scripts/pull/22)。 #### **启动参数** ``` $ egg-scripts start --port=7001 --daemon --title=egg-server-showcase ``` 如上示例,支持以下参数: * `--port=7001` 端口号,默认会读取环境变量 process.env.PORT,如未传递将使用框架内置端口 7001。 * `--daemon` 是否允许在后台模式,无需 nohup。若使用 Docker 建议直接前台运行。 * `--env=prod` 框架运行环境,默认会读取环境变量 process.env.EGG\_SERVER\_ENV, 如未传递将使用框架内置环境 prod。 * `--workers=2` 框架 worker 线程数,默认会创建和 CPU 核数相当的 app worker 数,可以充分的利用 CPU 资源。 * `--title=egg-server-showcase` 用于方便 ps 进程时 grep 用,默认为 `egg-server-${appname}`。 * `--framework=yadan` 如果应用使用了[自定义框架](https://eggjs.org/zh-cn/advanced/framework.html),可以配置 package.json 的 egg.framework 或指定该参数。 * `--ignore-stderr` 忽略启动期的报错。 * `--https.key` 指定 HTTPS 所需密钥文件的完整路径。 * `--https.cert` 指定 HTTPS 所需证书文件的完整路径。 * 所有 [egg-cluster](https://github.com/eggjs/egg-cluster) 的 Options 都支持透传,如 --port 等。 更多参数可查看 [egg-scripts](https://github.com/eggjs/egg-scripts) 和 [egg-cluster](https://github.com/eggjs/egg-cluster) 文档。 信息 使用 egg-scripts 部署的日志会存放在 \*\*用户目录 **下**,\*\*比如 `/home/xxxx/logs` 。 ## 部署为 Serverless 应用[​](#部署为-serverless-应用 "部署为 Serverless 应用的直接链接") Midway 可以将现有的 Web 项目部署为 Serverless 应用,这里以部署到阿里云函数计算作为示例。 ### 部署到 Serverless 环境[​](#部署到-serverless-环境 "部署到 Serverless 环境的直接链接") 1、添加 `f.yml`  文件到你的项目根目录。 ``` ➜ my_midway_app tree . ├── src ├── dist ├── f.yml # Midway Serverless 部署配置文件 ├── package.json └── tsconfig.json ``` ``` service: my-midway-app ## 应用发布到云平台的名字,一般指应用名 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: egg ## 部署的应用类型 ``` 应用类型选项如下: | @midwayjs/web 项目 | egg | | | ---------------------- | ------- | - | | @midwayjs/experss 项目 | express | | | @midwayjs/koa 项目 | koa | | 2、添加发布时的构建钩子 在 `package.json`  加入下面的这段,用于在发布时自动执行 `npm run build` 。 ``` "midway-integration": { "lifecycle": { "before:package:cleanup": "npm run build" } }, "scripts": { "deploy": "midway-bin deploy" }, "egg":{ "framework": "@midwayjs/web" } ``` 信息 如果使用了自己的 egg 上层框架,这里的 egg.framework 可以变为自己的包名。 3、执行 `npm run deploy`  即可,发布后,阿里云会输出一个临时可用的域名,打开浏览器访问即可。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600835297676-1753de7a-fb0d-46ca-98f0-944eba5b2f2b.png#height=193\&id=s5j4s\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=193\&originWidth=1219\&originalType=binary\&ratio=1\&size=35152\&status=done\&style=none\&width=1219) 如需更详细的发布文档,请查阅 [**Serverless 发布 FAQ**](https://www.yuque.com/midwayjs/faas/deploy_aliyun_faq)。 ### 部署到 Serverless 平台的限制[​](#部署到-serverless-平台的限制 "部署到 Serverless 平台的限制的直接链接") * 1、不支持 egg-socketio 等网关**不支持的协议** * 2、不支持 \*\*文件上传 \*\*等网关无法支持的能力 * 3、不支持 **定时任务**(可以使用组合 Timer 触发器的方式) * 3、还有一些,请参考 [**应用迁移 faq**](https://www.yuque.com/midwayjs/faas/migrate_faq) 如需发布到腾讯云环境,请查看 [**发布到腾讯云**](/docs/2.0.0/deploy_to_tencent)。 另外这里还有一些 [**常见问题**](/docs/2.0.0/deploy_aliyun_faq),请查阅。 ## 使用 Docker 部署[​](#使用-docker-部署 "使用 Docker 部署的直接链接") ### 编写 Dockerfile,构建镜像[​](#编写-dockerfile构建镜像 "编写 Dockerfile,构建镜像的直接链接") 步骤一:在当前目录下新增 Dockerfile: ``` FROM node:12 WORKDIR /app ENV TZ="Asia/Shanghai" COPY . . # 如果各公司有自己的私有源,可以替换registry地址 RUN npm install --registry=https://registry.npm.taobao.org RUN npm run build # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "online"] ``` 步骤二: 新增 `.dockerignore`  文件(类似 git 的 ignore 文件),可以把 `.gitignore`  的内容拷贝到 `.dockerignore`  里面 步骤三:package.json 文件的 scripts 里面新增 online,对比 start,把 `--daemon`  去掉。如下图 ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608881958246-5b5da75e-2f60-4582-81b8-1b0645c91bd7.png#height=39\&id=SeRTA\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=55\&originWidth=904\&originalType=binary\&ratio=1\&size=92433\&status=done\&style=none\&width=634) 这里使用的是 egg-scripts 部署,当使用 pm2 部署时,请将命令修改为 `pm2-runtime start` ,pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 步骤四:构建 docker 镜像 ``` $ docker build -t helloworld . ``` 步骤五:运行 docker 镜像 ``` $ docker run -itd -P helloworld ``` 运行效果如下: ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882492099-49160b6a-601c-4f08-ba65-b95a1335aedf.png#height=33\&id=BtUCB\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=45\&originWidth=1024\&originalType=binary\&ratio=1\&size=33790\&status=done\&style=none\&width=746) 然后大写的 `-P`  由于给我们默认分配了一个端口,所以我们访问可以访问 `32791`  端口(这个 `-P`  是随机分配,我们也可以使用 `-p 7001:7001`  指定特定端口) ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882559686-031bcf0d-2185-42cd-a838-80f008777395.png#height=94\&id=dfag9\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=188\&originWidth=578\&originalType=binary\&ratio=1\&size=24488\&status=done\&style=none\&width=289) 关于别的推送到 dockerhub 或者 docker 的 registry,可以大家搜索对应的方法。 **优化** 我们看到前面我们打出来的镜像有 1 个多 G,可优化的地方: 1、我们可以采用更精简的 docker image 的基础镜像:例如 node:12-alpine, 2、其中的源码最终也打在了镜像中,其实这块我们可以不需要。 然后我们同时结合 docker 的 multistage 功能,这个功能请注意要在 Docker 17.05 版本之后才能使用。 ``` FROM node:12 AS build WORKDIR /app COPY . . RUN npm install RUN npm run build FROM node:12-alpine WORKDIR /app COPY --from=build /app/dist ./dist COPY --from=build /app/bootstrap.js ./ COPY --from=build /app/package.json ./ RUN apk add --no-cache tzdata ENV TZ="Asia/Shanghai" RUN npm install --production # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "start"] ``` 然后我们看到结果只有 207MB。相比原有的 1.26G 省了很多的空间。 ### 结合 Docker-Compose 运行[​](#结合-docker-compose-运行 "结合 Docker-Compose 运行的直接链接") 在 docker 部署的基础上,还可以结合 docker-compose 部署一些跟自己服务相关的服务。 **步骤一** 按照 Docker 方式部署的方式新增 dockerfile **步骤二** 新增 docker-compose.yml 文件,内容如下:(此处我们模拟我们的 midway 项目需要使用 redis) ``` version: '3' services: web: build: . ports: - '7001:7001' links: - redis redis: image: redis ``` **步骤三:构建** 使用命令: ``` $ docker-compose build ``` **步骤四:运行** ``` $ docker-compose up -d ``` ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608884158660-02bd2d3c-08b4-4ecc-a4dd-a18d4b9d2c12.png#height=44\&id=jWw4i\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=62\&originWidth=1054\&originalType=binary\&ratio=1\&size=47727\&status=done\&style=none\&width=746) 那么 redis 比如怎么用,因为 docker-compose 里面加了一个 redis,并且 link 了,所以我们代码里面如下写: 在 service 目录下添加 `redis.service.ts`  文件,代码如下: ``` import { Provide, Scope, ScopeEnum, Init } from '@midwayjs/decorator'; import * as Redis from 'ioredis'; @Provide() @Scope(ScopeEnum.Singleton) export class RedisService { redis: Redis.Redis = null; @Init() async init() { this.redis = new Redis({ host: 'redis', }); } async setValue(key, value) { return await this.redis.set(key, value); } async getValue(key) { return await this.redis.get(key); } } ``` 然后在 `controller/home.ts`  里面添加一个接口如下: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; import { RedisService } from '../service/redis.service'; @Provide() @Controller('/') export class HomeController { @Inject() redisService: RedisService; @Get('/') async home() { let res = await this.redisService.getValue('foo'); return 'Hello Midwayjs!' + res; } @Get('/update') async update() { let res = await this.redisService.setValue('foo', 'hello world'); return res; } } ``` 这个代码比较好理解,相当于访问 `127.0.0.1:7001/update`  接口,会去调用 redisService 新增一个 key,对应的 value 为 hello world 然后访问 `127.0.0.1:7001`  ,会调用 redisService 获取 key 为 foo 的值,并返回给页面。 如下: ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608886309353-2a65279f-8164-45c0-ab41-a759d31f1492.png#height=92\&id=APR77\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=184\&originWidth=686\&originalType=binary\&ratio=1\&size=26724\&status=done\&style=none\&width=343) 关于更多关于 docker-compose 的详情,可以查看网上关于 docker-compose 的使用方法。 --- # EggJS Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 ## 依赖包[​](#依赖包 "依赖包的直接链接") 针对 EggJS,Midway 提供了 `@midwayjs/web`  包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。 针对 EggJS 场景,这些包列举如下。 ``` "dependencies": { "@midwayjs/web": "^2.3.11", "@midwayjs/decorator": "^2.3.11", "egg": "^2.0.0", "egg-scripts": "^2.10.0", "midway": "^2.3.11" }, "devDependencies": { "@midwayjs/egg-ts-helper": "^1.0.1", }, ``` | @midwayjs/web | **必须**,Midway EggJS 适配层 | | ----------------------- | -------------------------------------------------- | | @midwayjs/decorator | **必须**,Midway 系列通用的装饰器包 | | midway | **可选**,Midway 启动适配包,提供了 midway v1 兼容 | | egg | **必须**,EggJS 依赖包,提供定义等其他能力 | | egg-scripts | **可选**,EggJS 启动脚本 | | @midwayjs/egg-ts-helper | **可选**,EggJS 定义生成工具 | ## 和默认 EggJS 的不同之处[​](#和默认-eggjs-的不同之处 "和默认 EggJS 的不同之处的直接链接") * 1、默认关闭 static 插件,需要时请自行开启 * 2、baseDir 默认调整为 `src`  目录,服务器上为 `dist`  目录 整个架构如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1614842824740-fc0c1432-3ace-4f77-b51f-15212984b168.png#height=828\&id=Lv3hN\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=828\&originWidth=1716\&originalType=binary\&ratio=1\&size=117877\&status=done\&style=none\&width=1716) ## 目录结构[​](#目录结构 "目录结构的直接链接") 除了 Midway 提供的目录结构外,EggJS 还有一些特殊的目录结构(不可变),整个结构如下。 ``` ➜ my_midway_app tree . ├── src | ├── app.ts ## EggJS 扩展 Worker 生命周期文件(可选) | ├── agent.ts ## EggJS 扩展 Agent 生命周期文件(可选) | ├── app ## EggJS 固定的根目录(可选) | │ ├── public ## EggJS 静态托管插件的默认目录(可配) | │ | └── reset.css | │ ├── view (可选) ## EggJS 模板渲染的默认目录(可配) | │ | └── home.tpl | │ └── extend (可选) ## EggJS 扩展目录(可配) | │ ├── helper.ts (可选) | │ ├── request.ts (可选) | │ ├── response.ts (可选) | │ ├── context.ts (可选) | │ ├── application.ts (可选) | │ └── agent.ts (可选) | │ | ├── config | | ├── plugin.ts | | ├── config.default.ts | │ ├── config.prod.ts | | ├── config.test.ts (可选) | | ├── config.local.ts (可选) | | └── config.unittest.ts (可选) │ ├── controller ## Midway 控制器目录(推荐) │ ├── service ## Midway 服务目录(推荐) │ └── schedule ## Midway 定时器目录(推荐) │ ├── typings ## EggJS 定义生成目录 ├── test ├── package.json └── tsconfig.json ``` 以上是 EggJS 的目录结构全貌,其中包含了很多 EggJS 特有的目录,有一些在 Midway 体系中已经有相应的能力替代,可以直接替换。整个结构,基本上等价于将 EggJS 的目录结构移动到了 `src`  目录下。 由于 EggJS 是基于约定的框架,整个工程的目录结构是固定的,这里列举一些常用的约定目录。 | `src/app/public/**`  | 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)。 | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `src/config/config.{env}.ts` | 用于编写配置文件,具体参见[配置](https://eggjs.org/zh-cn/basics/config.html)。 | | `src/config/plugin.js` | 用于配置需要加载的插件,具体参见[插件](https://eggjs.org/zh-cn/basics/plugin.html)。 | | `test/**` | 具体参见[单元测试](https://eggjs.org/zh-cn/core/unittest.html)。 | | `src/app.js` 和 `src/agent.js` | 用于自定义启动时的初始化工作,可选,具体参见[启动自定义](https://eggjs.org/zh-cn/basics/app-start.html)。关于`agent.js`的作用参见[Agent 机制](https://eggjs.org/zh-cn/core/cluster-and-ipc.html#agent-%E6%9C%BA%E5%88%B6)。 | ## 配置定义[​](#配置定义 "配置定义的直接链接") Midway 在脚手架中提供了标准的 EggJS 的 TS 配置写法,其中包括了完整的定义和属性提示,结构如下。 ``` // src/config/config.default.ts import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; export type DefaultConfig = PowerPartial; export default (appInfo: EggAppInfo) => { const config = {} as DefaultConfig; // use for cookie sign key, should change to your own and keep security config.keys = appInfo.name + '_1600001669991_8079'; // add your middleware here config.middleware = []; config.security = { csrf: { enable: false, }, }; config.sequelize = {}; return config; }; ``` 通过这样返回方法的形式,在运行期会被自动执行,合并进完整的配置对象。 这个函数的参数为 `EggAppInfo` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | 信息 注意,这里的 `baseDir` 和 `appDir` 和 EggJS 应用有所区别。 ## 插件[​](#插件 "插件的直接链接") 插件是 EggJS 的特色之一,Midway 也支持 EggJS 的插件体系。 ### 开启插件[​](#开启插件 "开启插件的直接链接") 插件一般通过 npm 模块的方式进行复用。 ``` $ npm i egg-mysql --save ``` 然后需要在应用或框架的 `src/config/plugin.js` 中声明开启。 如果有 `export default` ,请写在其中。 ``` import { EggPlugin } from 'egg'; export default { static: false, // default is true mysql: { enable: true, package: 'egg-mysql', }, } as EggPlugin; ``` 如果没有 `export default` ,可以直接导出。 ``` // src/config/plugin.ts // 使用 mysql 插件 export const mysql = { enable: true, package: 'egg-mysql', }; ``` ### 使用插件[​](#使用插件 "使用插件的直接链接") 在开启插件之后,我们就可以在业务代码中使用插件提供的功能了。一般来说,插件会将对象挂载到 EggJS 的 `app`  和 `ctx`  之上,然后直接使用。 ``` app.mysql.query(sql, values); // egg 提供的方法 ``` 在 Midway 中可以通过 `@App`  获取 `app`  对象,以及在请求作用域中通过 `@Inject() ctx`  获取 `ctx`  对象,所以我们可以通过注入来获取插件对象。 ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; import { Application, Context } from 'egg'; @Provide() export class HomeController { @App() app: Application; @Inject() ctx: Context; @Get('/') async home() { this.app.mysql.query(sql, values); // 调用 app 上的方法(如果有的话) this.ctx.mysql.query(sql, values); // 调用挂载在 ctx 上的方法(如果有的话) } } ``` 此外,还可以通过 `@Plugin`  装饰器来直接注入 `app`  挂载的插件,默认情况下,如果不传参数,将以属性名作为 key。 ``` import { Provide, Get, Plugin } from '@midwayjs/decorator'; @Provide() export class HomeController { @Plugin() mysql: any; @Get('/') async home() { this.mysql.query(sql, values); } } ``` 信息 `@Plugin() mysql`  等价于 `app.mysql` 。 `@Plugin`  的作用就是从 app 对象上拿对应属性名的插件,所以 `@Plugin() xxx`  就等于 `app['xxx']` 。 ## Web 中间件[​](#web-中间件 "Web 中间件的直接链接") 一般情况下,我们会在 `src/middleware` 文件夹中编写 Web 中间件,比如创建一个 `src/middleware/report.ts` 。我们在这个 Web 中间件中打印了控制器(Controller)执行的时间。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ ├── middleware ## 中间件目录 │ │ └── report.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 简单来说, `await next()` 则代表了下一个要执行的逻辑,这里一般代表控制器执行,在执行的前后,我们可以进行一些打印和赋值操作,这也是洋葱圈模型最大的优势。 ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next: IMidwayWebNext) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime); }; } } ``` 警告 注意,如果要继续使用 EggJS 传统的函数式写法,必须将文件放在 `src/app/middleware`  下。 ### 配置全局中间件[​](#配置全局中间件 "配置全局中间件的直接链接") 在 EggJS 中,除了上面提到的全局中间件使用方法外,其提供了一个更为配置性的加载全局中间件的用法。在 `src/config/config.default.ts` 中配置 `middleware` 属性即可定义全局中间件,同样的,指定全局中间件的 key 即可。 ``` // src/config/config.default.ts export default (appInfo: EggAppInfo) => { const config = {} as DefaultConfig; // ... config.middleware = ['reportMiddleware']; return config; }; ``` ### 配置路由中间件[​](#配置路由中间件 "配置路由中间件的直接链接") 按照 Midway 的通用的配置在路由装饰器即可。 ``` import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/', { middleware: ['reportMiddleware'] }) // controller 级别的中间件 export class HomeController { @Get('/', { middleware: ['reportMiddleware'] }) // 路由级别的中间件 async home() {} } ``` ### 关于 Match 和 Ignore[​](#关于-match-和-ignore "关于 Match 和 Ignore的直接链接") EggJS 的中间件支持在 config 中配置 `match`  和 `ignore` ,在 Midway 中,这一特性只会对 EggJS 自己的中间件生效,即只对 `src/app/middleware`  里的函数写法生效。 ## 模板渲染[​](#模板渲染 "模板渲染的直接链接") EggJS 默认的 `egg-view`  提供默认渲染的能力,他默认的模板目录为 `app/view` ,在 Midway 中目前没有对此做调整,所以相应的,view 目录需要放在 `src/app/view`  下。 如果目录结构不是很喜欢,可以在配置中修改。 ``` // src/config/config.default.ts module.exports = (appInfo) => { return { view: { root: path.join(appInfo.baseDir, 'view'), }, }; }; ``` ## 文件上传[​](#文件上传 "文件上传的直接链接") Egg.js 使用 [egg-multipart](https://github.com/eggjs/egg-multipart) 插件进行文件上传处理。 ### File 模式[​](#file-模式 "File 模式的直接链接") 在 config 文件中启用 file 模式: ``` // src/config/config.default.ts exports.multipart = { mode: 'file', }; ``` 1、上传 / 接收文件 你的前端静态页面代码类似如下: ```

title: file: ``` ``` // controller/upload.ts const fs = require('mz/fs'); import { basename } from 'path'; import { Context } from 'egg'; @Controller('/api') export class ApiController { @Inject() ctx: Context; @Post('/upload') async uplaodFile() { const file = this.ctx.request.files[0]; const name = 'egg-multipart-test/' + basename(file.filename); let result; try { // 处理文件,比如上传到云端 result = await this.ctx.oss.put(name, file.filepath); } finally { // 需要删除临时文件 await fs.unlink(file.filepath); } return { url: result.url, // 获取所有的字段值 requestBody: ctx.request.body, }; } } ``` 2、上传 / 接收多个文件: 对于多个文件,我们借助 `ctx.request.files` 属性进行遍历,然后分别进行处理: 你的前端静态页面代码应该看上去如下样子: ```
title: file1: file2:
``` 对应的后端代码: ``` // controller/upload.ts const fs = require('mz/fs'); import { basename } from 'path'; import { Context } from 'egg'; @Controller('/api') export class ApiController { @Inject() ctx: Context; @Post('/upload') async uplaodFile() { console.log('got %d files', this.ctx.request.files.length); for (const file of this.ctx.request.files) { console.log('field: ' + file.fieldname); console.log('filename: ' + file.filename); console.log('encoding: ' + file.encoding); console.log('mime: ' + file.mime); console.log('tmp filepath: ' + file.filepath); let result; try { // 处理文件,比如上传到云端 result = await this.ctx.oss.put('egg-multipart-test/' + file.filename, file.filepath); } finally { // 需要删除临时文件 await fs.unlink(file.filepath); } console.log(result); } return { url: result.url, // 获取所有的字段值 requestBody: ctx.request.body, }; } } ``` 除了简单的文件上传,还有更加复杂的流式上传,可以参考[ egg 文件上传](https://eggjs.org/zh-cn/basics/controller.html#%E8%8E%B7%E5%8F%96%E4%B8%8A%E4%BC%A0%E7%9A%84%E6%96%87%E4%BB%B6)。 ## 静态文件[​](#静态文件 "静态文件的直接链接") 请使用 egg 自带的静态方案:。 ## 定时任务[​](#定时任务 "定时任务的直接链接") midway 的定时任务是基于 [egg 定时任务](https://eggjs.org/zh-cn/basics/schedule.html) 提供了更多 TypeScript 以及装饰器方面的支持。 ### 编写代码[​](#编写代码 "编写代码的直接链接") 定时任务一般存放在 `src/schedule`  目录下,可以配置定时任务的属性和要执行的方法。例如: ``` // src/schedule/hello.ts import { Provide, Inject, Schedule, CommonSchedule } from '@midwayjs/decorator'; import { Context } from 'egg'; @Provide() @Schedule({ interval: 2333, // 2.333s 间隔 type: 'worker', // 指定某一个 worker 执行 }) export class HelloCron implements CommonSchedule { @Inject() ctx: Context; // 定时执行的具体任务 async exec() { this.ctx.logger.info(process.pid, 'hello'); } } ``` 信息 推荐使用 `CommonSchedule` 接口来规范你的计划任务类。 警告 请不要放到 src/app/schedule 中,会和 egg 本身的加载冲突。 ### 手动调用[​](#手动调用 "手动调用的直接链接") EggJS 提供了 `app.runSchedule`  方法来测试计划任务,这个方法在 Midway 下做了特殊处理,参数的格式变为 `id#className` ,id 为依赖注入的标识符(类名的驼峰)。 示例如下: ``` app.runSchedule('helloCron#HelloCron'); ``` 当然,也可以使用 Midway 自身的动态获取实例的方式。 ``` const helloCron = await ctx.requestContext.getAsync('helloCron'); await helloCron.exec(); ``` ## 日志[​](#日志 "日志的直接链接") 默认情况下,在 Midway 中使用 @mdwayjs/logger,文档请参考[日志章节](/docs/2.0.0/logger.md)。在使用 egg-logger 的情况下,可以参考这里或者直接[访问 egg 文档](https://eggjs.org/zh-cn/core/logger.html)。 ### 自定义日志[​](#自定义日志 "自定义日志的直接链接") 比如自定义一个日志 `myLogger`,这个时候,日志的 key 则为 `myLogger` 。 ``` module.exports = (appInfo) => { return { customLogger: { myLogger: { file: path.join(appInfo.root, 'logs/xx.log'), }, }, }; }; ``` 这个时候可以用 `@Logger` 装饰器来获取日志实例。 ``` import { Provide, Logger } from '@midwayjs/decorator'; @Provide() export class BaseService { @Logger('myLogger') logger; } ``` ### 日志等级[​](#日志等级 "日志等级的直接链接") 默认情况下,EggJS 的日志等级均为 `WARN` ,我们可以修改 EggJS 默认的日志等级覆盖这一行为。 ``` // src/config/config.local.ts export const logger = { consoleLevel: 'INFO', coreLogger: { consoleLevel: 'INFO', }, }; ``` ### 默认日志名[​](#默认日志名 "默认日志名的直接链接") Midway 对 EggJS 默认的日志文件名做了修改。 * `midway-core.log`  框架输入日志 * `midway-web.log`  应用输出日志 * `midway-agent.log` agent 中输出的日志 * `common-error.log`  统一的错误输出日志 ### 服务器日志[​](#服务器日志 "服务器日志的直接链接") EggJS 默认开启了日志清理,日志文件**最多保存一个月**,要修改这一行为,可以进行配置。 ``` // config.default.ts exports.logrotator = { // for clean_log maxDays: 0, }; ``` ## 异常处理[​](#异常处理 "异常处理的直接链接") EggJS 框架通过  [onerror](https://github.com/eggjs/egg-onerror)  插件提供了统一的错误处理机制。对一个请求的所有处理方法(Middleware、Controller、Service)中抛出的任何异常都会被它捕获,并自动根据请求想要获取的类型返回不同类型的错误(基于  [Content Negotiation](https://tools.ietf.org/html/rfc7231#section-5.3.2))。 | 请求需求的格式 | 环境 | errorPageUrl 是否配置 | 返回内容 | | -------------- | ---------------- | --------------------- | ---------------------------------------------------- | | HTML & TEXT | local & unittest | - | onerror 自带的错误页面,展示详细的错误信息 | | HTML & TEXT | 其他 | 是 | 重定向到 errorPageUrl | | HTML & TEXT | 其他 | 否 | onerror 自带的没有错误信息的简单错误页(不推荐) | | JSON & JSONP | local & unittest | - | JSON 对象或对应的 JSONP 格式响应,带详细的错误信息 | | JSON & JSONP | 其他 | - | JSON 对象或对应的 JSONP 格式响应,不带详细的错误信息 | ### errorPageUrl[​](#errorpageurl "errorPageUrl的直接链接") onerror 插件的配置中支持 errorPageUrl 属性,当配置了 errorPageUrl 时,一旦用户请求线上应用的 HTML 页面异常,就会重定向到这个地址。 在 `src/config/config.default.ts` 中 ``` // src/config/config.default.ts module.exports = { onerror: { // 线上页面发生异常时,重定向到这个页面上 errorPageUrl: '/50x.html', }, }; ``` ### 自定义统一异常处理[​](#自定义统一异常处理 "自定义统一异常处理的直接链接") 尽管框架提供了默认的统一异常处理机制,但是应用开发中经常需要对异常时的响应做自定义,特别是在做一些接口开发的时候。框架自带的 onerror 插件支持自定义配置错误处理方法,可以覆盖默认的错误处理方法。 ``` // src/config/config.default.ts export const onerror = { all(err, ctx) { // 在此处定义针对所有响应类型的错误处理方法 // 注意,定义了 config.all 之后,其他错误处理方法不会再生效 ctx.body = 'error'; ctx.status = 500; }, html(err, ctx) { // html hander ctx.body = '

error

'; ctx.status = 500; }, json(err, ctx) { // json hander ctx.body = { message: 'error' }; ctx.status = 500; }, jsonp(err, ctx) { // 一般来说,不需要特殊针对 jsonp 进行错误定义,jsonp 的错误处理会自动调用 json 错误处理,并包装成 jsonp 的响应格式 }, }; ``` ### 404[​](#404 "404的直接链接") 框架并不会将服务端返回的 404 状态当做异常来处理,但是框架提供了当响应为 404 且没有返回 body 时的默认响应。 当请求被框架判定为需要 JSON 格式的响应时,会返回一段 JSON: ``` { "message": "Not Found" } ``` 当请求被框架判定为需要 HTML 格式的响应时,会返回一段 HTML: ```

404 Not Found

``` 框架支持通过配置,将默认的 HTML 请求的 404 响应重定向到指定的页面。 ``` // src/config/config.default.ts export const notfound = { pageUrl: '/404.html', }; ``` ### 自定义 404 响应[​](#自定义-404-响应 "自定义 404 响应的直接链接") 在一些场景下,我们需要自定义服务器 404 时的响应,和自定义异常处理一样,我们也只需要加入一个中间件即可对 404 做统一处理。 ``` // src/middleware/notfound_handler.ts import { Provide } from '@midwayjs/decorator'; @Provide('notfoundHandler') export class NotFoundHandlerMiddleware { resolve() { return async function notFoundHandler(ctx, next) { await next(); if (ctx.status === 404 && !ctx.body) { if (ctx.acceptJSON) { ctx.body = { error: 'Not Found' }; } else { ctx.body = '

Page Not Found

'; } } }; } } ``` 然后在配置中引入中间件。 ``` // src/config/config.default.ts export const middleware = ['notfoundHandler']; ``` ## 不存在定义的问题[​](#不存在定义的问题 "不存在定义的问题的直接链接") 一些 egg 插件未提供 ts 定义,导致使用会出现未声明方法的情况,比如 egg-mysql。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1623158462288-d55fc0ff-dcc3-4c58-b952-101a552efe12.png#clientId=u9825f56d-757f-4\&from=paste\&height=438\&id=uec9c4ff6\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=876\&originWidth=1478\&originalType=binary\&ratio=2\&size=581313\&status=done\&style=none\&taskId=ubcf947b0-1a9d-43b5-9b57-f678da05da9\&width=739) 可以使用 any 绕过。 ``` await(this.app as any).mysql.query(sql); ``` 或者可以自行增加扩展定义。 ## 扩展 Application/Context/Request/Response[​](#扩展-applicationcontextrequestresponse "扩展 Application/Context/Request/Response的直接链接") ### 增加扩展文件[​](#增加扩展文件 "增加扩展文件的直接链接") 虽然 MidwayJS 并不希望直接将属性挂载到 koa 的 Context,App 上(会造成管理和定义的不确定性),但是 EggJS 的这项功能依旧可用。 文件位置如下。 ``` ➜ my_midway_app tree . ├── src │ ├── app │ │ └── extend │ │ ├── application.ts │ │ ├── context.ts │ │ ├── request.ts │ │ └── response.ts │ ├── config │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` 内容和原来的 EggJS 相同。 ``` // src/app/extend/context.ts export default { get hello() { return 'hello world'; }, }; ``` ### 增加扩展定义[​](#增加扩展定义 "增加扩展定义的直接链接") 扩展了 EggJS 之后,你需要增加扩展的定义。请在 `src/interface.ts`  中扩展增加的 `ctx.hello`  属性。 ``` // src/interface.ts declare module 'egg' { interface Context { hello: string; } } ``` 信息 业务自定义扩展的定义请 **不要放在根目录** `typings`  下,避免被 ts-helper 工具覆盖掉。 除此之外,还可以扩展其他的定义,MidwayJS 的相关方法也是如此支持的。 ``` declare module 'egg' { interface EggAppInfo { // 扩展 eggInfo appDir: string; } interface Application { // 扩展 Application applicationContext: IMidwayContainer; getBaseDir(): string; getAppDir(): string; getEnv(): string; getFrameworkType(): MidwayFrameworkType; getProcessType(): MidwayProcessTypeEnum; getApplicationContext(): IMidwayContainer; getConfig(key?: string): any; generateController?(controllerMapping: string); generateMiddleware?(middlewareId: string): Promise>; } interface Context { // 扩展 Context requestContext: IMidwayContainer; } } ``` ## 框架启动参数[​](#框架启动参数 "框架启动参数的直接链接") `@midwayjs/web`  框架的启动参数如下: \| port | number | 必填,启动的端口 | | -------- | ------- | ---------------------------- | ------------ | ------- | --------------------- | | key | string | Buffer | Array\ | 可选,HTTPS 证书 key | | cert | string | Buffer | Array\ | 可选,HTTPS 证书 cert | | ca | string | Buffer | Array\ | 可选,HTTPS 证书 ca | | hostname | string | 监听的 hostname,默认 127.1 | | http2 | boolean | 可选,http2 支持,默认 false | 这些参数在使用 `bootstrap.js` 启动时生效。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 默认的 csrf 错误[​](#默认的-csrf-错误 "默认的 csrf 错误的直接链接") 在 post 请求,特别是第一次时用户会发现一个 csrf 报错。原因是 egg 在框架中默认内置了安全插件  [egg-security](https://github.com/eggjs/egg-security), 默认开启了 csrf 校验。 我们可以在配置中关闭它,但是更好的是去[**了解它**](https://eggjs.org/zh-cn/core/security.html#%E5%AE%89%E5%85%A8%E5%A8%81%E8%83%81-csrf-%E7%9A%84%E9%98%B2%E8%8C%83)之后再做选择。 ``` export const security = { csrf: false, }; ``` ## 其他[​](#其他 "其他的直接链接") ### 生成 ts 定义[​](#生成-ts-定义 "生成 ts 定义的直接链接") Midway 提供了 `@midwayjs/egg-ts-hepler`  工具包,用于快速生成 EggJS 开发时所依赖的定义。 ``` npm install @midwayjs/egg-ts-helper --save-dev ``` 在 `package.json`  中加入对应的 `ets`  命令即可,一般来说,我们会在 dev 命令前加入,以保证代码的正确性。 ``` "scripts": { "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", }, ``` 信息 在第一次编写代码前,需要执行一次此命令才能有 ts 定义生成。 EggJS 生成的定义在 `typings`  目录中。 ``` ➜ my_midway_app tree . ├── src ## midway 项目源码 ├── typings ## EggJS 定义生成目录 ├── test ├── package.json └── tsconfig.json ``` ### EggJS 中 Configuration 的特殊情况[​](#eggjs-中-configuration-的特殊情况 "EggJS 中 Configuration 的特殊情况的直接链接") 在 EggJS 下, `configuration.ts`  中的生命周期**只会在 worker 下加载执行**。如果在 Agent 有类似的需求,请直接使用 EggJS 自身的 `agent.ts`  处理。 --- # 多环境配置 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 本篇我们来介绍 Midway 如何加载不同环境的业务配置。 ## 全局容器配置和业务配置的区别[​](#全局容器配置和业务配置的区别 "全局容器配置和业务配置的区别的直接链接") `src/configuration.ts` 文件用于配置依赖注入容器的行为,是整个 Midway 最重要的文件。其中的 `@Configuration` 装饰器能控制整个 Midway 依赖注入容器的加载行为,例如组件加载,全局生命周期调整等能力。 依赖注入容器包含多个服务,`ConfigService` 是依赖注入容器的其中一个默认服务,用于加载业务配置。我们可以通过在 `@configuration` 装饰器中配置这个服务的行为,来加载不同环境 ,自定义的业务配置文件。 业务配置只跟业务本身相关,和框架不耦合,文件数量不定,内容也是自定义的。 ## 业务配置文件[​](#业务配置文件 "业务配置文件的直接链接") 框架提供了可扩展的配置功能,可以自动合并应用、框架、组件的配置,且可以根据环境维护不同的配置。 我们可以自定义目录,在其中放入多个环境的配置文件,如下列常见的目录结构,具体环境的概念请查看 [运行环境](/docs/2.0.0/environment.md)。 ``` ➜ my_midway_app tree . ├── src │ ├── config │ │ ├── config.default.ts │ │ ├── config.prod.ts │ │ ├── config.unittest.ts │ │ └── config.local.ts │ ├── interface.ts │ └── service ├── test ├── package.json └── tsconfig.json ``` `config.default.ts` 为默认的配置文件,所有环境都会加载这个配置文件,一般也会作为开发环境的默认配置文件。 配置不是必须项,请酌情添加自己需要的环境配置。 ## 业务配置加载[​](#业务配置加载 "业务配置加载的直接链接") 然后我们可以在 `src/configuration.ts`  中配置这个文件(目录),框架就知道加载它了。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [join(__dirname, './config/')], }) export class ContainerLifeCycle {} ``` ### 1、目录或者文件查找加载[​](#1目录或者文件查找加载 "1、目录或者文件查找加载的直接链接") 可以指定加载一个目录,目录里所有的 `config.*.ts` 都会被扫描加载。 信息 `importConfigs`   这里只是指定需要加载的文件,实际运行时会**自动选择当前的环境**来找对应的文件后缀。 配置文件的规则为: * 1、可以指定一个目录,推荐传统的 `src/config`  目录,也可以指定一个文件 * 2、文件指定无需 ts 后缀 * 3、配置文件 **必须显式指定添加** **示例:指定目录** ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [join(__dirname, './config/')], }) export class ContainerLifeCycle {} ``` **示例:指定特定文件** 手动指定一批文件时,这个时候如果文件不存在,则会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/config.default'), join(__dirname, './config/config.local'), join(__dirname, './config/custom.local'), // 可以使用自定义的命名,只要中间部分带环境就行 ], }) export class ContainerLifeCycle {} ``` 也可以使用项目外的配置,但是请使用绝对路径,以及 `*.js` 后缀。 比如目录结构如下(注意 `customConfig.default.js` 文件): ``` base-app ├── package.json ├── customConfig.default.js └── src ├── configuration.ts └── config └── config.default.ts ``` ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [join(__dirname, './config/'), join(__dirname, '../customConfig.default')], }) export class ContainerLifeCycle {} ``` ### 2、对象形式加载[​](#2对象形式加载 "2、对象形式加载的直接链接") 在特殊场景下,比如希望 bundle/package 等和目录结构无关的需求,可以使用标准的模块加载方式来加载配置。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ importConfigs: [ { default: DefaultConfig, local: LocalConfig, }, ], }) export class ContainerLifeCycle {} ``` `importConfigs` 中的数组中传递配置对象,每个对象的 key 为环境,值为环境对应的配置值,midway 在启动中会根据环境来加载对应的配置。 ## 配置合并规则[​](#配置合并规则 "配置合并规则的直接链接") 框架会加载 `**/config.defaut.ts`   的文件以及 `**/config.{环境}.ts`   文件。 比如,下面的代码在 `local` 环境会查找 `config.default.*` 和 `config.local.*` 文件,如果在其他环境,则只会查找 `config.default.*` 和 `config.{当前环境}.*` ,如果文件不存在,则不会加载,也不会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [join(__dirname, './config/')], }) export class ContainerLifeCycle {} ``` 为了向前兼容,我们对某些特殊环境的配置读取做了一些处理。这里环境的值指的是根据 `NODE_ENV`  和 `MIDWAY_SERVER_ENV`  的值综合得出的 [结果](/docs/2.0.0/environment.md#AxjGQ)。 | **环境的值** | **读取的配置文件** | | ------------ | --------------------------------------------- | | prod | \_.default.ts + \_.prod.ts | | production | \_.default.ts + \_.production.ts + \*.prod.ts | | unittest | \_.default.ts + \_.unittest.ts | | test | \_.default.ts + \_.test.ts + \*.unittest.ts | | | | 除了上述表格外,其余都是 `*.default.ts + *.{当前环境}.ts`  的值。 此外,配置的合并使用 [extend2](https://github.com/eggjs/extend2) 模块进行深度拷贝,[extend2](https://github.com/eggjs/extend2) fork 自 [extend](https://github.com/justmoon/node-extend),处理数组时会存在差异。 ``` const a = { arr: [1, 2], }; const b = { arr: [3], }; extend(true, a, b); // => { arr: [ 3 ] } ``` 根据上面的例子,框架直接覆盖数组而不是进行合并。 ## 配置格式[​](#配置格式 "配置格式的直接链接") ### 对象形式[​](#对象形式 "对象形式的直接链接") 配置文件格式为 object,比如: ``` // src/config/config.default.ts export const userService = { appname: 'test', }; export const customKey = { appname: 'abc', }; ``` ### 函数形式[​](#函数形式 "函数形式的直接链接") 配置文件为一个带有 `appInfo` 参数的函数。通过这样返回方法的形式,在运行期会被自动执行,将返回值合并进完整的配置对象。 ``` // src/config/config.default.ts export default (appInfo) => { return { view: { root: path.join(appInfo.baseDir, 'view'), }, }; }; ``` 这个函数的参数为 `AppInfo` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | ## 配置加载顺序[​](#配置加载顺序 "配置加载顺序的直接链接") 配置存在优先级(应用代码 > 框架 > 组件),相对于此运行环境的优先级会更高。 比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。 ``` -> 组件 config.default.ts -> 框架 config.default.ts -> 应用 config.default.ts -> 组件 config.prod.ts -> 框架 config.prod.ts -> 应用 config.prod.ts ``` ## 代码中使用配置[​](#代码中使用配置 "代码中使用配置的直接链接") Midway 会将配置都保存在内部的配置服务中,整个结构是一个对象,在 Midway 业务代码使用时,使用 `@Config` 装饰器注入。 ### 单个配置值[​](#单个配置值 "单个配置值的直接链接") 默认情况下,如果不传参数,将以属性名作为 key,从配置对象中获取值。 ``` import { Config } from '@midwayjs/decorator'; export class IndexHandler { @Config('userService') userConfig; async handler() { console.log(this.userConfig); // { appname: 'test'} } } ``` ### 深层级别配置值[​](#深层级别配置值 "深层级别配置值的直接链接") 如果配置对象的值在对象的深处,那么可以用级联的方式获取。 比如数据源为: ``` { "userService": { "appname": { "test": { "data": "xxx" } } } } ``` 则可以写复杂的获取表达式来获取值,示例如下。 ``` import { Config } from '@midwayjs/decorator'; export class IndexHandler { @Config('userService.appname.test.data') data; async handler() { console.log(this.data); // xxx } } ``` ### 整个配置对象[​](#整个配置对象 "整个配置对象的直接链接") 也可以通过 `ALL` 这个特殊属性,来获取整个配置的对象。 ``` import { Config, ALL } from '@midwayjs/decorator'; export class IndexHandler { @Config(ALL) allConfig; async handler() { console.log(this.allConfig); // { userService: { appname: 'test'}} } } ``` ## 动态添加配置[​](#动态添加配置 "动态添加配置的直接链接") 如果项目启动后,还需要修改配置,可以使用 midway 提供的 API。 ``` app.addConfigObject({ a: 1, b: 2, }); ``` 该 API 可以让新增的配置对象和现有的配置合并。 ## 异步初始化配置[​](#异步初始化配置 "异步初始化配置的直接链接") midway 新增了一个异步配置加载的生命周期,可以在配置加载后执行。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { IMidwayContainer } from '@midwayjs/core'; import { join } from 'path'; import { RemoteConfigService } from '../service/remote'; // 自定义的获取远端配置服务 @Configuration({ importConfigs: [join(__dirname, './config/')], }) export class ContainerLifeCycle { async onConfigLoad(container: IMidwayContainer) { // 这里你可以修改全局配置 const remoteConfigService = await container.getAsync(RemoteConfigService); const remoteConfig = await remoteConfigService.getData(); // 这里的返回值会和全局的 config 做合并 return { data: remoteConfig, }; } } ``` 注意,`onConfigLoad` 生命周期会在 egg 插件(若有)初始化之后执行,所以不能用于覆盖 egg 插件所使用的配置。 老的 bootstrap 用法,请参考 [框架前异步逻辑](/docs/2.0.0/multi_framework_start.md#n5oDJ)。 ## 配置的特殊 TS 写法问题[​](#配置的特殊-ts-写法问题 "配置的特殊 TS 写法问题的直接链接") ### export= 的情况[​](#export-的情况 "export= 的情况的直接链接") `export=`  混用的情况,如果后面有其他配置,会忽略 `export=`  的值。 ``` export = { a: 1, }; export const b = 2; ``` 编译后结果: ``` export const b = 2; ``` ### export default 的情况[​](#export-default-的情况 "export default 的情况的直接链接") `export default` 混用的情况,虽然编译没有问题,但是框架层会只读取 `default`  的配置。 ``` export default { a: 1, }; export const b = 2; ``` 框架侧只会读取 `default`  的值。 ``` export default { a: 1, }; ``` ## 使用环境变量[​](#使用环境变量 "使用环境变量的直接链接") 社区有一些库,比如 `dotenv` 可以加载 `.env` 文件注入到环境中,从而将一些秘钥放在环境中,在 Midway 中可以直接依赖它使用。 ``` $ npm i dotenv --save ``` 可以在项目根目录增加 `.env` 文件,比如下面的内容: ``` OSS_SECRET=12345 OSS_ACCESSKEY=54321 ``` 我们可以在入口中初始化,比如 `bootstrap.js` 或者 `configuration` 。 ``` import { Configuration } from '@midwayjs/decorator'; import * as dotenv from 'dotenv'; // load .env file in process.cwd dotenv.config(); @Configuration({ //... }) export class AutoConfiguration { async onReady(container) {} } ``` 我们可以在环境配置中使用了。 ``` // src/config/config.default export const oss = { accessKey: process.env.OSS_ACCESSKEY, // 54321 secret: process.env.OSS_SECRET, // 12345 }; ``` ## 常见错误[​](#常见错误 "常见错误的直接链接") ### 1、在构造器(constructor)中获取 @Config 注入的值[​](#1在构造器constructor中获取-config-注入的值 "1、在构造器(constructor)中获取 @Config 注入的值的直接链接") \*\*请不要在构造器中 \*\*获取 `@Config()` 注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('redisConfig') redisConfig; constructor() { console.log(this.redisConfig); // undefined } @Init() async initMethod() { console.log(this.redisConfig); // has value } } ``` ### 2、配置写法混用[​](#2配置写法混用 "2、配置写法混用的直接链接") 1、比如在 egg 里的回调和导出混用。 **下面是错误用法。** ``` export default (appInfo: EggAppInfo) => { const config = {} as DefaultConfig; // xxx return config; }; export const keys = '12345'; ``` `export const` 定义的值会被忽略。 2、比如 export default 和 export const 混用。 **下面是错误用法。** ``` export default { keys: '12345', }; export const anotherKey = '54321'; ``` 位于后面的配置将会被忽略。 ### 3、配置没有生效[​](#3配置没有生效 "3、配置没有生效的直接链接") 可能性很多,排查思路如下: * 1、检查 configuration 文件中是否显式配置 `importConfigs` 相关的文件或者目录 * 2、检查应用启动的环境,是否和配置文件一致,比如 prod 的配置肯定不会在 local 出现 * 3、检查是否将普通导出和方法回调导出混用,比如 "常见错误 2“ --- # 运行环境 Node.js 应用一般通过 `NODE_ENV`  来获取环境变量,来满足不同环境下的不同需求。比如在 `production`  环境下,开启缓存,优化性能,而在 `development`  环境下,会打开所有的日志开关,输出详细的错误信息等等。 ## 指定运行环境[​](#指定运行环境 "指定运行环境的直接链接") 由于在一些情况下 `NODE_ENV` 会被一些工具包拦截注入,所以在 Midway 体系下,我们会根据 `MIDWAY_SERVER_ENV` 优先获取环境,而 `NODE_ENV` 作为第二优先级获取。 我们可以通过启动时增加环境变量来指定。 ``` MIDWAY_SERVER_ENV=prod npm start // 第一优先级 NODE_ENV=local npm start // 第二优先级 ``` 在 windows 环境,我们需要使用 [cross-env](https://www.npmjs.com/package/cross-env) 模块以达到同样的效果。 ``` cross-env MIDWAY_SERVER_ENV=prod npm start // 第一优先级 cross-env NODE_ENV=local npm start // 第二优先级 ``` ## 代码中获取环境[​](#代码中获取环境 "代码中获取环境的直接链接") Midway 在 app 对象上提供了 `getEnv()`  方法获取环境,面对不同的上层框架,Midway 都做了相应的处理,保使得在不同场景下,都拥有 `getEnv()`  方法。。 ``` import { Application } from 'egg'; // process.env.MIDWAY_SERVER_ENV=prod @Provide() export class UserService { @App() app: Application; // 请替换为使用的上层框架 async invoke() { console.log(this.app.getEnv()); // prod } } ``` 如果 `NODE_ENV` 和 `MIDWAY_SERVER_ENV`  都没有赋值,那么默认情况下,方法的返回值为 `prod` 。 信息 注意,你不能直接通过 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 来获取环境,这两个值都有可能为空,且 Midway 不会反向设置它。如需获取环境,请通过 app.getEnv() 获取其他框架提供的 API 方法获取。 ## 常见的环境变量值[​](#常见的环境变量值 "常见的环境变量值的直接链接") 一般来说,每个公司都有一些自己的环境变量值,下面是一些常见的环境变量值以及他们对应的说明。 | **值** | **说明** | | | --------------------- | ------------ | - | | local | 本地开发环境 | | | dev/daily/development | 日常开发环境 | | | pre/prepub | 预生产环境 | | | prod/production | 生产环境 | | | test/unittest | 单元测试环境 | | | benchmark | 性能测试环境 | | ## 依赖注入容器中获取环境[​](#依赖注入容器中获取环境 "依赖注入容器中获取环境的直接链接") 在依赖注入容器初始化的过程中,Midway 默认初始化了一个 `EnvironmentService` 服务用来解析环境,并在整个生命周期中,持续保持这个服务对象。 借助服务的 `getCurrentEnvironment`  方法,我们可以直接从上面获取环境值,而 `app.getEnv()`  方法也正是这样获取值的。 ``` const environmentService = app.getApplicationContext().getEnvironmentService(); const env = environmentService.getCurrentEnvironment(); ``` --- # Express 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 ## 创建项目[​](#创建项目 "创建项目的直接链接") 我们可以使用我们的脚手架来创建一个模版项目: ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=express hello_express # 如果是 npm v7 $ npm init midway -- --type=express hello_express ``` 运行: ``` $ cd hello_express // 进入项目路径 $ npm run dev // 本地运行 ``` 针对 Express,Midway 提供了 `@midwayjs/express` 包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。 这些包列举如下。 ``` "dependencies": { "@midwayjs/express": "^2.3.11", "@midwayjs/decorator": "^2.3.11" }, "devDependencies": { "@midwayjs/mock": "^2.3.11", }, ``` | @midwayjs/express | Midway 针对 express 的适配层 | | ------------------- | ---------------------------- | | @midwayjs/decorator | Midway 系列通用的装饰器包 | | @midwayjs/mock | 本地开发工具包 | 信息 我们使用的 Express 版本为 `v4` 。 ## 目录结构[​](#目录结构 "目录结构的直接链接") ``` . ├── src │ ├── controller # controller接口的地方 │ ├── service # service逻辑处理的地方 | └── configuration.ts # 入口及生命周期配置、组件管理 ├── test ├── package.json └── tsconfig.json ``` ## 控制器(Controller)[​](#控制器controller "控制器(Controller)的直接链接") 整个请求控制器的写法和 Midway 适配其他框架的类似。为了和其他场景的框架写法一致,在请求的时候,Midway 将 Express 的 `req` 和 `res` 包装为 `ctx` 对象。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request, Response } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; // 包含了 req 和 res @Get('/') async home(@Query() id) { console.log(id); // this.ctx.req.query.id === id return 'hello world'; // 简单返回,等价于 res.send('hello world'); } } ``` 你也可以额外注入 `req` 和 `res` 。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request, Response } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; // 包含了 req 和 res @Inject() req: Request; @Inject() res: Response; @Get('/') async home(@Query() id) { // this.req.query.id === id } } ``` ### 请求参数装饰器[​](#请求参数装饰器 "请求参数装饰器的直接链接") 在 @midwayjs/express 中,可以使用大部分的请求装饰器,具体的列表如下: | @Query | √ | | ------------ | ------------------------------ | | @Body | 需要自行安装 body 解析库后使用 | | @Param | √ | | @Headers | √ | | @Session | 需要自行安装 session 后使用 | | @RequestPath | √ | | @RequestIP | √ | | @Queries | 同 @Query | 由于 express 框架相对纯粹,默认情况下,我们没有埋入 body 解析的库。 `@Body` 装饰器将在安装了解析 body 库之后才能使用。 下面就是如何使用 body 解析库的示例: 首先安装模块。 ``` $ npm i body-parser --save ``` 然后中间件在 configuration 中加载。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as bodyParser from 'body-parser'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use(bodyParser.json()); this.app.use(bodyParser.urlencoded({ extended: false })); } } ``` 更多配置可以查看 [body-parser](https://github.com/expressjs/body-parser) 文档。 同理 Session 支持也可以查看 [Session 文档](/docs/2.0.0/session.md)。 ## 编写 Web 中间件[​](#编写-web-中间件 "编写 Web 中间件的直接链接") Express 的中间件写法比较特殊,它的参数不同。 ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware } from '@midwayjs/express'; import { Request, Response, NextFunction } from 'express'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (req: Request, res: Response, next: NextFunction) => { console.log('Request...'); next(); }; } } ``` 注意,这里我们导出了一个 `ReportMiddleware`  类,这个中间件类的 id 为 `reportMiddleware` 。 ## 路由中间件[​](#路由中间件 "路由中间件的直接链接") 我们可以把上面编写的中间件应用到单个 Controller 上,也可以将中间件应用到单个路由上。 ``` import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/', { middleware: ['reportMiddleware'] }) // controller 级别的中间件 export class HomeController { @Get('/', { middleware: ['reportMiddleware'] }) // 路由级别的中间件 async home() { return 'hello world'; } } ``` ## 全局中间件[​](#全局中间件 "全局中间件的直接链接") 直接使用 Midway 提供的 `app.generateMiddleware`  方法,在入口处加载全局中间件。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/express'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { this.app.use(await this.app.generateMiddleware('reportMiddleware')); } } ``` 除了加载 Class 形式的中间件外,也支持加载传统的 Express 中间件。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/express'; import { join } from 'path'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { this.app.use((req, res, next) => { // xxx }); } } ``` 你可以通过注入 `app` 对象,来调用到所有 Express 上的方法。 ## 框架启动参数[​](#框架启动参数 "框架启动参数的直接链接") `@midwayjs/express`  框架的启动参数如下: \| port | number | 必填,启动的端口 | | -------- | ------- | ---------------------------- | ------------ | ------- | --------------------- | | key | string | Buffer | Array\ | 可选,HTTPS 证书 key | | cert | string | Buffer | Array\ | 可选,HTTPS 证书 cert | | ca | string | Buffer | Array\ | 可选,HTTPS 证书 ca | | hostname | string | 监听的 hostname,默认 127.1 | | http2 | boolean | 可选,http2 支持,默认 false | ## 部署[​](#部署 "部署的直接链接") ### 部署到普通应用容器[​](#部署到普通应用容器 "部署到普通应用容器的直接链接") Midway 构建出来的项目是单进程的,不管是采用 `fork` 模式还是 `cluster` 模式,单进程的代码总是很容易的兼容到不同的体系中,因此非常容易被社区现有的 pm2/forever 等工具所加载, 我们这里以 pm2 来演示如何部署。 项目一般都需要一个入口文件,比如,我们在根目录创建一个 `bootstrap.js` 作为我们的部署文件。 ``` ➜ hello_express tree . ├── src ├── dist # Midway 构建产物目录 ├── test ├── server.js # 部署启动文件 ├── package.json └── tsconfig.json ``` Midway 提供了一个简单方式以满足不同场景的启动方式,只需要安装我们提供的 `@midwayjs/bootstrap` 模块。 ``` $ npm install @midwayjs/bootstrap --save ``` 然后在入口文件中写入代码,注意,这里的代码使用的是 `JavaScript` 。 ``` // 获取框架 const WebFramework = require('@midwayjs/express').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载框架并执行 Bootstrap.load(web).run(); ``` 我们提供的每个上层框架都将会导出一个 `Framework` 类,而 `Bootstrap` 的作用则是加载这些框架,传入启动参数,运行他们。 这个时候,你已经可以直接使用 `node bootstrap.js` 来启动代码了,也可以使用 pm2 来执行启动。 ``` $ npm install -g pm2 $ pm2 start bootstrap.js ``` ### 部署到 Serverless 环境[​](#部署到-serverless-环境 "部署到 Serverless 环境的直接链接") Serverless 环境指的是阿里云 FC,腾讯云等函数环境。Midway 可以将现有的 Web 项目部署为 Serverless 应用,这里以部署到阿里云函数计算作为示例。 1、添加 `f.yml` 文件到你的项目根目录。 ``` ➜ hello_express tree . ├── src ├── dist ├── f.yml # Midway Serverless 部署配置文件 ├── package.json └── tsconfig.json ``` ``` service: my-midway-app ## 应用发布到云平台的名字,一般指应用名 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: express ## 部署的应用类型 ``` 2、代码修改 将 `bootstrap.js` 重命名为 `app.js` ,移除内部的端口(Serverless 环境不需要),并返回一个 app。 修改后的代码如下: ``` // 获取框架 const WebFramework = require('@midwayjs/express').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({}); const { Bootstrap } = require('@midwayjs/bootstrap'); module.exports = async () => { // 加载框架并执行 await Bootstrap.load(web).run(); // 返回 app 对象 return web.getApplication(); }; ``` 3、添加发布时的构建钩子 在 `package.json` 加入下面的这段,用于在发布时自动执行 `npm run build` 。 ``` "midway-integration": { "lifecycle": { "before:package:cleanup": "npm run build" } }, "scripts": { "deploy": "midway-bin deploy" } ``` 3、执行 `npm run deploy` 即可,发布后,阿里云会输出一个临时可用的域名,打开浏览器访问即可。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600835297676-1753de7a-fb0d-46ca-98f0-944eba5b2f2b.png#height=193\&id=WKAhy\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=193\&originWidth=1219\&originalType=binary\&ratio=1\&size=35152\&status=done\&style=none\&width=1219) 如需更详细的发布文档,请查阅 [**Serverless 发布 FAQ**](https://www.yuque.com/midwayjs/faas/deploy_aliyun_faq)。 --- # HTTP 请求(Axios) midway 包裹了 [axios](https://github.com/axios/axios) 包,使得在代码中可以简单的使用 axios 接口。 和 axios 的一些关系如下: * 接口完全一致 * 适配依赖注入写法,完整的类型定义 * 方便框架串联依赖链路,排查问题 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/axios@2 --save ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; @Configuration({ imports: [ axios, // 导入 axios 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` 然后在业务代码中即可注入使用。 ## 使用服务[​](#使用服务 "使用服务的直接链接") 接口和 [axios](https://github.com/axios/axios) 一致。 ``` axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]]) ``` 使用示例: ``` import { HttpService } from '@midwayjs/axios'; @Provide() export class UserService { @Inject() httpService: HttpService; async invoke() { const url = 'http://www.weather.com.cn/data/cityinfo/101010100.html'; const result = await this.httpService.get(url); // TODO result } } ``` ## 配置 Axios[​](#配置-axios "配置 Axios的直接链接") HttpService 实例等价于 `axios.create` ,所以可以有一些配置参数,我们可以在 `src/config.default.ts` 中配置它,配置完之后,全局的 axios 都会生效。 比如: ``` export const axios = { baseURL: 'https://api.example.com', // `headers` are custom headers to be sent headers: { 'X-Requested-With': 'XMLHttpRequest', }, timeout: 1000, // default is `0` (no timeout) // `withCredentials` indicates whether or not cross-site Access-Control requests // should be made using credentials withCredentials: false, // default }; ``` 具体的参数可以参考 [axios global config](https://github.com/axios/axios#config-defaults)。 ## 配置全局拦截器[​](#配置全局拦截器 "配置全局拦截器的直接链接") ``` import { Configuration } from '@midwayjs/decorator'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; import { IMidwayContainer } from '@midwayjs/core'; @Configuration({ imports: [ axios, // 导入 axios 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle { async onReady(container: IMidwayContainer) { const httpService = await container.getAsync(axios.HttpService); httpService.interceptors.request.use( (config) => { // Do something before request is sent return config; }, (error) => { // Do something with request error return Promise.reject(error); } ); } } ``` --- # 缓存(Cache) Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 ## 安装[​](#安装 "安装的直接链接") 首先安装相关的组件模块。 ``` $ npm install @midwayjs/cache@2 cache-manager -S $ npm install @types/cache-manager -D ``` ## 使用 Cache[​](#使用-cache "使用 Cache的直接链接") Midway 为不同的 cache 存储提供了统一的 API。默认内置了一个基于内存数据存储的数据中心。如果想要使用别的数据中心,开发者也可以切换到例如 mongodb、fs 等模式。 首先,引入 Cache 组件,在 `configuration.ts`  中导入: ``` import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import * as bodyParser from 'koa-bodyparser'; import * as cache from '@midwayjs/cache'; // 导入cacheComponent模块 import { join } from 'path'; @Configuration({ imports: [ cache, // 导入 cache 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` 然后在业务代码中即可注入使用。 ``` import { Inject, Provide } from '@midwayjs/decorator'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cache: CacheManager; // 依赖注入CacheManager } ``` 通过提供的 API 来设置,获取缓存数据。 ``` import { Inject, Provide } from '@midwayjs/decorator'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cache: CacheManager; async getUser(options: IUserOptions) { // 设置缓存内容 await this.cache.set(`name`, 'stone-jin'); // 获取缓存内容 let result = await this.cache.get(`name`); return result; } async getUser2() { //获取缓存内容 let result = await this.cache.get(`name`); return result; } async reset() { await this.cache.reset(); // 清空对应 store 的内容 } } ``` ### 设置缓存[​](#设置缓存 "设置缓存的直接链接") 我们通过 `await this.cache.set(key, value)`  方法进行设置,此处默认过期时间是 10s。 你也可以手动设置 TTL(过期时间),如下: ``` await this.cache.set(key, value, { ttl: 1000 }); // ttl的单位为秒 ``` 如果你想要禁止 Cache 不过期,则将 TTL 设置为 null 即可。 ``` await this.cache.set(key, value, { ttl: null }); ``` 同时你也可以通过全局的 `config.default.ts`  中进行设置。 ``` export const cache = { store: 'memory', options: { max: 100, ttl: 10, // 修改默认的ttl配置 }, }; ``` ### 获取缓存[​](#获取缓存 "获取缓存的直接链接") ``` const value = await this.cache.get(key); ``` 如果获取不到,则为 undefined。 ### 移除缓存[​](#移除缓存 "移除缓存的直接链�接") 移除缓存,可以通过 del 方法。 ``` await this.cache.del(key); ``` ### 清空整体 store 数据(此处是整体清除,需要重点 ⚠️)[​](#清空整体-store-数据此处是整体清除需要重点-️ "清空整体 store 数据(此处是整体清除,需要重点 ⚠️)的直接链接") 比如用户设置了某个 redis 为 store,调用的话,包括非 cache 模块设置的也会清除。 ``` await this.cache.reset(); // 这块需要注意 ``` ## 全局配置[​](#全局配置 "全局配置的直接链接") 当我们引用了这个 cache 组件后,我们能对其进行全局的配置。配置方法跟别的组件类似。 默认的配置: ``` export const cache = { store: 'memory', options: { max: 100, ttl: 10, }, }; ``` 例如用户可以修改默认的 TTL,也就是过期时间。 ## 其他 Cache[​](#其他-cache "其他 Cache的直接链接") 用户也可以修改 store 方式,在 `config.default.ts`  中进行组件的配置: ``` import * as redisStore from 'cache-manager-ioredis'; export const cache = { store: redisStore, options: { host: 'localhost', // default value port: 6379, // default value password: '', db: 0, keyPrefix: 'cache:', ttl: 100, }, }; ``` 或者修改为 mongodb 的 cache。 危险 **再次注意 ⚠️:使用 redis 的作为 cache 的时候,代码里面慎用 reset 方法,因为会把整个 redis 给 flushdb,简称数据清空。** ## 相关文档[​](#相关文档 "相关文档的直接链接") 由于 Midway Cache 是基于 cache-manager 封装,所以相关资料用户也可以查询:[cache-manger](https://www.npmjs.com/package/cache-manager)。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、set 和 get 无法得到相同值?[​](#1set-和-get-无法得到相同值 "1、set 和 get 无法得到相同值?的直接链接") 用户使用了 cache 模块,默认是内存式的,例如在本地用 dev 模式,由于是单进程的,那 set 和 get 最终能达到相同的值。但是用户部署到服务器上面后,由于会有多 worker,相当于第一次请求,落在进程 1 上,然后第二次落在进程 2 上,这样获得到空了。 解决办法:参考 其他 Cache 的章节,配置 store 为分布式的,例如 redis 的 store 等方式。 --- # Consul consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 本文介绍了如何用 consul 作为 midway 的服务注册发现中心,以及如何使用 consul 来做软负载的功能。 感谢 [boostbob](https://github.com/boostbob) 提供的组件。 效果如下图: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617690430023-1749c2da-14f3-4064-9388-b3e15669d7a2.png#height=494\&id=zSztd\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=988\&originWidth=3144\&originalType=binary\&ratio=1\&size=245867\&status=done\&style=none\&width=1572) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617690444687-cf583ac5-82ec-4f31-a528-772491964184.png#height=937\&id=X6FNK\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1874\&originWidth=3140\&originalType=binary\&ratio=1\&size=682382\&status=done\&style=none\&width=1570) ## 安装组件[​](#安装组件 "安装组件的直接链接") 首先安装 consul 的组件: ``` npm i @midwayjs/consul@2 -S npm i @types/consul -D ``` ## 目前支持的能力[​](#目前支持的能力 "目前支持的能力的直接链接") * 注册能力(可选) * 在停止服务的时候反注册(可选) * 服务选择(随机) * 暴露原始的 consul 对象 ## 使用方法:[​](#使用方法 "使用方法:的直接链接") ``` import * as consul from '@midwayjs/consul'; @Configuration({ imports: [consul], importConfigs: [join(__dirname, 'config')], }) export class ContainerConfiguration {} ``` 配置 `config.default.ts`  文件: ``` config.consul = { provider: { // 注册本服务 register: true, // 应用正常下线反注册 deregister: true, // consul server 主机 host: '192.168.0.10', // 此处修改 consul server 的地址 // consul server 端口 port: 8500, // 端口也需要进行修改 // 调用服务的策略(默认选取 random 具有随机性) strategy: 'random', }, service: { address: '127.0.0.1', // 此处是当前这个 midway 应用的地址 port: 7001, // midway应用的端口 tags: ['tag1', 'tag2'], // 做泳道隔离等使用 name: 'my-midway-project', // others consul service definition }, }; ``` 然后启动 midway 项目,然后同时打开我们 consul server 的 ui 地址: 就呈现了如下效果: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617690430023-1749c2da-14f3-4064-9388-b3e15669d7a2.png#height=494\&id=N82Ws\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=988\&originWidth=3144\&originalType=binary\&ratio=1\&size=245867\&status=done\&style=none\&width=1572) 相当于我们的 my-midway-project 项目注册上来了。 然后我们停止我们的 midway 项目。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617690952779-9b4b5293-47ca-4379-a7cb-2e1033785fc2.png#height=417\&id=1RHPp\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=834\&originWidth=3122\&originalType=binary\&ratio=1\&size=280981\&status=done\&style=none\&width=1561) 我们可以看到我们项目的状态就变为红色了。 我们演示多台的情况,如下表现:(1 台在线+1 台不在线) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617691097036-3484b9c1-0825-4890-a275-59140ca57f1b.png#height=420\&id=dW4kg\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=840\&originWidth=3108\&originalType=binary\&ratio=1\&size=293770\&status=done\&style=none\&width=1554) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617691111593-4ef18594-179e-45bf-ac34-8bd16839a13b.png#height=369\&id=AnxNA\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=738\&originWidth=3076\&originalType=binary\&ratio=1\&size=419244\&status=done\&style=none\&width=1538) ## 作为客户端[​](#作为客户端 "作为客户端的直接链接") 例如我们作为客户端 A,需要调用服务 B 的接口,然后我们首先是查出 B 健康的服务,然后进行 http 请求。 此处为了方便理解,我们模拟查询刚刚注册的成功的服务: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; import { BalancerService } from '@midwayjs/consul'; @Provide() @Controller('/') export class HomeController { @Inject() balancerService: BalancerService; @Get('/') async home() { const service = await this.balancerService.getServiceBalancer().select('my-midway-project'); console.log(service); return 'Hello Midwayjs!'; } } ``` 然后我们看到 14 行打印的这个 service 的内容了: ``` { ID: 'c434e36b-1b62-c4e1-c4ec-76c5d3742ff8', Node: '1b2d5b8771cb', Address: '127.0.0.1', Datacenter: 'dc1', TaggedAddresses: { lan: '127.0.0.1', lan_ipv4: '127.0.0.1', wan: '127.0.0.1', wan_ipv4: '127.0.0.1' }, NodeMeta: { 'consul-network-segment': '' }, ServiceKind: '', ServiceID: 'my-midway-project:xxx:7001', ServiceName: 'my-midway-project', ServiceTags: [ 'tag1', 'tag2' ], ServiceAddress: 'xxxxx', ServiceTaggedAddresses: { lan_ipv4: { Address: 'xxxxx', Port: 7001 }, wan_ipv4: { Address: 'xxxxxx', Port: 7001 } }, ServiceWeights: { Passing: 1, Warning: 1 }, ServiceMeta: {}, ServicePort: 7001, ServiceEnableTagOverride: false, ServiceProxy: { MeshGateway: {}, Expose: {} }, ServiceConnect: {}, CreateIndex: 14, ModifyIndex: 14 } ``` 此时,我们只要通过 Address 和 ServicePort 去连接服务 B,比如做 http 请求。 查询不健康的: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; import { BalancerService } from '@midwayjs/consul'; @Provide() @Controller('/') export class HomeController { @Inject() balancerService: BalancerService; @Get('/') async home() { const service = await this.balancerService.getServiceBalancer().select('my-midway-project', false); console.log(service); return 'Hello Midwayjs!'; } } ``` 13 行,第二个参数是不健康的表现。 ## 配置中心[​](#配置中心 "配置中心的直接链接") 同时 consul 也能作为一个服务配置的地方,如下代码: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; import * as Consul from 'consul'; @Provide() @Controller('/') export class HomeController { @Inject('consul:consul') consul: Consul.Consul; @Get('/') async home() { await this.consul.kv.set(`name`, `juhai`); // let res = await this.consul.kv.get(`name`); // console.log(res); return 'Hello Midwayjs!'; } } ``` 第 13 行,比如我们调用 set 方法,我们可以设置对应的配置,然后我们 14 行也可以拿到对应的配置。 注意:在代码中,有同学出现,在每次请求中去 get 对应的配置,这时你的 QPS 多少对 consul server 的压力。 所以在 QPS 比较大的情况,可以如下处理: ``` import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; import * as Consul from 'consul'; @Provide() @Scope(ScopeEnum.Singleton) export class ConfigService { @Inject('consul:consul') consul: Consul.Consul; config: any; @Init() async init() { setInterval(() => { this.consul.kv.get(`name`).then((res) => { this.config = res; }); }, 5000); this.config = await this.consul.kv.get(`name`); } async getConfig() { return this.config; } } ``` 上面的代码,相当于定时去获取对应的配置,当每个请求进来的时候,获取 Scope 为 ScopeEnum.Singleton 服务的 `getConfig`  方法,这样每 5s 一次获取请求,就减少了对服务的压力。 Consul 界面上如下图: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617703213009-850f48b3-e3ef-4036-bb8e-c7999986e668.png#height=391\&id=4ccIQ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=782\&originWidth=3140\&originalType=binary\&ratio=1\&size=193680\&status=done\&style=none\&width=1570) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617703225726-5e069b9d-cddd-4777-9a42-df4a1d30443d.png#height=619\&id=1jAvc\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1238\&originWidth=2784\&originalType=binary\&ratio=1\&size=213448\&status=done\&style=none\&width=1392) 一共提供如下几种方法: * [get](https://www.npmjs.com/package/consul#kv-get),获取对应 key 的 value * [keys](https://www.npmjs.com/package/consul#kv-keys),查询某个 prefix 的 key 的列表 * [set](https://www.npmjs.com/package/consul#kv-set),设置对应的 key 的值 * [del](https://www.npmjs.com/package/consul#kv-del),删除对应的 key ## 其他说明[​](#其他说明 "其他说明的直接链接") 这样的好处,就是 A->B,B 也可以进行扩展,并且可以通过 tags 做泳道隔离。例如做单元隔离等。并且可以通过 ServiceWeights 做对应的权重控制。 consul 还能做 Key/Value 的配置中心的作用,这个后续我们考虑支持。 ## 搭建 Consul 测试服务[​](#搭建-consul-测试服务 "搭建 Consul 测试服务的直接链接") 下面描述了单机版本的 consul 搭建流程。 ``` docker run -itd -P consul ``` 然后执行 `docker ps` ``` ➜ my_consul_app docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1b2d5b8771cb consul "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 0.0.0.0:32782->8300/tcp, 0.0.0.0:32776->8301/udp, 0.0.0.0:32781->8301/tcp, 0.0.0.0:32775->8302/udp, 0.0.0.0:32780->8302/tcp, 0.0.0.0:32779->8500/tcp, 0.0.0.0:32774->8600/udp, 0.0.0.0:32778->8600/tcp cocky_wing ``` 然后我们打开 8500 所对应的端口:(上图比如我的对应端口是 32779) [http://127.0.0.1:32779/ui/](http://127.0.0.1:32779/ui/dc1/kv) 打开后效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617690430023-1749c2da-14f3-4064-9388-b3e15669d7a2.png#height=494\&id=pZQL5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=988\&originWidth=3144\&originalType=binary\&ratio=1\&size=245867\&status=done\&style=none\&width=1572) 然后我们的 `config.default.ts`  中的 port 就是 32779 端口。 ## 常用问题[​](#常用问题 "常用问题的直接链接") ### 下线服务[​](#下线服务 "下线服务的直接链接") 如果想要手动将 consul 界面上不需要的服务给下线掉,可以通过下面的方法: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; import * as Consul from 'consul'; @Provide() @Controller('/') export class HomeController { @Inject('consul:consul') consul: Consul.Consul; @Get('/222') async home2() { let res = await this.consul.agent.service.deregister(`my-midway-project:30.10.72.195:7002`); console.log(res); return 'Hello Midwayjs2!'; } } ``` 13 行的 deregister 里面,就是对应 consul 界面上的名字了: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617707700852-c21f6855-e587-4b1c-affb-b96dc576ff4a.png#height=577\&id=IgPIB\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1154\&originWidth=3724\&originalType=binary\&ratio=1\&size=836136\&status=done\&style=none\&width=1862) --- # 对象存储(COS) 本文介绍了如何使用 midway 接入腾讯云 COS。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/cos@2 --save ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as cos from '@midwayjs/cos'; import { join } from 'path'; @Configuration({ imports: [ cos, // 导入 cos 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` export const cos = { client: { SecretId: '***********', SecretKey: '***********', }, }; ``` **多个客户端配置,需要配置多个** ``` export const cos = { clients: { instance1: { SecretId: '***********', SecretKey: '***********', }, instance2: { SecretId: '***********', SecretKey: '***********', }, }, }; ``` 更多参数可以查看 [cos-nodejs-sdk-v5](https://github.com/tencentyun/cos-nodejs-sdk-v5) 文档。 ## 使用 COS 服务[​](#使用-cos-服务 "使用 COS 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/decorator'; import { CosService } from '@midwayjs/cos'; @Provide() export class UserService { @Inject() cosService: COSService; async invoke() { await this.cosService.sliceUploadFile({ Bucket: 'test-1250000000', Region: 'ap-guangzhou', Key: '1.zip', FilePath: './1.zip' }, } } ``` 可以使用 `COSServiceFactory` 获取不同的实例。 ``` import { COSServiceFactory } from '@midwayjs/cos'; import { join } from 'path'; @Provide() export class UserService { @Inject() cosServiceFactory: COSServiceFactory; async save() { const redis1 = await this.cosServiceFactory.get('instance1'); const redis2 = await this.cosServiceFactory.get('instance3'); //... } } ``` --- # GraphQL ## 概述[​](#概述 "概述的直接链接") [Apollo-Server-Midway](https://github.com/linbudu599/apollo-server-midway) 基于 [Apollo Server V3](https://www.apollographql.com/docs/apollo-server) 构建,它使得你可以在 Midway && Midway Serverless 应用 中使用 Apollo-Server 作为 GraphQL 请求处理层,因此,你现在可以使用 MidwayJS 构建 GraphQL API 甚至是 GraphQL FaaS 应用了。 * 在 Midway Serverless 中,Apollo-Server-Midway 通过将 Apollo-Server 作为一个 GraphQL 专有的响应处理器来工作,同时内置了 [TypeGraphQL](https://typegraphql.com/) 支持来配合 MidwayJS 的装饰器体系(TypeGraphQL 使用 TypeScript 的 Class 以及装饰器声明 GraphQL Schema 以及 GraphQL Resolvers 等一系列能力)。 * 在 Midway Node 应用中,它主要通过将 Apollo-Server 作为一个仅针对 GraphQL API 路径(如`/graphql`)的中间件进行工作,所以你可以同时构建 RESTFul API 与 GraphQL API,不同的基座框架需要使用不同的中间件,在不同的框架下也对应了不同版本的 Apollo-Server 集成(如 Apollo-Server-Koa、Apollo-Server-Express)。 * 这两部分都对 TypeGraphQL 做了内置支持,但你同样可以仅使用 Apollo-Server 的能力,如从外部传入 GraphQL Schema,以及使用 Apollo Server 内置的能力来实现 GraphQL Resolver。在这种情况下,TypeGraphQL 的选项将被忽略。 * 在 Node 应用中,实际上更推荐使用自定义的 GraphQL 中间件,而不是使用框架内置。 * 对于框架内置的版本,你无法直观的控制被包含在 GraphQL Context 中的数据,而是只能在 config 下单独定义一些不具有外部依赖的数据,对于依赖应用上下文、请求上下文或者其他注入进来的数据则束手无策。 * 使用自定义的 GraphQL 中间件,你可以进行更加灵活的逻辑定制,包括但不限于 Apollo Server Plugin、GraphQL Context 以及 TypeGraphQL AuthChecker 等等。 * Apollo-Server-Midway 的重心在于提供 Midway Serverless 下低成本接入 GraphQL 的能力,对于 Node 应用的支持只是附带,同时,由于 Node 应用中可能存在各种可能的定制需求,在框架层定制同样不现实。 * 参考下方 定制 GraphQL 中间件 一节了解更多。 ## Serverless 应用[​](#serverless-应用 "Serverless 应用的直接链接") 大致的使用流程如下: ``` import { Provide, Inject, ServerlessTrigger, ServerlessFunction, ServerlessTriggerType, App, } from '@midwayjs/decorator'; import { Context, IMidwayFaaSApplication } from '@midwayjs/faas'; import { createApolloServerHandler } from 'apollo-server-midway'; import { SampleResolver } from '../resolvers/sample.resolver'; import { DogResolver } from '../resolvers/dog.resolver'; import path from 'path'; const apolloHandlerFuncName = 'apollo-handler'; const APOLLO_SERVER_MIDWAY_PATH = '/apollo'; @Provide() export class HelloHTTPService { @Inject() ctx: Context; @App() app: IMidwayFaaSApplication; @ServerlessFunction({ functionName: apolloHandlerFuncName, }) @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: APOLLO_SERVER_MIDWAY_PATH, method: 'get', }) @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: APOLLO_SERVER_MIDWAY_PATH, method: 'post', }) async apolloHandler() { return await createApolloServerHandler({ path: '/', app: this.app, context: this.ctx, schema: { resolvers: [SampleResolver, DogResolver], }, }); } } ``` 我们分几个部分讲解: * 首先,推荐在函数上同时指定 GET 与 POST 方法触发器,并配置相同的路径。这一行为是为了允许你通过 GET 方法在本地开发中访问 [GraphQL Playground](https://github.com/graphql/graphql-playground)(一个 GraphQL IDE)(在生产环境下将被禁用,可以通过 `prodPlayground` 选项来在生产环境下启用,但不推荐这么做),并使用 POST 方法作为 API 的真正承接。 * 函数路径(`ServerlessTrigger`中的`path`)与 GraphQL API 路径(`createApolloServerHandler`选项中的`path`)是并存的,在上面的例子中,可以通过 `/apollo-handler/` 访问 GraphQL API,即 函数名(函数路径)/。如果配置 GraphQL Path 为 `/graphql`,则访问地址为 `/apollo-handler/graphql`。 * 关于可用选项参考最后的部分,注意,如果 `options.apollo.schema` 被指定,那么 `options.schema` 将被忽略。 * options.apollo:Apollo Server 的初始化参数 * options.schema:TypeGraphQL buildSchemaSync 参数 ## Node 应用[​](#node-应用 "Node 应用的直接链接") Node 应用需要使用框架对应的中间件,整体代码会被以 Midway Component 的形式加载,如在 Koa 应用中,需要这么做: ``` // config.default.ts import { SampleResolver } from '../resolvers/sample.resolver'; import { CreateGraphQLMiddlewareOption } from 'apollo-server-midway'; export const graphql: CreateGraphQLMiddlewareOption = { schema: { resolvers: [SampleResolver], }, }; // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { IMidwayKoaApplication } from '@midwayjs/koa'; import * as GraphQL from 'apollo-server-midway'; @Configuration({ imports: [GraphQL], importConfigs: ['./config'], }) export class ContainerConfiguration implements ILifeCycle { @App() app: IMidwayKoaApplication; async onReady(): Promise { this.app.use( // Express 下的命名空间:graphql:GraphQLExpressMiddleware await this.app.generateMiddleware('graphql:GraphQLKoaMiddleware') ); } } ``` 在 Express 应用中, 将其换成 `graphql:GraphQLExpressMiddleware` 即可。 > 目前仅有 Koa / Express 支持。 上面展示了通过 `config.default.ts` 注入配置的能力,你也可以通过 `@Config` 的方式将配置注入到 `ContainerConfiguration` 类中进行配置。 ## 定制 GraphQL 中间件[​](#定制-graphql-中间件 "定制 GraphQL 中间件的直接链接") 定制 GraphQL 中间件的成本实际上非常低的,不到 100 行代码即可实现: > 示例参考 [koa-app-sample](https://github.com/LinbuduLab/apollo-server-midway/blob/main/packages/koa-app-sample/src/middlewares/extend.ts) 以下示例以 Koa 为例 首先定义中间件 ``` import { Provide, Config, App } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayKoaApplication, IMidwayKoaContext, IMidwayKoaNext } from '@midwayjs/koa'; import { ApolloServer, ServerRegistration } from 'apollo-server-koa'; import { buildSchemaSync } from 'type-graphql'; import { ApolloServerPluginLandingPageGraphQLPlayground, ApolloServerPluginLandingPageDisabled, } from 'apollo-server-core'; import { SampleResolver } from '../resolvers/sample.resolver'; @Provide('extend:GraphQLKoaMiddleware') export class GraphQLMiddleware implements IWebMiddleware { @Config('apollo') config: ServerRegistration; @App() app: IMidwayKoaApplication; resolve() { return async (_ctx: IMidwayKoaContext, next: IMidwayKoaNext) => { const container = this.app.getApplicationContext(); const schema = buildSchemaSync({ resolvers: [SampleResolver], // 直接传入 container,意味着使用应用上下文作为容器 // container, // 从 Apollo Context 中获取 container ,意味着使用请求上下文作为容器 container: ({ context }: ResolverData<{ container: IMidwayContainer }>) => context.container, emitSchemaFile: 'schema.graphql', }); const server = new ApolloServer({ schema, // 这里的 ctx 实际上是被 Midway 处理过的,所以你可以拿到 requestContext context: ({ ctx }: { ctx: IMidwayKoaContext }) => { return { // 返回请求上下文容器供 TypeGraphQL 使用 container: ctx.requestContext, // 返回请求上下文供 Resolver 中使用 reqCtx: ctx, }; }, plugins: [ ['production'].includes(process.env.NODE_ENV) || process.env.DISABLE_PLAYGROUND ? ApolloServerPluginLandingPageDisabled() : ApolloServerPluginLandingPageGraphQLPlayground({ settings: { // playground settings }, }), ], }); await server.start(); server.applyMiddleware({ app: this.app, ...this.config, }); await next(); }; } } ``` 可以看到这里的逻辑其实是很简单的,与框架内置不同的是定制了 GraphQL Context,包含应用上下文与请求上下文。**另外,需要注意的是,这里的 **`**Context**`** 需要使用函数,来确保每次请求来时能保持更新,尤其是当你需要使用请求上下文信息如 cookie、headers 等时。** 在 Resolver 中你就可以拿到关联请求上下文的信息了: ``` import { IMidwayContainer } from '@midwayjs/core'; import { Provide, Inject, App } from '@midwayjs/decorator'; import { IMidwayKoaContext } from '@midwayjs/koa'; import { Resolver, Query, Ctx } from 'type-graphql'; import { SampleType } from '../graphql/sample.type'; interface IContext { container: IMidwayContainer; reqCtx: IMidwayKoaContext; } @Provide() @Resolver((type) => SampleType) export class SampleResolver { @Query((type) => SampleType) QueryApplicationContext(@Ctx() ctx: IContext): SampleType { console.log(ctx.reqCtx.header['authorization']); return { SampleField: 'SampleField', Child: { ChildField: 'ChildField', }, }; } } ``` 加载方式仍然保持一致: ``` import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import { IMidwayKoaApplication } from '@midwayjs/koa'; @Configuration({ importConfigs: ['./config'], }) export class ContainerConfiguration implements ILifeCycle { @App() app: IMidwayKoaApplication; async onReady(container: IMidwayContainer): Promise { this.app.use( // Use extend middleware await this.app.generateMiddleware('extend:GraphQLKoaMiddleware') ); } async onStop(): Promise {} } ``` ## 注意事项[​](#注意事项 "注意事项的直接链接") * TypeGraphQL 支持使用外部 IoC 容器,因此你可以在 Resolver Class 中自然的使用 Midway 的依赖注入体系,但请确保使 `Resolver` 类中使用了 `Provide` 装饰器。在 Serverless 中, 容器来自于请求上下文,即`context.requestContext`,而在 Node 应用中,容器来自于应用上下文,即 `app.getApplicationContext`。 * 你也可以使用 `resolvers: [path.resolve(this.app.getBaseDir(), "resolvers/*")]` 的形式一次性加载所有指定目录下的 resolver,但注意的是,请关闭 `tsconfig.json` 中的 `declaration` `inlineSourceMap` `sourceMap` 选项,避免 `.d.ts` 与 `.js.map` 文件以及 `inlineSourceMap` 被错误的进行读取而导致报错。 * 对于集团内部用户,由于 FaaS 默认的构建器强制要求 sourceMap 启用,你可以直接导入 Resolver 类或使用 `resolvers/${ process.env.NODE_ENV === 'development' ? '*.ts' : '*.js' }` 加载。 ## 自动生成 TypeGraphQL 类型定义[​](#自动生成-typegraphql-类型定义 "自动生成 TypeGraphQL 类型定义的直接链接") 对于从 RESTFul API 迁移,或已有确定的接口文件格式,你可以使用 [json-type-graphql](https://github.com/LinbuduLab/json-to-type-graphql) 这个库(与 Apollo-Server-Midway 是同一个作者)来进行一些自动化的代码生成,最简单的使用如图所示: ``` import transformer from 'json-type-graphql'; import path from 'path'; (async () => { await transformer({ reader: { url: 'http://127.0.0.1:7001/', }, writter: { outputPath: path.join(__dirname, './generated.ts'), }, }); })(); ``` 以上代码会生成这样一个文件: ``` import { ObjectType, Field, Int, ID } from 'type-graphql'; @ObjectType() export class Root { @Field() success!: boolean; @Field() message!: string; } ``` 目前,json-to-type-graphql 提供了以下能力: * 使用对象、JSON 文件或者是 URL 作为数据源 * 支持自定义的预处理器(pre-processer)、后处理器(post-processer)来 hook 进入执行逻辑内部 * 支持嵌套的对象,以及数组入口的 JSON(如 `[{},{}]`) * 支持对具有父子关系的 Class 进行排序,如`P-C1-C11-C12-C2-C21-C3-C31`. * 支持 Class 名的前缀与后缀配置,支持 TypeGraphQL `@Field()` 装饰器的 ReturnType 如果你在使用 Prisma 作为 ORM,你也可以使用 [typegraphql-prisma](https://github.com/MichalLytek/typegraphql-prisma) 这个库(来自于 TypeGraphQL 作者)来从 Prisma Schema 生成 TypeGraphQL Class、Resolver。 ## 配置[​](#配置 "配置的直接链接") ### Serverless[​](#serverless "Serverless的直接链接") * `context`: 必传,使用 FaaS Context 即可。 * `path`:GraphQL API 路径,默认为`/graphql`。 * `app`:FaaS 应用实例。 * `prodPlayground`:即便在生产环境也开启 GraphQL Playground,同时会开启 `introspection` 选项。 * `appendFaaSContext`:将 FaaS 上下文也注入到 GraphQL Context 中,可通过 TypeGraphQL `@Ctx` 装饰器获取。 * `builtInPlugins`:见 内置插件定义。 * `apollo`:支持的 Apollo Server 选项,参考类型定义。 * `schema`:支持的 TypeGraphQL buildSchemaSync 选项,参考类型定义。 * `disableHealthCheck`:禁用 Apollo Server 内置的 Health Check。 * `onHealthCheck`:自定义 Apollo Server 内置的 Health Check 行为。 * `disableHealthResolver`:禁用内置 的 Health Check Resolver。 ### Node[​](#node "Node的直接链接") * `path`:GraphQL API 路径,默认为`/graphql`。 * `prodPlayground`:即便在生产环境也开启 GraphQL Playground,同时会开启 `introspection` 选项。 * `appendApplicationContext`:将应用上下文也注入到 GraphQL Context 中,可通过 TypeGraphQL `@Ctx` 装饰器获取。 * `builtInPlugins`:见 内置的插件选项。 * `apollo`:支持的 Apollo Server 选项。 * `schema`:支持的 TypeGraphQL buildSchemaSync 选项。 * `disableHealthCheck`:禁用 Apollo Server 内置的 Health Check。 * `onHealthCheck`:自定义 Apollo Server 内置的 Health Check 行为,Koa 与 Express 下的具体入参不同。 * `cors`:在 Koa 下等同于 `@koa/cors` 配置,在 Express 下等同于 `cors` 配置。 * `bodyParserConfig`:在 Koa 下等同于 `koa-bodyparser` 配置,在 Express 下等同于 `body-parser` 配置。 ### 内置插件[​](#内置插件 "内置插件的直接链接") * `resolveTime` 将请求消耗的时间在 GraphQL Extensions 中返回 * `enabled`:是否启用 * `queryComplexity` 检查 GraphQL Query 的复杂度 * `enable`:是否启用 * `maxComlexity`:最大复杂度 * `throwOnMaximum`:在超出最大复杂度时,是否抛出错误 * `contextExtension`:将 Midway Container 的信息以及应用上下文信息在 GraphQL Extensions 中返回,用于 DEBUG * `enabled`:是否启用 * `printSchema`:将 API 使用的 GraphQL Schema 在 GraphQL Extensions 中返回 * `enable`:是否启用 * `sort`:是否进行词法排序(`lexicographicSortSchema`) ### 配置类型定义[​](#配置类型定义 "配置类型定义的直接链接") ``` export type UsableApolloOption = Pick< ApolloServerConfig, | 'persistedQueries' | 'plugins' | 'context' | 'formatError' | 'formatResponse' | 'rootValue' | 'dataSources' | 'introspection' | 'mocks' | 'mockEntireSchema' | 'schema' >; export type UsableBuildSchemaOption = Pick< BuildSchemaOptions, 'authChecker' | 'authMode' | 'dateScalarMode' | 'globalMiddlewares' | 'nullableByDefault' | 'skipCheck' | 'resolvers' >; export type BuiltInPluginConfiguration = { /** * Enable Apollo-Resolve-Time plugin to report GraphQL resolving time as GraphQL Extension. */ resolveTime?: { enable?: boolean; }; /** * Enable Apollo-Query-Complexity plugin to report GraphQL query complexity as GraphQL Extension, * and reject request when query complexity is greater than configurated. */ queryComplexity?: { enable?: boolean; maxComlexity?: number; throwOnMaximum?: boolean; }; /** * Enable plugin to send back `MidwayJS Container` information、Application Context as GraphQL Extension. */ contextExtension?: { enable?: boolean; }; /** * Enable plugin to send back generated `GraphQL Schema` as GraphQL Extension. */ printSchema?: { enable?: boolean; sort?: boolean; }; }; export type CreateGraphQLMiddlewareOption = { /** * GraphQL API path */ path?: string; /** * Enable GraphQL Playground even in production. * Requires `apollo.introspection` to be true for working correctly. */ prodPlaygound?: boolean; /** * Add `Application Context` to GraphQL Context which you can get in GraphQL Resolvers. */ appendApplicationContext?: boolean; /** * Built-In plugin options. */ builtInPlugins?: BuiltInPluginConfiguration; /** * Supported ApolloServer options. */ apollo?: UsableApolloOption; /** * Supported TyepeGraphQL buildSchemaSync options. */ schema?: UsableBuildSchemaOption & Pick; /** * Disable Apollo-Server health check. */ disableHealthCheck?: boolean; }; export interface CreateKoaGraphQLMiddlewareOption extends CreateGraphQLMiddlewareOption { /** * CORS options, equal to @koa/cors options. */ cors?: CORSOptions | boolean; /** * Customize health check handler. */ onHealthCheck?: KoaServerRegistration['onHealthCheck']; /** * BodyParser options, equal to koa-bodyparser options. */ bodyParserConfig?: BodyParserOptions | boolean; } export interface CreateExpressGraphQLMiddlewareOption extends CreateGraphQLMiddlewareOption { /** * CORS options, equal to cors options. */ cors?: corsMiddleware.CorsOptions | corsMiddleware.CorsOptionsDelegate | boolean; /** * Customize health check handler. */ onHealthCheck?: ExpressServerRegistration['onHealthCheck']; /** * BodyParser options, equal to bodyparser options. */ bodyParserConfig?: OptionsJson | boolean; } export type CreateApolloHandlerOption = { /** * Required. FaaS Context. */ context: Context; /** * GraphQL API path */ path?: string; /** * FaaS Application. */ app?: IMidwayFaaSApplication; /** * Enable GraphQL Playground even in production. * Requires `apollo.introspection` to be true for working correctly. */ prodPlaygound?: boolean; /** * Add `FaaS Context` to GraphQL Context which you can get in GraphQL Resolvers. */ appendFaaSContext?: boolean; /** * Built-In plugin options. */ builtInPlugins?: BuiltInPluginConfiguration; /** * Supported ApolloServer options. */ apollo?: UsableApolloOption; /** * Supported TyepeGraphQL buildSchemaSync options. */ schema?: UsableBuildSchemaOption; /** * Disable Apollo-Server health check. */ disableHealthCheck?: boolean; /** * Disable Built-In health check resolver. */ disableHealthResolver?: boolean; /** * Customize health check handler. */ onHealthCheck?: (req: MidwayReq) => Promise; }; ``` --- # gRPC gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 本篇内容演示了如何在 Midway 体系下,提供 gRPC 服务,以及调用 gRPC 服务的方法。 Midway 当前采用了最新的 gRPC 官方推荐的 [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) 进行开发,并提供了一些工具包,用于快速发布服务和调用服务。 我们使用的模块为 `@midwayjs/grpc` ,既是一个框架(可以独立发布服务),又是一个组件(可以接入其它框架调用 gRPC 服务)。 ## 创建示例[​](#创建示例 "创建示例的直接链接") ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=grpc my_midway_app # 如果是 npm v7 $ npm init midway -- --type=grpc my_midway_app ``` 此示例包含一个 gRPC 服务。 ## 目录结构[​](#目录结构 "目录结构的直接链接") ``` . ├── package.json ├── proto ## proto 定义文件 │   └── helloworld.proto ├── src │   ├── configuration.ts ## 入口配置文件 │   ├── interface.ts │   └── provider ## gRPC 提供服务的文件 │   └── greeter.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 定义服务接口[​](#定义服务接口 "定义服务接口的直接链接") 在微服务中,定义一个服务需要特定的接口定义语言(IDL)来完成,在 gRPC 中 默认使用 Protocol Buffers 作为序列化协议。 序列化协议独立于语言和平台,提供了多种语言的实现,Java,C++,Go 等等,每一种实现都包含了相应语言的编译器和库文件。所以 gRPC 是一个提供和调用都可以跨语言的服务框架。 一个 gRPC 服务的大体架构可以用官网上的一幅图表示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612885948978-1d2ce3ba-66a6-4372-b220-84ffc8202bc1.png#height=445\&id=YAYtB\&originHeight=445\&originWidth=621\&originalType=binary\&size=0\&status=done\&style=none\&width=621) Protocol Buffers 协议的文件,默认的后缀为 `.proto` 。.proto 后缀的 IDL 文件,并通过其编译器生成特定语言的数据结构、服务端接口和客户端 Stub 代码。 信息 由于 proto 文件可以跨语言使用,为了方便共享,我们一般将 proto 文件放在 src 目录外侧,方便其他工具复制分发。 下面是一个基础的 `proto/helloworld.proto`  文件。 ``` syntax = "proto3"; package helloworld; service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } ``` proto3 表示的是第三版的 protobuf 协议,是 gRPC 目前推荐的版本,“语法简单,功能更全”。 我们可以用 `service`  格式,定义服务体,其中可以包含方法。同时,我们可以更加细致的通过 `message`  描述服务具体的请求参数和响应参数。 我们可以从 [Google 的官网文档](https://developers.google.com/protocol-buffers/docs/overview#simple) 中查看更多细节。 信息 大家会看到,这和 Java 中的 Class 非常相像,每个结构就相当于 Java 中的一个类。 ### 编写 proto 文件[​](#编写-proto-文件 "编写 proto 文件的直接链接") 现在我们再来看之前的服务,是不是就很好理解了。 ``` syntax = "proto3"; package helloworld; // 服务的定义 service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // 服务的请求参数 message HelloRequest { string name = 1; } // 服务的响应参数 message HelloReply { string message = 1; } ``` 我们定义了一个名为 `Greeter`  的服务,包含一个 `HelloRequest`  结构的请求体,以及返回 `HelloReply`  结构的响应体。 接下去,我们将对这个服务给大家做演示。 ### 生成代码定义[​](#生成代码定义 "生成代码定义的直接链接") 传统的 gRPC 框架,需要用户手动编写 proto 文件,以及生成 js 服务,最后再根据 js 生成的服务再编写实现,在 Midway 体系下,我们提供了一个 grpc-helper 工具包来加速这个过程。 如果没有安装,可以先安装(脚手架示例中已带)。 ``` $ npm i @midwayjs/grpc-helper --save-dev ``` grpc-helper 工具的作用,是将用户提供的 proto 文件,生成对应可读的 ts interface 文件。 我们可以添加一个脚本,方便这个过程。 ``` { "scripts": { "generate": "tsproto --path proto --output src/domain" } } ``` 然后执行 `npm run generate` 。 上述命令执行后,会在代码的 `src/domain`  目录中生成 proto 文件对应的服务接口定义。 信息 不管是提供 gRPC 服务还是调用 gRPC 服务,都要先生成定义。 生成的代码如下,包含有一个命名空间(namespace),以及命名空间下的两个 TypeScript Interface, `Greeter`  用于编写服务端实现, `GreeterClient`  用于编写客户端实现。 ``` /** * This file is auto-generated by grpc-helper */ import * as grpc from '@midwayjs/grpc'; // 生成的命名空间 export namespace helloworld { // 服务端使用的定义 export interface Greeter { // Sends a greeting sayHello(data: HelloRequest): Promise; } // 客户端使用的定义 export interface GreeterClient { // Sends a greeting sayHello(options?: grpc.IClientOptions): grpc.IClientUnaryService; } // 请求体结构 export interface HelloRequest { name?: string; } // 响应体结构 export interface HelloReply { message?: string; } } ``` 信息 每当 proto 文件被修改时,就需要重新生成对应的服务定义,然后将对应的方法实现。 ## 提供 gRPC 服务(Provider)[​](#提供-grpc-服务provider "提供 gRPC 服务(Provider)的直接链接") ### 编写生产者(Provider)[​](#编写生产者provider "编写生产者(Provider)的直接链接") 在 `src/provider`  目录中,我们创建 `greeter.ts` ,内容如下。 ``` import { MSProviderType, Provider, Provide, GrpcMethod } from '@midwayjs/decorator'; import { helloworld } from '../domain/helloworld'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provide() @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { return { message: 'Hello ' + request.name }; } } ``` 信息 注意,@Provider 装饰器和 @Provide 装饰器不同,前者用于提供服务,后者用于依赖注入容器扫描标识的类。 我们使用 `@Provider`  暴露出一个 RPC 服务, `@Provider`  的第一个参数为 RPC 服务类型,这个参数是个枚举,这里选择 GRPC 类型。 `@Provider` 的第二个参数为 RPC 服务的元数据,这里指代的是 gRPC 服务的元数据。这里需要写入 gRPC 的 package 字段,即 proto 文件中的 package 字段(这里的字段用于和 proto 文件加载后的字段做对应)。 对于普通的 gRPC 服务接口(UnaryCall),我们只需要使用 `@GrpcMethod()`  装饰器修饰即可。修饰的方法即为服务定义本身,入参为 proto 中定义好的入参,return 值即为定义好的响应体。 信息 注意,生成的 Interface 是为了更好的编写服务代码,规范结构,请务必按照定义编写。 ### 启动 gRPC 服务[​](#启动-grpc-服务 "启动 gRPC 服务的直接链接") 这里启动需要用到项目根目录 `bootstrap.js`  独立文件。代码和其他框架初始化类似,只是这里的框架包是 `@midwayjs/grpc` 。 内容如下: ``` // 获取框架 const { Framework } = require('@midwayjs/grpc'); const { join } = require('path'); // 初始化框架 const grpcService = new Framework().configure({ services: [ { protoPath: join(__dirname, 'proto/helloworld.proto'), package: 'helloworld', }, ], }); // 使用 bootstrap 启动 const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.load(grpcService).run(); ``` 我们已经将启动命令写到了 start 脚本中,执行 `npm run start`  即可。 ``` "scripts": { "start": "NODE_ENV=production node ./bootstrap.js", }, ``` 信息 在部署前,需要执行 npm run build 将 ts 代码编译为 js。 ### 框架选项[​](#框架选项 "框架选项的直接链接") `@midwayjs/grpc`  作为框架启动时,可以传递的参数如下: | url | string | 可选,gRPC 服务连接字符串,默认为 localhost:6565 | | ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | services | IGRPCServiceOptions\[] | 必选,数组,需要暴露的 gRPC 服务信息,每个服务对应一个 proto 文件 | | loaderOptions | object | 可选,使用  @grpc/proto-loader 加载的选项,具体参考[这里](https://github.com/grpc/grpc-node/blob/master/packages/proto-loader/README.md),默认为 | `{   keepCase: true,  longs: String,  enums: String,  defaults: true,  oneofs: true, }` | | credentials | ServerCredentials | 可选,服务凭证,值参考[这里](https://grpc.github.io/grpc/node/grpc.ServerCredentials.html),默认值为 ServerCredentials.createInsecure() | services 字段是数组,意味着 Midway 项目可以同时发布多个 gRPC 服务。每个 service 的结构为: | protoPath | string | 必选,proto 文件的绝对路径 | | --------- | ------ | -------------------------- | | package | string | 必选,服务对应的 package | | | | | ### 编写单元测试[​](#编写单元测试 "编写单元测试的直接链接") `@midwayjs/grpc`  库提供了一个 `createGRPCConsumer`  方法,用于实时调用客户端,一般我们用这个方法做测试。 警告 这个方法每次调用会实时连接,不建议将该方法用在生产环境。 在测试中写法如下。 ``` import { createApp, close } from '@midwayjs/mock'; import { Framework, createGRPCConsumer } from '@midwayjs/grpc'; import { join } from 'path'; import { helloworld } from '../src/domain/helloworld'; describe('test/index.test.ts', () => { it('should create multiple grpc service in one server', async () => { const baseDir = join(__dirname, '../'); // 创建服务 const app = await createApp(baseDir, { services: [ { protoPath: join(baseDir, 'proto', 'helloworld.proto'), package: 'helloworld', }, ], }); // 调用服务 const service = await createGRPCConsumer({ package: 'helloworld', protoPath: join(baseDir, 'proto', 'helloworld.proto'), url: 'localhost:6565', }); const result = await service.sayHello().sendMessage({ name: 'harry', }); expect(result.message).toEqual('Hello harry'); await close(app); }); }); ``` ## 调用 gRPC 服务(Consumer)[​](#调用-grpc-服务consumer "调用 gRPC 服务(Consumer)的直接链接") 我们编写一个 gRPC 服务来调用上面的暴露的服务。 信息 事实上,你可以在 Web 的 Controller,或者 Service 等其他地方来调用,这里只是做一个示例。 ### 增加组件[​](#增加组件 "增加组件的直接链接") `@midwayjs/grpc`  库即是 Framework,又是组件,在作为组件引入时,需要在 `src/configuration.ts`  中配置。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as grpc from '@midwayjs/grpc'; import { join } from 'path'; @Configuration({ imports: [grpc], importConfigs: [join(__dirname, './config')], }) export class AutoConfiguration {} ``` ### 提供调用配置[​](#提供调用配置 "提供调用配置的直接链接") 你需要在 `src/config/config.default.ts`  中增加你需要调用的目标服务以及它的 proto 文件信息。 比如,这里我们填写了上面暴露的服务本身,以及该服务的 proto,包名等信息。 ``` // src/config/config.default.ts import { DefaultConfig } from '@midwayjs/grpc'; import { join } from 'path'; export const grpc = { services: [ { url: 'localhost:6565', protoPath: join(__dirname, '../../proto/helloworld.proto'), package: 'helloworld', }, ], } as DefaultConfig; ``` ### 代码调用[​](#代码调用 "代码调用的直接链接") 配置完后,我们就可以在代码里调用了。 `@midwayjs/grpc`  提供了 `clients` ,可以方便的获取到已配置的服务。我们只需要在需要注入的地方,注入这个对象即可。 比如: ``` import { Provide, Inject } from '@midwayjs/decorator'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; } ``` 我们通过 `clients`  获取到对方服务的客户端实例,然后调用即可。 ``` import { Provide, Inject } from '@midwayjs/decorator'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; async invoke() { // 获取服务 const greeterService = this.grpcClients.getService('helloworld.Greeter'); // 调用服务 const result = await greeterService.sayHello().sendMessage({ name: 'harry', }); // 返回结果 return result; } } ``` 我们也可以利用 `@Init`  装饰器,将需要调用的服务缓存到属性上。这样可以在其他方法调用时复用。 示例如下。 ``` import { GrpcMethod, MSProviderType, Provider, Provide, Inject, Init } from '@midwayjs/decorator'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() @Provider(MSProviderType.GRPC, { package: 'hero' }) export class HeroService implements hero.HeroService { // 注入客户端 @Inject() grpcClients: Clients; greeterService: helloworld.Greeter; @Init() async init() { // 赋值一个服务实例 this.greeterService = this.grpcClients.getService('helloworld.Greeter'); } @GrpcMethod() async findOne(data) { // 调用服务 const result = await greeterService.sayHello().sendMessage({ name: 'harry', }); // 返回结果 return result; } } ``` ## 流式服务[​](#流式服务 "流式服务的直接链接") gRPC 的流式服务用于减少连接,让服务端或者客户端不需要等待即可执行任务,从而提高执行效率。 gRPC 的流式服务分为三种,以服务端角度来说,为 * 服务端接收流(客户端推) * 服务端响应流(服务端推) * 双向流 下面我们将一一介绍。 ### 流式 proto 文件[​](#流式-proto-文件 "流式 proto 文件的直接链接") 流式的 proto 文件写法不同,需要在希望使用流式的地方将参数标记为 `stream` 。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; int32 num = 2; } message Num { int32 id = 1; int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } // 双向流 rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 该服务生成的接口定义为: ``` import { IClientDuplexStreamService, IClientReadableStreamService, IClientUnaryService, IClientWritableStreamService, IClientOptions, } from '@midwayjs/grpc'; export namespace math { export interface AddArgs { id?: number; num?: number; } export interface Num { id?: number; num?: number; } /** * server interface */ export interface Math { add(data: AddArgs): Promise; addMore(data: AddArgs): Promise; // 服务端推,客户端读 sumMany(data: AddArgs): Promise; // 客户端端推,服务端读 addMany(num: AddArgs): Promise; } /** * client interface */ export interface MathClient { add(options?: IClientOptions): IClientUnaryService; addMore(options?: IClientOptions): IClientDuplexStreamService; // 服务端推,客户端读 sumMany(options?: IClientOptions): IClientReadableStreamService; // 客户端端推,服务端读 addMany(options?: IClientOptions): IClientWritableStreamService; } } ``` ### 服务端推送[​](#服务端推送 "服务端推送的�直接链接") 客户端调用一次,服务端可以多次返回。通过 `@GrpcMethod()`  的参数来标识流式类型。 可用的类型为: * `GrpcStreamTypeEnum.WRITEABLE`  服务端输出流(单工) * `GrpcStreamTypeEnum.READABLE`  客户端输出流(单工),服务端接受多次 * `GrpcStreamTypeEnum.DUPLEX`  双工流 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provide, Provider } from '@midwayjs/decorator'; import { Context } from '@midwayjs/grpc'; import { math } from '../interface'; import { Metadata } from '@grpc/grpc-js'; /** */ @Provide() @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({ type: GrpcStreamTypeEnum.WRITEABLE }) async sumMany(args: math.AddArgs) { this.ctx.write({ num: 1 + args.num, }); this.ctx.write({ num: 2 + args.num, }); this.ctx.write({ num: 3 + args.num, }); this.ctx.end(); } // ... } ``` 服务端使用 `ctx.write`  方法来返回数据,由于是服务端流,可以返回多次。 返回结束后,请使用 `ctx.end()`  方法关闭流。 客户端,调用一次,接受多次数据。 比如下面的累加逻辑。 Promise 写法,会等待服务端数据都返回再做处理。 ``` // 服务端推送 let total = 0; let result = await service.sumMany().sendMessage({ num: 1, }); result.forEach((data) => { total += data.num; }); // total = 9; ``` 事件写法,实时处理。 ``` // 服务端推送 let call = service.sumMany().getCall(); call.on('data', (data) => { // do something }); call.sendMessage({ num: 1, }); ``` ### 客户端推送[​](#客户端推送 "客户端推送的直接链接") 客户端调用多次,服务端接收多次数据,返回一个结果。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.READABLE})` 的参数来标识流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provide, Provider } from '@midwayjs/decorator'; import { Context } from '@midwayjs/grpc'; import { math } from '../interface'; import { Metadata } from '@grpc/grpc-js'; /** */ @Provide() @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { sumDataList: number[] = []; @Inject() ctx: Context; @GrpcMethod({ type: GrpcStreamTypeEnum.READABLE, onEnd: 'sumEnd' }) async addMany(data: math.Num) { this.sumDataList.push(data); } async sumEnd(): Promise { const total = this.sumDataList.reduce((pre, cur) => { return { num: pre.num + cur.num, }; }); return total; } // ... } ``` 客户端每次调用,都会触发一次 `addMany` 方法。 在客户端发送 `end`  事件之后,会调用 `@GrpcMethod`  装饰器上的 `onEnd`  参数指定的方法,该方法的返回值即为最后客户端拿到的值。 客户端示例如下: ``` // 客户端推送 const data = await service.addMany().sendMessage({ num: 1 }).sendMessage({ num: 2 }).sendMessage({ num: 3 }).end(); // data.num = 6 ``` ### 双向流[​](#双向流 "双向流的直接链接") 客户端可以调用多次,服务端也可以接收多次数据,返回多个结果,类似于传统的 TCP 通信。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.DUPLEX})` 的参数来标识双工流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provide, Provider } from '@midwayjs/decorator'; import { Context } from '@midwayjs/grpc'; import { math } from '../interface'; import { Metadata } from '@grpc/grpc-js'; /** */ @Provide() @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({ type: GrpcStreamTypeEnum.DUPLEX, onEnd: 'duplexEnd' }) async addMore(message: math.AddArgs) { this.ctx.write({ id: message.id, num: message.num + 10, }); } async duplexEnd() { console.log('got client end message'); } // ... } ``` 服务端可以随时使用 `ctx.write`  返回数据,也可以使用 `ctx.end`  来关闭流。 客户端示例: 对于双工通信的客户端,由于无法保证调用、返回的顺序,我们需要使用监听的模式来消费结果。 ``` const clientStream = service.addMore().getCall(); let total = 0; let idx = 0; duplexCall.on('data', (data: math.Num) => { total += data.num; idx++; if (idx === 2) { duplexCall.end(); // total => 29 } }); duplexCall.write({ num: 3, }); duplexCall.write({ num: 6, }); ``` 如果希望保证调用顺序,我们也提供了保证顺序的双向流调用方法,但是需要在 proto 中定义一个固定的 id,来确保顺序。 比如我们的 Math.proto,对每个入参和出参,都增加了一个固定的 id,所以可以固定顺序。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } message Num { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 固定顺序的客户端调用方式如下: ``` // 保证顺序的双向流 const t = service.addMore(); const result4 = await new Promise((resolve, reject) => { let total = 0; // 第一次调用和返回 t.sendMessage({ num: 2, }) .then((res) => { expect(res.num).toEqual(12); total += res.num; }) .catch((err) => console.error(err)); // 第二次调用和返回 t.sendMessage({ num: 5, }) .then((res) => { expect(res.num).toEqual(15); total += res.num; resolve(total); }) .catch((err) => console.error(err)); t.end(); }); // result4 => 27 ``` 默认的 id 为 `id` ,如果服务端定义不同,需要修改,可以在客户端调用时传递。 ``` // 保证顺序的双向流 const t = service.addMore({ messageKey: 'uid', }); ``` ## 元数据(Metadata)[​](#元数据metadata "元数据(Metadata)的直接链接") gRPC 的元数据等价于 HTTP 的上下文。 服务端通过 `ctx.sendMetadata`  方法返回元数据,也可以通过 `ctx.metadata` 获取客户端传递的元数据。 ``` import { MSProviderType, Provider, Provide, GrpcMethod } from '@midwayjs/decorator'; import { helloworld } from '../domain/helloworld'; import { Metadata } from '@grpc/grpc-js'; import { Context } from '@midwayjs/grpc'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provide() @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @Inject() ctx: Context; @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { // 客户端传递的元数据 console.log(this.ctx.metadata); // 创建元数据 const meta = new Metadata(); this.ctx.metadata.add('xxx', 'bbb'); this.ctx.sendMetadata(meta); return { message: 'Hello ' + request.name }; } } ``` 客户端通过方法的 options 参数传递元数据。 ``` import { Metadata } from '@grpc/grpc-js'; const meta = new Metadata(); meta.add('key', 'value'); const result = await service .sayHello({ metadata: meta, }) .sendMessage({ name: 'harry', }); ``` 获取元数据相对麻烦一些。 普通一元调用(UnaryCall)获取元数据需要使用 `sendMessageWithCallback`  方法。 ``` const call = service.sayHello().sendMessageWithCallback( { name: 'zhangting', }, (err) => { if (err) { reject(err); } } ); call.on('metadata', (meta) => { // output meta }); ``` 其他流式服务,可以通过 `getCall()`  方法获取原始客户端流对象,从而直接订阅。 ``` // 获取服务,注意,这里没有 await const call = service.addMany().getCall(); call.on('metadata', (meta) => { // output meta }); ``` ## 超时处理[​](#超时处理 "超时处理的直接链接") 我们可以在调用服务时传递参数,单位毫秒。 ``` const result = await service .sayHello({ timeout: 5000, }) .sendMessage({ name: 'harry', }); ``` --- # MongoDB 在这一章节中,我们选择 [Typegoose](https://github.com/typegoose/typegoose) 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 简单的来说,Typegoose 使用 TypeScript 编写 Mongoose 模型的 “包装器”,它的大部分能力还是由 [mongoose](https://www.npmjs.com/package/mongoose) 库来提供的。 也可以直接选择 [mongoose](https://www.npmjs.com/package/mongoose) 库来使用,我们会分别描述。 ## Mongoose 版本依赖[​](#mongoose-版本依赖 "Mongoose 版本依赖的直接链接") mongoose 和你服务器使用的 MongoDB Server 的版本也有着一定的关系,如下,请务必注意。 * MongoDB Server 2.4.x: mongoose ^3.8 or 4.x * MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x * MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x * MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x * MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x * MongoDB Server 3.6.x: mongoose 5.x * MongoDB Server 4.0.x: mongoose ^5.2.0 * MongoDB Server 4.2.x: mongoose ^5.7.0 * MongoDB Server 4.4.x: mongoose ^5.10.0 * MongoDB Server 5.x: mongoose ^6.0.0 **mongoose 相关的依赖比较复杂,且对应不同的版本,现阶段,我们使用的主要是 mongoose v5 和 v6。** 信息 从 mongoose\@v5.11.0 开始,mongoose 官方支持了定义,所以不再需要安装 @types/mongoose 依赖包。 安装包依赖版本如下: **支持 MongoDB Server 5.x** ``` "dependencies": { "mongoose": "^6.0.7", "@typegoose/typegoose": "^9.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 4.4.x** 以下版本不需要安装额外定义包。 ``` "dependencies": { "mongoose": "^5.13.3", "@typegoose/typegoose": "^8.0.0", // 使用 typegoose 需要安装此依赖 }, ``` 以下版本需要安装额外定义包(不推荐)。 ``` "dependencies": { "mongodb": "3.6.3", // mongoose 内部写死了该版本 "mongoose": "~5.10.18", "@typegoose/typegoose": "^7.0.0", // 使用 typegoose 需要安装此依赖 }, "devDependencies": { "@types/mongodb": "3.6.3", // 只能使用此版本 "@types/mongoose": "~5.10.3", } ``` 其余的 MongoDB 安装模块类似,未测。 ## 使用 Typegoose[​](#使用-typegoose "使用 Typegoose的直接链接") ### 1、安装组件[​](#1安装组件 "1、安装组件的直接链接") 安装 Typegoose 组件,提供访问 MongoDB 的能力。 **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/typegoose@2 --save ``` 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as typegoose from '@midwayjs/typegoose'; @Configuration({ imports: [ typegoose, // 加载 typegoose 组件 ], importConfigs: [join(__dirname, './config')], }) export class ContainerConfiguration {} ``` 信息 在该组件中,midway 只是做了简单的配置规则化,并将其注入到初始化流程中。 ### 2、配置连接信息[​](#2配置连接信息 "2、配置连接信息的直接链接") 在 `src/config/config.default.ts`  中加入连接的配置。 ``` export const mongoose = { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********', }, }, }; ``` ### 3、简单的目录结构[​](#3简单的目录结构 "3、简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── user.ts // 实体文件 │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ### 3、创建实体文件[​](#3创建实体文件 "3、创建实体文件的直接链接") ``` import { prop } from '@typegoose/typegoose'; import { EntityModel } from '@midwayjs/typegoose'; @EntityModel() export class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 等价于使用 mongoose 的下列代码 ``` const userSchema = new mongoose.Schema({ name: String, jobs: [{ type: String }], }); const User = mongoose.model('User', userSchema); ``` 信息 所以说,typegoose 只是简化了 model 的创建过程。 ### 4、引用实体,调用数据库[​](#4引用实体调用数据库 "4、引用实体,调用数据库的��直接链接") 示例代码如下: ``` import { Provide } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/typegoose'; import { ReturnModelType } from '@typegoose/typegoose'; import { User } from '../entity/user'; @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; async getTest() { // create data const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties // find data const user = await this.userModel.findById(id).exec(); console.log(user); } } ``` ### 5、多库的情况[​](#5多库的情况 "5、多库的情况的直接链接") 首先配置多个连接。 在 `src/config/config.default.ts`  中加入连接的配置,`default` 代表了默认的连接。 ``` export const mongoose = { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********', }, }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********', }, }, }, }; ``` 定义实例时使用固定的连接,比如: ``` @EntityModel() // 默认使用了 default 连接 class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } @EntityModel({ connectionName: 'db1', // 这里使用了 db1连接 }) class User2 { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 在使用时,注入特定的连接 ``` @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; @InjectEntityModel(User2) user2Model: ReturnModelType; async getTest() { const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties const user = await this.userModel.findById(id).exec(); console.log(user); const { _id: id2 } = await this.user2Model.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User2); // an "as" assertion, to have types for all properties const user2 = await this.user2Model.findById(id2).exec(); console.log(user2); } } ``` ## 直接使用 mongoose[​](#直接使用-mongoose "直接使用 mongoose的直接链接") mongoose 组件是 typegoose 的基础组件,有时候我们可以直接使用它。 ### 1、安装组件[​](#1安装组件-1 "1、安装组件的直接链接") **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/mongoose@2 --save ``` ### 2、开启组件[​](#2开启组件 "2、开启组件的直接链接") 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as mongoose from '@midwayjs/mongoose'; @Configuration({ imports: [ mongoose, // 加载 mongoose 组件 ], importConfigs: [join(__dirname, './config')], }) export class ContainerConfiguration {} ``` ### 2、配置[​](#2配置 "2、配置的直接链接") 和 typegoose 相同,或者说 typegoose 使用的就是 mongoose 的配置。 单库: ``` export const mongoose = { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '**********', }, }, }; ``` 多库: ``` export const mongoose = { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********', }, }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********', }, }, }, }; ``` ### 3、使用[​](#3使用 "3、使用的直接链接") 在只有一个默认连接或者直接使用 default 连接时,我们可以直接使用封装好的 `MongooseConnectionService` 对象来创建 model。 ``` import { Provide, Inject } from '@midwayjs/decorator'; import { MongooseConnectionService } from '@midwayjs/mongoose'; import { Schema, Document } from 'mongoose'; interface User extends Document { name: string; email: string; avatar: string; } @Provide() export class TestService { @Inject() conn: MongooseConnectionService; async invoke() { const schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, avatar: String, }); const UserModel = this.conn.model('User', schema); const doc = new UserModel({ name: 'Bill', email: 'bill@initech.com', avatar: 'https://i.imgur.com/dM7Thhn.png', }); await doc.save(); } } ``` 如果配置了多个其他连接,请从工厂方法中获取连接后再使用。 ``` import { MongooseConnectionServiceFactory } from '@midwayjs/mongoose'; import { Schema } from 'mongoose'; @Provide() export class TestService { @Inject() connFactory: MongooseConnectionServiceFactory; async invoke() { // get db1 connection const conn = this.connFactory.get('db1'); // get default connection const defaultConn = this.connFactory.get('default'); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、E002: You are using a NodeJS Version below 12.22.0[​](#1e002-you-are-using-a-nodejs-version-below-12220 "1、E002: You are using a NodeJS Version below 12.22.0的直接链接") 在新版本 @typegoose/typegoose (v8, v9) 中增加了 Node 版本的校验,如果你的 Node.js 版本低于 v12.22.0,就会出现这个提示。 普通情况下,请升级 Node.js 到这个版本以上即可解决。 在特殊场景下,比如 Serverless 无法修改 Node.js 版本且版本低于 v12.22 的情况下,由于 v12 版本子版本其实都可以,可以通过临时修改 process.version 绕过。 ``` // src/configuration.ts Object.defineProperty(process, 'version', { value: 'v12.22.0', writable: true, }); // other code export class AutoConfiguration {} ``` --- # Database(TypeORM) [TypeORM](https://github.com/typeorm/typeorm)  是  `node.js`  现有社区最成熟的对象关系映射器(`ORM` )。Midway 和 TypeORM 搭配,使开发更简单。 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 orm 组件,提供数据库 ORM 能力。 ``` npm i @midwayjs/orm@2 typeorm --save ``` 信息 当前已升级为 2.x 版本,变化见[这里](https://www.yuque.com/midwayjs/report/v2.11.5#rhgpV)。 ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts`  引入 orm 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as orm from '@midwayjs/orm'; import { join } from 'path'; @Configuration({ imports: [ orm, // 加载 orm 组件 ], importConfigs: [join(__dirname, './config')], }) export class ContainerConfiguratin {} ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 信息 To make the\*\* Oracle driver work\*\*, you need to follow the installation instructions from [their](https://github.com/oracle/node-oracledb) site. ## 简单的目录结构[​](#简单的目录结构 "简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── photo.ts // 实体文件 │ │ └── photoMetadata.ts │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity`  目录(非强制),这只是一个简单的约定。 ## 入门[​](#入门 "入门的直接链接") 下面,我们将以 mysql 举例。 ### ### 1、创建 Model[​](#1创建-model "1、创建 Model的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `photo`  举例。新建 entity 目录,在其中添加实体文件 `photo.ts` ,一个简单的实体如下。 ``` // entity/photo.ts export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 ### 2、添加实体模型装饰器[​](#2添加实体模型装饰器 "2、添加实体模型装饰器的直接链接") 我们使用 `EntityModel`  来定义一个实体模型类。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 警告 注意,这里的 EntityModel 是 midway 做了封装的特殊装饰器,为了和 midway 更好的结合使用。请不要直接使用 typeorm 中的 Entity。 如果表名和当前的实体名不同,可以在参数中指定。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo_table_name') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 这些实体列也可以使用 [typeorm\_generator](/docs/2.0.0/extensions/typeorm_generator) 工具生成。 ### 3、添加数据库列[​](#3添加数据库列 "3、添加数据库列的直接链接") 通过 typeorm 提供的 `@Column`  装饰器来修饰属性,每一个属性对应一个列。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column } from 'typeorm'; @EntityModel() export class Photo { @Column() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` 现在 `id` , `name` , `description` ,`filename` , `views` , `isPublished`  列将添加到 `photo`  表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 `@Column`装饰器中显式指定列类型来使用数据库支持的任何列类型。 我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。 数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 [官方文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/entities.md#%E5%88%97%E9%80%89%E9%A1%B9)。 ### 4、创建主键列[​](#4创建主键列 "4、创建主键列的直接链接") 每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 `@PrimaryColumn`  装饰器。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 5、创建自增主键列[​](#5创建自增主键列 "5、创建自增主键列的直接链接") 现在,如果要设置自增的 id 列,需要将 `@PrimaryColumn`  装饰器更改为 `@PrimaryGeneratedColumn`  装饰器: ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 6、列数据类型[​](#6列数据类型 "6、列数据类型的直接链接") 接下来,让我们调整数据类型。默认情况下,字符串映射到类似 `varchar(255)`  的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column({ length: 100, }) name: string; @Column('text') description: string; @Column() filename: string; @Column('double') views: number; @Column() isPublished: boolean; } ``` 示例,不同列名 ``` @Column({ length: 100, name: 'custom_name' }) name: string; ``` 此外还有有几种特殊的列类型可以使用: * `@CreateDateColumn` 是一个特殊列,自动为实体插入日期。 * `@UpdateDateColumn` 是一个特殊列,在每次调用实体管理器或存储库的 save 时,自动更新实体日期。 * `@VersionColumn` 是一个特殊列,在每次调用实体管理器或存储库的 save 时自动增长实体版本(增量编号)。 * `@DeleteDateColumn` 是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。 列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](https://github.com/typeorm/typeorm/blob/master/docs/entities.md#column-types)。 ### 7、配置连接信息[​](#7配置连接信息 "7、配置连接信息的直接链接") 请参考 [配置](/docs/2.0.0/env_config.md) 章节,增加配置文件。 然后在 `config.default.ts`  中配置数据库连接信息。 ``` /** * 单数据库实例 */ export const orm = { type: 'mysql', host: '', port: 3306, username: '', password: '', database: undefined, synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true logging: false, }; ``` 默认存储的是 utc 时间(推荐)。 也可以配置时区(不建议) ``` export const orm = { // ... timezone: '+08:00', }; ``` 这个 `type` 字段你可以使用其他的数据库类型,包括`mysql`, `mariadb`, `postgres`, `cockroachdb`, `sqlite`, `mssql`, `oracle`, `cordova`, `nativescript`, `react-native`, `expo`, or `mongodb` 比如 sqlite,则只需要以下信息。 ``` export const orm = { type: 'sqlite', database: path.join(__dirname, '../../test.sqlite'), synchronize: true, logging: true, }; ``` 信息 注意:synchronize 字段用于同步表结构。使用 `synchronize: true` 进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。 ### 8、使用 Model 插入数据库数据[​](#8使用-model-插入数据库数据 "8、使用 Model 插入数据库数据的直接链接") 在常见的 Midway 文件中,使用 `@InjectEntityModel`  装饰器注入我们配置好的 Model。我们所需要做的只是: * 1、创建实体对象 * 2、执行 save() ``` import { Provide } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // save async savePhoto() { // create a entity object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // save entity const photoResult = await this.photoModel.save(photo); // save success console.log('photo id = ', photoResult.id); } } ``` ### 9、查询数据[​](#9查询数据 "9、查询数据的直接链接") 更多的查询参数,请查询 [find 文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/find-options.md)。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhotos() { // find All let allPhotos = await this.photoModel.find(); console.log('All photos from the db: ', allPhotos); // find first let firstPhoto = await this.photoModel.findOne(1); console.log('First photo from the db: ', firstPhoto); // find one by name let meAndBearsPhoto = await this.photoModel.findOne({ name: 'Me and Bears' }); console.log('Me and Bears photo from the db: ', meAndBearsPhoto); // find by views let allViewedPhotos = await this.photoModel.find({ views: 1 }); console.log('All viewed photos: ', allViewedPhotos); let allPublishedPhotos = await this.photoModel.find({ isPublished: true }); console.log('All published photos: ', allPublishedPhotos); // find and get count let [allPhotos, photosCount] = await this.photoModel.findAndCount(); console.log('All photos: ', allPhotos); console.log('Photos count: ', photosCount); } } ``` ### 10、更新数据库[​](#10更新数据库 "10、更新数据库的直接链接") 现在,让我们从数据库中加载一个 Photo,对其进行更新并保存。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { let photoToUpdate = await this.photoModel.findOne(1); photoToUpdate.name = 'Me, my friends and polar bears'; await this.photoModel.save(photoToUpdate); } } ``` ### 11、删除数据[​](#11删除数据 "11、删除数据的直接链接") ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { /*...*/ let photoToRemove = await this.photoModel.findOne(1); await this.photoModel.remove(photoToRemove); } } ``` 现在,ID = 1 的 Photo 将从数据库中删除。 此外还有软删除的方法。 ``` await this.photoModel.softDelete(1); ``` ### 12、创建一对一关联[​](#12创建一对一关联 "12、创建一对一关联的直接链接") 让我们与另一个类创建一对一的关系。让我们在 `entity/photoMetadata.ts`  中创建一个新类。这个类包含 photo 的其他元信息。 ``` import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { EntityModel } from '@midwayjs/orm'; import { Photo } from './photo'; @EntityModel() export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column('int') height: number; @Column('int') width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string; @OneToOne((type) => Photo) @JoinColumn() photo: Photo; } ``` 在这里,我们使用一个名为 `@OneToOne`  的新装饰器。它允许我们在两个实体之间创建一对一的关系。`type => Photo`是一个函数,它返回我们要与其建立关系的实体的类。 由于语言的特殊性,我们被迫使用一个返回类的函数,而不是直接使用该类。我们也可以将其写为 `() => Photo`  ,但是我们使用 `type => Photo`作为惯例来提高代码的可读性。类型变量本身不包含任何内容。 我们还添加了一个 `@JoinColumn`装饰器,它指示关系的这一侧将拥有该关系。关系可以是单向或双向的。关系只有一方可以拥有。关系的所有者端需要使用@JoinColumn 装饰器。 如果您运行该应用程序,则会看到一个新生成的表,该表将包含一列,其中包含用于 Photo 关系的外键。 ``` +-------------+--------------+----------------------------+ | photo_metadata | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | height | int(11) | | | width | int(11) | | | comment | varchar(255) | | | compressed | boolean | | | orientation | varchar(255) | | | photoId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 接下去我们要在代码中关联他们。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(PhotoMetadata) photoMetadataModel: Repository; async updatePhoto() { // create a photo let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.isPublished = true; // create a photo metadata let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = 'cybershoot'; metadata.orientation = 'portrait'; metadata.photo = photo; // this way we connect them // first we should save a photo await this.photoModel.save(photo); // photo is saved. Now we need to save a photo metadata await this.photoMetadataModel.save(metadata); // done console.log('Metadata is saved, and relation between metadata and photo is created in the database too'); } } ``` ### 13、反向关系映射[​](#13反向关系映射 "13、反向关系映射的直接链接") 关系映射可以是单向或双向的。当在 PhotoMetadata 和 Photo 之间的关系是单向的。关系的所有者是 PhotoMetadata,而 Photo 对 PhotoMetadata 是一无所知的。这使得从 Photo 端访问 PhotoMetadata 变得很复杂。若要解决此问题,我们添加一个反向的关系映射,使 PhotoMetadata 和 Photo 之间变成双向关联。让我们修改我们的实体。 ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo'; @EntityModel() export class PhotoMetadata { /* ... other columns */ @OneToOne((type) => Photo, (photo) => photo.metadata) @JoinColumn() photo: Photo; } ``` ``` import { EntityModel } from '@midwayjs/orm'; import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from 'typeorm"; import { PhotoMetadata } from './photoMetadata'; @EntityModel() export class Photo { /* ... other columns */ @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo) metadata: PhotoMetadata; } ``` `photo => photo.metadata`  是一个返回反向映射关系的函数。在这里,我们显式声明 Photo 类的 metadata 属性用于关联 PhotoMetadata。除了传递返回 photo 属性的函数外,您还可以直接将字符串传递给 `@OneToOne`  装饰器,例如 `“metadata”` 。但是我们使用了这种函数回调的方法来让我们的代码写法更简单。 请注意,只会在关系映射的一侧使用 `@JoinColumn`  装饰器。无论您放置此装饰器的哪一侧,都是关系的所有者。关系的拥有方在数据库中包含带有外键的列。 ### 14、加载对象及其依赖关系[​](#14加载对象及其依赖关系 "14、加载对象及其依赖关系的直接链接") 现在,让我们尝试在单个查询中一起加载出 Photo 和 PhotoMetadata。有两种方法可以执行此操作,使用 `find *`  方法或使用 `QueryBuilder`  功能。让我们首先使用 `find *`  方法。 `find *`  方法允许您使用 `FindOneOptions`  / `FindManyOptions`  接口指定对象。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel.find({ relations: ['metadata'] }); } } ``` 在这里,photos 的值是一个数组,包含了整个数据库的查询结果,并且每个 photo 对象都包含其关联的 metadata 属性。在[此文档](https://github.com/typeorm/typeorm/blob/master/docs/find-options.md)中了解有关 `Find Options`  的更多信息。 使用 `Find Options` 很简单,但如果需要更复杂的查询,则应改用 `QueryBuilder` 。 `QueryBuilder`  允许以优雅的方式使用更复杂的查询。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel .createQueryBuilder('photo') .innerJoinAndSelect('photo.metadata', 'metadata') .getMany(); } } ``` `QueryBuilder`允许创建和执行几乎任何复杂的 SQL 查询。使用 `QueryBuilder`  时,请像创建 SQL 查询一样思考。在此示例中,“photo” 和 “metadata” 是应用于所选 photos 的别名。您可以使用别名来访问所选数据的列和属性。 ### 15、使用级联操作自动保存关联对象[​](#15使用级联操作自动保存关联对象 "15、使用级联操作自动保存关联对象的直接链接") 在我们希望在每次保存另一个对象时都自动保存关联的对象,这个时候可以在关系中设置级联。让我们稍微更改照片的 `@OneToOne`  装饰器。 ``` export class Photo { /// ... other columns @OneToOne((type) => PhotoMetadata, (metadata) => metadata.photo, { cascade: true, }) metadata: PhotoMetadata; } ``` 使用 `cascade` 允许我们现在不再单独保存 Photo 和 PhotoMetadata,由于级联选项,元数据对象将被自动保存。 ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { // create photo object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.isPublished = true; // create photo metadata object let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = 'cybershoot'; metadata.orientation = 'portrait'; photo.metadata = metadata; // this way we connect them // save a photo also save the metadata await this.photoModel.save(photo); // done console.log('Photo is saved, photo metadata is saved too'); } } ``` 注意,我们现在设置 Photo 的元数据,而不需要像之前那样设置元数据的 Photo 属性。这仅当您从 Photo 这边将 Photo 连接到 PhotoMetadata 时,级联功能才有效。如果在 PhotoMetadata 侧设置,则不会自动保存。 ### 16、创建多对一/一对多关联[​](#16创建多对一一对多关联 "16、创建多对一/一对多关联的直接链接") 让我们创建一个多对一/一对多关系。假设一张照片有一个作者,每个作者可以有很多照片。首先,让我们创建一个 Author 类: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from 'typeorm'; import { Photo } from './entity/photo'; @EntityModel() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany((type) => Photo, (photo) => photo.author) // note: we will create author property in the Photo class below photos: Photo[]; } ``` `Author`  包含了一个反向关系。 `OneToMany`  和 `ManyToOne`  需要成对出现。 现在,将关系的所有者添加到 Photo 实体中: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata'; import { Author } from './author'; @Entity() export class Photo { /* ... other columns */ @ManyToOne((type) => Author, (author) => author.photos) author: Author; } ``` 在多对一/一对多关系中,所有者方始终是多对一。这意味着使用 `@ManyToOne`  的类将存储相关对象的 ID。 运行应用程序后,ORM 将创建 `author`  表: ``` +-------------+--------------+----------------------------+ | author | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | +-------------+--------------+----------------------------+ ``` 它还将修改 `photo`  表,添加新的 `author`  列并为其创建外键: ``` +-------------+--------------+----------------------------+ | photo | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | | description | varchar(255) | | | filename | varchar(255) | | | isPublished | boolean | | | authorId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` ### 17、创建多对多关联[​](#17创建多对多关联 "17、创建多对多关联的直接链接") 让我们创建一个多对一/多对多关系。假设一张照片可以在许多相册中,并且每个相册可以包含许多照片。让我们创建一个 `Album`  类。 ``` import { EntityModel } from '@midwayjs/orm'; import { PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm'; @EntityModel() export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany((type) => Photo, (photo) => photo.albums) @JoinTable() photos: Photo[]; } ``` `@JoinTable`  用来指明这是关系的所有者。 现在,将反向关联添加到 `Photo` 。 ``` export class Photo { /// ... other columns @ManyToMany((type) => Album, (album) => album.photos) albums: Album[]; } ``` 运行应用程序后,ORM 将创建一个 album\_photos\_photo\_albums 联结表: ``` +-------------+--------------+----------------------------+ | album_photos_photo_albums | +-------------+--------------+----------------------------+ | album_id | int(11) | PRIMARY KEY FOREIGN KEY | | photo_id | int(11) | PRIMARY KEY FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 现在,让我们将相册和照片插入数据库: ``` import { Provide, Inject, Func } from '@midwayjs/decorator'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(Album) albumModel: Repository; async updatePhoto() { // create a few albums let album1 = new Album(); album1.name = 'Bears'; await this.albumModel.save(album1); let album2 = new Album(); album2.name = 'Me'; await this.albumModel.save(album2); // create a few photos let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.albums = [album1, album2]; await this.photoModel.save(photo); // now our photo is saved and albums are attached to it // now lets load them: const loadedPhoto = await this.photoModel.findOne(1, { relations: ['albums'] }); } } ``` `loadedPhoto`  的值为: ``` { "id": 1, "name": "Me and Bears", "description": "I am near polar bears", "filename": "photo-with-bears.jpg", "albums": [ { "id": 1, "name": "Bears" }, { "id": 2, "name": "Me" } ] } ``` ### [​](#-1 "-1的直接链接") ### 18、使用 QueryBuilder[​](#18使用-querybuilder "18、使用 QueryBuilder的直接链接") 您可以使用 QueryBuilder 来构建几乎任何复杂的 SQL 查询。例如,您可以这样做: ``` let photos = await this.photoModel .createQueryBuilder('photo') // first argument is an alias. Alias is what you are selecting - photos. You must specify it. .innerJoinAndSelect('photo.metadata', 'metadata') .leftJoinAndSelect('photo.albums', 'album') .where('photo.isPublished = true') .andWhere('(photo.name = :photoName OR photo.name = :bearName)') .orderBy('photo.id', 'DESC') .skip(5) .take(10) .setParameters({ photoName: 'My', bearName: 'Mishka' }) .getMany(); ``` 该查询选择所有带有 “My” 或 “Mishka” 名称的已发布照片。它将从位置 5 开始返回结果(分页偏移),并且将仅选择 10 个结果(分页限制)。选择结果将按 ID 降序排列。该照片的相册将 left-Joined,元数据将自动关联。 您将在应用程序中大量使用查询生成器。在 [此处](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/select-query-builder.md) 了解有关 QueryBuilder 的更多信息。 ### 19、Event Subscriber[​](#19event-subscriber "19、Event Subscriber的直接链接") typeorm 提供了一个事件订阅机制,方便在做一些数据库操作时的日志输出,为此 midway 提供了一个 `EventSubscriberModel`  装饰器,用来标注事件订阅类,代码如下。 ``` import { Provide } from '@midwayjs/decorator'; import { EventSubscriberModel } from '@midwayjs/orm'; import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm'; @Provide() @EventSubscriberModel() export class EverythingSubscriber implements EntitySubscriberInterface { /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { console.log(`BEFORE ENTITY INSERTED: `, event.entity); } /** * Called before entity insertion. */ beforeUpdate(event: UpdateEvent) { console.log(`BEFORE ENTITY UPDATED: `, event.entity); } /** * Called before entity insertion. */ beforeRemove(event: RemoveEvent) { console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity insertion. */ afterInsert(event: InsertEvent) { console.log(`AFTER ENTITY INSERTED: `, event.entity); } /** * Called after entity insertion. */ afterUpdate(event: UpdateEvent) { console.log(`AFTER ENTITY UPDATED: `, event.entity); } /** * Called after entity insertion. */ afterRemove(event: RemoveEvent) { console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity is loaded. */ afterLoad(entity: any) { console.log(`AFTER ENTITY LOADED: `, entity); } } ``` 这个订阅类提供了一些常用的接口,用来在数据库操作时执行一些事情。 ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 多数据库支持[​](#多数据库支持 "多数据库支持的直接链接") 有时候,我们一个应用中会有多个数据库连接(Connection)的情况,这个时候会有多个配置。我们使用**对象的形式**来定义配置。 比如下面定义了 `default`  和 `test`  两个数据库连接(Connection)。 ``` import { join } from 'path'; export default { orm: { default: { type: 'sqlite', database: join(__dirname, '../../default.sqlite'), logging: true, }, test: { type: 'mysql', host: '127.0.0.1', port: 3306, username: '*********', password: '*********', database: undefined, synchronize: true, logging: false, }, }, }; ``` 在使用时,需要指定模型归属于哪个连接(Connection)。 ``` // entity/photo.ts import { InjectEntityModel } from '@midwayjs/orm'; import { User } from './model/user'; export class XXX { @InjectEntityModel(User, 'test') testUserModel: Repository; //... } ``` 同样的,在使用注入 Model 时,需要指定连接。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo', { connectionName: 'test', }) export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` ### 获取连接池[​](#获取连接池 "获取连接池的直接链接") ``` import { Configuration } from '@midwayjs/decorator'; import { getConnection } from 'typeorm'; @Configuration() export class AutoConfiguration { async onReady() { const conn = getConnection('default'); console.log(conn.isConnected); } } ``` ### Hooks 场景支持[​](#hooks-场景支持 "Hooks 场景支持的直接链接") 针对函数式编程的场景,我们提供了简化的函数式写法。 ``` import { useEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; export async function getPhoto() { // get model const photoModel = useEntityModel(Photo); const photo = new Photo(); // create entity photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // find const newPhoto = await photoModel.save(photo); return 'hello world'; } ``` ### 关于表结构同步[​](#关于表结构同步 "关于表结构同步的直接链接") * 如果你已有表结构,想自动创建 Entity,使用 [生成器](/docs/2.0.0/extensions/typeorm_generator) * 如果已经有 Entity 代码,想创建表结构请使用配置中的 `synchronize: true` 。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Handshake inactivity timeout[​](#handshake-inactivity-timeout "Handshake inactivity timeout的直接链接") 一般是网络原因,如果本地出现,可以 ping 但是 telnet 不通,可以尝试执行如下命令: ``` sudo sysctl -w net.inet.tcp.sack=0 ``` ### [​](#-2 "-2的直接链接") ### 关于 mysql 时间列的当前时区展示[​](#关于-mysql-时间列的当前时区展示 "关于 mysql 时间列的当前时区展示的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,一般情况下,数据库中保存的是 UTC 时间,如果你希望返回当前时区的时间,可以使用下面的方式。 在配置时,开启时间转字符串的选项。 ``` // src/config/config/default config.orm = { //... dateStrings: true, }; ``` 实体中的时间列需要列类型。 ``` @EntityModel() export class Photo { //... @UpdateDateColumn({ name: 'gmt_modified', type: 'timestamp', }) gmtModified: Date; @CreateDateColumn({ name: 'gmt_create', type: 'timestamp', }) gmtCreate: Date; } ``` 这样,输出的时间字段就是当前的时区了。 效果如下: **配置前:** ``` gmtModified: 2021-12-13T03:49:43.000Z, gmtCreate: 2021-12-13T03:49:43.000Z ``` **配置后:** ``` gmtModified: '2021-12-13 11:49:43', gmtCreate: '2021-12-13 11:49:43' ``` ### 关于时间列的默认值[​](#关于时间列的默认值 "关于时间列的默认值的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,那么注意,typeorm 是在建表语句中自动添加了默认值,如果表是用户自建的,该字段会由于没有默认值而写入 00:00:00 的时间。 解决方案有两个 **1、修改表的默认值** 或者 **2、修改代码中列的默认值** **如果不想修改表,而想修改代码,请参考下面的代码。** ``` @Column({ default: () => "NOW()", type: 'timestamp' }) createdOn: Date; @Column({ default: () => "NOW()", type: 'timestamp' }) modifiedOn: Date; ``` --- # 对象存储(OSS) 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 `@midwayjs/oss` 组件就是在 midway 体系下用于对接 OSS 服务的 sdk。 ## 前置条件[​](#前置条件 "前置条件的直接链接") 使用 OSS 组件,你需要提前申请一个 OSS Bucket。Bucket 是 OSS 的存储库的概念,你的文件都将存储在这个库里。 * OSS 对象存储官网: * 什么是对象存储: ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/oss` 是主要的功能包,`@types/ali-oss` 是 oss 的官方定义包。 ``` $ npm i @midwayjs/oss@2 --save $ npm i @types/ali-oss --save-dev // 安装到 dev 依赖 ``` 如果发现 OSSService 没有方法定义,请务必检查此项。 ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as oss from '@midwayjs/oss'; import { join } from 'path'; @Configuration({ imports: [ oss, // 导入 oss 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` ## 配置 OSS[​](#配置-oss "配置 OSS的直接链接") OSS 组件需要配置后才能使用。需要填写 OSS 的 bucket、accessKeyId、accessKeySecret 等必要信息。 支持普通 oss 客户端和 oss 集群客户端,基于 [ali-oss](https://github.com/ali-sdk/ali-oss/) 这个包。 比如: **普通的 oss bucket 配置** ``` // normal oss bucket export const oss = { client: { accessKeyId: 'your access key', accessKeySecret: 'your access secret', bucket: 'your bucket name', endpoint: 'oss-cn-hongkong.aliyuncs.com', timeout: '60s', }, }; ``` **集群(cluster) 模式的 oss bucket 配置,需要配置多个** ``` // need to config all bucket information under cluster export const oss = { client: { cluster: [ { endpoint: 'host1', accessKeyId: 'id1', accessKeySecret: 'secret1', }, { endpoint: 'host2', accessKeyId: 'id2', accessKeySecret: 'secret2', }, ], schedule: 'masterSlave', //default is `roundRobin` timeout: '60s', }, }; ``` **sts 模式** ``` // if config.sts == true, oss will create STS client export const oss = { client: { sts: true, accessKeyId: 'your access key', accessKeySecret: 'your access secret', }, }; ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 可以直接获取 `OSSService`,然后调用接口,比如,保存文件。 ``` import { OSSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossService: OSSService; async saveFile() { const localFile = join(__dirname, 'test.log'); const result = await this.ossService.put('/test/test.log', localFile); // => result.url } } ``` 如果配置的是 STS 模式,客户端可以使用 `OSSSTSService` 。 ``` import { OSSSTSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() stsService: OSSSTSService; async saveFile() { const roleArn = '******'; // 这里是阿里云角色的 arn const result = await this.stsService.assumeRole(roleArn); // result.credentials.AccessKeyId // result.credentials.AccessKeySecret; // result.credentials.SecurityToken; } } ``` 更多的 OSS 客户端 API,请查看 [OSS 文档](https://github.com/ali-sdk/ali-oss)。 ## 使用多个 OSS Bucket[​](#使用多个-oss-bucket "使用多个 OSS Bucket的直接链接") 有些应用需要访问多个 oss bucket,那么就需要配置 `oss.clients`。 ``` export const oss = { clients: { bucket1: { bucket: 'bucket1', }, bucket2: { bucket: 'bucket2', }, }, // shared by client, clients and createInstance default: { endpoint: '', accessKeyId: '', accessKeySecret: '', }, }; export const bucket3 = { bucket: 'bucket3', }; ``` 可以使用 `OSSServiceFactory` 获取不同的实例。 ``` import { OSSServiceFactory } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossServiceFactory: OSSServiceFactory; @Config('bucket3') bucket3Config; async saveFile() { // 默认获取的类型是 OSSService const bucket1 = this.ossServiceFactory.get('bucket1'); const bucket2 = this.ossServiceFactory.get('bucket2'); // 如果是 STS,需要设置泛型联系 // const bucket1 = this.ossServiceFactory.get('bucket1'); // 会合并 config.bucket3 和 config.oss.default const bucket3 = await this.ossServiceFactory.createInstance(this.bucket3Config, 'bucket3'); // 传了名字之后也可以从 factory 中获取 bucket3 = this.ossServiceFactory.get('bucket3'); } } ``` --- # Passport 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Node.js 中最流行的 Passport 库。 Passport 是通过称为策略的可扩展插件进行身份验证请求。Passport 不挂载路由或假设任何特定的数据库,这最大限度地提高了灵活性并允许开发人员做出应用程序级别的决策。 ## 准备[​](#准备 "准备的直接链接") 1. 安装 `npm i @midwayjs/passport` ``` $ npm i @midwayjs/passport@2 passport --save $ npm i @types/passport --save-dev ``` 2. 如果你需要保存到 session 中,开启相对应框架的 session 功能 ## 使用[​](#使用 "使用的直接链接") 这里我们以本地认证,和 JWT 作为演示,这里用到了另一个 JWT 组件。 首先 ``` // src/configuration.ts import { ILifeCycle } from '@midwayjs/core'; import { Configuration } from '@midwayjs/decorator'; import * as jwt from '@midwayjs/jwt'; import * as passport from '@midwayjs/passport'; @Configuration({ imports: [jwt, passport], // ... }) export class ContainerLifeCycle implements ILifeCycle {} ``` ### e.g. 本地策略[​](#eg-本地策略 "e.g. 本地策略的直接链接") 我们可以通过 `@CustomStrategy` 和派生 `PassportStrategy`来 自启动一个策略。通过 validate 钩子来获取有效负载,并且此函数必须有返回值,其参数并不明确,可以参考对应的 Strategy 或者通过展开符打印查看。 ``` // strategy/local.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import * as bcrypt from 'bcrypt'; @CustomStrategy() export class LocalStrategy extends PassportStrategy(Strategy) { async validate(user, password) { // 实际的秘钥 const password = '*********'; // 和用户的秘钥做对比 const isLegalUser = await bcrypt.compare(password, user.password); if (!isLegalUser) { throw new Error('error password ' + user.name); } return { user, password, }; } // 当前策略的参数 getStrategyOptions(): any { return { passwordField: 'pwd', }; } } ``` 之后派生`PassportMiddleware`出一个中间件。 ``` // local-middleware.ts import { Inject, Provide } from '@midwayjs/decorator'; import { PassportMiddleware } from '@midwayjs/passport'; import { Context } from '@midwayjs/express'; @Provide('local') // 此处可以使用一个简短的identifier export class LocalPassportMiddleware extends PassportMiddleware(LocalStrategy) { // 设置 AuthenticateOptions getAuthenticateOptions(): Promise | passport.AuthenticateOptions { return { failureRedirect: '/login', presetProperty: 'user', }; } } ``` ``` // controller.ts import { Provide, Post, Inject, Controller } from '@midwayjs/decorator'; @Provide() @Controller('/') export class LocalController { @Post('/passport/local', { middleware: ['local'] }) async localPassport() { console.log('local user: ', this.ctx.req.user); return this.ctx.req.user; } } ``` 使用 curl 模拟一次请求。 ``` curl -X POST http://localhost:7001/passport/local -d '{"username": "demo", "pwd": "1234"}' -H "Content-Type: application/json" 结果 {"username": "demo", "pwd": "1234"} ``` ### 注意,express 的用户信息会保存到 `req.user` ,而 koa/egg 会保存到 `ctx.state.user` 。 ### [​](#-1 "-1的直接链接") ### e.g. Jwt[​](#eg-jwt "e.g. Jwt的直接链接") 首先需要 **额外安装** 依赖和策略: ``` $ npm i @midwayjs/jwt passport-jwt --save ``` 然后在 config.ts 中配置, 默认未加密,请不要把敏感信息存放在 payload 中。 ``` export const jwt = { secret: 'xxxxxxxxxxxxxx', // fs.readFileSync('xxxxx.key') expiresIn: '2d', // https://github.com/vercel/ms }; ``` ``` // jwt-strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; @CustomStrategy() export class JwtStrategy extends PassportStrategy(Strategy) { @Config('jwt') jwtConfig; async validate(payload) { return payload; } getStrategyOptions(): any { return { secretOrKey: this.jwtConfig.secret, jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), }; } } ``` ``` // jwt-middleware.ts import { Provide } from '@midwayjs/decorator'; import { PassportMiddleware } from '@midwayjs/passport'; @Provide() export class JwtPassportMiddleware extends PassportMiddleware(JwtStrategy) { getAuthenticateOptions(): Promise | passport.AuthenticateOptions { return {}; } } ``` ``` import { Provide, Post, Inject } from '@midwayjs/decorator'; import { Controller, Post } from '@midwayjs/decorator'; import { JwtService } from '@midwayjs/jwt'; @Provide() @Controller('/') export class JwtController { @Inject() jwt: JwtService; @Inject(); ctx: any; @Post('/passport/jwt', { middleware: ['jwtPassportMiddleware'] }) async jwtPassport() { console.log('jwt user: ', this.ctx.req.user); return this.ctx.req.user; } @Post('/jwt') async genJwt() { return { t: await this.jwt.sign({ msg: 'Hello Midway' }), }; } } ``` 使用 curl 模拟请求 ``` curl -X POST http://127.0.0.1:7001/jwt 结果 {"t": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} curl http://127.0.0.1:7001/passport/jwt -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 结果 {"msg": "Hello Midway","iat": 1635468727,"exp": 1635468827} ``` ## 自定义其他策略[​](#自定义其他策略 "自定义其他策略的直接链接") `@midwayjs/passport` 支持自定义[其他策略](http://www.passportjs.org/packages/),这里以 Github OAuth 为例。 首先需要安装相应的 passport 库。 ``` $ npm i passport-github --save ``` 编写如下策略代码: ``` // github-strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, StrategyOptions } from 'passport-github'; const GITHUB_CLIENT_ID = 'xxxxxx', GITHUB_CLIENT_SECRET = 'xxxxxxxx'; @CustomStrategy() export class GithubStrategy extends PassportStrategy(Strategy) { async validate(...payload) { return payload; } getStrategyOptions() { return { clientID: GITHUB_CLIENT_ID, clientSecret: GITHUB_CLIENT_SECRET, callbackURL: 'https://127.0.0.1:7001/auth/github/cb', }; } } ``` 提供一个中间件 ``` // github-middleware.ts import { PassportMiddleware } from '@midwayjs/passport'; @Provide() export class GithubPassportMiddleware extends PassportMiddleware {} ``` ``` // controller.ts import { Provide, Get, Inject } from '@midwayjs/decorator'; @Provide() @Controller('/oauth') export class AuthController { @Inject() ctx: any; @Get('/github', { middleware: ['githubPassportMiddleware'] }) async githubOAuth() {} @Get('/github/cb', { middleware: ['githubPassportMiddleware'] }) async githubOAuthCallback() { return this.ctx.req.user; } } ``` ## 一些相关资料[​](#一些相关资料 "一些相关资料的直接链接") * [JWT 入门](https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html) --- # 进程共享(ProcessAgent) midway 封装了 `@midwayjs/process-agent` 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 举例: * 如果使用 pm2、cluster、多进程进行部署方式,使用内存的 cache,那这个 cache 在自己的进程内。 * prometheus,获取 `/metrics` 的时候,需要把所有进程的数据收集上来,而不是某个进程的 * 健康检查,如果有 4 个进程,如果有一个进程不正常了,健康检查应该检查失败。 ## 安装方法[​](#安装方法 "安装方法的直接链接") 使用方法: ``` $ npm install @midwayjs/process-agent@2 -S ``` `configuration.ts` 使用方法: ``` import * as processAgent from '@midwayjs/process-agent'; @Configuration({ imports: [processAgent], }) export class ContainerLifeCycle {} ``` ## 使用方法[​](#使用方法 "使用方法的直接链接") 业务代码 UserService: ``` import { Provide, Inject } from '@midwayjs/decorator'; import { TestService } from './test'; @Provide() export class UserService { @Inject() testService: TestService; async getUser() { let result = await this.testService.setData(1); return result; } } ``` 然后调用 testService 的时候,希望只在主进程执行: ``` import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; import { RunInPrimary } from '@midwayjs/process-agent'; @Provide() @Scope(ScopeEnum.Singleton) export class TestService { data: any = 0; @RunInPrimary() async setData(b) { this.data = b; return this.data; } @RunInPrimary() async getData() { return this.data; } } ``` 注意,执行返回的数据只限于可序列化的数据,比如普通 JSON,不支持包含方法等无法序列化的数据。 ## 效果描述[​](#效果描述 "效果描述的直接链接") 假设采用 pm2 或者 egg-script 等多进程方式启动,假设这是个请求 首先: * 1、设置 setData * 2、然后获取 getData 如果没有 RunInPrimary 这个装饰器,那请求可能落在进程 2,或者进程 3,那可能没有获取更新的 data。 所以 RunInPrimary 能确保这个函数执行能落到主进程去。 ## 功能征集[​](#功能征集 "功能征集的直接链接") 如果有其他类似相关功能,觉得可以放在这个包里面的,欢迎在评论区,或者 [issue](https://github.com/midwayjs/midway/issues) 里面帮忙提一下,我们会跟大家一起讨论和实现。 --- # RabbitMQ 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务 A 负责产生消息给消息队列,而服务 B 则负责消费消息队列中的任务。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1610433906644-871308e0-01de-4f33-a9b2-b9c53fc362be.png#crop=0\&crop=0\&crop=1\&crop=1\&height=174\&id=im7Ob\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=251\&originWidth=646\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=26456\&status=done\&style=none\&title=\&width=448) 在 Midway 中,我们提供了订阅 rabbitMQ 的能力,专门来满足用户的这类需求。 ## 基础概念[​](#基础概念 "基础概念的直接链接") RabbitMQ 的概念较为复杂,其基于高级消息队列协议即 Advanced Message Queuing Protocol(AMQP),如果第一次接触请阅读一下相关的参考文档。 AMQP 有一些概念,Queue、Exchange 和 Binding 构成了 AMQP 协议的核心,包括: * Producer:消息生产者,即投递消息的程序。 * Broker:消息队列服务器实体。 * Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。 * Binding:绑定,它的作用就是把 Exchange 和 Queue 按照路由规则绑定起来。 * Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 * Consumer:消息消费者,即接受消息的程序。 简单的理解,消息通过 Publisher 发布到 Exchange(交换机),Consumer 通过订阅 Queue 来接受消息,Exchange 和 Queue 通过路由做连接。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1623914924280-ad0d2f20-018f-4d5e-9825-1120c52c747f.png#clientId=u2ace4f48-26d7-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=328\&id=uaa4f930a\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=328\&originWidth=700\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=59458\&status=done\&style=none\&taskId=ua324994f-d9b2-414c-960a-d20c5824834\&title=\&width=700) ## 消费者(Consumer)使用方法[​](#消费者consumer使用方法 "消费者(Consumer)使用方法的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") Midway 提供了订阅 rabbitMQ 的能力,并能够独立部署和使用。安装 `@midwayjs/rabbitmq`  模块及其定义。 ``` $ npm i @midwayjs/rabbitmq@2 amqplib --save $ npm i @types/amqplib --save-dev ``` ### 入口函数[​](#入口函数 "入口函数的直接链接") 和 Web 一样,创建一个入口文件,指定 Framework 即可。 ``` // server.js const { Bootstrap } = require('@midwayjs/bootstrap'); const RabbitMQFramework = require('@midwayjs/rabbitmq').Framework; const rabbitMQFramework = new RabbitMQFramework().configure({ url: 'amqp://localhost', }); Bootstrap.load(rabbitMQFramework).run(); ``` 整个启动的配置为: ``` export type IMidwayRabbitMQConfigurationOptions = { url: string | Options.Connect; socketOptions?: any; reconnectTime?: number; }; ``` | url | rabbitMQ 的连接信息 | | ------------- | -------------------------------- | | socketOptions | amqplib.connect 的第二个参数 | | reconnectTime | 队列断连后的重试时间,默认 10 秒 | ### 订阅 rabbitMQ[​](#订阅-rabbitmq "订阅 rabbitMQ的直接链接") 我们一般把能力分为生产者和消费者,而订阅正是消费者的能力。 我们一般把消费者放在 consumer 目录。比如 `src/consumer/userConsumer.ts`  。 ``` ➜ my_midway_app tree . ├── src │ ├── consumer │ │ └── userConsumer.ts │ ├── interface.ts │ └── service │ └── userService.ts ├── test ├── package.json └── tsconfig.json ``` 代码示例如下。 ``` import { Provide, Consumer, MSListenerType, RabbitMQListener, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Provide() @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @Inject() ctx: Context; @RabbitMQListener('tasks') async gotData(msg: ConsumeMessage) { this.ctx.channel.ack(msg); } } ``` `@Consumer`  装饰器,提供消费者标识,并且它的参数,指定了某种消费框架的类型,比如,我们这里指定了 `MSListenerType.RABBITMQ`  这个类型,指的就是 rabbitMQ 类型。 标识了 `@Consumer`  的类,对方法使用 `@RabbitMQListener`  装饰器后,可以绑定一个 RabbitMQ 的队列(Queue)。 方法的参数为接收到的消息,类型为 `ConsumeMessage` 。如果返回值需要确认,则需要对服务端进行 `ack`  操作,明确接收到的数据。 如果需要订阅多个队列,可以使用多个方法,也可以使用多个文件。 ### RabbitMQ 消息上下文[​](#rabbitmq-消息上下文 "RabbitMQ 消息上下文的直接链接") 订阅 `RabbitMQ`  数据的上下文,和 Web 同样的,其中包含一个 `requestContext` ,和每次接收消息的数据绑定。 从 ctx 上可以取到 `channel` ,整个 ctx 的定义为: ``` export type Context = { channel: amqp.Channel; requestContext: IMidwayContainer; }; ``` 可以从框架获取定义 ``` import { Context } from '@midwayjs/rabbitmq'; ``` ### Fanout Exchange[​](#fanout-exchange "Fanout Exchange的直接链接") Fanout 是一种特定的交换机,如果满足匹配(binding),就往 Exchange 所绑定的 Queue 发送消息。Fanout Exchange 会忽略 RoutingKey 的设置,直接将 Message 广播到所有绑定的 Queue 中。 即所有订阅该交换机的 Queue 都会收到消息。 比如,下面我们添加了两个 Queue,订阅了相同的交换机。 ``` import { Provide, Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/decorator'; import { Context, Application } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Provide() @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('abc', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, }, }) async gotData(msg: ConsumeMessage) { this.logger.info('test output1 =>', msg.content.toString('utf8')); // TODO } @RabbitMQListener('bcd', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, }, }) async gotData2(msg: ConsumeMessage) { this.logger.info('test output2 =>', msg.content.toString('utf8')); // TODO } } ``` 订阅的 abc 和 bcd 队列,绑定了相同的交换机 logs,最终的结果是,两个方法都会被调用。 ### Direct Exchange[​](#direct-exchange "Direct Exchange的直接链接") Direct Exchange 是 RabbitMQ 默认的 Exchange,完全根据 RoutingKey 来路由消息。设置 Exchange 和 Queue 的 Binding 时需指定 RoutingKey(一般为 Queue Name),发消息时也指定一样的 RoutingKey,消息就会被路由到对应的 Queue。 下面的示例代码,我们不填写 Queue Name,只添加一个 routingKey,交换机类型为 direct。 ``` import { Provide, Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/decorator'; import { Context, Application } from '../../../../../src'; import { ConsumeMessage } from 'amqplib'; @Provide() @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('', { exchange: 'direct_logs', exchangeOptions: { type: 'direct', durable: false, }, routingKey: 'direct_key', exclusive: true, consumeOptions: { noAck: true, }, }) async gotData(msg: ConsumeMessage) { // TODO } } ``` direct 类型的消息,会根据 routerKey 做定向过滤,所以只有特定订阅能收到消息。 ### 装饰器参数[​](#装饰器参数 "装饰器参数的直接链接") `@RabbitMQListener` 装饰器的第一个参数为 queueName,代表需要监听的队列。 第二个参数是一个对象,包含队列,交换机等参数,详细定义如下: ``` export interface RabbitMQListenerOptions { exchange?: string; /** * queue options */ exclusive?: boolean; durable?: boolean; autoDelete?: boolean; messageTtl?: number; expires?: number; deadLetterExchange?: string; deadLetterRoutingKey?: string; maxLength?: number; maxPriority?: number; pattern?: string; /** * prefetch */ prefetch?: number; /** * router */ routingKey?: string; /** * exchange options */ exchangeOptions?: { type?: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string; durable?: boolean; internal?: boolean; autoDelete?: boolean; alternateExchange?: string; arguments?: any; }; /** * consumeOptions */ consumeOptions?: { consumerTag?: string; noLocal?: boolean; noAck?: boolean; exclusive?: boolean; priority?: number; arguments?: any; }; } ``` ### 本地测试[​](#本地测试 "本地测试的直接链接") Midway 提供了一个简单的测试方法用于测试订阅某个数据。 `@midwayjs/mock` 工具提供了一个 `createRabbitMQProducer` 的方法,用于创建一个生产者,通过它,你可以创建一个队列(Queue),以及向这个队列发消息。 然后,我们启动一个 app,就可以自动监听到这个队列中的数据,并执行后续逻辑。 ``` import { createRabbitMQProducer, closeApp, creatApp } from '@midwayjs/mock'; describe('/test/index.test.ts', () => { it('should test create message and get from app', async () => { // create a queue and channel const channel = await createRabbitMQProducer('tasks', { isConfirmChannel: true, mock: false, url: 'amqp://localhost', }); // send data to queue channel.sendToQueue('tasks', Buffer.from('something to do')); // create app and got data const app = await creatApp('base-app', { url: 'amqp://localhost' }); await closeApp(app); }); }); ``` **示例一** 创建一个 fanout exchange。 ``` const manager = await createRabbitMQProducer('tasks-fanout', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'logs'; // Write a message const msg = 'Hello World!'; // 声明交换机 manager.assertExchange(ex, 'fanout', { durable: false }); // 'fanout' will broadcast all messages to all the queues it knows // 启动服务 const app = await creatApp('base-app-fanout', { url: 'amqp://localhost', reconnectTime: 2000, }); // 发送到交换机,由于不持久化,需要等订阅服务起来之后再发 manager.sendToExchange(ex, '', Buffer.from(msg)); // 等一段时间 await sleep(5000); // 校验结果 // 关闭 producer await manager.close(); // 关闭 app await closeApp(app); ``` **示例二** 创建一个 direct exchange。 ``` /** * direct 类型的消息,根据 routerKey 做定向过滤 */ const manager = await createRabbitMQProducer('tasks-direct', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'direct_logs'; // Write a message const msg = 'Hello World!'; // 声明交换机 manager.assertExchange(ex, 'direct', { durable: false }); // 'fanout' will broadcast all messages to all the queues it knows const app = await creatApp('base-app-direct', { url: 'amqp://localhost', reconnectTime: 2000, }); // 这里指定 routerKey,发送到交换机 manager.sendToExchange(ex, 'direct_key', Buffer.from(msg)); // 校验结果 await manager.close(); await closeApp(app); ``` ## 生产者(Producer)使用方法[​](#生产者producer使用方法 "生产者(Producer)使用方法的直接链接") 生产者(Producer)也就是第一节中的消息产生者,简单的来说就是会创建一个客户端,将消息发送到 RabbitMQ 服务。 注意:当前 Midway 并没有使用组件来支持消息发送,这里展示的示例只是使用纯 SDK 在 Midway 中的写法。 ### 安装依赖[​](#安装依赖-1 "安装依赖的直接链接") ``` $ npm i amqplib amqp-connection-manager --save $ npm i @types/amqplib --save-dev ``` ### 调用服务发送消息[​](#调用服务发送消息 "调用服务发送消息的直接链接") 比如,我们在 service 文件下,新增一个 `rabbitmq.ts`  文件。 ``` import { Provide, Scope, ScopeEnum, Init, Autoload, Destroy } from '@midwayjs/decorator'; import * as amqp from 'amqp-connection-manager'; @Autoload() @Provide() @Scope(ScopeEnum.Singleton) // Singleton 单例,全局唯一(进程级别) export class RabbitmqService { private connection: amqp.AmqpConnectionManager; private channelWrapper; @Init() async connect() { // 创建连接,你可以把配置放在 Config 中,然后注入进来 this.connection = await amqp.connect('amqp://localhost'); // 创建 channel this.channelWrapper = this.connection.createChannel({ json: true, setup: function (channel) { return Promise.all([ // 绑定队列 channel.assertQueue('tasks', { durable: true }), ]); }, }); } // 发送消息 public async sendToQueue(queueName: string, data: any) { return this.channelWrapper.sendToQueue(queueName, data); } @Destroy() async close() { await this.channelWrapper.close(); await this.connection.close(); } } ``` 大概就是创建了一个用来封装消息通信的 service,同时他是全局唯一的 Singleton 单例。由于增加了 `@AutoLoad` 装饰器,可以自执行初始化。 这样基础的调用服务就抽象好了,我们只需要在用到的地方,调用 `sendToQueue` 方法即可。 比如: ``` @Provide() export class UserService { @Inject() rabbitmqService: RabbitmqService; async invoke() { // TODO // 发送消息 await this.rabbitmqService.sendToQueue('tasks', { hello: 'world' }); } } ``` ## 参考文档[​](#参考文档 "参考文档的直接链接") * [理解 RabbitMQ Exchange](https://zhuanlan.zhihu.com/p/37198933) * [RabbitMQ for Node.js in 30 steps](https://github.com/Gurenax/node-rabbitmq) --- # Redis 这里介绍如何快速在 Midway 中使用 Redis。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/redis` 是主要的功能包,`@types/ioredis` 是 定义包。 ``` $ npm i @midwayjs/redis@2 --save $ npm i @types/ioredis --save-dev // 安装到 dev 依赖 ``` 如果发现 RedisService 没有方法定义,请务必检查此项。 ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `src/configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as redis from '@midwayjs/redis'; import { join } from 'path'; @Configuration({ imports: [ redis, // 导入 redis 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` ## 配置 Redis[​](#配置-redis "配置 Redis的直接链接") 比如: **单客户端配置** ``` // src/config.default // Single Redis export const redis = { client: { port: 6379, // Redis port host: '127.0.0.1', // Redis host password: 'auth', db: 0, }, }; ``` **Sentinel 配置** ``` export const redis = { client: { sentinels: [ { // Sentinel instances port: 26379, // Sentinel port host: '127.0.0.1', // Sentinel host }, ], name: 'mymaster', // Master name password: 'auth', db: 0, }, }; ``` **Cluster 模式配置,需要配置多个** ``` // Cluster Redis export const redis = { client: { cluster: true, nodes: [{ host: 'host', port: 'port', password: 'password', db: 'db', },{ host: 'host', port: 'port', password: 'password', db: 'db', }, } }; ``` **多个客户端配置,需要配置多个** ``` // Multi Redis export const redis = { clients: { instance1: { host: 'host', port: 'port', password: 'password', db: 'db', }, instance2: { host: 'host', port: 'port', password: 'password', db: 'db', }, }, }; ``` 更多参数可以查看 [ioredis 文档](https://github.com/luin/ioredis/blob/master/API.md#new_Redis_new)。 ## 使用 Redis 服务[​](#使用-redis-服务 "使用 Redis 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/decorator'; import { RedisService } from '@midwayjs/redis'; @Provide() export class UserService { @Inject() redisService: RedisService; async invoke() { await this.redisService.set('foo', 'bar'); const result = await this.redisService.get('foo'); // result => bar } } ``` 可以使用 `RedisServiceFactory` 获取不同的实例。 ``` import { RedisServiceFactory } from '@midwayjs/redis'; import { join } from 'path'; @Provide() export class UserService { @Inject() redisServiceFactory: RedisServiceFactory; async save() { const redis1 = await this.redisServiceFactory.get('instance1'); const redis2 = await this.redisServiceFactory.get('instance3'); //... } } ``` --- # 模板渲染 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 ## 使用 ejs[​](#使用-ejs "使用 ejs的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") 选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-ejs@2 --save ``` ### 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as view from '@midwayjs/view-ejs'; import { join } from 'path'; @Configuration({ imports: [ view, // 导入 ejs 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` ### 配置[​](#配置 "配置的直接链接") ``` // src/config/config.default.ts export const view = { defaultViewEngine: 'ejs', mapping: { '.ejs': 'ejs', }, }; // ejs config export const ejs = {}; ``` ### 使用[​](#使用 "使用的直接链接") 注意,默认的 view 目录为 `${appRoot}/view` ,在其中创建一个 `hello.ejs` 文件。 目录结构如下: ``` ➜ my_midway_app tree . ├── src │   └── controller ## Controller 目录 │      └── home.ts ├── view ## 模板目录 │   └── hello.ejs ├── test ├── package.json └── tsconfig.json ``` 我们在模板里写一些 ejs 格式的内容,比如: ``` // view/hello.ejs hello <%= data %> ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render() { await this.ctx.render('hello.ejs', { data: 'world', }); } } ``` ## 使用 Nunjucks[​](#使用-nunjucks "使用 Nunjucks的直接链接") 和 ejs 类似,引入对应组件即可。 1、选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-nunjucks --save ``` 2、引入组件,在 `configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path'; @Configuration({ imports: [ view, // 导入 nunjucks 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` 3、增加 nunjucks 的配置,比如默认使用 nunjucks。 ``` // src/config/config.default.ts export const view = { defaultViewEngine: 'nunjucks', mapping: { '.nj': 'nunjucks', }, }; ``` 4、在 view 目录增加模板 ``` // view/test.ejs hi, {{ user }} ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render() { await ctx.render('test.nj', { user: 'midway' }); } } ``` 访问后会输出 `hi, midway` 。 如果有自定义 filter 的需求,可以在入口处增加,比如下面增加了一个名为 `hello` 的 filter。 ``` import { App, Configuration, Inject } from '@midwayjs/decorator'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path'; @Configuration({ imports: [view], importConfigs: [join(__dirname, 'config')], }) export class AutoConfiguration { @App() app; @Inject() env: view.NunjucksEnvironment; async onReady() { this.env.addFilter('hello', (str) => { return 'hi, ' + str; }); } } ``` 在模板里可以使用 ``` { { name | hello; } } ``` 然后渲染 ``` // controller // ... await ctx.render('test.nj', { name: 'midway' }); ``` 也会输出 `hi, midway` 。 ## 注意事项[​](#注意事项 "注意事项的直接链接") 如需在 egg(@midwayjs/web) 场景下使用,请在 `plugint.ts` 中关闭 view 和其相关插件。 ``` import { EggPlugin } from 'egg'; export default { // ... view: false, } as EggPlugin; ``` 否则会出现下面类似的错误。 ``` TypeError: Cannot set property view of # which has only a getter ``` --- # Sequelize ## 使用方法:[​](#使用方法 "使用方法:的直接链接") ``` $ npm install @midwayjs/sequelize@2 -S ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` ## 引入模块[​](#引入模块 "引入模块的直接链接") 在 configuration.ts 文件中 ``` import { App, Configuration } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from 'egg'; import { join } from 'path'; import * as sequlize from '@midwayjs/sequelize'; @Configuration({ imports: [sequlize], importConfigs: [join(__dirname, './config')], }) export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() {} } ``` ## 配置[​](#配置 "配置的直接链接") 在 config.default.ts 中配置: ``` export const sequelize = { options: { database: 'test4', username: 'root', password: '123456', host: '127.0.0.1', // 此处支持idb上面vipserver key的那种方式,也支持aliyun的地址。 port: 3306, encrypt: false, dialect: 'mysql', define: { charset: 'utf8' }, timezone: '+08:00', logging: console.log, }, sync: false, // 本地的时候,可以通过sync: true直接createTable }; ``` ## 业务层[​](#业务层 "业务层的直接链接") 定义 Entity ``` import { Column, Model } from 'sequelize-typescript'; import { BaseTable } from '@midwayjs/sequelize'; @BaseTable export class Photo extends Model { @Column({ comment: '名字', }) name: string; } ``` 使用 Entity: 查询列表 ``` import { Config, Controller, Get, Provide } from '@midwayjs/decorator'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { let result = await Photo.findAll(); console.log(result); return 'hello world'; } } ``` 增加数据: ``` import { Config, Controller, Get, Provide } from '@midwayjs/decorator'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/add') async home() { let result = await Photo.create({ name: '123', }); console.log(result); return 'hello world'; } } ``` 删除: ``` import { Config, Controller, Get, Provide } from '@midwayjs/decorator'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { await UserModel.destroy({ where: { name: '123', }, }); return 'hello world'; } } ``` 查找单个: ``` import { Config, Controller, Get, Provide } from '@midwayjs/decorator'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { let result = await UserModel.findOne({ where: { name: '123', }, }); return 'hello world'; } } ``` 联合查询: ``` import { Config, Controller, Get, Provide } from '@midwayjs/decorator'; import { Photo } from '../entity/Photo'; import { Op } from 'sequelize'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { let result = await Photo.findAll({ where: { [Op.or]: [{ name: '23' }, { name: '34' }], // SELECT * FROM photo WHERE name = "23" OR name = "34"; }, }); console.log(result); return 'hello world'; } } ``` 关于 OP 的更多用法: 如果遇到比较复杂的,可以使用 raw query 方法: --- # Swagger [Swagger](https://swagger.io/) 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。Swagger 让部署管理和使用功能强大的 API 从未如此简单。 Midway 通过组件化的形式来支持 swagger 能力。 ## 一、例子[​](#一例子 "一、例子的直接链接") 点此 [访问示例库](https://github.com/midwayjs/midway-examples/tree/master/v2/demo-swagger) ``` $ npm install $ npm run dev ``` 然后访问: ## 二、使用方法[​](#二使用方法 "二、使用方法的直接链接") ### 2.1 安装[​](#21-安装 "2.1 安装的直接链接") 安装依赖。 ``` npm install @midwayjs/swagger@1 --save npm install swagger-ui-dist --save-dev ``` 如果想要在服务器上输出 swagger API 页面,则需要将 `swagger-ui-dist` 安装到依赖中。 ``` npm install swagger-ui-dist --save ``` ### 2.2 配置[​](#22-配置 "2.2 配置的直接链接") 在 `configuration.ts` 中增加组件。 ``` import { Configuration } from '@midwayjs/decorator'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [swagger], }) export class ContainerConfiguration {} ``` 可以配置启用的环境,比如下面的代码指的是“只在 local 环境下启用”。 ``` import { Configuration } from '@midwayjs/decorator'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [ { component: swagger, enabledEnvironment: ['local'], }, ], }) export class ContainerConfiguration {} ``` ### 2.3 使用[​](#23-使用 "2.3 使用的直接链接") 直接启动即可,由于通过元数据进行了分析,默认情况下,可以**直接获取到当前的参数,类型,名称,依赖关系**等。 访问: 拿到 swagger UI 界面。 访问: 拿到 swagger json 结构。 ## 三、示例[​](#三示例 "三、示例的直接链接") ### 3.1 描述请求[​](#31-描述请求 "3.1 描述请求的直接链接") 通过 `summary` 和 `description` 方法,我们可以对整个接口进行描述。 ``` import { CreateApiDoc } from '@midwayjs/swagger' @CreateApiDoc() .summary('get user') .description('This is a open api for get user') .build() @Get('/:userId') async getUser(@Param() userId: number, @Query() name?: string) { return { name: 'harry', age: 18 }; } ``` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605013889037-58cb5bc5-cc37-43e6-8512-834d9c2e0ba9.png#height=150\&id=jRI8p\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=300\&originWidth=750\&originalType=binary\&ratio=1\&size=18686\&status=done\&style=none\&width=375) ### 3.2 参数描述[​](#32-参数描述 "3.2 参数描述的直接链接") 通过 `param` 方法可以描述接口的参数,按顺序描述参数。如果有多个参数,则可以调用多次。以我们的示例为例,有两个参数, `userId` 和 `name` 。 `param` 方法的定义如下。 ``` param(description: Partial): SwaggerAPI; param(description: string, options?: Partial): SwaggerAPI; ``` 在最简单的情况下,我们可以直接写参数的描述,同时,会自动分析出参数的类型,比如路由中的参数、请求中的参数等。 ``` @CreateApiDoc() .param('user id') .param('user name') .build() @Get('/:userId') async getUser(@Param() userId: number, @Query() name?: string) { return { name: 'harry', age: 18 }; } ``` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605016059585-e2bce9f0-bf62-4d25-b794-f54340b555ab.png#height=347\&id=YwKAq\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=694\&originWidth=1270\&originalType=binary\&ratio=1\&size=51562\&status=done\&style=none\&width=635) 在更为复杂的情况下,参数可以更加精确的描述。 ``` export interface APIParamFormat { name: string; // 参数名 description: string; // 参数描述 required: boolean; // 参数是否必须 deprecated: boolean; // 参数是否废弃 allowEmptyValue: boolean; // 参数是否允许控制 example: any; // 参数的示例 } ``` 下面是参数的示例,有两种方式去具体描述参数。 ``` @CreateApiDoc() .summary('get user') .description('This is a open api for get user') .param('user id', { required: true, example: '123456' }) .param({ description: 'This is a user name' }) .build() @Get('/:userId') async getUser(@Param() userId: number, @Query() name?: string) { return { name: 'harry', age: 18 }; } ``` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605016872114-640ff1e2-88d9-4c1e-969b-a1c8794180bd.png#height=340\&id=UdmiX\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=680\&originWidth=1112\&originalType=binary\&ratio=1\&size=47848\&status=done\&style=none\&width=556) ### 3.3 返回值描述[​](#33-返回值描述 "3.3 返回值描述的直接链接") 一个接口会有多种返回值的可能性,可以调用多次 `respond` 方法来描述不同的返回结果。 响应的接口描述如下。 ``` respond( status: number, description?: string, respondType?: string, options?: Partial ): SwaggerAPI; export interface APIResponseFormat { status: string; description: string; headers: any; example: any; } ``` 参数分为四个部分,除了状态码,其他都是可选参数,下面的示例展示了多种不同的返回描述。 ``` @CreateApiDoc() .summary('get user') .description('This is a open api for get user') .respond(200) .respond(302, 'redirect to another URL') .respond(201, 'response a text data', 'text', { headers: { 'x-schema': { description: 'set a schema header', type: 'string' } }, example: 'this is a reponse data' }) .respond(500, 'error in response', 'json', { example: { a: 1 } }) .build() ``` 你可以直接设置一个状态码,也可以在设置状态码之后,紧跟着设置描述,以及返回的 header,数据类型和示例。 展示的效果为 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605023356892-77af3cf9-949d-49d5-adfe-8da98e888b60.png#height=829\&id=nFEky\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1658\&originWidth=2860\&originalType=binary\&ratio=1\&size=194050\&status=done\&style=none\&width=1430) ### 3.4 通用描述[​](#34-通用描述 "3.4 通用描述的直接链接") 可以通过在 `Controller` 装饰器和 `Get` 等路由装饰器上简单的增加描述信息。 #### 控制器分组和描述[​](#控制器分组和描述 "控制器分组和描述的直接链接") ``` @Controller('/', { tagName: 'Custom Group', description: 'Home Router' }) export class HomeController {} ``` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605011893128-f72e4916-24c7-4c59-ba76-4cd3f17c7bc9.png#height=143\&id=Fqp8z\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=286\&originWidth=808\&originalType=binary\&ratio=1\&size=16673\&status=done\&style=none\&width=404) #### 路由描述[​](#路由描述 "路由描述的直接链接") ``` @Get('/', {summary: 'Main Page', description: 'This is a home router'}) async home() { return 'Hello Midwayjs!'; } ``` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1605011937991-8fb2136a-f091-4016-9745-8434d8130a6a.png#height=173\&id=UdC82\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=346\&originWidth=942\&originalType=binary\&ratio=1\&size=19218\&status=done\&style=none\&width=471) ## #### 增强的接口描述信息(进阶模式)[​](#增强的接口描述信息进阶模式 "增强的接口描述信息(进阶模式)的直接链接") 如果需要增加细节描述字段,则增加了 `@CreateApiDoc` 装饰器,用于定义描述,包括入参和出参。整个装饰器设计为链式调用,方便 IDE 获取到对应的方法和参数定义。 我们以一个接口为例。注意, `@CreateApiDoc`  装饰器最后需要跟一个 `build`  方法作为结尾。 **完整的示例** ``` import { CreateApiDoc, CreateApiPropertyDoc } from '@midwayjs/swagger'; export class UserDTO { @CreateApiPropertyDoc('user name') @Rule(RuleType.string().required()) name: string; @CreateApiPropertyDoc('user age') @Rule(RuleType.number()) age: number; } @Provide() @Controller('/user') export class UserController { @Inject() ctx: IMidwayKoaContext; @Inject() userService: UserService; @(CreateApiDoc() .summary('get user') .description('This a a open api for get user') .param('user id', { required: true, example: 2, }) .param('user name') .respond(200, 'success', 'text', { example: 'hello world', }) .respond(500, 'throw error') .build()) @Get('/:userId') async getUser(@Param() userId: number, @Query() name?: string) { return { name: 'harry', age: 18, }; } } ``` #### 更多配置[​](#更多配置 "更多配置的直接链接") 可以修改默认的 Swagger 版本,描述等。这些配置可以在用户配置,比如 `src/config/config.default.ts`  中配置。 ``` export const swagger = { title: 'midway-swagger', description: 'swagger-ui for midway api', version: '1.0.0', termsOfService: '', contact: { name: 'API Support', url: 'http://www.example.com/support', email: 'support@example.com', }, license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0.html', }, }; ``` ## 四、其他[​](#四其他 "四、其他的直接链接") midwayjs Swagger【增加返回数据的配置】[](https://github.com/midwayjs/midway) --- # TableStore 本文介绍了如何使用 midway 接入阿里云 TableStore。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/tablestore@2 --save ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts`  中导入: ``` import { Configuration } from '@midwayjs/decorator'; import * as tablestore from '@midwayjs/tablestore'; import { join } from 'path'; @Configuration({ imports: [ tablestore, // 导入 tablestore 组件 ], importConfigs: [join(__dirname, 'config')], }) export class ContainerLifeCycle {} ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` export const tableStore = { client: { accessKeyId: '', secretAccessKey: '', stsToken: '' /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/, endpoint: '', instancename: '', }, }; ``` **多个客户端配置,需要配置多个** ``` export const tableStore = { clients: { db1: { accessKeyId: '', secretAccessKey: '', stsToken: '' /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/, endpoint: '', instancename: '', }, db2: { accessKeyId: '', secretAccessKey: '', stsToken: '' /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/, endpoint: '', instancename: '', }, }, }; ``` 更多参数可以查看 [aliyun tablestore sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk) 文档。 ## 使用 TableStore 服务[​](#使用-tablestore-服务 "使用 TableStore 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/decorator'; import { TableStoreService } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async invoke() { await this.tableStoreService.putRow(params); } } ``` 可以使用 `TableStoreServiceFactory` 获取不同的实例。 ``` import { TableStoreServiceFactory } from '@midwayjs/tablestore'; import { join } from 'path'; @Provide() export class UserService { @Inject() tableStoreServiceFactory: TableStoreServiceFactory; async save() { const db1 = await this.tableStoreServiceFactory.get('db1'); const db2 = await this.tableStoreServiceFactory.get('db2'); //... } } ``` 示例:getRow ``` import { join } from 'path'; import { TableStoreService, Long, CompositeCondition, SingleColumnCondition, LogicalOperator, ComparatorType, } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async getInfo() { const data = await tableStoreService.getRow({ tableName: 'sampleTable', primaryKey: [{ gid: Long.fromNumber(20013) }, { uid: Long.fromNumber(20013) }], columnFilter: condition, }); // TODO } } ``` 如示例所示,原有的 tablestore 包中导出的类型,应该都已经被 @midwayjs/tablestore 代理和接管,更多具体方法参数可以查看 [示例](https://github.com/midwayjs/midway/tree/2.x/packages/tablestore/test/sample)。 --- # 任务调度(Task) @midwayjs/task 是为了解决任务系列的模块,例如分布式定时任务、延迟任务调度。例如每日定时报表邮件发送、订单2小时后失效等工作。 分布式定时任务依赖 bull,其通过 redis 进行实现,所以配置中,需要配置额外的 Redis,本地定时任务基于 Cron 模块,不需要额外配置。 ## 安装组件[​](#安装组件 "安装组件的直接链接") 首先安装 Midway 提供的任务组件: ``` $ npm install @midwayjs/task@2 -S ``` 在 `configuration.ts` 中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as task from '@midwayjs/task'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [task], importConfigs: [join(__dirname, 'config')], }) export class AutoConfiguration {} ``` ## 配置[​](#配置 "配置的直接链接") 在 `config.default.ts` 文件中配置对应的模块信息: ``` export const taskConfig = { redis: `redis://127.0.0.1:32768`, //任务依赖redis,所以此处需要加一个redis prefix: 'midway-task', // 这些任务存储的key,都是midway-task开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: 'Asia/Shanghai', // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }; ``` 有账号密码情况: ``` export const taskConfig = { redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, //此处相当于是ioredis的配置 https://www.npmjs.com/package/ioredis prefix: 'midway-task', // 这些任务存储的key,都是midway-task开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: 'Asia/Shanghai', // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }; ``` ## 业务代码编写方式[​](#业务代码编写方式 "业务代码编写方式的直接链接") ### 分布式定时任务[​](#分布式定时任务 "分布式定时任务的直接链接") ``` import { Provide, Inject, Task } from '@midwayjs/decorator'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每分钟执行一次,并且是分布式任务 @Task({ repeat: { cron: '* * * * *' }, }) async test() { console.log(this.helloService.getName()); } } ``` ### 本地定时任务[​](#本地定时任务 "本地定时任务的直接链接") ``` import { Provide, Inject, TaskLocal } from '@midwayjs/decorator'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每秒钟执行一次 @TaskLocal('* * * * * *') async test() { console.log(this.helloService.getName()); } } ``` ### 手动触发任务[​](#手动触发任务 "手动触发任务的直接链接") 任务的定义,通过 `@Queue` 装饰器,定义一个任务类,内必须含有 execute 方法,并且是 async 的。为什么需要是 async 的因为,这个代码,是为了分布式,相当于有个内部的任务调度过程。 ``` import { Provide, Inject, Queue } from '@midwayjs/decorator'; @Queue() @Provide() export class HelloTask { @Inject() service; async execute(params) { console.log(params); } } ``` 触发: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Inject } from '@midwayjs/decorator'; @Provide() export class UserTask { @Inject() service; @Inject() queueService: QueueService; async execute(params) { // 3秒后触发分布式任务调度。 const xxx = await this.queueService.execute(HelloTask, params, { delay: 3000 }); } } ``` 这样,就相当于是 3 秒后,触发 HelloTask 这个任务。 #### 设置进度[​](#设置进度 "设置进度的直接链接") 例如我们在做音视频或者发布这种比较耗时的任务的时候,我们希望能设置进度。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620884757992-fb18a58f-9e56-4eda-92d9-68965df73e8a.png#clientId=uecb893ec-cfee-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=342\&id=ubf7a3918\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=454\&originWidth=576\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=29448\&status=done\&style=none\&taskId=uffac1111-2306-44ac-bd3e-906503e1764\&title=\&width=434) 相当于第二个参数,将 bull 的 job 传递给了用户。用户可以通过 job.progress 来设置进度。 然后查询进度: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Controller, Get } from '@midwayjs/decorator'; @Provide() @Controller() export class HelloController { @Inject() queueService: QueueService; @Get('/get-queue') async getQueue(@Query() id: string) { return await this.queueService.getClassQueue(TestJob).getJob(id); } } ``` #### 任务的相关内容[​](#任务的相关内容 "任务的相关内容的直接链接") ``` let job = await this.queueService.getClassQueue(TestJob).getJob(id); ``` 然后 job 上面有类似停止的方法,或者查看进度的方法。 ### 启动就触发[​](#启动就触发 "启动就触发的直接链接") 有朋友由于只有一台机器,希望重启后立马能执行一下对应的定时任务。 ``` import { Context, ILifeCycle, IMidwayBaseApplication, IMidwayContainer } from '@midwayjs/core'; import { Configuration } from '@midwayjs/decorator'; import { Queue } from 'bull'; import { join } from 'path'; import * as task from '@midwayjs/task'; import { QueueService } from '@midwayjs/task'; @Configuration({ imports: [task], importConfigs: [join(__dirname, './config')], }) export class ContainerConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer, app?: IMidwayBaseApplication): Promise { // Task这块的启动后立马执行 let result: any = await container.getAsync(QueueService); let job: Queue = result.getQueueTask(`HelloTask`, 'task'); // 此处第一个是你任务的类名,第二个任务的名字也就是装饰器Task的函数名 job.add({}, { delay: 0 }); // 表示立即执行。 } } ``` ## 运维[​](#运维 "运维的直接链接") ### 日志[​](#日志 "日志的直接链接") 在 Midway Task Component 上面,增加了两个日志: * midway-task.log * midway-task-error.log 分别在 task、localTask、queue 触发开始和结束的时候会打印对应的日志。 分布式的 Task 触发日志: ``` logger.info(`task start.`); // 异常情况: logger.error(`${e.stack}`); logger.info(`task end.`); ``` 非分布式的 LocalTask 触发日志: ``` logger.info(`local task start.`); // 异常情况: // logger.error(`${e.stack}`) logger.info(`local task end.`); ``` 任务队列的触发日志: ``` logger.info(`queue process start.`); // 异常情况: // logger.error(`${e.stack}`) logger.info(`queue process end.`); ``` ### 排查问题链路:[​](#排查问题链路 "排查问题链路:的直接链接") ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1626926172431-ce41c896-fc64-4c73-8d3b-f2633a916b5f.png#clientId=u62783ce8-4645-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=504\&id=viDCK\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1008\&originWidth=1992\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=2693469\&status=done\&style=none\&taskId=u467a4354-7dc2-49c3-9bb6-3c6dea1903e\&title=\&width=996) 用户可以搜索这个相同的 id,找到同一次请求的日志。 为了方便用户在自己的业务代码中串联对应的日志,我在 ctx 上面挂了 traceId 变量。 例如异常情况: 当异常的时候, **本地 可以在 console 栏内看到这个错误相关的情况:** ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1626929372403-df50b85d-c71e-4b87-b602-275d10d3dc83.png#clientId=u8f28ddc7-5bc1-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=162\&id=UlGrO\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=324\&originWidth=1964\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=669523\&status=done\&style=none\&taskId=u4b77719b-978b-4a21-90f8-3ee205dbf9d\&title=\&width=982) 日志: 可以在 midway-task.log 文件中查看完整日志: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1626929372403-df50b85d-c71e-4b87-b602-275d10d3dc83.png#clientId=u8f28ddc7-5bc1-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=162\&id=binL0\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=324\&originWidth=1964\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=669523\&status=done\&style=none\&taskId=u4b77719b-978b-4a21-90f8-3ee205dbf9d\&title=\&width=982) 如果调用情况比较多的时候,会出现 A 还没执行完成,B 又进来,导致日志区分比较麻烦,所以用户可以搜索调用的 traceId,也就是下图红色圈起来的地方: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1626929496543-7d79db19-622f-4f99-a2fd-60b7f00bd57d.png#clientId=u8f28ddc7-5bc1-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=163\&id=DM3xz\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=326\&originWidth=2034\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=691391\&status=done\&style=none\&taskId=ucd8b1d59-b13d-4fc4-81e2-2d4f43bab7b\&title=\&width=1017) 相当于 ctrl + f 搜索相同的 traceId 即可。 ### traceId[​](#traceid "traceId的直接链接") localTask 则是自己生成了一个 uuid 的 id 作为 traceId。 task 和 queue 则采用 job 的 id 作为 traceId。 ### 业务内部的代码[​](#业务内部的代码 "业务内部的代码的直接链接") 在 service 内可以通过 inject 注入 logger,或者注入 ctx 拿 logger 变量 ``` import { App, Inject, Provide, Queue } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; @Queue() @Provide() export class QueueTask { @App() app: Application; @Inject() logger; async execute(params) { this.logger.info(`====>QueueTask execute`); this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 或者 ``` import { App, Inject, Provide, Queue } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; @Queue() @Provide() export class QueueTask { @App() app: Application; @Inject() ctx; async execute(params) { this.ctx.logger.info(`====>QueueTask execute`); this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 打印的日志 ``` 2021-07-30 13:00:13,101 INFO 5577 [Queue][12][QueueTask] queue process start. 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] ====>QueueTask execute 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] queue process end. ``` ## 其他[​](#其他 "其他的直接链接") ### Cron 表达式[​](#cron-表达式 "Cron 表达式的直接链接") 关于 Task 任务的配置: ``` * * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional) ``` 常见表达式: * 每隔5秒执行一次:`*/5 * * * * *` * 每隔1分钟执行一次:`0 */1 * * * *` * 每小时的20分执行一次:`0 20 * * * *` * 每天 0 点执行一次:`0 0 0 * * *` * 每天的两点35分执行一次:`0 35 2 * * *` 可以使用 [在线工具](https://cron.qqe2.com/) 执行确认下一次执行的时间。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1637042668291-70527b75-bb33-4ad2-adc0-5f0f5dfe8c81.png#clientId=u21d1027f-3ac8-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=340\&id=gQnon\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=680\&originWidth=1868\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=98959\&status=done\&style=none\&taskId=u0adb2151-a667-4900-8bba-b13d4aac93c\&title=\&width=934) ### EVALSHA 错误[​](#evalsha-错误 "EVALSHA 错误的直接链接") ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1633771728525-1efeb2a6-cefd-4fc3-a16d-0e9a97f371d1.png#clientId=u52b8d912-3ffa-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=51\&id=u0c96f70a\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=102\&originWidth=3540\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=164783\&status=done\&style=none\&taskId=uc38084d4-e2cf-435d-a8b9-6a9bec80c9b\&title=\&width=1770) 这个问题基本明确,问题会出现在 redis 的集群版本上。原因是 redis 会对 key 做 hash 来确定存储的 slot,集群下这一步@midwayjs/task 的 key 命中了不同的 slot。临时的解决办法是 taskConfig 里的 prefix 配置用包括,强制 redis 只计算里的 hash,例如 `prefix: '{midway-task}'` ### 历史日志删除[​](#历史日志删除 "历史日志删除的直接链接") 当每次 redis 执行完他会有日志,那么如何让其在完成后删除: ``` import { Provide, Task } from '@midwayjs/decorator'; import { IUserOptions } from '../interface'; @Provide() export class UserService { async getUser(options: IUserOptions) { return { uid: options.uid, username: 'mockedName', phone: '12345678901', email: 'xxx.xxx@xxx.com', }; } @Task({ repeat: { cron: '* * * * * *' }, removeOnComplete: true, // 加了一行这个 }) async test() { console.log(`====`); } } ``` 目前是否默认删除,需要跟用户沟通 --- # FaaS 文件上传 ### 一、使用场景[​](#一使用场景 "一、使用场景的直接链接") 仅适用于 Serverless 环境,小于 6M 的文件上传到函数端,进行文件相关处理操作。 ### 二、前置需求[​](#二前置需求 "二、前置需求的直接链接") 确认上传的文件是否小于 6M,超过 6M 的文件建议使用 OSS 直传方案。 ### 三、代码中如何使用[​](#三代码中如何使用 "三、代码中如何使用的直接链接") #### 1. 代码中安装上传组件[​](#1-代码中安装上传组件 "1. 代码中安装上传组件的直接链接") ``` npm i @midwayjs/faas-middleware-upload --save ``` #### 2. 添加配置[​](#2-添加配置 "2. 添加配置的直接链接") 在函数目录中创建 config 目录,在此目录中添加 `config.default.ts` 文件 ``` // config/config.default.ts export const upload = { mod: 'stream', }; ``` #### 配置中的 mod 支持三种模式,默认为 `stream`,即流式,还支持 `buffer` 和 `file` 两种配置,这三种 mod 配置分别对应的 file.data 为 ReadStream、File Data Buffer 和 临时文件地址。 #### [​](#-1 "-1的直接链接") #### 3. 添加组件[​](#3-添加组件 "3. 添加组件的直接链接") 在函数目录中创建 `configuration.ts` 文件 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import * as Upload from '@midwayjs/faas-middleware-upload'; @Configuration({ importConfigs: ['./config/'], imports: [Upload], }) export class ContainerConfiguration { @App() app; async onReady() { const uploadMW = await this.app.generateMiddleware(Upload.Upload); this.app.use(uploadMW); } } ``` #### 4. 代码中获取上传后的文件[​](#4-代码中获取上传后的文件 "4. 代码中获取上传后的文件的直接链接") ``` // index.ts import { Provide, Inject, ServerlessTrigger } from '@midwayjs/decorator'; @Provide() export class IndexHandler { @Inject() ctx; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/upload', method: 'post', }) async handler() { const files = (this.ctx as any).files; /* files = [ { filename: "20210118142906.jpg", data: FileReadStream, // 还支持其他模式,参照配置中的 mod 参数 fieldname: "fileFormName", mimeType: "image/jpeg" } ] */ const fields = (this.ctx as any).fields; /* fields = { formKey: formValue } */ } } ``` --- # 框架扩展 Midway 提供了一套可以自定义框架的能力,如果 Midway 没有提供某种上层框架能力,则可以自定义接入。 ## 框架和组件的区别[​](#框架和组件的区别 "框架和组件的区别的直接链接") Midway 有着组件和框架的概念,两者有一些区别。 框架(Framework)是一个可以独立运行,独立提供特定服务的模块,一般会暴露端口,绑定协议,承接上游流量,比如 @midwayjs/web (包装 Egg.js,提供 HTTP 服务),@midwayjs/grpc(包装 grpc.js,提供 gRPC 服务)。 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: * 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等 * 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等 不管是框架和组件,都可以发布到 npm 包。 在某些情况下,一个 npm 包可以既包含框架, 又包含组件,那么说明该 npm 包既可以暴露服务,又可以往下游调用。比如 @midwayjs/grpc ,既可以暴露 gRPC 服务,又可以往下游调用 gRPC 服务。 整个区分如下图,任意一个框架(暴露服务)加上大部分组件(下游调用+复用扩展)为业务场景服务。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612541348981-bc32540f-e9b2-4375-9bdd-c77231b17c81.png#height=550\&id=HPSqp\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1100\&originWidth=1930\&originalType=binary\&ratio=1\&size=282162\&status=done\&style=none\&width=965) ## 框架(Framework)概念[​](#框架framework概念 "框架(Framework)概念的直接链接") Midway 现有的框架(Framework)每个是独立的,每一个框架都可以单独在进程中运行,理论上来说,每个框架都是一个独立的依赖注入容器,加上特定框架包含的三方库的组合。 这些独立的框架,都遵循 `IMidwayFramewok`  的接口定义,由 `@midwayjs/bootstrap`  库加载起来。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612086965489-9d1659ff-7440-40ac-a57a-f9195c57a73e.png#height=642\&id=TLWHg\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1284\&originWidth=1888\&originalType=binary\&ratio=1\&size=159418\&status=done\&style=none\&width=944) 所以在提供的单进程部署方案中,我们可以通过一个 `bootstrap.js`  入口来启动应用。 ``` // bootstrap.js const WebFramework = require('@midwayjs/koa').Framework; const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.load(web).run(); ``` ## 框架启动生命周期[​](#框架启动生命周期 "框架启动生命周期的直接链接") 这里的介绍的生命周期不同于用户在 `configuration.ts`  中编写的 `onReady` 、 `onStop` ,而是更顶层从整个框架的角度来看的周期,用户的 `onReady` 、 `onStop` 是其中的一小部分。 整个框架的生命周期分为初始化、运行、停止三个部分,由 [@midwayjs/bootstrap](https://www.npmjs.com/package/@midwayjs/bootstrap) 库来处理。 如下图,左侧是 `@midwayjs/bootstrap`  启动提供的阶段,右侧是对应阶段框架(Framework)所执行的方法。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612086533035-970240ed-6ea9-48d8-aaef-985082b7dacd.png#height=944\&id=HXGoc\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1888\&originWidth=1784\&originalType=binary\&ratio=1\&size=170229\&status=done\&style=none\&width=892) 对于完全自定义框架,每个阶段都可以进行修改和覆盖。 | **启动流程** | | | --------------------------- | -------------------------------------------------------- | | beforeContainerInitialize | 容器初始化之前,可以修改容器配置入参 | | containerInitialize | 创建依赖注入容器,new MidwayContainer() | | afterContainerInitialize | 容器初始化之后,目录加载之前 | | containerDirectoryLoad | 容器加载目录,创建对象定义 | | afterContainerDirectoryLoad | 容器目录加载之后 | | applicationInitialize | 第三方应用初始化 | | containerReady | 容器刷新,触发生命周期,在这个阶段,会执行业务的 onReady | | afterContainerReady | 容器生命周期触发后 | | | | | **关闭流程** | | | beforeStop | 框架关闭前,会执行业务的 onStop | | stop | 框架关闭 | | | | 下面我们来演示如何修改这些生命周期的阶段。 ## 编写自定义 Framework[​](#编写自定义-framework "编写自定义 Framework的直接链接") 一般用户使用现成的 Framework 即可,自定义组件也能满足大部分的场景。 但是在特殊情况下,比如团队需要额外扩展,或者固定一些能力,同时不希望每个使用者额外修改代码,这个时候就需要完全自定义框架(Framework)的功能。 除了完全重写框架之外,用户也可以基于现有的 koa/express/gRPC 等框架编写属于自己的 Framework。下面我们就来解释如何扩展。 ### 基于现有框架扩展[​](#基于现有框架扩展 "基于现有框架扩展的直接链接") 这里以扩展 `@midwayjs/koa`  为例。大部分的情况,我们都只需要修改 `applicationInitialize`  方法。 比如,我们接下去的需求为,给 `@midwayjs/koa`  框架增加默认的 bodyParser。其基本思路为,继承现有的 `midwayjs/koa`  框架,在其 app 对象之上默认加入一个中间件。 示例代码如下: ``` import { Framework } from '@midwayjs/koa'; import * as bodyParser from 'koa-bodyparser'; export class CustomKoaFramework extends Framework { async applicationInitialize(options) { // 执行父类的 app 初始化 await super.applicationInitialize(options); // this.app 初始化完之后就有值了,可以直接去 use 中间件了 this.app.use(bodyParser(this.getConfiguration('bodyParser'))); } } ``` 信息 每个框架,Midway 开发者都会导出 Framework 这个属性,指向当前库的 Framework。 完成框架扩展后,我们要将它导出。框架的约定是,默认导出为 `Framework` 。 ``` export { CustomKoaFramework as Framework } from './custom'; ``` 这样,我们的 Framework 就修改完毕了,我们可以将它包成新的 npm,提供给外部使用。 ### 完全自定义 Framework[​](#完全自定义-framework "完全自定义 Framework的直接链接") 对于没有提供基础框架的场景,我们可以从基础的 `BaseFramework` 开始扩展。 `BaseFrameowk`  类,用于方便的向上扩展。 * 依赖注入容器加载、扫描、初始化 * 组件加载,业务配置加载、生命周期加载 * 默认的 Provide/Inject/Config/App/Aspect/Init 等基础装饰器的支持 * 默认的全局日志和上下文日志,并做好的切割管理 由于 `BaseFrameowk` 是个抽象类,所以需要实现的方法有: * `applicationInitialize`  初始化一个三方库的 app * `run`  三方 app 运行的方式(比如监听端口) 以及一些需要的基础类型定义: ``` export class BaseFramework< APP extends IMidwayApplication, CTX extends IMidwayContext, OPT extends IConfigurationOptions > implements IMidwayFramework {} ``` 第一个, `APP` 是 IMidwayApplication 类型,一般来说,这个 Application 类型是我们实际的应用类型,比如 Express 、Koa,EggJS 的 app 对象 ,或者是其他相似的对象实例。 第二个 `CTX` 是 IMidwayContext 类型,一般我们会自定一个上下文对象,用于存放上下文的信息,比如启动时间,请求作用域容器等。 第三个 `OPT` 是这个框架对应的配置信息,我们定义为继承 `IConfigurationOptions` 这个类型的对象,指的是在启动时需要传入给该框架的参数。比如在 HTTP 时的端口信息等。 接下去我们会以实现一个基础的 HTTP 服务框架作为示例。下面的代码是该框架的核心部分。 ``` import { BaseFramework, IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core'; import * as http from 'http'; // 定义一些上层业务要使用的定义 export interface Context extends IMidwayContext {} export interface Application extends IMidwayApplication {} // 这里是 new Framework().configure({...}) 传递的参数定义 export interface IMidwayCustomConfigurationOptions extends IConfigurationOptions { port: number; } // 实现一个自定义框架,继承基础框架 export class MidwayCustomHTTPFramework extends BaseFramework { public app: Application; async applicationInitialize(options: Partial) { // 创建一个 app 实例 this.app = http.createServer((req, res) => { // 创建请求上下文,自带了 logger,请求作用域等 const ctx = this.app.createAnonymousContext(); // 从请求上下文拿到注入的服务 ctx.requestContext .getAsync('xxxx') .then((ins) => { // 调用服务 return ins.xxx(); }) .then(() => { // 请求结束 res.end(); }); }); // 给 app 绑定上 midway 框架需要的一些方法,比如 getConfig, getLogger 等。 this.defineApplicationProperties(); } async run() { // 启动的参数,这里只定义了启动的 HTTP 端口 if (this.configurationOptions.port) { new Promise((resolve) => { this.server.listen(this.configurationOptions.port, () => { resolve(); }); }); } } } ``` 我们定义了一个 `MidwayCustomHTTPFramework` 类,继承了 `BaseFramework` ,同时实现了 `applicationInitialize`  和 `run`  方法。 这样,一个最基础的框架就完成了。 最后,我们只要按照约定,将 Framework 导出即可。 ``` export { Application, Context, MidwayCustomHTTPFramework as Framework, IMidwayCustomConfigurationOptions, } from './custom'; ``` 上面是一个最简单的框架示例。事实上,Midway 所有的框架都是这么编写的。 ### 一些约定[​](#一些约定 "一些约定的直接链接") 自定义框架导出,除了约定的 `Framework`  之外,对于用户常用的定义,我们也有一些习惯性约定。 * 1、一般来说,我们将应用和请求上下文,约定为 `Application`  和 `Context` * 2、一般来说,默认的配置定义,我们约定为 `DefaultConfig` ## 自定义框架启动[​](#自定义框架启动 "自定义框架启动的直接链接") `@midwayjs/bootstrap`  能启动任意的基于 `IMidwayFramework`  实现的框架。只要我们导出了 `Framework`  属性即可。 ``` // bootstrap.js const Framework = require('xxxxx').Framework; const framework = new Framework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.load(framework).run(); ``` ## 自定义框架让用户开发和测试[​](#自定义框架让用户开发和测试 "自定义框架让用户开发和测试的直接链接") `@midwayjs/mock`  除了提供 app 的测试外,也提供了创建框架的方法,和应用测试类似,我们通过 `create`  方法创建一个框架实例。 ``` import { Framework } from 'xxxxxx'; import { create } from '@midwayjs/mock'; describe('/test/framework.test.ts', () => { it('test framework', async () => { // create framework with user code const framework = await create(); } } ``` --- # 常见框架错误 ## 多个 @midwayjs/decorator 警告[​](#多个-midwayjsdecorator-警告 "多个 @midwayjs/decorator 警告的直接链接") `@midwayjs/decorator` 包一般来说,npm 会让相同的依赖在 node\_modules 存在一份实例,其余的模块都会通过软链(link)链接到 node\_modules/@midwayjs/decorator。 我们会用到下面的命令,`npm ls` 会列出项目底下某个包的依赖树。 ``` $ npm ls @midwayjs/decorator ``` 比如下图所示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1619410071552-37bf3b21-202c-4925-9140-5244d526225c.png#clientId=u71824833-3cf4-4\&from=paste\&height=183\&id=u9799682e\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=183\&originWidth=541\&originalType=binary\&size=29975\&status=done\&style=none\&taskId=uc4dadc41-2faf-4bd0-a11b-703a7aa1734\&width=541) 灰色的 `deduped` 指的就是该包是被 npm 软链到同一个模块,是正常的。 我们再来看下有问题的示例。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1619410270669-45dd7973-ddc8-4ad5-b9b6-e7a2822b6686.png#clientId=u71824833-3cf4-4\&from=paste\&height=308\&id=u0fc19ab4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=308\&originWidth=1010\&originalType=binary\&size=140832\&status=done\&style=none\&taskId=u29f7d583-7971-4ffe-87cf-0413e02dfba\&width=1010) 这是一个 lerna 项目,最下面的 demo-docs 中的 decorator 包,后面没有 **deduped** 标示,说明这个包是独立存在的,是错误的。 根据这个思路,我们可以逐步排查为什么会出现这种情况。 比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装。 我们可以按照下面的思路逐步排查: * 1、包含不同版本的 decorator 包(比如,package-lock 锁包,或者依赖写死版本) * 2、未正确使用 lerna 的 hoist 模式(比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装) ## xxx is not valid in current context[​](#xxx-is-not-valid-in-current-context "xxx is not valid in current context的直接链接") 这个是当依赖注入容器中某个属性所关联的类在依赖注入容器中找不到爆出的。这个错误展示的可能会递归,比较深。 比如: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1621827595535-04bba2da-e00d-4743-8476-12b96733afca.png#clientId=u9d5ed330-0baa-4\&from=paste\&height=141\&id=u759ee365\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=141\&originWidth=1053\&originalType=binary\&size=191056\&status=done\&style=none\&taskId=ud19d0270-80f8-45a7-82e2-0e2a9da8e07\&width=1053) 错误核心就是第一个属性,在某个类中找不到。 比如上图的核心就是 `packageBuildInfoHsfService` 这个注入的类找不到。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1621827663159-75dd34ca-5dcd-4301-be23-f6bd59ee9f2e.png#clientId=u9d5ed330-0baa-4\&from=paste\&height=166\&id=ucf60cd20\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=166\&originWidth=765\&originalType=binary\&size=149169\&status=done\&style=none\&taskId=ub1438e1c-aceb-4a3a-b528-6858619363d\&width=765) 这个时候,就需要去对应的类中去看,是否是 provide 出来的名字被自定义了。 常见的问题有: * 1、Provide 装饰器导出的名字不对,无法和属性对应 * 2、Provide 为空的话,大概率是大小写没写对 * 3、注入是组件的话,可能是漏了组件名 简单的解法:`@Inject` 装饰器不加参数,属性的定义写明确的类,这样 midway 可以自动找到对应的类并注入(不适用于多态的情况)。 ``` @Inject() service: PackageBuildInfoHsfService; ``` --- # 常见 git 问题 ## 文件名大小写问题[​](#文件名大小写问题 "文件名大小写问题的直接链接") 由于 git 默认对大小写不敏感,如果文件名从小写变成了大写之后,无法发现文件有变化导致没有提交到仓库。 更可怕的是 mac 也是大小写不敏感,经常出现到本地可以运行,到服务器就执行错误的情况。 为此,我们最好把 git 的默认大小写关闭。 下面的命令。 ``` $ git config core.ignorecase false ## 对当前项目生效 $ git config --global --add core.ignorecase false ## 对全局生效 ``` ## windows 下换行问题[​](#windows-下换行问题 "windows 下换行问题的直接链接") 在 Windows 上创建或者克隆代码,开发或者提交时,可能出现如下错误: ``` Delete `␍`eslint(prettier/prettier) ``` 原因如下: 由于历史原因,windows 下和 linux 下的文本文件的换行符不一致。 * Windows 在换行的时候,同时使用了回车符 CR(carriage-return character) 和换行符 LF(linefeed character) * 而 Mac 和 Linux 系统,仅仅使用了换行符 LF * 老版本的 Mac 系统使用的是回车符 CR | Windows | Linux/Mac | Old Mac(pre-OSX | | ------- | --------- | --------------- | | CRLF | LF | CR | | '\n\r' | '\n' | '\r' | 因此,文本文件在不同系统下创建和使用时就会出现不兼容的问题。 解决方案如下: 设置全局 git 文本换行 ``` $ git config --global core.autocrlf false ``` 注意:git 全局配置之后,你需要重新拉取代码。 参考: * [Delete `␍`eslint(prettier/prettier) 错误的解决方案](https://juejin.cn/post/6844904069304156168) * [配置 Git 处理行结束符](https://docs.github.com/cn/github/getting-started-with-github/configuring-git-to-handle-line-endings) --- # 非 Serverless 环境使用一体化 在 Midway Serverless 2.0 中,我们支持了 Web 全栈应用的开发。 在后续的开发中,你可以将你的 Web 应用部署至任意的服务器,来为用户提供服务。 ## 项目创建[​](#项目创建 "项目创建的直接链接") 请先安装 `@midwayjs/cli`。 ``` # 如果是 npm v6 $ npm init midway --type=koa-hooks-react my_app # 如果是 npm v7 $ npm init midway -- --type=koa-hooks-react my_app $ cd my_app ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") > 生成后的目录结构如下 ``` . ├── bootstrap.js // 应用启动 ├── index.html ├── jest.config.js ├── midway.config.ts // Midway 配置文件 ├── package.json ├── src │   ├── App.css │   ├── App.tsx │   ├── apis // 后端文件(可在 midway.config.ts 修改) │   │   ├── configuration.ts │   │   └── lambda // Api 文件 │   │   ├── index.test.ts │   │   └── index.ts │   ├── favicon.svg │   ├── index.css │   ├── logo.svg │   └── main.tsx ├── tsconfig.json └── vite.config.ts // Vite 配置文件 ``` ## 本地运行[​](#本地运行 "本地运行的直接链接") 在项目根目录运行 `npm run dev` 即可启动项目,启动后,Vite 将输入可访问的地址。 > 复制地址到浏览器即可访问 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615534917254-24d943e2-59de-4245-9644-65af606f249e.png#height=148\&id=Jyv52\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=148\&originWidth=366\&originalType=binary\&ratio=1\&size=17073\&status=done\&style=none\&width=366) 页面显示如下画面则代表启动成功: ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615534968377-a64836b1-53e7-4cb6-8e28-518ff534d574.png#height=903\&id=gpL0D\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=903\&originWidth=1504\&originalType=binary\&ratio=1\&size=103681\&status=done\&style=none\&width=1504) 你可以修改 /src/apis/lambda 下的函数,尝试极为直观的函数式开发方式与极快的热更新所带来的流畅体验。 ## 单元测试[​](#单元测试 "单元测试的直接链接") 在应用根目录中,你可以运行 `npm run test` 来运行单元测试。 > 单元测试运行截图 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615535886310-db9a293e-0bd3-438e-86b2-e1629144757c.png#height=327\&id=VRpGm\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=327\&originWidth=717\&originalType=binary\&ratio=1\&size=39910\&status=done\&style=none\&width=717) 在单元测试中,我们提供了便捷的 runFunction 方法,帮助你快速完成单元测试,就像调用一个普通函数一样。 ``` import { createApp, HooksApplication } from '@midwayjs/hooks-testing-library'; import api from '.'; describe('test new features', () => { let app: HooksApplication; beforeAll(async () => { app = await createApp(); }); afterAll(async () => { await app.close(); }); it('runFunction', async () => { expect(await app.runFunction(api)).toMatchInlineSnapshot(` Object { "message": "Hello World", "method": "GET", } `); }); }); ``` ## 构建[​](#构建 "构建的直接链接") 在项目中,我们也提供了现成的 `npm run build` 命令,来快速构建项目。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615536615700-9e653c38-6942-49b6-907e-c388fc1c5c1b.png#height=433\&id=Upy5S\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=433\&originWidth=783\&originalType=binary\&ratio=1\&size=67053\&status=done\&style=none\&width=783) 构建结束后,可以通过 `node bootstrap.js` 来运行项目。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615536663706-57b78c22-8bf5-4907-bc01-07f2c346f1d4.png#height=61\&id=xAW86\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=61\&originWidth=672\&originalType=binary\&ratio=1\&size=12895\&status=done\&style=none\&width=672) 访问 `http://localhost:7001`,就可以看到页面了。 ## 线上部署[​](#线上部署 "线上部署的直接链接") 在完成后构建后,你可以按你喜欢的方式将应用部署至任意的服务器中。 在此,我们推荐使用 `[pm2](https://www.npmjs.com/package/pm2)` 来启动和管理应用。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1615536837253-5c2e21ea-626c-4c6b-9a72-3c773ee65500.png#height=209\&id=fyPSG\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=209\&originWidth=902\&originalType=binary\&ratio=1\&size=29305\&status=done\&style=none\&width=902) --- # 接口开发 & 前端调用 ## “零” API 调用[​](#零-api-调用 "“零” API 调用的直接链接") 在 Midway Hooks 中,你在前端可以直接导入服务端函数并进行调用。 这意味着你再也不用拼接 API URL,在前端手动发起请求并管理状态等。 > 后端接口 ``` import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } export async function post(name: string) { const ctx = useContext(); return { message: `Hello ${name}!`, method: ctx.method, }; } ``` > 前端调用 ``` import { getPath, post } from './apis/lambda'; // send GET request to /api/getPath const path = await getPath(); console.assert(path === '/api/getPath'); const { message, method } = await post('Jake'); console.assert(message === 'Hello Jake!'); console.assert(method === 'POST'); ``` 我们打造了“零” API 调用功能,你只需要关注于接口的调用,而非 HTTP 的细节。 ## 创建接口与调用[​](#创建接口与调用 "创建接口与调用的直接链接") 在 Midway Hooks 中,我们默认配置的接口是在 `lambda` 文件夹下 任意 `.ts` 文件中导出的异步函数,你也可以通过[路由配置](/docs/hooks_route)来使用自定义的文件夹。 ### Get[​](#get "Get的直接链接") 导出的函数中,如果不带参数则为 `Get` 接口。 > /apis/lambda/index.ts ``` export async function foo() { return 'foo'; } ``` > 前端调用示例(src/app.tsx) ``` import { foo } from './apis/lambda'; const response = await foo(); console.log(response); // foo ``` ### Post[​](#post "Post的直接链接") 函数有参数则为 `Post` 接口。 > /apis/lambda/index.ts ``` export async function bar(name: string) { return `hello ${name}`; } ``` > 前端调用示例(src/app.tsx) ``` import { bar } from './apis/lambda'; const response = await bar('张三'); console.log(response); // hello 张三 ``` ### Put/Delete[​](#putdelete "Put/Delete的直接链接") Midway Hooks 的接口信息与前端调用 SDK 均为自动生成,因此不支持 `Put/Delete` 调用。 ## 规则[​](#规则 "规则的直接链接") Midway Hooks 的接口,必须是在模块顶层直接导出的函数。 > 例子 ``` export async function demo() {} export const demo = async function () {}; export default async function demo() {} ``` --- # 纯接口项目增加 Hooks 支持 如果你之前的项目是 Midway Web 或者 Midway FaaS 的纯接口项目,想在代码中使用纯函数的开发方式,那么可以参考本文档。 > 安装依赖 ``` $ npm install @midwayjs/hooks -S ``` > 在根目录下新增:midway.config.ts ``` import { defineConfig } from '@midwayjs/hooks'; export default defineConfig({ source: './src', routes: [ { baseDir: 'lambda', basePath: '/api', }, ], }); ``` > 修改 configuration.ts(文件如不存在请新建) ``` import { Configuration } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { join } from 'path'; +import { hooks } from '@midwayjs/hooks' @Configuration({ importConfigs: [join(__dirname, './config/')], conflictCheck: true, + imports: [ + hooks() + ] }) export class ContainerLifeCycle implements ILifeCycle { ``` > 新增接口文件:src/lambda/index.ts ``` export default () => { return 'Hello Midway Hooks!'; }; ``` 启动工程,访问 /api,查看接口是否正确返回 `Hello Midway Hooks!`。 --- # 内置 Hooks ## useContext[​](#usecontext "useContext的直接链接") ``` const ctx = useContext(); ``` `useContext` 可以用于获取当前请求的上下文。 Context 类型可以通过泛型注入,如: ``` // Koa import { Context } from '@midwayjs/koa'; const ctx = useContext(); // FaaS import { Context } from '@midwayjs/faas'; const ctx = useContext(); ``` ### ctx.requestContext[​](#ctxrequestcontext "ctx.requestContext的直接链接") Midway 的 IoC 请求上下文对象,具体文档可以参考:[使用依赖注入](https://www.yuque.com/midwayjs/faas/use_inject) ### ctx.logger[​](#ctxlogger "ctx.logger的直接链接") Midway   自带的 Logger 对象 ## useInject[​](#useinject "useInject的直接链接") ``` function useInject(identifier: any): Promise; ``` useInject 是对 Midway IoC 依赖注入功能的封装,用于获取注入的实例,等同于 Class 里使用的 `@Inject` 装饰器与 [使用依赖注入](/docs/container.md) 文档中提到的 `getAsync` 方法。 > 示例 ``` import { useInject } from '@midwayjs/hooks'; import { Provide } from '@midwayjs/decorator'; export async function getModel() { const model = await useInject(Model); return model.name; } @Provide() export class Model { name = 'model'; } ``` 进一步的文档可以参考:[使用依赖注入](/docs/container.md)。 ## useConfig[​](#useconfig "useConfig的直接链接") ``` const config = useConfig('key'); ``` useConfig 可以用于获取业务配置。 业务配置的使用方式可以参考:[多环境配置](/docs/env_config.md) 警告 Midway Hooks 中,相关的函数文件默认存放于 `./src/apis/` 目录下。因此 config 与 configuration 所在的目录需为 `./src/apis/`(如修改了 midway.config.ts 的 source 字段,请使用修改后的目录) ## useLogger[​](#uselogger "useLogger的直接链接") ``` const logger = useLogger(); ``` `useLogger` 可以获取 `logger` 并输出日志。 输出日志: ``` logger.debug(); logger.info(); logger.warn(); logger.error(); ``` ## usePlugin[​](#useplugin "usePlugin的直接链接") 用于获取 Egg 插件等。 ``` const plugin = usePlugin('pluginName'); ``` > Demo:通过 [egg-sequelize](https://github.com/eggjs/egg-sequelize) 查询数据库 ``` import { usePlugin } from '@midwayjs/hooks'; export default async function getUserById(empId: number) { const sequelize = usePlugin('sequelize'); console.log(sequelize); } ``` --- # 运行时配置 & Hooks 组件 2.0 版 在 2.0 中,我们将 Midway Hooks 变为了 Midway 的 Component。 同时我们也支持了 `createConfiguration`,支持以函数的方式创建 `Midway Configuration`,减少 Class 与函数式混用所带来的迷惑感。 > ./src/apis/configuration.ts ``` import { hooks, createConfiguration } from '@midwayjs/hooks'; export default createConfiguration({ imports: [hooks()], }); ``` 通过上述方式即可启用 Hooks 功能。 --- # 项目初始化 ### 创建[​](#创建 "创建的直接链接") serverless 应用 ``` # npm v6 $ npm init midway --template=@midwayjs-examples/serverless-boilerplate-hooks-react # npm v7 $ npm init midway -- --template=@midwayjs-examples/serverless-boilerplate-hooks-react ``` web 应用 ``` # npm v6 $ npm init midway --template=@midwayjs-examples/applicaiton-hooks-koa-react # npm v7 $ npm init midway -- --template=@midwayjs-examples/applicaiton-hooks-koa-react ``` 社区用户也提供了 vue 模板,可以查看 [issue](https://github.com/midwayjs/midway/issues/1229) ### 运行[​](#运行 "运行的直接链接") ``` $ npm run dev ``` 此时可以访问命令行提示的端口,就能看到页面了,你也可以点击 `Send message to backend`,来体验函数式开发的接口。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622788746000-d557cbdb-76d7-435f-91d8-1a1f54c6af51.png#clientId=u5406b60f-a2f1-4\&from=paste\&height=222\&id=u1aaa3515\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=222\&originWidth=404\&originalType=binary\&ratio=1\&size=58812\&status=done\&style=none\&taskId=ueeba5812-e5fb-4ffc-907c-9aabe6a78aa\&width=404) ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622788715959-e1b7d313-9ce3-40c4-bb32-066b665c4d78.png#clientId=u5406b60f-a2f1-4\&from=paste\&height=845\&id=ub431f200\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=845\&originWidth=1469\&originalType=binary\&ratio=1\&size=338897\&status=done\&style=none\&taskId=u00355cc6-42ea-4999-a6f5-dda5270d326\&width=1469) ### 部署[​](#部署 "部署的直接链接") 部署前请先运行: ``` npm run build ``` > 部署 Web 应用 ``` $ node bootstrap.js ``` > 部署 Serverless ``` $ npm run deploy ``` --- # 自定义前端 SDK Midway Hooks 默认使用浏览器指定的 fetch 发送请求,为了支持不同场景,开发者可以自定义请求函数。 比如,你希望使用 Axios 作为 HTTP 请求的客户端,只需要在前端页面入口处,添加如下代码即可: ``` import { defaults, ApiParam } from '@midwayjs/hooks/request'; import axios from 'axios'; defaults.request = async (param: ApiParam) => { const resp = await axios(params); return resp.data; }; ``` ##### 注意事项[​](#注意事项 "注意事项的直接链接") 关于开发者实现的自定义函数,需要注意以下情况: * 自定义函数对所有请求生效,重复设置 `defaults.request` 方法,会覆盖之前的设置 * 自定义函数的返回值应该是调用的接口返回值,像 `axios` 这种对响应自行包装的,需要手动解析出接口的返回值 --- # 本地调试 ## VSCode[​](#vscode "VSCode的直接链接") ### JavaScript Debug Terminal[​](#javascript-debug-terminal "JavaScript Debug Terminal的直接链接") 在 VSCode 中创建 JavaScript Debug Terminal。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789601759-d2634846-49f7-4487-be6f-0dc9e5f80082.png#clientId=u3a1b2f6d-ebe0-4\&from=paste\&height=192\&id=p5BOe\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=192\&originWidth=375\&originalType=binary\&size=31856\&status=done\&style=none\&taskId=u7286159b-9369-4d17-8a6a-c43a6f52556\&width=375) 在命令行中运行命令(如 `npm start`),将自动启用调试模式。 ### Debug Scripts[​](#debug-scripts "Debug Scripts的直接链接") 打开 `package.json`,查看 `scripts` 上方的 `debug` 按钮 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789617835-64b2099a-6b94-41c4-81fa-4f0bb0763ebb.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=225\&id=u459844f5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=225\&originWidth=565\&originalType=binary\&size=26636\&status=done\&style=none\&taskId=u3838b111-c93e-41e0-81ce-01c1bdd6ad4\&width=565) 选择 `start` 命令,既可正常的启动调试模式 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789623261-57851b50-421e-45fa-9dd9-95ac7d48776e.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=170\&id=ue315d401\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=170\&originWidth=427\&originalType=binary\&size=19905\&status=done\&style=none\&taskId=u8b079aa2-8376-4014-b48b-ed27ef66da6\&width=427) ## Jetbrains (WebStorm/IDEA...)[​](#jetbrains-webstormidea "Jetbrains (WebStorm/IDEA...)的直接链接") 打开 `package.json`,选择你要执行的 `scripts` ,并点击 `debug` 按钮,即可启动本地调试 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789628840-eb403a2a-a864-4fd6-8f57-3f576c9b3417.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=176\&id=uc2a06ce8\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=176\&originWidth=548\&originalType=binary\&size=28656\&status=done\&style=none\&taskId=ucb4c5c34-6e56-47c9-a724-4ed700dce9d\&width=548) --- # Web 中间件 在 2.0 版本中,Midway Hooks 支持三种形式的中间件,用来覆盖不同的使用诉求。 * 2.0 全局,对所有 Api 调用都生效 * 2.0 文件,对文件内部所有 Api 生效 * 1.0 函数,仅对该 Api 函数生效 ## ## 语法[​](#语法 "语法的直接链接") 中间件仅有 `next` 一个参数,`ctx` 需要通过 `useContext` 获得。你也可以在中间件中使用任意的 `Hooks`。 > Logger 中间件 ``` import { Context } from '@midwayjs/faas'; import { useContext } from '@midwayjs/hooks'; const logger = async (next: any) => { const ctx = useContext(); console.log(`<-- [${ctx.method}] ${ctx.url}`); const start = Date.now(); await next(); const cost = Date.now() - start; console.log(`[${ctx.method}] ${ctx.url} ${cost}ms`); }; ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 全局中间件在 `configuration.ts` 中定义,可以传入任何框架支持的中间件 ``` import { hooks, createConfiguration } from '@midwayjs/hooks'; import logger from './logger'; // Global Middleware export default createConfiguration({ imports: [ hooks({ middleware: [logger], }), ], }); ``` ### 文件级中间件[​](#文件级中间件 "文件级中间件的直接链接") 文件级中间件在 Api 文件中定义,通过导出 `config.middleware`,使得其对该文件内所有 Api 函数生效。 ``` import { ApiConfig } from '@midwayjs/hooks'; import logger from './logger'; // File Level Middleware export const config: ApiConfig = { middleware: [logger], }; export default async (message: string) => { return { type: 'POST', message }; }; ``` ## 单函数中间件[​](#单函数中间件 "单函数中间件的直接链接") 单函数中间件即只针对单个函数生效的 Web 中间件。 在 Midway Hooks 中,可以通过 `withController` 来支持单函数级别的中间件。 > 使用函数中间件 ``` import { withController } from '@midwayjs/hooks'; import { Context } from '@midwayjs/faas'; const logger = async (next) => { const ctx: Context = useContext(); const start = Date.now(); await next(); const cost = Date.now() - start; console.log(`request ${ctx.url} cost ${cost}ms`); }; export default withController( { middleware: [logger], }, () => { return 'Hello Controller'; } ); ``` > 使用 IoC 中间件 ``` import { withController } from '@midwayjs/hooks'; import { Context } from '@midwayjs/faas'; import { Provide, ScopeEnum, Scope } from '@midwayjs/decorator'; @Provide('classMiddleware') @Scope(ScopeEnum.Singleton) export class ClassMiddleware { resolve() { return async (ctx: Context, next) => { ctx.query.from = 'classMiddleware'; await next(); }; } } export default withController( { middleware: ['classMiddleware'], }, () => { return 'Hello Controller ' + ctx.query.from; } ); ``` ## API[​](#api "API的直接链接") ## withController[​](#withcontroller "withController的直接链接") 通过 `withController` 增强函数功能,第一个参数是 controller 配置,第二个参数是要执行的 FaaS 函数。 其中 controller 配置如下 * middleware(`any[]`):可选参数,用于给当前的函数增加中间件功能,可以同时传入多个中间件。支持函数定义的中间件及 IoC 定义的中间件。 > 类型定义 ``` type Controller = { middleware?: any[]; }; function withController(controller: Controller, func); ``` --- # 小程序一体化 小程序一体化是 Midway.js 团队与 Rax 团队合作的产品,通过 Midway.js 对一体化的支持与 Rax 对小程序的支持,我们可以为小程序带去更好的研发体验。 ## ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630379244981-d18b59d3-e27d-455e-8562-0eb7e370f6b9.png#clientId=uae0cc9ff-b84a-4\&from=paste\&height=1080\&id=u4a272148\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1080\&originWidth=1920\&originalType=binary\&ratio=1\&size=108701\&status=done\&style=stroke\&taskId=u4b884bcc-4e76-4311-93fe-877bb69b911\&width=1920) ## 初始化[​](#初始化 "初始化的直接链接") 在命令行输入以下命令,即可快速完成小程序一体化项目的创建。 ``` npm init rax ``` 选择 App -> 小程序云开发一体化应用即可。 ## 本地开发[​](#本地开发 "本地开发的直接链接") > 以微信小程序开发为例 项目创建完成后,进入项目根目录。 ### 配置 AppId[​](#配置-appid "配置 AppId的直接链接") 小程序的运行与预览依赖于 AppId([获取方式](https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.html#%E7%94%B3%E8%AF%B7%E5%B8%90%E5%8F%B7)),获取到 AppID 时,你可以打开项目根目录的 build.json 文件,将 AppId 配置在此。 ``` { "targets": [ //... ], "plugins": [ //... ], "wechat-miniprogram": { "nativeConfig": { "appid": "<你的 AppID>", "name": "nativeConfig 是用户配置 project.config.json 的地方" } } } ``` ### 本地启动[​](#本地启动 "本地启动的直接链接") 运行如下命令。 ``` npm start ``` 本地服务启动后将输出以下日志。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630379551910-f8a43b3b-0017-4aad-b5f8-5eca9056f4df.png#clientId=uae0cc9ff-b84a-4\&from=paste\&height=326\&id=uc1e5095d\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=326\&originWidth=981\&originalType=binary\&ratio=1\&size=56255\&status=done\&style=stroke\&taskId=u26c58d5b-51ea-487b-906f-0484e4bd264\&width=981) ### 目录结构[​](#目录结构 "目录结构的直接链接") 整体目录结构如下 * src:前端开发目录 * src/cloud:云开发目录 * src/cloud/functions:云函数目录 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630379466121-ef63511d-4a9a-441a-846d-6c80912f3bd8.png#clientId=uae0cc9ff-b84a-4\&from=paste\&height=1124\&id=lhHzc\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1124\&originWidth=2272\&originalType=binary\&ratio=1\&size=363965\&status=done\&style=stroke\&taskId=uf9b75197-be74-4d6d-b23d-4142578e747\&width=2272) ### 使用小程序开发工具预览[​](#使用小程序开发工具预览 "使用小程序开发工具预览的直接链接") 打开微信小程序开发者工具,选择导入项目,微信小程序的目录是 <项目根目录>/build/wechat-miniprogram. ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630381124950-fd510d0e-fd14-42e3-a01a-6efa92be1ea2.png#clientId=u5ad910ea-f37d-4\&from=paste\&height=909\&id=ufe8e37e3\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=909\&originWidth=1708\&originalType=binary\&ratio=1\&size=125292\&status=done\&style=none\&taskId=ud11606b5-14a1-42d3-9cd2-f09afba9eeb\&width=1708) 你可以在此处预览项目,并进行函数的部署与发布工作。 ### 开发函数[​](#开发函数 "开发函数的直接链接") 使用 Midway Hooks 可以方便的开发云函数。 > 以获取 OpenId 为例。 ``` export const getOpenId = async () => { const wechatContext = cloud.getWXContext(); return { openId: wechatContext.OPENID, }; }; ``` > 前端调用代码(需要提前安装 rax-use-async-effect 依赖) ``` import { createElement, useState } from 'rax'; import useAsyncEffect from 'rax-use-async-effect'; import View from 'rax-view'; import Text from 'rax-text'; import styles from './index.module.css'; import Logo from '../../components/Logo'; import { hello, getOpenId } from '@/cloud/function'; export default function Home() { const [message, setMessage] = useState(''); const [openId, setOpenId] = useState(''); useAsyncEffect(async () => { const message = await hello('Rax', 'Midway.js'); setMessage(message); const { openId } = await getOpenId(); setOpenId(`${openId!.substring(0, 3)}***************${openId!.substring(14)}`); }, []); return ( Welcome to Your Rax App Message: {message} OpenId: {openId} ); } ``` Midway Hooks 相关的语法和文档可参考: [介绍](/docs/hooks/intro.md?view=doc_embed) ### 函数部署[​](#函数部署 "函数部署的直接链接") 云开发的函数需要部署后才能调用,你可以在生成的 cloudfunctions 目录下,通过右键点击上传部署函数。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630381168629-1871ca82-65b7-45d4-9625-3b3cb12327b8.png#clientId=u5ad910ea-f37d-4\&from=paste\&height=220\&id=u9070ab28\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=220\&originWidth=611\&originalType=binary\&ratio=1\&size=42440\&status=done\&style=none\&taskId=u87382ca9-543b-4541-8748-12e0e7eb4be\&width=611) 部署完成后重新编译项目即可查看函数运行结果,更多的云开发指导,可以参考官方文档: ### 本地调试[​](#本地调试 "本地调试的直接链接") 你可以方便的通过小程序开发工具来进行函数调试,如下图所示。 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1630381412803-f33ed7ef-c043-4a96-bcbf-40d308c4b523.png#clientId=u5ad910ea-f37d-4\&from=paste\&height=794\&id=uf83f1005\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=794\&originWidth=1752\&originalType=binary\&ratio=1\&size=490406\&status=done\&style=none\&taskId=u7623c3c6-3c12-4d40-bbb0-8e4a0544197\&width=1752) 参考文档: ## 项目部署[​](#项目部署 "项目部署的直接链接") 在完成开发后,即可开始发布小程序,后续参考云开发平台的发布文档即可。 小程序发布: --- # 路由 Midway Hooks 的路由机制是文件路由,我们会根据 目录/文件/导出的方法 来分析出路由配置。同时我们也提供了相应的配置选项。 ## 默认配置[​](#默认配置 "默认配置的直接链接") ### 2.0 版本[​](#20-版本 "2.0 版本的直接链接") 在 2.0 中,我们将文件路由的配置统一至 `midway.config.ts` 中。 > midway.config.ts ``` import { defineConfig } from '@midwayjs/hooks'; export default defineConfig({ source: './src/apis', routes: [ { baseDir: 'lambda', basePath: '/api', }, ], }); ``` #### 字段解释[​](#字段解释 "字段解释的直接链接") * source: 后端目录,默认为` ./src/apis`,你也可以指定为 `./src/functions` 等自定义目录 * routes: 路由配置,默认为数组 * baseDir: 函数文件夹,文件夹下任意 `.ts` 文件导出的异步函数都会生成为 Api 接口 * basePath: 生成的 API 地址前缀 ### 1.0 版本[​](#10-版本 "1.0 版本的直接链接") 文件路由系统的解析机制是可配置的,下面是一体化项目中默认的配置。 > f.yml ``` functionsRule: rules: - baseDir: lambda events: http: basePath: /api ``` #### 字段解释[​](#字段解释-1 "字段解释的直接链接") * rules: 具体函数路由配置规则 * baseDir: 函数文件夹,文件夹下任意 `.ts` 文件导出的异步函数都会生成为 Api 接口 * events: 函数触发器配置 * http * basePath: 生成的 API 地址前缀 * underscore: 0.x 兼容逻辑,默认为 false,添加后将在具名路由的生成时,在方法名前添加下划线 ## Index 路由[​](#index-路由 "Index 路由的直接链接") 我们会将目录下 `index.ts` 文件,作为根路由。 * `/lambda/index.ts`  → `/` * `/lambda/about/index.ts` →  `/about` ## 嵌套路由[​](#嵌套路由 "嵌套路由的直接链接") 嵌套的文件也将生成嵌套的路由 * `/lambda/about.ts`  → `/about` * `/lambda/blog/index.ts`  → `/blog` * `/lambda/about/contact.ts`  →  `/about/contact` ## 导出方法与对应路由[​](#导出方法与对应路由 "导出方法与对应路由的直接链接") 默认导出的方法则会生成为根路径,而具名方法则会在路径上拼接函数名。 在此以 `/lambda/about.ts`   为例 * `export default () => {}`   → `/about` * `export function contact ()` → `/about/contact` ## 通配路由[​](#通配路由 "通配路由的直接链接") Midway Hooks 支持通过文件名生成通配符路由,例如:`/api/*` ,可以匹配 /api、/api/about、/api/about/a/b/c 等。只需要在文件名上加入 `...` 即可。 例子: * `/lambda/[...index].ts` → `/api/*` * `/lambda/[...user].ts` → `/api/user/*` * `/lambda/about/[...contact].ts` → `/api/about/contact/*` 信息 我们推荐在通配路由中,只存在 `export default` 方法,从而避免不必要的路由冲突 --- # Hooks 语法 Midway Hooks 使用了类似于 React Hooks 的语法,允许开发者通过 Function + Hooks 的方式,获取当前请求数据并提供 Web 服务。 在下面的例子中,我们通过 `useContext` 获取请求上下文,并返回当前请求的 HTTP Method。 ``` import { useContext } from '@midwayjs/hooks'; export function getHttpMethod() { const { request } = useContext(); return request.method; } ``` ## 什么是 Hooks[​](#什么是-hooks "什么是 Hooks的直接链接") Hooks 是一些可以让你在函数里访问当前请求上下文信息的函数。 我们提供了内置的 Hooks: * useContext: 获取请求上下文 * useLogger: 获取 Logger * useInject: 获取 IoC 注入的实例 * useConfig: 获取用户配置 * usePlugin: 获取 Egg 插件 你也可以创建自己的 Hooks 来复用代码逻辑。 ## 与 React Hooks 的区别[​](#与-react-hooks-的区别 "与 React Hooks 的区别的直接链接") 在 Midway Hooks 中,Hooks 是用于访问请求上下文信息的函数。因此 Hooks 只是用于访问信息,而不能保存状态或执行副作用等。 ## 自定义 Hooks[​](#自定义-hooks "自定义 Hooks的直接链接") 我们可以通过自定义 Hooks 来对复杂逻辑进行封装与复用。 在定义与封装 Hooks 时,我们要求遵守统一的 Hooks 命名规范,以 `use` 作为自定义 Hooks 的命名前缀,如 `useHeader, usePath` 等。 > 定义 Hooks(apis/hooks/request.ts) ``` import { useContext } from '@midwayjs/hooks'; export function useHeader() { const { request } = useContext(); return request.headers; } export function usePath() { const { request } = useContext(); return request.path; } ``` > 调用自定义 Hooks(apis/function/index.ts) ``` import { useHeader, usePath } from '../hooks/request'; export function get() { return { header: useHeader(), path: usePath(), }; } ``` --- # 介绍 ## ✨ 特性[​](#-特性 "✨ 特性的直接链接") * ☁️   全栈,在 src 一个目录中开发前后端代码 * 🌈  "零" API,从后端 import 函数,调用时自动转换为 API 请求 * 🌍 使用 "React Hooks | Vue composition Api" 开发后端 * ⚡️   极快的启动速度(小于 3 秒) * ⚙️   使用 Vite,支持 React/Vue 等框架 * ✈️   可部署至 Server 或者 Serverless * 🛡 完善的 TypeScript 支持 ## ☁️ 应用结构[​](#️-应用结构 "☁️ 应用结构的直接链接") 基于 Midway Hooks 开发应用有以下几点优势: * **易于开发**,前后端同仓库,无缝融合一体开发 * **易于部署**,前后端一同发布与部署 * **易于维护**,在同一仓库中排查问题,后端支持使用 Serverless 部署,降低运维难度 > 目录结构 ![](https://cdn.nlark.com/yuque/0/2021/png/98602/1622788353126-95c182d2-1462-4ff0-b166-51d6f3405f2d.png#clientId=uaba2bffc-e32b-4\&from=paste\&height=1866\&id=u2422df2b\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1866\&originWidth=1948\&originalType=binary\&ratio=1\&size=199238\&status=done\&style=none\&taskId=u29d9d308-25ac-4631-ba44-adfa132e044\&width=1948) ## 🌰 代码示例[​](#-代码示例 "🌰 代码示例的直接链接") > 后端接口 ``` import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } export async function post(name: string) { const ctx = useContext(); return { message: `Hello ${name}!`, method: ctx.method, }; } ``` > 前端调用 ``` import { getPath, post } from './apis/lambda'; // send GET request to /api/getPath const path = await getPath(); console.assert(path === '/api/getPath'); const { message, method } = await post('Jake'); console.assert(message === 'Hello Jake!'); console.assert(method === 'POST'); ``` --- # OSS 文件上传 由于函数网关的问题,文件无法直传至函数,但我们也提供了两种方式来解决文件上传的问题。 ## 【推荐】后端生成加密地址,前端上传[​](#推荐后端生成加密地址前端上传 "【推荐】后端生成加密地址,前端上传的直接链接") OSS 上传目前采用阿里云提供的开源包「ali-oss」,npm 包地址: ### 安装[​](#安装 "安装的直接链接") > 安装依赖 ``` npm i ali-oss -S && npm i @types/ali-oss -D ``` ### 阿里云 OSS 配置[​](#阿里云-oss-配置 "阿里云 OSS 配置的直接链接") 客户端进行表单直传到 OSS 时,会从浏览器向 OSS 发送带有`Origin`的请求消息。OSS 对带有`Origin`头的请求消息会进行跨域规则(CORS)的验证,因此需要为 Bucket 设置跨域规则以支持 Post 方法 1. 登录[OSS 管理控制台](https://oss.console.aliyun.com/)。 2. 单击**Bucket 列表**,之后单击目标 Bucket 名称。 3. 单击**权限管理 > 跨域设置**,在**跨域设置**区域单击**设置**。 4. 单击**创建规则**,配置如下图所示。 \[ ![](https://cdn.nlark.com/yuque/0/2020/png/98602/1607502650388-1a12351a-99f3-4099-87b4-830d8f700681.png#height=866\&id=BlST2\&originHeight=866\&originWidth=688\&originalType=binary\&size=0\&status=done\&style=none\&width=688) ]\() ### 后端代码[​](#后端代码 "后端代码的直接链接") ``` // src/apis/lambda/index.ts /** * * @param params Object {filename: 编码后文件名称} */ export async function getOSSUploadUrl(params: { filename: string }) { const { filename } = params; const dir = 'user-dir-prefix/'; // OSS 文件根目录 const client = new OSS({ region: '', // 这里需要修改成你自己的 region accessKeyId: '', // 这里需要修改成你自己的 accessKeyId accessKeySecret: '', // 这里需要修改成你自己的 accessKeySecret bucket: '', // 这里需要修改成你自己的 bucket secure: true, }); const url = client.signatureUrl(dir + decodeURIComponent(filename), { method: 'PUT', 'Content-Type': 'application/octet-stream', }); return url; } ``` ### 前端代码[​](#前端代码 "前端代码的直接链接") ``` import React, { useEffect, useState } from 'react'; import { getOSSUploadUrl } from '../../apis/lambda'; export default () => { const [message, setMessage] = useState(''); useEffect(() => {}, []); const uploadPhoto = (e: any) => { const file = e.target.files[0]; const filename = encodeURIComponent(file.name); getOSSUploadUrl({ filename }).then((url) => { const contentType = 'application/octet-stream'; const body = new Blob([file], { type: contentType }); fetch(url, { method: 'PUT', headers: new Headers({ 'Content-Type': contentType }), body, }) .then((res) => { setMessage(`上传成功!文件路径:${url.substring(0, url.indexOf('?'))}`); }) .catch((e) => { console.log(e); }); }); }; return (
<>

上传文件,可以在accept属性中控制想要传的文件类型

{message}

); }; ``` ### 注意事项[​](#注意事项 "注意事项的直接链接") 获取上传文件地址的时候有很多的权限设置可以在 阿里云的 OSS 控制台设置,如果返回的 url 在页面中打不开,那么需要在 OSS 控制台授权 ![](https://cdn.nlark.com/yuque/0/2020/png/98602/1607502650376-2efc20dd-6387-42e5-a8ec-21543f6fa751.png#height=179\&id=NebVF\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=358\&originWidth=2194\&originalType=binary\&size=119122\&status=done\&style=none\&width=1097) ## 前端 OSS SDK 直传[​](#前端-oss-sdk-直传 "前端 OSS SDK 直传的直接链接") 小文件(大小 < 3m)可通过编码至 base64 上传,大文件请采用前端 OSS 的方式上传。参考文档:[OSS Browser.js SDK](https://help.aliyun.com/document_detail/64041.html?spm=a2c4g.11174283.6.1332.75c17da2VHuApP) 前端 OSS SDK 可能会有泄露 access key 与 sercet key 的问题,推荐配合 [阿里云临时安全令牌(Security Token Service,STS)](https://help.aliyun.com/document_detail/28756.html) 使用。 --- # 如何安装 Node.js 环境 ## 使用场景[​](#使用场景 "使用场景的直接链接") 一般来说,直接从 [Node.js 官网](https://link.zhihu.com/?target=https%3A//nodejs.org/)下载对应的安装包,即可完成环境配置。 但在**本地开发**的时候,经常需要快速更新或切换版本。 社区有 [nvm](https://link.zhihu.com/?target=https%3A//github.com/creationix/nvm)、[n](https://link.zhihu.com/?target=https%3A//github.com/tj/n) 等方案,我们推荐跨平台的 [nvs](https://link.zhihu.com/?target=https%3A//github.com/jasongin/nvs)。 * nvs 是跨平台的。 * nvs 是基于 Node 编写的,我们可以参与维护。 > 友情提示:Node 6.x 和 8.x 都将在今年结束 LTS 的支持,请尽快升级到 10.x 。 [https://github.com/nodejs/Release](https://link.zhihu.com/?target=https%3A//github.com/nodejs/Release) **PS:nvs 我们一般只用于本地开发,线上参见:**[科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) *** ## 如何安装[​](#如何安装 "如何安装的直接链接") ### Linux / macOS 环境[​](#linux--macos-环境 "Linux / macOS 环境的直接链接") 通过 Git Clone 对应的项目即可。 ``` $ export NVS_HOME="$HOME/.nvs" $ git clone https://github.com/jasongin/nvs --depth=1 "$NVS_HOME" $ . "$NVS_HOME/nvs.sh" install ``` ### Windows 环境[​](#windows-环境 "Windows 环境的直接链接") 由于 Windows 环境配置比较复杂,所以还是推荐使用 `msi` 文件完成初始化工作。 访问 [nvs/releases](https://link.zhihu.com/?target=https%3A//github.com/jasongin/nvs/releases) 下载最新版本的 `nvs.msi`,然后双击安装即可。 *** ## 配置镜像地址[​](#配置镜像地址 "配置镜像地址的直接链接") 在国内由于大家都懂的原因,需要把对应的镜像地址修改下: ``` $ nvs remote node https://npm.taobao.org/mirrors/node/ $ nvs remote default node chakracore https://github.com/nodejs/node-chakracore/releases/ chakracore-nightly https://nodejs.org/download/chakracore-nightly/ nightly https://nodejs.org/download/nightly/ node https://nodejs.org/dist/ ``` *** ## 使用指南[​](#使用指南 "使用指南的直接链接") 通过以下命令,即可非常简单的安装 Node.js 最新的 LTS 版本。 ``` # 安装最新的 LTS 版本 $ nvs add lts # 配置为默认版本 $ nvs link lts ``` 安装其他版本: ``` # 安装其他版本尝尝鲜 $ nvs add 12 # 查看已安装的版本 $ nvs ls # 在当前 Shell 切换版本 $ nvs use 12 ``` 更多指令参见 `nvs --help` 。 *** ## 共用 npm 全局模块[​](#共用-npm-全局模块 "共用 npm 全局模块的直接链接") 使用 `nvs` 时,默认的 `prefix` 是当前激活的 Node.js 版本的安装路径。 带来一个问题是:切换版本之后,之前安装全局命令模块需要重新安装,非常不方便。 解决方案是配置统一的全局模块安装路径到 `~/.npm-global`,如下: ``` $ mkdir -p ~/.npm-global $ npm config set prefix ~/.npm-global ``` 还需配置环境变量到 `~/.bashrc` 或 `~/.zshrc` 文件里面: ``` $ echo "export PATH=~/.npm-global/bin:$PATH" >> ~/.zshrc $ source ~/.zshrc ``` *** ## 相关阅读[​](#相关阅读 "相关阅读的直接链接") * [科普文:Node.js 安全攻防 - 如何伪造和获取用户真实 IP ?](https://zhuanlan.zhihu.com/p/62265144) * [科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) * [科普文:为什么不能在服务器上 npm install ?](https://zhuanlan.zhihu.com/p/39209596) --- # 如何更新 Midway ## midway 项目的依赖使用 lerna 发布,**请不要**: * 1、单独升级某个 @midwayjs/\* 的包 * 2、将 package.json 中的版本号移除 ^ 符号 ## 普通项目更新[​](#普通项目更新 "普通项目更新的直接链接") 普通使用 npm/yarn 的项目,升级请按照下面的流程 * 1、删除 package-lock.json 或者 yarn.lock * 2、彻底删除 node\_modules(比如 rm -rf node\_modules) * 3、重新安装依赖( npm install 或者 yarn) **我们不保证使用其他工具、cli 单独升级包的效果。** ## lerna 项目更新[​](#lerna-项目更新 "lerna 项目更新的直接链接") 使用 lerna 开发项目,由于有 hoist 模式的存在,升级请按照下面的流程(以 lerna3 为例) * 1、清理子包的 node\_modules,比如(lerna clean --yes) * 2、删除主包的 node\_modules(比如 rm -rf node\_modules) * 3、删除 package-lock.json 或者 yarn.lock * 4、重新安装依赖( npm install && lerna bootstrap) **我们不保证使用其他工具、cli 单独升级包的效果。** ## 大版本更新[​](#大版本更新 "大版本更新的直接链接") 请手动修改版本号,比如从 `^1.0.0` 修改为 `^2.0.0` 。 ## 查看当前包版本[​](#查看当前包版本 "查看当前包版本的直接链接") Midway 包采用标准的 Semver 版本进行管理和发布,在 `package.json` 指定的版本一般为 `^` 开头,表示在大版本范围内都兼容。 比如,`package.json` 中 `@midwayjs/core` 为 `^2.3.0` ,那么按照 npm 安装规则,会安装 `2.x` 这个版本下最新的 latest 版本。 所以实际安装的版本高于 `package.json` 中指定的版本都是正常的。 你可以使用 `npm ls 包名` 来查看具体的版本,比如 `npm ls @midwayjs/core` 来查看 `@midwayjs/core` 的版本。 ## 版本匹配查询[​](#版本匹配查询 "版本匹配查询的直接链接") 由于 lerna 发包有一定的依赖性,比如修改到的包才会更新,就会出现 **midway 下的包版本不一定完全一致的情况。** 比如,`@midwayjs/web` 的版本高于 `@midwayjs/core`,这都是很正常的。 midway 每次发布会提交一个 [@midwayjs/version ](https://www.npmjs.com/package/@midwayjs/version)的包,其中包含了我们每个版本,以及该版本的包所匹配的全部包版本,请 [访问这里](https://github.com/midwayjs/midway/tree/2.x/packages/version/versions) 查看。 目录中的文件名按照 `@midwayjs/decorator版本 - @midwayjs/core版本.json` 规则创建,每个版本对应一个 JSON 文件。 文件内容以包名作为 key,以可兼容匹配的版本名作为值。 比如,当前文件 decorator(v2.10.18)和 core(v2.10.18) 所能兼容的 egg-layer 包版本为 v2.10.18 和 v2.10.19。 如果 decorator 和 core 组合的文件名未找到,或者文件里的版本不匹配,都说明 **版本可能产生了问题**。 内容示例如下: ``` { "@midwayjs/egg-layer": ["2.10.18", "2.10.19"], "@midwayjs/express-layer": "2.10.18", "@midwayjs/faas-typings": "2.10.7", "@midwayjs/koa-layer": "2.10.18", "@midwayjs/runtime-engine": "2.10.14", "@midwayjs/runtime-mock": "2.10.14", "@midwayjs/serverless-app": "2.10.18", "@midwayjs/serverless-aws-starter": "2.10.14", "@midwayjs/serverless-fc-starter": "2.10.18", "@midwayjs/serverless-fc-trigger": "2.10.18", "@midwayjs/serverless-http-parser": "2.10.7", "@midwayjs/serverless-scf-starter": "2.10.14", "@midwayjs/serverless-scf-trigger": "2.10.18", "@midwayjs/static-layer": "2.10.18", "@midwayjs/bootstrap": "2.10.18", "@midwayjs/cache": "2.10.18", "@midwayjs/consul": "2.10.18", "@midwayjs/core": "2.10.18", "@midwayjs/decorator": "2.10.18", "@midwayjs/faas": "2.10.18", "@midwayjs/grpc": "2.10.18", "@midwayjs/logger": "2.10.18", "midway-schedule": "2.10.18", "midway": ["2.10.18", "2.10.19"], "@midwayjs/mock": "2.10.18", "@midwayjs/prometheus": "2.10.18", "@midwayjs/rabbitmq": "2.10.18", "@midwayjs/socketio": "2.10.18", "@midwayjs/task": ["2.10.18", "2.10.19"], "@midwayjs/typegoose": "2.10.18", "@midwayjs/version": ["2.10.18", "2.10.19"], "@midwayjs/express": "2.10.18", "@midwayjs/koa": "2.10.18", "@midwayjs/web": ["2.10.18", "2.10.19"] } ``` --- # 介绍 Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架。 Midway 基于 TypeScript 开发,结合了`面向对象(OOP + Class + IoC)`与`函数式(FP + Function + Hooks)`两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验 ## 为什么要有 Midway[​](#为什么要有-midway "为什么要有 Midway的直接链接") 社区上也有很多类似的框架,那为什么还需要 Midway ? 原因有三点 1. Midway 是阿里内部一直持续在研发的框架,之前 egg 是作为底层框架,需要有面向应用层面的框架来和集团场景对接 2. 全量使用 TypeScript 是未来一段时间的趋势,面向未来去迭代和研发是作为架构组创新的要求 3. 虽然社区已经有 nest 这样的框架,但是这些产品的维护、协作、修改都会受到商业化产品的制约,也无法做到需求的快速迭代和安全性保障,整体的研发理念也和我们不同,为此,我们需要有一套自研的框架体系 ## 我们的优势[​](#我们的优势 "我们的优势的直接链接") 1. Midway 框架是在内部已经使用 5 年以上的 Node.js 框架,有着长期投入和持续维护的团队做后盾。 2. 已经在每年的大促场景经过考验,稳定性无须担心 3. 丰富的组件和扩展能力,例如数据库,缓存,定时任务,进程模型,部署以及 Web,Socket 甚至 Serverless 等新场景的支持 4. 一体化调用方案可以方便快捷和前端页面协同开发 5. 良好的 TypeScript 定义支持 6. 国产化文档和沟通容易简单 ## 多编程范式[​](#多编程范式 "多编程范式的直接链接") Midway 支持面向对象与函数式两种编程范式,你可以根据实际研发的需要,选择不同的编程范式来开发应用。 ### 面向对象(OOP + Class + IoC)[​](#面向对象oop--class--ioc "面向对象(OOP + Class + IoC)的直接链接") Midway 支持面向对象的编程范式,为应用提供更优雅的架构。 下面是基于面向对象,开发路由的示例。 ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { return { message: 'Hello Midwayjs!', query: this.ctx.ip, }; } } ``` ### 函数式(FP + Function + Hooks)[​](#函数式fp--function--hooks "函数式(FP + Function + Hooks)的直接链接") Midway 也支持函数式的编程范式,为应用提供更高的研发效率。 下面是基于函数式,开发路由接口的示例。 ``` // src/api/index.ts import { useContext } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default async function home() { const ctx = useContext(); return { message: 'Hello Midwayjs!', query: ctx.ip, }; } ``` ## 准备工作[​](#准备工作 "准备工作的直接链接") Midway 运行请预先安装 Node.js 环境和 npm,在国内可以使用 cnpm。 * 操作系统:支持 macOS,Linux,Windows * 运行环境:建议选择 [LTS 版本](http://nodejs.org/),最低要求 12.x。 如果需要帮助,请参考 [如何安装 Node.js 环境](/docs/2.0.0/how_to_install_nodejs.md)。 ## 正确的提问[​](#正确的提问 "正确的提问的直接链接") * ❌ 在 yuque 评论区提问 * ✅ 在 [github issue](https://github.com/midwayjs/midway/issues) 提问,可追踪,可沉淀,可 Star * 1、描述你的问题,提供尽可能详细的复现方法,框架版本,场景(Serverless 还是应用) * 2、尽可能提供报错截图,堆栈信息,最小复现的 repo ## 答疑分享群[​](#答疑分享群 "答疑分享群的直接链接") 群里会有热心的朋友,也会有新版本发布推送。 * 钉钉(左图):扫码加入答疑群(申请加入,自动通过) * 微信(右图):由于微信群限制,可以先加拉群小助手(备注 midway 加群),然后拉到微信群。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01LW04Ah1EFWHjVLu7s_!!6000000000322-0-tps-1658-1010.jpg) --- # Koa Koa 是一个非常轻量易用的 Web 框架。 本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 ## 创建项目[​](#创建项目 "创建项目的直接链接") 我们可以使用我们的脚手架来创建一个模版项目: ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=koa hello_koa # 如果是 npm v7 $ npm init midway -- --type=koa hello_koa ``` 运行: ``` cd hello_koa // 进入项目路径 npm run dev // 本地运行 ``` 针对 Koa,Midway 提供了 `@midwayjs/koa` 包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。 这些包列举如下。 ``` "dependencies": { "@midwayjs/koa": "^2.3.11", "@midwayjs/decorator": "^2.3.11" }, "devDependencies": { "@midwayjs/mock": "^2.3.11", }, ``` | @midwayjs/koa | Midway 针对 Koa 的适配层 | | ------------------- | ------------------------- | | @midwayjs/decorator | Midway 系列通用的装饰器包 | | @midwayjs/mock | 本地开发工具包 | `@midwayjs/koa` 包默认使用 `koa@2` 以及集成了 `@koa/router` 作为路由基础能力。 ## 目录结构[​](#目录结构 "目录结构的直接链接") ``` . ├── src │ ├── controller # controller 接口的地方 │ └── service # service 逻辑处理的地方 | └── configuration.ts # 入口及生命周期配置、组件管理 ├── test ├── package.json └── tsconfig.json ``` ## 控制器(Controller)[​](#控制器controller "控制器(Controller)的直接链接") 整个请求接口的写法和 Midway 适配其他框架的相同,只是定义有少许差异。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home(@Query() id) { // this.ctx.query.id === id } } ``` ### 请求参数装饰器[​](#请求参数装饰器 "请求参数装饰器的直接链接") 在 @midwayjs/koa 中,可以使用大部分的请求装饰器,具体的列表如下: | @Query | √ | | ------------ | ------------------------------ | | @Body | 需要自行安装 body 解析库后使用 | | @Param | √ | | @Headers | √ | | @Session | 需要自行安装 session 后使用 | | @RequestPath | √ | | @RequestIP | √ | | @Queries | 同 @Query | 由于 koa 框架相对纯粹,默认情况下,我们没有埋入 body 解析的库。 `@Body`  装饰器将在安装了解析 body 库之后才能使用。 比如下面就是如何引入 `koa-bodyparser`  的代码(示例项目已包含): ``` import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; import * as bodyParser from 'koa-bodyparser'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { // bodyparser options see https://github.com/koajs/bodyparser this.app.use(bodyParser()); } } ``` 同理, `@Session`  装饰也需要自行安装 `koa-session`  库。 ``` import { Configuration, App } from '@midwayjs/decorator'; import * as bodyParser from 'koa-bodyparser'; import * as session from 'koa-session'; @Configuration({ importConfigs: ['./config'], }) export class ContainerConfiguration { @App() app; async onReady() { this.app.keys = ['some secret hurr']; this.app.use( session( { key: 'koa.sess', maxAge: 86400000, httpOnly: true, }, this.app ) ); this.app.use(bodyParser()); } } ``` ## 编写 Web 中间件[​](#编写-web-中间件 "编写 Web 中间件的直接链接") 创建一个 `src/middleware/report.ts` 。我们在这个 Web 中间件中打印了控制器(Controller)执行的时间。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ └── home.ts │ ├── interface.ts │ ├── middleware ## 中间件目录 │ │ └── report.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 简单来说, `await next()` 则代表了下一个要执行的逻辑,这里一般代表控制器执行,在执行的前后,我们可以进行一些打印和赋值操作,这也是洋葱圈模型最大的优势。 ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayKoaContext, IMidwayKoaNext } from '@midwayjs/koa'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: IMidwayKoaContext, next: IMidwayKoaNext) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime); }; } } ``` 注意,这里我们导出了一个 `ReportMiddleware` 类,这个中间件类的 key 为 `reportMiddleware` 。 ## 路由中间件[​](#路由中间件 "路由中间件的直接链接") 我们可以把上面编写的中间件应用到单个 Controller 上,也可以将中间件应用到单个路由上。 ``` import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/', { middleware: ['reportMiddleware'] }) // controller 级别的中间件 export class HomeController { @Get('/', { middleware: ['reportMiddleware'] }) // 路由级别的中间件 async home() {} } ``` ## 全局中间件[​](#全局中间件 "全局中间件的直接链接") 直接使用 Midway 提供的 `app.generateMiddleware` 方法,在入口处加载全局中间件。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { this.app.use(await this.app.generateMiddleware('reportMiddleware')); } } ``` 除了加载 Class 形式的中间件外,也支持加载传统的 koa 中间件。 我们以加载一个三方中间件(koa-static)举例。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; import { join } from 'path'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { const root = join(__dirname, 'public'); this.app.use(require('koa-static')(root, {})); } } ``` 你可以通过注入 `app` 对象,来调用到所有 koa 上的方法。 ## 框架启动参数[​](#框架启动参数 "框架启动参数的直接链接") `@midwayjs/koa`  框架的启动参数如下: | port | number | 必填,启动的端口 | | -------- | ------- | ---------------------------- | | key | string | Buffer | | cert | string | Buffer | | ca | string | Buffer | | hostname | string | 监听的 hostname,默认 127.1 | | http2 | boolean | 可选,http2 支持,默认 false | ## 部署[​](#部署 "部署的直接链接") ### 部署到普通应用容器[​](#部署到普通应用容器 "部署到普通应用容器的直接链接") Midway 构建出来的项目是单进程的,不管是采用 `fork` 模式还是 `cluster` 模式,单进程的代码总是很容易的兼容到不同的体系中,因此非常容易被社区现有的 pm2/forever 等工具所加载, 我们这里以 pm2 来演示如何部署。 项目一般都需要一个入口文件,比如,我们在根目录创建一个 `bootstrap.js` 作为我们的部署文件。 ``` ➜ hello_koa tree . ├── src ├── dist # Midway 构建产物目录 ├── test ├── server.js # 部署启动文件 ├── package.json └── tsconfig.json ``` Midway 提供了一个简单方式以满足不同场景的启动方式,只需要安装我们提供的 `@midwayjs/bootstrap` 模块。 ``` $ npm install @midwayjs/bootstrap --save ``` 然后在入口文件中写入代码,注意,这里的代码使用的是 `JavaScript` 。 ``` // 获取框架 const WebFramework = require('@midwayjs/koa').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载框架并执行 Bootstrap.load(web).run(); ``` 我们提供的每个上层框架都将会导出一个 `Framework` 类,而 `Bootstrap` 的作用则是加载这些框架,传入启动参数,运行他们。 这个时候,你已经可以直接使用 `node bootstrap.js` 来启动代码了,也可以使用 pm2 来执行启动。 ``` $ npm install -g pm2 $ pm2 start bootstrap.js ``` ### 部署到 Serverless 环境[​](#部署到-serverless-环境 "部署到 Serverless 环境的直接链接") Serverless 环境指的是阿里云 FC,腾讯云等函数环境。Midway 可以将现有的 Web 项目部署为 Serverless 应用,这里以部署到阿里云函数计算作为示例。 1、添加 `f.yml` 文件到你的项目根目录。 ``` ➜ hello_koa tree . ├── src ├── dist ├── f.yml # Midway Serverless 部署配置文件 ├── package.json └── tsconfig.json ``` ``` service: my-midway-app ## 应用发布到云平台的名字,一般指应用名 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: koa ## 部署的应用类型 ``` 2、代码修改 将 `bootstrap.js`  重命名为 `app.js` ,移除内部的端口(Serverless 环境不需要),并返回一个 app。 修改后的代码如下: ``` // 获取框架 const WebFramework = require('@midwayjs/koa').Framework; // 初始化 web 框架并传入启动参数 const web = new WebFramework().configure({}); const { Bootstrap } = require('@midwayjs/bootstrap'); module.exports = async () => { // 加载框架并执行 await Bootstrap.load(web).run(); // 返回 app 对象 return web.getApplication(); }; ``` 3、添加发布时的构建钩子 在 `package.json` 加入下面的这段,用于在发布时自动执行 `npm run build` 。 ``` "midway-integration": { "lifecycle": { "before:package:cleanup": "npm run build" } }, "scripts": { "deploy": "midway-bin deploy" } ``` 3、执行 `npm run deploy` 即可,发布后,阿里云会输出一个临时可用的域名,打开浏览器访问即可。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600835297676-1753de7a-fb0d-46ca-98f0-944eba5b2f2b.png#height=193\&id=XpZAN\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=193\&originWidth=1219\&originalType=binary\&ratio=1\&size=35152\&status=done\&style=none\&width=1219) 如需更详细的发布文档,请查阅 [**Serverless 发布 FAQ**](https://www.yuque.com/midwayjs/faas/deploy_aliyun_faq)。 --- # 生命周期 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 ## 扩展生命周期[​](#扩展生命周期 "扩展生命周期的直接链接") Midway 的生命周期是通过 `src/configuration.ts` 文件,实现 ILifeCycle 接口,就可以在容器 ready 的时候处理这类需求。 信息 注意,这里的 ready 指的是依赖注入容器 ready,并不是应用 ready,所以你可以对应用做任意扩展,比如添加中间件,连接数据库等等。 接口定义如下。 ``` interface ILifeCycle { /** * 在应用 ready 的时候执行 * @param container IoC 容器 * @param app 应用 app */ onReady(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用配置加载后执行 */ onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用停止的时候执行 * @param container IoC 容器 * @param app 应用 app */ onStop?(container: IMidwayContainer, app: IMidwayApplication): Promise; } ``` 举个例子。 我们需要在初始化时提前连接一个数据库,由于在类中,所以也可以通过 `@Inject`   装饰器注入 db 这样一个数据库的连接工具类,这个实例包含 connect 和 close 两个函数: ``` import { Configuration } from '@midwayjs/decorator'; import { ILifeCycle, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class ContainerConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { // 建立数据库连接 await this.db.connect(); } async onStop(): Promise { // 关闭数据库连接 await this.db.close(); } } ``` 这样,我们就能够在应用启动时建立数据库连接,而不是在请求响应时再去创建。同时,在应用停止时,也可以优雅的关闭数据库连接。 除此之外,通过这个方式,可以对默认注入的对象做扩充。 ``` import * as sequelize from 'sequelize'; @Configuration() export class ContainerConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer): Promise { // 三方包对象 container.registerObject('sequelize', sequelize); } } ``` 在其他的类中可以直接注入使用。 ``` export class IndexHandler { @Inject() sequelize; async handler() { console.log(this.sequelize); } } ``` --- # 日志 ## 简介[​](#简介 "简介的直接链接") Midway 为不同场景提供了一套统一的日志接入方式。通过 `@midwayjs/logger`  包导出的方法,可以方便的接入不同场景的日志系统。 Midway 的日志系统基于社区的 [winston](https://github.com/winstonjs/winston),是现在社区非常受欢迎的日志库。 ## 普通使用[​](#普通使用 "普通使用的直接链接") 首先我们学会 Midway 的日常日志使用方法。 ``` import { Get } from '@midwayjs/decorator'; import { Inject, Controller, Provide } from '@midwayjs/decorator'; @Provide() @Controller() export class HelloController { @Inject() logger; // 获取上下文日志,等价于 ctx.logger @Logger('logger') appLogger; // 获取 appLogger,非请求链路下,比如 configuration 或者单例中 @Inject() ctx; @Get('/') async ctx() { // 请求链路的日志,包含请求的 url,请求协议等信息 this.logger.info('hello world'); // 普通日志 this.appLogger.info('hello world'); } } ``` 访问后,我们能在两个地方看到日志输出: * console 栏看到输出。 * 日志目录的 midway-app.log 文件中。 输出结果: ``` 2021-07-22 14:50:59,388 INFO 7739 [-/::ffff:127.0.0.1/-/0ms GET /api/get_user] hello world ``` 以上是用户在项目开发的基本使用。如果有更多高阶用法,请继续阅读接下来的章节。 ## 默认日志对象[​](#默认日志对象 "默认日志对象的直接链接") 默认情况下,Midway 已经将日志库埋入到整个框架中,在框架启动时已经能够自动输出信息到控制台,以及输出到文件。 Midway 日志的默认逻辑为: * 将日志输出到控制台和写入文件 * 按日期每天切割,以及按大小切割 * 将错误( `.error()` 输出的内容)统一输出到一个固定的错误文件 Midway 默认在框架提供了三种不同的日志,对应三种不同的行为。 | 日志 | 释义 | 描述 | 常见使用 | | ----------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | coreLogger | 框架,组件层面的日志 | 默认会输出控制台日志和文本日志 `midway-core.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 框架和组件的错误,一般会打印到其中。 | | appLogger | 业务层面的日志 | 默认会输出控制台日志和文本日志 `midway-app.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 业务使用的日志,一般业务日志会打印到其中。 | | 上下文日志(复用 appLogger 的配置) | 请求链路的日志 | 默认使用 `appLogger` 进行输出,除了会将错误日志发送到 `common-error.log` 之外,还增加了上下文信息。 | 修改日志输出的标记(Label),不同的框架有不同的请求标记,比如 HTTP 下就会输出路由信息。 | ## 日志路径和文件[​](#日志路径和文件 "日志路径和文件的直接链接") 默认情况下,Midway 会在本地开发和服务器部署时输出日志到**日志根目录**。 * 本地的日志根目录为 `${app.appDir}/logs/项目名` 目录下 * 服务器的日志根目录为用户目录 `${process.env.HOME}/logs/项目名` (Linux/Mac)以及 `${process.env.USERPROFILE}/logs/项目名` (Windows)下,例如 `/home/admin/logs/example-app`。 Midway 会在日志根目录创建一些默认的文件。 * `midway-core.log` 框架、组件打印信息的日志,对应 `coreLogger` 。 * `midway-app.log` 应用打印信息的日志,对应 `appLogger` * `common-error.log` 所有错误的日志(所有 Midway 创建出来的日志,都会将错误重复打印一份到该文件中) 信息 在 EggJS 下,为了兼容以前的日志,依旧处理将日志打印在 `midway-web.log` 下。 ## 使用日志对象[​](#使用日志对象 "使用日志对象的直接链接") 一般来说,框架开发者需要获取到 `coreLogger` ,记录框架,组件层面的日志。而业务开发者,需要获取到 `appLogger`  来记录业务日志。在业务和请求相关的流程中,需要拿到上下文日志对象,方便追踪请求。 ### 使用装饰器获取日志对象[​](#使用装饰器获取日志对象 "使用装饰器获取日志对象的直接链接") 在任意类中,我们可以通过装饰器来获取日志对象。下面是一个通过装饰器获取各种默认日志对象的方式。 **1、获取 `coreLogger`** ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Logger() coreLogger: ILogger; // 获取 coreLogger @Logger('coreLogger') anotherLogger: ILogger; // 这里和依赖注入的规则相同,依旧获取的是 coreLogger async getUser() { // this.coreLogger === this.anotherLogger this.coreLogger.warn('warn message'); } } ``` **2、获取 `appLogger`** 为了使用更简单,我们将 `appLogger`  的 key 变为了最为普通的 `logger` 。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Logger() logger: ILogger; // 获取 appLogger async getUser() { this.logger.info('hello user'); this.coreLogger.warn('warn message'); } } ``` **3、获取上下文日志对象(Context Logger)** 上下文日志是在每个请求实例中动态创建的日志对象,因此它和**请求作用域**绑定,即和**请求实例**绑定。 Midway 默认会将上下文日志对象挂载到上下文(ctx)上,即 `ctx.logger` 。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; // 获取上下文日志 async getUser() { this.logger.info('hello user'); } } ``` 信息 和全局的日志不同,上下文日志对象,默认会放在请求作用域的依赖注入容器中,它的 key 为 logger,所以可以使用 `Inject`  装饰器注入它。 ### 使用 API 接口获取日志对象[​](#使用-api-接口获取日志对象 "使用 API 接口获取日志对象的直接链接") 有时候,我们不在 Class 的场景下,我们可以从 `app`  上的方法来获取这些默认的日志对象。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @App() app: IMidwayApplication; @Inject() ctx; async getUser() { this.app.getLogger('logger').info('hello user'); // 获取 appLogger this.app.getLogger('coreLogger').warn('warn message'); // 获取 coreLogger // this.ctx.logger 获取请求上下文日志 } } ``` ## 输出方法和格式[​](#输出方法和格式 "输出方法和格式的直接链接") Midway 的日志对象继承与 winston 的日志对象,一般情况下,只提供 `error()` , `warn()` , `info()` , `debug`  四种方法。 示例如下。 ``` logger.debug('debug info'); logger.info('启动耗时 %d ms', Date.now() - start); logger.warn('warning!'); logger.error(new Error('my error')); ``` ### 默认的输出行为[​](#默认的输出行为 "默认的输出行为的直接链接") 在大部分的普通类型下,日志库都能工作的很好。 比如: ``` logger.info('hello world'); // 输出字符串 logger.info(123); // 输出数字 logger.info(['b', 'c']); // 输出数组 logger.info(new Set([2, 3, 4])); // 输出 Set logger.info( new Map([ ['key1', 'value1'], ['key2', 'value2'], ]) ); // 输出 Map ``` 信息 Midway 针对 winston 无法输出的 `Array` , `Set` , `Map` 类型,做了特殊定制,使其也能够正常的输出。 不过需要注意的是,日志对象在一般情况下,只能传入一个参数,它的第二个参数有其他作用。 ``` logger.info('plain error message', 321); // 会忽略 321 ``` ### 错误输出[​](#错误输出 "错误输出的直接链接") 针对错误对象,Midway 也对 winston 做了定制,使其能够方便的和普通文本结合到一起输出。 ``` // 输出错误对象 logger.error(new Error('error instance')); // 输出自定义的错误对象 const error = new Error('named error instance'); error.name = 'NamedError'; logger.error(error); // 文本在前,加上 error 实例 logger.info('text before error', new Error('error instance after text')); ``` 警告 注意,错误对象只能放在最后,且有且只有一个,其后面的所有参数都会被忽略。 ### 格式化内容[​](#格式化内容 "格式化内容的直接链接") 基于 `util.format`  的格式化方式。 ``` logger.info('%s %d', 'aaa', 222); ``` 常用的有 * `%s`  字符串占位 * `%d`  数字占位 * `%j` json 占位 更多的占位和详细信息,请参考 node.js 的 [util.format](https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_format_format_args) 方法。 ### 输出自定义对象或者复杂类型[​](#输出自定义对象或者复杂类型 "输出自定义对象或者复杂类型的直接链接") 基于性能考虑,Midway(winston)大部分时间只会输出基本类型,所以当输出的参数为高级对象时,**需要用户手动转换为需要打印的字符串**。 如下示例,将不会得到希望的结果。 ``` const obj = { a: 1 }; logger.info(obj); // 默认情况下,输出 [object Object] ``` 需要手动输出希望打印的内容。 ``` const obj = {a: 1}; logger.info(JSON.stringify(obj)); // 可以输出格式化文本 logger.info(a.1); // 直接输出属性值 logger.info('%j', a); // 直接占位符输出整个 json ``` ### 纯输出内容[​](#纯输出内容 "纯输出内容的直接链接") 特殊场景下,我们需要单纯的输出内容,不希望输出时间戳,label 等和格式相关的信息。这种需求我们可以使用 `write` 方法。 `write` 方法是个非常底层的方法,并且不管什么级别的日志,它都会写入到文件中。 虽然 `write` 方法在每个 logger 上都有,但是我们只在 `IMidwayLogger` 定义中提供它,我们希望你能明确的知道自己希望调用它。 ``` (logger as IMidwayLogger).write('hello world'); // 文件中只会有 hello world ``` ## 日志定义[​](#日志定义 "日志定义的直接链接") 默认的情况,用户应该使用最简单的 `ILogger`  定义。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; // 获取上下文日志 async getUser() { this.logger.info('hello user'); } } ``` `ILogger`  定义只提供最简单的 `debug` , `info` , `warn`  以及 `error`  方法。 在某些场景下,我们需要更为复杂的定义,比如修改日志属性或者动态调节,这个时候需要使用更为复杂的 `IMidwayLogger`  定义。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { IMidwayLogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: IMidwayLogger; // 获取上下文日志 async getUser() { this.logger.disableConsole(); // 禁止控制台输出 this.logger.info('hello user'); // 这句话在控制台看不到 this.logger.enableConsole(); // 开启控制台输出 this.logger.info('hello user'); // 这句话在控制台可以看到 } } ``` `IMidwayLogger` 的定义可以参考 interface 中的描述,或者查看 [代码](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ## 日志等级[​](#日志等级 "日志等级的直接链接") winston 的日志等级分为下面几类,日志等级依次降低(数字越大,等级越低): ``` const levels = { none: 0, error: 1, trace: 2, warn: 3, info: 4, verbose: 5, debug: 6, silly: 7, all: 8, } ``` 在 Midway 中,为了简化,一般情况下,我们只会使用 `error` , `warn` , `info` , `debug` 这四种等级。 日志等级表示当前可输出日志的最低等级。比如当你的日志 level 设置为 `warn`  时,仅 `warn`  以及更高的 `error`  等级的日志能被输出。 ### 框架的默认等级[​](#框架的默认等级 "框架的默认等级的直接链接") 在 Midway 中,有着自己的默认日志等级。 * 在开发环境下(local,test,unittest),日志等级统一为 `info` 。 * 在服务器环境(除开发环境外),为减少日志数量,日志等级统一为 `warn` 。 ### 动态调整等级[​](#动态调整等级 "动态调整等级的直接链接") 在开发调试时,我们往往有动态调整等级的诉求。在 Midway 的日志下,我们可以使用方法动态的调整日志等级。 ``` logger.updateLevel('debug'); // 动态调整等级为 debug ``` 也可以单独调整文本和控制台输出的等级。 ``` // 动态调整文件的日志等级 logger.updateFileLevel('warn'); // 动态调整控制台输出日志等级 logger.updateConsoleLevel('error'); ``` ## 日志输出管道(Transport)[​](#日志输出管道transport "日志输出管道(Transport)的直接链接") Midway 的日志对象基于 Winston 日志,默认包含三个日志管道。 * `ConsoleTransport`  用于向控制台输出日志 * `FileTransport`  用于向文件写入日志 * `ErrorTransport`  用于将 Error 级别输出到特定的错误日志 我们可以通过方法动态更新这三个管道,控制输出。 ``` logger.enableFile(); logger.disableFile(); logger.enableConsole(); logger.disableConsole(); logger.enableError(); logger.disableError(); ``` 同时,还提供了判断的 API。 ``` logger.isEnableConsole(); logger.isEnableFile(); logger.isEnableError(); ``` ## 日志切割(轮转)[​](#日志切割轮转 "日志切割(轮转)的直接链接") 默认行为下,同一个日志对象**会生成两个文件**。 以 `midway-core.log` 为例,应用启动时会生成一个带当日时间戳 `midway-core.YYYY-MM-DD` 格式的文件,以及一个不带时间戳的 `midway-core.log` 的软链文件。 为方便配置日志采集和查看,该软链文件永远指向最新的日志文件。 当凌晨 `00:00` 时,会生成一个以当天日志结尾 `midway-core.log.YYYY-MM-DD` 的形式的新文件。 同时,当单个日志文件超过 200M 时,也会自动切割,产生新的日志文件。 ## 日志标签(label)[​](#日志标签label "日志标签(label)的直接链接") 日志标签(label)指的是日志输出时,带有 `[xx]`  的部分。 ### 默认的日志标签[​](#默认的日志标签 "默认的日志标签的直接链接") 默认情况下,Midway 对 `coreLogger`  的标签做了特殊处理,使用 `coreLogger`  输出的日志,会自带当前的框架信息。 比如: ``` 2021-01-22 12:34:24,354 INFO 34458 [midway:gRPC] Find 1 class has gRPC provider decorator 2021-01-22 12:34:24,372 INFO 34458 [midway:gRPC] Proto helloworld.Greeter found and add to gRPC server 2021-01-22 12:34:24,381 INFO 34458 [midway:gRPC] Server port = 6565 start success 2021-01-22 12:34:24,416 INFO 34458 [midway:gRPC] Server shutdown success ``` Midway 没有对 `appLogger`  做特殊处理,即输出的日志不带标签。 Midway 对 `contextLogger`  做了特殊处理,默认的标签会关联上下文信息。 比如在 Web 下,会输出 ip,method,path 等: ``` 2021-01-20 15:13:25,408 INFO 66376 [-/127.0.0.1/-/5ms GET /] xxxx ``` ### 修改日志标签[​](#修改日志标签 "修改日志标签的直接链接") 有两个地方可以修改日志标签。 **1、初始化时** ``` const logger = this.app.createLogger('custom', { // 创建了一个日志等级为 level,只输出到终端的日志 level: 'info', defaultLabel: 'main label', }); logger.info('hello world'); // output => 2021-01-20 15:13:25,408 INFO 66376 [main label] hello world ``` **2、动态调整** ``` const logger = this.app.createLogger('custom', { // 创建了一个日志等级为 level,只输出到终端的日志 level: 'info', }); // 可以传递一个字符串 logger.info('hello world', { label: 'UserService' }); // output => 2021-01-20 15:13:25,408 INFO 66376 [UserService] hello world // 也可以传递数组,会使用:进行组合 logger.info('hello world', { label: ['a', 'b'] }); // output => 2021-01-20 15:13:25,408 INFO 66376 [a:b] hello world ``` 信息 注意,动态调整标签,不会影响默认的标签,即下一次如果不带 `{label: xxx}`,依旧会输出默认标签。 ## 自定义日志[​](#自定义日志 "自定义日志的直接链接") 如果用户不满足于默认的日志对象,也可以自行创建。 创建日志有两种方法: * 1、从 app/framework 创建 * 2、从日志库 `@midwayjs/logger`  创建 不管哪一种,都是代理自日志容器的 `createLogger`  方法。 ### 日志容器[​](#日志容器 "日志容器的直接链接") 日志容器是来存放日志对象以及管理日志对象,你可以理解为一个 Map。key 为日志对象的名称,value 为日志对象本身。 默认情况下,引入 `@midwayjs/logger` 库时,会在全局创建一个日志容器。 ``` import { loggers } from '@midwayjs/logger'; console.log(loggers); // 当前全局默认的日志容器 ``` 所有通过框架以及自定义创建的日志对象,都会存储其中。 每次使用 `@Logger` 装饰器以及 `app.getLogger()` 获取日志的行为,本质上都是从默认的日志容器或获取同名的日志对象。 ``` import { Provide, Logger } from '@midwayjs/decorator'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @App() app: IMidwayApplication; @Logger() logger; // 即 loggers.getLogger('logger') async getUser() { // 即 loggers.getLogger('coreLogger') this.app.getLogger('coreLogger').warn('warn message'); } } ``` 除了 `getLogger`  之外,还有其他一些方法,这些最基础的方法,可以以最原始的方式来获取、修改日志对象。 ``` import { loggers, ILogger } from '@midwayjs/logger'; const customLogger = loggers.createLogger('customLogger', { // ... }); customLogger.info('hello world'); loggers.getLogger('customLogger'); // 从容器获取一个日志 loggers.addLogger('anotherLogger', customLogger); // 添加一个新的日志 loggers.removeLogger('customLogger'); // 移除一个日志 loggers.close(); // 关闭并移除所有日志 ``` **这种方法是一般用于和框架无关的场景**,需要传递相对完整的参数,比如日志文件的路径等。 同时, `@midway/logger`  也提供两个简化的方法,用于快速创建日志。 ``` import { createLogger, createConsoleLogger } from '@midwayjs/logger'; // 一个只有控制台输出的日志,并添加到默认的日志容器中 const consoleLogger = createConsoleLogger('customConsoleLogger'); // 一个只写文本的日志,并添加到默认的日志容器中(不会将错误转到其他日志,也不会输出控制台) const onlyFileLogger = createFileLogger('customOnlyFileConsoleLogger', { dir: logsDir, fileLogName: 'test-logger.log', }); // 文本日志,并添加到默认的日志容器中 const fileLogger = createLogger('customFileLogger', { level: 'warn', dir: __dirname, }); ``` 注意,如果创建同名的日志,日志容器会自动判断重名,跳过创建,并返回原有日志对象。 ``` const customLogger1 = loggers.createLogger('customLogger', { // ... }); const customLogger2 = loggers.createLogger('customLogger', { // ... }); // customLogger1 === customLogger2 ``` 信息 这个特性很有用,使得在不同场景下,能够让业务使用到同一个日志对象。 ### 从当前框架、App 创建日志[​](#从当前框架app-创建日志 "从当前框架、App 创建日志的直接链接") 在大多数请下,用户会使用这种方式创建日志。 Midway 在 `app`  上增加了 `createLogger`  方法,以方便用户快速基于框架默认的日志配置创建自己的日志实例。 比如在入口的 `configuration.ts`  中,我们可以创建出自己的日志。 ``` export class AutoConfiguration { @App() app: IMidwayApplication; async onReady() { this.app.createLogger('custom1'); // 创建一个全功能的自定义日志 this.app.createLogger('custom2', { // 创建了一个日志等级为 level,只输出到终端的日志 level: 'error', disableFile: true, disableError: true, }); this.app.createLogger('custom3', { fileLevel: 'warn', // 只修改文件日志等级 disableConsole: true, // 禁止终端输出 }); } } ``` 这样创建出日志会**自动绑定到框架**中,并且使用框架默认的路径创建日志,后期可以直接根据日志名获取使用。 ``` import { ILogger } from '@midwayjs/logger'; export class UserService { @Logger('custom1') custom1Logger: ILogger; @Logger('custom2') custom2Logger: ILogger; @Logger('custom3') custom3Logger: ILogger; } ``` 信息 所有创建的日志,在全局日志容器 `loggers` 中都能获取到。 创建日志,等价于在全局日志容器中调用 `loggers.createLogger()`  方法。 ### 创建日志选项[​](#创建日志选项 "创建日志选项的直接链接") `createLogger`  方法的所有参数如下,用户可以自行调整。 更多的日志选项可以参考 interface 中 [LoggerOptions 描述](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ### 修改显示格式(Display)[​](#修改显示格式display "修改显示格式(Display)的直接链接") 显示格式指的是日志输出时单行文本的字符串结构。Midway 对 Winston 的日志做了定制,提供了一些默认对象。 显示格式是一个返回字符串结构的方法,参数为 Winston 的 [info 对象](https://github.com/winstonjs/logform#info-objects)。 默认情况下,我们的显示格式为: ``` (info) => { return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.labelText}${info.message}`; }; ``` 输出如下: ``` 2020-12-30 07:50:10,453 ERROR 3847 [customLabel] Error: another test error at Object. (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18) ``` info 对象的默认属性如下: | **属性名** | **描述** | **示例** | | ----------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | timestamp | 时间戳,默认为 `'YYYY-MM-DD HH:mm:ss,SSS` 格式。 | 2020-12-30 07:50:10,453 | | level | 小写的日志等级 | info | | LEVEL | 大写的日志等级 | INFO | | pid | 当前进程 pid | 3847 | | labelText | 标签的聚合文本 | \[abcde] | | message | 普通消息 + 错误消息 + 错误堆栈的组合 | 1、普通文本,如 `123456` , `hello world`
2、错误文本(错误名+堆栈)Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18)
3、普通文本+错误文本 hello world Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18) | | stack | 错误堆栈 | | | originError | 原始错误对象 | 错误实例本身 | | originArgs | 原始的用户入参 | \[ 'a', 'b', 'c' ] | 示例,创建一个自定义格式的 Logger。 ``` export class AutoConfiguration { @App() app: IMidwayApplication; async onReady() { this.app.createLogger('custom1', { printFormat: (info) => { return `${info.timestamp} ${info.level} ${info.message}`; }, }); this.app.getLogger('custom1').info('hello world'); } } ``` 这样该日志的输出效果则为: ``` 2020-12-30 07:50:10,453 info hello world ``` ### 动态修改默认显示内容(TransformableInfoInfo)[​](#动态修改默认显示内容transformableinfoinfo "动态修改默认显示内容(TransformableInfoInfo)的直接链接") 在某些场景下,我们无法在初始化修改日志对象 ,如果希望可以修改输出内容,也可以使用动态修改 info 对象的值来达到类似的效果。 ``` logger.updateTransformableInfo((info) => { info.timestamp = '123'; return info; }); ``` 在原有输出的时间字段的位置则会变成 ``` 123,408 INFO 66376 [-/127.0.0.1/-/5ms GET /] xxxx ``` 信息 注意,该方法只能修改属性值,但是不能修改输出结构。 ## 配置框架日志[​](#配置框架日志 "配置框架日志的直接链接") Midway 在框架中提供了默认日志,如果需要修改默认日志的行为,可以在初始化框架时修改,传入不同的日志对象。 ### 覆盖框架日志[​](#覆盖框架日志 "覆盖框架日志的直接链接") 框架的初始化入口一般为下面的代码,在其中创建日志实例,替换即可。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); import { Framework } from '@midwayjs/koa'; import { createLogger, createConsoleLogger } from '@midwayjs/logger'; // 一个只有控制台输出的日志 const consoleLogger = createConsoleLogger('customConsoleLogger'); // 文本日志 const fileLogger = createLogger('customFileLogger', { dir: __dirname, }); const koaFramework = new Framework().configure({ port: 7001, logger: consoleLogger, // or fileLogger }); Bootstrap.load(koaFramework).run(); ``` ### 覆盖请求链路日志的 Label[​](#覆盖请求链路日志的-label "覆盖请求链路日志的 Label的直接链接") 每个框架(Framework)可能会有默认的上下文日志输出,ContextLogger 是基于 appLogger 来打日志的,**会复用 appLogger 的所有信息**,唯一不同的是,ContextLogger 会输出特殊的 label。 比如 HTTP 下的默认输出为: ``` 2021-01-20 15:13:25,408 INFO 66376 [-/127.0.0.1/-/5ms GET /] xxxx ``` label 为 `-/127.0.0.1/-/5ms GET /`  这一部分。 我们可以通过重写上下文日志类来修改上下文输出信息(ContextLogger)的 label。 首先,你需要定义一个文件,继承默认的 `MidwayContextLogger`  类,实现 `formatContextLabel`  来返回 label 内容。比如 HTTP 下: ``` // src/custom/logger.ts import { MidwayContextLogger } from '@midwayjs/logger'; import { Context } from 'egg'; export class MidwayCustomContextLogger extends MidwayContextLogger { formatContextLabel() { const ctx = this.ctx; return `${Date.now() - ctx.startTime}ms ${ctx.method}`; } } ``` Midway 为每个框架的 app 增加了一个 `setContextLoggerClass` 方法,用于覆盖默认的 `ctx.logger` 输出的 label。 你可以在启动时进行覆盖。 ``` // configuration.ts import { Configuration } from '@midwayjs/decorator'; import { ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import { MidwayCustomContextLogger } from './custom/logger'; import { Application } from 'egg'; @Configuration() export class ContainerConfiguration implements ILifeCycle { @App() app: Application; async onReady(container: IMidwayContainer): Promise { this.app.setContextLoggerClass(MidwayCustomContextLogger); } } ``` 则你在使用 `ctx.logger`  输出时,会默认变成你 format 的样子。 ``` ctx.logger.info('hello world'); // 2021-01-28 11:10:19,334 INFO 9223 [2ms POST] hello world ``` ## @midwayjs/web(EggJS)下特殊情况[​](#midwayjswebeggjs下特殊情况 "@midwayjs/web(EggJS)下特殊情况的直接链接") 信息 在 2021-01-28 之前的创建的项目,默认使用 egg-logger,之后创建的项目,将使用 @mdwayjs/logger。 ### 兼容配置[​](#兼容配置 "兼容配置的直接链接") 由于 Egg 下原日志配置是非 API 形式,统一放在 config 文件中,在这一场景下,我们依旧支持大部分的参数,用于快速将应用迁移到新的日志体系。 以下配置只在 Egg 下生效。 **config.logger** | dir | 日志根目录 | | ------------------------ | ------------------------ | | level | 文本日志等级 | | consoleLevel | 控制台日志等级 | | errorLogName | 错误日志文件名 | | coreLogName | core 日志文件名 | | agentLogName | agent 日志名 | | appLogName | 应用日志名 | | disableConsoleAfterReady | ready 之后禁止控制台输出 | **config.customLogger** | dir | 日志根目录 | | ------------ | -------------- | | file | 日志文件名 | | level | 文本日志等级 | | consoleLevel | 控制台日志等级 | ### 替换日志库[​](#替换日志库 "替换日志库的直接链接") 默认情况下,脚手架生成的日志库为 `@midwayjs/logger` ,并且默认关闭 egg 的日志切割能力(因为 midway 的日志库自带了),如果希望继续使用 `egg-logger` ,可以通过配置改回。 ``` // src/config.default.ts export const midwayFeature = { // true 代表 使用 midway logger // false 或者为空代表使用 egg-logger replaceEggLogger: false, }; ``` 同时,由于 egg-logger 日志需要额外开启切割能力,需要开启切割插件。 ``` // src/config/plugin.ts import { EggPlugin } from 'egg'; export default { logrotator: true, // 这行改成 true,或者删掉 static: false, } as EggPlugin; ``` ### 调整默认 level[​](#调整默认-level "调整默认 level的直接链接") ``` // config.local.ts export const logger = { level: 'INFO', consoleLevel: 'WARN', }; ``` **启动输出** 开发时,框架的默认输出都使用的是 `coreLogger` ,egg 默认的 `coreLogger`  的 `consoleLevel`  为 `WARN` ,如有查看的需求,可以覆盖默认的 egg 配置。 ``` // config.local.ts export const logger = { coreLogger: { consoleLevel: 'INFO', }, }; ``` --- # 使用组件 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 ## 使用组件[​](#使用组件 "使用组件的直接链接") 组件一般以 npm 包形式进行复用。每个组件都是一个可以被直接 `require`  的代码包。我们以 `@midwayjs/orm`  组件为例。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "@midwayjs/orm": "^1.0.0" } } ``` 我们需要在代码中启用这个组件,Midway 的组件加载能力设计在 `src/configuration.ts`  文件中。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as orm from '@midwayjs/orm'; @Configuration({ imports: [orm], }) export class ContainerLifeCycle {} ``` ## 不同环境启用组件[​](#不同环境启用组件 "不同环境启用组件的直接链接") 有时候,我们需要在特殊环境下才使用组件,比如本地开发时。 `imports`  属性可以传入对象数组,我们可以在对象中针对组件启用的环境进行配置。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as orm from '@midwayjs/orm'; @Configuration({ imports: [ { component: orm, enabledEnvironment: ['local'], }, ], }) export class ContainerLifeCycle {} ``` * `component`  用于指定组件对象,组件对象必须包含一个 `Configuration`  导出的属性 * `enabledEnvironment`  组件启用的环境数组 ## 开发组件[​](#开发组件 "开发组件的直接链接") 参见文档:[组件开发](/docs/2.0.0/component_development.md)。 --- # 关于 Midway 启动慢的问题 Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 一般 Mac 都是 SSD,所以基本没有问题,而 Windows 会有出现,构建后执行无此问题。 如下图所示。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523014939-40121f9c-bc19-4f9e-a7e6-e744d409a9ea.png#height=486\&id=JKv1L\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=972\&originWidth=1488\&originalType=binary\&size=523362\&status=done\&style=none\&width=744) ## 如何判断[​](#如何判断 "如何判断的直接链接") 1、先清理下 ts-node 缓存。 在临时目录中有一个 `ts-node-*`  的目录,删除即可(不知道临时目录的可以在命令行执行 `require('os').tmpdir()`  输出查看)。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523402032-7e9c162a-762e-4cba-82b4-8ae63fe37280.png#height=121\&id=EOZnh\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=242\&originWidth=960\&originalType=binary\&size=45718\&status=done\&style=none\&width=480) 删了下面类似的这个目录。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523340452-7924affe-96b5-4544-85b7-e41ace4206e8.png#height=255\&id=fFggf\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=510\&originWidth=1200\&originalType=binary\&size=86980\&status=done\&style=none\&width=600) 2、用 ts-node 启动 Midway 执行下面的启动命令。 ``` // midway v1 cross-env DEBUG=midway* NODE_ENV=local midway-bin dev --ts // midway v2 cross-env NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 会出现每个文件的 require 时长,如果时间比较久一般就是了。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523470970-1812326a-39d9-4b39-af57-7723f80f6e17.png#height=471\&id=OwZNU\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=2176\&originalType=binary\&size=828844\&status=done\&style=none\&width=1088) ## 解决问题[​](#解决问题 "解决问题的直接链接") 由于 `TS_NODE_TYPE_CHECK`  内部会启动一个 Server,在文件特别的多的情况下,每次 require 都会做类型检查,如果造成严重启动影响,建议关闭。**代价是启动运行时不会做类型校验,由于一般在编辑器里已经有提示,运行时不再做检查也可以。** 在执行命令前增加下面两个环境变量。 ``` TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true ``` 比如: ``` cross-env TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 下面是使用相同的项目的对比效果。 | | 第一次执行(无缓存) | 第二次执行(有缓存) | | ------------ | -------------------- | -------------------- | | 不加优化参数 | 约 258s | 约 5.6s | | 加优化参数 | 约 15s | 约 4.7s | | | | | ## 其他[​](#其他 "其他的直接链接") 如果任有问题,请提交你的仓库 + node\_modules 给我们。 --- # 多框架研发 所谓的多框架启动,指的是多个能提供服务的上层框架,在一个进程中同时提供服务。 这里的多个上层框架,指的是 midway 提供的 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` , `@midwayjs/socektio` , `@midwayjs/grpc` , `@midwayjs/rabbitmq`  等。 这些框架都能独立对外提供服务,暴露某个协议。比如 @midwayjs/web (包装 Egg.js,提供 HTTP   服务),@midwayjs/grpc(包装 grpc.js,提供 gRPC 服务)。 ## 框架(Framework)概念[​](#框架framework概念 "框架(Framework)概念的直接链接") Midway 现有的框架(Framework)每个是独立的,每一个框架都可以单独在进程中运行,理论上来说,每个框架都是一个独立的依赖注入容器,加上特定框架包含的三方库的组合。 这些独立的框架,都遵循 `IMidwayFramewok` 的接口定义,由 `@midwayjs/bootstrap` 库加载起来。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612086965489-9d1659ff-7440-40ac-a57a-f9195c57a73e.png#height=642\&id=uuRd5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1284\&originWidth=1888\&originalType=binary\&ratio=1\&size=159418\&status=done\&style=none\&width=944) 所以在提供的单进程部署方案中,我们可以通过一个 `bootstrap.js` 入口来启动应用。 ``` // bootstrap.js const WebFramework = require('@midwayjs/koa').Framework; const web = new WebFramework().configure({ port: 7001, }); const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.load(web).run(); ``` ## 多个框架启动文件(主副框架)[​](#多个框架启动文件主副框架 "多个框架启动文件(主副框架)的直接链接") 如果我们需要启动多个上层框架,可以利用 `load`  方法加载多次  。 ``` // bootstrap.js const WebFramework = require('@midwayjs/koa').Framework; const GRPCFramework = require('@midwayjs/grpc').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); const web = new WebFramework().configure({ port: 7001, }); const grpcService = new GRPCFramemwork().configure({ services: [ { protoPath: join(__dirname, 'proto/helloworld.proto'), package: 'helloworld', }, ], }); Bootstrap.load(web).load(grpcService).run(); ``` 信息 注意,所有的上层框架都会遵循规范,导出一个 Framework 属性。 这里有一个主、副框架的概念。 **第一个被 load 的框架为主框架,后面被 load 的都为副框架。** 比如,上面示例的 `@midwayjs/koa`  为主框架, `@midwayjs/grpc`  为副框架。 主框架只能一个,而副框架可以有多个。 信息 主框架在使用时略微有一些优势。 ## 启动多框架[​](#启动多框架 "启动多框架的直接链接") 多框架启动需要依赖启动文件。 在本地开发时,我们之前使用 `midway-bin dev --ts`  命令,需要增加一个 `entryFile`  的入口参数。 ``` $ cross-env NODE_ENV=local midway-bin dev --ts --entryFile=bootstrap.js ``` 信息 `bootstrap.js`  会自动判断 ts 环境,在本地开发时会加载 src 下的 ts 文件。 在服务器部署时,由于脚手架自带了 `bootstrap.js`  文件,直接修改即可,启动文件依旧为 start 命令(注意,启动前需要执行 npm run build 先将 ts 构建为 js)。 ``` $ cross-env NODE_ENV=production node bootstrap.js ``` **多框架场景不支持使用 egg-scripts 部署。** ## 多框架生命周期[​](#多框架生命周期 "多框架生命周期的直接链接") 业务代码中生命周期的 `onReady`  方法在一个进程只执行一次。 信息 在 egg 场景下,只会在 worker 进程生效。 ``` import { Configuration } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import { Application as GRPCApplication } from '@midwayjs/grpc'; @Configuration() export class AutoConfiguration { async onReady() { // 这个 onReady 方法只会执行一次 } } ``` ## 全局的依赖注入容器[​](#全局的依赖注入容器 "全局的依赖注入容器的直接链接") 所有的框架将共享同一个依赖注入容器。 如下图,启动器(@midwayjs/bootstrap)模块将提前初始化一个依赖注入容器 A,在后续所有的框架中,都将复用这个依赖注入容器 A。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616483855279-c4efe465-6783-4aa7-b156-1fee8fedd777.png#height=878\&id=FXtTw\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=878\&originWidth=1148\&originalType=binary\&ratio=1\&size=86904\&status=done\&style=none\&width=1148) 这意味这,在任意框架注入到容器中的单例,在其他框架也可以取到。 ## 多框架获取应用(app)对象[​](#多框架获取应用app对象 "�多框架获取应用(app)对象的直接链接") 如果需要不同框架的 app ,比如需要 web app 加载中间件,以及 grpc app 做初始化,我们可以通过 `@App` 的参数来注入不同框架的 app 实例。 如果不传递 `@App`  装饰器的参数,默认注入的 app 为**主框架 app**。 如果需要副框架的 app,请传递框架类型参数。框架的类型,是一个 `MidwayFrameworkType`  类型的枚举值。 ``` import { Configuration, MidwayFrameworkType } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import { Application as GRPCApplication } from '@midwayjs/grpc'; @Configuration() export class AutoConfiguration { @App() app: Application; // 注入不同的 app @App(MidwayFrameworkType.MS_GRPC) grpcApp: GRPCApplication; async onReady() {} } ``` 对于其他服务类来说,一般不会需要获取和框架相关联的 app 属性,常用的 API 比如 `getLogger` , `getApplicationContext` , `getBaseDir`  等方法,在所有的 app 返回是一致的,一般直接使用主框架的 app 即可(事实上你不需要知道是哪个框架)。 ``` import { Provide, App } from '@midwayjs/decorator'; import { IMidwayApplication } from '@midwayjs/core'; @Provide() export class UserService { @App() app: IMidwayApplication; // 推荐使用这个定义,所有的框架都会实现这个定义 } ``` ## 多框架上下文处理[​](#多框架上下文处理 "多框架上下文处理的直接链接") 对于接入层(Controller,Socket 等暴露服务的),都是固定某一种框架和协议的,所以注入的 Context 是固定的。 ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller() export class HomeController { @Inject() ctx: Context; // 这里注入的一定是匹配当前框架的上下文 @Get() async getMethod() {} } ``` 对于服务层来说,由于代码是一份,上下文对象有可能随着请求的不同,而随着框架变动。 我们不建议在 Service 层去获取跟 Controller(协议层)相关的代码,当前的上下文对象透传只是为了传递一些请求链路的数据(比如 open-tracing)。 比如在 web 场景下: ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; @Provide() export class UserService { @Inject() ctx: any; async getUser() { // ctx.query.id // 不推荐在 service 调用协议相关的代码 } } ``` 推荐的用法是使用和协议层无关的定义: ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; import { IMidwayContext } from '@midwayjs/core'; @Provide() export class UserService { @Inject() ctx: IMidwayContext; // 这个定义仅有一些特定的属性 async getUser() { // ctx.logger } } ``` 在实在需要特定框架的上下文的场景下,依旧可以使用原框架的定义(不太推荐)。 ``` import { Provide, Inject, Get } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; import { Context as GRPCContext } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() ctx: Context & GRPCContext; async getUser() { // ctx.xxxxx } } ``` ## 入口文件加载环境配置[​](#入口文件加载环境配置 "入口文件加载环境配置的直接链接") 如果框架初始化的配置较长或者有时候用户希望放到 `src/config.default.ts`  下,可以使用我们提供的回调写法,回调的参数为当前环境的配置对象。 比如 `config.default.ts`  中。 ``` // config.default export const cluster = { port: 7001, }; export const grpcServer = { services: [ { protoPath: join(__dirname, 'proto/helloworld.proto'), package: 'helloworld', }, ], }; ``` 那么在入口的地方,也可以这么写: ``` const WebFramework = require('@midwayjs/koa').Framework; const GRPCFramework = require('@midwayjs/grpc').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.load((config) => { return new WebFramework().configure(config.cluster); }) .load((config) => { return new GRPCFramemwork().configure(config.grpcServer); }) .run(); ``` 这样的好处是,入口的配置可以随着环境变化。 注意,这个功能是由 Midway 提供的,必须要在 `configuration.ts`  中开启 `importConfigs`  功能。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), // 该功能依靠这段代码查找配置 ], }) export class ContainerLifeCycle {} ``` 信息 只会读取到用户代码和 midway 组件的配置,egg 插件的配置不会被读取到。 ## 框架前异步逻辑(异步配置)[​](#框架前异步逻辑异步配置 "框架前异步逻辑(异步配置)的直接链接") 我们可以在所有的框架启动之前,做一些异步的行为,比如比较常见的在启动前使用异步加载配置。 `Bootstrap`  提供了 `before`  方法用于在所有的框架前执行异步操作。 ``` Bootstrap.load(webFramework) .load(grpcFramework) .before(async (container) => { // ... }) .run(); ``` 以一个异步配置加载为例,我们的需求是在应用启动前,从远端拉取配置,并合并到业务的配置中。 首先定义一个异步获取配置的类,比如 `src/remoteConfigService.ts` 。 ``` import { App, Provide, Init } from '@midwayjs/decorator'; import { IMidwayApplication } from '@midwayjs/core'; @Provide() export class RemoteConfigService { @App() app: IMidwayApplication; @Init() async syncConfig() { // 这里获取一个远端的配置,HTTP,或者订阅其他的配置协议 const remoteConfig = await this.getRemote(); // 将配置合并到全局的配置服务中 this.app.addConfigObject(remoteConfig); } } ``` 然后在所有框架启动时激活它。 ``` Bootstrap.load(webFramework) .load(grpcFramework) .before(async (container) => { await container.getAsync(RemoteConfigService); }) .run(); ``` 这里的 `container` 是我们的全局依赖注入容器,等价于 `app.getApplicationContext()` ,所以**获取的服务是单例**。 由于我们使用了 `@Init`  装饰器,所以在创建实例的时候就会被触发,并且保留在内存中。代码的流程和在应用中相同。 这里使用了 `app.addConfigObject`  方法和应用中的配置合并,后续业务中使用 `@Config`  获取配置的时候,就能拿到最终的配置了。 ## 多框架测试[​](#多框架测试 "多框架测试的直接链接") 传统单框架,我们使用 `createApp`  方法进行测试,获取到 app 对象后做操作,但是在多框架下,稍有不同,会创建出多个框架的 app 实例。 `@midwayjs/mock`  提供了 `createBootstrap`  方法做启动文件类型的测试。我们可以将入口文件 `bootstrap.js`  作为启动参数传入,这样 `createBootstrap`  方法会通过入口文件来启动代码。 ``` import { createBootstrap } from '@midwayjs/mock'; import { MidwayFrameworkType } from '@midwayjs/decorator'; describe('/test/new.test.ts', () => { it('should GET /', async () => { // create app const bootstrap = await createBootstrap(join(process.cwd(), 'bootstrap.js')); const app = bootstrap.getApp(MidwayFrameworkType.WEB_KOA); // expect and test // close bootstrap await bootstrap.close(); }); }); ``` 具体请参考 [使用 bootstrap 文件测试](/docs/2.0.0/testing.md#MgzE6)。 --- # 常见 npm 问题 ## 1、不希望生成 package-lock.json[​](#1不希望生成-package-lockjson "1、不希望生成 package-lock.json的直接链接") 在某些时候,锁版本不是特别好用,反而会出现不少奇怪的问题,我们会禁用 npm 的生成 `package-lock.json`  文件的功能。 可以输入下面的命令。 ``` $ npm config set package-lock false ``` ## 2、Maximum call stack size exceeded 报错[​](#2maximum-call-stack-size-exceeded-报错 "2、Maximum call stack size exceeded 报错的直接链接") 一般在 npm install 之后,再 npm install 某个包导致的。 解法: * 1、删除 node\_modules * 2、删除 package-lock.json * 3、重新 npm install 如果还有问题,可以尝试使用 node v14/npm6 重试。 ## 3、Python/Canvas 报错[​](#3pythoncanvas-报错 "3、Python/Canvas 报错的直接链接") 出现在使用 node v15/npm7 安装 jest 模块。 比如: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1621492368192-54f40921-a605-4f4d-bf7b-4e6465e86ae5.png#clientId=u4111fa3b-b948-4\&from=paste\&height=295\&id=u1299a886\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=295\&originWidth=1623\&originalType=binary\&size=43816\&status=done\&style=none\&taskId=udf1343b1-25dc-4d94-a976-1c182b76e3f\&width=1623) 解决方案:npm i 时添加 `--legacy-peer-deps`   参数。 原因:测试框架 Jest 依赖 jsdom,npm7 会自动安装其 peerDependencies 中依赖的 canvas 包, 而 canvas 的安装编译需要有 python3 环境。 --- # 代码流程控制 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 ## Pipeline[​](#pipeline "Pipeline的直接链接") 在 Node.js 的 Stream 实现中,可以使用 `a.pipe(b).pipe(c).pipe(d)` 这样,把多个 Stream 串连起来。但是这样只能顺序执行的 pipe 实现不一定能够满足不同的业务场景。 在 Midway 中我们使用 `@Pipeline`  装饰器,可以创建一个继承与 `IPipelineHandler`  接口的实例,可以将多个 `IValveHandler`  实例串联起来执行。 `IValveHandler`  就是具体的任务阶段执行单位。整个 IPipelineHandler 执行方式可以是 parallel、series、concat、waterfall (很熟悉是吧?我们参考了 [async](https://github.com/caolan/async) 库提供的方法能力命名)。 Pipeline 执行时期的上下文 IPipelineContext 可以用来存储 Pipeline 入参、上一次 IValveHandler 实例的执行结果、上一次的中间产物等等,提供了非常大的灵活性。 ## 类型定义[​](#类型定义 "类型定义的直接链接") ### IPipelineHandler[​](#ipipelinehandler "IPipelineHandler的直接链接") ``` interface IPipelineHandler { /** * 并行执行,使用 Promise.all * @param opts 执行参数 */ parallel(opts: IPipelineOptions): Promise>; /** * 并行执行,最终 result 为数组 * @param opts 执行参数 */ concat(opts: IPipelineOptions): Promise>; /** * 串行执行,使用 foreach await * @param opts 执行参数 */ series(opts: IPipelineOptions): Promise>; /** * 串行执行,使用 foreach await,最终 result 为数组 * @param opts 执行参数 */ concatSeries(opts: IPipelineOptions): Promise>; /** * 串行执行,但是会把前者执行结果当成入参,传入到下一个执行中去,最后一个执行的 valve 结果会被返回 * @param opts 执行参数 */ waterfall(opts: IPipelineOptions): Promise>; } ``` * 白名单机制 使用 Pipeline 装饰器时,如果填写了数组参数,那么方法执行函数中的 valves 入参只能是装饰器数组参数中的项。当然,valves 是可选项,不填默认就以装饰器数组参数为准。例如,`@Pipeline(['a', 'b', 'c'])` 那么 series 等执行函数中可选参数 `opts.valves` 数组必须是 `['a', 'b', 'c']` 或者其子集,如果不填则以 `['a', 'b', 'c']`   逻辑顺序来执行。 ### 返回结果[​](#返回结果 "返回结果的直接链接") IPipelineResult 的类型如下。 ``` /** * pipeline 执行返回结果 */ export interface IPipelineResult { /** * 是否成功 */ success: boolean; /** * 异常信息(如果有则返回) */ error?: { /** * 异常出在那个 valve 上 */ valveName?: string; /** * 异常信息 */ message?: string; /** * 原始 Error */ error?: Error; }; /** * 返回结果 */ result: T; } ``` ## 使用举例[​](#使用举例 "使用举例的直接链接") 1. 假设有这样一个场景,我们需要一次性获取页面上的数据信息、当前用户信息以及有几个 Tab。那么我们先声明返回的数据类型 ``` class VideoDto { videoId: string; videoUrl: string; videoTitle: string; } class AccountDto { id: string; nick: string; isFollow: boolean; } class TabDto { tabId: string; title: string; index: number; } interface HomepageDto { videos: VideoDto[]; account: AccountDto; tab: TabDto; } ``` 2. 实现一个 TestService 来封装一下返回的这些数据 ``` @Provide('service') class TestService { // 返回当前登录用户信息 async getAccount(args: any): Promise { return { id: 'test_account_id', nick: 'test hello', isFollow: true, }; } // 返回视屏列表 async getVideos(args: any): Promise { return [ { videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video', }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video', }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video', }, ]; } // 返回tab页面 async getTab(args: any): Promise { return { title: 'test tab', tabId: 'firstTab', index: 0, }; } } ``` 3. 将几个任务封装拆分成不同的 IValveHandler 实现 ``` // 返回视屏信息的 @Provide() class VideoFeeds implements IValveHandler { alias = 'videos'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { return this.service.getVideos(ctx.args); } } // 返回账户信息的 @Provide() class AccountMap implements IValveHandler { alias = 'account'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 return this.service.getAccount(ctx.args); } } // 返回tab信息的 @Provide() class CrowFeeds implements IValveHandler { alias = 'tab'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 return this.service.getTab(ctx.args); } } // 捕捉整个错误异常的 @Provide() class ErrorFeeds implements IValveHandler { alias = 'tab'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 throw new Error('this is error feeds'); } } ``` ### parallel[​](#parallel "parallel的直接链接") 通过该方法执行的结果,最终返回的是一个 object 对象,且每个 IValveHandler 实现 alias 作为对象返回值的 key ``` class StageTest { // 这里声明一个 pipeline @Pipeline(['videoFeeds', 'accountMap', 'crowFeeds']) stages: IPipelineHandler; async runParallel(): Promise { // 这里并发执行 videoFeeds、accountMap、crowFeeds return this.stages.parallel({ args: { aa: 123 }, }); // 返回的 result 结构 /* { // 以 accountMap 的 alias account 作为返回对象的 key account: { id: 'test_account_id', nick: 'test hello', isFollow: true, }, // 以 videoFeeds 的 alias video 作为返回对象的 key video: [ { videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video' }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video' }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video' } ], // 以 crowFeeds 的 alias tab 作为返回对象的 key tab: { title: 'test tab', tabId: 'firstTab', index: 0 } } */ } } ``` ### concat[​](#concat "concat的直接链接") 执行方式同 parallel 只不过最终返回结果 result 是一个数组 ``` class StageTest { // 这里声明一个 pipeline @Pipeline(['videoFeeds', 'accountMap', 'crowFeeds']) stages: IPipelineHandler; async runConcat(): Promise { // 这里并发执行 videoFeeds、accountMap、crowFeeds return this.stages.concat({ args: { aa: 123 }, }); // 这里返回的 result 是一个数组 /* [ // 以 videoFeeds 作为第一个返回对象 [ { videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video' }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video' }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video' } ], // 以 accountMap 作为第二个返回对象 { id: 'test_account_id', nick: 'test hello', isFollow: true, }, // 以 crowFeeds 作为第三个返回对象 { title: 'test tab', tabId: 'firstTab', index: 0 } ] */ } } ``` ### series[​](#series "series的直接链接") 这里 series 是串行执行,按照 Pipeline 装饰器参数顺序,一个一个执行下去,且 IPipelienContext 中的 prev 就是前一个 valve,current 是当前,next 即下一个即将执行的 valve ``` class StageTest { // 这里声明一个 pipeline @Pipeline(['videoFeeds', 'accountMap', 'crowFeeds']) stages: IPipelineHandler; async runSeries(): Promise { // 这里串行执行 videoFeeds、accountMap、crowFeeds return this.stages.series({ args: { aa: 123 }, }); // 这里返回的 result 是一个对象,结果同 parallel 返回的对象拼装规则 } } ``` ### concatSeries[​](#concatseries "concatSeries的直接链接") 原理同 series,只不过返回结果是一个数组 ``` class StageTest { // 这里声明一个 pipeline @Pipeline(['videoFeeds', 'accountMap', 'crowFeeds']) stages: IPipelineHandler; async runConcatSeries(): Promise { // 这里串行执行 videoFeeds、accountMap、crowFeeds return this.stages.concatSeries({ args: { aa: 123 }, }); // 这里返回的 result 是一个数组,同 concat 返回对象拼装 } } ``` ### waterfall[​](#waterfall "waterfall的直接链接") 串行执行,最终只返回最后一个 valve 执行结果 ``` @Provide() class StageOne implements IValveHandler { async invoke(ctx: IPipelineContext): Promise { if (ctx.args.aa !== 123) { throw new Error('args aa is undefined'); } ctx.set('stageone', 'this is stage one'); ctx.set('stageone_date', Date.now()); if (ctx.info.current !== 'stageOne') { throw new Error('current stage is not stageOne'); } if (ctx.info.next !== 'stageTwo') { throw new Error('next stage is not stageTwo'); } if (ctx.info.prev) { throw new Error('stageOne prev stage is not undefined'); } return 'stageone'; } } @Provide() class StageTwo implements IValveHandler { async invoke(ctx: IPipelineContext): Promise { const keys = ctx.keys(); if (keys.length !== 2) { throw new Error('keys is not equal'); } ctx.set('stagetwo', ctx.get('stageone') + 1); ctx.set('stagetwo_date', Date.now()); // 验证是否是执行 stageOne 返回的结果 if (ctx.info.prevValue !== 'stageone') { throw new Error('stageone result empty'); } if (ctx.info.current !== 'stageTwo') { throw new Error('current stage is not stageTwo'); } if (ctx.info.next) { throw new Error('stageTwo next stage is not undefined'); } if (ctx.info.prev !== 'stageOne') { throw new Error('prev stage is not stageOne'); } return 'stagetwo'; } } class StageTest { // 这里声明一个 pipeline @Pipeline(['stageOne', 'stageTwo']) stages: IPipelineHandler; async runStagesWaterfall(): Promise { // 这里通过串行方式执行,可以看到 stageTwo 中做了校验,prevValue 即 stageOne 执行的结果 return this.stages.waterfall({ args: { aa: 123 }, }); } } ``` --- # 使用 pm2 [PM2](https://github.com/Unitech/pm2) 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 ## 安装[​](#安装 "安装的直接链接") 我们一般会把 pm2 安装到全局。 ``` $ npm install pm2 -g # 命令行安装 pm2 ``` ## 常用命令[​](#常用命令 "常用命令的直接链接") ``` $ pm2 start # 启动一个服务 $ pm2 list # 列出当前的服务 $ pm2 stop # 停止某个服务 $ pm2 restart # 重启某个服务 $ pm2 delete # 删除某个服务 $ pm2 logs # 查看服务的输出日志 ``` 比如, `pm2 list` ,就会以表格显示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616560437389-b193a0d0-b463-49f1-a347-8dec20e7504d.png#align=left\&display=inline\&height=310\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=310\&originWidth=1065\&size=165090\&status=done\&style=none\&width=1065) pm2 的服务都有一个数组 id,你可以用 id 快速操作它。 比如: ``` $ pm2 stop 1 # 停止编号为 1 的服务 $ pm2 delete 1 # 删除编号为 1 的服务 ``` 使用 `--name`  参数添加一个应用名。 ``` $ pm2 start ./bootstrap.js --name test_app ``` 然后你可以用这个应用名来操作启停。 ``` $ pm2 stop test_app $ pm2 restart test_app ``` ## 启动应用[​](#启动应用 "启动应用的直接链接") Midway 应用一般使用 `npm run start`  做线上部署。其对应的命令为 `NODE_ENV=production node bootstrap.js` 。 信息 部署前需要执行编译 npm run build 对应的 pm2 命令为 ``` $ NODE_ENV=production pm2 start ./bootstrap.js --name midway_app -i 4 ``` * \--name 用于指定应用名 * -i 用于指定启动的实例数(进程),会使用 cluster 模式启动 效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616562075255-088155ee-7c4f-4eae-b5c5-db826f78b519.png#align=left\&display=inline\&height=189\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=189\&originWidth=1008\&size=48357\&status=done\&style=none\&width=1008) ## Docker 容器启动[​](#docker-容器启动 "Docker 容器启动的直接链接") 在 Docker 容器中,后台启动的代码都会被退出,达不到预期效果。pm2 使用另一个命令来支持容器启动。 请将命令修改为 pm2-runtime start 。 ``` $ NODE_ENV=production pm2-runtime start ./bootstrap.js --name midway_app -i 4 ``` 具体的 pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 --- # 接入 Prometheus Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 Grafana 是一个开源的度量分析与可视化套件。纯 Javascript 开发的前端工具,通过访问库(如 InfluxDB),展示自定义报表、显示图表等。Grafana 支持许多不同的数据源。每个数据源都有一个特定的查询编辑器,该编辑器定制的特性和功能是公开的特定数据来源。而 Prometheus 正好是其支持的数据源之一。 本篇介绍了 Midway 如何接入 Grafana + Prometheus。 接入效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617259935548-a2df4339-3229-4391-bd3d-4ba8e6979d4d.png#height=498\&id=KoiiE\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=996\&originWidth=1914\&originalType=binary\&ratio=1\&size=969345\&status=done\&style=none\&width=957) ## 安装组件[​](#安装组件 "安装组件的直接链接") 首先安装 Midway 提供的指标监控组件: ``` $ npm install @midwayjs/prometheus -S ``` 在 `configuration.ts`  中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/decorator'; import * as prometheus from '@midwayjs/prometheus'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [prometheus], // 引入模块 importConfigs: [join(__dirname, 'config')], }) export class AutoConfiguration {} ``` 启动我们的应用,此时访问的时候多了一个 `${host}:${port}/metrics`  。 信息 Prometheus 基于 HTTP 获取监控数据,请加载 web/koa/express 任一框架,并使用多框架模式启动。 访问接口,返回如下,里面的内容是当前的指标。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260048533-4f725824-9471-40c9-be8b-6dcbf27d9cca.png#height=997\&id=DIl0G\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1994\&originWidth=2276\&originalType=binary\&ratio=1\&size=1070956\&status=done\&style=none\&width=1138) ## 其他配置[​](#其他配置 "其他配置的直接链接") 指标组件也提供了相关的配置,方便开发者进行配置。 可以在 `config.default.ts`  中,修改 prometheus 的配置。 ``` import { DefaultConfig } from '@midwayjs/prometheus'; export const prometheus: DefaultConfig = { labels: { APP_NAME: 'demo_project', }, }; ``` 更多的配置,我们可以查看 `DefaultConfig`  这个定义进行配置。 通过配置,我们例如可以归类哪些 node 是同一个应用,因为我们部署的时候,node 程序是分布式的。例如上面我们加了 APP\_NAME,用来区分不同的应用,这样在监控指标中,我们可以区分不同的应用。 ## 数据采集[​](#数据采集 "数据采集的直接链接") 我们前面在 Midway 中引入的组件主要是在 Node 中加了指标模块。接下来我们需要让 Prometheus 来采集我们的指标数据。 如果开发者所在部门已经有 Prometheus+grafana 了,则只需将应用的指标地址上报给 PE 或者通过接口上报即可。此处我们假设大家没有 Prometheus+grafana,然后按照下面描述进行操作。 ## 搭建 Prometheus[​](#搭建-prometheus "搭建 Prometheus的直接链接") 此处我们通过 docker-compose 来搭建 Prometheus, docker-compose.yml  文件如下: ``` version: '2.2' services: tapi: logging: driver: 'json-file' options: max-size: '50m' image: prom/prometheus restart: always volumes: - ./prometheus_data:/prometheus_data:rw - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./targets.json:/etc/prometheus/targets.json command: - '--storage.tsdb.path=/prometheus_data' - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention=10d' - '--web.enable-lifecycle' ports: - '9090:9090' ``` `prometheus.yml`   文件如下: ``` global: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. scrape_configs: - job_name: 'node' file_sd_configs: - refresh_interval: 1m files: - '/etc/prometheus/targets.json' - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] ``` 然后采集的 `targets.json`   如下:下面文件里面 `${ip}`   替换为 Node.js 应用所在服务器的 ip 地址。 ``` [ { "targets": ["${ip}:7001"], "labels": { "env": "prod", "job": "api" } } ] ``` 然后我们启动 `docker-compose.yml`   文件, ``` $ docker-compose up ``` 至此,Prometheus 已经会去拉取我们 Node 应用程序的指标数据了。 如果想要更新 target 怎么做: 修改了这个 targets.json 文件后,通过 prometheus 的 reload 方法进行热加载。 方法如下: ``` curl -X POST http://${prometheus的ip}:9090/-/reload ``` 然后我们可以查看 prometheus 的页面也可以确认是否生效,界面地址: ``` http://${prometheus的ip}:9090/classic/targets ``` 接下来就是如何展示这些采集到的数据了。 ## 数据展示[​](#数据展示 "数据展示的直接链接") 我们可以借助 Grafana 来展示我们的数据。 此处我们简单通过 Docker 来搭建一下 Grafana: ``` $ docker run -d --name=grafana -p 3000:3000 grafana/grafana ``` 然后我们访问 127.0.0.1:3000,默认账号密码:admin:admin。 然后访问后如下效果: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260561047-c2643a69-6258-491b-937d-9bfc4558252f.png#height=346\&id=yNdWZ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=692\&originWidth=1496\&originalType=binary\&ratio=1\&size=551202\&status=done\&style=none\&width=748) 然后我们让 Grafana 接入我们的 Prometheus 数据源: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260581029-1e2e06a8-3054-4ad8-96b5-d50ab9bb1612.png#height=286\&id=atAvT\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=572\&originWidth=1490\&originalType=binary\&ratio=1\&size=169944\&status=done\&style=none\&width=745) 然后我们点击 Grafana 添加图表: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725466020-28793a78-c03b-48fa-bf16-0c9c8ecc1a94.png#clientId=u070308fc-4e5d-4\&from=paste\&height=741\&id=uce167575\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1482\&originWidth=2626\&originalType=binary\&ratio=1\&size=310590\&status=done\&style=none\&taskId=uedd61eb7-8e61-488f-963f-f70adb9a651\&width=1313) 这边 ID 选择 14403,然后点击 load,然后点击下一步,然后点击 import 后,就能看到我们刚刚接入的效果了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725497338-a32a8982-d51f-4e74-b511-dc10a7c66d80.png#clientId=u070308fc-4e5d-4\&from=paste\&height=996\&id=uba6ac1f0\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1992\&originWidth=3836\&originalType=binary\&ratio=1\&size=1951604\&status=done\&style=none\&taskId=ua7c2fc08-0633-4614-9af0-5bf2da800ef\&width=1918) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725514630-4f654f10-ef3a-41f7-b403-02832d3ef7d8.png#clientId=u070308fc-4e5d-4\&from=paste\&height=998\&id=u27a3ae30\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1996\&originWidth=3830\&originalType=binary\&ratio=1\&size=2201307\&status=done\&style=none\&taskId=ucee30610-4c1f-4fa8-82fd-a952d5aa9e1\&width=1915) 这样开发者可以运维自己的 Node 程序了,例如,是否最近引入了一个 NPM 包导致了什么内存泄漏的情况,是否最近有应用重启的情况了。 当然还能支持其他的自定义操作。 ## Socket-io 场景[​](#socket-io-场景 "Socket-io 场景的直接链接") 使用方法: ``` npm install @midwayjs/prometheus-socket-io -S ``` 使用方法: ``` import { Configuration } from '@midwayjs/decorator'; import { join } from 'path'; import * as prometheus from '@midwayjs/prometheus'; import * as prometheusSocketIo from '@midwayjs/prometheus-socket-io'; @Configuration({ imports: [prometheus, prometheusSocketIo], importConfigs: [join(__dirname, './config')], conflictCheck: true, }) export class ContainerLifeCycle {} ``` 然后在/metrics 这边就能看到 socket-io 的数据了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1631090438583-d925c13c-371a-4037-9f53-edaa34580aab.png#clientId=u24adff00-2245-4\&from=paste\&height=459\&id=u2862ab6b\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=918\&originWidth=1470\&originalType=binary\&ratio=1\&size=481525\&status=done\&style=none\&taskId=ua4ce06b2-a75d-4e4a-8bd9-c94496dca33\&width=735) 一共新增 8 个指标。 后续会提供 Grafana 的模版 ID 给大家使用。 ## 功能介绍[​](#功能介绍 "功能介绍的直接链接") * 根据 appName 进行分类 * 查看不同 path 的 qps 情况 * 查看不同 status 的分布情况 * 查询不同 path 的 rt 情况 * 进程的 CPU 使用情况 * 进程的内存使用情况 * 堆栈情况 * Event Loop * 等 --- # Midway 维护计划 | Release | Status | Codename | Initial Release | Active LTS Start | Maintenance LTS Start | End-of-life | | -------------------- | ------------------- | -------- | --------------- | ---------------- | --------------------- | ----------- | | midway v1(inner v6) | **Maintenance LTS** | VISION | 2018-06-14 | 2018-10 | 2020-04 | 2022-04 | | midway v2(inner v7) | **Active LTS** | | 2020-10 | 2021-02 | 2021-10 | | | midway v3 | **Beta** | | 2022-01 | | | | --- # 请求、响应、应用 Midway 框架会根据不同的场景来启动不同的应用,前文提到,我们默认选用 EggJS 作为我们的 Web 框架,也可以使用 Express 或者 Koa。 每个使用的 Web 框架会提供自己独特的能力,这些独特的能力都会体现在各自的 **请求和响应**(Context)和 **应用**(Application)之上。 ## 上下文和应用定义约定[​](#上下文和应用定义约定 "上下文和应用定义约定的直接链��接") 为了简化使用,所有的上层框架导出 **请求和响应**(Context)和 **应用**(Application)定义,我们都保持一致。即 `Context`  和 `Application` 。 ``` import { Application, Context } from 'egg'; import { Application, Context } from '@midwayjs/koa'; import { Application, Context } from '@midwayjs/express'; ``` 且非 Web 框架,我们也保持了一致。 ``` import { Application, Context } from '@midwayjs/socketio'; import { Application, Context } from '@midwayjs/grpc'; import { Application, Context } from '@midwayjs/rabbitmq'; ``` ## 请求和响应[​](#请求和响应 "请求和响应的直接链接") 每个 Web 框架的请求和响应对象是不同的,EggJS 和 Koa 都是使用 `ctx`  对象,而 Express 使用 `req` , `res`  对象。 在 Midway 提供的装饰器不够,或者需要复杂业务逻辑的时候,我们就需要原生框架的对象支持。 在 \*\*默认的请求作用域 \*\*中,也就是说在 控制器(Controller)或者普通的 服务(Service)中,我们可以使用 `@Inject`  来注入对应的实例。 比如在以 EggJS 为上层 Web 框架代码中,我们可以这样获取到对应的 ctx 实例。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/decorator'; import { Context } from 'egg'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // this.ctx.query } } ``` 而 Koa 和 Express 则是不同的用法。Koa 示例如下。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // this.ctx.query } } ``` Express 比较特殊, `@Inject`  注入的 ctx 对象由 Midway 做了封装,为 Express 的 req 对象和 res 对象的集合。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request, Response } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; // 包含了 req 和 res @Inject() req: Request; @Inject() res: Response; @Get('/') async home() { // this.req.query } } ``` ## 应用实例[​](#应用实例 "应用实例的直接链接") 在编写业务代码中,有时候我们需要用到原本框架的能力,而这些能力可能暴露在各自的 app 对象之上。Midway 提供了 `@App`  这个装饰器,用于注入当前运行时的 app 示例。 比如,在 EggJS 框架中,app 提供了 `curl`  方法,用于获取远程的数据,我们通过注入这个 app 就可以拿到对应的方法。 ``` import { App, Controller, Get, Provide } from '@midwayjs/decorator'; import { Application } from 'egg'; @Provide() @Controller('/') export class HomeController { @App() app: Application; @Get('/') async home() { const data = await this.app.curl('/api/data.json'); return { data, }; } } ``` 信息 我们在任意的 `@Provide`  装饰的 Class 上都可以使用 `@App`  装饰器。 而在 Koa 为 Web 框架的应用上,将会注入 Koa 的 app 实例。 ``` import { App, Controller, Get, Provide } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @App() app: Application; @Get('/') async home() { // this.app.use(xxx) } } ``` 信息 这里的 **Application**  定义是由于 Koa 不支持直接扩展,Midway 为了方便使用,进行了封装。 具体的 app 上的方法,请参考详细 app API 或者不同的 Web 框架文档。 --- # Web 路由表 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 在应用启动,onReady 生命周期以及之后可用。 ## 创建路由表收集器[​](#创建路由表收集器 "创建路由表收集器的直接链接") ``` import { WebRouterCollector } from '@midwayjs/core'; const collector = new WebRouterCollector(); ``` ## 路由信息定义[​](#路由信息定义 "路由信息定义的直接链接") 每个路由信息由一个 `RouterInfo`  定义表示,包含一些属性。 定义如下: ``` export interface RouterInfo { /** * router prefix */ prefix: string; /** * router alias name */ routerName: string; /** * router path, without prefix */ url: string | RegExp; /** * request method for http, like get/post/delete */ requestMethod: string; /** * invoke function method */ method: string; description: string; summary: string; /** * router handler function key,for IoC container load */ handlerName: string; /** * serverless func load key */ funcHandlerName: string; /** * controller provideId */ controllerId: string; /** * router middleware */ middleware: any[]; /** * controller middleware in this router */ controllerMiddleware: any[]; /** * request args metadata */ requestMetadata: any[]; /** * response data metadata */ responseMetadata: any[]; } ``` | 属性 | 类型 | 描述 | | -------------------- | --------- | --------------------------------------------------------------- | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | routerName | string | 路由名 | | url | string | 路由的去除路由前缀的部分,也是用户写在 @Get 等装饰器上的部分 | | requestMethod | string | get/post/delete/put/all 等 | | method | string | 实际调用的类上的方法名 | | description | string | 描述,路由装饰器上的参数 | | summary | string | 摘要,路由装饰器上的参数 | | handlerName | string | 等价于 controllerId.method | | funcHandlerName | string | 使用 @Func 写的 handler 名字 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | middleware | string\[] | 路由中间件字符串数组 | | controllerMiddleware | string\[] | 控制器中间件字符串数组 | | requestMetadata | any\[] | 请求参数的元数据,@Query/@Body 等元数据 | | responseMetadata | any\[] | 响应参数的元数据,@SetHeader/@ContentType 等元数据 | ## 路由优先级[​](#路由优先级 "路由优先级的直接链接") 以往我们需要关心路由的加载顺序,比如通配的 `/*` 比如在实际的 `/abc` 之后,否则会加载到错误的路由。在新版本中,我们对此种情况做了自动排序。 规则如下: * 1. 绝对路径规则优先级最高如 /ab/cb/e * 2. 星号只能出现最后且必须在/后面,如 /ab/cb/\*\* * 3. 如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高 * 4. 有多个通配能匹配一个路径时,最长的规则匹配,如 /ab/\*\* 和 /ab/cd/\*\* 在匹配 /ab/cd/f 时命中 /ab/cd/\*\* * 5. 如果 / 与 /\_ 都能匹配 / ,但 / 的优先级高于 /\_ 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如,排序完的优先级如下(高到低): ``` /api/invoke/abc /api/invoke/* /api/abc /api/* /abc /* ``` ## 获取扁平化路由列表[​](#获取扁平化路由列表 "获取扁平化路由列表的直接链接") 获取当前所有可注册到 HTTP 服务的路由列表(包括 @Func/@Controller,以及一切按照标准信息注册的自定义装饰器)。 会按照优先级从高到低自动排序。 定义: ``` async getFlattenRouterTable(): Promise ``` 获取路由表 API。 ``` const result = await collector.getFlattenRouterTable(); ``` 输出示例: ``` [ { prefix: '/', routerName: '', url: '/set_header', requestMethod: 'get', method: 'homeSet', description: '', summary: '', handlerName: 'apiController.homeSet', funcHandlerName: 'apiController.homeSet', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [ { type: 'web:response_header', setHeaders: { ccc: 'ddd', }, }, { type: 'web:response_header', setHeaders: { bbb: 'aaa', }, }, ], }, { prefix: '/', routerName: '', url: '/ctx-body', requestMethod: 'get', method: 'getCtxBody', description: '', summary: '', handlerName: 'apiController.getCtxBody', funcHandlerName: 'apiController.getCtxBody', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [], }, // ... ]; ``` ## 获取 Router 信息列表[​](#获取-router-信息列表 "获取 Router 信息列表的直接链接") 在 Midway 中,每个 Controller 对应一个 Router 对象,每个 Router 都会有一个路由前缀(prefix),在此之中的所有路由都会按照上面的规则进行排序。 Router 本身也会按照 prefix 进行排序。 定义: ``` export interface RouterPriority { prefix: string; priority: number; middleware: any[]; routerOptions: any; controllerId: string; } async getRoutePriorityList(): Promise ``` Router 的数据相对简单。 | 属性 | 类型 | 描述 | | ------------- | --------- | ------------------------------------------------------------------------------ | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | priority | number | Router 的优先级,@Priority 装饰器填写的值,/ 根 Router 默认优先级最低,为 -999 | | middleware | string\[] | 控制器中间件字符串数组 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | routerOptions | any | @Controller 装饰器的 options | 获取路由表 API。 ``` const list = await collector.getRoutePriorityList(); ``` 输出示例: ``` [ { prefix: '/case', priority: 0, middleware: [], routerOptions: { middleware: [], sensitive: true, }, controllerId: 'caseController', }, { prefix: '/user', priority: 0, middleware: [], routerOptions: { middleware: [], sensitive: true, }, controllerId: 'userController', }, { prefix: '/', priority: -999, middleware: [], routerOptions: { middleware: [], sensitive: true, }, controllerId: 'apiController', }, ]; ``` ## 获取带层级的路由[​](#获取带层级的路由 "获取带层级的路由的直接链接") 某些情况下,我们需要拿到带层级的路由,包括哪些路由在哪个控制器(Controller)下,这样能更好的创建路由。 Midway 也提供了获取带层级的路由表方法。层级内会按照优先级从高到低自动排序。 定义: ``` async getRouterTable(): Promise> ``` 获取层级路由表 API,返回的是个 Map,key 为控制器的路由前缀 prefix 字符串。未明确写明路由前缀的(比如函数或者其他场景),都将归为 / 路由前缀下。 ``` const result = await collector.getRouterTable(); ``` 输出示例: ``` Map(3) { '/' => [ { prefix: '/', routerName: '', url: '/set_header', requestMethod: 'get', method: 'homeSet', description: '', summary: '', handlerName: 'apiController.homeSet', funcHandlerName: 'apiController.homeSet', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [Array], }, { prefix: '/', routerName: '', url: '/ctx-body', requestMethod: 'get', method: 'getCtxBody', description: '', summary: '', handlerName: 'apiController.getCtxBody', funcHandlerName: 'apiController.getCtxBody', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [], }, // ... ] } ``` --- # 示例列表 ## 官方示例[​](#官方示例 "官方示例的直接链接") * 官方示例库: * prisma 示例: * GraphQL 示例: ## 社区示例[​](#社区示例 "社区示例的直接链接") * 一个组件示例: * 一个 midway 最佳实践: * 一个基于 Midway 的后台管理系统: * 一个包含 nacos+crud 的示例: --- # API 网关 API 网关在阿里云函数体系中比较特殊,他类似于创建一个无触发器函数,通过平台网关的绑定到特定的路径上。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.API_GATEWAY, { path: '/api_gateway_aliyun', method: 'post', }) async handleAPIGatewayEvent(@Body() name) { return `hello ${name}`; } } ``` 在 `npm run deploy` 后,参考[阿里云文档](https://help.aliyun.com/document_detail/74798.html?spm=a2c4g.11186623.6.701.3be978a1MKsNN4)配置即可。 信息 当前 API 网关线上的路由在平台进行配置。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { Framework } from '@midwayjs/serverless-app'; import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; import { createFunctionApp, createHttpRequest } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); }); afterAll(async () => { await close(app); }); it('should get result from http trigger', async () => { const result = await createHttpRequest(app).post('api_gateway_aliyun').send({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); }); }); ``` --- # 事件触发器(Event) 发布不包含触发器的函数,这是最简单的类型,可以直接通过 event 手动触发参数,也可以在平台绑定其他触发器。 ## 使用方式[​](#使用方式 "使用方式的直接链接") 通过直接在代码中的 `@ServerlessTrigger`  装饰器绑定事件触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, FC } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.EVENT) async handleEvent(event: any) { return event; } } ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") 通过 `createFunctionApp`  创建函数 app,通过 `getServerlessInstance`  获取类实例,然后通过实例的方法直接调用,传入参数进行测试。 ``` describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from event trigger', async () => { expect(await instance.handleEvent('hello world')).toEqual('hello world'); }); }); ``` --- # HTTP 触发器 阿里云的 HTTP 触发器和其他平台的有所区别,是独立于 API 网关的另一套服务于 HTTP 场景的触发器。相比于 API 网关,该触发器更易于使用和配置。 ## 单接口配置[​](#单接口配置 "单接口配置的直接链接") 通过直接在代码中的 `@ServerlessTrigger` 装饰器绑定 HTTP 触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") 和应用类似相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { Framework } from '@midwayjs/serverless-app'; import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; import { createFunctionApp, createHttpRequest } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); }); afterAll(async () => { await close(app); }); it('should get result from http trigger', async () => { const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); }); }); ``` ## 部署[​](#部署 "部署的直接链接") 使用 `npm run deploy`  部署代码。 发布完成后,平台状态如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1586685106514-c52880d4-c447-4bc1-9b8b-6db99dd81878.png#height=436\&id=wtVSC\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=872\&originWidth=2684\&originalType=binary\&size=164942\&status=done\&style=none\&width=1342) 发布效果,每个配置的函数都将发布成一个平台上的函数,并且自动配置 http 触发器: ## 自定义域名[​](#自定义域名 "自定义域名的直接链接") 你需要提前申请一个域名,在国内的话,需要备案,否则无法绑定。 第一步,先将默认自动生成的域名的功能关闭 ``` service: name: midway-faas-examples provider: name: aliyun custom: customDomain: false ``` 第二步,添加域名解析到你函数对应网关。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588654519449-2c98a9d8-ffac-42b7-bcf2-ac19c21f08ac.png#height=478\&id=kmxTj\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1090\&originWidth=1700\&originalType=binary\&size=132002\&status=done\&style=none\&width=746) 在函数页面绑定自定义域名,添加路由 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588654440214-75bfd1c2-1b6a-4c2b-9c57-198bec9d4e64.png#height=706\&id=IEhZC\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1412\&originWidth=2794\&originalType=binary\&size=310772\&status=done\&style=none\&width=1397) 绑定完成后,即可用域名访问。 ## 一些限制[​](#一些限制 "一些限制的直接链接") Request Headers 不支持以 x-fc-开头的自定义及以下字段的自定义: * accept-encoding * connection * keep-alive * proxy-authorization * te * trailer * transfer-encoding Response Headers 不支持以 `x-fc-` 开头的自定义及以下字段的自定义: * connection * content-length * content-encoding * date * keep-alive * proxy-authenticate * server * trailer * transfer-encoding * upgrade Request 限制项。如果超过以下限制,会返回 400 状态码和 InvalidArgument 错误码。 * Headers 大小:Headers 中的所有 Key 和 Value 的总大小不得超过 4 KB。 * Path 大小:包括所有的 Query Params,Path 的总大小不得超过 4 KB。 * Body 大小:HTTP Body 的总大小不得超过 6 MB。 Response 限制项。如果超过以下限制,会返回 502 状态码和 BadResponse 错误码。 * Headers 大小:Headers 中的所有 Key 和 Value 的总大小不得超过 4 KB。 --- # MNS 触发器(消息队列) 信息 请务必注意,阿里云消息队列会对 Topic 和 Queue 产生一定的费用。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, FC } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.MQ, { topic: 'test-topic', tags: 'bbb', }) async handleMNSEvent(event: FC.MNSEvent) { // ... } } ``` 在 `npm run deploy` 后,即可。 信息 注意,在阿里云下,midway faas 提供的默认消息队列格式为 JSON ## MNS 触发器配置[​](#mns-触发器配置 "MNS 触发器配置的直接链接") | 属性名 | 类型 | 描述 | | ------ | ------ | -------------------------------------------------------------- | | topic | string | 接收消息的 topic | | tags | string | 可选,描述了该订阅中消息过滤的标签(标签一致的消息才会被推送) | \| strategy � | 'BACKOFF\_RETRY' | 'EXPONENTIAL\_DECAY\_RETRY' | 调用函数的重试策略,可选值:BACKOFF\_RETRY, EXPONENTIAL\_DECAY\_RETRY, 默认值为: BACKOFF\_RETRY, | | region � | string | 可选,topic 所在的 region,如果不填,默认为和函数一样的 region | 示例: **监听 MQ 消息** ``` @ServerlessTrigger(ServerlessTriggerType.MQ, { topic: 'test-topic', region: 'cn-shanghai' strategy: 'BACKOFF_RETRY' }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") MNS 消息返回的结构如下,在 `FC.MNSEvent` 类型中有描述。 ``` { "Context": "user custom info", "TopicOwner": "1186202104331798", "Message": "hello topic", "Subscriber": "1186202104331798", "PublishTime": 1550216302888, "SubscriptionName": "test-fc-subscibe", "MessageMD5": "BA4BA9B48AC81F0F9C66F6C909C39DBB", "TopicName": "test-topic", "MessageId": "2F5B3C281B283D4EAC694B7425288675" } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createMNSEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloAliyunService } from '../src/function/hello_aliyun'; import { createMNSEvent, createInitializeContext } from '@midwayjs/serverless-fc-trigger'; import { join } from 'path'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from oss trigger', async () => { expect(await instance.handleMNSEvent(createMNSEvent())).toEqual('hello world'); }); }); ``` --- # OSS 触发器(对象存储) OSS 用于存储一些资源文件,是阿里云的资源存储产品。 当 OSS 中有文件创建,更新,对应的函数就会被触发而执行。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, FC } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.OS, { bucket: 'ossBucketName', events: ['oss:ObjectCreated:*', 'oss:ObjectRemoved:DeleteObject'], filter: { prefix: 'filterdir/', suffix: '.jpg', }, }) async handleOSSEvent(event: FC.OSSEvent) { // xxx } } ``` 在 `npm run deploy` 后,即可。 ## OSS 触发器配置[​](#oss-触发器配置 "OSS 触发器配置的直接链接") | 属性名 | 类型 | 描述 | | ------ | --------- | -------------------- | | bucket | string | 对象存储的 bucket 名 | | events | string\[] | 触发函数执行的事件名 | | filter | { | | prefix: string;    suffix: string;  } | 对象过滤参数,满足过滤条件的 对象才可以触发函数,包含一个配置属性 key,表示过滤器支持过滤的对象键 (key)。 | | | | | 示例: **监听对象创建和对象删除时的事件** ``` @ServerlessTrigger(ServerlessTriggerType.OS, { bucket: 'ossBucketName', events: ['oss:ObjectCreated:*', 'oss:ObjectRemoved:DeleteObject'], filter: { prefix: 'filterdir/', suffix: '.jpg', }, }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") OSS 消息返回的结构如下,在 `FC.OSSEvent` 类型中有描述。 ``` { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161e853" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.128.221" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createOSSEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloAliyunService } from '../src/function/hello_aliyun'; import { createOSSEvent, createInitializeContext } from '@midwayjs/serverless-fc-trigger'; import { join } from 'path'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from oss trigger', async () => { expect(await instance.handleOSSEvent(createOSSEvent())).toEqual('hello world'); }); }); ``` ## 注意[​](#注意 "注意的直接链接") * 1、一个 bucket 的一个前缀下只能支持配置一个触发器,如果配置多个会出现 `message: event source 'oss' returned error: Cannot specify overlapping prefix and suffix with same event type.`  的报错 --- # Timer 触发器(定时任务) 定时任务触发器用于定时执行一个函数。定时有两种方式,时间间隔(every)和 cron 格式。 信息 温馨提醒,测试函数后请及时关闭触发器自动执行,避免超额扣费。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, FC } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'cron', value: '0 0 4 * * *', // 每天4:00触发 https://help.aliyun.com/document_detail/68172.html }) async handleTimerEvent(event: FC.TimerEvent) { this.ctx.logger.info(event); return 'hello world'; } } ``` 在 `npm run deploy` 后,即可。 ## Timer 配置[​](#timer-配置 "Timer 配置的直接链接") \| 属性名 | 类型 | 描述 | | ------- | ------ | ------------------------------------------------------------------------- | ---------------------------------------------------- | | type | 'cron' | 'every' | 必填,触发类型,分别代表 cron 表达式,固定时间间隔。 | | value | string | 必填,cron 表达式或者 every 值。every 时最小时间间隔 1 分钟,固定单位分钟 | | payload | string | 可选,一个固定传递的值,很少用 | | | | | 信息 注意,FC 使用的是 UTC 时间,和传统的中国时区不同。 示例: **cron 表达式** ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'cron', value: '0 0 4 * * *', // 每天4:00触发 }) ``` cron 表达式可以查看 [文档](https://help.aliyun.com/document_detail/169784.html)。 **every 表达式** ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'every', value: '5m', // 每隔 5 分钟,最小为 1 分钟 }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") Timer 消息返回的结构如下,在 `FC.TimerEvent` 类型中有描述。 ``` { triggerTime: new Date().toJSON(), triggerName: 'timer', payload: '', } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createTimerEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloAliyunService } from '../src/function/hello_aliyun'; import { createTimerEvent, createInitializeContext } from '@midwayjs/serverless-fc-trigger'; import { join } from 'path'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from timer trigger', async () => { expect(await instance.handleTimerEvent(createTimerEvent())).toEqual('hello world'); }); }); ``` ## 关闭触发器[​](#关闭触发器 "关闭触发器的直接链接") 如果不再使用,请务必关闭触发器或者直接删除。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618734441838-7a943f47-bbf7-4398-b63e-4b249f83d711.png#clientId=u77edf6bf-5564-4\&from=paste\&height=405\&id=u9e6b7d20\&margin=%5Bobject%20Object%5D\&originHeight=810\&originWidth=2280\&originalType=binary\&ratio=1\&size=134297\&status=done\&style=none\&taskId=u261c1c9a-06a0-4664-9a2b-4f0188cd9b8\&width=1140) --- # 应用迁移方案说明 ## 迁移方案[​](#迁移方案 "迁移方案的直接链接") 本方案适用于已有 EggJS,Express,Koa 等应用,可以部署在不同云平台的弹性容器中,减少部署和运维成本。 请根据当前的应用类型进行文档选择。 [Egg/Midway 应用迁移](https://www.yuque.com/go/doc/32353538?view=doc_embed)[Express 应用迁移](https://www.yuque.com/go/doc/32353537?view=doc_embed)[Koa 应用迁移](https://www.yuque.com/go/doc/32353536?view=doc_embed) ## 这套方案和平台的迁移方案有什么区别?[​](#这套方案和平台的迁移方案有什么区别 "这套方案和平台的迁移方案有什么区别?的直接链接") Midway Serverless 从 v1.1 版本开始提供了一套应用迁移到  Serverless 容器的方案,而各个平台也已经有自己的方案,比如阿里云的 customRuntime 接入方案,以及腾讯云的各种 Component 组件。 这其中的区别有几个: * 1、Midway Serverless 提供的平台迁移方案和函数部分相同,**是跨平台的**,即方案不受限于阿里云或者其他云平台,代码和应用时期一致,不需要(或者很少)做修改 * 2、复用函数的运行时适配能力,可以和函数享受同样稳定的能力,这套适配能力由 Midway Serverless 本身提供,**代码开源,也方便排查和定位问题**,或者增强能力 * 3、Midway Serverless 这套能力比较通用,私有化部署或者**适配其他应用框架非常容易** ## 迁移方案和纯函数的区别[​](#迁移方案和纯函数的区别 "迁移方案和纯函数的区别的直接链接") 迁移方案使用的是传统的应用代码,在部署时使用的是固定的 HTTP 触发器模式,无法在项目中添加其他触发器。 迁移方案通过一套中间的代理层(Proxy Layer),将函数的入参转换为传统请求到原函数,而纯函数不经过这层代理,所以性能会比迁移方案高。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1623937490756-27bcb3d0-8d61-49af-a1f1-0efe72b5c1dc.png#clientId=ub2750586-4d72-4\&from=paste\&height=542\&id=u06931f71\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1084\&originWidth=2290\&originalType=binary\&ratio=2\&size=120683\&status=done\&style=none\&taskId=u4f359237-b2d5-46ad-9dfa-42fd42375fa\&width=1145) 如需纯函数,可以新起一个纯函数项目。 迁移方案绑定的是 `/*` 的路由,和纯函数可以共享一个域名。 ## 一些能力限制[​](#��一些能力限制 "一些能力限制的直接链接") * 1、平台网关的限制,比如阿里云和腾讯云网关,超时时间,POST 大小、文件上传等,和函数是一样的,即函数不能做的事情,在这套应用部署方案中依旧不能做 * 2、应用的包部署不宜过大,如果比较大,可以使用云平台的对应方案来解决,比如阿里云的 NAS,或是腾讯云/AWS 的 Layer * 3、应用在函数容器中的带状态的部分,由应用本身处理,这套方案不负责解决这个问题 * 4、应用在函数容器中部署模型为\*\*单进程,\*\*稳定性由弹性容器本身来解决 * 5、应用中有 long runing 或者定时任务的部分,在无流量情况下不会触发,请使用其他方案代替。 * 6、应用中 socket 等非 HTTP 协议,不会生效 --- # 阿里云发布 FAQ ## 包大小问题[​](#包大小问题 "包大小问题的直接链接") 为了提升启动速度,阿里云 FC 容器限制压缩包大小为 50M,请尽可能精简你的后端代码依赖。 一般来说,midway 默认脚手架(eggjs)构建完在 9M 左右,其他框架会更小,请尝试先删除 `package-lock.json` 后再尝试。 ## 容器时区问题[​](#容器时区问题 "容器时区问题的直接链接") > 大部分 Docker  镜像都是基于 Alpine,Ubuntu,Debian,CentOS 等基础镜像制作而成。 基本上都采用 UTC 时间,默认时区为零时区。 阿里云容器环境的时区默认是 `GMT +0000` ,直接使用 `new Date()`  等前端获取的时候,国内的用户可能未作时区处理,会相差 8 个小时。 国内用户使用,默认可能习惯 `GMT +0800` 。可以通过环境变量调整(配置在平台或者 f.yml)。 ``` process.env.TZ = 'Asia/Shanghai'; ``` ``` provider: name: aliyun runtime: nodejs12 environment: TZ: 'Asia/Shanghai' ``` 信息 注意,定时任务由网关触发,不会受到这里配置的函数时区影响。 ## 修改 AccessKey[​](#修改-accesskey "修改 AccessKey的直接链接") 有时候,我们在第一次发布时会填错一个 accessKey,或者其他区域选项,我们提供了一个 可以修改的参数,用于在发布时清理上次错误的选项。 ``` midway-bin deploy --resetConfig ``` 如果只希望调整特定字段,可以进入 `~/.fcli/config.yaml`  文件中,直接修改保存。 ## CLI 发布红色提示[​](#cli-发布红色提示 "CLI 发布红色提示的直接链接") 在 HTTP 触发器发布后,会出现下面的红色提示。这是**一个提示**,原因为,未配置域名的情况下,阿里云将默认添加 `Content-Disposition: attachment` 头到响应中,浏览器打开地址会变为附件下载。可以通过绑定自定义域名或者本地 curl 的方式来测试结果。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1587036400388-b2ebe43f-fa7d-463b-b9b6-b38bf9e18430.png#height=268\&id=H2BJz\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=268\&originWidth=958\&originalType=binary\&ratio=1\&size=242934\&status=done\&style=none\&width=958) ## HTTP 函数绑定自定义域名[​](#http-函数绑定自定义域名 "HTTP 函数绑定自定义域名的直接链接") 阿里云的 http 函数绑定自定义域名的菜单就在左侧函数下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588753540328-1198bf42-6b57-4062-8e7b-ba4a9cc5ec0b.png#height=572\&id=f9LRZ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=572\&originWidth=1185\&originalType=binary\&ratio=1\&size=64810\&status=done\&style=none\&width=1185) 阿里云绑定域名会检测实名,备案等,请提前准备。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588753614297-b391fe03-2fef-4d8d-a065-ce7322016085.png#height=887\&id=ZndLt\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=887\&originWidth=880\&originalType=binary\&ratio=1\&size=72499\&status=done\&style=none\&width=880) ## 发布时指定 accessKey 等[​](#发布时指定-accesskey-等 "发布时指定 accessKey 等的直接链接") ``` export REGION=cn-beijing export ACCOUNT_ID=xxx export ACCESS_KEY_ID=xxx export ACCESS_KEY_SECRET=xxx ``` 当前阿里云发布使用的是 funcraft 工具,可以使用 funcraft 的环境变量,可以加载启动的命令行前,也可以使用 yml 的变量填充方式。 ## 发布时超时问题[​](#发布时超时问题 "发布时超时问题的直接链接") 有时候包比较大, `midway-bin deploy`  上传可能会碰到超时的问题,这个超时时间是 funcraft 工具内部控制的。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1598423950078-15838cbb-95f3-41f9-94ac-a31741b111d3.png#height=179\&id=EOCLm\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=358\&originWidth=2784\&originalType=binary\&ratio=1\&size=310195\&status=done\&style=none\&width=1392) 解决方案: `~/.fcli/config.yaml`  里面配置 timeout,单位是 s(秒)。 一般来说,midway 默认脚手架(eggjs)构建完在 9M 左右,其他框架会更小,请尝试先删除 `package-lock.json` 后再尝试。 如无效果,确实是包过大,可以修改 fun 工具的部署时间,位置为 `~/.fcli/config.yaml` ,在其中增加 timeout 字段。 示例如下: ``` endpoint: *************** api_version: '2016-08-15' access_key_id: *************** access_key_secret: *************** security_token: '' debug: false timeout: 50 ## 部署超时时间,单位为 s retries: 3 ``` --- # 腾讯云发布 FAQ ## 用户鉴权[​](#用户鉴权 "用户鉴权的直接链接") 腾讯云在部署时,如果是首次部署,则控制台会展示相应二维码,扫码即可完成认证,单项目后续会默认复用该配置。 鉴权文件保存在部署的根目录下的 `.env`   文件,如果要修改,可以删除该文件重新扫码。 也可以修改其中的内容,格式如下: ``` TENCENT_APP_ID=xxxxxx #授权账号的 AppId TENCENT_SECRET_ID=xxxxxx #授权账号的 SecretId TENCENT_SECRET_KEY=xxxxxx #授权账号的 SecretKey TENCENT_TOKEN=xxxxx #临时 token ``` 如果需要使用子账号发布,请查询 [子账号权限配置文档](https://cloud.tencent.com/document/product/1154/43006)。 ## ## 发布区域切换[​](#发布区域切换 "发布区域切换的直接链接") 腾讯云配置支持发布到不同的区域。 ``` service: fc-qinyue-test provider: name: tencent runtime: nodejs10 region: ap-shanghai ``` 常见的 region 值有: * ap-shanghai 上海 * ap-guangzhou 广州 * ap-beijing 北京 * ap-hongkong 香港 完整的地区列表请查看 [腾讯云文档](https://cloud.tencent.com/document/api/583/17238)。 ## [​](#-1 "-1的直接链接") ## 复用 API 网关[​](#复用-api-网关 "复用 API 网关的直接链接") 如果正式发布 HTTP 函数,每发布一次腾讯云都将自动创建一个标识网关的 serviceId,长期就会出现很多个,为了每次能复用,在第一次发布后,记录下 serviceId 让后面的代码复用,是比较好的习惯(或者提前申请好网关)。 ``` service: fc-qinyue-test provider: name: tencent runtime: nodejs10 serviceId: service-xxxxxx # <---- 把 id 填在这里复用 ``` **获取 API 网关 id** 方式一,从平台获取。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588752561344-c520ce4d-8dba-4e88-99c6-744e5af73cb9.png#height=577\&id=nPqm4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=577\&originWidth=1173\&originalType=binary\&size=72901\&status=done\&style=none\&width=1173) 方式二,在每次发布后获取。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588752629863-178fd9db-7dcb-496e-af05-1fc68abfb30f.png#height=115\&id=iBgEU\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=115\&originWidth=746\&originalType=binary\&size=39588\&status=done\&style=none\&width=746) ## 绑定域名[​](#绑定域名 "绑定域名的直接链接") 腾讯云发布后会自动给一个网关地址来访问云函数,比如 `http://service-xxxxx-xxxxxxxx.gz.apigw.tencentcs.com:80` ,同时针对环境,会自动映射三套环境名,加载 path 上。 * 测试环境 /test * 预发 /prepub * 线上 /release 在函数的触发管理和 API 网关处都可以看到这个地址。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588752924557-d0eb153e-f583-49c2-b9a4-55e417867b43.png#height=421\&id=cPfTl\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=578\&originWidth=1025\&originalType=binary\&size=49631\&status=done\&style=none\&width=746) 网关处。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588752972052-c2f7fbc8-0725-49e0-ab73-5dec6a7c0c00.png#height=732\&id=Qw18W\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=732\&originWidth=3010\&originalType=binary\&size=238685\&status=done\&style=none\&width=3010) 如果我们想移除这个环境,那么就得绑定自定义域名。 在 API 网关的自定义域名处,点“新建”。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588753063041-496d876f-3457-47cb-8156-c9e8364e91db.png#height=338\&id=mIiB5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=338\&originWidth=1096\&originalType=binary\&size=26777\&status=done\&style=none\&width=1096) 配置自定义路径映射,比如将 `/`  映射到正式的发布环境,这样在用域名访问的时候,就不会带有环境后缀了。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588753124170-9e6a2b01-dad8-47df-9d81-294d8397137b.png#height=607\&id=FAbTy\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=607\&originWidth=904\&originalType=binary\&size=49449\&status=done\&style=none\&width=904) ## 额外计费[​](#额外计费 "额外计费的直接链接") 使用本地工具时,由于使用了腾讯云提供的 SDK,可能会创建一个 COS Bucket 用于代码包的存储,由于 COS 是付费使用,会产生一定的费用费用。请及时关注自己的 COS 情况避免扣费。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1606803155279-51e71ffa-6e9a-4ab9-812b-19003d45483c.png#height=460\&id=DRD5n\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=460\&originWidth=1196\&originalType=binary\&size=60856\&status=done\&style=none\&width=1196) ## **删除腾讯云网关服务**[​](#删除腾讯云网关服务 "删除腾讯云网关服务的直接链接") 在试玩一段时间的腾讯云服务之后,由于不是每次复用 API 网关,会导致出现很多非重用的网关示例,如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588749300990-34089754-5fe2-4fb9-942a-0f9f0abc6984.png#height=1226\&id=Jo9cX\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1226\&originWidth=2778\&originalType=binary\&size=261243\&status=done\&style=none\&width=2778) 这个时候由于网关有绑定的函数,删除按钮是灰色的,我们需要手动将资源一一删除。 先进入一个 API 网关实例。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588749368951-da40aa66-249f-46ac-b208-e7085952c528.png#height=361\&id=fA0yx\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=1946\&originalType=binary\&size=134710\&status=done\&style=none\&width=746) 进入管理 API,删除底下的通用 API。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588749549259-fd35cfa1-9e00-42a3-82ff-78f3de23dd85.png#height=930\&id=iTseJ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=930\&originWidth=2346\&originalType=binary\&size=122962\&status=done\&style=none\&width=2346) 进入环境管理,将环境下线。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588749641386-77ddf012-2b29-46a5-a8dc-6d416d07518e.png#height=770\&id=lAclZ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=770\&originWidth=2234\&originalType=binary\&size=134714\&status=done\&style=none\&width=2234) 再回到最开始的列表,就可以点删除了。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1588749709595-1c47d6e3-08af-42e1-be34-961409f82e1a.png#height=986\&id=ZpugG\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=986\&originWidth=2342\&originalType=binary\&size=182531\&status=done\&style=none\&width=2342) --- # 发布到阿里云 FC ## 配置[​](#配置 "配置的直接链接") 在项目根目录的 `f.yml` 的 `provider` 段落处确保为 `aliyun` 。 ``` service: name: midway-faas-examples provider: name: aliyun ``` ## 部署[​](#部署 "部署的直接链接") 部署函数,直接使用发布命令即可打包并部署函数,Deploy 命令会自动打包,并调用阿里云官方部署工具发布。 ``` $ npm run deploy ``` 信息 如果输错了信息,可以重新执行 `npx midway-bin deploy --resetConfig` 修改。 阿里云部署首次需要配置 `accountId`、`accountKey`、`accountSecret` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654967-11e1bcbd-5a56-4239-99e1-5a1472ad49fd.png#align=left\&display=inline\&height=514\&margin=%5Bobject%20Object%5D\&originHeight=514\&originWidth=1152\&size=0\&status=done\&style=none\&width=1152) 相关配置获取,可参照下方图片: ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654949-9c14958c-3aff-403a-b89b-d03a3a95cd18.png#align=left\&display=inline\&height=696\&margin=%5Bobject%20Object%5D\&originHeight=696\&originWidth=1832\&size=0\&status=done\&style=none\&width=1832) 点击此处跳转阿里云[安全设置页](https://account.console.aliyun.com/#/secure)。 *** ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654950-19a811c5-2cf3-4843-a619-cfd744430fae.png#align=left\&display=inline\&height=184\&margin=%5Bobject%20Object%5D\&originHeight=592\&originWidth=2406\&size=0\&status=done\&style=none\&width=746) 点击跳转阿里云个人 [AccessKey 页面](https://usercenter.console.aliyun.com/#/manage/ak)。 发布后,阿里云会输出一个临时可用的域名,打开浏览器访问即可。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600835297676-1753de7a-fb0d-46ca-98f0-944eba5b2f2b.png#align=left\&display=inline\&height=193\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=193\&originWidth=1219\&size=35152\&status=done\&style=none\&width=1219) ## 常见问题[​](#常见问题 "常见问题的直接链接") 请查询 [阿里云发布 FAQ](/docs/deploy_aliyun_faq)。 --- # 发布到腾讯云 SCF ## 配置[​](#配置 "配置的直接链接") 在项目根目录的 `f.yml`  的 `provider`  段落处确保为 `tencent` 。 ``` service: name: midway-faas-examples provider: name: tencent ``` 配置运行时 ``` service: name: midway-faas-examples provider: name: tencent runtime: nodejs12 ``` 配置函数超时 ``` service: name: midway-faas-examples provider: name: tencent timeout: 60 # 单位秒 ``` 复用 HTTP 网关 腾讯云在每次部署 HTTP 类型时,都会创建一个新的网关绑定,对于开发时,我们可以复用同一个 id ``` service: name: midway-faas-examples provider: name: tencent serviceId: ******** ``` 具体写法可以参考 [复用网关 id](/docs/2.0.0/serverless/deploy_tencent_faq.md#NGqUs)。 ## 部署[​](#部署 "部署的直接链接") 执行 `npm run deploy`  即可,Deploy 命令会自动打包,并调用腾讯云官方部署工具发布。 视频流程如下: [屏幕录制 2021-03-25 下午 4.47.41.mov](https://www.yuque.com/attachments/yuque/0/2021/mov/501408/1616730670232-05605683-d88e-4e27-a393-9d8f2dfa489f.mov?_lake_card=%7B%22src%22%3A%22https%3A%2F%2Fwww.yuque.com%2Fattachments%2Fyuque%2F0%2F2021%2Fmov%2F501408%2F1616730670232-05605683-d88e-4e27-a393-9d8f2dfa489f.mov%22%2C%22name%22%3A%22%E5%B1%8F%E5%B9%95%E5%BD%95%E5%88%B62021-03-25+%E4%B8%8B%E5%8D%884.47.41.mov%22%2C%22size%22%3A19344722%2C%22type%22%3A%22video%2Fquicktime%22%2C%22ext%22%3A%22mov%22%2C%22status%22%3A%22done%22%2C%22uid%22%3A%221616730664011-0%22%2C%22progress%22%3A%7B%22percent%22%3A99%7D%2C%22percent%22%3A0%2C%22id%22%3A%22dWRP5%22%2C%22card%22%3A%22file%22%7D) ## 常见问题[​](#常见问题 "常见问题的直接链接") 请查询 [腾讯云发布 FAQ](/docs/2.0.0/serverless/deploy_tencent_faq.md)。 --- # Egg/Midway 应用迁移 Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 egg/midway 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 ## 使用[​](#使用 "使用的直接链接") 在代码根目录新增加文件 `f.yml` ,最为精简的内容如下。 ``` service: my-egg-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: egg ## 部署的应用类型 package: include: - public ## 如果有静态文件目录,写在这里会被自动拷贝 exclude: - package-lock.json ## 忽略 package-lock.json 文件 custom: customDomain: domainName: auto ## 自动生成域名 ``` 信息 有时候 package-lock.json 文件会造成部署包过大(将 dev 依赖打入)。 ## TS 编译[​](#ts-编译 "TS 编译的直接链接") 如果是 midway 项目,可以使用我们提供的发布钩子,在发布时自动执行编译,在 `package.json` 配置如下。 ``` { "name": "xxxxxx", "version": "xxxx", ..... "scripts": { "deploy": "midway-bin deploy", .... }, "midway-integration": { "lifecycle": { "before:package:cleanup": "npm run build" } }, "egg": { "framework": "@midwayjs/web" } } ``` 这里的要点有两个: * 1、这里指定了 `egg` 字段,用于指定特定的 egg 上层框架 * 2、这里配置了 `midway-integration` 字段,用于支持 midway 应用体系下原来的编译。 * 3、增加 deploy 脚本 信息 如果使用了自己的 egg 上层框架,这里的 egg.framework 可以变为自己的包名。 如果使用了 egg-ts ,则配置如下。 ``` { "name": "xxxxxx", "version": "xxxx", ..... "midway-integration": { "lifecycle": { "before:package:cleanup": "npm run tsc" } } } ``` ## 部署[​](#部署 "部署的直接链接") 在 `package.json` 配置 Scripts 脚本和 dev 依赖 `@midwayjs/cli` ,执行 `npm run deploy` 。 ``` { "devDependencies": { "@midwayjs/cli": "^1.2.36" ... }, "scripts": { "deploy": "midway-bin deploy", ... } } ``` 或者使用不同的 npm 包加速。 ``` { "scripts": { "deploy": "midway-bin deploy --npm=cnpm", ... } } ``` 也可以单独执行命令。 ``` $ npx midway-bin deploy ## deploy by npm $ npx midway-bin deploy --npm=cnpm ## deploy by cnpm ``` ## 默认情况[​](#默认情况 "默认情况的直接链接") ### 修改默认部署的函数名[​](#修改默认部署的函数名 "修改默认部署的函数名的直接链接") 可以通过 name 字段。 ``` service: my-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: egg name: app_idx ## 函数名 ``` 信息 使用 deployType 时 aggregation 字段不生效。 ### 迁移方案的 Egg 默认配置[​](#迁移方案的-egg-默认配置 "迁移方案的 Egg 默认配置的直接链接") 当前迁移方案会增加一些默认配置,用于在函数体系下更好运行,**一般情况下,用户无需修改**。 ``` // config.default const os = require('os'); exports.logger = { dir: os.tmpdir(), }; exports.rundir = os.tmpdir(); exports.static = { buffer: true, }; ``` 由于函数环境磁盘不可写,我们将默认的日志目录都调整为了临时目录。 ``` // plugin 'use strict'; exports.i18n = false; exports.watcher = false; exports.development = false; exports.logrotator = false; exports.schedule = false; exports.static = false; ``` 和默认 egg 不同的是,这里默认关闭了 static 插件,原因是,如果默认没有 `app/public`  目录,插件启动时会创建一个,由于服务器磁盘不可写,就会报错。 如果有 static 插件的需求,请**手动打开**,并**务必保证存在** `app/public`  或者相应的目录。 如果 `public`  目录在根目录,请配置 `f.yml`  中的 `package.include`  字段。 ``` service: my-egg-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: egg ## 部署的应用类型 package: include: - public ## 如果有静态文件目录,写在这里会被自动拷贝 exclude: - package-lock.json ## 忽略 package-lock.json 文件 ``` ### 阿里云[​](#阿里云 "阿里云的直接链接") 默认发布为 http 触发器,如果需要 API 网关,可以自行按照 f.yml 的格式进行 functions 结构的修改配置,同时,在 API 网关处配置路由 `/*`  中转到该函数即可。 ### 腾讯云[​](#腾讯云 "腾讯云的直接链接") 默认发布为 API 网关触发器,同时会自动配置网关路由。 ## 一些限制[​](#一些限制 "一些限制的直接链接") * 不支持 egg-socketio 等 * 不支持文件上传等网关无法支持的能力 * 还有一些,请参考 [应用迁移 faq](/docs/2.0.0/serverless/migrate_faq.md) --- # Express 应用迁移 Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 express 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 ## 新增函数配置[​](#新增函数配置 "新增函数配置的直接链接") 在代码根目录新增加文件 `f.yml` ,内容如下。 ``` service: my-express-demo ## 发布到云平台的应用名 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: express ## 部署的应用类型 package: exclude: - package-lock.json ## 忽略 package-lock.json 文件 custom: customDomain: domainName: auto ## 自动生成域名 ``` 信息 有时候 package-lock.json 文件会造成部署包过大(将 dev 依赖打入)。 ## 代码修改[​](#代码修改 "代码修改的直接链接") * 1、需要导出默认的 app * 2、项目文件当前文件名必须为 `app.js` * 3、 `index.js` 为保留文件,项目中请 不要有此文件。 ``` // app.js const express = require('express'); const app = express(); // ***** // 注释原本的监听 // app.listen(3000); // 导出默认的 app module.exports = app; ``` 如果在初始化有异步的情况 ,比如连接数据库等,我们提供了异步的支持。 ``` // app.js const express = require('express'); const app = new express(); // ***** // 注释原本的监听 // app.listen(3000); // 导出默认的 app module.exports = async () => { // do some async method, like db connect return app; }; ``` ## 静态资源[​](#静态资源 "静态资源的直接链接") 如果在项目根目录有希望构建拷贝的目录,比如静态文件 `public` 目录,请配置 `f.yml` 中的 `package.include` 字段。 ``` service: my-egg-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: express ## 部署的应用类型 package: include: - public ## 写在这里会被自动打包 exclude: - package-lock.json ## 忽略 package-lock.json 文件 ``` ## 部署[​](#部署 "部署的直接链接") 在 `package.json` 配置 Scripts 脚本和 dev 依赖 `@midwayjs/cli` ,执行 `npm run deploy` 。 ``` { "devDependencies": { "@midwayjs/cli": "^1.2.36" ... }, "scripts": { "deploy": "midway-bin deploy", ... } } ``` 或者使用不同的 npm 包加速。 ``` { "scripts": { "deploy": "midway-bin deploy --npm=cnpm", ... } } ``` 也可以单独执行命令。 ``` $ npx midway-bin deploy ## deploy by npm $ npx midway-bin deploy --npm=cnpm ## deploy by cnpm ``` ## 默认情况[​](#默认情况 "默认情况的直接链接") ### 阿里云[​](#阿里云 "阿里云的直接链接") 默认发布为  http 触发器,如果需要 API 网关,可以自行按照 f.yml 的格式进行 functions 结构的修改配置,同时,需要在平台配置路由。 ### 腾讯云[​](#腾讯云 "腾讯云的直接链接") 默认发布为  API 网关触发器,同时会自动配置网关路由。 ### 修改部署的函数名[​](#修改部署的函数名 "修改部署的函数名的直接链接") 可以通过 name 字段。 ``` service: my-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: express name: app_idx ## 函数名 ``` ## 一些限制[​](#一些限制 "一些限制的直接链接") * 不支持文件上传等网关无法支持的能力 * 还有一些,请参考 [应用迁移 faq](/docs/2.0.0/serverless/migrate_faq.md) --- # 应用迁移 FAQ ## 这套方案和平台的迁移方案有什么区别?[​](#这套方案和平台的迁移方案有什么区别 "这套方案和平台的迁移方案有什么区别?的直接链接") Midway Serverless 从 v1.1 版本开始提供了一套应用迁移到 Serverless 容器的方案,而各个平台也已经有自己的方案,比如阿里云的 customRuntime 接入方案,以及腾讯云的各种 Component 组件。 这其中的区别有几个: * 1、Midway Serverless 提供的平台迁移方案和函数部分相同,**是跨平台的**,即方案不受限于阿里云或者其他云平台,代码和应用时期一致,不需要(或者很少)做修改 * 2、复用函数的运行时适配能力,可以和函数享受同样稳定的能力,这套适配能力由 Midway Serverless 本身提供,**代码开源,也方便排查和定位问题**,或者增强能力 * 3、Midway Serverless 这套能力比较通用,私有化部署或者**适配其他应用框架非常容易** ## 一些能力限制[​](#一些能力限制 "一些能力限制的直接链接") * 1、平台网关的限制,比如阿里云和腾讯云网关,超时时间,POST 大小、文件上传等,和函数是一样的,即函数不能做的事情,在这套应用部署方案中依旧不能做 * 2、应用的包部署不宜过大,如果比较大,可以使用云平台的对应方案来解决,比如阿里云的 NAS,或是腾讯云/AWS 的 Layer * 3、应用在函数容器中的带状态的部分,由应用本身处理,这套方案不负责解决这个问题 * 4、应用在函数容器中部署模型为\*\*单进程,\*\*稳定性由弹性容器本身来解决 * 5、应用中有 long runing 或者定时任务的部分,在无流量情况下不会触发,请使用其他方案代替。 * 6、应用中 socket 等非 HTTP 协议,不会生效 --- # Koa 应用迁移 Midway Serverless 提供了一套通用的应用迁移方案,将原有应用尽可能不修改代码,就可以发布到函数平台。使用此方案,可以将原有的 koa 应用尽可能快速简单的迁移到函数平台进行托管,享受云原生时代的弹性红利。 ## 新增函数配置[​](#新增函数配置 "新增函数配置的直接链接") 在代码根目录新增加文件 `f.yml` ,内容如下。 ``` service: my-koa-demo ## 发布到云平台的应用名 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: koa ## 部署的应用类型 package: exclude: - package-lock.json ## 忽略 package-lock.json 文件 custom: customDomain: domainName: auto ## 自动生成域名 ``` 信息 有时候 package-lock.json 文件会造成部署包过大(将 dev 依赖打入)。 ## 代码修改[​](#代码修改 "代码修改的直��接链接") * 1、需要导出默认的 app * 2、项目文件当前文件名必须为 `app.js` * 3、 `index.js`  为保留文件,项目中请不要有此文件。 ``` // app.js const Koa = require('koa'); const Router = require('koa-router'); const app = new Koa(); // ***** // 注释原本的监听 // app.listen(3000); // 导出默认的 app module.exports = app; ``` 如果在初始化有异步的情况 ,比如连接数据库等,我们提供了异步的支持。 ``` // app.js const Koa = require('koa'); const Router = require('koa-router'); const app = new Koa(); // ***** // 注释原本的监听 // app.listen(3000); // 导出默认的 app module.exports = async () => { // do some async method, like db connect return app; }; ``` ## 静态资源[​](#静态资源 "静态资源的直接链接") 如果在项目根目录有希望构建拷贝的目录,比如静态文件 `public` 目录,请配置 `f.yml` 中的 `package.include` 字段。 ``` service: my-egg-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: koa ## 部署的应用类型 package: include: - public ## 写在这里会被自动打包 exclude: - package-lock.json ## 忽略 package-lock.json 文件 ``` ## 部署[​](#部署 "部署的直接链接") 在 `package.json` 配置 Scripts 脚本和 dev 依赖 `@midwayjs/cli` ,执行 `npm run deploy` 。 ``` { "devDependencies": { "@midwayjs/cli": "^1.2.36" ... }, "scripts": { "deploy": "midway-bin deploy", ... } } ``` 或者使用不同的 npm 包加速。 ``` { "scripts": { "deploy": "midway-bin deploy --npm=cnpm", ... } } ``` 也可以单独执行命令。 ``` $ npx midway-bin deploy ## deploy by npm $ npx midway-bin deploy --npm=cnpm ## deploy by cnpm ``` ## 默认情况[​](#默认情况 "默认情况的直接链接") ### 阿里云[​](#阿里云 "阿里云的直接链接") 默认发布为  http 触发器,如果需要 API 网关,可以自行按照 f.yml 的格式进行 functions 结构的修改配置,同时,需要在平台配置路由。 ### 腾讯云[​](#腾讯云 "腾讯云的直接链接") 默认发布为  API 网关触发器,同时会自动配置网关路由。 ### 修改部署的函数名[​](#修改部署的函数名 "修改部署的函数名的直接链接") 可以通过 name 字段。 ``` service: my-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: koa name: app_idx ## 函数名 ``` ## 一些限制[​](#一些限制 "一些限制的直接链接") * 不支持文件上传等网关无法支持的能力 * 还有一些,请参考 [应用迁移 faq](/docs/2.0.0/serverless/migrate_faq.md) --- # 静态网站托管 此方案适用于纯前端项目(React、vue 等)托管到 Serverless 平台(阿里云,腾讯云等)。 常见的场景有托管公司官网,个人主页,博客等。 ## 使用方法[​](#使用方法 "使用方法的直接链接") 在任意的静态项目下加入下面的 `f.yml` ,内容如下: ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: static package: include: - build ## 需要拷贝的目录 exclude: - package-lock.json ## 忽略 package-lock.json 文件 custom: customDomain: domainName: auto ## 自动生成域名 ``` 信息 有时候 package-lock.json 文件会造成部署包过大(将 dev 依赖打入)。 加入 dev 依赖 `@midwayjs/cli` 。 ``` { "devDependencies": { "@midwayjs/cli": "^1.2.36" ... }, "scripts": { "deploy": "npm run build && midway-bin deploy --skipBuild" } } ``` 执行 `npm run deploy`  即可。 或者使用不同的 npm 包加速。 ``` { "scripts": { "deploy": "npm run build && midway-bin deploy --skipBuild --npm=cnpm", ... } } ``` 信息 这里使用 --skipBuild 参数是为了跳过函数的构建。 `npm run build`  对接前端的构建命令。 默认情况下,会使用 `build`  目录作为托管根目录,访问 `/`  路由时,会自动查找 `/index.html` 。 比如: * / => /index.html * /api/ => /api/index.html ## 可选配置[​](#可选配置 "可选配置的直接链接") 除了默认配置外,我们可以对静态网站做一些额外的配置。 ### 修改托管目录[​](#修改托管目录 "修改托管目录的直接链接") ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: static config: rootDir: public ## 托管目录变为 public package: include: public ## 需要拷贝的目录,随着配置的托管目录为变 ``` ### 修改托管前缀[​](#修改托管前缀 "修改托管前缀的直接链接") 有时候部署需要统一的路由前缀,比如 `/api/*`  这样的形式。 ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: static config: prefix: /api package: include: build ``` 这样所有的 /\_ 都会变成 /api/\_。 ### 配置 404 页面[​](#配置-404-页面 "配置 404 页面的直接链接") 普通的路由是根据托管的目录结构和文件来的。如果访问到不存在的文件,则会返回 404。我们可以指定一个 404 页面。 ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: static config: notFoundUrl: /404.html package: include: build ``` ### rewrite 路由[​](#rewrite-路由 "rewrite 路由的直接链接") 有时候,我们希望将一些特定的路由,都访问到特定的文件上,比如将所有的路由请求,都转向到 `/index.html` ,然后让前端路由处理。 ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: static config: rewrite: /(.*): /index.html package: include: build ``` 此 rewrite 可以写多个,规则同 [koa-rewrite](https://github.com/koajs/rewrite)。 如果要排除某些目录,可以使用 `@not` 取反语法。 比如,排除 static 目录。 ``` deployType: type: static config: rootDir: build rewrite: '@not /static/(.*)': /index.html ``` ### 修改部署的函数名[​](#修改部署的函数名 "修改部署的函数名的直接链接") 可以通过 name 字段。 ``` service: my-static-demo ## 应用发布到云平台的名字 provider: name: aliyun ## 发布的云平台,aliyun,tencent 等 deployType: type: static name: app_idx ## 函数名 package: include: public ## 需要拷贝的目录,随着配置的托管目录为变 ``` --- # 聚合部署 Midway 针对 HTTP 场景,提供了一种聚合部署的方式,在开发时和传统 Web 应用类似,在部署时将多个路由部署在同一个函数容器中,可以节省冷启动时间,节省费用。 聚合部署模式特别适合用于传统中后台服务。 ## 创建代码[​](#创建代码 "创建代码的直接链接") 创建聚合部署的代码示例。 ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=faas-aggr my_midway_app # 如果是 npm v7 $ npm init midway -- --type=faas-aggr my_midway_app ``` 也可以执行 `npm init midway` ,选择 `faas-aggr` 脚手架。 信息 该脚手架针对 HTTP 的场景做了特殊处理,会将所有的 HTTP 接口部署为同一个函数(聚合部署)。 ## 目录结构[​](#目录结构 "目录结构的直接链接") 以下就是一个函数的最精简的结构,核心会包括一个 `f.yml` 标准化函数文件,以及 TypeScript 的项目结构。 ``` . ├── f.yml # 标准化 spec 文件 ├── package.json # 项目依赖 ├── src │ └── index.ts # 函数入口 └── tsconfig.json ``` 我们来简单了解一下文件内容。 * `f.yml`   函数定义文件 * `tsconfig.json` tsc 配置文件(没有 IDE 会报错) * `src` 函数源码目录 * `src/index.ts` 示例函数文件 ## 函数文件[​](#函数文件 "函�数文件的直接链接") 我们首先来看看函数文件,传统的函数是一个 `function` ,为了更符合 midway 体系,以及使用我们的依赖注入,这里将它变成了 Class。 和传统应用相同,我们依旧使用 `@Controller` 装饰器来开发聚合的 HTTP 函数。 如下代码,我们暴露了三个路由,在聚合部署模式下,会只部署成一个 HTTP 函数: ``` import { Inject, Provide, Controller, Get, Post } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() @Controller('/') export class APIService { @Inject() ctx: Context; @Get('/') async hello() { return 'Hello Midwayjs'; } @Get('/get') async get() { return this.ctx.query; } @Post('/post') async post() { return this.ctx.method; } } ``` ## 函数定义文件[​](#函数定义文件 "函数定义文件的直接链接") `f.yml` 是函数的定义文件,通过这个文件,在构建时生成不同平台所能认识的文件,示例中的文件内容如下。 ``` service: name: midway-faas-examples ## 函数组名,可以理解为应用名 provider: name: aliyun ## 发布的平台,这里是阿里云 aggregation: ## 对 HTTP 函数使用聚合模式部署 all: ## 部署的函数名 functionsPattern: ## 匹配的函数规则 - '*' ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 函数本地开发和传统 Web 相同,输入以下命令。 ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 `[http://127.0.0.1:7001](http://127.0.0.1:7001)` ,浏览器会打印出 `Hello midwayjs`   的信息。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1615045887650-73a90be7-1d49-4024-82c4-fd6b5192e75e.png#height=384\&id=JCH29\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=768\&originWidth=1268\&originalType=binary\&ratio=1\&size=85174\&status=done\&style=none\&width=634) ## 本地测试[​](#本地测试 "本地测试的直接链接") 使用和应用相同的测试方法来测试,针对 HTTP 函数,使用封装了 supertest 的 `createHttpRequest` 方法创建 HTTP 客户端。 唯一和应用不同的是,使用 `createFunctionApp` 方法创建函数应用(app)。 `createFunctionApp` 方法是 `createApp` 方法在函数场景下的定制(其中指定了函数的 `@midwayjs/serverless-app` 框架)。 信息 这里不直接使用 `@midwayjs/faas` 框架,而是使用 `@midwayjs/serverless-app`   框架,因为后者包含了网关模拟到函数调用的系列步骤。 HTTP 测试代码如下: ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/serverless-app'; import * as assert from 'assert'; describe('test/index.test.ts', () => { it('should get /', async () => { // create app const app = await createFunctionApp(); // make request const result = await createHttpRequest(app).get('/'); // use expect by jest expect(result.status).toBe(200); expect(result.text).toBe('Hello Midwayjs'); const result2 = await createHttpRequest(app).get('/get').query({ name: 123 }); // or use assert assert.deepStrictEqual(result2.status, 200); assert.deepStrictEqual(result2.body.name, '123'); // close app await close(app); }); }); ``` ## 和纯函数的区别[​](#和纯函数的区别 "和纯函数的区别的直接链接") 普通的函数,会将单个的函数注册到特定的路由上。客户端请求的流量,会分别打到不同的函数实例上,这样的好处是每个接口对应的函数实例数量可能都是不同的,调用多的接口,实例就多,调用少的接口就会少。 坏处就是,如果调用量较少,函数的冷启动概率就大,调用的时间会明显变大,由于每个函数都会有开销,资源没有复用,最终的收费也会变多。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618156727582-20f0df7c-9f91-430b-87a6-1796b1ee35e1.png#height=494\&id=Rdl50\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=988\&originWidth=1912\&originalType=binary\&ratio=1\&size=85218\&status=done\&style=none\&width=956) 而聚合部署,会将所有的路由都注册到 `/*`  路由上,由框架内部的路由代码进行分发,所有的函数共享同一个容器,任意的请求都会让这个容器保活,使得冷启动的可能性大大减少。同时,由于代码是复用的,容器的复用率大大增加,比较适合于中后台这类请求均衡且接口的调用量相对均衡的场景。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618156735858-4ddb1d49-357d-4cec-8201-b2e49bde4b5f.png#height=456\&id=I9ZeD\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=912\&originWidth=1770\&originalType=binary\&ratio=1\&size=59657\&status=done\&style=none\&width=885) ## 函数名规则[​](#函数名规则 "函数名规则的直接链接") 使用聚合模式部署的函数,我们一般使用 `@Controller`  装饰器或者一体化方式进行开发,和传统 Web 开发、测试保持一致。 在构建时,我们会生成 `f.yml`  中的 `functions`  字段,一般情况下用户不需要关心函数名,接口等信息。 在使用 `@Controller`  装饰器的情况下,生成的函数名规则为 `providerId_methodName` ,即依赖注入的 key 和方法名的组合。 比如: ``` @Provide('userService') // <--- 取的是这个名字,如果不填,默认是类名的驼峰形式 @Controller('/api') export class UserService { @Get('/get/:id') async getUser(@Query() name) {} @Post('/create') async createUser(@Query() name) {} } ``` 构建时会自动生成 `userService_getUser`  和 `userService_createUser`  两个函数并做内部路由处理。 下面是生成的 YAML 伪代码(实际由于是聚合部署,变为内部路由,并不会创建这段代码)。 ``` functions: userService_getUser: events: - http: method: get path: /get/[:id] userService_createUser: events: - http: method: post path: /create ``` --- # 函数上下文 ## Event 转换[​](#event-转换 "Event 转换的直接链接") Midway Serverless 针对不同平台的情况,进行了入参包裹,同时,在函数使用了 apigw(API 网关)和 http (阿里云)触发器的情况下,对入参(event)做了特殊处理,为了简化和统一写法,将 event 统一规则化成了类似 koa 写法的代码。 普通触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/decorator'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler(event) { return 'hello world' } } ``` HTTP 、API 网关触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/decorator'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler() { // 下面两种写法相同 // this.ctx.body = 'hello world'; return 'hello world'; } } ``` ## Context[​](#context "Context的直接链接") 每次函数调用,都会创建一个全新的 ctx(函数上下文)。针对 ctx 上的属性或者方法,我们提供 ts 定义。 信息 在 Serverless v1 时代,我们的定义叫 FaaSContext,在 v2 我们将定义和应用做了统一,更为一致。 ### ctx.logger[​](#ctxlogger "ctx.logger的直接链接") * return `ILogger` 运行时传递下来的每次请求的日志对象,默认为 console。 ``` ctx.logger.info('hello'); ctx.logger.warn('hello'); ctx.logger.error('hello'); ``` ### ctx.env[​](#ctxenv "ctx.env的直接链接") * return `string` 当前启动的环境,即 NODE\_ENV 或者 MIDWAY\_SERVER\_ENV 的值,默认为 prod。 ``` ctx.env; // 默认 prod ``` ### ctx.requestContext[​](#ctxrequestcontext "ctx.requestContext的直接链接") * return `MidwayRequestContainer` midway faas 的 IoC 请求作用域容器,用于获取其他 IoC 容器中的对象实例。 ``` const userService = await ctx.requestContext.getAsync('userService'); ``` ## FaaSHTTPContext[​](#faashttpcontext "FaaSHTTPContext的直接链接") `Context`  定义继承于 `FaaSHTTPContext` ,前者保留了后者,大部分场景下可以直接使用前者,后者是在   apigw(API 网关)和 http (阿里云)触发器下才有的能力。 对于普通用户,直接使用 `Context`  定义即可。 ``` import { Context } from '@midwayjs/faas'; @Inject() ctx: Context; ``` 在 ctx 对象中,我们提供了一些和编写传统 Koa Web 应用程序类似的 API。这样的好处是减少用户的认知成本,并且,在一定程度上,兼容原有传统代码,兼容社区 middleware 成为了可能。 我们提供了一些和传统类似的 API,支持常用的能力,**在不同的平台可能不一定完全相同**,我们会在特定 API 中指出。 ### ctx.request[​](#ctxrequest "ctx.request的直接链接") * return `FaaSHTTPRequest` FaaS 模拟的 HTTP Request 对象。 ### ctx.response[​](#ctxresponse "ctx.response的直接链接") * return `FaaSHTTPResponse` FaaS 模拟的 HTTP Response 对象。 ### ctx.params[​](#ctxparams "ctx.params的直接链接") 代理自 `request.pathParameters` ,在 http 触发器(阿里云)和 API 网关触发器下可用。 ``` // /api/user/[id] /api/user/faas ctx.params.id; // faas ``` ### ctx.set[​](#ctxset "ctx.set的直接链接") 设置响应头,此方法代理自 `response.setHeader` 。 ``` ctx.set('X-FaaS-Duration', 2100); ``` ### ctx.status[​](#ctxstatus "ctx.status的直接链接") 设置返回状态码,此属性代理自 `response.statusCode` 。 ``` ctx.status = 404; ``` ### ### Request aliases[​](#request-aliases "Request aliases的直接链接") 以下列出的属性是从  [Request](#k6AZp)  对象代理过来 * `ctx.headers` * `ctx.method` * `ctx.url` * `ctx.path` * `ctx.ip` * `ctx.query` * `ctx.get()` ### Response aliases[​](#response-aliases "Response aliases的直接链接") 以下列出的属性是从 [Response](#kfTOD) 对象代理过来 * `ctx.body=` * `ctx.status=` alias to `response.statusCode` * `ctx.type=` * `ctx.set()` alias to `response.setHeader` ## [​](#-1 "-1的直接链接") ## FaaSHTTPRequest[​](#faashttprequest "FaaSHTTPRequest的直接链接") 此对象是通过将函数的 `event`  和 `context`  入参进行转换得来。 ### request.headers[​](#requestheaders "request.headers的直接链接") 包含所有请求头的对象,键值对存储。 ### request.ip[​](#requestip "request.ip的直接链接") 获取客户端请求 ip。 信息 在阿里云 FC 上,只有 HTTP 触发器能获取到值,api 网关暂时无法获取。 ### request.url[​](#requesturl "request.url的直接链接") 客户端请求完整 url。 ### request.path[​](#requestpath "request.path的直接链接") 客户端请求 path。 ### request.method[​](#requestmethod "request.method的直接链接") 请求的 method。 ### request.body[​](#requestbody "request.body的直接链接") POST 请求的 body,已经解析为 JSON。 ## FaaSHTTPResponse[​](#faashttpresponse "FaaSHTTPResponse的直接链接") 此对象是通过将函数的 `event` 和 `context` 入参进行转换得来。 ### response.setHeader[​](#responsesetheader "response.setHeader的直接链接") 设置响应头。 ### response.statusCode[​](#responsestatuscode "response.statusCode的直接链接") 设置返回状态码。 ### response.body[​](#responsebody "response.body的直接链接") 设置返回响应体内容, `string`  或者 `buffer` 。 --- # 开发函数 ## 初始化代码[​](#初始化代码 "初始化代码的直接链接") 让我们来开发第一个纯 HTTP 函数,来尝试将它部署到云环境(不用担心,函数现在都有免费额度,一般情况下不花钱)。 ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=faas my_midway_app # 如果是 npm v7 $ npm init midway -- --type=faas my_midway_app ``` 也可以执行 `npm init midway` ,选择 `faas`  脚手架。 ## 目录结构[​](#目录结构 "目录结构的直接链接") 以下就是一个函数的最精简的结构,核心会包括一个 `f.yml` 标准化函数文件,以及 TypeScript 的项目结构。 ``` . ├── f.yml # 标准化 spec 文件 ├── package.json # 项目依赖 ├── src │ └── function │ └── hello.ts ## 函数文件 └── tsconfig.json ``` 我们来简单了解一下文件内容。 * `f.yml`   函数定义文件 * `tsconfig.json` TypeScript 配置文件 * `src` 函数源码目录 * `src/function/hello.ts` 示例函数文件 我们将函数放在 `function`目录下,是为了更好的和其他类型的代码分开。 ## 函数文件[​](#函数文件 "函数文件的直接链接") 我们首先来看看函数文件,传统的函数是一个 `function` ,为了更符合 midway 体系,以及使用我们的依赖注入,这里将它变成了 Class。 通过 `@ServerlessTrigger`  装饰器,我们将方法标注为一个 HTTP 接口,并且标示 `path`  和 `method`  属性。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType, Query } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloHTTPService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` 除了触发器外,我们还可以使用 `@ServerlessFunction` 装饰器描述函数层面的元信息,比如函数名,并发度等等。 这样,当我们在一个函数上,使用多个触发器时,就可以这样设置。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType, Query } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloServerlessService { @Inject() ctx: Context; // 一个函数多个触发器 @ServerlessFunction({ functionName: 'abcde', }) @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'every', value: '5m', }) @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'every', value: '10m', }) async handleTimerEvent() { // TODO } } ``` 警告 注意,有些平台无法将不同类型的触发器放在同一个函数中,比如阿里云规定,HTTP 触发器和其他触发器不能同时在一个函数生效。 ## 函数定义文件[​](#函数定义文件 "函数定义文件的直接链接") `f.yml` 是函数的定义文件,通过这个文件,在构建时生成不同平台所能认识的文件,示例中的文件内容如下。 ``` service: name: midway-faas-examples ## 函数组名,可以理解为应用名 provider: name: aliyun ## 发布的平台,这里是阿里云 custom: customDomain: domainName: auto ## 由于发布 HTTP 服务,域名这里使用自动生成,后续可以单独绑定 ``` ### ## 触发器装饰器参数[​](#触发器装饰器参数 "触发器装饰器参数的直接链接") `@ServerlessTrigger` 装饰器用于定义不同的触发器,它的参数为每个触发器信息,以及通用触发器参数。 触发器和 [f.yml 的定义](/docs/serverless_yml#YoMeC)保持一致,当前的定义请参考每个触发器的 [interface](https://github.com/midwayjs/midway/blob/2.x/packages/decorator/src/interface.ts#L141)。 比如触发器的名称修改为 abc。 ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { name: 'abc' type: 'every', value: '5m', }) ``` ## 函数装饰器参数[​](#函数装饰器参数 "函数装饰器参数的直接链接") `@ServerlessFunction` 装饰器用于定义函数,通过它可以修改函数名。 函数触发器和 [f.yml 的定义](/docs/serverless_yml#f1568472) 保持一致,当前的定义请参考每个触发器的 [interface](https://github.com/midwayjs/midway/blob/2.x/packages/decorator/src/interface.ts#L141)。 比如: ``` @ServerlessFunction({ functionName: 'abcde', initTimeout: 3, // 初始化超时,只对阿里云 fc 有效,默认 3s timeout: 3 // 函数执行超时时间,默认 3s }) ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 函数本地开发和传统 Web 相同,输入以下命令。 ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 ,浏览器会打印出 `Hello midwayjs`   的信息。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1615045887650-73a90be7-1d49-4024-82c4-fd6b5192e75e.png#height=384\&id=X8Jmz\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=768\&originWidth=1268\&originalType=binary\&ratio=1\&size=85174\&status=done\&style=none\&width=634) ## 部署函数[​](#部署函数 "部署函数的直接链接") 部署函数,直接使用发布命令即可打包并部署函数: ``` $ npm run deploy ``` 信息 如果输错了信息,可以重新执行 `npx midway-bin deploy --resetConfig` 修改。 这里我们用阿里云 FC 平台来演示,如需部署到腾讯云,请参考 [腾讯云部署](/docs/2.0.0/serverless/deploy_to_tencent.md)。 阿里云部署首次需要配置 `accountId`、`accountKey`、`accountSecret` ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654967-11e1bcbd-5a56-4239-99e1-5a1472ad49fd.png#height=514\&id=cd07s\&margin=%5Bobject%20Object%5D\&originHeight=514\&originWidth=1152\&originalType=binary\&ratio=1\&size=0\&status=done\&style=none\&width=1152) 相关配置获取,可参照下方图片: ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654949-9c14958c-3aff-403a-b89b-d03a3a95cd18.png#height=696\&id=XCMN7\&margin=%5Bobject%20Object%5D\&originHeight=696\&originWidth=1832\&originalType=binary\&ratio=1\&size=0\&status=done\&style=none\&width=1832) 点击此处跳转阿里云[安全设置页](https://account.console.aliyun.com/#/secure)。 *** ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1585718654950-19a811c5-2cf3-4843-a619-cfd744430fae.png#height=184\&id=H5HaQ\&margin=%5Bobject%20Object%5D\&originHeight=592\&originWidth=2406\&originalType=binary\&ratio=1\&size=0\&status=done\&style=none\&width=746) 点击跳转阿里云个人 [AccessKey 页面](https://usercenter.console.aliyun.com/#/manage/ak)。 整个部署效果如下: ![](https://cdn.nlark.com/yuque/0/2021/svg/501408/1618722302423-d7d159b3-45b0-4a93-a2b1-daf50f46bc9f.svg#clientId=ude874b22-3d94-4\&from=ui\&id=w8IDi\&margin=%5Bobject%20Object%5D\&originHeight=1015\&originWidth=1620\&originalType=binary\&ratio=1\&size=458083\&status=done\&style=none\&taskId=u53dbfdb6-ec4e-4b4e-866d-ab578d3839a) 发布完后,从控制台获取当前的 url 即可访问。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618722353090-bf9e0061-ea62-46a2-a77e-57236a4e4024.png#clientId=ude874b22-3d94-4\&from=paste\&height=361\&id=u7afbff35\&margin=%5Bobject%20Object%5D\&originHeight=722\&originWidth=2084\&originalType=binary\&ratio=1\&size=156355\&status=done\&style=none\&taskId=u39af502c-85b3-4eeb-b387-a5d70448c89\&width=1042) 由于开启了自动域名,阿里云会免费增送一个临时域名用开发和调试,后续也可以自己绑定新域名。 --- # 部署环境 在 Serverless 场景,由于环境和传统的容器不同(平台提供,无法修改),我们在启动时,使用传统的命令透传环境变量,函数是无法正确的读取到的。 比如,下面的命令,只能对本地生效,无法对服务器生效。 ``` $ NODE_ENV midway-bin deploy // 错误写法,只在本地生效 ``` 我们需要特殊的方式来让函数容器也能接收到环境。 ## 发布环境变量[​](#发布环境变量 "发布环境变量的直接链接") 为了和普通的环境变量区分,部署到平台的环境变量使用 `UDEV_` (User Defined Environment Variable)前缀,并且**会在发布后写入到发布的 yml 文件对应的 environment 字段中。** 例如: ``` $ UDEV_NODE_ENV=prod midway-bin deploy ``` 这个时候在平台将会接收到名为 `NODE_ENV` ,值为 `prod`  的环境变量。 ## YML 变量填充[​](#yml-变量填充 "YML 变量填充的直接链接") 在 yml 中可以使用填充一些变量,我们提供了一个默认填充关键字 `env` ,通过它可以对任意的 yml 变量赋值。比如: ``` provider: runtime: ${env.RUNTIME} ``` 那么,如果 `midway-bin deploy` 时增加的环境变量为 `RUNTIME=nodejs10 midway-bin deploy` ,则会被填充为: ``` provider: runtime: nodejs10 ``` ## 错误堆栈输出[​](#错误堆栈输出 "错误堆栈输出的直接链接") 当函数报错时,Midway 会自动在函数日志中输出错误信息,包括堆栈等。但是只会在 `local` 和 `development` 环境将报错堆栈在响应(Response)中输出。 如果需要在其他环境的返回值中看到错误堆栈,可以通过配置下面的环境变量。 ``` process.env.SERVERLESS_OUTPUT_ERROR_STACK = 'true'; ``` ## 拷贝额外资源[​](#拷贝额外资源 "拷贝额外资源的直接链接") 默认构建工具只会拷贝 package.json、构建后的代码和依赖,如果需要拷贝其他目录,比如一些静态资源,需要在 `f.yml` 中配置。 比如: ``` package: # 打包配置 include: # 打包包含文件列表,默认为 package.json、构建后的代码和依赖 - resource - public exclude: # 打包剔除文件列表 - test ``` --- # 默认错误行为 ## 错误值处理[​](#错误值处理 "错误值处理的直接链接") 为了保证安全性,Midway 针对 Serverless 场景下返回的错误做了一些特殊处理。 在函数业务抛出错误的情况下,框架侧会捕获所有的错误,并返回 “Internal Server Error” 的错误。 比如我们的函数返回一个错误: ``` @ServerlessTrigger(//...) async invoke() { throw new Error('abc'); } ``` 不管是 HTTP 还是非 HTTP 触发器,框架部分都有相应的处理。 在 **非线上环境**,比如 `NODE_ENV=local` 环境,框架会将整个错误通过网关透出。 比如(完整的错误堆栈): ``` 2021-07-02T05:57:08.553Z 19be4d99-c9cb-4c4c-aac2-9330d31b4408 [error] Error: abc at hello (/code/dist/function/index.js:17:15) at invokeHandler (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:174:56) at processTicksAndRejections (internal/process/task_queues.js:97:5) at (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:117:40) at cors (/code/node_modules/_@koa_cors@3.1.0@@koa/cors/index.js:98:16) at invokeHandlerWrapper (/code/node_modules/_@midwayjs_runtime-engine@2.11.1@@midwayjs/runtime-engine/dist/lightRuntime.js:18:28) { } ``` 在 线上环境,框架将直接返回 **“Internal Server Error”** ,但是日志中是完整的堆栈。 如图所示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1625205528496-96f7d2b8-d728-4f04-82f4-f2617e00720b.png#clientId=uf90c84ad-5af6-4\&from=paste\&height=184\&id=u9c48573b\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=184\&originWidth=533\&originalType=binary\&ratio=1\&size=7090\&status=done\&style=none\&taskId=u9ff827c3-41a4-4b19-bedb-83ee598cc4e\&width=533) ## 调整错误返回[​](#调整错误返回 "调整错误返回的直接链接") 以上为默认行为,在特殊环境下,如果需要显示出错误,可以使用环境变量开启强制输出。 ``` process.env.SERVERLESS_OUTPUT_ERROR_STACK = 'true'; ``` --- # 介绍 ## Midway Serverless 能做什么[​](#midway-serverless-能做什么 "Midway Serverless 能做什么的直接链接") Midway Serverless 是用于构建 Node.js 云函数的 Serverless 框架。帮助您在云原生时代大幅降低维护成本,更专注于产品研发。 * \*\*跨云厂商:\*\*一份代码可在多个云平台间快速部署,不用担心你的产品会被云厂商所绑定。 * \*\*云端一体化:\*\*提供了多套和社区前端 React、Vue 等融合一体化开发的方案。 * \*\*代码复用:\*\*通过框架的依赖注入能力,让每一部分逻辑单元都天然可复用,可以快速方便地组合以生成复杂的应用。 * \*\*传统迁移:\*\*通过框架的运行时扩展能力,让 Egg.js 、Koa、Express.js 等传统应用无缝迁移至各云厂商的云函数 你可以使用  Midway 来构建你的**全栈应用**,也可以发布的**函数服务** ,Restful 接口等,也可以加上前端(react,vue)代码**构建中后台项目**,也可以使用 Midway 提供的方案**迁移传统**的 Egg/Koa/Express 应用上弹性容器。 ## Midway Serverless 和 Midway 的关系[​](#midway-serverless-和-midway-的关系 "Midway Serverless 和 Midway 的关系的直接链接") Midway Serverless 是 Midway 产出的一套面向 Serverless 云平台的开发方案。其内容主要包括函数框架 `@midwayjs/faas` ,以及一系列跟平台配套的工具链,启动器等。 在 Midway Serverless 2.0 之后,Midway Serverless 和 Midway 的能力复用,有着相同的 CLI 工具链,编译器,装饰器等等。 当前,Midway Serverless 主要面向的是 函数(FaaS)场景。 ## 函数(FaaS)能做什么[​](#函数faas能做什么 "函数(FaaS)能做什么的直接链接") 很多人对函数还不是很清楚或者不了解他能做什么。当前的函数,可以当做一个小容器,原来我们要写一个完整的应用来承载能力,现在只需要写中间的逻辑部分,以及考虑输入和输出的数据。 通过绑定平台的触发器,可以承载例如 HTTP,Socket 等流量。 通过平台提供的 BaaS SDK,可以对外调用数据库,Redis 等服务。 通过函数,能提供传统的 HTTP API 服务,结合现有的前端框架(react,vue 等)渲染出一个个美丽的页面,也可以做为一个独立的数据模块,等待被调用(触发),比如常见的文件上传变更,解压等等,也能作为定时任务的逻辑部分,到了指定的时间或者时间间隔被执行。 随着时间的更替,平台的迭代,函数的能力会越来越强,而用户的上手成本,服务器成本则会越来越低。 ## 函数不能做什么[​](#函数不能做什么 "函数不能做什么的直接链接") 函数的架构决定了,有些需求是无法支持的,另外,函数和应用在能力上还是有一定的区别。 函数不适用: * 执行时间超过函数配置下限制的(最好不超过 5s) * 有状态,在本地存储数据的 * 长链接,比如 ws 等 * 后台任务,有大数据执行的 * 依赖多进程通信的 * 大文件上传(比如网关限制的 2M 以上) * 自定义环境的,比如 nginx 配置,c++ 库(c++ addon 动态链接库等),python 版本依赖的 * 大量服务端渲染(服务端渲染需要缓存,不是很适合函数场景) 以上的**部分**场景,可以使用原应用模式来开发,然后用 [现有的迁移方案](/docs/2.0.0/serverless/migrate_egg.md) 来接入 serverless 弹性容器。 ## 术语描述[​](#术语描述 "术语描述的直接链接") ### 函数[​](#函数 "函数的直接链接") 逻辑意义上的一段代码片段,通过常见的入口文件包裹起来执行。函数是单一链路,并且无状态的,现在很多人认为,Serverless = FaaS + BaaS ,而 FaaS 则是无状态的函数,BaaS 解决带状态的服务。 ### 函数组[​](#函数组 "函数组的直接链接") 多个函数聚合到一起的逻辑分组名,对应原有的应用概念。 ### 触发器[​](#触发器 "触发器的直接链接") 触发器,也叫 Event(事件),Trigger 等,特指触发函数的方式。 与传统的开发理念不同,函数不需要自己启动一个服务去监听数据,而是通过绑定一个(或者多个)触发器,数据是通过类似事件触发的机制来调用到函数。 ### 函数运行时[​](#函数运行时 "函数运行时的直接链接") 英文叫 Runtime,具体指执行函数的环境,具体在各个平台可能是镜像,也可能是 Node.js 代码包,比如常见的社区运行时有 kubeless 等,该代码包会实现对接平台的各种接口,处理异常,转发日志等能力。 ### 发布平台[​](#发布平台 "发布平台的直接链接") 函数最后承载的平台,现在社区最常见的有阿里云 FC 、腾讯云 SCF,AWS 的 Lambda 等等。 ### Layer[​](#layer "Layer的直接链接") 由于运行时的代码比较简单,且需要保证稳定性无法经常性的更新,Layer 被设计出来扩展运行时的能力,并且可以精简本地的函数代码量(有一些平台限制了上传压缩包的大小)。 --- # Serverless 触发器 POST 情况差异 ## 阿里云 API 网关[​](#阿里云-api-网关 "阿里云 API 网关的直接链接") 阿里云 API 网关支持不同类型的的 POST 请求。 ### 入参透传的 POST[​](#入参透传的-post "入参透传的 POST的直接链接") 网关配置如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593175823751-f9b305fc-ddeb-4b04-ba13-481a616be260.png#height=536\&id=R8Ber\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1072\&originWidth=1560\&originalType=binary\&size=138055\&status=done\&style=none\&width=780) 网关透传的 event 特征为有 `body` 字段以及 `isBase64Encoded` 为 true,解码比较容易,直接解 base64 即可。 信息 透传了之后,即为所有的结果交给函数处理。 #### 示例一 (text/html)[​](#示例一-texthtml "示例一 (text/html)的直接链接") 下面的 event,是一个最简单的透传示例,因为其中的 `content-type`  为 `text/html` ,所以 body 传递过来 base64 解码的结果也同样是字符串。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "x-ca-dashboard-action": "DEBUG", "x-ca-dashboard-uid": "125087", "x-ca-stage": "RELEASE", "x-ca-dashboard-role": "USER", "user-agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "accept-encoding": "gzip,deflate", "content-md5": "Kry+hjKjc2lvIrwoJqdY9Q==", "content-type": "text/html; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // '{"c":"b"}' => string ``` #### 示例二(application/json)[​](#示例二applicationjson "示例二(application/json)的直接链接") 使用 `content-type`  为 `application/json` ,这样框架认为是一个 JSON,会自动被 JSON.parse。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "125087", "X-Ca-Stage": "RELEASE", "X-Ca-Dashboard-Role": "USER", "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "Accept-Encoding": "gzip,deflate", "Content-MD5": "Kry+hjKjc2lvIrwoJqdY9Q==", "Content-Type": "application/json; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` #### 示例三 (application/x-www-form-urlencoded)[​](#示例三-applicationx-www-form-urlencoded "示例三 (application/x-www-form-urlencoded)的直接链接") 使用 `content-type`  为 `application/x-www-form-urlencoded` ,这个时候网关不会以 base64 格式透传,这也是前端原生表单的默认提交类型。 信息 在 API 网关侧测试,保持“入参透传”下,似乎没有效果,于是我换到了 Postman 进行测试。 Postman 模拟请求如下: ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593188653464-2a5659de-40ad-4611-ba86-f5754c7d4425.png#height=684\&id=hkVhi\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1368\&originWidth=1316\&originalType=binary\&size=178770\&status=done\&style=none\&width=658) 函数拿到的 event 值如下。 ``` { "body": "{\"c\":\"b\"}", "headers": { "accept": "*/*", "cache-control": "no-cache", "user-agent": "PostmanRuntime/7.24.1", "postman-token": "feb51b11-9103-463a-92ff-73076d37b683", "accept-encoding": "gzip, deflate, br", "content-type": "application/x-www-form-urlencoded" }, "httpMethod": "POST", "isBase64Encoded": false, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` ### 入参映射的 POST[​](#入参映射的-post "入参映射的 POST的直接链接") 网关配置选择入参映射之后,body 数据类型有两种选择。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593186831907-7975c65c-aee5-4f96-9ae4-ffaeee66c7dd.png#height=179\&id=KonHW\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=358\&originWidth=1112\&originalType=binary\&size=117003\&status=done\&style=none\&width=556) 一旦选了映射,整个函数拿到的 Headers 中就 **没有了 content-type**。 这个时候,网关的返回 event 为 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "111111", "X-Ca-Dashboard-Role": "USER" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数由于默认没有拿到 header 头,只会对 base64 的结果做处理,结果为字符串。 ``` ctx.request.body; // '{"c":"b"}' => string ``` ## 阿里云 HTTP 触发器[​](#阿里云-http-触发器 "阿里云 HTTP 触发器的直接链接") 函数提供的 HTTP 触发器(和网关不同)。 ### 普通 POST(application/json)[​](#普通-postapplicationjson "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 字符串格式。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321679770-a7609684-ec5e-4f93-99f2-d346ed79c1fa.png#height=426\&id=ny1FQ\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=426\&originWidth=1154\&originalType=binary\&size=33111\&status=done\&style=none\&width=1154) ``` ctx.request.body; // "bbb" => string ``` JSON 格式 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321730423-f9b2860f-7902-4f3a-81cf-bfbcfd4ee57f.png#height=431\&id=Vz8q7\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=431\&originWidth=1074\&originalType=binary\&size=34435\&status=done\&style=none\&width=1074) ``` ctx.request.body; // {"b":"c"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded "表单(application/x-www-form-urlencoded)的直接链接") ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321823455-23ec3970-35a5-4746-8995-d9146eaa4ab0.png#height=387\&id=qxW8I\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=387\&originWidth=1310\&originalType=binary\&size=36914\&status=done\&style=none\&width=1310) ``` ctx.request.body; // {"b":"c"} => object ``` ### 文件上传(Binary)[​](#文件上传binary "文件上传(Binary)的直接链接") 暂未支持 ## 腾讯云网关[​](#腾讯云网关 "腾讯云网关的直接链接") 腾讯云提供单独网关。 ### 普通 POST(application/json)[​](#普通-postapplicationjson-1 "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 使用 Postman 请求。 字符串格式,正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323223487-c4e5f365-b500-4a2d-85e3-45bd4aba4653.png#height=1094\&id=BcYdP\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1094\&originWidth=1486\&originalType=binary\&size=79437\&status=done\&style=none\&width=1486) ``` ctx.request.body; // "bbb" => string ``` JSON 格式,能正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323187488-e7b4e32e-4195-404d-b309-ba436c3f5f8e.png#height=1072\&id=Wf7Tf\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1072\&originWidth=1312\&originalType=binary\&size=76807\&status=done\&style=none\&width=1312) ``` ctx.request.body; // {"c":"b"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded-1 "表单(application/x-www-form-urlencoded)的直接链接") 正常解析为 JSON。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323279728-983fd844-f37d-419b-90f3-f96d1ee8236d.png#height=686\&id=nOyZ8\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=686\&originWidth=1556\&originalType=binary\&size=75708\&status=done\&style=none\&width=1556) ``` ctx.request.body; // {"c":"b"} => object ``` --- # 测试函数 ## HTTP 类的函数[​](#http-类的函数 "HTTP 类的函数的直接链接") 该方法适用于所有的类 HTTP 触发器的函数,包括 `HTTP` 和 `API_GATEWAY`。 使用和应用相同的测试方法来测试,针对 HTTP 函数,使用封装了 supertest 的 `createHttpRequest` 方法创建 HTTP 客户端。 唯一和应用不同的是,使用 `createFunctionApp` 方法创建函数应用(app)。 `createFunctionApp` 方法是 `createApp` 方法在函数场景下的定制(其中指定了函数的 `@midwayjs/serverless-app` 框架)。 信息 这里不直接使用 `@midwayjs/faas` 框架,而是使用 `@midwayjs/serverless-app`  框架,因为后者包含了网关模拟到函数调用的系列步骤。 HTTP 测试代码如下: ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; describe('test/hello_aliyun.test.ts', () => { let app: Application; beforeAll(async () => { // create app app = await createFunctionApp(); }); afterAll(async () => { await close(app); }); it('should get result from api gateway trigger', async () => { const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); }); }); ``` ## 普通触发器[​](#普通触发器 "普通触发器的直接链接") 除了类 HTTP 触发器之外,我们还有其他比如定时器、对象存储等函数触发器,这些触发器由于和网关关系密切,不能使用 HTTP 行为来测试,而是使用传统的方法调用来做。 通过 `createFunctionApp` 方法创建函数 app,通过 `getServerlessInstance` 方法获取类实例,然后通过实例的方法直接调用,传入参数进行测试。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // 创建函数 app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), // 这里传入了 aliyun 特有的初始化上下文数据 }); // 拿到服务类 instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from event trigger', async () => { // 调用函数方法,传入参数 expect(await instance.handleEvent('hello world')).toEqual('hello world'); }); }); ``` ## 平台工具类[​](#平台工具类 "平台工具类的直接链接") Midway 提供了平台工具类,用于快速创建测试数据。 现有的平台工具类包括: | @midwayjs/serverless-fc-trigger | 阿里云触发器模拟 | | -------------------------------- | ---------------- | | @midwayjs/serverless-sfc-trigger | 腾讯云触发器模拟 | 这些工具类中,提供了一些快速创建初始化数据的方法。 比如,在阿里云函数中,提供了快速创建初始化上下文的方法,我们可以在初始化函数 app 时传入。 ``` import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; describe('test/hello_aliyun.test.ts', () => { // ... beforeAll(async () => { // 创建函数 app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), // 这里传入了 aliyun 特有的初始化上下文数据 }); // ... }); }); ``` 所有的工具方法都支持修改数据,可以通过参数传入,会和默认的数据做合并。比如要修改初始化上下文数据。 ``` import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; describe('test/hello_aliyun.test.ts', () => { // ... beforeAll(async () => { // 创建函数 app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext({ accountId: 'xxxxxxx', // 可以按照结构,调整数据 }), }); // ... }); }); ``` 比如创建一个定时任务触发器的数据。 ``` import { createTimerEvent } from '@midwayjs/serverless-fc-trigger'; it('should get result from timer trigger', async () => { // 拿到服务类 const instance = await app.getServerlessInstance(HelloAliyunService); // 调用函数方法,传入参数 await instance.handleTimer(createTimerEvent()); }); ``` 这里的 `createTimerEvent` 方法,会返回一个和平台相符的数据结构。 ``` { triggerTime: new Date().toJSON(), triggerName: 'timer', payload: '', } ``` 同样的,我们可以传递参数进行覆盖。 ``` // 调用函数方法,传入参数 await instance.handleTimer(createTimerEvent({ // ... })); ``` 具体的函数工具方法,可以查阅不同的平台触发器测试。 --- # Serverless 函数部署为应用 Midway Serverless 在 v1.0 版本已经支持部署到各个 Serverless 云平台,例如阿里云 FC、腾讯云 SCF 等。从 v2.0 版本开始支持已有的 Serverless 函数以应用模式部署在你的私有服务器上。 ## 前提[​](#前提 "前提的直接链接") `@midwayjs/faas`  版本需要大于 `2.8.7` 。 ## 使用[​](#使用 "使用的直接链接") #### ### 1、安装应用部署依赖[​](#1安装应用部署依赖 "1、安装应用部署依赖的直接链接") 主要是 `@midwayjs/bootstrap`  和 `@midwayjs/serverless-app`  包。 ``` $ npm i @midwayjs/bootstrap @midwayjs/serverless-app --save ``` `@midwayjs/bootstrap`  用于启动 Midway 上层框架, `@midwayjs/serverless-app`  用于将原有的函数代码包裹成实际应用运行,它也是 Midway 的上层 Framework 之一。 ### 2、添加启动文件[​](#2添加启动文件 "2、添加启动文件的直接链接") 在项目根目录添加 `bootstrap.js`  文件,代码如下: ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); const { Framework } = require('@midwayjs/serverless-app'); const app = new Framework().configure({ port: 7001, }); Bootstrap.load(app).run(); ``` ### 3、部署应用[​](#3部署应用 "3、部署应用的直接链接") 可以在 `package.json`  中增加 `start`  命令方便启动。 ``` { "scripts": { "start": "NODE_ENV=production node bootstrap.js" } } ``` 然后执行 `npm run start`  即可。也 可以直接使用 `pm2`  等工具执行该命令进行启动。 启动后访问 `http://127.0.0.1:7001` 。 --- # 从 Serverless v1 迁移到 v2 本文章介绍如何从 Serverless v1.0 迁移到 Serverless v2.0。 Midway Serverless 2.0 的升级主要体现在架构和包的变化上,功能本身变化不大。 ## 升级方式[​](#升级方式 "升级方式的直接链接") ### 1、全局 CLI 的升级[​](#1全局-cli-的升级 "1、全局 CLI 的升级的直接链接") 移除原有的 `@midwayjs/faas-cli`  包,不再使用 `f`  全局命令,改为项目下的包和命令。 ``` $ npm uninstall @midwayjs/faas-cli -g ``` ### 2、项目包版本的升级[​](#2项目包版本的升级 "2、项目包版本的升级的直接链接") 依赖包升级。 ``` "dependencies": { "@midwayjs/faas": "^2.0.0" }, ``` 开发依赖包升级(向传统应用靠拢)。 ``` "devDependencies": { "@midwayjs/cli": "^1.2.45", "@midwayjs/mock": "^2.8.7", "@midwayjs/serverless-app": "^2.8.7", "@midwayjs/fcli-plugin-fc": "^1.2.45", "@types/jest": "^26.0.10", "@types/node": "^14", "typescript": "^4.0.0" } ``` * 1、将原有的 mocha 测试换成了 jest,所以 `@types/mocha`  变为了 `@types/jest` 。 * 2、 `@midwayjs/serverless-invoke`  被移除,由于采用了应用的测试方式,不再需要。 * 3、平台模块区分, `@midwayjs/fcli-plugin-fc`  该模块是用于阿里云 FC 环境的工具包,如果要发布到腾讯云 SCF 环境,请使用 `midwayjs/fcli-plugin-scf` 。 ### 3、脚本的升级[​](#3脚本的升级 "3、脚本的升级的直接链接") 向应用靠拢,提供了 `dev` 、 `test` 、 `deploy`  命令。 ``` "scripts": { "dev": "midway-bin dev --ts", "test": "midway-bin test --ts", "deploy": "midway-bin deploy" }, ``` * 原有的 `build` 命令被移除,因为部署时 deploy 会自动 build * 原有的 `f test`  命令将和开发应用相同,替换为 `midway-bin test --ts` * 原有的 `f dev`  和 debug,将和开发应用相同,统一使用 `midway-bin dev --ts` ,调试方式也相同 ### 4、包定义变更[​](#4包定义变更 "4、包定义变更的直接链接") 常见定义变更。 原有的 `IFaaSApplication` 变为 `Application` ,和应用一致从 `@midwayjs/faas` 包获取。 ``` import { Application, Context } from '@midwayjs/faas'; ``` 原有的小写装饰器变为大写,和应用一致从 `@midwayjs/decorator` 获取。 ``` import { App, Config } from '@midwayjs/decorator'; ``` 原有的 `ILifeCycle` , `IMidwayContainer` 为容器定义,和应用一致从 `@midwayjs/core` 获取。 ``` import { ILifeCycle, IMidwayContainer } from '@midwayjs/core'; ``` ### 5、运行[​](#5运行 "5、运行的直接链接") HTTP 类的函数,本地直接使用 `npm run dev` 运行,非 HTTP 类的函数,请使用 `npm run test` 进行测试开发。 ## 可选的调整[​](#可选的调整 "可选的调整的直接链接") ### 1、@Func 装饰器升级为 @ServerlessTrigger 装饰器[​](#1func-装饰器升级为-serverlesstrigger-装饰器 "1、@Func 装饰器升级为 @ServerlessTrigger 装饰器的直接链接") 现有代码依旧可以使用 `@Func` 装饰器兼容,新代码请使用 `@ServerlessTrigger` 装饰器,构建器可以通过分析 `@ServerlessTrigger` 装饰器,自动生成 yml 内容。 ### 2、f.yml[​](#2fyml "2、f.yml的直接链接") 使用了 `@ServerlessTrigger` 装饰器后,f.yml 中的 functions 字段可以移除。编译时会自动根据代码生成函数路由信息。 ### 3、测试代码的调整[​](#3测试代码的调整 "3、测试代码的调整的直接链接") HTTP 类型的函数,使用和应用相同的封装了 supertest 的 `createHttpRequest` 方法创建 HTTP 客户端。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; describe('test/hello_aliyun.test.ts', () => { let app: Application; beforeAll(async () => { // create app app = await createFunctionApp(); }); afterAll(async () => { await close(app); }); it('should get result from api gateway trigger', async () => { const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); }); }); ``` 除了类 HTTP 触发器之外,我们还有其他比如定时器、对象存储等函数触发器,这些触发器由于和网关关系密切,不能使用 HTTP 行为来测试,而是使用传统的方法调用来做。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { createInitializeContext } from '@midwayjs/serverless-fc-trigger'; describe('test/hello_aliyun.test.ts', () => { let app: Application; let instance: HelloAliyunService; beforeAll(async () => { // 创建函数 app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), // 这里传入了 aliyun 特有的初始化上下文数据 }); // 拿到服务类 instance = await app.getServerlessInstance(HelloAliyunService); }); afterAll(async () => { await close(app); }); it('should get result from event trigger', async () => { // 调用函数方法,传入参数 expect(await instance.handleEvent('hello world')).toEqual('hello world'); }); }); ``` --- # f.yml 定义 ## 概述[​](#概述 "概述的直接链接") 经过阿里集团标准化小组的讨论,结合社区 `serverless.yml` 的已有设计,通过一个描述文件 (**f.yml**) 来描述整个仓库中的函数信息,现有的发布构建工具,运行时都会基于此文件进行各种处理。 描述文件结构基于 [serverless.yml](https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/),目标是在现有社区化复用能力之上,希望各个平台的代码能尽可能统一,一套代码可以多处部署,并向上扩展。 在 midway serverless v2 之后, `functions` 段落逐步被装饰器所替代,但是 yml 中的内容依旧保留,作为底层能力。 装饰器将最终生成为下面的 yml 结构,可以对照排错。 ## 大体结构[​](#大体结构 "大体结构的直接链接") 由于不同平台的触发器不同,配置信息也不同,配置略微有些差别,但是整体基本一致。 目前第一层字段包括: * **service**   当前的服务(函数分组),对标应用 * **provider** 当前的服务提供商,比如 aliyun,tencent 等。 * **functions** 函数的具体信息 * **layers** 具体的 layer 层配置 * **resources**   引用的资源 * **plugins**   引用的插件,serverless 预留 * **aggregation** 聚合部署字段 * **package**   构建的配置信息 大体如下: ``` service: serverless-hello-world provider: name: aliyun runtime: nodejs10 role: acs:ram::1647796581073291:role/aoneserverlesstestrole functions: hello1: handler: entry.handler events: - http: path: /foo method: - GET - POST hello2: handler: entry.handler2 events: - http: path: /foo method: - GET - POST hello3: handler: test.handler2 events: - http: path: /foo method: - GET - POST layers: test: path: npm:@midwayjs/egg-layer@latest custom: customDomain: domainName: midway-fc.xxxx.com ``` ## 平台字段支持[​](#平台字段支持 "平台字段支持的直接链接") 由于字段非常多,下面的表格统计了所有当前支持的字段,具体的字段描述可以在下面更详细的表格中查找。 √ 代表工具链已经支持,○ 代表部分支持平台支持,但是工具链尚未支持。 | **字段** | **aliyun** | **tencent** | **aws** | | | ------------------------------------------------------ | ---------- | ----------- | ------- | - | | service.name | √ | √ | | | | service.description | √ | √ | | | | | | | | | | provider.name | √ | √ | | | | provider.runtime | √ | √ | | | | provider.stage | | √ | | | | provider.region | | √ | | | | provider.credentials | | √ | | | | provider.timeout | √ | √ | | | | provider.initTimeout | √ | | | | | provider.memorySize | √ | √ | | | | provider.description | √ | | | | | provider.role | √ | √ | | | | provider.environment | √ | √ | | | | provider.serviceId | | √ | | | | provider.vpcConfig | √ | | | | | provider.vpcConfig.vpcId | √ | | | | | provider.vpcConfig.vSwitchIds | √ | | | | | provider.vpcConfig.securityGroupId | √ | | | | | provider.internetAccess | √ | | | | | provider.policies | √ | | | | | provider.logConfig.project | √ | | | | | provider.logConfig.logstore | √ | | | | | provider.nasConfig | √ | | | | | provider.nasConfig.userId | √ | | | | | provider.nasConfig.groupId | √ | | | | | provider.nasConfig.mountPoints | √ | | | | | | | | | | | functions.\[fnName] | √ | √ | | | | functions.\[fnName].handler | √ | √ | | | | functions.\[fnName].stage | | √ | | | | functions.\[fnName].name | | | | | | functions.\[fnName].description | √ | √ | | | | functions.\[fnName].memorySize | √ | √ | | | | functions.\[fnName].timeout | √ | | | | | functions.\[fnName].runtime | √ | | | | | functions.\[fnName].initTimeout | √ | | | | | functions.\[fnName].environment | √ | √ | | | | functions.\[fnName].concurrency | √ | | | | | functions.\[fnName].events | √ | √ | | | | | | | | | | functions.\[fnName].events.\[http] | √ | √ | | | | functions.\[fnName].events.\[http].name | √ | | | | | functions.\[fnName].events.\[http].method | √ | √ | | | | functions.\[fnName].events.\[http].path | √ | √ | | | | functions.\[fnName].events.\[http].serviceId | | √ | | | | functions.\[fnName].events.\[http].timeout | | √ | | | | functions.\[fnName].events.\[http].integratedResponse | | √ | | | | functions.\[fnName].events.\[http].cors | | √ | | | | functions.\[fnName].events.\[http].role | √ | | | | | functions.\[fnName].events.\[http].vesion | √ | | | | | | | | | | | functions.\[fnName].events.\[apigw] | √ | √ | | | | functions.\[fnName].events.\[apigw].method | ○ 附 1 | √ | | | | functions.\[fnName].events.\[apigw].path | ○ | √ | | | | functions.\[fnName].events.\[apigw].serviceId | | √ | | | | functions.\[fnName].events.\[apigw].timeout | | √ | | | | functions.\[fnName].events.\[apigw].integratedResponse | | √ | | | | functions.\[fnName].events.\[apigw].cors | | √ | | | | | | | | | | functions.\[fnName].events.\[timer] | √ | √ | | | | functions.\[fnName].events.\[timer].name | √ | | | | | functions.\[fnName].events.\[timer].type | √ | | | | | functions.\[fnName].events.\[timer].value | √ | √ | | | | functions.\[fnName].events.\[timer].enable | √ | √ | | | | functions.\[fnName].events.\[timer].payload | √ | | | | | functions.\[fnName].events.\[timer].version | √ | | | | | | | | | | | functions.\[fnName].events.\[mq] | √ | √ | | | | functions.\[fnName].events.\[mq].name | √ | | | | | functions.\[fnName].events.\[mq].topic | √ | √ | | | | functions.\[fnName].events.\[mq].strategy | √ | | | | | functions.\[fnName].events.\[mq].tags | √ | | | | | functions.\[fnName].events.\[mq].region | √ | | | | | functions.\[fnName].events.\[mq].role | √ | | | | | functions.\[fnName].events.\[mq].version | √ | | | | | functions.\[fnName].events.\[mq].enable | | √ | | | | | | | | | | functions.\[fnName].events.\[os] | √ | √ | | | | functions.\[fnName].events.\[os].name | √ | √ | | | | functions.\[fnName].events.\[os].bucket | √ | √ | | | | functions.\[fnName].events.\[os],events | √ | √ | | | | functions.\[fnName].events.\[os].filter.prefix | √ | √ | | | | functions.\[fnName].events.\[os].filter.suffix | √ | √ | | | | functions.\[fnName].events.\[os].role | √ | | | | | functions.\[fnName].events.\[os].version | √ | | | | | functions.\[fnName].events.\[os].enable | | √ | | | | | | | | | | | | | | | | layers | √ | √ | | | | layers.\[layerName].name | √ | √ | | | | layers.\[layerName].path | √ | √ | | | | | | | | | | package.include | √ | √ | | | | package.exclude | √ | √ | | | | package.artifact | √ | √ | | | | | | | | | | plugins\[pluginsName] | √ | √ | | | | | | | | | | aggregation.\[fnName].deployOrigin | √ | √ | | | | aggregation.\[fnName].functions | √ | √ | | | | aggregation.\[fnName].functionsPattern | √ | √ | | | | | | | | | | deployType | √ | √ | | | | deployType.type | √ | √ | | | | deployType.config | √ | √ | | | | | | | | | | | | | | | * 附 1:CLI 工具链在本地开发时支持此参数,但是发布时不会读取,需要去网关配置;[阿里云云开发平台](https://workbench.aliyun.com/)已经支持此参数进行发布 ## service[​](#service "service的直接链接") 主要是服务名信息,一个服务可以包含多个函数。 ### 结构[​](#结构 "结构的直接链接") ``` export type ServiceStructure = | string | { name: string; description?: string; }; ``` ### 字段描述[​](#字段描述 "字段描述的直接链接") | **ServiceStructure** | | | | -------------------- | ------ | ------------ | | name | string | 必选,服务名 | | description | string | 描述 | | | | | ### 示例[​](#示例 "示例的直接链接") ``` service: serverless-hello-world // 简写 ``` ``` service: name: serverless-hello-world description: 'some description' ``` ## provider[​](#provider "provider的直接链接") 描述云平台,运行时,权限,以及所有函数复用的信息。 ### 结构[​](#结构-1 "结构的直接链接") ``` export interface ProviderStructure { name: string; runtime: string; stage?: string; region?: string; timeout?: number; memorySize?: number; description?: string; role?: string; environment?: { [key: string]: string; }; serviceId?: string; vpcConfig?: { vpcId: string; vSwitchIds: string[]; securityGroupId: string; }; internetAccess?: boolean; policies?: string | string[]; logConfig?: { project: string; logstore: string; }; nasConfig?: | 'auto' | { userId: number; groupId: number; mountPoints: Array<{ serverAddr: string; mountDir: string; }>; }; } ``` ### 字段描述[​](#字段描述-1 "字段描述的直接链接") | **ProviderStructure** | | | | --------------------- | ------ | ----------------------------------------------------------------------- | | name | string | 必选,可以发布的平台信息,可选的有 `aliyun` , `tencent` ,后续还会增加 | | runtime | string | 必选,函数的运行时 | 默认值 * 阿里云:nodejs12(可选 nodejs6、nodejs8、nodejs10、nodejs12) * 腾讯云:nodejs10(可选 nodejs6, nodejs8, nodejs10) \| | stage | string | 全局发布的环境 | | region | string | 部署的区域,腾讯云特有,比如   ap-shanghai | | timeout | number | 超时时间,单位 秒 默认值 * 阿里云:3 * 腾讯云::3 | | initTimeout | number | 阿里云字段,全局初始化函数超时时间,单位秒,默认 3 | | memorySize | number | 内存限制大小,单位 M, 默认值: * 阿里云:128 * 腾讯云:128 | | description | string | 描述 | | role | string | 角色,事件源会使用该角色触发函数执行,请确保该角色有调用函数的权限。 | | environment | object | 全局环境变量 | | serviceId | string | 网关服务 Id,目前只有腾讯云用到 | | vpcConfig | object | 阿里云字段,vpcConfig 包含的属性包括: `vpcId` 、 `vSwitchIds`  以及 `securityGroupId`  属性 | | internetAccess | boolean | 阿里云字段,表示此服务是否可以访问公网。 | | policies | string | string\[] | 阿里云字段,函数需要的阿里云管理的 RAM policies 或 RAM policy 文档的名称,将会被附加到该函数的默认角色上。如果设置了 Role 属性,则该属性会被忽略。 | | logConfig | object | 阿里云字段,函数执行的日志存储服务配置。 | | nasConfig | 'auto' | object | 阿里云字段,Nas 配置对象用来指定函数可以访问的 Nas 共享的文件系统。 Nas 配置对象可配置的属性包括:`UserId`、`GroupId`、`MountPoints`。 | 信息 腾讯云的 Node.js Runtime 版本我们做了映射,对应关系如下: * nodejs10 -> Node.js10.15 * nodejs8 -> Node.js8.9 * node.js6 -> Node.js6.10 ### 示例[​](#示例-1 "示例的直接链接") aliyun fc 下 ``` provider: name: aliyun runtime: nodejs10 memorySize: 128 policies: - AliyunECSNetworkInterfaceManagementAccess vpcConfig: vpcId: 'vpc-j6cfu2g6tslzekh8grfmk' vSwitchIds: ['vsw-j6chkgsg9naj6gx49espd'] securityGroupId: 'sg-j6ceitqs6ljyssm1apom' logConfig: project: localtestlog logstore: localteststore nasConfig: userId: 10003 groupId: 10003 mountPoints: - serverAddr: '012194b28f-xxxxx.cn-hangzhou.nas.aliyuncs.com:/' mountDir: '/mnt/test' ``` tencent ``` provider: name: tencent runtime: Nodejs10 memorySize: 128 timeout: 10 serviceId: xxxxx region: ap-shanghai ``` ## functions[​](#functions "functions的直接链接") 一个 functions 结构中包含多个 函数(function)。每个函数是一个对象(function)结构。 functions 中的字段和结构,在 midway v2 开始已经变为 `@ServerlessFunction` 和 `@ServerlessTrigger` 装饰器,下面的参数只是原始的描述。 ### functions/function 结构[​](#functionsfunction-结构 "functions/function 结构的直接链接") `functions`   和 `function`   结构是包含的关系,定义如下。 ``` export interface FunctionsStructure { [functionName: string]: FunctionStructure; } export interface FunctionStructure { handler: string; name?: string; description?: string; memorySize?: number; timeout?: number; runtime?: string; initTimeout?: number; environment?: { [key: string]: string; }; events?: EventStructureType[]; concurrency?: number; stage?: string; } ``` ### 字段描述[​](#字段描述-2 "字段描述的直接链接") Functions 是一个由多个 function 组成的对象(非数组),**以函数名作为 key**,函数信息作为值。 单个函数结构如下: | **FunctionStructure** | | | | ----------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------- | | handler | string | 必选,指定入口文件,以 "." 分割,前半部分指定**入口文件名**,后半部分指定**入口函数名**。 | | name | string | 函数名 | | description | string | 描述 | | memorySize | string | 内存限制大小,单位 M,如果不配置,默认取 provider.memorySize | | timeout | number | 超时时间,单位秒, | | 如果不配置,默认取 provider.timeout | | | | runtime | number | 单独对函数指定运行时,同 provider.runtime | | initTimeout | number | 阿里云字段,初始化函数超时时间,单位秒,默认 3 | | environment | object | 函数级别的环境变量 | | concurrency | number | 阿里云字段,为函数设置一个实例并发度 (最小为 1,最大为 100),表示单个函数实例可以同时处理多少个请求,默认为 1 | | stage | string | 腾讯云字段,函数发布的环境 | | events | EventStructureType\[] | 事件,函数触发器 | | | | | | | | | ### 示例[​](#示例-2 "示例的直接链接") 以下结构描述了三个函数,每个函数的入口不同,内存限制不同。 ``` functions: hello1: handler: index.handler1 memorySize: 128 hello2: handler: index.handler2 memorySize: 256 hello3: handler: index.handler3 memorySize: 512 ``` ## ## events[​](#events "events的直接链接") ``` export interface HTTPEvent { path?: string; method?: string | string[]; role?: string; version?: string; serviceId?: string; cors?: boolean; timeout?: number; integratedResponse?: boolean; } export interface APIGatewayEvent extends HTTPEvent {} export interface TimerEvent { type?: 'cron' | 'every' | 'interval'; value: string; payload?: string; version?: string; enable?: boolean; } export interface LogEvent { source: string; project: string; log: string; retryTime?: number; interval?: number; role?: string; version?: string; } export interface OSEvent { name?: string; bucket: string; events: string; filter: { prefix: string; suffix: string; }; enable?: boolean; role?: string; version?: string; } export interface MQEvent { topic: string; tags?: string; region?: string; strategy?: string; role?: string; version?: string; enable?: boolean; } ``` ### 字段描述[​](#字段描述-3 "字段描述的直接链接") events 是一个由不同事件(触发器)组成的**对象数组**。这个对象的 key 为事件类型,值为事件描述。 \| **EventStructureType** | | | | ---------------------- | --------- | --------------------------------------- | ------------------------------------------------------------------------- | ------------ | | key: eventName | string | 事件类型名 | | value: Event | HTTPEvent |  MQEvent | TimerEvent ... | 事件描述结构 | | | | | | **HTTPEvent** | | | | name | string | 触发器的名字 | | path | string | 暴露 http path | | method | string | 暴露的 http 方法,比如 get/post | | role | string | 此角色用来可以触发函数执行 | | version | string | 阿里云云字段,服务版本,默认 "LATEST"。 | | serviceId | string | 腾讯云字段,网关 Id | | cors | boolean | 腾讯云字段,是否开启网关 CORS | | timeout | number | 服务超时时间 | | integratedResponse | boolean | 腾讯云字段,是否开启集成相应,默认 true | | | | | | **APIGatewayEvent** | | | | 和 HTTPEvent 相同 | | | | | | | | | | | | **TimerEvent** | | | | name | string | 触发器的名字 | | type | 'cron' | 'every' | 必填,触发类型,分别代表 cron 表达式,固定时间间隔。腾讯云只支持  `cron`  | | value | string | 必填,对应触发的值。 | 如果是 cron 类型,则填写 cron 表达式。 如果是 every 类型,则填写间隔时间,**带上单位** | | payload | string | 可选,配置在网关,每次触发的内容 | | version | string | 阿里云云字段,服务版本,默认 "LATEST"。 | | enable | boolean | 是否默认开启,默认 true | | | | | | | | | | **OSEvent** | | | | name | string | 可选,触发器名 | | bucket | string | 对象存储的 bucket 名 | | events | string | 触发函数执行的事件名 | | filter | `{prefix: string;suffix: string;}` | 对象过滤参数,满足过滤条件的 对象才可以触发函数,包含一个配置属性 key,表示过滤器支持过滤的对象键 (key)。 | | enable | boolean | 是否默认开启,默认 true | | role | string | 此角色用来可以触发函数执行 | | version | string | 阿里云云字段,服务版本,默认 "LATEST"。 | | | | | | **MQEvent** | | | | name | string | 触发器的名字 | | topic | string | 接收消息的 topic | | tags | string | 阿里云云字段,描述了该订阅中消息过滤的标签(标签一致的消息才会被推送) | | region | string | 阿里云云字段,topic 所在的 region,如果不填,默认为和函数一样的 region | | strategy | string | 阿里云云字段,调用函数的重试策略,可选值:BACKOFF\_RETRY, EXPONENTIAL\_DECAY\_RETRY, 默认值为: BACKOFF\_RETRY,  | | role | string | 此角色用来可以触发函数执行 | | version | string | 阿里云云字段,服务版本,默认 "LATEST"。 | | enable | boolean | 是否默认开启,默认 true | | | | | | | | | | | | | ### 示例[​](#示例-3 "示例的直接链接") 两个函数。 ``` functions: hello1: handler: index.handler1 events: - http: # http 触发器 path: /foo method: get hello3: handler: index.handler3 events: - mq: topic: mytopic ``` HTTP 示例 ``` functions: hello1: handler: index.handler1 events: - http: path: /foo method: get,post // 阿里云支持同时多个,腾讯只支持单个 ``` ``` functions: hello1: handler: index.handler1 events: - http: path: /foo method: all // 所有method ``` timer 示例 ``` service: serverless-hello-world provider: name: fc runtime: nodejs8 stage: dev functions: hello3: handler: bbbbbb events: - timer: type: 'cron' value: '0 0 8 * * *' payload: 'test' ``` ## layers[​](#layers "layers的直接链接") layer 作为 runtime 的扩展能力,用于在不同层面扩展 runtime 的接口。 ### 结构[​](#结构-2 "结构的直接链接") ``` export interface LayersStructure { [layerName: string]: { path: string; name?: string; }; } ``` ### 字段描述[​](#字段描述-4 "字段描述的直接链接") layers 是一个由多个 layer 组成的对象(非数组),**以 layer 名作为 key**,信息作为值。 | **LayersStructure** | | | | ------------------- | ------ | ---------- | | key: layerName | string | layer 名 | | value: path | string | layer 路径 | | value: name | string | layer 名 | | | | | | | | | ### 示例[​](#示例-4 "示例的直接链接") ``` layers: egg-layer: path: npm:@midwayjs/egg-layer@latest ``` ## package[​](#package "package的直接链接") 用于控制打包时,包含或者忽略某些文件,以及指定打包的最终产物的名称。 ### 示例[​](#示例-5 "示例的直接链接") ``` package: # 打包配置 include: # 打包包含文件列表,默认为 package.json、构建后的代码和依赖 - resource/* exclude: # 打包剔除文件列表 - test/* artifact: code.zip # 打包后的压缩包文件名 ``` ## aggregation[​](#aggregation "aggregation的直接链接") 设置聚合部署的结构,指定一些函数聚合在一起部署为一个新函数。 ### 示例[​](#示例-6 "示例的直接链接") ``` aggregation: # 聚合部署,详细内容请查看 聚合部署部分 index: # 聚合部署聚合名称 deployOrigin: false # 是否部署原始方法 functions: # 聚合部署方法列表,比functionsPattern优先级要高 - index # 聚合部署方法名 - hello functionsPattern: # 聚合部署方法匹配规则,配置 functions 时无效 - 'render*' # 使用 micromatch 匹配规则,即任何以render开头的函数 - '!render2' ``` ## resource[​](#resource "resource的直接链接") 各个子项目依赖的资源信息配置。 信息 暂时没有使用,作为预留项目。 ## deployType[​](#deploytype "deployType的直接链接") 定制的部署类型,目前是应用迁移方案在使用。 比如: ``` deployType: egg ``` 如果部署类型有更多的配置,则需要更为完整的写法,比如: ``` deployType: type: static config: rootDir: public ``` --- # API 网关(HTTP) API 网关在腾讯云函数体系中类似于 HTTP 函数,我们通过它将函数发布为 HTTP 服务。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloTencentService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.API_GATEWAY, { path: '/api_gateway_tencent', method: 'post', }) async handleAPIGatewayEvent(@Body() name) { return `hello ${name}`; } } ``` 在 `npm run deploy` 后即可通过控制台输出的链接访问。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和传统应用 HTTP 测试相同,通过 createFunctionApp 创建函数 app,通过 createHttpRequest 方式进行测试。 ``` import { Framework } from '@midwayjs/serverless-app'; import { createFunctionApp, createHttpRequest } from '@midwayjs/mock'; describe('test/hello_tencent.test.ts', () => { let app: Application; let instance: HelloTencentService; beforeAll(async () => { // create app app = await createFunctionApp(); }); afterAll(async () => { await close(app); }); it('should get result from http trigger', async () => { const result = await createHttpRequest(app).post('api_gateway_tencent').send({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); }); }); ``` --- # CMQ 触发器(消息队列) CMQ(mq) 触发器,订阅的是腾讯云的消息队列服务。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, SCF } from '@midwayjs/faas'; @Provide() export class HelloTencentService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.MQ, { topic: 'test-topic', tags: 'bbb', }) async handleCMQEvent(event: SCF.CMQEvent) { // xxx } } ``` 在 `f deploy` 后,即可。 信息 注意,在腾讯云下,midway faas 提供的默认消息队列格式为 JSON ## CMS 触发器配置[​](#cms-触发器配置 "CMS 触发器配置的直接链接") | 属性名 | 类型 | 描述 | | ------ | ------ | -------------------------------------------------------------- | | topic | string | 接收消息的 topic | | tags | string | 可选,描述了该订阅中消息过滤的标签(标签一致的消息才会被推送) | 示例: **监听 MQ 消息** ``` @ServerlessTrigger(ServerlessTriggerType.MQ, { topic: 'test-topic', region: 'cn-shanghai' strategy: 'BACKOFF_RETRY' }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") CMQ 消息返回的结构如下,在 `SCF.CMQEvent` 类型中有描述。 ``` { "Records": [ { "CMQ": { "type": "topic", "topicOwner": 1567, "topicName": "testtopic", "subscriptionName": "xxxxxx", "publishTime": "1970-01-01T00:00:00.000Z", "msgId": "123345346", "requestId": "123345346", "msgBody": "Hello from CMQ!", "msgTag": "tag1,tag2" } } ] } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createCMQEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloTencentService } from '../src/function/hello_tencent'; import { createCMQEvent } from '@midwayjs/serverless-scf-trigger'; import { join } from 'path'; describe('test/hello_tencent.test.ts', () => { let app: Application; let instance: HelloTencentService; beforeAll(async () => { // create app app = await createFunctionApp(join(__dirname, '../'), { initContext: createInitializeContext(), }); instance = await app.getServerlessInstance(HelloTencentService); }); afterAll(async () => { await close(app); }); it('should get result from cmq trigger', async () => { expect(await instance.handleCMQEvent(createCMQEvent())).toEqual('hello world'); }); }); ``` --- # COS 触发器(对象存储) COS 是腾讯云用于存储一些资源文件的服务。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType, } from '@midwayjs/decorator'; import { Context, SCF } from '@midwayjs/faas'; @Provide() export class HelloTencentService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.OS, { bucket: 'cli-appid.cos.ap-beijing.myqcloud.com', events: 'cos:ObjectCreated:*, filter: { prefix: 'filterdir/', suffix: '.jpg', }, }) async handleCOSEvent(event: SCF.COSEvent) { // xxx } } ``` 在 `npm run deploy` 后,即可。 ## OSS 触发器配置[​](#oss-触发器配置 "OSS 触发器配置的直接链接") | 属性名 | 类型 | 描述 | | ------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------- | | bucket | string | 对象存储的 bucket 地址 | | events | string | 触发函数执行的事件名 | | filter | `{prefix: string;suffix: string;}` | 对象过滤参数,满足过滤条件的 对象才可以触发函数,包含一个配置属性 key,表示过滤器支持过滤的对象键 (key)。 | | | | | 示例: **监听对象创建事件** ``` @ServerlessTrigger(ServerlessTriggerType.OS, { bucket: 'cli-appid.cos.ap-beijing.myqcloud.com', events: 'cos:ObjectCreated:*, filter: { prefix: 'filterdir/', suffix: '.jpg', }, }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") COS 消息返回的结构如下,在 `SCF.COSEvent` 类型中有描述。 ``` { "Records": [ { "cos": { "cosSchemaVersion": "1.0", "cosObject": { "url": "http://testpic-1253970026.cos.ap-chengdu.myqcloud.com/testfile", "meta": { "x-cos-request-id": "NWMxOWY4MGFfMjViMjU4NjRfMTUyMV8yNzhhZjM=", "Content-Type": "" }, "vid": "", "key": "", "size": 1029 }, "cosBucket": { "region": "cd", "name": "testpic", "appid": "1253970026" }, "cosNotificationId": "unkown" }, "event": { "eventName": "cos:ObjectCreated:*", "eventVersion": "1.0", "eventTime": 1545205770, "eventSource": "qcs::cos", "requestParameters": { "requestSourceIP": "192.168.15.101", "requestHeaders": { "Authorization": "****************" } }, "eventQueue": "qcs:0:lambda:cd:appid/1253970026:default.printevent.$LATEST", "reservedInfo": "", "reqid": 179398952 } } ] } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") ## 本地开发[​](#本地开发-1 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createCOSEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloTencentService } from '../src/function/hello_tencent'; import { createCOSEvent } from '@midwayjs/serverless-scf-trigger'; import { join } from 'path'; describe('test/hello_tencent.test.ts', () => { let app: Application; let instance: HelloTencentService; beforeAll(async () => { // create app app = await createFunctionApp(); instance = await app.getServerlessInstance(HelloTencentService); }); afterAll(async () => { await close(app); }); it('should get result from timer trigger', async () => { expect(await instance.handleCOSEvent(createCOSEvent())).toEqual('hello world'); }); }); ``` --- # Timer 触发器(定时任务) 定时任务触发器用于定时执行一个函数。腾讯云 Timer 触发器目前只支持 cron 格式。 信息 温馨提醒,测试函数后请及时关闭触发器自动执行,避免超额扣费。 ## 使用方式[​](#使用方式 "使用方式的直接链接") ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/decorator'; import { Context, SCF } from '@midwayjs/faas'; @Provide() export class HelloTencentService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'cron', value: '*/60 * * * * * *', // 每 60s 触发 }) async handleTimerEvent(event: SCF.TimerEvent) { this.ctx.logger.info(event); return 'hello world'; } } ``` 注意,腾讯云的定时为全 Cron,具体 Cron 格式请参考 [开发文档](https://cloud.tencent.com/document/product/583/9708)。 常用格式: ``` */5 * * * * * * 表示每5秒触发一次 0 0 2 1 * * * 表示在每月的1日的凌晨2点触发 0 15 10 * * MON-FRI * 表示在周一到周五每天上午10:15触发 0 0 10,14,16 * * * * 表示在每天上午10点,下午2点,4点触发 0 */30 9-17 * * * * 表示在每天上午9点到下午5点每半小时触发 0 0 12 * * WED * 表示在每个星期三中午12点触发 ``` 执行 `npm run deploy` 部署即可。 ## Timer 配置[​](#timer-配置 "Timer 配置的直接链接") | 属性名 | 类型 | 描述 | | ------- | ------ | ---------------------------------- | | type | cron | 必填,触发类型,代表 cron 表达式。 | | value | string | 必填,cron 表达式或者 every 值。 | | payload | string | 可选,一个固定传递的值,很少用 | | | | | 示例: **cron 表达式** ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { type: 'cron', value: '0 0 4 * * *', // 每天4:00触发 }) ``` ## 事件结构[​](#事件结构 "事件结构的直接链接") Timer 消息返回的结构如下,在 `SCF.TimerEvent` 类型中有描述。 ``` { Message: '', Time: new Date().toJSON(), TriggerName: 'test', Type: 'Timer', } ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") 事件类型的函数本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createTimerEvent` 方法快速创建平台传入的结构。 ``` import { createFunctionApp, close } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/serverless-app'; import { HelloTencentService } from '../src/function/hello_tencent'; import { createTimerEvent } from '@midwayjs/serverless-scf-trigger'; import { join } from 'path'; describe('test/hello_tencent.test.ts', () => { let app: Application; let instance: HelloTencentService; beforeAll(async () => { // create app app = await createFunctionApp(); instance = await app.getServerlessInstance(HelloTencentService); }); afterAll(async () => { await close(app); }); it('should get result from timer trigger', async () => { expect(await instance.handleTimerEvent(createTimerEvent())).toEqual('hello world'); }); }); ``` ## --- # 服务和注入 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600604974682-f5309741-dda9-484b-bcf3-ac054f98fe78.png#height=172\&id=xMfop\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=344\&originWidth=2130\&originalType=binary\&ratio=1\&size=46493\&status=done\&style=none\&width=1065) 提供这个抽象有以下几个好处: * 保持 Controller 中的逻辑更加简洁。 * 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。 * 将逻辑和展现分离,更容易编写测试用例。 ## 创建服务[​](#创建服务 "创建服务的直接链接") 在 Midway 中,普通的服务就是一个 Class,比如我们之前创建了一个接受 user 请求的 Controller,这些我们来新增一个处理这些数据的服务。 对于服务的文件,我们一般会存放到 `src/service`  目录中。我们来添加一个 user 服务。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 内容为: ``` // src/service/user.ts import { Provide } from '@midwayjs/decorator'; @Provide() export class UserService { async getUser(id: number) { return { id, name: 'Harry', age: 18, }; } } ``` 除了一个 `@Provide`  装饰器外,整个服务的结构和普通的 Class 一模一样,这样就行了。 之前我们还增加了一个 User 定义,这里也可以直接使用。 ``` import { Provide } from '@midwayjs/decorator'; import { User } from '../interface'; @Provide() export class UserService { async getUser(id: number): Promise { return { id, name: 'Harry', age: 18', }; } } ``` ## 使用服务[​](#使用服务 "使用服务的直接链接") 在 Controller 处,我们需要来调用这个服务。传统的代码写法,我们需要初始化这个 Class(new),然后将实例放在需要调用的地方。在 Midway 中,你**不需要这么做**,只需要编写我们提供的\*\* "依赖注入" \*\*的代码写法。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator'; import { UserService } from '../service/user'; @Provide() @Controller('/api/user') export class APIController { @Inject() userService: UserService; @Get('/') async getUser(@Query('id') uid) { const user = await this.userService.getUser(uid); return { success: true, message: 'OK', data: user }; } } ``` 使用服务的过程分为几部分: * 1、使用 `@Provide`  装饰器暴露你的服务 * 2、在调用的代码处,使用 `@Inject`  装饰器注入你的服务 * 3、调用注入服务,执行对应的方法 Midway 的核心 “依赖注入” 容器会**自动关联**你的控制器(Controller) 和服务(Service),在运行过程中**会自动初始化**所有的代码,你**无需手动初始化**这些 Class。 ## 注入行为描述[​](#注入行为描述 "注入行为描述的直接链接") 看到这里,你应该明白为什么控制器(Controller) 和服务(Service)上都有一个 `@Provide`  装饰器。不仅如此,之后的大部分代码中,你都会发现这个装饰器。 `@Provide`  装饰器的作用: * 1、这个 Class,被依赖注入容器托管,会自动被实例化(new) * 2、这个 Class,可以被其他在容器中的 Class 注入 而对应的 `@Inject`  装饰器,作用为: * 1、在依赖注入容器中,找到对应的属性名,并赋值为对应的实例化对象 信息 `@Inject`  的类中,必须有 `@Provide`  才会生效。 `@Provide`  和 `@Inject`  装饰器是成对出现的,两者通过冒号后的类名进行关联。 ``` // service @Provide() export class UserService { //... } // controller @Provide() @Controller('/api/user') export class APIController { @Inject() userService: UserService; // <------ 这里的类型是 Class,即会注入一个该类型的实例 //... } ``` 这样的组合之后会用到很多地方,**请务必记住这个用法**。 依赖注入还有更为复杂的情况,可以阅读 [依赖注入](/docs/2.0.0/container.md) 参考。 --- # 服务工厂 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 比如我们的 oss 组件,由于会创建多个 oss 对象,在编写的时候就需要留好多实例的接口。为了这种场景,midway 抽象了 `ServiceFactory` 类。 `ServiceFactory` 是个抽象类,每个需要实现的服务,都需要继承他。 我们以一个 http 客户端为例,需要准备一个创建 http 客户端实例的方法,其中包含两个部分: * 1、创建客户端实例的方法 * 2、客户端的配置 ``` // 创建客户端的配置 const config = { baseUrl: '', timeout: 1000, }; // 创建客户端实例的方法 const httpClient = new HTTPClient(config); ``` ## 实现一个服务类[​](#实现一个服务类 "实现一个服务类的直接链接") 我们希望实现一个上述 HTTPClient 的服务工厂,用于在 midway 体系中创建多个 httpClient 对象。 服务工厂在 midway 中也是一个普通的导出类,作为服务的一员,比如我们也可以把他放到 `src/service/httpServiceFactory.ts` 中。 ### 1、实现创建实例接口[​](#1实现创建实例接口 "1、实现创建实例接口的直接链接") `ServiceFactory` 是个用于继承的抽象类,它包含一个泛型(创建的实例类型,比如下面就是创建出 HTTPClient 类型)。 我们只需要继承它。 ``` import { ServiceFactory } from '@midwayjs/core'; import { Provide } from '@midwayjs/decorator'; @Provide() export class HTTPClientServiceFactory extends ServiceFactory { // ... } ``` 由于是抽象类,我们需要实现其中的两个方法。 ``` import { ServiceFactory } from '@midwayjs/core'; import { Provide } from '@midwayjs/decorator'; @Provide() export class HTTPClientServiceFactory extends ServiceFactory { // 创建单个实例 protected createClient(config: any): any { return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `createClient` 方法用于传入一个创建服务配置(比如 httpClient 配置),返回一个具体的实例,就像示例的那样。 `getName` 方法用于返回这个服务工厂的名字,方便框架识别和日志输出。 ### 2、增加配置和初始化方法[​](#2增加配置和初始化方法 "2、增加配��置和初始化方法的直接链接") 我们需要注入一个配置,比如我们使用 `httpClient` 作为这个服务的配置。 ``` // config.default.ts export const httpClient = { // ... }; ``` 然后注入到服务工厂中,同时,我们还需要在初始化时,调用创建多个实例的方法。 ``` import { ServiceFactory } from '@midwayjs/core'; import { Provide } from '@midwayjs/decorator'; @Provide() export class HTTPClientServiceFactory extends ServiceFactory { @Config('httpClient') httpClientConfig; @Init() async init() { await this.initClients(this.httpClientConfig); } protected createClient(config: any): any { // 创建实例 return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `initClients` 方法是基类中实现的,它需要传递一个完整的用户配置,并循环调用 `createClient` 来创建对象,保存到内存中。 ## 获取实例[​](#获取实例 "获取实例的直接链接") `createClient` 方法只是定义了创建对象的方法,我们还需要定义配置的结构。 配置的结构分为几部分: * 1、默认配置,即所有对象都能复用的配置 * 2、单个实例需要的配置 * 3、多个实例需要的配置 我们来分别说明, **默认配置** 默认的配置,我们约定为 `default` 属性。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000, }, }; ``` ### 单个实例[​](#单个实例 "单个实例的直接链接") **单个配置** ``` // config.default.ts export const httpClient = { default: { timeout: 3000, }, client: { baseUrl: '', }, }; ``` `client` 用于单个实例结构的描述,创建对象时会和 `default` 做合并。使用 `get` 方法获取默认实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const httpClient = this.serviceFactory.get(); } ``` ### 多个实例[​](#多个实例 "多个实例的直接链接") 使用 `clients` 来配置多个实例,每个 key 都是一个独立的实例配置。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000, }, clients: { aaa: { baseUrl: '', }, bbb: { baseUrl: '', }, }, }; ``` 通过 key 来获取实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const aaaInstance = this.serviceFactory.get('aaa'); // ... const bbbInstance = this.serviceFactory.get('bbb'); // ... } } ``` ### 动态创建实例[​](#动态创建实例 "动态创建实例的直接链接") 也可以通过基类的 `createInstance` 方法动态获取实例。 警告 注意,这里使用的不是子类的 createClient,createClient 不包含和默认配置的逻辑。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { // 会合并 config.bucket3 和 config.default let customHttpClient = await this.serviceFactory.createInstance( { baseUrl: 'xxxxx', }, 'custom' ); // 传了名字之后也可以从 factory 中获取 customHttpClient = this.serviceFactory.get('custom'); } } ``` `createInstance` 方法的第一个参数是配置,如果动态调用的时候,可以手动传参,第二个参数是一个字符串名称,如果传入了名称,创建完的实例将会保存到内存中,后续可以从服务工厂中再次获取。 --- # Session Session 在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。 ## 在 @midwayjs/web 使用[​](#在-midwayjsweb-使用 "在 @midwayjs/web 使用的直接链接") 框架内置了 [Session](https://github.com/eggjs/egg-session) 插件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 比如 Controller 中。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; import { Context } from 'egg'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 Session 上的内容 const userId = this.ctx.session.userId; // ... // 修改 Session 的值 this.ctx.session.visited = this.ctx.session.visited ? this.ctx.session.visited + 1 : 1; } } ``` Session 的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为 null: ``` ctx.session = null; ``` 需要 \*\*特别注意 \*\*的是:设置 session 属性时需要避免以下几种情况(会造成字段丢失,详见[koa-session](https://github.com/koajs/session/blob/master/lib/session.js#L37-L47)源码) * 不要以 \_ 开头 * 不能为 isNew ``` // ❌ 错误的用法 ctx.session._visited = 1; // --> 该字段会在下一次请求时丢失 ctx.session.isNew = 'HeHe'; // --> 为内部关键字, 不应该去更改 // ✔️ 正确的用法 ctx.session.visited = 1; // --> 此处没有问题 ``` Session 的实现是基于 Cookie 的,默认配置下,用户 Session 的内容加密后直接存储在 Cookie 中的一个字段中,用户每次请求我们网站的时候都会带上这个 Cookie,我们在服务端解密后使用。Session 的默认配置如下: ``` export const session = { key: 'EGG_SESS', maxAge: 24 * 3600 * 1000, // 1 天 httpOnly: true, encrypt: true, }; ``` 可以看到这些参数除了 key 都是 Cookie 的参数,key 代表了存储 Session 的 Cookie 键值对的 key 是什么。在默认的配置下,存放 Session 的 Cookie 将会加密存储、不可被前端 js 访问,这样可以保证用户的 Session 是安全的。 Session 默认存放在 Cookie 中,如需放在其他存储中,具体可以查阅 [Cookie 与 Session](https://eggjs.org/zh-cn/core/cookie-and-session.html)。 ## 在 @midwayjs/koa 使用[​](#在-midwayjskoa-使用 "在 @midwayjs/koa 使用的直接链接") koa 原生功能只提供了 Cookie 的操作,但是没有提供 Session 操作。Session 就只用自己实现或者通过第三方中间件实现。 常用的 koa session 中间件有 [koa-session](https://github.com/koajs/session)。koa-session 默认基于 cookie 来实现 Session 数据存储,同时也支持其他存储的扩展。 首先需要安装中间件。 ``` $ npm install koa-session --save ``` 在启动时加载该中间件,示例如下: ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import * as session from 'koa-session'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( session( { key: 'koa.sess', // cookie key maxAge: 24 * 3600 * 1000, // 1天 }, this.app ) ); } } ``` 这里的配置也可以放到 config 中,然后使用 `@Config` 装饰器注入。 这里中间件的更多选项可以参考 [koa-session 文档](https://github.com/koajs/session)。 之后就可以在其他地方使用了,比如: ``` // src/controller/home.ts import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.session.visits = this.ctx.session.visits ? this.ctx.session.visits + 1 : 1; } } ``` 也可以使用 `@Session` 装饰器获取 Session。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject, Session, ALL } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home(@Session() visits = 1) { this.req.session.visits = session.visits = visits + 1; } } ``` 或者直接获取整个 Session。 ``` // src/controller/home.ts import { Controller, Get, Provide, Session, ALL } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/') async home(@Session(ALL) session) { session.visits = session.visits ? session.visits + 1 : 1; } } ``` 如需使用不同的存储,可以使用类似的 [generic-session](https://github.com/koajs/generic-session) 来替换该中间件。 ## 在 @midwayjs/express 使用[​](#在-midwayjsexpress-使用 "在 @midwayjs/express 使用的直接链接") 首先安装依赖。 ``` $ npm i express-session $ npm i -D @types/express-session ``` 加到中间件中。 ``` // configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as session from 'express-session'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( session({ secret: 'my-secret', resave: false, saveUninitialized: false, }) ); } } ``` `secret` 用于对 sessionId cookie 进行加密。它可以是字符串,也可以是多个秘钥字符串组成的数组。如果提供了数组,则使用第一个字符串进行签名,而在验证请求中的签名时会循环所有的加密串。 这个秘钥最好是随机的一组字符。 通过获取 req 对象设置获取 Session 中的值。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() req: Request; @Get('/') async home() { this.req.session.visits = this.req.session.visits ? this.req.session.visits + 1 : 1; } } ``` 也可以使用 `@Session` 装饰器获取 Session。 ``` // src/controller/home.ts import { Controller, Get, Provide, Inject, Session, ALL } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; import { Request } from 'express'; @Provide() @Controller('/') export class HomeController { @Inject() req: Request; @Get('/') async home(@Session() visits = 1) { this.req.session.visits = session.visits = visits + 1; } } ``` 或者直接获取整个 Session。 ``` // src/controller/home.ts import { Controller, Get, Provide, Session, ALL } from '@midwayjs/decorator'; import { Context } from '@midwayjs/express'; @Provide() @Controller('/') export class HomeController { @Get('/') async home(@Session(ALL) session) { session.visits = session.visits ? session.visits + 1 : 1; } } ``` ## 在 Serverless 场景使用[​](#在-serverless-场景使用 "在 Serverless 场景使用的直接链接") Serverless 场景有与弹性的存在,没有维护 Session 的必要性,最多只能使用基于 Cookie 的 Session。 --- # SocketIO Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616508690266-37c60f43-99a5-4586-b96d-49fbe88a9db7.png#height=176\&id=dC3sH\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=352\&originWidth=1204\&originalType=binary\&ratio=1\&size=26196\&status=done\&style=none\&width=602) Midway 提供了对 Socket.io 的支持和封装,能够简单的创建一个 Socket.io 服务。本篇内容演示了如何在 Midway 体系下,提供 Socket.io 服务的方法。 Midway 当前采用了最新的 [Socket.io (v4.0.0)](https://socket.io/docs/v4) 进行开发。 ## 创建示例[​](#创建示例 "创建示例的直接链接") 纯 socket.io 示例。 ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=socketio my_midway_app # 如果是 npm v7 $ npm init midway -- --type=socketio my_midway_app ``` 或者在现有项目中安装 Socket.io 的依赖。 ``` $ npm i @midwayjs/socketio --save $ npm i @types/socket.io-client socket.io-client --save-dev ``` Egg.js + Socket.io 示例。 ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=web-socketio my_midway_app # 如果是 npm v7 $ npm init midway -- --type=web-socketio my_midway_app ``` ## 目录结构[​](#目��录结构 "目录结构的直接链接") 下面是 Socket.io 项目的基础目录结构,和传统应用类似,我们创建了 `socket`  目录,用户存放 Soscket.io 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## socket.io 服务的文件 │ └── hello.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## Socket.io 工作原理[​](#socketio-工作原理 "Socket.io 工作原理的直接链接") Socket.io 服务器和 Socket.io 客户端(浏览器,Node.js 或另一种编程语言)之间的双向通道通过 [WebSocket 连接](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) 建立起来,在不可用时,将使用 HTTP 长轮询作为备用手段。 Socket.io 代码是基于 Engine.io 库搭建起来的,是属于 Engine.io 的上层实现。Engine.io 负责整个服务端和客户端连接的部分,包括连接检查,传输方式等等。而 Socket.io 负责上层的重连,封包缓冲,广播等等特性。 Socket.io(Engine.io)实现了两种 Transports(传输方式)。 第一种是 HTTP 长轮询。HTTP Get 请求用于 long-running(长连接),Post 请求用于 short-running(短连接)。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616509613529-24413e09-2173-4b68-94d2-f0c492e8a192.png#height=534\&id=wNTnr\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1068\&originWidth=1778\&originalType=binary\&ratio=1\&size=97397\&status=done\&style=none\&width=889) 第二种是 WebSocket 协议,直接基于 [WebSocket Connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 实现。它在服务器和客户端之间提供了双向且低延迟的通信通道。 在默认的情况下,Socket.io 会先采用 HTTP 长轮询进行连接,并发送一个类似下面结构的数据。 ``` { "sid": "FSDjX-WRwSA4zTZMALqx", // 连接的 session id "upgrades": ["websocket"], // 可升级的协议 "pingInterval": 25000, // 心跳时间间隔 "pingTimeout": 20000 // 心跳超时时间 } ``` 当当前的服务满足升级到 WebSocket 协议的要求时,会自动升级到 WebSocket 协议,如下图。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616510929886-2eed0b2e-0ca2-44e4-b471-a342e2a916b0.png#height=210\&id=XUhOM\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=216\&originWidth=585\&originalType=binary\&ratio=1\&size=28233\&status=done\&style=none\&width=568) * 1、第一次握手,传输 sid 等结构 * 2、使用 HTTP 长轮询发送数据 * 3、使用 HTTP 长轮询返回数据 * 4、升级协议,使用 WebSocket 协议发送数据 * 5、当协议升级后,关闭之前的长轮询 之后就开始正常的 WebSocket 通信了。 ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController`  装饰器定义 Socket 服务。 ``` @Provide() @WSController('/') export class HelloController {} ``` `@WSController`  的入参,指代了每个 Socket 的 Namespace(非 path)。如果不提供 Namespace,每个 Socket.io 会自动创建一个 `/`  的 Namespace,并且将客户端连接都归到其中。 信息 这里的 namespace 支持字符串和正则。 当 Namespace 有客户端连接时,会触发 `connection`  事件,我们在代码中可以使用 `@OnWSConnection()`  装饰器来修饰一个方法,当每个客户端第一次连接到该 Namespace 时,将自动调用该方法。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/socketio'; @Provide() @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod() { console.log('on client connect', this.ctx.id); } } ``` 信息 这里的 ctx 等价于 socket 实例。 ## 消息和响应[​](#消息和响应 "消息和响应的直接链接") Socket.io 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()`  装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/socketio'; @Provide() @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') async gotMessage(data) { console.log('on data got', this.ctx.id, data); } } ``` 注意,由于 Socket.io 在一个事件中可以传递多个数据,这里的参数可以是多个。 ``` @OnWSMessage('myEvent') async gotMessage(data1, data2, data3) { // ... } ``` 当获取到数据之后,通过业务逻辑处理数据,然后将结果返回给客户端,返回的时候,我们也是通过另一个事件发送给客户端。 通过 `@WSEmit`  装饰器来将方法的返回值返回给客户端。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/socketio'; @Provide() @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { return 'hello world'; // 这里将 hello world 字符串返回给客户端 } } ``` 上面的代码,我们的方法返回值 hello world,将自动发送给客户端监听的 `myEventResult`  事件。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和传统 web 的 midway 测试方法一样,我们使用 `createApp`  创建我们的服务端,唯一不同的是,我们要启动一个 Socket.io 服务,比如传递一个端口。 ``` import { createApp, close } from '@midwayjs/mock'; import { Framework } from '@midwayjs/socketio'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { const app = await createApp(process.cwd(), { port: 3000 }); //... await close(app); }); }); ``` 你可以直接使用 `socket.io-client` 来测试。也可以使用 Midway 提供的基于 `socket.io-client` 模块封装的测试客户端。 假如我们的服务端处理逻辑如下(返回客户端传递的数据相加的结果): ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 测试代码如下: ``` import { createApp, close } from '@midwayjs/mock'; import { Framework } from '@midwayjs/socketio'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(process.cwd(), { port: 3000 }); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 拿到结果返回 const data = await new Promise((resolve) => { client.on('myEventResult', resolve); // 发送事件 client.send('myEvent', 1, 2, 3); }); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 如果多个客户端,也可以使用更简单的写法,使用 node 自带的 `events`  模块的 `once`  方法来优化,就会变成下面的代码。 ``` import { createApp, close } from '@midwayjs/mock'; import { Framework } from '@midwayjs/socketio'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(process.cwd(), { port: 3000 }); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 用事件的 promise 写法监听 const gotEvent = once(client, 'myEventResult'); // 发送事件 client.send('myEvent', 1, 2, 3); // 等待返回 const [data] = await gotEvent; // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 等待回执(ack)的消息[​](#等待回执ack的消息 "等待回执(ack)的消息的直接链接") Socket.io 支持一种直接返回消息的写法。当客户端传递消息的时候,如果最后一个参数为一个 function(callback),则服务端可以拿到这个 callback,将数据直接返回给客户端,不需要创建一个新的消息。 我们的服务代码不需要变化, `@midwayjs/socketio`  内部会判断最后一个参数,自动返回给客户端。 比如,服务端代码: ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 客户端测试代码: ``` import { createApp, close } from '@midwayjs/mock'; import { Framework } from '@midwayjs/socketio'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(process.cwd(), { port: 3000 }); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 发送事件,这里使用了 await 的写法 const data = await client.sendWithAck('myEvent', 1, 2, 3); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` ## 常见的消息和广播[​](#常见的消息和广播 "常见的消息和广播的直接链接") 以下面的代码示例举例: ``` import { Context, Application } from '@midwayjs/socketio'; @Provide() @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @App() app: Application; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { // TODO } } ``` 发送给客户端(也可以用装饰器形式直接 return)。 ``` this.ctx.emit('hello', 'can you hear me?', 1, 2, 'abc'); ``` 发送给的所有除发件人以外的所有客户端。 ``` this.ctx.broadcast.emit('broadcast', 'hello friends!'); ``` 发送给所有在 `game`  房间的客户端(除了发送者)。 ``` this.ctx.to('game').emit('nice game', "let's play a game"); ``` 发送给所有的 `game1`  和 `game2`  房间的客户端(除了发送者)。 ``` this.ctx.to('game1').to('game2').emit('nice game', "let's play a game (too)"); ``` 发送给所有 `game`  房间的客户端,包括发送者。 ``` this.app.in('game').emit('big-announcement', 'the game will start soon'); ``` 给 `myNamespace`  命名空间的客户端广播,包括发送者。 ``` // 从 app 发送 this.app.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon'); // 从 ctx 发送 this.ctx.nsp.emit('bigger-announcement', 'the tournament will start soon'); ``` 发送到特定的 namespace 和 room,包括发送者。 ``` // 从 app 发送 this.app.of('myNamespace').to('room').emit('event', 'message'); // 从 ctx 发送 this.ctx.nsp.emit('bigger-announcement', 'the tournament will start soon'); ``` 发送给所有连接到当前节点上的客户端(多个节点的时候,就是多进程) ``` this.app.local.emit('hi', 'my lovely babies'); ``` ## 启动服务[​](#启动服务 "启动服务的直接链接") Socket.io 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway 框架一起启动)。通过编写 `bootstrap.js`  即可。 和其他框架类似,示例如下: ``` // bootstrap.js const SocketFramework = require('@midwayjs/socketio').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); // 初始化 socket.io 框架 const socketFramework = new SocketFramework().configure({ port: 3000, }); Bootstrap.load(socketFramework).run(); ``` 我们在本地开发时可以直接使用这个文件进行开发,我们的脚手架示例已经将其添加到 `npm run dev`  命令中。 而在线上部署时,也可以使用 `npm run start`  命令。 ``` "scripts": { "start": "NODE_ENV=production node ./bootstrap.js", "dev": "cross-env NODE_ENV=local midway-bin dev --ts --entryFile=bootstrap.js", "test": "midway-bin test --ts", "cov": "midway-bin cov --ts", ... }, ``` ## 多进程[​](#多进程 "多进程的直接链接") 在多进程(pm2)场景下,我们需要注意两件事。 * 1、如果启用了 HTTP 长轮询(默认设置),则需要启用粘性会话(sticky session) * 2、配置一个 redis 适配器 ### 配置粘性会话[​](#配置粘性会话 "配置粘性会话的直接链接") ### 配置 redis 适配器[​](#配置-redis-适配器 "配置 redis 适配器的直接链接") `@midwayjs/socketio`  提供了一个生成 redis 适配器的工具类,只需要传入 redis 的 host 和 port 即可。 示例如下: ``` // bootstrap.js const { Framework, createRedisAdapter } = require('@midwayjs/socketio'); const { Bootstrap } = require('@midwayjs/bootstrap'); // 初始化 socket.io 框架 const socketFramework = new Framework().configure({ port: 3000, adapter: createRedisAdapter({ host: '127.0.0.1', port: 6379 }), }); Bootstrap.load(socketFramework).run(); ``` ## 框架选项[​](#框架选项 "框架选项的直接链接") `@midwayjs/socketio` 作为框架启动时,可以传递的参数如下: \| port | number | 可选,如果传递了该端口,socket.io 内部会创建一个该端口的 HTTP 服务,并将 socket 服务 attach 在其之上。 \| 如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | ------------------------------------------------------------- | ------ | ---------------------------------------- | | pubClient | object | 可选,当 ioredis 作为适配器时的参数 | | subClient | object | 可选,当 ioredis 作为适配器时的参数 | | path | string | 可选,服务端 path | | adapter | object | socket.io-redis 适配器 | | connectTimeout | number | 客户端超时时间,单位 ms,默认值  *45000* | 更多的启动选项,请参考 [Socket.io 文档](https://socket.io/docs/v4/server-api/#new-Server-httpServer-options)。 ## 接入已有的 HTTP 服务[​](#接入已有的-http-服务 "接入已有的 HTTP 服务的直接链接") `@midwayjs/socketio`  默认支持和 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express`  的多框架部署。 当多个框架部署时,请把 HTTP 类型的框架作为主框架,Socket.io 将作为副框架加载,同时会自动找到当前的 HTTP 服务接入。 示例如下: ``` // bootstrap.js const WebFramework = require('@midwayjs/koa').Framework; const SocketFramework = require('@midwayjs/socketio').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载主 web 框架 const webFramework = new WebFramework().configure({ port: 7001, }); // 加载副 socket.io 框架,自动适配主框架,这里不需要配置 port const socketFramework = new SocketFramework().configure({}); Bootstrap.load(webFramework).load(socketFramework).run(); ``` ## Appliation(io 对象)[​](#appliationio-对象 "Appliation(io 对象)的直接链接") 传统的 Socket.io 服务端创建代码如下: ``` const io = require('socket.io')(3000); io.on('connection', (socket) => { // ... }); ``` 在 `@midwayjs/socketio` 框架中,Application 实例即为该 io 实例,类型和能力保持一致。即通过 `@App` 装饰器注入的 app 实例,即为 io 对象。 我们可以通过该对象做一些全局的事情。 比如获取所有的 socket 实例。 ``` // 返回所有的 socket 实例 const sockets = await app.fetchSockets(); // 返回所有的在 room1 的 socket 实例 const sockets = await app.in('room1').fetchSockets(); // 返回特定 socketId 的实例 const sockets = await app.in(theSocketId).fetchSockets(); ``` 更多的 io API,请参考 [Socket.io Server instance 文档](https://socket.io/docs/v4/server-instance/)。 ## 多框架场景[​](#多框架场景 "多框架场景的直接链接") 多框架下,主框架一般为 Web 框架,我们可以通过指定 key 获取 Socket.io 的 app。 ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Provide, Controller, App, MidwayFrameworkType } from '@midwayjs/decorator'; @Provide() @Controller() export class UserController { @App(MidwayFrameworkType.WS_IO) socketApp: SocketApplication; } ``` 这样我们可以通过 `@midwayjs/socketio` 的 app 对象(等价于 io),调用现有的 socket 连接。 比如,HTTP 请求调用进来对特定 namespace 下的所有客户端广播: ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Provide, Controller, App, Get, MidwayFrameworkType } from '@midwayjs/decorator'; @Provide() @Controller() export class UserController { @App(MidwayFrameworkType.WS_IO) socketApp: SocketApplication; @Get() async invoke() { // 对 / 下的连接做广播 this.socketApp.of('/').emit('hi', 'everyone'); } } ``` 多框架场景下,测试和启动都有一定变化,请参考 [多框架研发](/docs/2.0.0/multi_framework_start.md#4r5Xm) 。 ## 常见 API[​](#常见-api "常见 API的直接链接") ### 获取连接数[​](#获取连接数 "获取连接数的直接链接") ``` const count = app.engine.clientsCount; // 获取所有的连接数 const count app.of('/').sockets.size; // 获取单个 namespace 里的连接数 ``` ### 修改 sid 生成[​](#修改-sid-生成 "修改 sid 生成的直接链接") ``` const uuid = require('uuid'); app.engine.generateId = (req) => { return uuid.v4(); // must be unique across all Socket.IO servers }; ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 服务端/客户端没连上,没响应[​](#服务端客户端没连上没响应 "服务端/客户端没连上,没响应的直接链接") 1、端口服务端和客户端一致 ``` const { Framework } = require('@midwayjs/socketio'); const io = require('socket.io-client'); // server const socketFramework = new Framework().configure({ port: 7001, // 这里的端口 }); ``` 和下面的端口要一致。 ``` // client const socket = io('************:7001', { //... }); // midway 的测试客户端 const client = await createSocketIOClient({ port: 7001, }); ``` 2、服务端的 path 和客户端的 path 要保持一致。path 指的是启动参数的部分。 ``` // bootstrap.js const { Framework } = require('@midwayjs/socketio'); const io = require('socket.io-client'); // server const socketFramework = new Framework().configure({ port: 7001, path: '/testPath', // 这里是服务端 path }); // client const socket = io('************:7001', { path: '/testPath', // 这里是客户端的 path }); // midway 的测试客户端 const client = await createSocketIOClient({ path: '/testPath', }); ``` 3、服务端的 namespace 和客户端的 namespace 要保持一致。 ``` // server @Provide() @WSController('/test') // 这里是服务端的 namespace export class HelloController {} // client const io = require('socket.io-client'); io('*****:3000/test', {}); // 这里是客户端的 namespace // midway 的测试客户端 const client = await createSocketIOClient({ namespace: '/test', }); ``` ### 配置 CORS[​](#配置-cors "配置 CORS的直接链接") 如果出现跨域错误,需要在启动的时候配置 cors 信息。 ``` // bootstrap.js const { Framework } = require('@midwayjs/socketio'); const socketFramework = new Framework().configure({ port: 7001, cors: { origin: 'http://localhost:8080', methods: ['GET', 'POST'], }, }); ``` 具体参数可以参考 [Socket.io Handling CORS](https://socket.io/docs/v4/handling-cors/)。 --- # 创建第一个应用 ## 快速初始化[​](#快速初始化 "快速初始化的直接链接") ``` $ npm -v # 如果是 npm v6 $ npm init midway --type=web my_midway_app # 如果是 npm v7 $ npm init midway -- --type=web my_midway_app ``` `my_midway_app`   是你即将创建的项目根目录名,CLI 会自动创建该目录,并将初始化示例代码写入其中。 流程示例如下(npm7 效果): ![](https://cdn.nlark.com/yuque/0/2021/svg/501408/1617863129019-55f49eaa-4507-4bd5-9481-1e59d6295103.svg#height=776\&id=iYjWX\&margin=%5Bobject%20Object%5D\&name=create.svg\&originHeight=776\&originWidth=1390\&originalType=binary\&ratio=1\&size=119483\&status=done\&style=none\&width=1390) 信息 可以使用 `npm init midway`  查看完整的脚手架列表,选中某个项目后,Midway 会自动创建示例目录,代码,以及安装依赖。 ![](https://cdn.nlark.com/yuque/0/2021/svg/501408/1619947815582-6283808a-b092-439b-b47f-f8a98852d2ed.svg#clientId=ub91e37c7-a0d3-4\&from=ui\&id=uc666f20c\&margin=%5Bobject%20Object%5D\&name=create-with-cli.svg\&originHeight=928\&originWidth=1770\&originalType=binary\&ratio=1\&size=122976\&status=done\&style=none\&taskId=uc9e17831-bc48-4ee0-a3ca-11de139c454) **可能会碰到的问题:** 警告 1、在 node15/npm7 下执行 `npm install/i` 命令安装依赖可能会有 Python 编译错误 **使用 npm init midway 创建的项目会自动安装依赖,无此问题。** **解决方案**:npm i 时添加 `--legacy-peer-deps`  参数。 **原因**:测试框架 Jest 依赖 jsdom,npm7 会自动安装其 peerDependencies 中依赖的 canvas 包, 而 canvas 的安装编译需要有 python3 环境。 警告 2、在安装依赖时会有 npm warn: deprecated 输出 **原因**:测试框架 Jest 依赖 jsdom,其依赖了已废弃的模块 request,目前 jsdom 尚未解决此问题,我们会持续进行跟踪,相关问题参看: 警告 3、windows 可能会碰到 eslint 报错的问题,请关注 [windows 下换行问题](/docs/2.0.0/git_problem.md#XCAgm)。 示例将创建一个类似下面的目录结构,其中最精简的 Midway 项目示例如下。 ``` ➜ my_midway_app tree . ├── src ## midway 项目源码 │   └── controller ## Web Controller 目录 │      └── home.ts ├── test ├── package.json └── tsconfig.json ``` 整个项目包括了一些最基本的文件和目录。 * `src`  整个 Midway 项目的源码目录,你之后所有的开发源码都将存放于此 * `test`  项目的测试目录,之后所有的代码测试文件都在这里 * `package.json`  Node.js 项目基础的包管理配置文件 * `tsconfig.json`  TypeScript 编译配置文件 除了整个目录,我们还有一些其他的目录,比如 `controller`  目录。 ## 开发习惯[​](#开发习惯 "开发习惯的直接链接") Midway 对目录没有特别的限制,但是我们会遵守一些简单的开发习惯,将一部分常用的文件进行归类,放到一些默认的文件夹中。 以下 ts 源码文件夹均在 `src`  目录下。 常用的有: * `controller` Web Controller 目录 * `middleware` Web 中间件目录 * `service` 服务逻辑目录 * `entity`  或 `model`   数据库实体目录 * `config`  业务的配置目录 * `util` 工具类存放的目录 * `interface.ts`  业务的 ts 定义文件 随着不同场景的出现,目录的习惯也会不断的增加,具体的目录内容会体现在不同的框架中。 ## Web 框架选择[​](#web-框架选择 "Web 框架选择的直接链接") Midway 设计之初就可以兼容多种上层框架,在 Web 场景默认封装了 Egg.js 作为上层的 Web 框架,同时,Midway 也提供了其他的 Web 框架选择,比如常见的 `Express`  和 `Koa` 。 这些上层框架都可以使用 Midway 提供的装饰器能力,但是 Midway 不会对特有的能力做出封装,比如 Egg.js 的插件体系,或者 Express 的中间件能力,如果你对其中的某个框架比较熟悉,或者希望使用特定框架的能力,就可以选择它作为你的主力 Web 框架。 | 名称 | 描述 | | ----------------- | --------------------------------------------------------------------------------------------------------- | | @midwayjs/web | 默认,Egg.js 是国内相对常用的 Web 框架,也在阿里的双促中经过稳定性考验,包含了比较多的默认插件。 | | @midwayjs/express | Express 是一个众所周知的 node.js 简约 Web 框架。 这是一个经过实战考验,适用于生产的库,拥有大量社区资源。 | | @midwayjs/koa | Koa 是一个 Express 的替代框架,它默认支持了异步中间件等能力,是第二大通用的 Node.js Web 框架。 | 如果你希望替代默认的 Web 框架,请参考对应的框架章节。 ## 启动项目[​](#启动项目 "启动项目的直接链接") ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 `http://127.0.0.1:7001` ,浏览器会打印出 `Hello midwayjs!`   的信息。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600531997433-eee21874-3f72-4ebf-bcfa-baa6c97ce4bf.png#height=384\&id=JfkIS\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=768\&originWidth=1268\&originalType=binary\&ratio=1\&size=85918\&status=done\&style=none\&width=634) 如果需要修改开发的启动端口,可以在 `package.json`  的 scripts 段落里修改,如修改为 6001: ``` "scripts": { //... "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts --port=6001", }, ``` --- # 静态资源(Static File) 静态资源一般用来托管前端文件(js/css/html/png)等。 ## 在 @midwayjs/web 使用[​](#在-midwayjsweb-使用 "在 @midwayjs/web 使用的直接链接") Egg.js 默认提供了 static 插件,只需配置插件启用即可。 ``` // src/config/plugin.ts exports.static = true; ``` egg-static 插件基于 [koa-static-cache](https://github.com/koajs/static-cache) 模块,支持其所有的配置。 插件默认的 config 配置为: ``` { prefix: '/public/', dir: path.join(appInfo.baseDir, 'app/public'), } ``` `prefix` 表示 URL 路径前缀,dir 表示静态文件存放的位置。比如 `${baseDir}/app/public/a.js` 这个文件,在开启插件后,所访问的 URL 为 `http://127.0.0.1:7001/public/a.js` 。 更多配置,请查看 [koa-static-cache](https://github.com/koajs/static-cache) 文档。 ## 在 @midwayjs/koa 使用[​](#在-midwayjskoa-使用 "在 @midwayjs/koa 使用的直接链接") 和 Egg.js 类似,我们可以直接引入 [koa-static-cache](https://github.com/koajs/static-cache) 模块。 ``` $ npm i koa-static-cache --save ``` 然后在 `configuration.ts` 中直接加入中间件即可。 下面的示例,我们将资源目录放到了项目目录下的 public 目录中。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/koa'; import * as staticCache from 'koa-static-cache'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( staticCache({ prefix: '/public/', dir: path.join(this.app.getAppDir(), 'public'), }) ); } } ``` 更多配置,请查看 [koa-static-cache](https://github.com/koajs/static-cache) 文档。 ## 在 @midwayjs/express 使用[​](#在-midwayjsexpress-使用 "在 @midwayjs/express 使用的直接链接") Express 中自带了 static 的支持,直接在 `configuration.ts` 中直接加入中间件即可。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/express'; import * as express from 'express'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use(express.static('public')); } } ``` 现在,可以访问位于 public 目录中的文件: ``` http://localhost:3000/images/kitten.jpg http://localhost:3000/css/style.css http://localhost:3000/js/app.js http://localhost:3000/images/bg.png http://localhost:3000/hello.html ``` 警告 注意:Express 相对于静态目录查找文件,因此静态目录的名称不是此 URL 的一部分。 如果你想修改路由,可以通过下面的 API。 ``` app.use('/static', express.static(path.join(__dirname, 'public'))); ``` 更多配置,请参考 [express 文档](https://expressjs.com/en/starter/hello-world.html)。 ## 在 Serverless 场景使用[​](#在-serverless-场景使用 "在 Serverless 场景使用的直接链接") Serverless 场景较为特殊,网关不支持流式处理,所以在使用时,需要寻找支持 buffer 返回的库。 [koa-static-cache](https://github.com/koajs/static-cache) 模块支持 buffer 返回。 ``` $ npm i koa-static-cache --save ``` 然后在 `configuration.ts` 中直接加入中间件。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { Application } from '@midwayjs/faas'; import * as staticCache from 'koa-static-cache'; @Configuration() export class AutoConfiguration { @App() app: Application; async onReady() { this.app.use( staticCache({ prefix: '/public/', dir: join(__dirname, '../public'), dynamic: true, preload: false, buffer: true, // 注意,这里是 true maxFiles: 1000, }) ); } } ``` 在 **非高密度场景**下(普通函数),需要提供一个 `/*` 的路由函数,否则不会进入函数逻辑(自然就走不到中间件中)。 比如,为了中间件可进入,我们增加一个空的 `Get /public/*` 的路由即可(写 `public/*` 的目的是防止其他非 public 静态资源的路由走到这个函数)。 ``` import { Inject, Provide, Controller, Get } from '@midwayjs/decorator'; import { Context } from '@midwayjs/faas'; @Provide() export class ServerlessHelloService { @Inject() ctx: Context; // 普通路由 @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/:user_id', method: 'get', }) async hello1() { return 22; } @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/public/*', method: 'get', }) async render() { // 这个函数的作用是为了让 static 全局中间件被执行。 } } ``` 更多配置,请参考 [koa-static-cache](https://github.com/koajs/static-cache) 模块文档。 --- # 测试 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 所以,应用的 Controller、Service 等代码,都必须有对应的单元测试保证代码质量。 当然,框架和组件的每个功能改动和重构都需要有相应的单元测试,并且要求尽量做到修改的代码能被 100% 覆盖到。 ## 测试目录结构[​](#测试目录结构 "测试目录结构的直接链接") 我们约定 `test` 目录为存放所有测试脚本的目录,测试所使用到的 `fixtures` 和相关辅助脚本都应该放在此目录下。 测试脚本文件统一按 `${filename}.test.ts` 命名,必须以 `.test.ts` 作为文件后缀。 一个应用的测试目录示例: ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.test.ts ├── package.json └── tsconfig.json ``` ## 测试运行工具[​](#测试运行工具 "测试运行工具的直接链接") Midway 默认提供 `midway-bin`  命令来运行测试脚本。在新版本中,Midway 默认将 mocha 替换成了 Jest,它的功能更为强大,集成度更高,这让我们**聚焦精力在编写测试代码**上,而不是纠结选择那些测试周边工具和模块。 只需要在 `package.json` 上配置好 `scripts.test` 即可。 ``` { "scripts": { "test": "midway-bin test --ts" } } ``` 然后就可以按标准的 `npm test` 来运行测试了,默认脚手架中,我们都已经提供了此命令,所以你可以开箱即用的运行测试。 ``` ➜ my_midway_app npm run test > my_midway_project@1.0.0 test /Users/harry/project/application/my_midway_app > midway-bin test Testing all *.test.ts... PASS test/controller/home.test.ts PASS test/controller/api.test.ts Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.26 s Ran all test suites matching /\/test\/[^.]*\.test\.ts$/i. ``` ## 断言库[​](#断言库 "断言库的直接链接") jest 中自带了强大的 `expect`  断言库,可以直接在全局使用它。 比如常用的。 ``` expect(result.status).toBe(200); // 值是否等于某个值,引用相等 expect(result.status).not.toBe(200); expect(result).toEqual('hello'); // 简单匹配,对象属性相同也为 true expect(result).toStrictEqual('hello'); // 严格匹配 expect(['lime', 'apple']).toContain('lime'); // 判断是否在数组中 ``` 更多断言方法,请参考文档 ## 创建测试[​](#创建测试 "创建测试的直接链接") 不同的上层框架的测试方法不同,以最常用的 HTTP 服务举例,如果需要测试一个 HTTP 服务,一般来说,我们需要创建一个 HTTP 服务,然后用客户端请求它。 Midway 提供了一套基础的 `@midwayjs/mock`  工具集,可以帮助上层框架在这方面进行测试。同时也提供了方便的创建 Framework,App ,以及关闭的方法。 整个流程方法分为几个部分: * `createApp`  创建某个 Framework 的 app 对象 * `close`  关闭一个 Framework 或者一个 app 为保持测试简单,整个流程目前就透出这两个方法。 ``` // create app const app = await createApp(); ``` 这里传入的 `Framework`  是用来给 TypeScript 推导类型的。这样就可以返回对应的框架 app 实例了。 当 app 运行完成后,可以使用 `close`  方法关闭。 ``` import { createApp, close } from '@midwayjs/mock'; await close(app); ``` 事实上, `createApp`  方法中都是封装了 `@midwayjs/bootstrap` ,有兴趣的小伙伴可以阅读源码。 ## 测试 HTTP 服务[​](#测试-http-服务 "测试 HTTP 服务的直接链接") 除了创建 app 之外, `@midwayjs/mock`  还提供了简单的客户端方法,用于快速创建各种服务对应的测试行为。 比如,针对 HTTP,我们封装了 supertest,提供了 `createHttpRequest`  方法创建 HTTP 客户端。 ``` // 创建一个客户端请求 const result = await createHttpRequest(app).get('/'); // 测试返回结果 expect(result.text).toBe('Hello Midwayjs!'); ``` 推荐在一个测试文件中复用 app 实例。完整的测试示例如下。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import { Application } from 'egg'; // 从特定的框架获取 App 定义 import * as assert from 'assert'; describe('test/controller/home.test.ts', () => { let app: Application; beforeAll(async () => { // 只创建一次 app,可以复用 try { // 由于Jest在BeforeAll阶段的error会忽略,所以需要包一层catch // refs: https://github.com/facebook/jest/issues/8688 app = await createApp(); } catch (err) { console.error('test beforeAll error', err); throw err; } }); afterAll(async () => { // close app await close(app); }); it('should GET /', async () => { // make request const result = await createHttpRequest(app).get('/').set('x-timeout', '5000'); // use expect by jest expect(result.status).toBe(200); expect(result.text).toBe('Hello Midwayjs!'); // or use assert assert.deepStrictEqual(result.status, 200); assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); }); it('should POST /', async () => { // make request const result = await createHttpRequest(app).post('/').send({ id: '1' }); // use expect by jest expect(result.status).toBe(200); }); }); ``` **示例:** 创建 get 请求,传递 query 参数。 ``` const result = await createHttpRequest(app).get('/set_header').query({ name: 'harry' }); ``` 创建 post 请求,传递 body 参数。 ``` const result = await createHttpRequest(app).post('/user/catchThrowWithValidate').send({ id: '1' }); ``` 创建 post 请求,传递 form body 参数。 ``` const result = await createHttpRequest(app).post('/param/body').type('form').send({ id: '1' }); ``` 传递 header 头。 ``` const result = await createHttpRequest(app) .get('/set_header') .set({ 'x-bbb': '123', }) .query({ name: 'harry' }); ``` 传递 cookie。 ``` const cookie = [ 'koa.sess=eyJuYW1lIjoiaGFycnkiLCJfZXhwaXJlIjoxNjE0MTQ5OTQ5NDcyLCJfbWF4QWdlIjo4NjQwMDAwMH0=; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly', 'koa.sess.sig=mMRQWascH-If2-BC7v8xfRbmiNo; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly', ]; const result = await createHttpRequest(app).get('/set_header').set('Cookie', cookie).query({ name: 'harry' }); ``` ## 测试服务[​](#测试服务 "测试服务的直接链接") 在控制器之外,有时候我们需要对单个服务进行测试,我们可以从依赖注入容器中获取这个服务。 假设需要测试 `UserService` 。 ``` // src/service/user.ts import { Provide } from '@midwayjs/decorator'; @Provide() export class UserService { async getUser() { // xxx } } ``` 那么在测试代码中这样写。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 Id 获取实例 const userService = await app.getApplicationContext().getAsync('userService'); // 根据依赖注入 class 获取实例 const userService = await app.getApplicationContext().getAsync(UserService); // 传入 class 忽略泛型也能正确推导 const userService = await app.getApplicationContext().getAsync(UserService); // close app await close(app); }); }); ``` 如果你的服务和请求相关联(ctx),可以使用请求作用域获取服务。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 Id 获取实例 const userService = await app.createAnonymousContext().requestContext.getAsync('userService'); // 也能传入 class 获取实例 const userService = await app.createAnonymousContext().requestContext.getAsync(UserService); // close app await close(app); }); }); ``` ## createApp 选项参数[​](#createapp-选项参数 "createApp 选项参数的直接链接") `createApp`  方法用于创建一个框架的 app 实例,通过传入泛型的框架类型,来使得我们推断出的 app 能够是该框架返回的 app。 比如: ``` import { Framework } from '@midwayjs/grpc'; // 这里的 app 能确保是 grpc 框架返回的 app const app = await createApp(); ``` `createApp`  方法其实是有参数的,它的方法签名如下。 ``` async createApp( appDir = process.cwd(), options: IConfigurationOptions = {}, customFrameworkName?: string | MidwayFrameworkType | any) ) ``` 第一个参数为项目的绝对根目录路径,默认为 `process.cwd()` 。 第二个参数为框架的启动参数,比如启动的端口等,由各个框架提供。 第三个参数为框架本身,一般用于自定义框架的测试,默认的框架在 API 内部已经有提供和排序。 比如,上面我们的示例,完整的写法为: ``` import { Framework } from '@midwayjs/grpc'; // 这里的 app 能确保是 grpc 框架返回的 app const app = await createApp(process.cwd(), { port: 6565 }, Framework); ``` ## close 选项参数[​](#close-选项参数 "close 选项参数的直接链接") `close`  方法用于关闭该 app 实例相关的框架。 ``` await close(app); ``` 其有一些参数。 ``` export declare function close( app: IMidwayApplication | IMidwayFramework, options?: { cleanLogsDir?: boolean; cleanTempDir?: boolean; sleep?: number; } ): Promise; ``` 第一个参数是 app 或者 framework 的实例。 第二个参数是个对象,在执行关闭时可以执行一些行为: * 1、 `cleanLogsDir`  默认为 false,控制测试完成后删除日志 logs 目录(windows 除外) * 2、 `cleanTempDir`  默认为 false,清理一些临时目录(比如 egg 生成的 run 目录) * 3、 `sleep`  默认为 50,单位毫秒,关闭 app 后延迟的时间(防止日志没有成功写入) ## 使用 bootstrap 文件测试[​](#使用-bootstrap-文件测试 "使用 bootstrap 文件��测试的直接链接") 默认情况下,你的单测和入口文件是隔离的,比如在测试 Web 时,单测是不会启动一个真实的端口。如果你希望直接使用 `bootstrap.js`  入口文件直接测试,那么可以在测试的时候传递入口文件信息。 和 dev/test 启动不同的是,使用 `bootstrap.js`  启动是一个真实的服务,会同时运行多个框架,创建出多个框架的 app 实例。 `@midwayjs/mock` 提供了 `createBootstrap` 方法做启动文件类型的测试。我们可以将入口文件 `bootstrap.js` 作为启动参数传入,这样 `createBootstrap` 方法会通过入口文件来启动代码。 ``` import { MidwayFrameworkType } from '@midwayjs/decorator'; it('should GET /', async () => { // create app const bootstrap = await createBootstrap(join(process.cwd(), 'bootstrap.js')); // 根据框架类型获取 app 实例 const app = bootstrap.getApp(MidwayFrameworkType.WEB_KOA); // expect and test // close bootstrap await bootstrap.close(); }); ``` 通过 `createBootstrap` 启动服务,默认的超时时间为 30s,我们可以通过参数修改它。 ``` import { createBootstrap } from '@midwayjs/mock'; import { MidwayFrameworkType } from '@midwayjs/decorator'; describe('/test/new.test.ts', () => { it('should GET /', async () => { // create app const bootstrap = await createBootstrap(join(process.cwd(), 'bootstrap.js'), { bootstrapTimeout: 10 * 1000, // 10s }); const app = bootstrap.getApp(MidwayFrameworkType.WEB_KOA); // expect and test // close bootstrap await bootstrap.close(); }); }); ``` ## 运行单个测试[​](#运行单个测试 "运行单个测试的直接链接") 和 mocha 的 `only`  不同,jest 的 `only`  方法只针对单个文件生效。 `midway-bin`  提供可以运行单个文件的能力。 ``` $ midway-bin test -f test/controller/api.ts ``` 这样可以指定运行某个文件的测试,再配合 `describe.only`  和 `it.only` ,这样可以只运行单个文件中的单个测试方法。 `midway-bin test --ts` 等价于直接使用 jest 的下面的命令。 ``` $ node --require=ts-node/register ./node_modules/.bin/jest ``` ## 自定义 Jest 文件内容[​](#自定义-jest-文件内容 "自定义 Jest 文件内容的直接链接") 一般情况下,Midway 工具链内置了 jest 配置,使得用户无需再添加该文件,但是有些特殊的场景下,比如使用 VSCode 或者 Idea 等编辑器,需要在可视化区域进行开发和测试时,可能会需要指定一个 `jest.config.js`  的场景,这种情况下,Midway 支持创建一个自定义的 jest 配置文件。 在项目根目录创建一个 `jest.config.js`  文件。 ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.test.ts ├── jest.config.js ├── package.json └── tsconfig.json ``` 内容如下,配置和标准的 jest 相同。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], }; ``` ## 常见设置[​](#常见设置 "常见设置的直接链接") 如果需要在单测前执行一些代码,可以增加 `jest.setup.js` ,增加配置如下。 ``` const path = require('path'); module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], setupFilesAfterEnv: ['/jest.setup.js'], // 预先读取 jest.setup.js }; ``` 警告 注意, `jest.setup.js` 只能使用 js 文件。 ### 示例一:测试代码时间较长的问题[​](#示例一测试代码时间较长的问题 "示例一:测试代码时间较长的问题的直接链接") 如果测试出现下面的错误,说明你的代码执行时间比较长(比如连接数据库,跑任务等),如果确定代码没有问题,就需要延长启动时间。 ``` Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout. ``` jest 默认时间为 **5000ms(5 秒钟)**,我们可以将它调整到更多。 我们可以在 `jest.setup.js` 文件中写入下面的代码,对 jest 超时时间做调整。 ``` // jest.setup.js jest.setTimeout(30000); ``` ### 示例二:全局环境变量[​](#示例二全局环境变量 "示例二:全局环境变量的直接链接") 同理, `jest.setup.js`  也可以执行自定义的代码,比如设置全局环境变量。 ``` // jest.setup.js process.env.MIDWAY_TS_MODE = 'true'; ``` ### 示例三:程序无法正常退出的处理[​](#示例三程�序无法正常退出的处理 "示例三:程序无法正常退出的处理的直接链接") 有时候,由于一些代码(定时器,监听等)在后台运行,导致单测跑完后会无法退出进程,对于这个情况,jest 提供了 `--forceExit` 参数。 ``` $ midway-bin test --ts --forceExit $ midway-bin cov --ts --forceExit ``` 也可以在自定义文件中,增加属性。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], forceExit: true, }; ``` ### 示例四:并行改串行执行[​](#示例四并行改串行执行 "示例四:并行改串行执行的直接链接") jest 默认为每个测试文件并行处理,如果测试代码中有启动端口等场景,并行处理可能会导致端口冲突而报错,这个时候需要加 `--runInBand` 参数,注意,这个参数只能加载命令中。 ``` $ midway-bin test --ts --runInBand $ midway-bin cov --ts --runInBand ``` ## 编辑器配置[​](#编辑器配置 "编辑器配置的直接链接") ### Jetbrain Webstorm/Idea 配置[​](#jetbrain-webstormidea-配置 "Jetbrain Webstorm/Idea 配置的直接链接") 在 Jetbrain 的编辑器使用,需要启用 "jest" 插件,由于使用了子进程的方式启动,我们依旧需要在启动时指定加载 `--require=ts-node/register` 。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1602178225943-8502d66a-0fa4-43b8-b133-4f2cc47acdbd.png#height=692\&id=a4cFb\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1384\&originWidth=2184\&originalType=binary\&ratio=1\&size=275268\&status=done\&style=none\&width=1092) ### VSCode 配置[​](#vscode-配置 "VSCode 配置的直接链接") 先搜索插件,安装 Jest Runner。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1617707260369-933cc245-e1e1-4ed2-8065-bc46026e7618.png#height=877\&id=ylNin\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=877\&originWidth=1242\&originalType=binary\&ratio=1\&size=193316\&status=done\&style=none\&width=1242) 打开配置,配置 jest 命令路径。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1617707314603-0a8ef997-8cea-493c-ab84-2ca76c0980dd.png#height=849\&id=JVfV0\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=849\&originWidth=1266\&originalType=binary\&ratio=1\&size=94311\&status=done\&style=none\&width=1266) 在 jest command 处填入 `node --require=ts-node/register ./node_modules/.bin/jest` 。 或者是在工作区文件夹 .vscode 里面设置 settings.json。 ``` { "jest.pathToJest": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles", "jestrunner.jestCommand": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles" } ``` 由于 jest runner 插件的调试使用的是 VSCode 的调试,需要单独配置 VSCode 的 launch.json。 在文件夹 .vscode 里面设置 launch.json ``` { "version": "0.0.1", "configurations": [ { "name": "Debug Jest Tests", "type": "node", "request": "launch", "runtimeArgs": [ "--inspect-brk", "--require=ts-node/register", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "--detectOpenHandles" ], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] } ``` ## 配置 alias paths[​](#配置-alias-paths "配置 alias paths的直接链接") tsc 将 ts 编译成 js 的时候,并不会去转换 import 的模块路径,因此当你在 `tsconfig.json`  中配置了 paths 之后,如果你在 ts 中使用 paths 并 import 了对应模块,编译成 js 的时候就有大概率出现模块找不到的情况。 解决办法是,要么不用 paths ,要么使用 paths 的时候只用来 import 一些声明而非具体值,再要么就可以使用 [tsconfig-paths](https://github.com/dividab/tsconfig-paths) 来 hook 掉 node 中的模块路径解析逻辑,从而支持 `tsconfig.json`  中的 paths。 ``` $ npm i tsconfig-paths --save-dev ``` 使用 tsconfig-paths 可以在 `src/configuration.ts`  中引入。 ``` // src/configuration.ts import 'tsconfig-paths/register'; ... ``` 信息 上述的方法只会对 dev 阶段( ts-node)生效。 在测试中,由于 Jest 的环境比较特殊,需要对 alias 再做一次处理,可以利用 Jest 的配置文件中的 `moduleNameMapper` 功能来替换加载到的模块,变相实现 alias 的功能。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], moduleNameMapper: { '^@/(.*)$': '/src/$1', }, }; ``` 注意,这里使用的 alias 前缀是 @符号,如果是其他的 alias 名,请自行修改。 ## 使用 mocha 替代 jest[​](#使用-mocha-替代-jest "使用 mocha 替代 jest的直接链接") 有些同学对 mocha 情有独钟,希望使用 mocha 作为测试工具。 可以使用 mocha 模式进行测试。 ``` $ midway-bin test --ts --mocha ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 信息 注意,由于 mocha 没有自带断言工具,需要使用其他如 assert,chai 等工具进行断言。 --- # midwayjs/cli `@midwayjs/cli`  是新版本的 Midway 体系工具链,和 Serverless,以及原应用的工具链进行了整合。 ## 基础入口[​](#基础入口 "基础入口的直接链接") `@midwayjs/cli` 提供了两个入口命令。 `midway-bin`  和 `mw`  命令。 当 `@midwayjs/cli` 安装到全局时,一般使用 `mw`  命令,比如 `mw new xxx` 。当安装到项目中,做 cli 工具时,我们一般使用 `midway-bin`  命令,但是请记住,这两个命令是相同的。 ## 命令[​](#命令 "命令的直接链接") ### new 新建项目[​](#new-新建项目 "new 新建项目的直接链接") 新建项目 ``` $ mw new [name] --template 指定远端的符合 light-generator 标准的脚手架包 --target 新建的项目目标位置 --type 新的项目类型,默认为 web,可选的为faas等 --npm npm client,默认为自动识别添加registry ``` 可用 `--template`  指定远端的符合 [light-generator](https://github.com/midwayjs/light-generator) 标准的脚手架包。 比如: ``` $ mw new hello_midway --template=@midwayjs-examples/applicaiton-koa ``` ### dev 本地开发[​](#dev-本地开发 "dev 本地开发的直接链接") 以当前目录启动本地开发命令。 ``` $ mw dev --ts --baseDir 应用目录,一般为 package.json 所在文件夹,默认为 process.cwd() --sourceDir ts代码目录,默认会自动分析 -p, --port dev侦听的端口,默认为 7001 --ts TS模式运行代码 --fast 极速模式 --framework 指定框架,默认会自动分析 -f, --entryFile 指定使用入口文件来启动 bootstrap.js --watchFile 更多的文件或文件夹修改侦听 --notWatch 代码变化时不自动重启 ``` 可以针对 HTTP 场景修改启动端口 。 ``` $ midway-bin dev --ts --port=7002 ``` #### 参数详解[​](#参数详解 "参数详解的直接链接") * `--baseDir`:指定应用目录,一般为 package.json 所在文件夹,默认为 process.cwd() ``` midway-bin dev --ts --baseDir=./app ``` * `--sourceDir`:指定 ts 代码目录,默认会自动分析 ``` midway-bin dev --ts --sourceDir=./app/src ``` * `-p` 或 `--port`:指定本地 dev server 侦听的端口,默认为 7001 ``` midway-bin dev --ts --port=7002 ``` * `--ts`:使用 TS 模式运行代码 ``` midway-bin dev --ts ``` * `--fast`:极速模式,更快速的 dev server 启动和重启 ``` // 使用 ts-node 的快速dev模式 midway-bin dev --ts --fast // 使用 esbuild 的快速dev模式 midway-bin dev --ts --fast=esbuild ``` * `--framework`:指定启动 dev server 使用的框架,默认会根据代码自动分析 ``` midway-bin dev --ts --framework=@midwayjs/faas ``` * `-f` 或 `--entryFile`:指定使用入口文件来启动 ``` midway-bin dev --ts --entryFile=bootstrap.js ``` * `--watchFile`:指定更多的文件或文件夹修改侦听,默认侦听 `sourceDir` 目录中 `.ts`、`.yml`和 `.json`结尾的文件(可通过 --watchExt 参数指定更多扩展名),以及 `baseDir` 目录中的 `f.yml` 文件 ``` // 指定多个文件,使用英文逗号分隔 midway-bin dev --ts --watchFile=./a.txt,./b.txt // 指定多个文件夹和文件,使用英文逗号分隔 midway-bin dev --ts --watchFile=./test,./b.txt ``` * `--watchExt`:指定更多的侦听文件扩展名,默认为 `.ts`、`.yml`和 `.json` ``` // 指定多个文件扩展名,使用英文逗号分隔 midway-bin dev --ts --watchExt=.js,.html ``` ### 本地单步 Debug 调试[​](#本地单步-debug-调试 "本地单步 Debug 调试的直接链接") * 支持 `--debug` 参数启动 debug 模式,可以通过 `chrome devtools` 进行单步代码调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994136312-f1eda8ba-165d-4322-82b8-b21d3b9c6beb.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=177\&id=z4u1f\&margin=%5Bobject%20Object%5D\&name=69456694-513D-4388-B52F-001562D4A520.png\&originHeight=666\&originWidth=1538\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=276022\&status=done\&style=none\&taskId=ud161d835-1e96-4246-8061-c795e9a0ff1\&title=\&width=409) 您可以通过 `chrome://inspect/` 打开 `nodejs devtools` 进行断点调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995391144-a9ec0d4a-c6fb-4638-a292-615a3588d33d.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=236\&id=u4986bfa4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=1948\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=572568\&status=done\&style=none\&taskId=u07555349-8e09-42b2-bd94-f93160b0431\&title=\&width=488) ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995418427-282d256a-de65-4eba-9a83-b474d3d74f9f.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=445\&id=u83271ad1\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1280\&originWidth=2280\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=710504\&status=done\&style=none\&taskId=uc2614db9-dea9-48d7-b87d-8cb608c8770\&title=\&width=792) 您也可以直接通过 chrome 浏览器打开命令行中输出的 `devtools` 协议的链接,给对应代码添加断点后调试: ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994137067-f663409a-483d-41f5-bc86-4798182edb38.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=135\&id=GooAh\&margin=%5Bobject%20Object%5D\&name=10016148-385E-46A4-8B3A-0A0110BECD18.png\&originHeight=950\&originWidth=2878\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=744085\&status=done\&style=none\&taskId=u892d9925-9206-4946-a1ed-cb6043c557d\&title=\&width=409) * 如果您使用 `vscode` ,那么您可以使用 vscode 的 js debug terminal,在其中执行 dev 命令(无需添加 `--debug` 参数)启动就可以打断点调试了。 ![](https://cdn.nlark.com/yuque/0/2021/png/128621/1625237917317-8e7bf448-fded-4bc7-b743-6aade0ebcba2.png#clientId=u7c8a3183-c32b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=650\&id=u75e3aec7\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1300\&originWidth=2868\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=1140427\&status=done\&style=none\&taskId=ubcffa6c8-02eb-4256-ba7e-7ab3128c1ee\&title=\&width=1434) ### test 单元测试[​](#test-单元测试 "test 单元测试的直接链接") 以当前目录启动测试,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin test --ts -c, --cov 获取代码测试覆盖率 -f, --file 指定测试文件,例如 ./test/index.test.ts --ts TS模式运行单测 --forceExit jest forceExit --runInBand jest runInBand -w, --watch watch模式 --mocha 使用 mocha 进行单测 ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 信息 如果项目中使用了 TypeScript 的 path alias,请参考:[midway\_v2/testing](/docs/testing.md#BKmhH) 单测编写文档请参阅:[Serverless 函数的单测](/docs/serverless_testing) ### cov 单测覆盖率[​](#cov-单测覆盖率 "cov 单测覆盖率的直接链接") 以当前目录启动测试,并输出覆盖率信息,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin cov --ts ``` 使用 mocha 进行单测覆盖率时,除 `mocha` 和 `@types/mocha` 两个依赖外,还需要安装 `nyc` 到 `devDependencies` 中:`npm i nyc -D` 。 ### check 问题检测[​](#check-问题检测 "check 问题检测的直接链接") 自动分析代码中存在的问题,并给出修复建议。 ``` $ midway-bin check ``` 目前已提供 31 项问题的校验。 ### build 本地构建[​](#build-本地构建 "build 本地构建的直接链接") 使用 mwcc(tsc)进行 ts 代码编译,适用于非 Serverless 项目,Serverless 项目请使用 package。 ``` $ midway-bin build -c -c, --clean 清理构建结果目录 --srcDir 源代码目录,默认 src --outDir 构建输出目录,默认为 tsconfig 中的 outDir 或 dist --tsConfig tsConfig json 字符串或文件位置 --buildCache 保留构建缓存 ``` * `c`  `clean`  清理构建目录 ### deploy 函数发布[​](#deploy-函数发布 "deploy 函数发布的直接链接") 适用于 Serverless 项目发布到 Aliyun FC、Tencent SCF、Aws Lambda 等运行时。 执行 deploy 命令会自动执行 package。 ``` $ midway-bin deploy -y, --yes 发布的确认都是yes --resetConfig 重置发布配置,AK/AK/Region等 --serverlessDev 使用 Serverless Dev 进行aliyun fc函数发布,目前默认为 funcraft ...兼容package命令的所有参数 ``` #### 函数发布时域名配置[​](#函数发布时域名配置 "函数发布时域名配置的直接链接") 在 `f.yml` 中配置 `custom.customDomain` 为 `auto` ,则在发布时会配置一个临时的自动域名: ``` custom: customDomain: auto ``` 如果要取消自动的域名,将 `customDomain` 改为 `false`: ``` custom: customDomain: false ``` 如果有自定义域名,在 `customDomain` 中配置即可: ``` custom: customDomain: test.example.com ``` ### package 函数打包[​](#package-函数打包 "package 函数打包的直接链接") 适用于 Serverless 项目构建 ``` $ midway-bin package --npm npm client,默认为自动识别添加registry --sourceDir 源代码所在目录,默认会自动分析 --buildDir 构建结果目标目录 --sharedTargetDir 共享文件目标目录,默认为static,参考 --sharedDir 参数 --sharedDir 构建时会拷贝此目录到结果目录内的 $sharedTargetDir 目录 --skipZip 跳过zip打包 --skipBuild 跳过ts代码构建 --tsConfig tsConfig json 字符串或文件位置 --function 指定打包哪几个函数,多个使用英文 , 分隔 ``` #### 参数详解[​](#参数详解-1 "参数详解的直接链接") * `--function`:指定打包哪几个函数,多个函数使用英文 , 分隔 ``` // 打包 midway-bin package --function=a,b,c // 发布 midway-bin deploy --function=a,b,c ``` #### #### 函数构建打包时文件拷贝逻辑[​](#函数构建打包时文件拷贝逻辑 "函数构建打包时文件拷贝逻辑的直接链接") 默认拷贝的内容包含 `后端代码文件夹` (一般为 `src` 、faas 前后端一体化一般为 `src/apis`)内的所有非 `.ts` 后缀的文件,以及 `项目根目录` 下的以 `.js`、`.json`、`.yml` 为扩展名的所有文件和 `config` 、`app` 文件夹内的所有文件。 如果要拷贝额外的文件,可以通过在 `f.yml` 文件中添加 `package`字段 中的 `include` 来指定,可以配置文件名,也可以通过 `fast-glob` [语法 ↗](https://github.com/mrmlnc/fast-glob#pattern-syntax) 匹配,使用示例如下: ``` # ...已省略其他属性的展示 package: include: # 通过 include 属性指定额外打包文件配置 - static # 项目根目录下的 static 文件夹 - a.json # 项目根目录下的 a.json 文件 - a/b/c.js # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - a/b/c.json # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - xxx/**/*.js # 项目根目录下的 xxx 目录下的所有 js 文件 ``` ## 实验性功能[​](#实验性功能 "实验性功能的直接链接") 在 `f.yml` 中通过 `experimentalFeatures` 配置开启实验性功能 ### 1. ignoreTsError[​](#1-ignoretserror "1. ignoreTsError的直接链接") 在构建时忽略 ts error,不中断构建过程。 ``` experimentalFeatures: ignoreTsError: true ``` ### 2. removeUselessFiles[​](#2-removeuselessfiles "2. removeUselessFiles的直接链接") 在构建时移除大量无效文件,例如 `LICENSE`、`*.ts.map`、`**/test/` 等文件,可以有效减少构建包尺寸。 ``` experimentalFeatures: removeUselessFiles: true ``` ### 3. fastInstallNodeModules[​](#3-fastinstallnodemodules "3. fastInstallNodeModules的直接链接") 在构建时从当前的 devDependencies 中挑选出 production 依赖进行发布,可能会显著提升发布速度。 ``` experimentalFeatures: fastInstallNodeModules: true ``` ## [​](#-1 "-1的直接链接") ## 扩展[​](#扩展 "扩展的直接链接") ### 1. 生命周期扩展[​](#1-生命周期扩展 "1. 生命周期扩展的直接链接") 用户可以在 `package.json` 中添加 `midway-integration` 字段来根据各个命令的生命周期扩展 cli 的行为。 比如,在 package 命令 `installDevDep` 的后面添加自定义逻辑: ``` { "midway-integration": { "lifecycle": { "after:package:installDevDep": "npm run build" } } } ``` 其中 `lifecycle` 的格式为 `${ 'before' | 'after' | '' }:${ 命令 }:${ 命令生命周期 }` 。 package 命令的声明周期列表: ``` 'cleanup', // 清理构建目录 'installDevDep', // 安装开发期依赖 'copyFile', // 拷贝文件: package.include 和 shared content 'compile', // 'emit', // 编译函数 'package:after:tscompile' 'analysisCode', // 分析代码 'copyStaticFile', // 拷贝src中的静态文件到dist目录,例如 html 等 'checkAggregation', // 检测高密度部署 'generateSpec', // 生成对应平台的描述文件,例如 serverless.yml 等 'generateEntry', // 生成对应平台的入口文件 'installLayer', // 安装layer 'installDep', // 安装依赖 'package', // 函数打包 'finalize', // 完成 ``` ### [​](#-2 "-2的直接链接") ### 2. 通过插件进行扩展[​](#2-通过插件进行扩展 "2. 通过插件进行扩展的直接链接") 用户可以自己编写 cli 插件,通过插件来实现更为复杂的 cli 的行为,也可以添加自定义命令。 目前支持两种插件: * npm 插件,插件是一个 npm 包 * local 插件,插件在本地位置 * 通过在 f.yml 文件中配置 `plugins` 字段使 cli 加载插件: ``` plugins: - npm::test-plugin-model - local::./test/plugin ``` plugin 配置格式为: `${ 'npm' | 'local' }:${ provider || '' }:${ pluginName || path }` 插件的代码参考: ``` // src/index.ts import { BasePlugin } from '@midwayjs/command-core'; export class TestLalalaPlugin extends BasePlugin { commands = { lalala: { usage: '自定义命令', lifecycleEvents: [ 'a', // 自定义生命周期 'b', ], // 暂无 options: { name: { usage: '参数 name, 例如: mw lalala --name=123', shortcut: 'n', // 参数缩写 }, }, }, }; hooks = { // 添加当前插件内的命令生命周期扩展 // lalala 命令的 a 生命周期 'lalala:a': async () => { // 输出 this.core.cli.log('lalala command hook'); // 获取用户输入的参数 this.core.cli.log(this.core.options); // f.yml 内容 this.core.cli.log(this.core.service); // 仅在 -V 参数下输出的内容 this.core.debug('lalala'); }, // 添加其他插件内的命令生命周期扩展 // 在 package 命令的 copyFile 生命周期 “之前” 执行 'before:package:copyFile': async () => { console.log('package command hook'); }, }; } ``` --- # midwayjs/egg-ts-helper 针对 midway 支持 Egg.js 的场景,重写了原 [egg-ts-helper](https://github.com/whxaxes/egg-ts-helper) 包,移除了原有的 TS,AST 分析等大依赖。 原来的包依赖的 ts v3 环境,依赖 egg 的目录结构,考虑非常多的可能性,在 midway 的场景中不会使用到。基于上述考虑 midway 将此包进行了重写,用最简单的方式提供 egg 定义。 [@midwayjs/egg-ts-helper](https://github.com/midwayjs/egg-ts-helper) 包提供 `ets` 全局命令。 ``` $ npm i @midwayjs/egg-ts-helper --save-dev $ ets ``` 一般我们会在开发命令里加入。 ``` "scripts": { "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", }, ``` 信息 此包是针对 midway 定制的,只能用于新版本 midway 及其配套代码。 最终会在项目根目录生成 `typings` 目录,其定义结构和文件如下: ``` . ├── ... └── typings ├── extend │ ├── request.d.ts │ ├── response.d.ts │ ├── application.d.ts │   └── context.d.ts ├── app │   └── index.d.ts └── config ├── index.d.ts └── plugin.d.ts ``` 警告 注意,该模块只是将 midway v2(Egg.js)的框架 + 插件定义聚合到一起,让当前的业务代码能够顺利的读取到框架和插件的定义,不支持生成业务代码本身的定义,也不支持在开发 egg 插件时生成定义。 --- # 检查工具 Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。`@midwayjs/luckyeye`  包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 > luckyeye,寓意为幸运眼,能快速发现和定位问题。 ## 使用[​](#使用 "使用的直接链接") 首先安装 `@midwayjs/luckyeye`  包。 ``` npm i @midwayjs/luckyeye --save-dev ``` 一般情况下,我们会将它加入到一个检查脚本中,比如: ``` "scripts": { // ...... "check": "luckyeye" }, ``` 接下去,我们需要配置“规则包”,比如 `midway_v2`  就是针对 midway v2 版本的规则检查包。 在 `package.json`  中加入下面的段落。 ``` "midway-luckyeye": { "packages": [ "midway_v2" ] }, ``` ## 执行[​](#执行 "执行的直接链接") 配置完后,可以执行上面添加的检查脚本。 ``` npm run check ``` **蓝色**代表输出的信息,用于排错,**绿色**代表检查项通过,**红色**代表检查项有问题,需要修改,**黄色**代表检查项可以做修改,但是可选。 执行效果如下。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1610983986151-79c54e7c-3ff0-4f94-98bc-359dda0fa694.png#align=left\&display=inline\&height=464\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=928\&originWidth=1234\&size=155051\&status=done\&style=none\&width=617) ## 自定义规则包[​](#自定义规则包 "自定义规则包的直接链接") 请参考 的 README。 --- # Lint 工具、规则和格式化 Midway 的框架和业务代码都是由 TypeScript 编写的,默认 Midway 提供了一套默认的 lint、编辑器以及格式化规则,用于更方便的进行开发和测试。 ## 代码风格库[​](#代码风格库 "代码风格库的直接链接") Midway 的代码风格库叫 [mwts](https://github.com/midwayjs/mwts),源自于 Google 的 [gts](https://github.com/google/gts)。mwts 是 Midway 的 TypeScript 样式指南,也是格式化程序,linter 和自动代码修复程序的配置。 信息 在 midway 项目中,我们会默认添加 mwts,下面的流程只是为了说明如何使用 mwts。 为了使用 mwts,我们需要把它添加到开发依赖中。 ``` "devDependencies": { "mwts": "^1.0.5", "typescript": "^4.0.0" }, ``` ## ESLint 配置[​](#eslint-配置 "ESLint 配置的直接链接") mwts 提供了一套默认的 ESLint 配置(TSLint 已经废弃,合并到了 ESLint 中)。 在项目根目录创建 `.eslintrc.json`  文件,内容如下(一般脚手架会自带): ``` { "extends": "./node_modules/mwts/", "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "interface.ts"], "env": { "jest": true } } ``` 上面是 midway 项目的默认配置,其他项目 `ignorePatterns`  和 `env`  可以自行根据 ESLint 自行调整。 整个 mwts 的默认规则请参考 [这里](https://github.com/midwayjs/mwts/blob/master/.eslintrc.json),如有需求,可以自行调整。 ## 执行代码检查和格式化[​](#执行代码检查和格式化 "执行代码检查和格式化的直接链接") 可以通过执行 `mwts check`  命令和 `mwts fix`  命令,来检查代码。比如在项目中增加脚本命令(一般脚手架会自带)。 ``` "scripts": { "lint": "mwts check", "lint:fix": "mwts fix", }, ``` ## Prettier 配置[​](#prettier-配置 "Prettier 配置的直接链接") mwts 提供了一套默认的 prettier 配置,创建一个 `.prettierrc.js`   文件,配置内容如下即可(一般脚手架自带)。 ``` module.exports = { ...require('mwts/.prettierrc.json'), }; ``` ## 配置保存自动格式化[​](#配置保存自动格式化 "配置保存自动格式化的直接链接") 我们以 VSCode 为例。 第一步,安装 Prettier 插件。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618042429530-177c3636-aefc-419d-8d3a-5258cad13631.png#align=left\&display=inline\&height=536\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1072\&originWidth=800\&size=114476\&status=done\&style=none\&width=400) 打开配置,搜索 “save”,找到右侧的 "Format On Save",勾选即可。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618042494782-71b6cc3c-18ae-4344-987b-ec82084f2dd8.png#align=left\&display=inline\&height=788\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1576\&originWidth=2370\&size=341414\&status=done\&style=none\&width=1185) 如果保存文件没有效果,一般是编辑器有多个格式化方式,可以右键进行默认选择。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125271116-845e8452-0f7b-46a9-a28a-388f2db9c5e3.png#align=left\&display=inline\&height=458\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=916\&originWidth=564\&size=102932\&status=done\&style=none\&width=282)   选择 “配置默认格式化程序”。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125381302-d3fe30c1-e56d-43f8-ada2-6e315f4ff2c4.png#align=left\&display=inline\&height=144\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=288\&originWidth=990\&size=37986\&status=done\&style=none\&width=495) 选择 Prettier 即可。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125423564-8e46b0f8-f422-4e3d-a805-3b0a1db037f8.png#align=left\&display=inline\&height=104\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=208\&originWidth=1074\&size=35043\&status=done\&style=none\&width=537) --- # TypeORM Model Generator 感谢社区用户 @youtiao66 提供此模块。 通过该工具,你可以快速创建 for Midway 的 TypeORM Model。 ## 使用[​](#使用 "使用的直接链接") 比如生成 mysql 的 model。 ``` # 推荐 # 请替换配置信息 $ npx mdl-gen-midway -h localhost -p 3306 -d yourdbname -u root -x yourpassword -e mysql --noConfig --case-property none ``` 完整参数: ``` Usage: npx mdl-gen-midway -h -d -p [port] -u -x [password] -e [engine] Options: --help Show help [boolean] --version Show version number [boolean] -h, --host IP address/Hostname for database server [default: "127.0.0.1"] -d, --database Database name(or path for sqlite) [required] -u, --user Username for database server -x, --pass Password for database server [default: ""] -p, --port Port number for database server -e, --engine Database engine [choices: "mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"] [default: "mssql"] -o, --output Where to place generated models [default: "./output"] -s, --schema Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3 --ssl [boolean] [default: false] --noConfig Doesn't create tsconfig.json and ormconfig.json [布尔] [默认值: false] --cp, --case-property Convert property names to specified case [可选值: "pascal", "camel", "snake", "none"] [默认值: "camel"] ``` --- # 常见 TS 问题 TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 ## 依赖包定义错误[​](#依赖包定义错误 "依赖包定义错误的直接链接") 如果依赖包和项目本身的 TS 版本不一致,在编译时会出现错误。 可以在 `tsconfig.json`  关闭依赖包的检查。 ``` { "compilerOptions": { "skipLibCheck": true }, } ``` ## TS2564 初始化未赋值错误[​](#ts2564-初始化未赋值错误 "TS2564 初始化未赋值错误的直接链接") 错误如下: ``` error TS2564: Property 'name' has no initializer and is not definitely assigned in the constructor. ``` 原因为开启了 TS 的初始化属性检查,如果没有初始化赋值就会报错。 处理方法: 第一种:移除 tsconfig.json 的检查规则 ``` { "strictPropertyInitialization": false // 或者移除 } ``` 第二种:属性加感叹号 ``` export class HomeController { @Inject() userService!: UserService; } ``` ## TS6133 对象声明未使用错误[​](#ts6133-对象声明未使用错误 "TS6133 对象声明未使用错误的直接链接") 错误如下: ``` error TS6133: 'app' is declared but its value is never read. ``` 原因为开启了 TS 的对象未使用检查,如果声明了但是没有使用就会报错。 处理方法: 第一种:移除未定义的变量 第二种:移除 tsconfig.json 的检查规则 ``` { "compilerOptions": { "noUnusedLocals": false } } ``` ## tsconfig 中定义 typings 不生效[​](#tsconfig-中定义-typings-不生效 "tsconfig 中定义 typings 不生效的直接链接") 在 tsconfig.json 中,如果定义了 typeRoots,且定义了 include,如果 include 中不包含 typeRoot 中的内容,则会在 dev/build 时报错。 此为 ts/ts-node 的问题,issue 见 [#782](https://github.com/TypeStrong/ts-node/issues/782) [#22217](https://github.com/microsoft/TypeScript/issues/22217) 比如: ``` "typeRoots": [ "./node_modules/@types", "./typings" ], "include": [ "src", "typings" ], "exclude": [ "dist", "node_modules" ], ``` 上述,如果 include 中不写 typings,则会在 dev/build 时找不到定义而报错。 --- # 从 Midway v1 升级到 v2 ## 手动迁移步骤[​](#手动迁移步骤 "手动迁移步骤的直接链接") ### 1、midway 版本修改[​](#1midway-版本修改 "1、midway 版本修改的直接链接") 将原来的 `midway` 依赖替换为下列依赖。 ``` "dependencies": { "@midwayjs/bootstrap": "^2.3.0", "@midwayjs/decorator": "^2.3.0", "@midwayjs/web": "^2.3.0", "midway": "^2.3.0" }, ``` 信息 `midway` 库为 v1 的兼容导出包。 ### 2、开发期依赖修改[​](#2开发期依赖修改 "2、开发期依赖修改的直接链接") * `**@midwayjs/mock**` 2.x 本地开发的测试库 * `**@types/jest**` 2.x 将 mocha 升级为了 jest,这是 jest 定义库 * **`@types/node`** node 定义库,如有,可以升级 * **`cross-env`** 跨平台的代码执行库,如有,可升级 * **`@midwayjs/egg-ts-helper`** ,egg 定义生成工具,2.x 新加 * **`@midwayjs/cli`** 2.x 将原来的 midway-bin 工具升级为了 @midwayjs/cli 工具,命令不变,依旧是 midway-bin * **`mwts`** Midway 2.x lint 规则库 * **`typescript`** ts 库,可升级 整体如下: ``` "devDependencies": { "@midwayjs/mock": "^2.3.0", "@types/jest": "^26.0.10", "@types/node": "14", "cross-env": "^6.0.0", "@midwayjs/egg-ts-helper": "^1.0.1", "@midwayjs/cli": "^1.0.0", "mwts": "^1.0.5", "typescript": "^3.9.0" }, ``` 信息 注意,请移除 midway-bin 的包依赖。 **脚本部分** 基本只是调整了 lint 的部分,移除了 debug 命令。 ``` "scripts": { "start": "egg-scripts start --daemon --title=midway-server-midway_project --framework=midway", "stop": "egg-scripts stop --title=midway-server-midway_project", "start_build": "npm run build && cross-env NODE_ENV=development midway-bin dev", "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", "test": "midway-bin test", "cov": "midway-bin cov", "lint": "mwts check", "lint:fix": "mwts fix", "ci": "npm run cov", "build": "midway-bin build -c" }, ``` 现在 debug 变成了每个命令的参数,你可以在 dev 或者其他命令时增加 `--debug` 参数来开启调试。 ``` { "debug": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts --debug" } ``` 更多调试场景,请参考 [调试文档](/docs/2.0.0/debugger.md)。 ### 3、src 代码的修改[​](#3src-代码的修改 "3、src 代码的修改的直接链接") * 暂无 ### 4、测试代码的修改[​](#4测试代码的修改 "4、测试代码的修改的直接链接") Midway v2 版本开始,默认的单测框架将由 mocha 迁移至 jest。 **方案** jest 提供了 [codemod](https://github.com/skovhus/jest-codemods) 工具用于快速迁移。 ``` npx jest-codemods ``` **手动修改** * jest 中,全局的方法为 `beforeAll` , `afterAll` ,而 mocha 为 `before` 和 `after` ## 可选调整[​](#可选调整 "可选调整的直接链接") ### Midway 代理 Egg 的定义变更(可选)[​](#midway-代理-egg-的定义变更可选 "Midway 代理 Egg 的定义变更(可选)的直接链接") 原有 Midway 代理了一部分 EggJS 定义,在新版本 Midway 中,提供了更为明确的定义,老的定义,我们依旧在 `midway` 这个包上进行兼容,但是我们希望新编写的代码逐步使用新的定义。 **旧写法** ``` import { Context, EggAppConfig, EggApplication, Service } from 'midway'; ``` **新写法** ``` import { Context, EggAppConfig, EggApplication, Service } from 'egg'; ``` 涉及到的定义如下 | **旧写法** | **新写法** | | ----------------------------------------------- | ----------------------------------------------- | | `import { Context } from 'midway'` | `import { Context } from 'egg'` | | `import { IContextLocals } from 'midway'` | `import { IContextLocals } from 'egg'` | | `import { EggEnvType } from 'midway'` | `import { EggEnvType } from 'egg'` | | `import { IEggPluginItem } from 'midway'` | `import { IEggPluginItem } from 'egg'` | | `import { EggPlugin } from 'midway'` | `import { EggPlugin } from 'egg'` | | `import { PowerPartial } from 'midway'` | `import { PowerPartial } from 'egg'` | | `import { EggAppConfig } from 'midway'` | `import { EggAppConfig } from 'egg'` | | `import { FileStream } from 'midway'` | `import { FileStream } from 'egg'` | | `import { IApplicationLocals } from 'midway'` | `import { IApplicationLocals } from 'egg'` | | `import { EggApplication } from 'midway'` | `import { EggApplication } from 'egg'` | | `import { EggAppInfo } from 'midway'` | `import { EggAppInfo } from 'egg'` | | `import { EggHttpClient } from 'midway'` | `import { EggHttpClient } from 'egg'` | | `import { EggContextHttpClient } from 'midway'` | `import { EggContextHttpClient } from 'egg'` | | `import { Request } from 'midway'` | `import { Request } from 'egg'` | | `import { Response } from 'midway'` | `import { Response } from 'egg'` | | `import { Router } from 'midway'` | `import { Router } from 'egg'` | | `import { Service } from 'midway'` | `import { Service } from 'egg'` | | `import { Boot } from 'midway'` | `import { Boot } from 'egg'` | | `import { IBoot } from 'midway'` | `import { IBoot } from 'egg'` | | `import { IgnoreOrMatch } from 'midway'` | `import { IgnoreOrMatch } from 'egg'` | | | | | `import { EggLoggerLevel } from 'midway'` | `import { LoggerLevel } from 'egg-logger'` | | `import { EggLogger } from 'midway'` | `import { EggLogger } from 'egg-logger'` | | `import { EggLoggers } from 'midway'` | `import { EggLoggers } from 'egg-logger'` | | `import { EggContextLogger } from 'midway'` | `import { EggContextLogger } from 'egg-logger'` | ### 中间件定义调整(可选)[​](#中间件定义调整可选 "中间件定义调整(可选)的直接链接") **旧写法** ``` import { provide, KoaMiddleware, Context } from 'midway'; @provide() export class ReportMiddleware implements IWebMiddleware { resolve(): KoaMiddleware { return async (ctx: any, next: () => Promise) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime)); }; } } ``` **新写法** ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next: IMidwayWebNext) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime)); }; } } ``` ### 装饰器变更调整(可选)[​](#装饰器变更调整可选 "装饰器变更调整(可选)的直接链接") 主要是大小写的变化。原有的小写装饰器为了兼容继续从 `midway` 包上导出,大写装饰器将从 `@midwayjs/decorator` 中导出。 **旧写法** ``` import { provide, plugin, inject, get, controller } from 'midway'; ``` 新写法 ``` import { Provide, Plugin, Inject, Get, Controller } from '@midwayjs/decorator'; ``` ### providerWrapper 导出��置变更(可选)[​](#providerwrapper-导出置变更可选 "providerWrapper 导出��置变更(可选)的直接链接") **旧写法** ``` export { providerWrapper } from 'midway'; ``` **新写法** ``` export { providerWrapper } from '@midwayjs/core'; ``` ### 启动命令的调整(可选)[​](#启动命令的调整可选 "启动命令的调整(可选)的直接链接") 虽然 `midway` 包依旧可用,但是我们建议您将启动框架修改为 `@midwayjs/web` 。 ``` "scripts": { "start": "egg-scripts start xxxxxx --framework=midway", // 老写法 "start": "egg-scripts start xxxxxx --framework=@midwayjs/web" // 新写法 }, ``` ### 部署[​](#部署 "部署的直接链接") 警告 注意:我们不再支持内置文件的启动方式,即 `require('midway/server')` 来启动 midway 的用法。也不再支持 `midway-server-options` 这个选项。 如有需要,请修改为我们新版本的 bootstrap 部署方式(支持单进程,支持 pm2)。 ## Midway 升级变更速查表[​](#midway-升级变更速查表 "Midway 升级变更速查表的直接链接") 这里只列出 v1 到 v2 对用户代码层面变更的部分,不含新增的能力。 | | 描述 | 是否兼容 | | -------------- | ---- | -------- | | **框架变更项** | | | | 包版本的变化 | | | * midway -> 2 | √ | | 包的变化 | * midway-bin -> @midwayjs/cli * midway-mock -> @midwayjs/mock * @types/mocha -> @types/jest | 部分 | | 装饰器变为大写 | 从 midway 中导出继���兼容小写,现有装饰器都从 @midwayjs/decorator 导出 | √ | | egg 定义导出 | 先有的定义继续从 midway 导出,但是建议直接使用 egg 的定义 | √ | | container 的 loader 配置 | 转为 Configuration 的 imports 配置 | | | @Query,@Body,@Headers,@Session,@Param 装饰器空参数的行为变更 | 如果入参为空,则返回整个原始对象,而在 v2 版本中,行为做了调整,会根据当前的属性名获取对应的值 | | | | | | | **测试部分变更项** | | | | mocha 默认变更为 jest | 默认测试框架变更,方法相应有变化,before 变为 beforeAll,after 变为 afterAll,其他的 only 等方法的作用域有区别 | | | | | | | **部署部分变更项** | | | | egg-scripts 的启动命令 | 框架部分从 midway 变为 @midwayjs/web | √ | | require('midway/server')的方式 | 移除,不再支持 | | | midway-server-options 选项 | 移除,不再支持 | | ## 最后[​](#最后 "最后的直接链接") 在将定义导出迁移到新的方式之后,请移除 `midway` 包的依赖。 --- # 参数校验和转换 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 [joi](https://joi.dev/api/) ,同时也提供了参数的转换能力,这个能力来自于 `class-transformer` 。 ## 背景[​](#背景 "背景的直接链接") 最常用参数校验的地方是 控制器(Controller),同时你也可以在任意的 Class 中使用这个能力。 我们以控制器(Controller)中使用为例,还是那个 user。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ └── user.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 普通情况下,我们从 `body`  上拿到所有 Post 结果,并进行一些校验。 ``` // src/interface.ts export interface User { id: number; firstName: string; lastName: string; age: number; } // src/controller/home.ts import { Controller, Get, Provide, ALL } from '@midwayjs/decorator'; @Provide() @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body(ALL) user: User) { if (!user.id || typeof user.id !== 'number') { throw new Error('id error'); } if (user.age <= 30) { throw new Error('age not match'); } // xxx } } ``` 如果每个方法都需要这么校验,会非常的繁琐。 Midway 提供了 `@Validate`  和 `@Rule`  装饰器,用来**快速定义校验的规则**,帮助用户**减少这些重复的代码**。 ## 适用场景[​](#适用场景 "适用场景的直接链接") * HTTP 请求 * Websocket 的处理场景 * MQ 的处理场景 * Task 的处理场景 * service 等其他场景 ## 定义检查规则[​](#定义检查规则 "定义检查规则的直接链接") 按照上面的逻辑,我们需要 **重新定义一个新的 Class**,因为装饰器只能装饰在实际的 Class 上,而不是 interface。 为了方便后续处理,我们将 user 放到一个 `src/dto`  目录中。 > Data Transfer Object(数据传输对象)DTO 是一组需要跨进程或网络边界传输的聚合数据的简单容器。它不应该包含业务逻辑,并将其行为限制为诸如内部一致性检查和基本验证之类的活动。 ``` // src/dto/user.ts import { Rule, RuleType } from '@midwayjs/decorator'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } ``` 信息 由于这个类属于一个 `PlainObject` ,也不需要被依赖注入管理,我们不需要提供 `@Provide` 装饰器。 这个 User Class 提供了三个属性和他们对应的校验规则。 * `id`  一个必填的数字类型 * `firstName`  一个必填的字符串类型 * `lastName` 一个可选的最长为 10 的字符串类型 * `age`  一个最大不超过 60 的数字 `@Rule`  装饰器用于 **修饰需要被校验的属性**,它的参数为 `RuleType`  对象提供的校验规则的链式方法。 信息 这里的 `RuleType` 即为 joi 对象本身。 [joi](https://joi.dev/api/) 提供了非常多的校验类型,还可以对对象和数组中的字段做校验,还有例如字符串常用的 `RuleType.string().email()` ,以及 `RuleType.string().pattern(/xxxx/)`  正则校验等,具体可以查询 [joi](https://joi.dev/api/) 的 API 文档。 ## 校验参数[​](#校验参数 "校验参数的直接链接") 定义完类型之后,就可以直接在业务代码中使用了,开启校验能力还需要 `@Validate`  装饰器。 ``` // src/controller/home.ts import { Controller, Get, Provide, ALL } from '@midwayjs/decorator'; import { UserDTO } from './dto/user'; @Provide() @Controller('/api/user') export class HomeController { @Post('/') @Validate() async updateUser(@Body(ALL) user: UserDTO) { // user.id } } ``` 所有的校验代码都通通不见了,业务变的更纯粹了,当然,记得要把原来的 user interface 换成 Class。 一旦校验失败,浏览器或者控制台就会报出类似的错误。 ``` ValidationError: "id" is required ``` 同时,由于定义了 `id`  的类型,在拿到字符串的情况下,会自动将 id 变为数字。 ``` @Validate() async updateUser(@Body(ALL) user: UserDTO ) { // typeof user.id === 'number' } ``` ## 常见的校验写法[​](#常见的校验写法 "常见的校验写法的直接链接") ``` RuleType.number().required(); // 数字,必填 RuleType.string().empty(''); // 字符串非必填 RuleType.number().max(10).min(1); // 数字,最大值和最小值 RuleType.number().greater(10).less(50); // 数字,大于 10,小于 50 RuleType.string().max(10).min(5); // 字符串,长度最大 10,最小 5 RuleType.string().length(20); // 字符串,长度 20 RuleType.string().pattern(/^[abc]+$/); // 字符串,匹配正则格式 RuleType.object().length(5); // 对象,key 数量等于 5 RuleType.array().items(RuleType.string()); // 数组,每个元素是字符串 RuleType.array().max(10); // 数组,最大长度为 10 RuleType.array().min(10); // 数组,最小长度为 10 RuleType.array().length(10); // 数组,长度为 10 RuleType.string().allow(''); // 非必填字段传入空字符串 ``` ## 级联校验[​](#级联校验 "级联校验的直接链接") Midway 支持每个校验的 Class 中的属性依旧是一个对象。 我们给 `UserDTO`  增加一个属性 `school` ,并且赋予一个 `SchoolDTO`  类型。 ``` import { Rule, RuleType } from '@midwayjs/decorator'; export class SchoolDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.string()) address: string; } export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; // 这里传入 SchoolDTO 作为校验参数,此时会默认是required字段, // 如果用户不想要required,则@Rule(SchoolDTO, {required: false}) @Rule(SchoolDTO) school: SchoolDTO; // 如果是数组,则也只要下面这样写,这边装饰器会判断类型是否是数组,只能适用这种class类型 @Rule(SchoolDTO) xxxx: SchoolDTO[]; } ``` 这个时候, `@Rule`  装饰器的参数可以为需要校验的这个类型本身。 ## 继承校验[​](#继承校验 "继承校验的直接链接") Midway 支持校验继承方式,满足开发者抽离通用的对象属性的时候做参数校验。 例如我们下面 `CommonUserDTO`  抽离接口的通用的一些属性,然后 `UserDTO`  作为特殊接口需要的特定参数。 ``` import { Rule, RuleType } from '@midwayjs/decorator'; export class CommonUserDTO { @Rule(RuleType.string().required()) token: string; @Rule(RuleType.string()) workId: string; } export class UserDTO extends CommonUserDTO { @Rule(RuleType.string().required()) name: string; } ``` 老版本需要在子类上面加,新版本不需要啦~ 信息 如果属性名相同,则取当前属性的规则进行校验,不会和父类合并。 ## 从原有 DTO 创建新 DTO[​](#从原有-dto-创建新-dto "从原有 DTO 创建新 DTO的直接链接") 有时候,我们会希望从某个 DTO 中获取一部分属性,变成一个新的 DTO 类。 Midway 提供了 `PickDto` 和 `OmitDto` 两个方法根据现有的的 DTO 类型创建新的 DTO。 `PickDto` 用于从现有的 DTO 中获取一些属性,变成新的 DTO,而 `OmitDto` 用于将其中某些属性剔除,比如: ``` // src/dto/user.ts import { Rule, RuleType, PickDto } from '@midwayjs/decorator'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } // 继承出一个新的 DTO export class SimpleUserDTO extends PickDto(UserDTO, ['firstName', 'lastName']) {} // const simpleUser = new SimpleUserDTO(); // 只包含了 firstName 和 lastName 属性 // simpleUser.firstName = xxx export class NewUserDTO extends OmitDto(UserDTO, ['age']) {} // const newUser = new NewUserDTO(); // newUser.age 定义和属性都不存在 // 使用 async login(@Body() user: NewUserDTO) { // ... } ``` ## 参数校验技巧[​](#参数校验技巧 "参数校验技巧的直接链接") 有人如果我很多都是字符串必填,或者类似需求,写 `RuleType.string().required()` 有点长,有点烦,那应该怎么办? ``` const requiredString = RuleType.string().required(); // 自己在一个文件中定义一下你们部门的规范或常用的。 export class UserDTO { @Rule(requiredString) // 这样就不用写上面这么长的了 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; } const maxString = (length) => RuleType.string().max(length); // 自己在一个文件中定义一下你们部门的规范或常用的。 export class UserDTO { @Rule(requiredString) // 同上 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; @Rule(maxString(50)) // 这样通过换个参数即可 info: string; @Rule(maxString(50).required()) //这样也行 info2: string; } ``` 相当于通过定义常用方法或变量。 ## 参数转换[​](#参数转换 "参数转换的直接链接") 除了校验参数, `@Validate`  装饰器还承担了转换对象的职责。你会发现**传入的参数已经被自动变为 UserDTO 的实例**。 这样做的好处是,可以直接调用对象中的一些方法,比如下面的 `getName`  和 `isAdult` 。在后续的 Model 保存到数据库等操作中有着非常明显的优势。 ``` // src/dto/user.ts import { Rule, RuleType } from '@midwayjs/decorator'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; getName() { return this.firstName + ' ' + this.lastName; } isAdult() { return this.age > 36 && this.age < 60; } } ``` 要关闭这一默认行为,可以在使用 `@Validate`  装饰器时加入 false 参数 ``` @Validate(false) async updateUser(@Body(ALL) user: UserDTO ) { // user instanceof UserDTO => false } ``` ## 其他问题[​](#其他问题 "其他问题的直接链接") 1、由于部分用户在参数校验的时候,希望允许出现没有定义的字段。但是这个 PR 由于社区的意见不一致,导致 PR 一直没合并进来。如果用户有这样的需求,暂时的解法: 在 config.default.ts 里面 ``` import { defaults } from 'joi/lib/common.js'; defaults.allowUnknown = true; ``` 2、用户咨询如何让对应的信息透出给端侧或者上游? 参数校验、转换,不仅可以使用在 http 请求、websocket、task、service 等场景。 然后当 @Validate 失败的时候,会向外抛一个 error。 如果 http 请求想要将对应信息处理一下抛给前端,则只需要通过用一个 middleware try catch 一下即可。 --- # Web 中间件 Web 中间件是在控制器调用  **之前**  和 \*\*之后(部分) \*\*调用的函数。 中间件函数可以访问请求和响应对象。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1600592120947-c000a3a8-5da1-4a8d-839a-c6f81b771577.png#height=219\&id=j94H0\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=438\&originWidth=2196\&originalType=binary\&ratio=1\&size=56855\&status=done\&style=none\&width=1098) 不同的上层 Web 框架中间件形式不同,EggJS 的中间件形式和 Koa 的中间件形式相同,都是基于[洋葱圈模型](https://eggjs.org/zh-cn/intro/egg-and-koa.html#midlleware)。而 Express 则是传统的队列模型。 所以在 Express 中,中间件**只能在控制器之前**调用,而 Koa 和 EggJs 可以在**控制器前后都被执行**。 由于 Web 中间件使用较为类同,下面的代码,我们将以 @midwayjs/web(Egg.js)框架举例。 ## 编写 Web 中间件[​](#编写-web-中间件 "编写 Web 中间件的直接链接") 一般情况下,我们会在 `src/middleware`  文件夹中编写 Web 中间件。 创建一个 `src/middleware/report.ts` 。我们在这个 Web 中间件中打印了控制器(Controller)执行的时间。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ ├── middleware ## 中间件目录 │ │ └── report.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 代码如下。 ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next: IMidwayWebNext) => { // 控制器前执行的逻辑 const startTime = Date.now(); // 执行下一个 Web 中间件,最后执行到控制器 await next(); // 控制器之后执行的逻辑 console.log(Date.now() - startTime); }; } } ``` 简单来说, `await next()` 则代表了下一个要执行的逻辑,这里一般代表控制器执行,在执行的前后,我们可以进行一些打印和赋值操作,这也是洋葱圈模型最大的优势。 注意,这里我们导出了一个 `ReportMiddleware` 类,这个中间件类的 key 为 `reportMiddleware` 。 ## 使用 Web 中间件[​](#使用-web-中间件 "使用 Web 中间件的直接链接") Web 中间件在写完之后,需要应用到请求流程之中。 根据应用到的位置,分为两种: * 1、全局中间件,所有的路由都会执行的中间件,比如 cookie、session 等等 * 2、路由中间件,单个/部分路由会执行的中间件,比如某个路由的前置校验,数据处理等等 他们之间的关系一般为: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1612801319333-17e50d3a-7baf-4bcc-af57-2be544152580.png#height=292\&id=hCpBr\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=584\&originWidth=2350\&originalType=binary\&ratio=1\&size=118405\&status=done\&style=none\&width=1175) ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 在写完中间件之后,我们需要把它应用到各个控制器路由之上。 `@Controller` 装饰器的第二个参数,可以让我们方便的在某个路由分组之上添加中间件。 ``` import { Controller, Provide } from '@midwayjs/decorator'; import { Context } from 'egg'; @Provide() @Controller('/', { middleware: ['reportMiddleware'] }) export class HomeController {} ``` Midway 同时也在 `@Get` 、 `@Post` 等路由装饰器上都提供了 middleware 参数,方便对单个路由做中间件拦截。 ``` import { Controller, Get, Provide } from '@midwayjs/decorator'; @Provide() @Controller('/') export class HomeController { @Get('/', { middleware: ['reportMiddleware'] }) async home() {} } ``` 这里 middleware 属性的参数则是依赖注入容器的 key,也就是 `@Provide` 的值,前面讲过,默认为类名的驼峰形式。 ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 所谓的全局中间件,就是对所有的路由生效的 Web 中间件。传统的 Express/Koa 中间件都可以是全局中间件。 设置全局中间件需要拿到应用的实例,同时,需要在所有请求之前被加载。 在 EggJS 中,其提供了一个配置性的加载全局中间件的用法。在 `src/config/config.default.ts` 中配置 `middleware` 属性即可定义全局中间件,同样的,指定全局中间件的 key 即可。 ``` // src/config/config.default.ts export default (appInfo: EggAppInfo) => { const config = {} as DefaultConfig; // ... config.middleware = ['reportMiddleware']; return config; }; ``` 信息 此配置方法为 EggJS 的特殊用法。 ## 常见示例[​](#常见示例 "常见示例的直接链接") ### 接入三方中间件[​](#接入三方中间件 "接入三方中间件的直接链接") 社区有很多三方中间件,Midway 的 Class 写法可以比较方便的接入。本质上, `resolve()` 方法只需要返回一个符合当前中间件格式的方法即可。 我们以 `koa-static` 举例。 在 `koa-static` 文档中,是这样写的。 ``` const Koa = require('koa'); const app = new Koa(); app.use(require('koa-static')(root, opts)); ``` 那么, `require('koa-static')(root, opts)` 这个,其实就是返回的中间件方法,我们只需要将这段代码加入到 `resolve` 方法中, 类写法示例如下。 ``` import * as koaStatic from 'koa-static'; import { join } from 'path'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return koaStatic(join(__dirname, '../public')); } } ``` ### 中间件中获取请求作用域实例[​](#中间件中获取请求作用域实例 "中间件中获取请求作用域实例的直接链接") 由于 Web 中间件在生命周期的特殊性,会在应用请求前就被加载(绑定)到路由上,所以无法和请求关联。中间件类的作用域 **固定为单例(Singleton**)。 由于 **中间件实例为单例**,所以中间件中注入的实例和请求不绑定,**无法获取到 ctx**,无法使用 `@Inject()` 注入请求作用域的实例,只能获取 Singleton 的实例。 比如,**下面的代码是错误的。** ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { @Inject() userService; // 这里注入的实例和上下文不绑定,无法获取到 ctx resolve() { return async (ctx: Context, next: IMidwayWebNext) => { // TODO await next(); }; } } ``` 如果要获取请求作用域的实例,可以使用从请求作用域容器 `ctx.requestContext`  中获取,如下面的方法。 ``` import { Provide } from '@midwayjs/decorator'; import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; import { Context } from 'egg'; @Provide() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next: IMidwayWebNext) => { const userService = await ctx.requestContext.getAsync('userService'); // TODO userService.xxxx await next(); }; } } ``` ### 传统函数式中间件[​](#传统函数式中间件 "传统函数式中间件的直接链接") 如果要继续使用 EggJS 传统的函数式写法,请参考 [EggJS 章节](/docs/eggjs)。 ### 特殊的全局中间件用法[​](#特殊的全局中间件用法 "特殊的全局中间件用法的直接链接") Midway 提供了一个生命周期的口子,方便业务在非常早的时候可以做一些自定义处理。我们需要手动创建一个生命周期文件,位于 `src/configuration.ts` 。 ``` ➜ my_midway_app tree . ├── src │ ├── configuration.ts ## 全局生命周期配置文件 │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ ├── middleware │ │ └── report.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 内容如下: ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/decorator'; import { ILifeCycle } from '@midwayjs/core'; import { Application } from 'egg'; @Configuration() export class ContainerLifeCycle implements ILifeCycle { @App() app: Application; async onReady() { this.app.use(await this.app.generateMiddleware('reportMiddleware')); } } ``` Midway 在各个 Web 框架的 app 上提供了一个 `generateMiddleware` 方法,用于快速创建 Class 形式的中间件,然后使用框架原有的 `use` 方法即可加载为全局中间件。 在 onReady 中加载的中间件,**框架会保证在 egg 中间件加载之前被执行**。 信息 代码编写完后,请先执行一次 `npm run dev` ,egg 需要在第一次运行后才会生成定义。 ### 全局路由前缀[​](#全局路由前缀 "全局路由前缀的直接链接") 全局的路由前缀可以由反向代理工具来做,比如 nginx,也可以由中间件代码来完成,下面的中间件简单演示了如何为所有路由增加 `api` 前缀。 ``` import { Provide } from '@midwayjs/decorator'; @Provide() export class PrefixMiddleware { resolve() { return async (ctx, next) => { ctx.path = ctx.path.replace(/^\/api/, '') || '/'; await next(); }; } } ``` --- # WebSocket [ws](https://www.npmjs.com/package/ws) 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. 这种可以持续连接的特性使得 WebScoket 特别适合用于适合用于游戏或者聊天室等使用场景。 Midway 提供了对 [ws](https://www.npmjs.com/package/ws) 模块的支持和封装,能够简单的创建一个 WebSocket 服务。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 WebSocket 的依赖。 ``` $ npm i @midwayjs/ws --save $ npm i @types/ws --save-dev ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 下面是 WebSocket 项目的基础目录结构,和传统应用类似,我们创建了 `socket` 目录,用户存放 WebSocket 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## ws 服务的文件 │ └── hello.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController` 装饰器定义 WebSocket 服务。 ``` @Provide() @WSController() export class HelloSocketController {} ``` 当有客户端连接时,会触发 `connection` 事件,我们在代码中可以使用 `@OnWSConnection()` 装饰器来修饰一个方法,当每个客户端第一次连接服务时,将自动调用该方法。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/ws'; import * as http from 'http'; @Provide() @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod(socket: Context, request: http.IncomingMessage) { console.log(`namespace / got a connection ${this.ctx.readyState}`); } } ``` 信息 这里的 ctx 等价于 WebSocket 实例。 ## 消息和响应[​](#消息和响应 "�消息和响应的直接链接") WebSocket 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()` 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/ws'; @Provide() @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') async gotMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } } ``` 我们可以通过 `@WSBroadCast` 装饰器将消息发送到所有连接的客户端上。 ``` import { WSController, Provide, OnWSConnection, Inject } from '@midwayjs/decorator'; import { Context } from '@midwayjs/ws'; @Provide() @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') @WSBroadCast() async gotMyMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } @OnWSDisConnection() async disconnect(id: number) { console.log('disconnect ' + id); } } ``` 通过 `@OnWSDisConnection` 装饰器,在客户端断连时,做一些额外处理。 ## 本地测试[​](#本地测试 "本地测试的直接链接") 和传统 web 的 midway 测试方法一样,我们使用 `createApp` 创建我们的服务端,唯一不同的是,我们要启动一个 WebSocket 服务,比如传递一个端口。 ``` import { createApp } from '@midwayjs/mock'; import { Framework } from '@midwayjs/ws'; describe('/test/index.test.ts', () => { it('should test create webSocket app', async () => { const app = await createApp(process.cwd(), { port: 3000 }); //... await closeApp(app); }); }); ``` 你可以直接使用 `ws` 来测试。也可以使用 Midway 提供的基于 `ws`   模块封装的测试客户端。 比如: ``` import { createApp, closeApp, createWebSocketClient } from '@midwayjs/mock'; / ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(process.cwd(), { port: 3000}); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); const result = await new Promise(resolve => { client.on('message', (data) => { // xxxx resolve(data); }); // 发送事件 client.send(1); }); // 判断结果 expect(JSON.parse(result)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await closeApp(app); }); ``` 使用 node 自带的 `events` 模块的 `once` 方法来优化,就会变成下面的代码。 ``` import { sleep } from '@midwayjs/decorator'; import { once } from 'events'; import { createApp, closeApp, createWebSocketClient } from '@midwayjs/mock'; // ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(process.cwd(), { port: 3000 }); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); // 发送事件 client.send(1); // 用事件的 promise 写法监听 let gotEvent = once(client, 'message'); // 等待返回 let [data] = await gotEvent; // 判断结果 expect(JSON.parse(data)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await closeApp(app); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 启动服务[​](#启动服务 "启动服务的直接链接") ws 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway   框架一起启动)。通过编写 `bootstrap.js` 即可。 和其他框架类似,示例如下: ``` // bootstrap.js const WebSocketFramework = require('@midwayjs/ws').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); // 初始化 socket.io 框架 const webSocketFramework = new WebSocketFramework().configure({ port: 3000, }); Bootstrap.load(webSocketFramework).run(); ``` 我们在本地开发时可以直接使用这个文件进行开发,我们的脚手架示例已经将其添加到 `npm run dev` 命令中。 而在线上部署时,也可以使用 `npm run start` 命令。 ``` "scripts": { "start": "NODE_ENV=production node ./bootstrap.js", "dev": "cross-env NODE_ENV=local midway-bin dev --ts --entryFile=bootstrap.js", "test": "midway-bin test --ts", "cov": "midway-bin cov --ts", ... }, ``` ## 框架选项[​](#框架选项 "框架选项的直接链接") `@midwayjs/ws` 作为框架启动时,可以传递的参数如下: \| port | number | 可选,如果传递了该端口,ws 内部会创建一个该端口的 HTTP 服务。 \| 如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | ------------------------------------------------------------- | ---------- | ------------------------------------------------------ | | server | httpServer | 可选,当传递 port 时,可以指定一个已经存在的 webServer | 更多的启动选项,请参考 [ws 文档](https://github.com/websockets/ws)。 ## 接入已有的 HTTP 服务[​](#接入已有的-http-服务 "接入已有的 HTTP 服务的直接链接") `@midwayjs/ws` 默认支持和 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` 的多框架部署。 当多个框架部署时,请把 HTTP 类型的框架作为主框架,ws 将作为副框架加载,同时会自动找到当前的 HTTP 服务接入。 示例如下: ``` // bootstrap.js const WebFramework = require('@midwayjs/koa').Framework; const SocketFramework = require('@midwayjs/ws').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); // 加载主 web 框架 const webFramework = new WebFramework().configure({ port: 7001, }); // 加载副 ws 框架,自动适配主框架,这里不需要配置 port const socketFramework = new SocketFramework().configure({}); Bootstrap.load(webFramework).load(socketFramework).run(); ``` ## --- # 拦截器(AOP) 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 Midway 设计了一套通用的方法拦截器(切面),用于在不同场景中,统一编写逻辑。 拦截器和传统的 Web 中间件和装饰器都不同,是由 Midway 框架提供的能力,在执行顺序上,处于中间的位置,这个能力能对任意的 Class 方法做拦截。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DFfT1y1FC8xYeocrX_!!6000000000450-2-tps-823-133.png) ## 使用拦截器(切面)[​](#使用拦截器切面 "使用拦截器(切面)的直接链接") 拦截器一般会放在 `src/aspect` 目录。下面我们写一个对控制器(Controller)方法拦截的示例。创建一个 `src/aspect/report.ts` 文件。 ``` ➜ my_midway_app tree . ├── src │ │── aspect ## 拦截器目录 │ │ └── report.ts │ └── controller ## Web Controller 目录 │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return "Hello Midwayjs!"; } } ``` 内容如下: ``` import { Aspect, IMethodAspect, JoinPoint } from '@midwayjs/core'; import { HomeController } from '../controller/home'; @Aspect(HomeController) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('before home router run'); } } ``` 启动项目,运行后,在控制台会输出 `before home router run` 的字样。 你会发现,我们不需要去侵入控制器的代码,既没有在业务文件中加装饰器,也没有在主流程前后可见的加代码。 拦截器(切面)的能力非常强大,也非常可怕,我们一定要小心而正确的使用。 拦截器 **固定为单例**。 警告 在继承的情况下,拦截器不会对父类的方法生效。 ## 可切面的生命周期[​](#可切面的生命周期 "可切面的生命周期的直接链接") 方法拦截器可以对整个方法进行拦截,拦截的方式包括几个方面。 ``` export interface IMethodAspect { after?(joinPoint: JoinPoint, result: any, error: Error); afterReturn?(joinPoint: JoinPoint, result: any): any; afterThrow?(joinPoint: JoinPoint, error: Error): void; before?(joinPoint: JoinPoint): void; around?(joinPoint: JoinPoint): any; } ``` | 方法 | 描述 | | ----------- | ---------------------------- | | before | 方法调用前执行 | | around | 包裹方法的前后执行 | | afterReturn | 正确返回内容时执行 | | afterThrow | 抛出异常时执行 | | after | 最后执行(不管正确还是错误) | 简单理解如下; ``` try { // before // around or invokeMethod // afterReturn } catch(err){ // afterThrow } finally { // after } ``` | | 修改入参 | 调用原方法 | 获取返回值 | 修改返回值 | 获取错误 | 拦截并抛出错误 | | ----------- | -------- | ---------- | ---------- | ---------- | -------- | -------------- | | before | √ | √ | | | | | | around | √ | √ | √ | √ | √ | √ | | afterReturn | | | √ | √ | | | | afterThrow | | | | | √ | √ | | after | | | √ | | √ | | 我们常会在 `before` 的过程中修改入参、校验,以符合程序执行的逻辑,比如: ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home(data1, data2) { return data1 + data2; // 因为拦截了方法,这里的返回值是 3 } } // src/aspect/ @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log(point.args); // 这里因为对 Controller 方法做切面,原本的参数为 [ctx, next] point.args = [1, 2]; // 修改入参 } } ``` 这里的 `JoinPoint` 就是可以对方法做修改的参数,定义如下。 ``` export interface JoinPoint { methodName: string; target: any; args: any[]; proceed(...args: any[]): any; } ``` | 参数 | 描述 | | ---------- | ------------------------------------------ | | methodName | 拦截到的方法名 | | target | 方法调用时的实例 | | args | 原方法调用的参数 | | proceed | 原方法本身,只会在 before 和 around 中存在 | `around` 是比较全能的方法,它可以包裹整个方法调用流程。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async around(point: JoinPoint) { const result = await point.proceed(...point.args); // 执行原方法 return result + ' world'; } } ``` 最终 Controller 会返回 `hello world` 。 `afterReturn` 方法会多一个返回结果参数,如果只需要修改返回结果,可以直接使用它,上面的 `around` 例子用 `afterReturn` 改写会更简单。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async afterReturn(point: JoinPoint, result) { return result + ' world'; } } ``` `afterThrow` 用于拦截错误。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async afterThrow(point: JoinPoint, error) { if(/not found/.test(error.message)) { throw new Error('another error'); } else { console.error('got custom error'); } } } ``` `afterThrow` 能拦截错误,相应的,它不能在流程中返回结果,一般用来记录错误日志。 `after` 用来做最后的处理,不管是成功或者失败,都可以用它执行一些事情,比如记录所有成功或者失败的次数。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async after(point: JoinPoint, result, error) { if(error) { console.error(error); } else { console.log(result); } } } ``` ## 切面的异步问题[​](#切面的异步问题 "切面的异步问题的直接链接") 如果被拦截的方法是异步的,则原则上我们的 `before` 等方法应该都是异步的,反之,则都是同步的。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { // 这里是异步的,则下面的 before 是异步的 } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { } } ``` ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') home() { // 这里是同步的,则下面的 before 也是同步的 } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { before(point: JoinPoint) { } } ``` ## 应用到多个 Class[​](#应用到多个-class "应用到多个 Class的直接链接") `@Aspect` 装饰器的参数可以是一个数组,我们可以提供多个 Class,这些 Class 的 \*\*所有方法 \*\*都将被拦截。比如,我们可以将上面的拦截器应用到多个 Controller,这样 \*\*每一个 Class 的每一个方法 \*\*都会被拦截。 ``` @Aspect([HomeController, APIController]) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { } } ``` ## 特定方法匹配[​](#特定方法匹配 "特定方法匹配的直接链接") 一般情况下,我们只需要对某个 Class 特定的方法做拦截。我们提供了一些匹配方法的能力。 `@Aspect` 装饰的第二个参数则是一个通配方法的字符串。使用的规则为 [picomatch](https://github.com/micromatch/picomatch)。 假如我们的方法为: ``` // src/controller/home.ts import { Controller, Get } from "@midwayjs/core"; @Controller('/') export class HomeController { @Get('/1') async hello1() { return "Hello Midwayjs!"; } @Get('/2') async hello2() { return "Hello Midwayjs, too!"; } } ``` 那么,我们如下配置时,只会匹配到 `hello2` 这个方法。 ``` @Aspect([HomeController], '*2') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('hello method with suffix 2'); } } ``` ## 切面执行顺序[​](#切面执行顺序 "切面执行顺序的直接链接") 如果多个拦截器(切面)同时针对一个方法做操作,可能会出现顺序错乱的问题,如果在两个文件中,这个顺序是随机的。 `@Aspect` 的第三个参数用于指定拦截器的优先级,默认为 0,数字越大,优先级越高,即先被注册到方法上,**先注册的方法会被后调用,**即洋葱模型**。** 以下面的代码作为示例。 `MyAspect2` 的优先级高于 `MyAspect1` ,所以会优先注册。示意图如下,整个拦截流程分为两部分,先是注册,后是执行。 **注册流程** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01d31RXA1cpHyjyPHCs_!!6000000003649-2-tps-924-497.png) **执行流程** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01RXmEtD26Thmkg8eX8_!!6000000007663-2-tps-769-311.png) 代码如下。 ``` @Aspect([HomeController]) export class MyAspect1 implements IMethodAspect { before(point: JoinPoint) { console.log('111'); } } @Aspect([HomeController], '*', 1) // 这里可以设置优先级 export class MyAspect2 implements IMethodAspect { before(point: JoinPoint) { console.log('222'); } } ``` 执行输出为 ``` 111 222 ``` ## 一些限制[​](#一些限制 "一些限制的直接链接") * 1、拦截器不会对父类生效 --- # 自执行代码 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 比如,我们有一些需要提前执行的逻辑,一个用于监听 Redis 错误,一个用于初始化数据同步: ``` @Provide() @Scope(ScopeEnum.Singleton) export class RedisErrorListener { // ... } @Provide() @Scope(ScopeEnum.Singleton) export class DataSyncListener { // ... } ``` 一般,我们会在启动时通过 `getAsync` 方法来创建实例,使其执行。 ``` // configuration.ts //... @Configuration({ // ... }) export class MainConfiguration { async onReady(container) { await container.getAsync(RedisErrorListerner); await container.getAsync(DataSyncListerner); } } ``` 这样一旦代码多了,onReady 中会出现许多非必要流程的代码。 ## 自初始化[​](#自初始化 "自初始化的直接链接") 如果代码和主流程不耦合,属于独立的逻辑,比如上述的监听一些事件,初始化数据同步等,就可以使用 @Autoload 装饰器,使某个类可以自初始化。 比如: ``` import { Autoload, Scope, ScopeEnum } from '@midwayjs/core'; @Autoload() @Scope(ScopeEnum.Singleton) export class RedisErrorListener { @Init() async init() { const redis = new Redis(); redis.on('xxx', () => { // ... }); } } ``` 这样无需在 `onReady` 中使用 `getAsync` 方法即可自动初始化,并执行 init 方法。 --- # Awesome Midway 以下列举了与 Midwayjs 相关的优质社区项目 ## 微服务[​](#微服务 "微服务的直接链接") | 名称 | 作者 | 描述 | | ------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [@letscollab/midway-nacos](https://github.com/deskbtm-letscollab/midway-nacos) | Nawbc | midway nacos 组件 | | [midway-elasticsearch](https://github.com/ddzyan/midway-elasticsearch) | ddzyan | midway elasticsearch 组件 | | [midway-apollo](https://github.com/helloHT/midway-apollo) | helloHT | midway 携程异步动态配置 apollo 组件 | | [@mwcp/cache](https://github.com/waitingsong/midway-components/tree/main/packages/cache) | waitingsong | midway Cache 增强组件 支持 [`Cacheable`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheable-%E8%A3%85%E9%A5%B0%E5%99%A8), [`CacheEvict`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheevict-%E8%A3%85%E9%A5%B0%E5%99%A8), [`CachePut`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheput-%E8%A3%85%E9%A5%B0%E5%99%A8) 装饰器 并支持[传入泛型参数获得方法入参类型](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#%E4%BB%8E%E6%B3%9B%E5%9E%8B%E5%8F%82%E6%95%B0%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B) | | [@mwcp/kmore](https://github.com/waitingsong/kmore) | waitingsong | midway 数据库组件 基于 [Knex](https://knexjs.org/),通过 `Transactional` 装饰器支持声明式事务,支持自动分页、智能连表,集成 [OpenTelemetry](https://github.com/open-telemetry) 链路追踪 | | [@mwcp/otel](https://github.com/waitingsong/midway-components/tree/main/packages/otel) | waitingsong | midway [OpenTelemetry](https://github.com/open-telemetry) 增强组件,协议支持 HTTP 和 [gRPC (Unary)](https://github.com/midwayjs/midway/tree/main/packages/grpc) 支持 [`Trace`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#trace-%E8%A3%85%E9%A5%B0%E5%99%A8), [`TraceLog`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#tracelog-%E8%A3%85%E9%A5%B0%E5%99%A8), [`TraceInit`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#traceinit-%E8%A3%85%E9%A5%B0%E5%99%A8) 装饰器 并支持[传入泛型参数获得方法入参类型](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#%E4%BB%8E%E6%B3%9B%E5%9E%8B%E5%8F%82%E6%95%B0%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B) | | [@mwcp/jwt](https://github.com/waitingsong/midway-components/tree/main/packages/jwt) | waitingsong | midway JWT 增强组件 支持 [`Public`](https://github.com/waitingsong/midway-components/blob/main/packages/jwt/README.md#public-decorator) 装饰器 | | [@mwcp/paradedb](https://github.com/waitingsong/paradedb/tree/main/packages/mwcp-paradedb) | waitingsong | midway [ParadeDb](https://pigsty.cc/zh/blog/pg/paradedb/) 组件。首个基于 Postgres 的 Elasticsearch 开源替代,采用 Rust 编写, 旨在提供快速的全文检索、语义检索和混合检索能力,适用于搜索场景 | | [@mwcp/pgmq](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js) | waitingsong | midway [pqmg-js](https://github.com/waitingsong/pgmq-js/tree/main/packages/pgmq-js) 组件 支持 [`Consumer`](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js#consumer-decorator), [`PgmqListener`](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js#consumer-decorator) 装饰器, 支持事务以及事务保护的类似 MQ `Exchange` 概念的路由。 [PGMQ](https://tembo-io.github.io/pgmq/) 是一个基于 [PG](https://pigsty.cc/zh/blog/pg/pg-eat-db-world/) 数据库扩展的轻量级消息队列,原生支持消息持久化和延迟消息,类似 `AWS SQS` 或 `RSMQ` | | [midway-throttler](https://github.com/larryzhuo/midway-throttler) | larryzhuo | midway throttler 限流组件 | ## 插件[​](#插件 "插件的直接链接") | 名称 | 作者 | 描述 | | ----------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [邮件组件](https://gitee.com/onlymry_admin/midwayjs_mailer) | MrDotYan | midway 邮箱组件,基于nodemailer和midwayjs,以服务的形式注入控制器使用[文档(国内)](https://gitee.com/onlymry_admin/midwayjs_mailer/blob/main/readme.md) [文档(国外)](https://github.com/MrDotYan/midwayjs_mailer/blob/main/readme.md) | ## swagger[​](#swagger "swagger的直接链接") | 名称 | 作者 | 描述 | | ---------------------------------------------------------------------------------------- | ----- | --------------------- | | [midwayjs-knife4j2](https://github.com/fangbao-0418/midway/tree/master/packages/swagger) | Junyi | midway swagger 新皮肤 | ## 模板渲染[​](#模板渲染 "模板渲染的直接链接") | 名称 | 作者 | 描述 | | ----------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------- | | [yuntian001/midway-vite-view](https://github.com/yuntian001/midway-vite-view) | yuntian001 | midway vite 服务端渲染(ssr)/客户端渲染(client)组件 支持 vue3 react | ## 社区示例[​](#社区示例 "社区示例的直接链接") | 名称 | 作者 | 描述 | | --------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [midwayjs-crud](https://github.com/developeryvan/midwayjs-crud) | DeveloperYvan | 一个包含 prisma+casbin+nacos+crud 的示例 | | [midway-practice](https://github.com/ddzyan/midway-practice) | ddzyan | 一个包含 请求日志链路,统一响应体,统一异常处理,异常过滤器 + 三大主流 ORM 模型 (sequelize,typeORM,prisma) 的示例 | | [midway-boot](https://github.com/bestaone/midway-boot) | 码道功臣 | 一个比较完整的后端功能最佳实践,包含:增删改查及基类封装、数据库操作、缓存操作、用户安全认证及访问安全控制、JWT 访问凭证、分布式访问状态管理、密码加解密、统一返回结果封装、统一异常管理、Snowflake 主键生成、Swagger 集成及支持访问认证、环境变量的使用、Docker 镜像构建、Serverless 发布等 | | [midway-vue3-ssr](https://github.com/lqsong/midway-vue3-ssr) | LiQingSong | 基于 Midway、Vue 3 组装的 SSR 框架,简单、易学易用、方便扩展、集成 Midway 框架,您一直想要的 Vue SSR 框架。 | | [midway-learn](https://github.com/hbsjmsjwj/midway-learn.git) | hbsjmsjwj | 一个学习midway的demo,包含 midway3 + egg + 官方的组件&扩展(consul, jwt, typeorm, prometheus, swagger, mysql2,grpc,rabbitmq) | | [midway-admin](https://gitee.com/yncykj/midway-admin.git) | MrDotYan | 一套GeekerAdmin+Midwayjs构建的后台管理框架 | | [me-admin](https://github.com/meadmin-cn/meadmin.git) | yuntian001 | 一套Midwayjs+vue3构建的后台全栈解决方案,支持服务端渲染、一键crud、多语言,完整解决方案封装。 | ## 学习资料[​](#学习资料 "学习资料的直接链接") | 名称 | 作者 | 描述 | | -------------- | -------- | ----------------------------------------- | | Midway开发实践 | 码道功臣 | | 提示 欢迎大家为社区贡献力量, 编辑此页添加你所喜爱的高质量 midway 项目/组件 --- # 内置服务 在 Midway 中,提供了众多的内置对象,方便用户使用。 在本章节,我们会介绍和框架相关联的的 Application,Context 对象,Midway 默认容器上的一些服务对象,这些对象在整个业务的开发中都会经常遇到。 以下是一些 Midway 依赖注入容器内置的服务,这些服务由依赖注入容器初始化,在业务中全局可用。 ## MidwayApplicationManager[​](#midwayapplicationmanager "MidwayApplicationManager的直接链接") Midway 内置的应用管理器,可以使用它获取到所有的 Application。 可以通过注入获取,比如对不同的 Application 添加同一个中间件。 ``` import { MidwayApplicationManager, onfiguration, Inject } from '@midwayjs/core' import { CustomMiddleware } from './middleware/custom.middleware'; @Configuration({ // ... }) export class MainConfiguration { @Inject() applicationManager: MidwayApplicationManager; async onReady() { this.applicationManager .getApplications(['koa', 'faas', 'express', 'egg']) .forEach(app => { app.useMiddleware(CustomMiddleware); }); } } ``` | API | 返回类型 | 描述 | | ------------------------------------- | --------------------- | ------------------------------------------------------ | | getFramework(namespace: string) | IMidwayFramework | 返回参数指定的 framework | | getApplication(namespace: string) | IMidwayApplication | 返回参数指定的 Application | | getApplications(namespace: string\[]) | IMidwayApplication\[] | 返回参数指定的多个 Application | | getWebLikeApplication() | IMidwayApplication\[] | 返回类似 Web 场景的 Application(express/koa/egg/faas) | ## MidwayInformationService[​](#midwayinformationservice "MidwayInformationService的直接链接") Midway 内置的信息服务,提供基础的项目数据。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayInformationService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() informationService: MidwayInformationService; @Get('/') async home() { // this.informationService.getAppDir(); } } ``` 一般用来返回用户相关的目录。 | API | 返回类型 | 描述 | | ------------ | -------- | ------------------------------------------------------- | | getAppDir() | String | 返回应用根目录 | | getBaseDir() | String | 返回应用代码目录,默认本地开发为 src,服务器运行为 dist | | getHome | String | 返回机器用户目录,指代 \~ 的地址。 | | getPkg | Object | 返回 package.json 的内容 | | getRoot | String | 在开发环境,返回 appDir,在其他环境,返回 Home 目录 | ## MidwayEnvironmentService[​](#midwayenvironmentservice "MidwayEnvironmentService的直接链接") Midway 内置的环境服务,提供环境设置和判断。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayEnvironmentService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() environmentService: MidwayEnvironmentService; @Get('/') async home() { // this.environmentService.getCurrentEnvironment(); } } ``` 一般用来获取当前的环境,API 如下: | API | 返回类型 | 描述 | | ------------------------ | -------- | ------------------ | | getCurrentEnvironment() | String | 返回应用当前环境 | | setCurrentEnvironment() | | 设置当前环境 | | isDevelopmentEnvironment | Boolean | 判断是否是开发环境 | ## MidwayConfigService[​](#midwayconfigservice "MidwayConfigService的直接链接") Midway 内置的多环境配置服务,提供配置的加载和获取,它也是 `@Config` 装饰器的数据源。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayConfigService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() configService: MidwayConfigService; @Get('/') async home() { // this.configService.getConfiguration(); } } ``` 一般用来获取当前的配置,API 如下: | API | 返回类型 | 描述 | | ------------------ | -------- | ------------------------ | | addObject(obj) | | 动态添加配置对象 | | getConfiguration() | Object | 返回当前合并好的配置对象 | | clearAllConfig() | | 清空所有配置 | ## MidwayLoggerService[​](#midwayloggerservice "MidwayLoggerService的直接链接") Midway 内置的日志服务,提供日志创建,获取等 API,它也是 `@Logger` 装饰器的数据源。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayLoggerService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() loggerService: MidwayLoggerService; @Get('/') async home() { // this.loggerService.getLogger('logger'); } } ``` 一般用来获取日志对象,API 如下: | API | 返回类型 | 描述 | | ---------------------------- | -------- | ------------------------------ | | createInstance(name, config) | ILogger | 动态创建一个 Logger 实例 | | getLogger(name) | ILogger | 根据日志名返回一个 Logger 实例 | ## MidwayFrameworkService[​](#midwayframeworkservice "MidwayFrameworkService的直接链接") Midway 内置的自定义框架服务,配合组件中自定义的 `@Framework` 标记的 Class,提供不同协议的对外服务。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayFrameworkService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() frameworkService: MidwayFrameworkService; @Get('/') async home() { // this.frameworkService.getMainFramework(); } } ``` 一般用来获取 Framework 对象,API 如下: | API | 返回类型 | 描述 | | --------------------------------- | ------------------ | ---------------------------------- | | getMainFramework() | IMidwayFramework | 返回主框架实例 | | getMainApp() | IMidwayApplication | 返回主框架中的 app 对象 | | getFramework(nameOrFrameworkType) | IMidwayFramework | 根据框架名或者框架类型返回框架实例 | ## MidwayMiddlewareService[​](#midwaymiddlewareservice "MidwayMiddlewareService的直接链接") Midway 内置的中间件处理服务,用于自建中间件的处理。 Midway 内置的自定义装饰器服务,用于实现框架层面的自定义装饰器,一般在自定义框架时使用。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayMiddlewareService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() middlewareService: MidwayMiddlewareService; @Get('/') async home() { // this.middlewareService.compose(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | -------------------------------- | ----------- | -------------------------------------------- | | compose(middlewares, app, name?) | IMiddleawre | 将多个中间件数组组合到一起返回一个新的中间件 | ## MidwayDecoratorService[​](#midwaydecoratorservice "MidwayDecoratorService的直接链接") Midway 内置的自定义装饰器服务,用于实现框架层面的自定义装饰器。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayDecoratorService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() decoratorService: MidwayDecoratorService; @Get('/') async home() { // this.decoratorService.registerPropertyHandler(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | ----------------------------------------------- | -------- | ---------------------- | | registerPropertyHandler(decoratorKey, handler) | | 添加一个属性装饰器实现 | | registerMethodHandler(decoratorKey, handler) | | 添加一个方法装饰器实现 | | registerParameterHandler(decoratorKey, handler) | | 添加一个参数装饰器实现 | 具体示例,请参考 **自定义装饰器** 部分。 ## MidwayAspectService[​](#midwayaspectservice "MidwayAspectService的直接链接") Midway 内置的拦截器服务,用于加载 `@Aspect` 相关的能力,自定义装饰器也使用了该服务。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayAspectService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() aspectService: MidwayAspectService; @Get('/') async home() { // this.aspectService.interceptPrototypeMethod(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | ------------------------------------------------------------------------ | -------- | ---------------------------------------- | | addAspect(aspectInstance, aspectData) | | 添加一个拦截器实现 | | interceptPrototypeMethod(Clazz, methodName, aspectObject: IMethodAspect) | | 拦截原型上的方法,将拦截器的实现添加上去 | ## MidwayLifeCycleService[​](#midwaylifecycleservice "MidwayLifeCycleService的直接链接") Midway 内置的生命周期运行服务,用于运行 `configuration` 中的生命周期。 该服务均为内部方法,用户无法直接使用。 ## MidwayMockService[​](#midwaymockservice "MidwayMockService的直接链接") Midway 内置的数据模拟服务,用于在开发和单测时模拟数据。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayMockService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() mockService: MidwayMockService; @Get('/') async home() { // this.mockService.mockProperty(/** 省略 **/); } } ``` API 如下 | API | 返回类型 | 描述 | | ---------------------------------------------------- | -------- | ----------------------------------------------------------------- | | mockClassProperty(clzz, propertyName, value, group?) | | mock 一个 class 上的属性(方法),支持分组,默认分组为 `default` | | mockProperty(obj, key, value, group?) | | mock 一个普通对象上的属性(方法),支持分组,默认分组为 `default` | | mockContext(app, key, value, group?) | | mock 上下文对象上的属性,支持分组,默认分组为 `default` | | restore(group?) | | 恢复指定分组的 mock 数据,未指定则恢复所有 | | restoreAll() | | 清空所有 mock 数据 | ### mockClassProperty[​](#mockclassproperty "mockClassProperty的直接链接") 用于模拟类的某个属性或者方法。支持通过 `group` 参数指定分组。如果不传 `group` 参数,默认使用 `default` 分组。 ``` @Provide() export class UserService { data; async getUser() { return 'hello'; } } ``` 我们也可以在代码中模拟。 ``` import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @Provide() class TestMockService { @Inject() mockService: MidwayMockService; mock() { // 模拟属性,使用默认分组 this.mockService.mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); // 模拟属性,指定分组 this.mockService.mockClassProperty(UserService, 'data', { bbb: '1' }, 'group2'); } } ``` ### mockProperty[​](#mockproperty "mockProperty的直接链接") 使用 `mockProperty` 方法来模拟对象的属性。支持通过 `group` 参数指定分组。 ``` import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @Provide() class TestMockService { @Inject() mockService: MidwayMockService; mock() { const a = {}; // 默认分组 this.mockService.mockProperty(a, 'name', 'hello'); // 模拟属性,自定义分组 this.mockService.mockProperty(a, 'name', 'hello', 'group1'); // a['name'] => 'hello' // 模拟方法 this.mockService.mockProperty(a, 'getUser', async () => { return 'midway'; }, 'group2'); // await a.getUser() => 'midway' } } ``` ### mockContext[​](#mockcontext "mockContext的直接链接") 由于 Midway 的 Context 和 app 关联,所以在模拟的时候需要传入 app 实例。支持通过 `group` 参数指定分组。 使用 `mockContext` 方法来模拟上下文。 ``` import { MidwayMockService, Configuration, App } from '@midwayjs/core'; @Configuration(/**/) export class MainConfiguration { @Inject() mockService: MidwayMockService; @App() app; async onReady() { // 模拟上下文, 默认分组 this.mockService.mockContext(app, 'user', 'midway'); // 自定义分组 this.mockService.mockContext(app, 'user', 'midway', 'group1'); } } // ctx.user => midway ``` 如果你的数据比较复杂,或者带有逻辑,也可以使用回调形式。 ``` import { MidwayMockService, Configuration, App } from '@midwayjs/core'; @Configuration(/**/) export class MainConfiguration { @Inject() mockService: MidwayMockService; @App() app; async onReady() { // 模拟上下文 this.mockService.mockContext(app, (ctx) => { ctx.user = 'midway'; }, 'group2'); } } // ctx.user => midway ``` 注意,这个 mock 行为是在所有中间件之前执行。 ## MidwayWebRouterService[​](#midwaywebrouterservice "MidwayWebRouterService的直接链接") Midway 内置的路由表服务,用于应用路由和函数的创建。 可以通过注入获取。 ``` import { MidwayWebRouterService, Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { this.webRouterService.addRouter(async (ctx) => { return 'hello world'; }, { url: '/', requestMethod: 'GET', }); } } ``` API 如下 | API | 返回类型 | 描述 | | ------------------------------------------------- | ------------------------------------- | -------------------------------------- | | addController(controllerClz, controllerOption) | | 动态添加一个 Controller | | addRouter(routerFunction, routerInfoOption) | | 动态添加一个路由函数 | | getRouterTable() | Promise\> | 获取带层级的路由 | | getFlattenRouterTable() | Promise\ | 获取扁平化路由列表 | | getRoutePriorityList() | Promise\ | 获取路由前缀列表 | | getMatchedRouterInfo(url: string, method: string) | Promise\ | 根据访问的路径,返回当前匹配的路由信息 | 更多使用请参考 [Web 路由表](#router_table)。 ## MidwayServerlessFunctionService[​](#midwayserverlessfunctionservice "MidwayServerlessFunctionService的直接链接") Midway 内置的函数信息服务,继承与 `MidwayWebRouterService` ,方法几乎相同。 可以通过注入获取。 ``` import { MidwayServerlessFunctionService, Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { this.serverlessFunctionService.addServerlessFunction(async (ctx, event) => { return 'hello world'; }, { type: ServerlessTriggerType.HTTP, metadata: { method: 'get', path: '/api/hello' }, functionName: 'hello', handlerName: 'index.hello', }); } } ``` API 如下 | API | 返回类型 | 描述 | | ---------------------------------------------------------- | ----------------------- | ---------------- | | addServerlessFunction(fn, triggerOptions, functionOptions) | | 动态添加一个函数 | | getFunctionList() | Promise\ | 获取所有函数列表 | 更多使用请参考 [Web 路由表](#router_table)。 ## MidwayHealthService[​](#midwayhealthservice "MidwayHealthService的直接链接") Midway 内置的健康检查执行服务,用于外部扩展的健康检查能力。 完整的健康检查包含两个部分: * 1、健康检查的触发端,比如外部的定时请求,通常为一个 Http 接口 * 2、健康检查的执行端,一般在各个组件或者业务中,检查特定的项是否正常 `MidwayHealthService` 一般用于健康检查的触发端,下面描述的内容一般在触发端会实现。 可以通过注入获取后,执行健康检查任务。 ``` import { MidwayHealthService ,Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() healthService: MidwayHealthService; async onServerReady() { setInterval(() => { const results = await this.healthService.getStatus(); // console.log(results); // => // { // "status": false // "namespace": "redis", // "reason": "health check timeout", // "results": [ // { // "status": false // "reason": "health check timeout", // "namespace": "redis" // } // ] // } }, 1000); // ... } } ``` API 如下 | API | 返回类型 | 描述 | | -------------------------------- | ----------------------- | ---------------- | | getStatus() | Promise\ | 动态添加一个函数 | | setCheckTimeout(timeout: number) | void | 设置超时时间 | `getStatus` 方法用于外部调用轮询 `configuration` 中的 `onHealthCheck` 方法,返回一个符合 `HealthResults` 结构的数据。 `HealthResults` 包含几个字段,`status` 表示本次检查是否成功, 如果失败,`reason` 表示本次第一个失败组件的原因,`namespace` 代表第一个失败的组件名, `results` 则表示本次检查所有的返回项内容,返回项的结构和外部相同。 在执行过程时,如果 `onHealthCheck` 方法出现下列的情况,都会标记为失败。 * 1、未返回符合 `HealthResult` 结构的数据 * 2、未返回值 * 3、执行超时 * 4、抛出错误 * 5、返回符合 `HealthResult` 结构的代表错误的数据,比如 `{status: false}` 健康检查默认等待超时时间 1s。 可以使用全局的配置进行覆盖。 ``` // config.default export default { core: { healthCheckTimeout: 2000, } }; ``` 健康检查的执行端在业务或者组件的生命周期中实现,具体请查看 [生命周期](/docs/lifecycle.md#onhealthcheck)。 --- # 修改源码目录 在某些特殊场景下,可以修改源码所在的 `src` 目录。 一些限制: * 1、@midwayjs/web(egg)egg 由于目录固定,无法修改 * 2、只在纯 node 项目下测试通过(非一体化) ## 源码目录的修改[​](#源码目录的修改 "源码目录的修改的直接链接") 下面,我们以将 `src` 目录修改为 `server` 为例。 ### dev 开发[​](#dev-开发 "dev 开发的直接链接") `package.json` 中的 dev 命令需要增加源码目录,方便 dev 查找。 * 使用 mwtsc * 使用 @midwayjs/cli 默认可以识别 `tsconfig.json` 中的 `outDir` 字段,无需调整。 ``` "dev": "cross-env NODE_ENV=local midway-bin dev --sourceDir=./server --ts", ``` ### build 编译[​](#build-编译 "build 编译的直接链接") * 使用 mwtsc * 使用 @midwayjs/cli 默认可以识别 `tsconfig.json` 中的 `outDir` 字段,无需调整。 为了让 tsc 编译能找到源码目录,需要修改 `tsconfig.json` ,增加 `rootDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "rootDir": "server" }, } ``` 这样,开发和编译就都正常了。 ## 编译目录的修改[​](#编译目录的修改 "编译目录的修改的直接链接") 编译目录影响到部署,也可以修改。我们以将 `dist` 目录修改为 `build` 为例。 ### build 编译[​](#build-编译-1 "build 编译的直接链接") 修改 `tsconfig.json` 中的 `outDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "outDir": "build" }, "exclude": { "build", //... } } ``` 这样编译就正常了。 ### bootstrap 启动[​](#bootstrap-启动 "bootstrap 启动的直接链接") 编译目录修改之后,线上部署会找不到代码,所以如果走 `bootstrap.js` 启动,需要修改代码。 ``` // bootstrap.js const { join } = require('path'); const { Bootstrap } = require('@midwayjs/bootstrap'); //... // 需要用 configure 方法配置 baseDir Bootstrap .configure({ baseDir: join(__dirname, 'build'), }) .run(); ``` 对 `Bootstrap` 配置入口目录即可。 --- # 自定义组件 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: * 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等 * 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等 组件可以本地加载,也可以打包到一起发布成一个 npm 包。组件可以在 midway v3/Serverless 中使用。你可以将复用的业务代码,或者功能模块都放到组件中进行维护。几乎所有的 Midway 通用能力都可以在组件中使用,包括但不限于配置,生命周期,控制器,拦截器等。 设计组件的时候尽可能的面向所有的上层框架场景,所以我们尽可能只依赖 `@midwayjs/core` 。 从 v3 开始,框架(Framework)也变为组件的一部分,使用方式和组件保持统一。 ## 开发组件[​](#开发组件 "开发组件的直接链接") ### 脚手架[​](#脚手架 "脚手架的直接链接") 只需执行下面的脚本,模板列表中选择 `component-v3` 模板,即可快速生成示例组件。 ``` $ npm init midway@latest -y ``` 注意 [Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C)。 ### 组件目录[​](#组件目录 "组件目录的直接链接") 组件的结构和 midway 的推荐目录结构一样,组件的目录结构没有特别明确的规范,和应用或者函数保持一致即可。简单的理解,组件就是一个 “迷你应用"。 一个推荐的组件目录结构如下。 ``` . ├── package.json ├── src │ ├── index.ts // 入口导出文件 │ ├── configuration.ts // 组件行为配置 │ └── service // 逻辑代码 │ └── bookService.ts ├── test ├── index.d.ts // 组件扩展定义 └── tsconfig.json ``` 对于组件来说,唯一的规范是入口导出的 `Configuration` 属性,其必须是一个带有 `@Configuration` 装饰器的 Class。 一般来说,我们的代码为 TypeScript 标准目录结构,和 Midway 体系相同。 同时,又是一个普通的 Node.js 包,需要使用 `src/index.ts` 文件作为入口导出内容。 下面,我们以一个非常简单的示例来演示如何编写一个组件。 ### 组件生命周期[​](#组件生命周期 "组件生命周期的直接链接") 和应用相同,组件也使用 `src/configuration.ts` 作为入口启动文件(或者说,应用就是一个大组件)。 其中的代码和应用完全相同。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; @Configuration({ namespace: 'book' }) export class BookConfiguration { async onReady() { // ... } } ``` 唯一不同的是,你需要加一个 `namespace` 作为组件的命名空间。 每个组件的代码是一个独立的作用域,这样即使导出同名的类,也不会和其他组件冲突。 和整个 Midway 通用的 [生命周期扩展](/docs/3.0.0/lifecycle.md) 能力相同。 ### 组件逻辑代码[​](#组件逻辑代码 "组件逻辑代码的直接链接") 和应用相同,编写类导出即可,由依赖注入容器负责管理和加载。 ``` // src/service/book.service.ts import { Provide } from '@midwayjs/core'; @Provide() export class BookService { async getBookById() { return { data: 'hello world', } } } ``` 信息 一个组件不会依赖明确的上层框架,为了达到在不同场景复用的目的,只会依赖通用的 `@midwayjs/core`。 ### 组件配置[​](#组件配置 "组件配置的直接链接") 配置和应用相同,参考 [多环境配置](/docs/3.0.0/env_config.md)。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ namespace: 'book', importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class BookConfiguration { async onReady() { // ... } } ``` 在 v3 有一个重要的特性,组件在加载后,`MidwayConfig` 定义中就会包含该组件配置的定义。 为此,我们需要独立编写配置的定义。 在根目录下的 `index.d.ts` 中增加配置定义。 ``` // 由于修改了默认的类型导出位置,需要额外导出 dist 下的类型 export * from './dist/index'; // 标准的扩展声明 declare module '@midwayjs/core/dist/interface' { // 将配置合并到 MidwayConfig 中 interface MidwayConfig { book?: { // ... }; } } ``` 同时,组件的 `package.json` 也有对应的修改。 ``` { "name": "****", "main": "dist/index.js", "typings": "index.d.ts", // 这里的类型导出文件使用项目根目录的 // ... "files": [ "dist/**/*.js", "dist/**/*.d.ts", "index.d.ts" // 发布时需要额外带上这个文件 ], } ``` ### 组件约定[​](#组件约定 "组件约定的直接链接") 组件和应用本身略微有些不同,差异主要在以下几个方面。 * 1、组件的代码需要导出一个 `Configuration` 属性,其必须是一个带有 `@Configuration` 装饰器的 Class,用于配置组件自身能力 * 2、所有 \*\*显式导出的代码 \*\*才会被依赖注入容器加载,简单来说,所有 **被装饰器装饰** 的类都需要导出,包括控制器,服务,中间件等等 比如: ``` // src/index.ts export { BookConfiguration as Configuration } from './configuration'; export * from './service/book.service'; ``` 信息 这样项目中只有 `service/book.service.ts` 这个文件才会被依赖注入容器扫描和加载。 以及在 `package.json` 中指定 main 路径。 ``` "main": "dist/index" ``` 这样组件就可以被上层场景依赖加载了。 ### 测试组件[​](#测试组件 "测试组件的直接链接") 测试单独某个服务,可以通过启动一个空的业务,指定当前组件来执行。 ``` import { createLightApp } from '@midwayjs/mock'; import * as custom from '../src'; describe('/test/index.test.ts', () => { it('test component', async () => { const app = await createLightApp('', { imports: [ custom ] }); const bookService = await app.getApplicationContext().getAsync(custom.BookService); expect(await bookService.getBookById()).toEqual('hello world'); }); }); ``` 如果组件是 Http 协议流程中的一部分,强依赖 context,必须依赖某个 Http 框架,那么,请使用一个完整的项目示例,使用 `createApp` 来测试。 ``` import { createApp, createHttpRequest } from '@midwayjs/mock'; import * as custom from '../src'; describe('/test/index.test.ts', () => { it('test component', async () => { // 在示例项目中,需要自行依赖 @midwayjs/koa 或其他对等框架 const app = await createApp(join(__dirname, 'fixtures/base-app'), { imports: [ custom ] }); const result = await createHttpRequest(app).get('/'); // ... }); }); ``` ### 依赖其他组件[​](#依赖其他组件 "依赖其他组件的直接链接") 如果组件依赖另一个组件中的类,和应用相同,需要在入口处声明,框架会按照模块顺序加载并处理重复的情况。 如果明确依赖某个组件中的类,那么必然是该组件的强依赖。 比如: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; @Configuration({ namespace: 'book', imports: [axios] }) export class BookConfiguration { async onReady() { // ... } } ``` 还有一种弱依赖的情况,无需显式声明,但是需要额外的判断。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration({ namespace: 'book', }) export class BookConfiguration { async onReady(container: IMidwayContainer) { // ... if (container.hasNamespace('axios')) { // 当 axios 组件被加载时才执行 } // ... } } ``` 增加依赖。 ``` // package.json { "dependencies": { "@midwayjs/axios": "xxxx" } } ``` 在根目录下的 `index.d.ts` 中增加显式导入依赖的组件定义。 ``` // 显式导入依赖的组件 import '@midwayjs/axios'; export * from './dist/index'; // ... ``` 提示 如果主应用不显式依赖 axios,代码执行是正常的,但是 typescript 的 axios 的定义不会被扫描到,导致编写配置时没有 axios 定义,上述代码可以解决这个问题。 ### 应用中开发组件[​](#应用中开发组件 "应用中开发组件的直接链接") 推荐使用 [lerna](https://github.com/lerna/lerna),以及开启 lerna 的 hoist 模式来编写组件。如果想在非 lerna 的场景场景下开发组件,请保证组件在 `src` 目录下,否则会出现加载失败的情况。 #### 使用 lerna[​](#使用-lerna "使用 lerna的直接链接") 使用 lerna 开发相对比较简单,具体的目录结构类似如下。 ``` . ├── src ├── packages/ │ ├── component-A │ │ └── package.json │ ├── component-B │ │ └── package.json │ ├── component-C │ │ └── package.json │ └── web │ └── package.json ├── lerna.json └── package.json ``` #### 非 lerna[​](#非-lerna "非 lerna的直接链接") 下面是一种常见的组件开发方式,示例结构为在应用代码开发时同时开发两个组件,当然,你也可以自定义你喜欢的目录结构。 ``` . ├── package.json ├── src // 源码目录 │ ├── components │ │ ├── book // book 组件代码 │ │ │ ├── src │ │ │ │ ├── service │ │ │ │ │ └── bookService.ts │ │ │ │ ├── configuration.ts │ │ │ │ └── index.ts │ │ │ └── package.json │ │ │ │ │ └── school │ │ ├── src │ │ │ ├── service // school 组件代码 │ │ │ │ └── schoolService.ts │ │ │ └── configuration.ts │ │ └── package.json │ │ │ ├── configuration.ts // 应用行为配置文件 │ └── controller // 应用路由目录 ├── test └── tsconfig.json ``` 组件行为配置。 ``` // src/components/book/src/bookConfiguration.ts import { Configuration } from '@midwayjs/core'; @Configuration() export class BookConfiguration {} ``` 为了让组件能导出,我们需要在组件的入口 `src/components/book/src/index.ts` 导出 `Configuration` 属性。 ``` // src/components/book/src/index.ts export { BookConfiguration as Configuration } from './bookConfiguration/src`; ``` 信息 注意,这里引用的地方是 "./xxxx/src",是因为一般我们 package.json 中的 main 字段指向了 dist/index,如果希望代码不修改,那么 main 字段要指向 src/index,且在发布时记得修改回 dist。 将组件引入的目录指向 src ,是为了能在保存是自动生效(重启)。 另外,在新版本可能会出现扫描冲突的问题。可以将 `configuration.ts` 中的依赖注入冲突检查功能关闭。 ### 使用组件[​](#使用组件 "使用组件的直接链接") 在任意的 midway 系列的应用中,可以通过同样的方式引入这个组件。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "midway-component-book": "*" } } ``` 然后,在应用(函数)中引入这个组件。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as book from 'midway-component-book'; @Configuration({ imports: [book], }) export class MainConfiguration {} ``` 至此,我们的准备工作就做完了,下面开始使用。 直接引入组件的类注入。 ``` import { Provide, Inject } from '@midwayjs/core'; import { BookService } from 'midway-component-book'; @Provide() export class Library { @Inject(); bookService: BookService; } ``` 其余如果组件有包含特定的能力,请参考组件本身的文档。 ### 组件发布[​](#组件发布 "组件发布的直接链接") 组件就是一个普通 Node.js 包,编译后发布到 npm 分发即可。 ``` ## 编译并发布对应的component $ npm run build && npm publish ``` ### 组件示例[​](#组件示例 "组件示例的直接链接") [这里](https://github.com/czy88840616/midway-test-component) 有一个组件示例。已经发布到 npm,可以尝试直接引入到项目中启动执行。 ## 开发框架(Framework)[​](#开发框架framework "开发框架(Framework)的直接链接") 在 v3 中,组件可以包含一个 Framework,来提供不同的服务,利用生命周期,我们可以扩展提供 gRPC,Http 等协议。 这里的 Framework 只是组件里的一个特殊业务逻辑文件。 比如: ``` . ├── package.json ├── src │ ├── index.ts // 入口导出文件 │ ├── configuration.ts // 组件行为配置 │ └── framework.ts // 框架代码 │ ├── test ├── index.d.ts // 组件扩展定义 └── tsconfig.json ``` ### 扩展现有 Framework[​](#扩展现有-framework "扩展现有 Framework的直接链接") 上面提到,Framework 是组件的一部分,同时也遵循组件规范,是可以注入以及扩展的。 我们以扩展 `@midwayjs/koa` 举例。 首先创建一个自定义组件,和普通应用相同,由于需要扩展 `@midwayjs/koa` ,那么在组件中,我们需要依赖 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ namespace: 'myKoa', imports: [koa] }) export class MyKoaConfiguration { async onReady() { // ... } } ``` 随后,我们就可以注入 `@midwayjs/koa` 导出的 Framework,来做扩展了。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ namespace: 'myKoa', imports: [koa] }) export class MyKoaConfiguration { @Inject() framework: koa.Framework; async onReady() { // 添加中间件,koa 中的 app.useMiddleware 其实代理了 framework 上的方法 this.framework.useMiddleware(/* ... */); // 添加过滤器,koa 中的 app.useFilter 其实代理了 framework 上的方法 this.framework.useFilter(/* ... */); // koa 自身的扩展能力,比如扩展 context const app = this.framework.getApplication(); Object.defineProperty(app.context, 'user', { get() { // ... return 'xxx'; }, enumerable: true, }); // ... } async onServerReady() { const server = this.framework.getServer(); // server.xxxx } } ``` 这是一种基于现有 Framework 去扩展的一种方法。 * 如果组件中扩展了 context,那么请参考 [扩展上下文定义](/docs/3.0.0/context_definition.md) * 如果组件中扩展了配置,那么请参考 [组件配置](#%E7%BB%84%E4%BB%B6%E9%85%8D%E7%BD%AE) 等组件发布后,比如叫 `@midwayjs/my-koa`,业务可以直接使用你的组件,而无需引入 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; // 你自己的组件 import * as myKoa from '@midwayjs/my-koa'; @Configuration({ imports: [myKoa], }) export class MyConfiguration { async onReady() { // ... } } ``` 如果希望完全定义自己的组件,比如不同的协议,就需要完整自定义 Framework。 ### 编写 Framework[​](#编写-framework "编写 Framework的直接链接") 框架都遵循 `IMidwayFramewok` 的接口定义,以及如下约定。 * 每个框架有要自定义独立的启停流程 * 每个框架需要定义自己独立的 `Application` ,`Context` * 每个框架可以有自己独立的中间件能力 为了简化开发,Midway 提供了一个基础的 `BaseFramework` 类供继承。 ``` import { Framework, BaseFramework, IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core'; // 定义 Context export interface Context extends IMidwayContext { // ... } // 定义 Application export interface Application extends IMidwayApplication { // ... } // 框架的配置 export interface IMidwayCustomConfigurationOptions extends IConfigurationOptions { // ... } // 实现一个自定义框架,继承基础框架 @Framework() export class MidwayCustomFramework extends BaseFramework { // 处理初始化配置 configure() { // ... } // app 初始化 async applicationInitialize() { // ... } // 框架启动,比如 listen async run() { // ... } } ``` ### 自定义示例[​](#自定义示例 "自定义示例的直接链接") 接下去我们会以实现一个基础的 HTTP 服务框架作为示例。 ``` import { BaseFramework, IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core'; import * as http from 'http'; // 定义一些上层业务要使用的定义 export interface Context extends IMidwayContext {} export interface Application extends IMidwayApplication {} export interface IMidwayCustomConfigurationOptions extends IConfigurationOptions { port: number; } // 实现一个自定义框架,继承基础框架 export class MidwayCustomHTTPFramework extends BaseFramework { configure(): IMidwayCustomConfigurationOptions { return this.configService.getConfiguration('customKey'); } async applicationInitialize(options: Partial) { // 创建一个 app 实例 this.app = http.createServer((req, res) => { // 创建请求上下文,自带了 logger,请求作用域等 const ctx = this.app.createAnonymousContext(); // 从请求上下文拿到注入的服务 ctx.requestContext .getAsync('xxxx') .then((ins) => { // 调用服务 return ins.xxx(); }) .then(() => { // 请求结束 res.end(); }); }); // 给 app 绑定上 midway 框架需要的一些方法,比如 getConfig, getLogger 等。 this.defineApplicationProperties(); } async run() { // 启动的参数,这里只定义了启动的 HTTP 端口 if (this.configurationOptions.port) { new Promise((resolve) => { this.app.listen(this.configurationOptions.port, () => { resolve(); }); }); } } } ``` 我们定义了一个 `MidwayCustomHTTPFramework` 类,继承了 `BaseFramework` ,同时实现了 `applicationInitialize` 和 `run` 方法。 这样,一个最基础的框架就完成了。 最后,我们只要按照约定,将 Framework 导出即可。 ``` export { Application, Context, MidwayCustomHTTPFramework as Framework, IMidwayCustomConfigurationOptions, } from './custom'; ``` 上面是一个最简单的框架示例。事实上,Midway 所有的框架都是这么编写的。 --- # 依赖注入 Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 依赖注入是 Java Spring 体系中非常重要的核心,我们用简单的做法讲解这个能力。 我们举个例子,以下面的函数目录结构为例。 ``` . ├── package.json ├── src │ ├── controller # 控制器目录 │ │ └── user.controller.ts │ └── service # 服务目录 │ └── user.service.ts └── tsconfig.json ``` 在上面的示例中,提供了两个文件, `user.controller.ts` 和 `user.service.ts` 。 提示 下面的示例,为了展示完整的功能,我们会写完整的 `@Provide` 装饰器,而在实际使用中,如果有其他装饰器(比如 `@Controller` )的情况下, `@Provide` 可以被省略。 为了解释方便,我们将它合并到了一起,内容大致如下。 ``` import { Provide, Inject, Get } from '@midwayjs/core'; // user.controller.ts @Provide() // 实际可省略 @Controller() export class UserController { @Inject() userService: UserService; @Get('/') async get() { const user = await this.userService.getUser(); console.log(user); // world } } // user.service.ts @Provide() export class UserService { async getUser() { return 'world'; } } ``` 抛开所有装饰器,你可以看到这是标准的 Class 写法,没有其他多余的内容,这也是 Midway 体系的核心能力,依赖注入最迷人的地方。 `@Provide` 的作用是告诉 **依赖注入容器**,我需要被容器所加载。 `@Inject` 装饰器告诉容器,我需要将某个实例注入到属性上。 通过这两个装饰器的搭配,我们可以方便的在任意类中拿到实例对象,就像上面的 `this.userService` 。 **注意**:实际使用中,如果有其他装饰器(比如 `@Controller` )的情况下 `@Provide` 经常被省略。 ## 依赖注入原理[​](#依赖注入原理 "依赖注入原理的直接链接") 我们以下面的伪代码举例,在 Midway 体系启动阶段,会创建一个依赖注入容器(MidwayContainer),扫描所有用户代码(src)中的文件,将拥有 `@Provide` 装饰器的 Class,保存到容器中。 ``` /***** 下面为 Midway 内部代码 *****/ const container = new MidwayContainer(); container.bind(UserController); container.bind(UserService); ``` 这里的依赖注入容器类似于一个 Map。Map 的 key 是类对应的标识符(比如 **类名的驼峰形式字符串**),Value 则是 **类本身**。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01qRbFaS1dETlDbbrsl_!!6000000003704-2-tps-623-269.png) 在请求时,会动态实例化这些 Class,并且处理属性的赋值,比如下面的伪代码,很容易理解。 ``` /***** 下面为依赖注入容器伪代码 *****/ const userService = new UserService(); const userController = new UserController(); userController.userService = userService; ``` 经过这样,我们就能拿到完整的 `userController` 对象了,实际的代码会稍微不一样。 MidwayContainer 有 `getAsync` 方法,用来异步处理对象的初始化(很多依赖都是有异步初始化的需求),自动属性赋值,缓存,返回对象,将上面的流程合为同一个。 ``` /***** 下面为依赖注入容器内部代码 *****/ // 自动 new UserService(); // 自动 new UserController(); // 自动赋值 userController.userService = await container.getAsync(UserService); const userController = await container.getAsync(UserController); await userController.handler(); // output 'world' ``` 以上就是依赖注入的核心过程,创建实例。 信息 此外,这里还有一篇名为 [《这一次,教你从零开始写一个 IoC 容器》](https://mp.weixin.qq.com/s/g07BByYS6yD3QkLsA7zLYQ)的文章,欢迎扩展阅读。 ## 依赖注入作用域[​](#依赖注入作用域 "依赖注入作用域的直接链接") 默认的未指定或者未声明的情况下,所有的 `@Provide` 出来的 Class 的作用域都为 **请求作用域**。这意味着这些 Class ,会在\*\*每一次请求第一次调用时被实例化(new),请求结束后实例销毁。\*\*我们默认情况下的控制器(Controller)和服务(Service)都是这种作用域。 在 Midway 的依赖注入体系中,有三种作用域。 | 作用域 | 描述 | | --------- | --------------------------------------------------------------------------------------- | | Singleton | 单例,全局唯一(进程级别) | | Request | **默认**,请求作用域,生命周期绑定 **请求链路**,实例在请求链路上唯一,请求结束立即销毁 | | Prototype | 原型作用域,每次调用都会重复创建一个新的对象 | 不同的作用域有不同的作用,\*\*单例 \*\*可以用来做进程级别的数据缓存,或者数据库连接等只需要执行一次的工作,同时单例由于全局唯一,只初始化一次,所以调用的时候速度比较快。而 \*\*请求作用域 \*\*则是大部分需要获取请求参数和数据的服务的选择,\*\*原型作用域 \*\*使用比较少,在一些特殊的场景下也有它独特的作用。 ### 配置作用域[​](#配置作用域 "配置作用域的直接链接") 如果我们需要将一个对象定义为其他两种作用域,需要额外的配置。Midway 提供了 `@Scope` 装饰器来定义一个类的作用域。下面的代码就将我们的 user 服务变成了一个全局唯一的实例。 ``` // service import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class UserService { //... } ``` 信息 注意,所有的入口类,比如 Controller,均为请求作用域,不支持修改。大部分情况下,只需要调整 Service 即可。 ### 单例作用域[​](#单例作用域 "单例作用域的直接链接") 在显式配置后,某个类的作用域就可以变成单例作用域。。 ``` // service import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class UserService { //... } ``` 后续不管获取这个类的实例多少次,在 **同一个进程下**,都是同一个实例。 比如基于上面的单例服务,下面两个注入的 `userService` 属性是同一个实例: ``` @Provide() export class A { @Inject() userService: UserService //... } @Provide() export class B { @Inject() userService: UserService //... } ``` 在 v3.10 版本之后,可以使用单例装饰器来简化原来的写法。 ``` import { Singleton } from '@midwayjs/core'; @Singleton() class UserService { // ... } ``` ### 请求作用域[​](#请求作用域 "请求作用域的直接链接") 默认情况下,代码中编写的类均为 **请求作用域**。 在每个协议入口框架会自动创建一个请求作用域下的依赖注入容器,所有创建的实例都会绑定当前协议的上下文。 比如: * http 请求进来的时候,会创建一个请求作用域,每个 Controller 都是在请求路由时动态创建 * 定时器触发,也相当于创建了请求作用域 ctx,我们可以通过@Inject()ctx可以拿到这个请求作用域。 信息 默认为请求作用域的目的是为了和请求上下文关联,显式传递 ctx 更为安全可靠,方便调试。 所以在请求作用域中,我们可以通过 `@Inject()` 来注入当前的 ctx 对象。 ``` import { Controller, Provide, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() // 实际可省略 @Controller('/user') export class UserController { @Inject() ctx: Context; //... } ``` 我们的 `@Inject` 装饰器也是在 **当前类的作用域** 下去寻找对象来注入的。比如,在 `Singleton` 作用域下,由于和请求不关联 ,默认没有 `ctx` 对象,所以注入 ctx 是不对的 。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() ctx; // undefined //... } ``` ### 作用域固化[​](#作用域固化 "作用域固化的直接链接") 当作用域被设置为单例(Singleton)之后,整个 Class 注入的对象在第一次实例化之后就已经被固定了,这意味着,单例中注入的内容不能是其他作用域。 我们来举个例子。 ``` // 这个类是默认的请求作用域(Request) @Provide() // 实际可省略 @Controller() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { async getUser() { // ... } } ``` 调用的情况如下。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01FN99rS1Xb1YydSFi0_!!6000000002941-2-tps-1110-388.png) 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 都会固定的那个。 我们再来举个例子演示单例中注入的服务是否还会保留原有作用域。 信息 这里的 `DBManager` 我们特地设置成请求作用域,来演示一下特殊场景。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01eAyxrC1xVEYzbNf9P_!!6000000006448-2-tps-1964-334.png) ``` // 这个类是默认的请求作用域(Request) @Provide() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() dbManager: DBManager; async getUser() { // ... } } // 未设置作用域,默认是请求作用域(这里用来验证单例链路下,后续的实例都被缓存的场景) @Provide() export class DBManager { } ``` 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 和 `DBManager` 都会固定的那个。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01UoLu1526stZQFhp1U_!!6000000007718-2-tps-1870-762.png) 简单的理解为,单例就像一个缓存,**其中依赖的所有对象都将被冻结,不再变化。** ### 作用域降级[​](#作用域降级 "作用域降级的直接链接") 上面提到,当单例作用域注入请求作用域对象时,请求作用域的对象实例将被固化,会保存一个固定的实例在单例的缓存中。 这个时候,请求作用域变为单例,出现 **作用域降级** 的情况。 在日常开发中,一不留神就会发生这种情况,比如中间件中调用服务。 ``` //下面这段是错误的示例 @Provide() export class UserService { @Inject() ctx: Context; async getUser() { const id = this.ctx.xxxx; // ctx not found, will throw error } } // 中间件是单例 @Middleware() export class ReportMiddleware implements IMiddleware { @Inject() userService: UserService; // 这里的用户服务是请求作用域 resolve() { return async(ctx, next) => { await this.userService.getUser(); // ... } } } ``` 这个时候,虽然 `UserService` 可以正常注入中间件,但是实际上是以 单例 的对象注入,而不是请求作用域的对象,会导致 `ctx` 为空的情况。 这个时候的内存对象图为: ![](https://img.alicdn.com/imgextra/i3/O1CN01SwATKb1zUtVUCaQGj_!!6000000006718-2-tps-1292-574.png) `UserService` 的实例变成了不同的对象,一个是单例调用的实例(单例,不含 ctx),一个是正常的请求作用域调用的实例(请求作用域,含 ctx)。 为了避免发生这种情况,默认在这类错误的注入时,框架会自动抛出名为 `MidwaySingletonInjectRequestError` 的错误,阻止程序执行。 如果用户了解其中的风险,明确需要在单例中调用请求作用域对象,可以通过作用域装饰器的参数来设置允许降级。 并在其中做好 `ctx` 的空对象判断。 ``` import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Request, { allowDowngrade: true }) export class UserService { @Inject() ctx: Context; async getUser() { if (ctx && ctx.xxxx) { // ... } // ... } } ``` 当然,如果只是误写,那可以使用动态的获取方式,使得作用域统一。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const userService = await ctx.requestContext.getAsync(UserService); // TODO userService.xxxx await next(); }; } } ``` ### 获取对象作用域[​](#获取对象作用域 "获取对象作用域的直接链接") 从 v3.12.0 版本开始,依赖注入容器增加了一个新的获取对象作用域的 API。 ``` import { Controller, Inject, ApplicationContext, Get, IMidwayContainer } from '@midwayjs/core'; import { UserService} from '../service/user.service'; @Singleton() export class UserSerivce { // ... } @Controller('/') export class HomeController { @Inject() userService: UserService; @ApplicationContext() applicationContext: IMidwayContainer; @Get('/') async home(): Promise { console.log(this.applicationContext.getInstanceScope(this)); // => Request console.log(this.applicationContext.getInstanceScope(this.userService)); // => Singleton // ... } } ``` `getInstanceScope` 方法的返回值为 `ScopeEnum` 值。 ## 注入规则[​](#注入规则 "注入规则的直接链接") Midway 支持多种方式的注入。 ### 基于 Class 的注入[​](#基于-class-的注入 "基于 Class 的注入的直接链接") 导出一个 Class,注入的类型使用 Class,这是最简单的注入方式,大部分的业务和组件都是使用这样的方式。 ``` import { Provide, Inject } from '@midwayjs/core'; @Provide() // <------ 暴露一个 Class export class B { //... } @Provide() export class A { @Inject() b: B; // <------ 这里的属性使用 Class //... } ``` Midway 会自动使用 B 作为 b 这个属性的类型,在容器中实例化它。 在这种情况下,Midway 会自动创建一个唯一的 uuid 关联这个 Class,同时这个 uuid 我们称为 **依赖注入标识符**。 默认情况: * 1、 `@Provide` 会自动生成一个 uuid 作为依赖注入标识符 * 2、 `@Inject` 根据类型的 uuid 来查找 如果要获取这个 uuid,可以使用下面的 API。 ``` import { getProviderUUId } from '@midwayjs/core'; const uuid = getProviderUUId(B); // ... ``` ### 基于固定名字的注入[​](#基于固定名字的注入 "基于固定名字的注入的直接链接") ``` import { Provide, Inject } from '@midwayjs/core'; @Provide('bbbb') // <------ 暴露一个 Class export class B { //... } @Provide() export class A { @Inject('bbbb') b: B; // <------ 这里的属性使用 Class //... } ``` Midway 会将 `bbbb` 作为 B 这个 Class 的依赖注入标识符,在容器中实例化它。这种情况下,即使写了类型 B,依赖注入容器依旧会查找 `bbbb` 。 `@Provide` 和 `@Inject` 装饰器的参数是成对出现。 规则如下: * 1、如果装饰器包含参数,则以 \*\*参数 \*\*作为依赖注入标识符 * 2、如果没有参数,标注的 TS 类型为 Class,则将类 `@Provide` 的 key 作为 key,如果没有 key,默认取 uuid * 3、如果没有参数,标注的 TS 类型为非 Class,则将 **属性名** 作为 key ### 基于属性名的注入[​](#基于属性名的注入 "基于属性名的注入的直接链接") Midway 也可以基于接口进行注入,但是由于 Typescirpt 编译后会移除接口类型,不如使用类作为定义好用。 比如,我们定义一个接口,以及它的实现类。 ``` export interface IPay { payMoney() } @Provide('APay') export class A implements IPay { async payMoney() { // ... } } @Provide('BPay') export class B implements IPay { async payMoney() { // ... } } ``` 这个时候,如果有个服务需要注入,可以使用下面显式声明的方式。 ``` @Provide() export class PaymentService { @Inject('APay') payService: IPay; // 注意,这里的类型是接口,编译后类型信息会被移除 async orderGood() { await this.payService.payMoney(); } } ``` 由于接口类型会被移除,Midway 只能通过 `@Inject` 装饰器的 **参数** 或者 **属性名** 类来匹配注入的对象信息,类似 Java Spring 中的 `Autowire by name` 。 ### 注入已有对象[​](#注入已有对象 "注入已有对象的直接链接") 有时候,应用已经有现有的实例,而不是类,比如引入了一个第三库,这个时候如果希望对象能够被其他 IoC 容器中的实例引用,也可以通过增加对象的方式进行处理。 我们拿常见的工具类库 lodash 来举例。 假如我们希望在不同的类中直接注入来使用,而不是通过 require 的方式。 你需要在业务调用前(一般在启动的生命周期中)通过 `registerObject` 方法添加这个对象。 在添加的时候需要给出一个 **依赖注入标识符**,方便其他类中注入。 ``` // src/configuration.ts import * as lodash from 'lodash'; import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration { async onReady(applicationContext: IMidwayContainer) { // 向依赖注入容器中添加一些全局对象 applicationContext.registerObject('lodash', lodash); } } ``` 这个时候就可以在任意的类中通过 `@Inject` 来使用了。 ``` @Provide() export class BaseService { @Inject('lodash') lodashTool; async getUser() { // this.lodashTool.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 }); } } ``` ### 注入默认标识符[​](#注入默认标识符 "注入默认标识符的直接链接") Midway 会默认注入一些值,方便业务直接使用。 | **标识符** | **值类型** | **作用域** | **描述** | | ---------- | ---------- | ---------- | ------------------------------------------------------------------ | | baseDir | string | 全局 | 本地开发时为 src 目录,否则为 dist 目录 | | appDir | string | 全局 | 应用的根路径,一般为 process.cwd() | | ctx | object | 请求链路 | 对应框架的上下文类型,比如 Koa 和 EggJS 的 Context,Express 的 req | | logger | object | 请求链路 | 等价于 ctx.logger | | req | object | 请求链路 | Express 特有 | | res | object | 请求链路 | Express 特有 | | socket | object | 请求链路 | WebSocket 场景特有 | ``` @Provide() export class BaseService { @Inject() baseDir; @Inject() appDir; async getUser() { console.log(this.baseDir); console.log(this.appDir); } } ``` ## 获取依赖注入容器[​](#获取依赖注入容器 "获取依赖注入容器的直接链接") 在一般情况下,用户无需关心依赖注入容器,但是在一些特殊场景下,比如 * 需要动态调用服务的,比如 Web 的中间件场景,启动阶段需要调用服务的 * 封装框架或者其他三方 SDK 中需要动态获取服务的 简单来说,任意需要 **通过 API 动态获取服务** 的场景,都需要先拿到依赖注入容器。 ### 从 @ApplicationContext() 装饰器中获取[​](#从-applicationcontext-装饰器中获取 "从 @ApplicationContext() 装饰器中获取的直接链接") 在新版本中,Midway 提供了一个 @ApplicationContext() 的装饰器,用来获取依赖注入容器。 ``` import { ApplicationContext, IMidwayContainer } from '@midwayjs/core'; import { IMidwayContainer } from '@midwayjs/core'; @Provide() export class BootApp { @ApplicationContext() applicationContext: IMidwayContainer; // 这里也可以换成实际的框架的 app 定义 async invoke() { // this.applicationContext } } ``` ### 从 app 中获取[​](#从-app-中获取 "从 app 中获取的直接链接") Midway 将依赖注入容器挂载在两个地方,框架的 app 以及每次请求的上下文 Context,由于不同上层框架的情况不同,我们这里列举一下常见的示例。 对于不同的上层框架,我们统一提供了 `IMidwayApplication` 定义,所有的上层框架 app 都会实现这个接口,定义如下。 ``` export interface IMidwayApplication { getApplicationContext(): IMidwayContainer; //... } ``` 即通过 `app.getApplicationContext()` 方法,我们都能获取到依赖注入容器。 ``` const container = app.getApplicationContext(); ``` 配合 `@App` 装饰器,我们可以方便的在任意地方拿到当前运行的 app 实例。 ``` import { App, IMidwayApplication } from '@midwayjs/core'; @Provide() export class BootApp { @App() app: IMidwayApplication; // 这里也可以换成实际的框架的 app 定义 async invoke() { // 获取依赖注入容器 const applicationContext = this.app.getApplicationContext(); } } ``` 除了普通的依赖注入容器之外,Midway 还提供了一个 \*\*请求链路的依赖注入容器,\*\*这个请求链路的依赖注入容器和全局的依赖注入容器关联,共享一个对象池。但是两者还是有所区别的。 请求链路的依赖注入容器,是为了获取特有的请求作用域的对象,这个容器中获取的对象,都是**和请求绑定**,关联了当前的上下文。这意味着,**如果 Class 代码和请求关联,必须要从这个请求链路的依赖注入容器中获取**。 请求链路的依赖注入容器,必须从请求上下文对象中获取,最常见的场景为 Web 中间件。 ``` @Middleware() export class ReportMiddleware { resolve() { return async(ctx, next) => { // ctx.requestContext 请求链路的依赖注入容器 await next(); } } } ``` Express 的请求链路依赖注入容器挂载在 req 对象上。 ``` @Middleware() export class ReportMiddleware { resolve() { return (req, res, next) => { // req.requestContext 请求链路的依赖注入容器 next(); } } } ``` ### 在 Configuration 中获取[​](#在-configuration-中获取 "在 Configuration 中获取的直接链接") 在代码的入口 `configuration` 文件的生命周期中,我们也会额外传递依赖注入容器参数,方便用户直接使用。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration { async onReady(applicationContext: IMidwayContainer) { // ... } } ``` ## 动态 API[​](#动态-api "动态 API的直接链接") ### 动态获取实例[​](#动态获取实例 "动态获取实例的直接链接") 拿到 \*\*依赖注入容器 \*\*或者 \*\*请求链路的依赖 \*\*注入容器之后,才可以通过容器的 API 获取到对象。 我们可以使用标准的依赖注入容器 API 来获取实例。 ``` // 全局容器,获取的是单例 const userSerivce = await applicationContext.getAsync(UserService); // 请求作用域容器,获取请求作用域实例 const userSerivce = await ctx.requestContext.getAsync(UserService); ``` 我们可以在任意能获取依赖注入容器的地方使用,比如中间件中。 ``` import { Middleware, ApplicationContext, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; import { UserService } from './service/user.service'; @Middleware() export class ReportMiddleware implements IMiddleware { @ApplicationContext() applicationContext: IMidwayContainer; resolve() { return async(ctx, next) => { // 指定泛型类型,比如某个接口 const userService1 = await this.applicationContext.getAsync(UserService); // 不写泛型,也能推导出正确的类型 const userService1 = await this.applicationContext.getAsync(UserService); // 下面的方法获取的服务和请求关联,可以注入上下文 const userService2 = await ctx.requestContext.getAsync(UserService); await next(); } } } ``` Express 的写法 ``` import { UserService, Middleware } from './service/user'; import { NextFunction, Context, Response } from '@midwayjs/express'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (req, res, next) => { const userService = await req.requestContext.getAsync(UserService); // ... next(); } } } ``` ### 传递构造器参数[​](#传递构造器参数 "传递构造器参数的直接链接") 在个别场景下,我们可以通过 `getAsync` 获取实例的时候,传递构造器的参数。普通装饰器模式无法做到,仅在 API 形式下可用。 ``` @Provide() class UserService { constructor(private readonly type) {} getUser() { // this.type => student } } // 全局容器,获取的是单例 const userSerivce = await applicationContext.getAsync(UserService, [ 'student', // 构造器参数,会 apply 到构造器中 ]); // 请求作用域容器,获取请求作用域实例 const userSerivce = await ctx.requestContext.getAsync(UserService, [ 'student' ]); ``` 注意,构造器不能使用注入形式传递实例,只能传递固定的值。 ### 动态函数注入[​](#动态函数注入 "动态函数注入的直接链接") 在某些场景下,我们需要函数作为某个逻辑动态执行,而依赖注入容器中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。 比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个工厂方法,并且在函数中拿到上下文,动态去生成实例。 下面是标准的工厂方法注入样例。 一般工厂方法用于返回相同接口的实现,比如我们有两个 `ICacheService` 接口的实现: ``` export interface ICacheService { getData(): any; } @Provide() export class LocalCacheService implements ICacheService { async getData {} } @Provide() export class RemoteCacheService implements ICacheService { async getData {} } ``` 然后可以定义一个动态服务(工厂),根据当前的用户配置返回不同的实现。 ``` // src/service/dynamicCacheService.ts import { providerWrapper, IMidwayContainer, MidwayConfigService } from '@midwayjs/core'; export async function dynamicCacheServiceHandler(container: IMidwayContainer) { // 从容器 API 获取全局配置 const config = container.get(MidwayConfigService).getConfiguration(); if (config['redis']['mode'] === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } } providerWrapper([ { id: 'dynamicCacheService', provider: dynamicCacheServiceHandler, scope: ScopeEnum.Request, // 设置为请求作用域,那么上面传入的容器就为请求作用域容器 // scope: ScopeEnum.Singleton, // 也可以设置为全局作用域,那么里面的调用的逻辑将被缓存 } ]); ``` 这样在业务中,可以直接来使用了。注意:在注入的时候,方法会**被调用后再注入**。 ``` @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('dynamicCacheServiceHandler') cacheService: ICacheService; @Get('/') async home() { const data = await this.cacheService.getData(); // ... } } ``` 通过 `providerWrapper` 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。 信息 注意,动态方法必须 export,才会被依赖注入扫描到,默认为请求作用域(获取的 Container 是请求作用域容器)。 由于我们能将动态方法绑定到依赖注入容器,那么也能将一个回调方法绑定进去,这样获取的方法是可以被执行的,我们可以根据业务的传参来决定返回的结果。 ``` import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export function cacheServiceHandler(container: IMidwayContainer) { return async (mode: string) => { if (mode === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } }; } providerWrapper([ { id: 'cacheServiceHandler', provider: cacheServiceHandler, scope: ScopeEnum.Singleton, } ]); @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('cacheServiceHandler') getCacheService; @Get('/') async home() { const data = await this.getCacheService('local'); // ... } } ``` ## 静态 API[​](#静态-api "静态 API的直接链接") 在有些工具类中,我们可以不需要创建 class 实例就能获取到全局的依赖注入容器(**在启动之后**)。 ``` import { getCurrentApplicationContext } from '@midwayjs/core'; export const getService = async (serviceName) => { return getCurrentApplicationContext().getAsync(serviceName); } ``` 获取主框架(**在启动之后**)。 ``` import { getCurrentMainFramework } from '@midwayjs/core'; export const framework = () => { return getCurrentMainFramework(); } ``` 获取主框架的 app 对象(**在启动之后**)。 ``` import { getCurrentMainApp } from '@midwayjs/core'; export const getGlobalConfig = () => { return getCurrentMainApp().getConfig(); } ``` ## 启动行为[​](#启动行为 "启动行为的直接链接") ### 自动扫描绑定[​](#自动扫描绑定 "自动扫描绑定的直接链接") 上面提到,在容器初始化之后,我们会将现有的 class 注册绑定到容器中。 ``` const container = new MidwayContainer(); container.bind(UserController); container.bind(UserService); ``` Midway 在启动过程中会自动扫描整个项目目录,自动处理这个行为,使得用户无需手动执行绑定的操作。 简单的来说,框架默认会递归扫描整个 `src` 目录下的 ts/js 文件,然后进行 require 操作,当文件导出的为 class,且显式或隐式包含 `@Provide()` 装饰器时,会执行 `container.bind` 逻辑。 ### 忽略扫描[​](#忽略扫描 "忽略扫描的直接链接") 一般情况下,我们不应该把非 ts 文件放在 src 下(比如前端代码),特殊场景下,我们可以忽略某些目录,可以在 `@Configuration` 装饰器中配置。 示例如下: ``` // src/configuration.ts import { App, Configuration, Logger } from '@midwayjs/core'; // ... @Configuration({ // ... detectorOptions: { ignore: [ '**/web/**' ] } }) export class MainConfiguration { // ... } ``` ## 对象生命周期[​](#对象生命周期 "对象生命周期的直接链接") 在依赖注入容器创建和销毁实例的时候,我们可以使用装饰器做一些自定义的操作。 ### 异步初始化[​](#异步初始化 "异步初始化的��直接链接") 在某些情况下,我们需要一个实例在被其他依赖调用前需要初始化,如果这个初始化只是读取某个文件,那么可以写成同步方式,而如果这个初始化是从远端拿取数据或者连接某个服务,这个情况下,普通的同步代码就非常的难写。 Midway 提供了异步初始化的能力,通过 `@Init` 标签来管理初始化方法。 `@Init` 方法目前只能是一个。 ``` @Provide() export class BaseService { @Config('hello') config; @Init() async init() { await new Promise(resolve => { setTimeout(() => { this.config.c = 10; resolve(); }, 100); }); } } ``` 等价于 ``` const service = new BaseService(); await service.init(); ``` 信息 @Init 装饰器标记的方法,一定会以异步方式来调用。一般来说,异步初始化的服务较慢,请尽可能标注为单例(@Scope(ScopeEnum.Singleton))。 ### 异步销毁[​](#异步销毁 "异步销毁的直接链接") Midway 提供了在对象销毁前执行方法的能力,通过 `@Destroy` 装饰器来管理方法。 `@Destroy` 方法目前只能是一个。 ``` @Provide() export class BaseService { @Config('hello') config; @Destroy() async stop() { // do something } } ``` ## 请求作用域中的上下文对象[​](#请求作用域中的上下文对象 "请求作用域中的上下文对象的直接链接") 在请求作用域创建的对象,框架会在对象上挂载一个上下文对象,即使对象未显式声明 `@Inject() ctx` 也能获取当前上下文对象。 ``` import { REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; @Provide() export class UserManager { // ... } @Provide() export class UserService { // ... @Inject() userManager: UserManager; async invoke() { const ctx = this.userManager[REQUEST_OBJ_CTX_KEY]; // ... } } ``` 这个特性在 [拦截器](/docs/3.0.0/aspect.md) 或者 [自定义方法装饰器](/docs/3.0.0/custom_decorator.md) 中很有用。 ## 常见的使用错误[​](#常见的使用错误 "常见的使用错误的直接链接") ### 错误:构造器中获取注入属性[​](#错误构造器中获取注入属性 "错误:构造器中获取注入属性的直接链接") \*\*请不要在构造器中 \*\*获取注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('userManager') userManager; constructor() { console.log(this.userManager); // undefined } @Init() async initMethod() { console.log(this.userManager); // has value } } ``` ### 关于继承[​](#关于继承 "关于继承的直接链接") 为了避免属性错乱,请不要在基类上使用 `@Provide` 装饰器。 现阶段,Midway 支持属性装饰器的继承,不支持类和方法装饰器的继承(会有歧义)。 --- # 扩展上下文定义 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 ``` import { Middleware } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next) => { ctx.abc = '123'; await next(); } } } ``` 但是由于 TypeScript 模块定义的关系,我们无法往现有的模块上去附加定义,所以我们使用了一种新的方法来扩展。 ## 项目中扩展定义[​](#项目中扩展定义 "项目中扩展定义的直接链接") 你可以在 `src/interface.ts` 通过下面的代码,在项目中扩展 Midway 通用的 Context。 ``` // src/interface.ts import '@midwayjs/core'; // ... declare module '@midwayjs/core' { interface Context { abc: string; } } ``` 信息 注意,`declare module` 会替代原有的定义,所以请在之前使用 `import` 语法导入模块后再操作。 ## 组件中扩展定义[​](#组件中扩展定义 "组件中扩展定义的直接链接") 组件中略有不同,一般来说,组件可能是只能在特定的场景使用。 你可以在组件根目录的 `index.d.ts` 通过下面的代码,扩展 Midway 通用的 Context。 如果你希望对所有场景的 Context 做扩展。 ``` // index.d.ts // 下面这段可以对所有的 Context 做扩展 declare module '@midwayjs/core/dist/interface' { interface Context { abc: string; } } ``` 如果你只希望对特定场景的 Context 做扩展。 ``` // index.d.ts // 下面这段只 @midwayjs/koa 的 Context 做扩展 declare module '@midwayjs/koa/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/web 的 Context 做扩展 declare module '@midwayjs/web/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/faas 的 Context 做扩展 declare module '@midwayjs/faas/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/express 的 Context 做扩展 declare module '@midwayjs/express/dist/interface' { interface Context { abc: string; } } ``` 警告 * 1、组件中扩展和项目中略有不同(怀疑是 TS 的 bug)。 * 2、如果组件中使用了项目的扩展方式,那么其余组件的扩展提示会出现问题。 --- # 向 Midway 贡献 Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 ## 报告问题[​](#报告问题 "报告问题的直接链接") 如果你在开发过程中遇到了一些问题,你无法解决需要想开发者问询的,我们强烈建议: * 1、先在文档中查找相关的问题 * 2、如果查找后无法解决,可以提交一个 [Q\&A](https://github.com/midwayjs/midway/discussions/new/choose)。 在提交的内容时,请遵守下列规范。 * 1、在标题或内容中清楚地解释你的目的,中文或者英文均可。 * 2、在内容中描述以下内容 * 如果是个新需求,请详细描述需求内容,最好有伪代码实现 * 如果是一个 BUG,请提供复现步骤,错误日志,截图,相关配置,框架版本等可以让开发者快速定位问题的内容 * 如果可以,请尽可能提供一个最小可复现的代码仓库,方便调试 * 3、在您报告问题之前,请搜索相关问题。确保您不会打开重复的问题 开发者会在看到时进行标记问题,回复或者解决问题。 ## 修复代码问题[​](#修复代码问题 "修复代码问题的直接链接") 如果你发现框架有一些待修改的问题,可以通过 PR 来提交。 ### PR 流程[​](#pr-流程 "PR 流程的直接链接") 1、首先在 [midway github](https://github.com/midwayjs/midway) 右上角 fork 一个仓库,到自己的空间下。 2、git clone 该仓库到本地或者其他 IDE 环境,进行开发或者修复工作。 ``` # 创建新分支 $ git checkout -b branch-name # 安装依赖 $ npm i # 构建项目 $ npm run build # 开发并执行测试 $ npm test $ git add . # git add -u to delete files $ git commit -m "fix(role): role.use must xxx" $ git push origin branch-name ``` 3、创建一个 Pull Request,选择将自己的项目分支,合并到目标 midwayjs/midway 的 main 分支。 4、系统自动会创建 PR 到 midway 仓库下,在测试通过后,开发者会合并此 PR。 ### 提交规范[​](#提交规范 "提交规范的直接链接") * 1、一般 PR 使用英文标题 * 2、提交前缀使用 `fix`,`chore`,`feat` ,`docs`字段,用于快速标示修复的类型。 ## 修复文档问题[​](#修复文档问题 "修复文档问题的直接链接") 和普通 PR 类似,如果是单篇文档,可以使用快速编辑的方式提交。 ### 单篇文档快速修复[​](#单篇文档快速修复 "单篇文档快速修复的直接链接") * 1、打开官网需要修复的文档,点击左下角 [Edit this page](#) 链接,会跳转到 Github 对应的文档 * 2、点击 “笔型” 按钮,进入编辑页面 * 3、编辑内容后,将提交的标题修改为 `docs: xxxx`,点击提交按钮创建 PR * 4、等待开发者合并 ### 多篇文档修复[​](#多篇文档修复 "多篇文档修复的直接链接") 和普通 PR 相同,clone 仓库,提交,注意,提交 PR 的标题为 `docs: xxx`。 --- # 路由和控制器 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 **解析用户的输入,处理后返回相应的结果。** 如图所示,客户端通过 Http 协议请求服务端的控制器,控制器处理结束后响应客户端,这是一个最基础的 ”请求 - 响应“ 流程。 ![controller](https://img.alicdn.com/imgextra/i1/O1CN01dYitV22ADuagILnp3_!!6000000008170-2-tps-1600-634.png) 常见的有: * 在 [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) 接口中,控制器接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。 * 在 HTML 页面请求中,控制器根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。 * 在代理服务器中,控制器将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。 一般来说,控制器常用于对用户的请求参数做一些校验,转换,调用复杂的业务逻辑,拿到相应的业务结果后进行数据组装,然后返回。 在 Midway 中,控制器 **也承载了路由的能力**,每个控制器可以提供多个路由,不同的路由可以执行不同的操作。 在接下去的示例中,我们将演示如何在控制器中创建路由。 ## 路由[​](#路由 "路由的直接链接") 控制器文件一般来说在 `src/controller` 目录中,我们可以在其中创建控制器文件。Midway 使用 `@Controller()` 装饰器标注控制器,其中装饰器有一个可选参数,用于进行路由前缀(分组),这样这个控制器下面的所有路由都会带上这个前缀。 同时,Midway 提供了方法装饰器用于标注请求的类型。 比如,我们创建一个首页控制器,用于返回一个默认的 `/` 路由的页面。 ``` ➜ my_midway_app tree . ├── src │ └── controller │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return "Hello Midwayjs!"; } } ``` `@Controller` 装饰器告诉框架,这是一个 Web 控制器类型的类,而 `@Get` 装饰器告诉框架,被修饰的 `home` 方法,将被暴露为 `/` 这个路由,可以由 `GET` 请求来访问。 整个方法返回了一个字符串,在浏览器中你会收到 `text/plain` 的响应类型,以及一个 `200` 的状态码。 提示 路由方法均为 async 方法。 ## 路由方法[​](#路由方法 "路由方法的直接链接") 上面的示例,我们已经创建了一个 **GET** 路由。一般情况下,我们会有其他的 HTTP Method,Midway 提供了更多的路由方法装饰器。 ``` // src/controller/home.ts import { Controller, Get, Post } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return 'Hello Midwayjs!'; } @Post('/update') async updateData() { return 'This is a post method' } } ``` Midway 还提供了其他的装饰器, `@Get` 、 `@Post` 、 `@Put()` 、 `@Del()` 、 `@Patch()` 、 `@Options()` 、 `@Head()` 和 `@All()` ,表示各自的 HTTP 请求方法。 `@All` 装饰器比较特殊,表示能接受以上所有类型的 HTTP Method。 你可以将多个路由绑定到同一个方法上。 ``` @Get('/') @Get('/main') async home() { return 'Hello Midwayjs!'; } ``` ## 获取请求参数[​](#获取请求参数 "获取请求参数的直接链接") 接下去,我们将创建一个关于用户的 HTTP API,同样的,创建一个 `src/controller/user.ts` 文件,这次我们会增加一个路由前缀,以及增加更多的请求类型。 我们以用户类型举例,先增加一个用户类型,我们一般会将定义的内容放在 `src/interface.ts` 文件中。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/interface.ts export interface User { id: number; name: string; age: number; } ``` 再添加一个路由前缀以及对应的控制器。 ``` // src/controller/user.ts import { Controller } from "@midwayjs/core"; @Controller('/api/user') export class UserController { // xxxx } ``` 接下去,我们要针对不同的请求类型,调用不同的处理逻辑。除了请求类型之外,请求的数据一般都是动态的,会在 HTTP 的不同位置来传递,比如常见的 Query,Body 等。 ### 装饰器参数约定[​](#装饰器参数约定 "装饰器参数约定的直接链接") Midway 添加了常见的动态取值的装饰器,我们以 `@Query` 装饰器举例, `@Query` 装饰器会获取到 URL 中的 Query 参数部分,并将它赋值给函数入参。下面的示例,id 会从路由的 Query 参数上拿,如果 URL 为 `/?id=1` ,则 id 的值为 1,同时,这个路由将会返回 `User` 类型的对象。 ``` // src/controller/user.ts import { Controller, Get, Query } from "@midwayjs/core"; @Controller('/api/user') export class UserController { @Get('/') async getUser(@Query('id') id: string): Promise { // xxxx } } ``` `@Query` 装饰器的有参数,可以传入一个指定的字符串 key,获取对应的值,赋值给入参,如果不传入,则默认返回整个 Query 对象。 ``` // URL = /?id=1 async getUser(@Query('id') id: string) // id = 1 async getUser(@Query() queryData) // {"id": "1"} ``` Midway 提供了更多从 Query、Body 、Header 等位置获取值的装饰器,这些都是开箱即用,并且适配于不同的上层 Web 框架。 下面是这些装饰器,以及对应的等价框架取值方式。 | 装饰器 | Express 对应的方法 | Koa/EggJS 对应的方法 | | ----------------------- | -------------------------------- | ----------------------------------------- | | @Session(key?: string) | req.session / req.session\[key] | ctx.session / ctx.session\[key] | | @Param(key?: string) | req.params / req.params\[key] | ctx.params / ctx.params\[key] | | @Body(key?: string) | req.body / req.body\[key] | ctx.request.body / ctx.request.body\[key] | | @Query(key?: string) | req.query / req.query\[key] | ctx.query / ctx.query\[key] | | @Queries(key?: string) | 无 | 无 / ctx.queries\[key] | | @Headers(name?: string) | req.headers / req.headers\[name] | ctx.headers / ctx.headers\[name] | 警告 **注意** EggJS 和其他框架不同,`@Queries` 装饰器和 `@Query` **有所区别**。 Queries 会将相同的 key 聚合到一起,变为数组。当用户访问的接口参数为 `/?name=a&name=b` 时,@Queries 会返回 `{name: [a, b]}`,而 Query 只会返回 `{name: b}`。 ### Query[​](#query "Query的直接链接") 在 URL 中 `?` 后面的部分是一个 Query String,这一部分经常用于 GET 类型的请求中传递参数。例如 ``` GET /user?uid=1&sex=male ``` 就是用户传递过来的参数。 **示例:从装饰器获取** ``` // src/controller/user.ts import { Controller, Get, Query } from "@midwayjs/core"; @Controller('/user') export class UserController { @Get('/') async getUser(@Query('uid') uid: string): Promise { // xxxx } } ``` **示例:从 API 获取** ``` // src/controller/user.ts import { Controller, Get, Inject } from "@midwayjs/core"; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/') async getUser(): Promise { const query = this.ctx.query; // { // uid: '1', // sex: 'male', // } } } ``` 警告 **注意** EggJS 和其他框架不同,在 当 Query String 中的 key 重复时,`ctx.query` 只取 key 第一次出现时的值,后面再出现的都会被忽略。 比如 `GET /user?uid=1&uid=2` 通过 `ctx.query` 拿到的值是 `{ uid: '1' }`。 ### Body[​](#body "Body的直接链接") 虽然我们可以通过 URL 传递参数,但是还是有诸多限制: * [浏览器中会对 URL 的长度有所限制](http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers),如果需要传递的参数过多就会无法传递。 * 服务端经常会将访问的完整 URL 记录到日志文件中,有一些敏感数据通过 URL 传递会不安全。 在前面的 HTTP 请求报文示例中,我们看到在 header 之后还有一个 body 部分,我们通常会在这个部分传递 POST、PUT 和 DELETE 等方法的参数。一般请求中有 body 的时候,客户端(浏览器)会同时发送 `Content-Type` 告诉服务端这次请求的 body 是什么格式的。Web 开发中数据传递最常用的两类格式分别是 `JSON` 和 `Form`。 框架内置了 [bodyParser](https://github.com/koajs/bodyparser) 中间件来对这两类格式的请求 body 解析成 object 挂载到 `ctx.request.body` 上。HTTP 协议中并不建议在通过 GET、HEAD 方法访问时传递 body,所以我们无法在 GET、HEAD 方法中按照此方法获取到内容。 **示例:获取单个 body** ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/user') export class UserController { @Post('/') async updateUser(@Body('uid') uid: string): Promise { // id 等价于 ctx.request.body.uid } } ``` \*\*示例:获取整个 body \*\* ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/user') export class UserController { @Post('/') async updateUser(@Body() user: User): Promise { // user 等价于 ctx.request.body 整个 body 对象 // => output user // { // uid: '1', // name: 'harry', // } } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Post('/') async getUser(): Promise { const body = this.ctx.request.body; // { // uid: '1', // name: 'harry', // } } } ``` **示例:获取 query 和 body 参数** 装饰器可以组合使用。 ``` @Post('/') async updateUser(@Body() user: User, @Query('pageIdx') pageIdx: number): Promise { // user 从 body 获取 // pageIdx 从 query 获取 } ``` 框架对 bodyParser 设置了一些默认参数,配置好之后拥有以下特性: * 当请求的 Content-Type 为 `application/json`,`application/json-patch+json`,`application/vnd.api+json` 和 `application/csp-report` 时,会按照 json 格式对请求 body 进行解析,并限制 body 最大长度为 `1mb`。 * 当请求的 Content-Type 为 `application/x-www-form-urlencoded` 时,会按照 form 格式对请求 body 进行解析,并限制 body 最大长度为 `1mb`。 * 如果解析成功,body 一定会是一个 Object(可能是一个数组)。 警告 常见错误: `ctx.request.body` 和 `ctx.body` 混淆,后者其实是 `ctx.response.body` 的简写。 ### Router Params[​](#router-params "Router Params的直接链接") 如果路由上使用 `:xxx` 的格式来声明路由,那么参数可以通过 `ctx.params` 获取到。 **示例:从装饰器获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Param } from '@midwayjs/core'; @Controller('/user') export class UserController { @Get('/:uid') async getUser(@Param('uid') uid: string): Promise { // xxxx } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/:uid') async getUser(): Promise { const params = this.ctx.params; // { // uid: '1', // } } } ``` ### Header[​](#header "Header的直接链接") 除了从 URL 和请求 body 上获取参数之外,还有许多参数是通过请求 header 传递的。框架提供了一些辅助属性和方法来获取。 * `ctx.headers`,`ctx.header`,`ctx.request.headers`,`ctx.request.header`:这几个方法是等价的,都是获取整个 header 对象。 * `ctx.get(name)`,`ctx.request.get(name)`:获取请求 header 中的一个字段的值,如果这个字段不存在,会返回空字符串。 * 我们建议用 `ctx.get(name)` 而不是 `ctx.headers['name']`,因为前者会自动处理大小写。 **示例:从装饰器获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Headers } from '@midwayjs/core'; @Controller('/user') export class UserController { @Get('/:uid') async getUser(@Headers('cache-control') cacheSetting: string): Promise { // no-cache // ... } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/:uid') async getUser(): Promise { const cacheSetting = this.ctx.get('cache-control'); // no-cache } } ``` ### Cookie[​](#cookie "Cookie的直接链接") HTTP 请求都是无状态的,但是我们的 Web 应用通常都需要知道发起请求的人是谁。为了解决这个问题,HTTP 协议设计了一个特殊的请求头:[Cookie](https://en.wikipedia.org/wiki/HTTP_cookie)。服务端可以通过响应头(set-cookie)将少量数据响应给客户端,浏览器会遵循协议将数据保存,并在下次请求同一个服务的时候带上(浏览器也会遵循协议,只在访问符合 Cookie 指定规则的网站时带上对应的 Cookie 来保证安全性)。 通过 `ctx.cookies`,我们可以在 Controller 中便捷、安全的设置和读取 Cookie。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // set cookie this.ctx.cookies.set('foo', 'bar', { encrypt: true }); // get cookie this.ctx.cookies.get('foo', { encrypt: true }); } } ``` Cookie 虽然在 HTTP 中只是一个头,但是通过 `foo=bar;foo1=bar1;` 的格式可以设置多个键值对。 Cookie 在 Web 应用中经常承担了传递客户端身份信息的作用,因此有许多安全相关的配置,不可忽视,[Cookie](/docs/3.0.0/cookie_session.md#%E9%BB%98%E8%AE%A4%E7%9A%84-cookies) 文档中详细介绍了 Cookie 的用法和安全相关的配置项,可以深入阅读了解。 ### Session[​](#session "Session的直接链接") 通过 Cookie,我们可以给每一个用户设置一个 Session,用来存储用户身份相关的信息,这份信息会加密后存储在 Cookie 中,实现跨请求的用户身份保持。 框架内置了 [Session](https://github.com/midwayjs/midway/tree/main/packages/session) 插件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 Session 上的内容 const userId = this.ctx.session.userId; const posts = await this.ctx.service.post.fetch(userId); // 修改 Session 的值 this.ctx.session.visited = ctx.session.visited ? (ctx.session.visited + 1) : 1; // ... } } ``` Session 的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为 `null`: ``` ctx.session = null; ``` 和 Cookie 一样,Session 也有许多安全等选项和功能,在使用之前也最好阅读 [Session](/docs/3.0.0/cookie_session.md#%E9%BB%98%E8%AE%A4%E7%9A%84-session) 文档深入了解。 ### 上传的文件[​](#上传的文件 "上传的文件的直接链接") 上传的文件一般使用 `multipart/form-data` 协议头,由 `@Files` 装饰器获取,由于上传功能由 upload 组件提供,具体可以参考 [upload 组件](/docs/3.0.0/extensions/upload.md)。 ### 其他的参数[​](#其他的参数 "其他的参数的直接链接") 还有一些比较常见的参数装饰器,以及它们的对应方法。 | 装饰器 | Express 对应的方法 | Koa/EggJS 对应的方法 | | ------------ | ------------------ | -------------------- | | @RequestPath | req.baseurl | ctx.path | | @RequestIP | req.ip | ctx.ip | **示例:获取 body 、path 和 ip** ``` @Post('/') async updateUser( @Body('id') id: string, @RequestPath() p: string, @RequestIP() ip: string): Promise { } ``` ### 自定义请求参数装饰器[​](#自定义请求参数装饰器 "自定义请求参数装饰器的直接链接") 你可以快速通过`createRequestParamDecorator` 创建自定义请求参数装饰器。 ``` import { createRequestParamDecorator } from '@midwayjs/core'; // 实现装饰器 export const Token = () => { return createRequestParamDecorator(ctx => { return ctx.headers.token; }); }; // 使用装饰器 export class UserController { async invoke(@Token() token: string) { console.log(token); } } ``` ## 请求参数类型转换[​](#请求参数类型转换 "请求参数类型转换的直接链接") 如果是简单类型,Midway 会自动将参数转换为用户声明的类型。 比如: 数字类型 ``` @Get('/') async getUser(@Query('id') id: number): Promise { console.log(typeof id) // number } ``` 布尔类型 * 当值为 0,"0", "false" 则转为 false,其余返回 Boolean(value) 的值 ``` @Get('/') async getUser(@Query('id') id: boolean): Promise { console.log(typeof id) // boolean } ``` 如果是复杂类型,如果指定的类型是 Class,将会自动转换为该类的实例。 ``` // class class UserDTO { name: string; getName() { return this.name; } } @Get('/') async getUser(@Query() query: UserDTO): Promise { // query.getName() } ``` 如果不希望被转换,可以使用 Interface。 ``` interface User { name: string; } @Get('/') async getUser(@Query() query: User): Promise { // ... } ``` ## 参数校验[​](#参数校验 "参数校验的直接链接") 参数校验功能由 validate 组件提供,具体可以参考 [validate 组件](/docs/3.0.0/extensions/validate.md)。 ## 设置 HTTP 响应[​](#设置-http-响应 "设置 HTTP 响应的直接链接") ### 设置返回值[​](#设置返回值 "设置返回值的直接链接") 绝大多数的数据都是通过 body 发送给请求方的,和请求中的 body 一样,在响应中发送的 body,也需要有配套的 Content-Type 告知客户端如何对数据进行解析。 * 作为一个 RESTful 的 API 接口 controller,我们通常会返回 Content-Type 为 `application/json` 格式的 body,内容是一个 JSON 字符串。 * 作为一个 html 页面的 controller,我们通常会返回 Content-Type 为 `text/html` 格式的 body,内容是 html 代码段。 在 Midway 中你可以简单的使用 `return` 来返回数据。 ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 返回字符串 return "Hello Midwayjs!"; // 返回 json return { a: 1, b: 2, }; // 返回 html return '

Hello

'; // 返回 stream return fs.createReadStream('./good.png'); } } ``` 也可以使用 koa 原生的 API。 ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { // 返回字符串 this.ctx.body = "Hello Midwayjs!"; // 返回 json this.ctx.body = { a: 1, b: 2, }; // 返回 html this.ctx.body = '

Hello

'; // 返回 stream this.ctx.body = fs.createReadStream('./good.png'); } } ``` 警告 注意:`ctx.body` 是 `ctx.response.body` 的简写,不要和 `ctx.request.body` 混淆了。 ### 设置状态码[​](#设置状态码 "设置状态码的直接链接") 默认情况下,响应的**状态码**总是**200**,我们可以通过在处理程序层添加 `@HttpCode` 装饰器或者通过 API 来轻松更改此行为。 当发送错误时,如 `4xx/5xx`,可以使用 [异常处理](/docs/3.0.0/error_filter.md) 抛出错误的方式实现。 **示例:使用装饰器** ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @HttpCode(201) async home() { return "Hello Midwayjs!"; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.status = 201; // ... } } ``` 信息 状态码不能在响应流关闭后(response.end之后)修改。 ### 设置响应头[​](#设置响应头 "设置响应头的直接链接") Midway 提供 `@SetHeader` 装饰器或者通过 API 来简单的设置自定义响应头。 **示例:使用装饰器** ``` import { Controller, Get, SetHeader } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @SetHeader('x-bbb', '123') async home() { return "Hello Midwayjs!"; } } ``` 当有多个响应头需要修改的时候,你可以直接传入对象。 ``` import { Controller, Get, SetHeader } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @SetHeader({ 'x-bbb': '123', 'x-ccc': '234' }) async home() { return "Hello Midwayjs!"; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.set('x-bbb', '123'); // ... } } ``` 信息 响应头不能在响应流关闭后(response.end之后)修改。 ### 重定向[​](#重定向 "重定向的直接链接") 如果需要简单的将某个路由重定向到另一个路由,可以使用 `@Redirect` 装饰器。 `@Redirect` 装饰器的参数为一个跳转的 URL,以及一个可选的状态码,默认跳转的状态码为 `302` 。 此外,也可以通过 API 来跳转。 **示例:使用装饰器** ``` import { Controller, Get, Redirect } from '@midwayjs/core'; @Controller('/') export class LoginController { @Get('/login_check') async check() { // TODO } @Get('/login') @Redirect('/login_check') async login() { // TODO } @Get('/login_another') @Redirect('/login_check', 302) async loginAnother() { // TODO } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.redirect('/login_check'); // ... } } ``` 信息 重定向不能在响应流关闭后(response.end之后)修改。 ### 响应类型[​](#响应类型 "响应类型的直接链接") 虽然浏览器会自动根据内容判断最佳的响应内容,但是我们经常会碰到需要手动设置的情况。我们也提供了 `@ContentType` 装饰器用于设置响应类型。 此外,也可以通过 API 来设置。 **示例:使用装饰器** ``` import { Controller, Get, ContentType } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @ContentType('html') async login() { return 'hello world'; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.type = 'html'; // ... } } ``` 信息 响应类型不能在响应流关闭后(response.end之后)修改。 ### 流式响应[​](#流式响应 "流式响应的直接链接") 如果希望以流式返回数据,可以使用 Node.js 原始的 response 对象上的 `write` 和 `end` 方法。 ``` import { Controller, Get, Inject, sleep } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.status = 200; this.ctx.set('Transfer-Encoding', 'chunked'); for (let i = 0; i < 100; i++) { await sleep(100); this.ctx.res.write('abc'.repeat(100)); } this.ctx.res.end(); } } ``` ### 高级响应处理[​](#高级响应处理 "高级响应处理的直接链接") 从 v3.17.0 开始,框架提供了一个新的的 `HttpServerResponse` 来处理返回数据,除了普通的数据之外,还提供了自定义状态模版,文件下载,SSE 等能力支持,具体请查看 [数据响应章节](/docs/data_response.md) ## 内部重定向[​](#内部重定向 "内部重定向的直接链接") 从 v3.12.0 开始,框架提供了一个内部重定向 API `ctx.forward(url)`,仅支持 koa/egg 类型。 和外部重定向不同的地方在于,内部重定向不会修改浏览器的 URL,只在程序内部流转。 ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { return this.ctx.forward('/api'); } @Get('/api') async api() { return 'abc'; } } ``` 注意,内部重定向有一些规则: * 1、重定向会保留原始路由的所有参数,即透传整个 ctx * 2、重定向只能在相同的 http method 中进行 * 3、重定向不会再执行一遍 Web Middleware,不会执行守卫,但是会执行拦截器和参数装饰器 ## 全局路由前缀[​](#全局路由前缀 "全局路由前缀的直接链接") 需要在 `src/config/config.default` 配置中设置。 注意,不同组件在不同的关键字配置下: * koa * Egg.js * Express ``` // src/config/config.default.ts export default { koa: { globalPrefix: '/v1' } }; ``` ``` // src/config/config.default.ts export default { egg: { globalPrefix: '/v1' } }; ``` ``` // src/config/config.default.ts export default { express: { globalPrefix: '/v1' } }; ``` 配置后,所有的路由都会自动增加该前缀。 如有特殊路由不需要,可以使用装饰器参数忽略。 **示例:Controller 级别忽略** ``` // 该 Controller 下所有路由都将忽略全局前缀 @Controller('/api', {ignoreGlobalPrefix: true}) export class HomeController { // ... } ``` **示例:路由级别忽略** ``` @Controller('/') export class HomeController { // 该路由不会忽略 @Get('/', {}) async homeSet() { } // 该路由会忽略全局前缀 @Get('/bbc', {ignoreGlobalPrefix: true}) async homeSet2() { } } ``` ## 路由优先级[​](#路由优先级 "路由优先级的直接链接") midway 已经统一对路由做排序,通配的路径将自动降低优先级,在最后被加载。 规则如下: * 1、绝对路径规则优先级最高如 `/ab/cb/e` * 2、星号只能出现最后且必须在/后面,`如 /ab/cb/**` * 3、如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高,比如 `/abc/*` 和 `/abc/d`,那么请求 `/abc/d` 时,会匹配到后一个绝对的路由 * 4、有多个通配能匹配一个路径时,最长的规则匹配,如 `/ab/**` 和 `/ab/cd/**` 在匹配 `/ab/cd/f` 时命中 `/ab/cd/**` * 5、如果 `/` 与 `/*` 都能匹配 `/` ,但 `/` 的优先级高于 `/*` * 6、如果都为通配,但是其余权重都一样,比如 `/:page/page` 和 `/page/:page` ,那么两者权重等价,以编码加载顺序为准 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如: ``` @Controller('/api') export class APIController { @Get('/invoke/*') async invokeAll() { } @Get('/invoke/abc') async invokeABC() { } } ``` 这种情况下,会先注册 `/invoke/abc` ,保证优先级更高。 不同的 Controller 的优先级,我们会以长度进行排序, `/` 根 Controller 我们将会最后加载。 --- # Cookies 和 Session HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: * 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息) * 个性化设置(如用户自定义设置、主题等) * 浏览器行为跟踪(如跟踪分析用户行为等) Cookie 在 Web 应用中经常承担标识请求方身份的功能,所以 Web 应用在 Cookie 的基础上封装了 Session 的概念,专门用做用户身份识别。 ## 适用范围[​](#适用范围 "适用范围的直接链接") * `@midwayjs/web` 下(即 egg)内置的是 egg 自带的 Cookie,未提供替换能力,不适用本文档 * `@midwayjs/express` 下(即 express)内置的是 express 自带的 Cookie 库,未提供替换能力,不适用本文档 ## 默认的 Cookies[​](#默认的-cookies "默认的 Cookies的直接链接") Midway 提供了 `@midwayjs/cookies` 模块来操作 Cookie。 同时在 `@midwayjs/koa` 中,默认提供了从上下文直接读取、写入 cookie 的方法 * `ctx.cookies.get(name, [options])` 读取上下文请求中的 cookie * `ctx.cookies.set(name, value, [options])` 在上下文中写入 cookie 示例如下: ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // set cookie this.ctx.cookies.set('foo', 'bar', { encrypt: true }); // get cookie this.ctx.cookies.get('foo', { encrypt: true }); } } ``` ## 设置 Cookie[​](#设置-cookie "设置 Cookie的直接链接") 使用 `ctx.cookies.set(key, value, options)` API 来设置 Cookie。 设置 Cookie 其实是通过在 HTTP 响应中设置 set-cookie 头完成的,每一个 set-cookie 都会让浏览器在 Cookie 中存一个键值对。在设置 Cookie 值的同时,协议还支持许多参数来配置这个 Cookie 的传输、存储和权限。 这些选项包括: | 选项 | 类型 | 描述 | 支持版本 | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | | path | String | 设置键值对生效的 URL 路径,默认设置在根路径上(`/`),也就是当前域名下的所有 URL 都可以访问这个 Cookie。 | | | domain | String | 设置键值对生效的域名,默认没有配置,可以配置成只在指定域名才能访问。 | | | expires | Date | 设置这个键值对的失效时间,如果设置了 maxAge,expires 将会被覆盖。如果 maxAge 和 expires 都没设置,Cookie 将会在浏览器的会话失效(一般是关闭浏览器时)的时候失效。 | | | maxAge | Number | 设置这个键值对在浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。如果设置了 maxAge,expires 将会被覆盖。 | | | secure | Boolean | 设置键值对 [只在 HTTPS 连接上传输](http://stackoverflow.com/questions/13729749/how-does-cookie-secure-flag-work),框架会帮我们判断当前是否在 HTTPS 连接上自动设置 secure 的值。 | | | httpOnly | Boolean | 设置键值对是否可以被 js 访问,默认为 true,不允许被 js 访问 | | | partitioned | Boolean | 设置独立分区状态([CHIPS](https://developers.google.com/privacy-sandbox/3pcd/chips))的 Cookie。注意,只有 `secure` 为 true 且 Chrome >=114 版本此配置才会生效 | @midwayjs/cookies >= 1.1.0 | | removeUnpartitioned | Boolean | 是否删除非独立分区状态的同名 cookie。注意,只有 `partitioned` 为 true 的时候此配置才会生效 | @midwayjs/cookies >= 1.2.0 | | priority | String | 设置 Cookie 的 [优先级](https://developer.chrome.com/blog/new-in-devtools-81?hl=zh-cn#cookiepriority),可选值为 `Low`、`Medium`、`High`,仅对 Chrome >= 81 版本有效 | @midwayjs/cookies >= 1.1.0 | 除了这些属性之外,框架另外扩展了 3 个参数: | 选项 | 类型 | 描述 | | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | overwrite | Boolean | 设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头。 | | signed | Boolean | 设置是否对 Cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true。 | | encrypt | Boolean | 设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false。 | 在设置 Cookie 时,我们需要考虑这个 Cookie 是否需要被前端获取,失效时间多久等等。 示例: ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.cookies.set('cid', 'hello world', { domain: 'localhost', // 写cookie所在的域名 path: '/index', // 写cookie所在的路径 maxAge: 10 * 60 * 1000, // cookie有效时长 expires: new Date('2017-02-15'), // cookie失效时间 httpOnly: false, // 是否只用于http请求中获取 overwrite: false, // 是否允许重写 }); ctx.body = 'cookie is ok'; } } ``` **默认的配置下,Cookie 是加签不加密的,浏览器可以看到明文,js 不能访问,不能被客户端(手工)篡改。** 如果想要 Cookie 在浏览器端可以被 js 访问并修改: ``` ctx.cookies.set(key, value, { httpOnly: false, signed: false, }); ``` 如果想要 Cookie 在浏览器端不能被修改,不能看到明文: ``` ctx.cookies.set(key, value, { httpOnly: true, // 默认就是 true encrypt: true, // 加密传输 }); ``` ## 获取 Cookie[​](#获取-cookie "获取 Cookie的直接链接") 使用 `ctx.cookies.get(key, options)` API 来获取 Cookie。 由于 HTTP 请求中的 Cookie 是在一个 header 中传输过来的,通过框架提供的这个方法可以快速的从整段 Cookie 中获取对应的键值对的值。上面在设置 Cookie 的时候,我们可以设置 `options.signed` 和 `options.encrypt` 来对 Cookie 进行签名或加密,因此对应的在获取 Cookie 的时候也要传相匹配的选项。 * 如果设置的时候指定为 signed,获取时未指定,则不会在获取时对取到的值做验签,导致可能被客户端篡改。 * 如果设置的时候指定为 encrypt,获取时未指定,则无法获取到真实的值,而是加密过后的密文。 如果要获取前端或者其他系统设置的 Cookie,需要指定参数 `signed` 为 `false`,避免对它做验签导致获取不到 Cookie 的值。 ``` ctx.cookies.get('frontend-cookie', { signed: false, }); ``` ## Cookie 秘钥[​](#cookie-秘钥 "Cookie 秘钥的直接链接") 由于我们在 Cookie 中需要用到加解密和验签,所以需要配置一个秘钥供加密使用。 默认脚手架会在配置文件 `src/config/config.default.ts` 中自动生成一个秘钥,也可以自己修改。 ``` // src/config/config.default export default { keys: ['key1','key2'], } ``` keys 默认是一个字符串,可以分隔配置多个 key。Cookie 在使用这个配置进行加解密时: * 加密和加签时只会使用第一个秘钥。 * 解密和验签时会遍历 keys 进行解密。 如果我们想要更新 Cookie 的秘钥,但是又不希望之前设置到用户浏览器上的 Cookie 失效,可以将新的秘钥配置到 keys 最前面,等过一段时间之后再删去不需要的秘钥即可。 ## 默认的 Session[​](#默认的-session "默认的 Session的直接链接") 默认的 `@midwayjs/koa` ,内置了 Session 组件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 Session 上的内容 const userId = this.ctx.session.userId; const posts = await this.ctx.service.post.fetch(userId); // 修改 Session 的值 this.ctx.session.visited = ctx.session.visited ? (ctx.session.visited + 1) : 1; // ... } } ``` Session 的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为 null: ``` ctx.session = null; ``` 需要 **特别注意** 的是:设置 session 属性时需要避免以下几种情况(会造成字段丢失,详见 [koa-session](https://github.com/koajs/session/blob/master/lib/session.js#L37-L47) 源码) * 不要以 `_` 开头 * 不能为 `isNew` ``` // ❌ 错误的用法 ctx.session._visited = 1; // --> 该字段会在下一次请求时丢失 ctx.session.isNew = 'HeHe'; // --> 为内部关键字, 不应该去更改 // ✔️ 正确的用法 ctx.session.visited = 1; // --> 此处没有问题 ``` Session 的实现是基于 Cookie 的,默认配置下,用户 Session 的内容加密后直接存储在 Cookie 中的一个字段中,用户每次请求我们网站的时候都会带上这个 Cookie,我们在服务端解密后使用。Session 的默认配置如下: ``` export default { session: { maxAge: 24 * 3600 * 1000, // 1天 key: 'MW_SESS', httpOnly: true, }, // ... } ``` 可以看到这些参数除了 `key` 都是 Cookie 的参数,`key` 代表了存储 Session 的 Cookie 键值对的 key 是什么。在默认的配置下,存放 Session 的 Cookie 将会加密存储、不可被前端 js 访问,这样可以保证用户的 Session 是安全的。 ## 函数下的 Session[​](#函数下的-session "函数下的 Session的直接链接") 在函数弹性容器的场景下,默认未内置 Session 模块,如果需要可以手动添加。 ``` { "dependencies": { "@midwayjs/session": "^3.0.0", // ... }, } ``` 在 configuration 中引入组件。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as faas from '@midwayjs/faas'; import * as session from '@midwayjs/session'; @Configuration({ imports: [ faas, session, // ... ] }) export class MainConfiguration { // ... } ``` ## Session 示例[​](#session-示例 "Session 示例的直接链接") ### 修改用户 Session 失效时间[​](#修改用户-session-失效时间 "修改用户 Session ��失效时间的直接链接") 虽然在 Session 的配置中有一项是 maxAge,但是它只能全局设置 Session 的有效期,我们经常可以在一些网站的登陆页上看到有 **记住我** 的选项框,勾选之后可以让登陆用户的 Session 有效期更长。这种针对特定用户的 Session 有效时间设置我们可以通过 `ctx.session.maxAge=` 来实现。 ``` import { Inject, Controller, Post, Body, Provide, FORMAT } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { UserService } from './service/user.service'; @Controller('/') export class UserController { @Inject() ctx: Context; @Inject() userService: UserService; @Post('/') async login(@Body() data) { const { username, password, rememberMe } = data; const user = await this.userService.loginAndGetUser(username, password); // 设置 Session this.ctx.session.user = user; // 如果用户勾选了 `记住我`,设置 30 天的过期时间 if (rememberMe) { this.ctx.session.maxAge = FORMAT.MS.ONE_DAY * 30; } } } ``` ### 延长用户 Session 有效期[​](#延长用户-session-有效期 "延长用户 Session 有效期的直接链接") 默认情况下,当用户请求没有导致 Session 被修改时,框架都不会延长 Session 的有效期,但是在有些场景下,我们希望用户如果长时间都在访问我们的站点,则延长他们的 Session 有效期,不让用户退出登录态。框架提供了一个 `renew` 配置项用于实现此功能,它会在发现当用户 Session 的有效期仅剩下最大有效期一半的时候,重置 Session 的有效期。 ``` // src/config/config.default.ts export default { session: { renew: true, // ... }, // ... } ``` ### 调整 SameSite 配置以允许跨域访问[​](#调整-samesite-配置以允许跨域访问 "调整 SameSite 配置以允许跨域访问的直接链接") 默认情况下,框架不会设置 Session Cookie 的 SameSite 选项。从 Chrome 84 版本开始,SameSite 选项为空的 Cookie 默认将不会在跨域请求时发送,即默认按照 SameSite=Lax 处理。一般情况下,如果用户都是直接访问你的应用,这不会有问题。如果你的应用需要支持跨域访问,比如被其他应用 iframe 嵌入,或者允许配置 CORS 跨域请求,则需要调整 SameSite 选项,将其设置为更为宽松的 SameSite=None: ``` // src/config/config.default.ts export default { session: { sameSite: 'none', // 需要指定 Secure,否则 SameSite=None 无效 secure: true, // ... }, // ... } ``` 可以阅读 [SameSite Cookie 说明](https://web.dev/articles/samesite-cookies-explained?hl=zh-cn) 了解更多 SameSite 选项。 ## 自定义 Session Store[​](#自定义-session-store "自定义 Session Store的直接链接") 过多的将数据放在 Session 中并不太合理,大部分情况下,我们只需要在 Session 中存储一些 Id,来保证安全性。虽然我们觉得 Cookie 作为存储 Session 已经足够,但是在某些极端情况下,还是需要使用例如 Redis 来存储 Session 的情况。 不同的上层框架使用了不同的 Session 方案,下面列举了一些 Session 替换方案 * [@midwayjs/koa 方案](https://github.com/midwayjs/midway/tree/main/packages/session#custom-session-store) * [@midwayjs/express 方案](https://github.com/midwayjs/midway/tree/main/packages/express-session) * [@midwayjs/web(egg)方案](https://github.com/eggjs/egg-session) --- # 自定义数据响应 在大多数正常的逻辑中,返回数据只需要 `return` 相应的对象。 ``` ``` --- # 自定义装饰器 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: * 定义可继承的属性装饰器 * 定义可包裹方法,做拦截的方法装饰器 * 定义修改参数的参数装饰器 我们考虑到了装饰器当前在标准中的阶段以及后续风险,Midway 提供的自定义装饰器方式及其配套能力由框架实现,以尽可能的规避后续规范变化带来的问题。 一般,我们推荐将自定义装饰器放到 `src/decorator` 目录中。 比如: ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── decorator ## 自定义装饰器 │ │ └── user.decorator.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` ## 装饰器 API[​](#装饰器-api "装饰器 API的直接链接") Midway 内部有一套标准的装饰器管理 API,用来将装饰器对接依赖注入容器,实现扫描和扩展,这些 API 方法我们都从 `@midwayjs/core` 包进行导出。 通过装饰器高级 API,我们可以自定义装饰器,并且将元数据附加其中,内部的各种装饰器都是通过该能力实现的。 常见的扩展 API 有: **装饰器** * `saveModule` 用于保存某个类到某个装饰器 * `listModule` 获取所有绑定到某类型装饰器的 class **元信息存取 (对应** [**reflect-metadata**](https://www.npmjs.com/package/reflect-metadata)**)** * `saveClassMetadata` 保存元信息到 class * `attachClassMetadata` 附加元信息到 class * `getClassMetadata` 从 class 获取元信息 * `savePropertyDataToClass` 保存属性的元信息到 class * `attachPropertyDataToClass` 附加属性的元信息到 class * `getPropertyDataFromClass` 从 class 获取属性元信息 * `listPropertyDataFromClass` 列出 class 上保存的所有的属性的元信息 * `savePropertyMetadata` 保存属性元信息到属性本身 * `attachPropertyMetadata` 附加属性元信息到属性本身 * `getPropertyMetadata` 从属性上获取保存的元信息 **快捷操作** * `getProviderUUId`获取 class provide 出来的 uuid,对应某个类,不会变 * `getProviderName` 获取 provide 时保存的 name,一般为类名小写 * `getProviderId` 获取 class 上 provide 出来的 id,一般为类名小写,也可能是自定义的 id * `isProvide` 判断某个类是否被 @Provide 修饰过 * `getObjectDefinition` 获取对象定义(ObjectDefiniton) * `getParamNames` 获取一个函数的所有参数名 * `getMethodParamTypes` 获取某个方法的参数类型,等价于 `Reflect.getMetadata(design:paramtypes)` * `getPropertyType` 获取某个属性的类型,等价于 `Reflect.getMetadata(design:type)` * `getMethodReturnTypes` 获取方法返回值类型,等价于 `Reflect.getMetadata(design:returntype)` ## 类装饰器[​](#类装饰器 "类装饰器的直接链接") 一般类装饰器都会和其他装饰器配合使用,用来标注某个类属于特定的一种场景,比如 `@Controller` 表示了类属于 Http 场景的入口。 我们举一个例子,定义一个类装饰器 @Model ,标识 class 是一个模型类,然后进一步操作。 首先创建一个装饰器文件,比如 `src/decorator/model.decorator.ts` 。 ``` import { Scope, ScopeEnum, saveClassMetadata, saveModule, Provide } from '@midwayjs/core'; // 提供一个唯一 key export const MODEL_KEY = 'decorator:model'; export function Model(): ClassDecorator { return (target: any) => { // 将装饰的类,绑定到该装饰器,用于后续能获取到 class saveModule(MODEL_KEY, target); // 保存一些元数据信息,任意你希望存的东西 saveClassMetadata( MODEL_KEY, { test: 'abc', }, target ); // 指定 IoC 容器创建实例的作用域,这里注册为请求作用域,这样能取到 ctx Scope(ScopeEnum.Request)(target); // 调用一下 Provide 装饰器,这样用户的 class 可以省略写 @Provide() 装饰器了 Provide()(target); }; } ``` 上面只是定义了这个装饰器,我们还要实现相应的功能,midway v2 开始有生命周期的概念,可以在 `configuration` 中的生命周期中执行。 ``` // src/configuration.ts import { listModule, Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { MODEL_KEY } from './decorator/model.decorator'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... // 可以获取到所有装饰了 @Model() 装饰器的 class const modules = listModule(MODEL_KEY); for (let mod of modules) { // 实现自定义能力 // 比如,拿元数据 getClassMetadata(mod) // 比如,提前初始化 app.applicationContext.getAsync(mod); } } } ``` 最后,我们要使用这个装饰器。 ``` import { Model } from '../decorator/model.decorator'; // Model 的作用是我们自己的逻辑能被执行(保存的元数据) @Model() export class UserModel { // ... } ``` ## 属性装饰器[​](#属性装饰器 "属性装饰器的直接链接") Midway 提供了 `createCustomPropertyDecorator` 方法,用于创建自定义属性装饰器,框架的 `@Logger` ,`@Config` 等装饰器都是这样创建而来的。 和 TypeScript 中定义的装饰器不同的是,Midway 提供的属性装饰器,可以在继承中使用。 我们举个例子,假如现在有一个内存缓存,我们的属性装饰器用于获取缓存数据,下面是一些准备工作。 ``` // 简单的缓存类 import { Configuration, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryStore extends Map { save(key, value) { this.set(key, value); } get(key) { return this.get(key); } } // src/configuration.ts // 入口实例化,并保存一些数据 import { Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() store: MemoryStore; async onReady() { // ... // 初始化一些数据 store.save('aaa', 1); store.save('bbb', 1); } } ``` 我们来实现一个简单的 `@MemoryCache()` 装饰器。属性装饰器的实现分为两部分: * 1、定义一个装饰器方法,一般只保存元数据 * 2、定义一个实现,在装饰器逻辑执行前即可 下面是定义装饰器方法的部分。 ``` // src/decorator/memoryCache.decorator.ts import { createCustomPropertyDecorator } from '@midwayjs/core'; // 装饰器内部的唯一 id export const MEMORY_CACHE_KEY = 'decorator:memory_cache_key'; export function MemoryCache(key?: string): PropertyDecorator { return createCustomPropertyDecorator(MEMORY_CACHE_KEY, { key, }); } ``` 在装饰器的方法执行之前(一般在初始化的地方)去实现。实现装饰器,我们需要用到内置的 `MidwayDecoratorService` 服务。 ``` import { Configuration, Inject, Init, MidwayDecoratorService } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { MEMORY_CACHE_KEY, MemoryStore } from 'decorator/memoryCache.decorator'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() store: MemoryStore; @Inject() decoratorService: MidwayDecoratorService; @Init() async init() { // ... // 实现装饰器 this.decoratorService.registerPropertyHandler(MEMORY_CACHE_KEY, (propertyName, meta) => { return this.store.get(meta.key); }); } } ``` `registerPropertyHandler` 方法包含两个参数,第一个是之前装饰器定义的唯一 id,第二个是装饰器实现的回调方法。 `propertyName` 是装饰器装饰的方法名,meta 是装饰器的使用时的参数。 然后我们就能使用这个装饰器了。 ``` import { MemoryCache } from 'decorator/memoryCache.decorator'; // ... export class UserService { @MemoryCache('aaa') cacheValue; async invoke() { console.log(this.cacheValue); // => 1 } } ``` ## 方法装饰器[​](#方法装饰器 "方法装饰器的直接链接") Midway 提供了 `createCustomMethodDecorator` 方法,用于创建自定义方法装饰器。 和 TypeScript 中定义的装饰器不同的是,Midway 提供的方法装饰器,由拦截器统一实现,和其他拦截方式不冲突,并且更加简单。 我们以打印方法执行时间为例。 和属性装饰器相同,我们的定义与实现是分离的。 下面是定义装饰器方法的部分。 ``` // src/decorator/logging.decorator.ts import { createCustomMethodDecorator } from '@midwayjs/core'; // 装饰器内部的唯一 id export const LOGGING_KEY = 'decorator:logging_key'; export function LoggingTime(formatUnit = 'ms'): MethodDecorator { // 我们传递了一个可以修改展示格式的参数 return createCustomMethodDecorator(LOGGING_KEY, { formatUnit }); } ``` 实现的部分,同样需要使用框架内置的 `DecoratorService` 服务。 ``` //... function formatDuring(value, formatUnit: string) { // 这里返回时间格式化 if (formatUnit === 'ms') { return `${value} ms`; } else if (formatUnit === 'min') { // return xxx } } @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现方法装饰器 this.decoratorService.registerMethodHandler(LOGGING_KEY, (options) => { return { around: async (joinPoint: JoinPoint) => { // 拿到格式化参数 const format = options.metadata.formatUnit || 'ms'; // 记录开始时间 const startTime = Date.now(); // 执行原方法 const result = await joinPoint.proceed(...joinPoint.args); const during = formatDuring(Date.now() - startTime, format); // 打印执行时间 this.logger.info(`Method ${joinPoint.methodName} invoke during ${during}`); // 返回执行结果 return result; }, }; }); } } ``` `registerMethodHandler` 方法的第一个参数是装饰器定义的 id,第二个参数是回调的实现,参数为 options 对象,包含: | 参数 | 类型 | 描述 | | -------------------- | ------------- | ---------------------- | | options.target | new (...args) | 装饰器修饰所在的类 | | options.propertyName | string | 装饰器修饰所在的方法名 | | options.metadata | | 装饰器本身的参数 | 回调的实现,需要返回一个由拦截器处理的方法,key 为拦截器的 `before`,`around`,`afterReturn`,`afterThrow`,`after` 这几个可拦截的生命周期。 由于方法装饰器本身是拦截器实现的,所以具体的拦截方法可以查看 [拦截器](/docs/3.0.0/aspect.md) 部分。 使用装饰器如下: ``` // ... export class UserService { @LoggingTime() async getUser() { // ... } } // 执行时 // output => Method "getUser" invoke during 4ms ``` 警告 注意,被装饰的方法必须为 async 方法。 ## 无需实现的方法装饰器[​](#无需实现的方法装饰器 "无需实现的方法装饰器的直接链接") 默认情况下,自定义的方法装饰器必须有一个实现,否则运行期会报错。 在某些特殊情况,希望有一个无需实现的装饰器,比如只需要存储元数据而不做拦截。 可以在定义装饰器的时候,增加一个 impl 参数。 ``` // src/decorator/logging.decorator.ts import { createCustomMethodDecorator } from '@midwayjs/core'; // 装饰器内部的唯一 id export const LOGGING_KEY = 'decorator:logging_key'; export function LoggingTime(): MethodDecorator { // 最后一个参数告诉框架,无需指定实现 return createCustomMethodDecorator(LOGGING_KEY, {}, false); } ``` ## 参数装饰器[​](#参数装饰器 "参数装饰器的直接链接") Midway 提供了 `createCustomParamDecorator` 方法,用于创建自定义参数装饰器。 参数装饰器,一般用于修改参数值,提前预处理数据等,Midway 的 `@Query` 等请求系列的装饰器都基于其实现。 和其他装饰器相同,我们的定义与实现是分离的,我们以获取参数中的用户(ctx.user)来举例。 下面是定义装饰器方法的部分。 ``` // src/decorator/logging.decorator.ts import { createCustomParamDecorator } from '@midwayjs/core'; // 装饰器内部的唯一 id export const USER_KEY = 'decorator:user_key'; export function User(): ParameterDecorator { return createCustomParamDecorator(USER_KEY, {}); } ``` 实现的部分,同样需要使用框架内置的 `DecoratorService` 服务。 ``` //... @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现参数装饰器 this.decoratorService.registerParameterHandler(USER_KEY, (options) => { // originArgs 是原始的方法入参 // 这里第一个参数是 ctx,所以取 ctx.user return options.originArgs[0]?.user ?? {}; }); } } ``` `registerParameterHandler` 方法的第一个参数是装饰器定义的 id,第二个参数是回调的实现,参数为 options 对象,包含: | 参数 | 类型 | 描述 | | ----------------------- | ------------- | ---------------------- | | options.target | new (...args) | 装饰器修饰所在的类 | | options.propertyName | string | 装饰器修饰所在的方法名 | | options.metadata | \| undefined | 装饰器本身的参数 | | options.originArgs | Array | 方法原始的参数 | | options.originParamType | | 方法原始的参数类型 | | options.parameterIndex | number | 装饰器修饰的参数索引 | 使用装饰器如下: ``` // ... export class UserController { @Inject() userService: UserService; @Inject() ctx: Context; async getUser() { return await this.getUser(ctx); } } export class UserService { async getUser(@User() user: string) { console.log(user); // => xxx } } ``` 提示 注意,为了方法调用的正确性,如果参数装饰器中报错,框架会使用原始的参数来调用方法,不会直接抛出异常。 你可以在开启 `NODE_DEBUG=midway:debug` 环境变量时找到这个错误。 警告 注意,被装饰的方法必须为 async 方法。 ## 方法装饰器获取上下文[​](#方法装饰器获取上下文 "方法装饰器获取上下文的直接链接") 在请求链路上,如果自定义了装饰器要获取上下文往往比较困难,如果代码没有显式的注入上下文,装饰器中获取会非常困难。 在 Midway 的依赖注入的请求作用域中,我们将上下文绑定到了每个实例上,从实例的特定属性 `REQUEST_OBJ_CTX_KEY` 上即可获取当前的上下文,从而进一步对请求做操作。 比如在我们自定义实现的方法装饰器中: ``` import { REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; //... export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现方法装饰器 this.decoratorService.registerMethodHandler(LOGGING_KEY, (options) => { return { around: async (joinPoint: JoinPoint) => { // 装饰器所在的实例 const instance = joinPoint.target; const ctx = instance[REQUEST_OBJ_CTX_KEY]; // ctx.xxxx // ... }, }; }); } } ``` --- # 自定义错误 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 通过扩展标准 Error,Midway 提供了内置的错误类型,额外增加了一些属性。 ``` export class MidwayError extends Error { // ... } ``` 现阶段,所有 Midway 框架提供的错误,都是该错误类抛出的实例。 MidwayError 包括几个属性: * name 错误的名字,比如 Error,TypeError 等,在自定义错误中,为自定义错误的类名 * message 错误的消息 * stack 错误的堆栈 * code 自定义错误码 * cause 错误的来源 我们可以通过简单的实例化并且抛出来使用,比如: ``` import { MidwayError } from '@midwayjs/core'; // ... async findAll() { throw new MidwayError('my custom error'); } ``` 也可以在业务中自定义一些错误。 常见的,我们会把异常统一定义到 error 目录中。 ``` ➜ my_midway_app tree . ├── src │ └── error │ ├── customA.error.ts │ └── customB.error.ts ├── test ├── package.json └── tsconfig.json ``` 如果业务有一些复用的异常,比如固定的错误 ``` // src/error/custom.error.ts import { MidwayError } from '@midwayjs/core'; export class CustomError extends MidwayError { constructor() { super('my custom error', 'CUSTOM_ERROR_CODE_10000'); } } ``` 然后在业务中抛出使用。 ``` import { CustomError } from './error/custom.error'; // ... async findAll() { throw new CustomError(); } ``` 上面的 `CUSTOM_ERROR_CODE_10000` 为错误的错误码,一般我们会为不同的错误分配不同的错误码和错误消息,以方便排查问题。 ## 自定义错误码[​](#自定义错误码 "自定义错误码的直接链接") 框架提供了一种通用的注册错误码的机制,错误码后期可以方便的排错,统计。 在业务的错误定义,以及组件错误定义的时候非常有用。 错误码一般是个枚举值,比如: ``` const CustomErrorEnum = { UNKNOWN: 10000, COMMON: 10001, PARAM_TYPE: 10002, // ... }; ``` 在编码中,我们会提供固定的错误码,并且希望在 SDK 或者组件中不冲突,这就需要框架来支持。 Midway 提供了 `registerErrorCode` 方法,用于向框架注册不重复的错误码,并且进行一定的格式化。 比如,在框架内部,我们有如下的定义: ``` import { registerErrorCode } from '@midwayjs/core'; export const FrameworkErrorEnum = registerErrorCode('midway', { UNKNOWN: 10000, COMMON: 10001, PARAM_TYPE: 10002, // ... } as const); ``` `registerErrorCode` 包含两个参数: * 错误分组,比如上面的 `midway` ,就是框架内置错误组名,在一个应用中,这个组名不应该重复 * 错误枚举对象,以错误名为 key,错误码为 value 方法会返回一个错误枚举值,枚举值会以错误名作为 key,错误分组加错误码作为 value。 比如: ``` FrameworkErrorEnum.UNKNOWN // => output: MIDWAY_10000 FrameworkErrorEnum.COMMON // => output: MIDWAY_10001 ``` 这样,当错误中出现 `MIDWAY_10000` 的错误码时,我们就知道是什么错误了,配合文档就可以沉淀所有的错误。 在错误定义时,直接使用这个错误码枚举即可。 ``` export class MidwayParameterError extends MidwayError { constructor(message?: string) { super(message ?? 'Parameter type not match', FrameworkErrorEnum.PARAM_TYPE); } } // user code async findAll(data) { if (!data.user) { throw new MidwayParameterError(); } // ... } // output // 2022-01-02 14:02:29,124 ERROR 14259 MidwayParameterError: Parameter type not match // at APIController.findAll (.... // at /Users/harry/project/midway-v3/packages/core/src/common/webGenerator.ts:38:57 // at processTicksAndRejections (node:internal/process/task_queues:96:5) { // code: 'MIDWAY_10002', // cause: undefined, // } ``` --- # 数据订阅 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 Midway 提供了 `DataListener` 的抽象,用于方便的创建这种模式的代码。 ## 实现数据订阅[​](#实现数据订阅 "实现数据订阅的直接链接") 我们以一个简单的 **内存数据更新** 的需求为例。 数据订阅在 midway 中也是一个普通的类,比如我们也可以把他放到 `src/listener/memory.listner.ts` 中。 我们只需要继承内置的 `DataListener` 类,同时,一般数据订阅类为单例。 `DataListener` 包含一个泛型类型,需要声明该数据订阅返回的数据类型。 比如: ``` // src/listener/memory.listner.ts import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { DataListener } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryDataListener extends DataListener { // 初始化数据 initData() { return 'hello' + Date.now(); } // 更新数据 onData(setData) { setInterval(() => { setData('hello' + Date.now()); }, 1000); } } ``` `DataListener` 类有两个必须实现的方法: * `initData` 数据的初始化方法 * `onData` 数据订阅更新的方法 示例中,我们初始化了数据,同时实现了数据更新的方法,每隔 1 秒钟,我们会使用 `setData` 来更新内置的数据。 此外,大部分的数据订阅会使用到定时器,或者其他外部的 sdk,我们需要考虑好关闭和清理资源的情况。 代码中提供了 `destroyListener` 方法来处理。 比如上面的示例代码,我们需要关闭定时器。 ``` // src/listener/memory.listner.ts import { Provide, Scope, ScopeEnum, DataListener } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryDataListener extends DataListener { private intervalHandler; // 初始化数据 initData() { return 'hello' + Date.now(); } // 更新数据 onData(setData) { this.intervalHandler = setInterval(() => { setData('hello' + Date.now()); }, 1000); } // 清理资源 async destroyListener() { // 关闭定时器 clearInterval(this.intervalHandler); // 其他清理, close sdk 等等 } } ``` 上面的 `initData` 方法可以异步获取数据。 ``` // ... export class MemoryDataListener extends DataListener { async initData() { // ... } } ``` ## 使用数据订阅[​](#使用数据订阅 "使用数据订阅的直接链接") 我们可以在任意的代码中使用它,在业务中通过 `getData` 方法来获取当前的数据,不需要考虑数据变化的情况。 比如: ``` import { Provide, Inject } from '@midwayjs/core'; import { MemoryDataListener } from '../listener/memory.listner.ts'; @Provide() export class UserService { @Inject() memoryDataListener: MemoryDataListener; async getUserHelloData() { const helloData = this.memoryDataListener.getData(); // helloData => helloxxxxxxxx // ... } } ``` 数据订阅模式可以方便的将变化的数据隐藏在普通类中,而透出不变化的 API,使得标准的业务代码在逻辑和流程上都变的简洁。 --- # 数据响应 从 v3.17.0 开始,框架添加了 `ServerResponse` 和 `HttpServerResponse` 的实现。 通过这个功能,可以定制服务端的响应成功和失败时的通用格式,规范整个返回逻辑。 ## Http 通用响应[​](#http-通用响应 "Http 通用响应的直接链接") 在 koa 场景下,一般都会处理一些逻辑,最后返回一个结果。在此过程中,会出现返回成功和失败的情况。 最为常见实现会在 `ctx` 增加一些方法,包括数据后返回。 ``` import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { try { // ... return this.ctx.ok(/*...*/); } catch (err) { return this.ctx.fail(/*...*/); } } } ``` 也有人会在 Web 中间件中处理成功的返回,在错误过滤器中处理失败的返回。 为了解决这类代码难以统一维护的问题,框架提供了一套统一返回的方案。 我们以最为常见的返回 JSON 数据为例。 通过创建 `HttpServerResponse` 实例后,调用 `json()` 方法,链式返回数据。 ``` import { Controller, Get, Inject, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/success') async home() { return new HttpServerResponse(this.ctx).success().json({ // ... }); } @Get('/fail') async home2() { return new HttpServerResponse(this.ctx).fail().json({ // ... }); } } ``` 默认情况下,`HttpServerResponse` 在成功和失败的场景上会提供 JSON 的通用包裹结构。 比如在成功的场景下,接收到的数据如下。 ``` { success: 'true', data: //... } ``` 而在失败的场景下,接收到的数据如下。 ``` { success: 'false', message: //... } ``` 注意,`json()` 方法是数据设置的方法,必须在最后一个调用。 ### 常用的响应格式[​](#常用的响应格式 "常用的响应格式的直接链接") `HttpServerResponse` 需要传递一个当前请求的上下文对象 `ctx` 才能实例化。 ``` const serverResponse = new HttpServerResponse(this.ctx); ``` 之后以链式的形式进行调用。 ``` // json serverResponse.json({ a: 1, }); // text serverResponse.text('abcde'); // blob serverResponse.blob(Buffer.from('hello world')); ``` 除了设置数据的方法,还提供了一些其他的快捷方法可以组合使用。 ``` // status serverResponse.status(200).text('abcde'); // header serverResponse.header('Content-Type', 'text/html').text('
hello
'); // headers serverResponse.headers({ 'Content-Type': 'text/plain', 'Content-Length': '100' }).text('a'.repeat(100)); ``` ### 响应模版[​](#响应模版 "响应模版的直接链接") 针对不同的设置数据的方法,框架提供了不同模版以供用户自定义。 比如 `json()` 方法的模版如下。 ``` class ServerResponse { // ... static JSON_TPL = (data: Record, isSuccess: boolean): unknown => { if (isSuccess) { return { success: 'true', data, }; } else { return { success: 'false', message: data || 'fail', }; } }; } ``` 我们可以将全局的模版进行覆盖达到自定义的目的。 ``` HttpServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { // ... } else { // ... } }; ``` 也可以通过继承,自定义不同的响应模版,这样可以不影响全局的默认模板。 ``` class CustomServerResponse extends HttpServerResponse {} CustomServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { // ... } else { // ... } }; ``` 在使用时,创建实例即可。 ``` // ... @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { return new CustomServerResponse(this.ctx).success().json({ // ... }); } } ``` 此外,针对 `text` ,`blob` 方法的模版均可以覆盖。 ``` HttpServerResponse.TEXT_TPL = (data, isSuccess) => { /*...*/}; HttpServerResponse.BLOB_TPL = (data, isSuccess) => { /*...*/}; ``` ### 数据流式响应[​](#数据流式响应 "数据流式响应的直接链接") 使用内置的 `HttpServerResponse` 中的 `stream` 方法来处理流式数据返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const res = new HttpServerResponse(this.ctx).stream(); setTimeout(() => { for (let i = 0; i < 100; i++) { await sleep(100); res.send('abc'.repeat(100)); } res.end(); }, 1000); return res; } } ``` 通过 `STEAM_TPL` 可以修改数据的返回结构 ``` HttpServerResponse.STREAM_TPL = (data) => { /*...*/}; ``` 注意,这个模版只处理成功的数据。 ### 文件流式响应[​](#文件流式响应 "文件流式响应的直接链接") 从 v3.17.0 开始,可以通过 `HttpServerResponse` 简单处理文件下载。 传递一个文件路径即可,默认会使用 `application/octet-stream` 响应头返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const filePath = join(__dirname, '../../package.json'); return new HttpServerResponse(this.ctx).file(filePath); } } ``` 如需返回不同的类型,可以通过第二个参数指定类型。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const filePath = join(__dirname, '../../package.json'); return new HttpServerResponse(this.ctx).file(filePath, 'application/json'); } } ``` 通过 `FILE_TPL` 可以修改返回结构。 ``` HttpServerResponse.FILE_TPL = (data: Readable, isSuccess: boolean) => { /*...*/}; ``` ### SSE 响应[​](#sse-响应 "SSE 响应的直接链接") 从 v3.17.0 开始,框架提供了内置的 SSE (Server-Sent Events)支持。 SSE 的数据定义如下,你需要按下面的格式返回。 ``` export interface ServerSendEventMessage { data?: string | object; event?: string; id?: string; retry?: number; } ``` 通过 `HttpServerResponse` 定义一个返回实例。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const res = new HttpServerResponse(this.ctx).sse(); // ... return res; } } ``` 可以通过 `send` 和 `sendEnd` 进行数据传递。 ``` const res = new HttpServerResponse(this.ctx).sse(); res.send({ data: 'abcde' }); res.sendEnd({ data: 'end' }); ``` 调用 `sendEnd` 后,请求将被关闭。 也可以通过 `sendError` 发送错误。 ``` const res = new HttpServerResponse(this.ctx).sse(); res.sendError(new Error('test error')); ``` 通过 `SSE_TPL` 可以修改返回结构。 ``` import { ServerSendEventMessage } from '@midwayjs/core'; HttpServerResponse.FILE_TPL = (data: ServerSendEventMessage) => { /*...*/}; ``` 注意,这个模版只处理成功的数据,不会处理 `sendError` 的情况,且返回也必须是 `ServerSendEventMessage` 格式。 ## 基础数据响应[​](#基础数据响应 "基础数据响应的直接链接") 除了 Http 场景之外,框架提供了基础的 `ServerResponse` 类,用于其他的场景。 `ServerResponse` 包含 `json`,`text`,`blob` 三种数据返回方法,以及 `success` 和 `fail` 这两个设置状态的方法。 行为和 `HttpServerResponse` 一致。 通过继承、覆盖等行为,可以非常简单的处理响应值。 比如我们对不同的用户做返回区分。 ``` // src/response/api.ts export class UserServerResponse extends HttpServerResponse {} UserServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { return { status: 200, ...data, }; } else { return { status: 500, message: 'limit exceed' }; } }; export class AdminServerResponse extends HttpServerResponse {} AdminServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { return { status: 200, router: data.router, ...data }; } else { return { status: 500, message: 'interal error', ...data }; } }; ``` 使用返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { UserServerResponse, AdminServerResponse } from '../response/api'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // ... if (this.ctx.user === 'xxx') { return new AdminServerResponse(this.ctx).json({ router: '/', dbInfo: { // ... }, userInfo: { role: 'admin', }, status: 'ok', }); } return new UserServerResponse(this.ctx).json({ status: 'ok', }); } } ``` --- # 数据源管理 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 虽然我们可以使用服务工厂来进行抽象,但是不管是语义,还是部分功能,和服务工厂还是略有不同,比如实体类的加载等能力,这都是数据源特有的。 为此,Midway 提供了 `DataSourceManager` 的抽象,方便数据源的管理。 我们以 `mysql2` 来举例,实现一个 `mysql2` 的连接池管理类。 下面是 `mysql2` 官方的示例,作为准备工作。 ``` // get the client const mysql = require('mysql2'); // create the connection to database const connection = mysql.createConnection({ host: 'localhost', user: 'root', database: 'test' }); // simple query connection.query( 'SELECT * FROM `table` WHERE `name` = "Page" AND `age` > 45', function(err, results, fields) { console.log(results); // results contains rows returned by server console.log(fields); // fields contains extra meta data about results, if available } ); ``` 和服务工厂类似,我们需要实现一些固定的方法。 * 1、创建数据源的方法 * 2、检查连接的方法 ## 实现数据源管理器[​](#实现数据源管理器 "实现数据源管理器的直接链接") 数据源管理器在 midway 中也是一个普通的导出类,比如我们也可以把他放到 `src/manager/mysqlDataSourceManager.ts` 中。 ### 1、实现创建数据源接口[​](#1实现创建数据源接口 "1、实现创建数据源接口的直接链接") 我们只需要继承内置的 `DataSourceManager` 类,就能实现一个数据源管理器。 `DataSourceManager` 包含一个泛型类型,需要声明该数据源的数据类型。 ``` import { Provide, Scope, ScopeEnum, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { // ... } ``` 由于是抽象类,我们需要实现其中的几个基本方法。 ``` import { Provide, Scope, ScopeEnum, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { // 创建单个实例 protected async createDataSource(config: any, dataSourceName: string): Promise { return mysql.createConnection(config); } getName(): string { return 'mysql'; } async checkConnected(dataSource: mysql.Connection): Promise { // 伪代码 return dataSource.status === 'connected'; } async destroyDataSource(dataSource: mysql.Connection): Promise { if (await this.checkConnected(dataSource)) { await dataSource.destroy(); } } } ``` ### 2、提供初始化配置[​](#2提供初始化配置 "2、提供初始化配置的直接链接") 我们可以利用 `@Init` 装饰器和 `@Config` 装饰器提供初始化配置。 ``` import { Provide, Scope, ScopeEnum, Init, Config, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { @Config('mysql') mysqlConfig; @Inject() baseDir: string; @Init() async init() { // 需要注意的是,这里第二个参数需要传入一个实体类扫描地址 await this.initDataSource(this.mysqlConfig, this.baseDir); } // ... } ``` 在 `src/config/config.default` 中,我们可以提供多数据源的配置,来创建多个数据源。 比如: ``` // config.default.ts export const mysql = { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test' }, dataSource2: { host: 'localhost', user: 'root', database: 'test' }, dataSource3: { host: 'localhost', user: 'root', database: 'test' }, } // 其他配置 } ``` 数据源天然就是为了多个实例而设计的,和服务工厂不同,没有单个和多个的配置区别。 ## 实体绑定[​](#实体绑定 "实体绑定的直接链接") 数据源最重要的一环是实体类,每个数据源都可以拥有自己的实体类。比如 typeorm 等 orm 框架,都是基于此来设计的。 ### 1、显式关联实体类[​](#1显式关联实体类 "1、显式关联实体类的直接链接") 实体类一般是和表结构相同的类。 比如: ``` // src/entity/user.entity.ts // 这里是伪代码,装饰器需要自行实现 @Entity() export class SimpleUser { @Column() name: string; } @Entity() export class User { @Column() name: string; @Column() age: number; } ``` 数据源管理器通过固定的配置,将这些实体类和数据源进行绑定。 ``` // config.default.ts import { User, SimpleUser } from '../entity/user.entity'; export default { mysql: { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test', entities: [User] }, dataSource2: { host: 'localhost', user: 'root', database: 'test', entities: [SimpleUser] }, // ... } } } ``` 每个数据源的 `entities` 配置,都可以添加各自的实体类。 ### 2、目录扫描关联实体[​](#2目录扫描关联实体 "2、目录扫描关联实体的直接链接") 在某些情况下,我们也可以通过通配的路径来替代,比如: ``` // config.default.ts import { User, SimpleUser } from '../entity/user.entity'; export default { mysql: { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test', entities: [ User, SimpleUser, 'entity', // 特定目录(等价于目录通配) '**/abc/**', // 仅获取包含 abc 字符的目录下的文件 'abc/**/*.ts', // 特定目录 + 通配 'abc/*.entity.ts', // 匹配后缀 '**/*.entity.ts', // 通配加后缀匹配 '**/*.{j,t}s', // 后缀匹配 ] }, // ... // ... } } } ``` 警告 注意 * 1、填写目录字符串时,以 initDataSource 方法的第二个参数作为相对路径查找,默认为 baseDir(src 或者 dist) * 2、如果匹配后缀,entities 的路径注意包括 js 和 ts 后缀,否则编译后会找不到实体 * 3、字符串路径的写法不支持 [单文件构建部署](/docs/3.0.0/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2)(bundle模式) ### 2、根据实体获取数据源[​](#2根据实体获取数据源 "2、根据实体获取数据源的直接链接") 一般我们的 API 都是在数据源对象上,比如 `connection.query`。 所以在很多时候,比如自定义装饰器,都需要一个从实体获取到数据源对象的方法。 ``` // 下面为伪代码 import { SimpleUser } from '../entity/user.entity'; class UserService { // 这里一般会注入一个实体类对应的 Model,包含增删改查方法 @InjectEntityModel(SimpleUser) userModel; } ``` 如果在实体类仅对应一个数据源的情况下,我们可以通过 `getDataSourceNameByModel` 来获取数据源。 ``` this.mysqlDataSourceManager.getDataSourceNameByModel(SimpleUser); // => dataSource1 ``` 多个的情况下,该方法获取的数据源不一定准确,会拿到最后设置的一个数据源。 这种时候一般需要用户手动指定数据源,比如: ``` // 下面为伪代码 import { SimpleUser } from '../entity/user.entity'; class UserService { @InjectEntityModel(SimpleUser, 'dataSource2') userModel; } ``` 也可以通过 `defaultDataSourceName` 配置显式指定默认的数据源。 ``` // config.default.ts export const mysql = { dataSource: { dataSource1: { // ... }, dataSource2: { // ... }, dataSource3: { // ... }, } defaultDataSourceName: 'dataSource2', } ``` ## 获取数据源[​](#获取数据源 "获取数据源的直接链接") 通过注入数据源管理器,我们可以通过其上面的方法来拿到数据源。 ``` import { MySqlDataSourceManager } from './manager/mysqlDataSourceManager'; import { join } from 'path'; @Provide() export class UserService { @Inject() mysqlDataSourceManager: MySqlDataSourceManager; async invoke() { const dataSource = this.mysqlDataSourceManager.getDataSource('dataSource1'); // TODO } } ``` 此外,还有一些其他方法。 ``` // 数据源是否存在 this.mysqlDataSourceManager.hasDataSource('dataSource1'); // 获取所有的数据源名 this.mysqlDataSourceManager.getDataSourceNames(); // 数据源是否连接 this.mysqlDataSourceManager.isConnected('dataSource1') ``` --- # 调试 本章节介绍如何在常用编辑器中调试 Midway 项目。 ## 在 VSCode 中调试[​](#在-vscode-中调试 "在 VSCode 中调试的直接链接") ### 方法一:使用 JavaScript Debug Teminal[​](#方法一使用-javascript-debug-teminal "方法一:使用 JavaScript Debug Teminal的直接链接") 在 VSCode 的终端下拉出,隐藏着一个 `JavaScript Debug Terminal` ,点击它,创建出来的终端将自带调试能力。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01HWzQEu1cQ6C7q9OYh_!!6000000003594-2-tps-1030-364.png) 输入任意的命令都将自动开启 Debug,比如输入 `npm run dev` 后。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01nnkbOQ1YN79M1svVV_!!6000000003046-2-tps-1500-570.png) ### 方法二:配置调试文件[​](#方法二配置调试文件 "方法二:配置调试文件的直接链接") 创建一个 vscode 的启动文件。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01WzgZwN23WVMLYP4Xs_!!6000000007263-2-tps-645-344.png) 随便选一个,会创建 `.vscode/launch.json` 文件, ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01pP7ntf1HRNMmTeGBT_!!6000000000754-2-tps-655-231.png) 将下面内容复制进去。 ``` { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [{ "name": "Midway Local", "type": "node", "request": "launch", "cwd": "${workspaceRoot}", "runtimeExecutable": "npm", "windows": { "runtimeExecutable": "npm.cmd" }, "runtimeArgs": [ "run", "dev" ], "env": { "NODE_ENV": "local" }, "console": "integratedTerminal", "protocol": "auto", "restart": true, "port": 7001, "autoAttachChildProcesses": true }] } ``` 启动断点即可。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01AGHSI51zZvrKgS9xx_!!6000000006729-2-tps-1470-1020.png) ## 在 WebStorm/Idea 中调试[​](#在-webstormidea-中调试 "在 WebStorm/Idea 中调试的直接链接") 开始配置 IDE。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01bmrjiW1frz9dLpdEZ_!!6000000004061-2-tps-1110-692.png) 配置 npm 命令。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01e4yJnU1QT3MOImlpR_!!6000000001976-2-tps-620-946.png) 选择你的 `package.json` 后,下拉选择 `Scrips` ,其中是你 `package.json` 中配置好的 `scripts` 中的命令,选择你要的命令,比如 `dev` 或者 `test` 等即可 。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01DBqmwD1rtbwqpuQZe_!!6000000005689-2-tps-1500-1017.png) 在代码上断点后执行调试即可。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01sGzfeH1iLPpzSIWSg_!!6000000004396-2-tps-1327-907.png) --- # 现有装饰器索引 Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 ## @midwayjs/core[​](#midwayjscore "@midwayjs/core的直接链接") | 装饰器 | 修饰位置 | 描述 | | ------------------ | ------------ | ----------------------------------------- | | @Provide | Class | 暴露一个 class,让 IoC 容器能够获取元数据 | | @Inject | Property | 注入一个 IoC 容器中的对象 | | @Scope | Class | 指定作用域 | | @Init | Method | 标注对象初始化时自动执行的方法 | | @Destroy | Method | 标注对象销毁时执行的方法 | | @Async | Class | 【已废弃】表明为异步函数 | | @Autowire | Class | 【已废弃】标识类为自动注入属性 | | @Autoload | Class | 让类可以自加载执行 | | @Configuration | Class | 标识一个容器入口配置类 | | @Aspect | Class | 标识拦截器 | | @Validate | Method | 标识方法,需要被验证 | | @Rule | Property | 标识 DTO 的校验规则 | | @App | Property | 注入当前应用实例 | | @Config | Property | 获取配置 | | @Logger | Property | 获取日志实例 | | @Controller | Class | 标识为一个 Web 控制器 | | @Get | Method | 注册为一个 GET 类型的路由 | | @Post | Method | 注册为一个 POST 类型的路由 | | @Del | Method | 注册为一个 DELETE 类型的路由 | | @Put | Method | 注册为一个 PUT 类型的路由 | | @Patch | Method | 注册为一个 PATCH 类型的路由 | | @Options | Method | 注册为一个 OPTIONS 类型的路由 | | @Head | Method | 注册为一个 HEAD 类型的路由 | | @All | Method | 注册为一个全类型的路由 | | @Session | Parameter | 从参数获取 ctx.session | | @Body | Parameter | 从参数获取 ctx.request.body | | @Query | Parameter | 从参数获取 ctx.query | | @Param | Parameter | 从参数获取 ctx.param | | @Headers | Parameter | 从参数获取 ctx.headers | | @File | Parameter | 从参数获取第一个上传文件 | | @Files | Parameter | 从参数获取所有的上传文件 | | @Fields | Parameter | 从参数获取表单 Field(上传时) | | @Redirect | Method | 修改响应跳转 | | @HttpCode | Method | 修改响应状态码 | | @SetHeader | Method | 修改响应头 | | @ContentType | Method | 修改响应头中的 Content-Type 字段 | | @Schedule | Class | 标识为一个 egg 定时任务 | | @Plugin | Property | 获取 egg 插件 | | @Provider | Class | 暴露微服务提供者(生产者) | | @Consumer | Class | 暴露微服务调用者(消费者) | | @GrpcMethod | Method | 标识暴露的 gRPC 方法 | | @Func | Class/Method | 【已废弃】标识为一个函数入口 | | @Handler | Method | 【已废弃】配合标记函数 | | @ServerlessTrigger | Method | 标识一个函数触发器 | | @Task | Method | 定义一个分布式任务 | | @TaskLocal | Method | 定义一个本地任务 | | @Queue | Class | 定义一个自触发的任务 | ## @midwayjs/typeorm[​](#midwayjstypeorm "@midwayjs/typeorm的直接链接") | 装饰器 | 修饰位置 | 作用 | | --------------------- | -------- | ---------------- | | @EntityModel | Class | 定义一个实体对象 | | @InjectEntityModel | Property | 注入一个实体对象 | | @EventSubscriberModel | Class | 定义事件订阅 | ## @midwayjs/validate[​](#midwayjsvalidate "@midwayjs/validate的直接链接") | 装饰器 | 修饰位置 | 描述 | | --------- | -------- | ---------------------- | | @Rule | Property | 定义一个规则 | | @Validate | Method | 标识一个需要校验的方法 | ## @midwayjs/swagger[​](#midwayjsswagger "@midwayjs/swagger的直接链接") | 装饰器 | 修饰位置 | 描述 | | ----------------------- | ----------------- | ---- | | `@ApiBody` | Method | | | `@ApiExcludeEndpoint` | Method | | | `@ApiExcludeController` | Class | | | `@ApiHeader` | Class/Method | | | `@ApiHeaders` | Class/Method | | | `@ApiOperation` | Method | | | `@ApiProperty` | Property | | | `@ApiPropertyOptional` | Property | | | `@ApiResponseProperty` | Property | | | `@ApiQuery` | Method | | | `@ApiResponse` | Method | | | `@ApiTags` | Controller/Method | | | `@ApiExtension` | Method | | | `@ApiBasicAuth` | Controller | | | `@ApiBearerAuth` | Controller | | | `@ApiCookieAuth` | Controller | | | `@ApiOAuth2` | Controller | | | `@ApiSecurity` | Controller | | | `@ApiParam` | Method | | | `@ApiParam` | Method | | --- # 启动和部署 Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 ## 本地开发[​](#本地开发 "本地开发的直接链接") 这里列举的主要是本地使用 `dev` 命令开发的方式,有两种。 ### 快速启动单个服务[​](#快速启动单个服务 "快速启�动单个服务的直接链接") 在本地研发时,Midway 在 `package.json` 中提供了一个 `dev` 命令启动框架,比如: * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "dev": "mwtsc --watch --run @midwayjs/mock/app.js", } } ``` 这是一个最精简的命令,他有如下特性: * 1、使用 `mwtsc` 工具构建代码,成功后通过 `@midwayjs/mock` 包中的 `app.js` 文件读取构建后的代码启动项目 * 2、使用内置的 API(@midwayjs/core 的 `initializeGlobalApplicationContext`)创建一个服务,不经过 `bootstrap.js` * 3、单进程运行 ``` { "script": { "dev": "midway-bin dev --ts" } } ``` 这是一个最精简的命令,他有如下特性: * 1、使用 `--ts` 指定 TypeScript(ts-node)环境启动 * 2、使用内置的 API(@midwayjs/core 的 `initializeGlobalApplicationContext`)创建一个服务,不经过 `bootstrap.js` * 3、单进程运行 在命令行运行下面的命令即可执行。 ``` $ npm run dev ``` ### 指定入口启动服务[​](#指定入口启动服务 "指定入口启动服务的直接链接") 由于本地的 dev 命令普通情况下和 `bootstrap.js` 启动文件初始化参数不同,有些用户担心本地开发和线上开发不一致,比如测试链路等。 这个时候我们可以直接传递一个入口文件给 `dev` 命令,直接使用入口文件启动服务。 * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "dev": "mwtsc --watch --run bootstrap.js", }, } ``` ``` { "script": { "dev": "midway-bin dev --ts --entryFile=bootstrap.js" } } ``` ## 部署到服务器[​](#部署到服务器 "部署到服务器的直接链接") ### 部署后和本地开发的区别[​](#部署后和本地开发的区别 "部署后和本地开发的区别的直接链接") 在部署后,有些地方和本地开发有所区别。 **1、node 环境的变化** 最大的不同是,服务器部署后,会直接使用 node 来启动项目。 * 如果使用了 `mwtsc` 开发项目,差距不是很大 * 如果使用了 `@midwayjs/cli`,将不会使用 `ts-node` 来启动项目,这意味着不再读取 `*.ts` 文件 **2、加载目录的变化** 服务器部署后,只会加载构建后的 `dist` 目录,而本地开发则是加载 `src` 目录。 | | 本地 | 服务器 | | ------- | ----------------------- | ------------------------ | | appDir | 项目根目录 | 项目根目录 | | baseDir | 项目根目录下的 src 目录 | 项目根目录下的 dist 目录 | **3、环境的变化** 服务器环境,一般使用 `NODE_ENV=production` ,很多库都会在这个环境下提供性能更好的方式,例如启用缓存,报错处理等。 **4、日志文件** 一般服务器环境,日志不会打印到项目的 logs 目录,而是其他不会受到项目更新影响的目录,比如 `home/admin/logs` ,这样固定的目录,也方便其他工具采集日志。 ### 部署的流程[​](#部署的流程 "部署的流程的直接链接") 整个部署分为几个部分,由于 Midway 是 TypeScript 编写,比传统 JavaScript 代码增加了一个构建的步骤,整个部署的过程如下。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01wSpCuM27pWGTDeDyK_!!6000000007846-2-tps-2212-242.png) 由于部署和平台、环境非常相关,下面我们都将以 Linux 来演示,其他平台可以视情况参考。 ### 编译代码和安装依赖[​](#编译代码和安装依赖 "编译代码和安装依赖的直接链接") 由于 Midway 项目是 TypeScript 编写,在部署前,我们先进行编译。在示例中,我们预先写好了构建脚本,执行 `npm run build` 即可,如果没有,在 `package.json` 中添加下面的 `build` 命令即可。 * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "build": "mwtsc --cleanOutDir", }, } ``` ``` { "scripts": { "build": "midway-bin build -c" }, } ``` 信息 虽然不是必须,但是推荐大家先执行测试和 lint。 一般来说,部署构建的环境和本地开发的环境是两套,我们推荐在一个干净的环境中构建你的应用。 下面的代码,是一个示例脚本,你可以保存为 `build.sh` 执行。 ``` ## 服务器构建(已经下载好代码) $ npm install # 安装开发期依赖 $ npm run build # 构建项目 $ npm prune --production # 移除开发依赖 ## 本地构建(已经安装好 dev 依赖) $ npm run build $ npm prune --production # 移除开发依赖 ``` 信息 一般安装依赖会指定 `NODE_ENV=production` 或 `npm install --production` ,在构建正式包的时候只安装 dependencies 的依赖。因为 devDependencies 中的模块过大而且在生产环境不会使用,安装后也可能遇到未知问题。 执行完构建后,会出现 Midway 构建产物 `dist` 目录。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── node_modules # Node.js 依赖包目录 ├── test ├── bootstrap.js # 部署启动文件 ├── package.json └── tsconfig.json ``` ### 构建时别名(alias path)的问题[​](#构建时别名alias-path的问题 "构建时别名(alias path)的问题的直接链接") 别名是前端工具带来的习惯,而非 Node.js 的标准能力,目前使用有两种可选的方式: * 1、使用 Node.js 自带的 [子路径导入方案](https://nodejs.org/dist/latest/docs/api/packages.html#subpath-imports) * 2、使用 [额外工具](/docs/faq/alias_path.md) 在编译时处理 ### 打包压缩[​](#打包压缩 "打包压缩的直接链接") 构建完成后,你可以简单的打包压缩,上传到待发布的环境。 警告 一般来说服务器运行必须包含的文件或者目录有 `package.json`,`bootstrap.js`,`dist`,`node_modules`。 ### 上传和解压[​](#上传和解压 "上传和解压的直接链接") 有很多种方式可以上传到服务器,比如常见的 `ssh/FTP/git` 等。也可以使用 [OSS](https://www.aliyun.com/product/oss) 等在线服务进行中转。 ### 启动项目[​](#启动项目 "启动项目的直接链接") Midway 构建出来的项目是单进程的,不管是采用 `fork` 模式还是 `cluster` 模式,单进程的代码总是很容易的兼容到不同的体系中,因此非常容易被社区现有的 pm2/forever 等工具所加载, 我们这里以 pm2 来演示如何部署。 项目一般都需要一个入口文件,比如,我们在根目录创建一个 `bootstrap.js` 作为我们的部署文件。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── test ├── bootstrap.js # 部署启动文件 ├── package.json └── tsconfig.json ``` Midway 提供了一个简单方式以满足不同场景的启动方式,只需要安装我们提供的 `@midwayjs/bootstrap` 模块(默认已自带)。 ``` $ npm install @midwayjs/bootstrap --save ``` 然后在入口文件中写入代码,注意,这里的代码使用的是 `JavaScript` 。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.run(); ``` 虽然启动文件的代码很简单,但是我们依旧需要这个文件,在后续的链路追踪等场景中需要用到。 注意,这里不含 http 的启动端口,如果你需要,可以参考文档 修改。 * [修改 koa 端口](/docs/3.0.0/extensions/koa.md#%E4%BF%AE%E6%94%B9%E7%AB%AF%E5%8F%A3) 这个时候,你已经可以直接使用 `NODE_ENV=production node bootstrap.js` 来启动代码了,也可以使用 pm2 来执行启动。 我们一般推荐使用工具来启动 Node.js 项目,下面有一些文档可以进阶阅读。 * [pm2 使用文档](/docs/3.0.0/extensions/pm2.md) * [cfork 使用文档](/docs/3.0.0/extensions/cfork.md) ### 启动参数[​](#启动参数 "启动参数的直接链接") 在大多数情况下,不太需要在 Bootstrap 里配置参数,但是依旧有一些可配置的启动参数选项,通过 `configure` 方法传入。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ imports: [/*...*/] }) .run(); ``` | 属性 | 类型 | 描述 | | -------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | appDir | string | 可选,项目根目录,默认为 `process.cwd()` | | baseDir | string | 可选,项目代码目录,研发时为 `src`,部署时为 `dist` | | imports | Component\[] | 可选,显式的组件引用 | | moduleDetector | 'file' \| IFileDetector \| false | 可选,使用的模块加载方式,默认为 `file` ,使用依赖注入本地文件扫描方式,可以显式指定一个扫描器,也可以关闭扫描 | | logger | Boolean \| ILogger | 可选,bootstrap 中使用的 logger,默认为 consoleLogger | | ignore | string\[] | 可选,依赖注入容器扫描忽略的路径,moduleDetector 为 false 时无效 | | globalConfig | Array<{ \[environmentName: string]: Record\ }> \| Record\ | 可选,全局传入的配置,如果传入对象,则直接以对象形式合并到当前的配置中,如果希望传入不同环境的配置,那么,以数组形式传入,结构和 `importConfigs` 一致。 | **示例,传入全局配置(对象)** ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: { customKey: 'abc' } }) .run(); ``` **示例,传入分环境的配置** ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: [{ default: {/*...*/}, unittest: {/*...*/} }] }) .run(); ``` ## 使用 Docker 部署[​](#使用-docker-部署 "使用 Docker 部署的直接链接") ### 编写 Dockerfile,构建镜像[​](#编写-dockerfile构建镜像 "编写 Dockerfile,构建镜像的直接链接") 步骤一:在当前目录下新增Dockerfile ``` FROM node:18 WORKDIR /app ENV TZ="Asia/Shanghai" COPY . . # 如果各公司有自己的私有源,可以替换registry地址 RUN npm install --registry=https://registry.npm.taobao.org RUN npm run build # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "start"] ``` 步骤二: 新增 `.dockerignore` 文件(类似 git 的 ignore 文件),可以把 `.gitignore` 的内容拷贝到 `.dockerignore` 里面 步骤三:当使用 pm2 部署时,请将命令修改为 `pm2-runtime start` ,pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 步骤四:构建 docker 镜像 ``` $ docker build -t helloworld . ``` 步骤五:运行 docker 镜像 ``` $ docker run -itd -P helloworld ``` 运行效果如下: ![image.png](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882492099-49160b6a-601c-4f08-ba65-b95a1335aedf.png#height=33\&id=BtUCB\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=45\&originWidth=1024\&originalType=binary\&ratio=1\&size=33790\&status=done\&style=none\&width=746) 然后大写的 `-P` 由于给我们默认分配了一个端口,所以我们访问可以访问 `32791` 端口(这个 `-P` 是随机分配,我们也可以使用 `-p 7001:7001` 指定特定端口) ![image.png](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882559686-031bcf0d-2185-42cd-a838-80f008777395.png#height=94\&id=dfag9\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=188\&originWidth=578\&originalType=binary\&ratio=1\&size=24488\&status=done\&style=none\&width=289) 后续:发布 docker 镜像 * 推送构建好的镜像到DockerHub,请参考[官方文档](https://docs.docker.com/get-started/04_sharing_app/) * 推送到自建的镜像仓库(以Harbor为例),请参考[Harbor文档](https://goharbor.io/docs/2.5.0/working-with-projects/working-with-images/pulling-pushing-images/) **优化** 我们看到前面我们打出来的镜像有1个多G,可优化的地方: * 1、我们可以采用更精简的 docker image 的基础镜像:例如 node:18-alpine, * 2、其中的源码最终也打在了镜像中,其实这块我们可以不需要。 我们可以同时结合 docker 的 multistage 功能来做一些优化,这个功能请注意要在 `Docker 17.05` 版本之后才能使用。 ``` FROM node:18 AS build WORKDIR /app COPY . . RUN npm install RUN npm run build FROM node:18-alpine WORKDIR /app COPY --from=build /app/dist ./dist # 把源代码复制过去, 以便报错能报对行 COPY --from=build /app/src ./src COPY --from=build /app/bootstrap.js ./ COPY --from=build /app/package.json ./ RUN apk add --no-cache tzdata ENV TZ="Asia/Shanghai" RUN npm install --production # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "start"] ``` 当前示例的结果只有 `207MB`。相比原有的 `1.26G` 省了很多的空间。 ### 结合 Docker-Compose 运行[​](#结合-docker-compose-运行 "结合 Docker-Compose 运行的直接链接") 在 docker 部署的基础上,还可以结合 docker-compose 配置项目依赖的服务,实现快速部署整个项目。 下面以 midway 结合 redis 为例,使用 docker-compose 快速部署整个项目。 **步骤一:编写Dockerfile** 按照上文使用 Docker 部署的方式[编写Dockerfile](/docs/3.0.0/deployment.md#%E7%BC%96%E5%86%99-dockerfile%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F) **步骤二:编写docker-compose.yml** 新增 `docker-compose.yml` 文件,内容如下:(此处模拟我们的 midway 项目需要使用 redis) ``` # 项目的根目录,与Dockerfile文件同级 version: "3" services: web: build: . ports: - "7001:7001" links: - redis depends_on: - redis redis: image: redis ``` **步骤三:修改配置** 修改 redis 的配置文件,内容如下:( 配置redis,请参考 [redis组件](/docs/3.0.0/extensions/redis.md) ) ``` // src/config/config.default.ts export default { // ... redis: { client: { port: 6379, // redis容器的端口 host: "redis", // 这里与docker-compose.yml文件中的redis服务名称一致 password: "", //默认没有密码,请自行修改为redis容器配置的密码 db: 0, }, }, } ``` **步骤四:构建** 使用命令: ``` $ docker-compose build ``` **步骤五:运行** ``` $ docker-compose up -d ``` ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608884158660-02bd2d3c-08b4-4ecc-a4dd-a18d4b9d2c12.png) **后续** 更多关于 docker-compose ,请参考[官方文档](https://docs.docker.com/compose/) ## 单文件构建部署[​](#单文件构建部署 "单文件构建部署的直接链接") 在某些场景,将项目构建为单文件,部署的文件可以更小,可以更容易的分发部署,在一些场景下特别的高效,如: * Serverless 场景,单文件可以更快的部署 * 私密场景,单文件可以更容易的做加密混淆 Midway 从 v3 开始支持将项目构建为单文件。 不支持的情况有: * egg 项目(@midwayjs/web) * 入口处 `importConfigs` 使用的路径形式引入配置的应用,组件 * 未显式依赖的包,或者包里有基于约定的文件 ### 前置依赖[​](#前置依赖 "前置依赖的直接链接") 单文件构建有一些前置依赖需要安装。 ``` ## 用于生成入口 $ npm i @midwayjs/bundle-helper --save-dev ## 用于构建单文件 ## 装到全局 $ npm i @vercel/ncc -g ## 或者装到项目(推荐) $ npm i @vercel/ncc --save-dev ``` ### 代码调整[​](#代码调整 "代码调整的直接链接") 有一些可能的调整,列举如下: #### 1、配置格式调整[​](#1配置格式调整 "1、配置格式调整的直接链接") 必须将项目引入的配置调整为 [对象模式](/docs/3.0.0/env_config.md)。 Midway 的官方组件都已经调整为该模式,如果有自己编写的组件,也请调整为该模式才能构建为单文件。 提示 Midway v2/v3 均支持配置以 "对象模式" 加载。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class MainConfiguration { } ``` #### 2、默认导出的情况[​](#2默认导出的情况 "2、默认导出的情况的直接链接") 由于 ncc 构建器的默认行为,请 **不要** 在依赖注入相关的代码中使用默认导出。 比如: ``` export default class UserSerivce { // ... } ``` 编译后会导致 `UserSerivce` 无法注入。 #### 3、数据源 entities 相关[​](#3数据源-entities-相关 "3、数据源 entities 相关的直接链接") 数据源依赖的扫描路径也是不支持的。 ``` export default { typeorm: { dataSource: { default: { // ... entities: [ '/abc', // 不支持 ] }, } } ``` 如果 entities 特别多,可以编写一个 js 文件,扫描出 entities 后,生成一个文件到目录下,在每次构建时执行。 ### 修改入口文件[​](#修改入口文件 "修改入口文件的直接链接") 修改入口 `bootstrap.js` 为下列代码。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ // 这里引用的是编译后的入口,本地开发不走这个文件 imports: require('./dist/index'), // 禁用依赖注入的目录扫描 moduleDetector: false, }).run() ``` ### 构建[​](#构建 "构建的直接链接") 单文件构建的编译需要几个步骤: * 1、将项目 ts 文件构建为 js * 2、使用额外编译器,将所有的 js 文件打包成一个文件 我们可以将上面的流程编写为下面的两条命令,放在 `package.json` 的 `scripts` 字段中。 ``` "scripts": { // ... "bundle": "bundle && npm run build && ncc build bootstrap.js -o build", "bundle_start": "NODE_ENV=production node ./build/index.js" }, ``` 包含三个部分 * `bundle` 是将所有的项目代码以组件的形式导出,并生成一个 `src/index.ts` 文件,该命令是 `@midwayjs/bundle-helper` 提供的 * `npm run build` 是基础的 ts 项目构建,将 `src/**/*.ts` 构建为 `dist/**/*.js` * `ncc build bootstrap.js -o build` 以 `bootstrap.js` 为入口构建为一个单文件,最终生成到 `build/index.js` 编写完成后,执行命令。 ``` $ npm run bundle ``` 提示 注意,构建过程中可能有错误,比如 ts 定义错误,入口生成语法不正确等情况,需要手动修复。 编译完成后,启动项目。 ``` $ npm run bundle_start ``` 如果启动访问没问题,那么你就可以拿着构建的 build 目录做分发了。 ## 二进制文件部署[​](#二进制文件部署 "二进制文件部署的直接链接") 将 Node.js 打包为一个单独的可执行文件,部署时直接拷贝执行即可,这种方式包含了 node 运行时,业务代码,有利于保护知识产权。 常见的将 Node.js 打包为可执行文件的工具有 `pkg`、`nexe`、`node-packer`、`enclose` 等,下面我们将以最为常见的 `pkg` 包作为示例。 ### 前置依赖[​](#前置依赖-1 "前置依赖的直接链接") 二进制文件部署有一些前置依赖需要安装。 ``` ## 用于生成入口 $ npm i @midwayjs/bundle-helper --save-dev ## 用于构建二进制文件 ## 装到全局 $ npm i pkg -g ## 或者装到项目(推荐) $ npm i pkg --save-dev ``` ### 代码调整[​](#代码调整-1 "代码调整的直接链接") 和 [单文件构建部署](/docs/3.0.0/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2) 的调整相同,请参考上面的文档。 ### 修改入口文件[​](#修改入口文件-1 "修改入口文件的直接链接") 和 [单文件构建部署](/docs/3.0.0/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2) 的调整相同,请参考上面的文档。 ### 构建[​](#构建-1 "构建的直接链接") 首先需要对 pkg 进行配置,主要内容在 `package.json` 的 `bin` 和 `pkg` 字段下。 * `bin` 我们指定为入口文件,即 `bootstrap.js` * `pkg.scripts` 构建后的目录,使用了 glob 的语法包括了 `dist` 下的所有 js 文件 * `pkg.asserts` 如果有一些静态资源文件,可以在这里配置 * `pkg.targets` 构建的平台产物,是下列选项的组合(示例中我指定了 mac + node18): * **nodeRange** (node8), node10, node12, node14, node16 or latest * **platform** alpine, linux, linuxstatic, win, macos, (freebsd) * **arch** x64, arm64, (armv6, armv7) * `pkg.outputPath` 构建产物的地址,为了和 ts 输出分开,我们选择了 build 目录 `package.json` 参考示例: ``` { "name": "my-midway-project", // ... "devDependencies": { // ... "@midwayjs/bundle-helper": "^1.2.0", "pkg": "^5.8.1" }, "scripts": { // ... "pkg": "pkg . -d > build/pkg.log", "bundle": "bundle && npm run build" }, "bin": "./bootstrap.js", "pkg": { "scripts": "dist/**/*.js", "assets": [], "targets": [ "node18-macos-arm64" ], "outputPath": "build" }, // ... } ``` 更为细节的部分请参考 [pkg文档](https://github.com/vercel/pkg)。 提示 上面的实例中,pkg 命令的 `-d` 参数是为了输出调试信息到特定文件,可以自行删减。 二进制文件构建的编译需要几个步骤: * 1、生成 `src/index.ts` 入口文件,将项目 ts 文件构建为 js * 2、使用 pkg,生成特定平台的构建产物 我们可以执行命令。 ``` $ npm run bundle $ npm run pkg ``` 正确的话,我们可以在 `build` 目录下看到一个 `my-midway-project` 文件(我们的 `package.json` 的 `name` 字段),双击它即可执行。 ## 部署失败的问题[​](#部署失败的问题 "部署失败的问题的直接链接") 部署后由于和环境相关,情况更为复杂,如果部署到服务器之后碰到了问题,请查看 [服务器启动失败排查](/docs/ops/ecs_start_err.md) 。 --- # 多环境配置 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 本篇我们来介绍 Midway 如何加载不同环境的业务配置。 ## 配置文件[​](#配置文件 "配置文件的直接链接") 最为简单的就是使用框架提供的业务配置文件能力。 该能力可以在所有业务代码和组件中使用,贯穿整个 Midway 生命周期。 配置文件可以以两种格式导出,**对象形式** 和 **函数形式**。 提示 经过我们的实践,**对象形式** 会更加的简单友好,可以规避许多错误用法。 大部分文档中我们都将以此形式进行展示。 ### 配置文件目录[​](#配置文件目录 "配置文件目录的直接链接") 我们可以自定义一个目录,在其中放入配置文件。 比如 `src/config` 目录。 ``` ➜ my_midway_app tree . ├── src │ ├── config │ │ ├── config.default.ts │ │ ├── config.prod.ts │ │ ├── config.unittest.ts │ │ └── config.local.ts │ ├── interface.ts │ └── service ├── test ├── package.json └── tsconfig.json ``` 配置文件的名字有一些特定的约定。 `config.default.ts` 为默认的配置文件,所有环境都会加载这个配置文件。 其余的文件名,使用 `config.环境` 作为文件名,具体环境的概念请查看 [运行环境](/docs/3.0.0/environment.md)。 配置不是 **必选项**,请酌情添加自己需要的环境配置。 ### 对象形式[​](#对象形式 "对象形式的直接链接") 配置文件导出的格式为 object,比如: ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { keys: '1639994056460_8009', koa: { port: 7001, }, } as MidwayConfig; ``` ### 函数形式[​](#函数形式 "函数形式的直接链接") 配置文件为一个带有 `appInfo` 参数的函数。这个函数在框架初始化时会被自动执行,将返回值合并进完整的配置对象。 ``` // src/config/config.default.ts import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { keys: '1639994056460_8009', koa: { port: 7001, }, view: { root: path.join(appInfo.appDir, 'view'), }, }; } ``` 这个函数的参数为 `MidwayAppInfo` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | ### 配置文件定义[​](#配置文件定义 "配置文件定义的直接链接") Midway 提供了 `MidwayConfig` 作为统一的配置项定义,所有的组件都会将定义合并到此配置项定义中。每当一个组件被开启(在 `configuration.ts` 中被 `imports` ),`MidwayConfig` 就会自动包含该组件的配置定义。 为此,请尽可能使用文档推荐的格式,以达到最佳的使用效果。 每当启用一个新组件时,配置定义都会自动加入该组件的配置项,通过这个行为,也可以变相的检查是否启用了某个组件。 比如,我们启用了 view 组件的效果。 ![](https://img.alicdn.com/imgextra/i2/O1CN013sHGlA1o3uQ4Pg0nO_!!6000000005170-2-tps-1416-572.png) 提示 为什么不使用普通 key 导出形式而使用对象? 1、用户在不了解配置项的情况下,依旧需要查看文档了解每项含义,除了第一层有一定的提示作用外,后面的层级提示没有很明显的效率提升 2、key 导出的形式在过深的结构下展示没有优势 3、key 导出可能会出现重复,但是代码层面不会有警告或者报错,难以排查,这一点对象形式较为友好 ### 对象形式加载配置文件[​](#对象形式加载配置文件 "对象形式加载配置文件的直接链接") 框架提供了加载不同环境的配置文件的功能,需要在 `src/configuration.ts` 文件中开启。 配置加载有两种方式,**对象形式** 和 **指定目录形式** 加载。 从 Midway v3 开始,我们将以 **对象形式** 作为主推的配置加载形式。 在单文件构建、ESM 等场景下,只支持这种标准的模块加载方式来加载配置。 每个环境的配置文件 **必须显式指定添加**,后续框架会根据实际的环境进行合并。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class MainConfiguration { } ``` `importConfigs` 中的数组中传递配置对象,每个对象的 key 为环境,值为环境对应的配置值,midway 在启动中会根据环境来加载对应的配置。 ### 指定目录、文件加载配置[​](#指定目录文件加载配置 "指定目录、文件加载配置的直接链接") 指定加载一个目录,目录里所有的 `config.*.ts` 都会被扫描加载。 ESM,单文件部署等方式不支持目录配置加载。 信息 `importConfigs` 这里只是指定需要加载的文件,实际运行时会**自动选择当前的环境**来找对应的文件后缀。 配置文件的规则为: * 1、可以指定一个目录,推荐传统的 `src/config` 目录,也可以指定一个文件 * 2、文件指定无需 ts 后缀 * 3、配置文件 **必须显式指定添加** **示例:指定目录** ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { } ``` **示例:指定特定文件** 手动指定一批文件时,这个时候如果文件不存在,则会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/config.default'), join(__dirname, './config/config.local'), join(__dirname, './config/custom.local') // 可以使用自定义的命名,只要中间部分带环境就行 ] }) export class MainConfiguration { } ``` 也可以使用项目外的配置,但是请使用绝对路径,以及 `*.js` 后缀。 比如目录结构如下(注意 `customConfig.default.js` 文件): ``` base-app ├── package.json ├── customConfig.default.js └── src ├── configuration.ts └── config └── config.default.ts ``` ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), join(__dirname, '../customConfig.default'), ] }) export class MainConfiguration { } ``` ### 配置加载顺序[​](#配置加载顺序 "配置加载顺序的直接链接") 配置存在优先级(应用代码 > 组件),相对于此运行环境的优先级会更高。 比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。 ``` -> 组件 config.default.ts -> 应用 config.default.ts -> 组件 config.prod.ts -> 应用 config.prod.ts ``` ### 配置合并规则[​](#配置合并规则 "配置合并规则的直接链接") 默认会加载 `**/config.defaut.ts` 的文件以及 `**/config.{环境}.ts` 文件。 比如,下面的代码在 `local` 环境会查找 `config.default.*` 和 `config.local.*` 文件,如果在其他环境,则只会查找 `config.default.*` 和 `config.{当前环境}.*` ,如果文件不存在,则不会加载,也不会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { } ``` 为了向前兼容,我们对某些特殊环境的配置读取做了一些处理。这里环境的值指的是根据 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 的值综合得出的 [结果](/docs/3.0.0/environment.md#AxjGQ)。 | **环境的值** | **读取的配置文件** | | ------------ | --------------------------------------------- | | prod | \*.default.ts + \*.prod.ts | | production | \*.default.ts + \*.production.ts + \*.prod.ts | | unittest | \*.default.ts + \*.unittest.ts | | test | \*.default.ts + \*.test.ts + \*.unittest.ts | 除了上述表格外,其余都是 `*.default.ts + *.{当前环境}.ts` 的值。 此外,配置的合并使用 [extend2](https://github.com/eggjs/extend2) 模块进行深度拷贝,[extend2](https://github.com/eggjs/extend2) fork 自 [extend](https://github.com/justmoon/node-extend),处理数组时会存在差异。 ``` const a = { arr: [ 1, 2 ], }; const b = { arr: [ 3 ], }; extend(true, a, b); // => { arr: [ 3 ] } ``` 根据上面的例子,框架直接覆盖数组而不是进行合并。 ## 获取配置[​](#获取配置 "获取配置的直接链接") Midway 会将配置都保存在内部的配置服务中,整个结构是一个对象,在 Midway 业务代码使用时,使用 `@Config` 装饰器注入。 ### 单个配置值[​](#单个配置值 "单个配置值的直接链接") 默认情况下,会根据装饰器的字符串参数值,从配置对象中获取。 ``` import { Config } from '@midwayjs/core'; export class IndexHandler { @Config('userService') userConfig; async handler() { console.log(this.userConfig); // { appname: 'test'} } } ``` ### 深层级别配置值[​](#深层级别配置值 "深层级别配置值的直接链接") 如果配置对象的值在对象的深处,那么可以用级联的方式获取。 比如数据源为: ``` { "userService": { "appname": { "test": { "data": "xxx" } } } } ``` 则可以写复杂的获取表达式来获取值,示例如下。 ``` import { Config } from '@midwayjs/core'; export class IndexHandler { @Config('userService.appname.test.data') data; async handler() { console.log(this.data); // xxx } } ``` ### 整个配置对象[​](#整个配置对象 "整个配置对象的直接链接") 也可以通过 `ALL` 这个特殊属性,来获取整个配置的对象。 ``` import { Config, ALL } from '@midwayjs/core'; export class IndexHandler { @Config(ALL) allConfig; async handler() { console.log(this.allConfig); // { userService: { appname: 'test'}} } } ``` ## 修改配置[​](#修改配置 "修改配置的直接链接") 在编码过程中,我们有一些可以动态修改配置的地方,用在不同的场景。 ### 生命周期中修改[​](#生命周期中修改 "生命周期中修改的直接链接") midway 新增了一个异步配置加载的生命周期,可以在配置加载后执行。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; import { join } from 'path'; import { RemoteConfigService } from '../service/remote'; // 自定义的获取远端配置服务 @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { async onConfigLoad(container: IMidwayContainer) { // 这里你可以修改全局配置 const remoteConfigService = await container.getAsync(RemoteConfigService); const remoteConfig = await remoteConfigService.getData(); // 这里的返回值会和全局的 config 做合并 // const remoteConfig = { // typeorm: { // dataSource: { // default: { // type: "mysql", // host: "localhost", // port: 3306, // username: "root", // password: "123456", // database: "admin", // synchronize: false, // logging: false, // entities: "/**/**.entity.ts", // dateStrings: true // } // } // } // } return remoteConfig; } } ``` 警告 `onConfigLoad` 生命周期会在 egg 插件(若有)初始化之后执行,不能用于覆盖 egg 插件的配置。 ### 启动时修改[​](#启动时修改 "启动时修改的直接链接") 可以在启动代码之前,使用 Bootstrap 的 `configure` 方法添加配置。 `configure` 方法可以传递一个 `globalConfig` 的属性,可以在应用启动前传递一个全局配置。 如果传递数组,则可以区分环境。 ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: [ { default: { abc: '123' }, unittest: { abc: '321' } } ] }) .run(); // in unittest, app.getConfig('abc') => '321' ``` 如果传递对象,则直接覆盖。 ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: { abc: 'text' } }) .run(); // app.getConfig('abc') => 'text' ``` ### 使用 API 修改[​](#使用-api-修改 "使用 API 修改的直接链接") 其他场景的修改配置,可以使用 midway 提供的 [API](/docs/3.0.0/built_in_service.md#midwayconfigservice)。 ## 环境变量和配置[​](#环境变量和配置 "环境变量和配置的直接链接") 社区有一些库,比如 `dotenv` 可以加载 `.env` 文件注入到环境中,从而将一些秘钥放在环境中,在 Midway 中可以直接依赖它使用。 ``` $ npm i dotenv --save ``` 可以在项目根目录增加 `.env` 文件,比如下面的内容: ``` OSS_SECRET=12345 OSS_ACCESSKEY=54321 ``` 我们可以在入口中初始化,比如 `bootstrap.js` 或者 `configuration` 。 ``` import { Configuration } from '@midwayjs/core'; import * as dotenv from 'dotenv'; // load .env file in process.cwd dotenv.config(); @Configuration({ //... }) export class MainConfiguration { async onReady(container) { } } ``` 我们可以在环境配置中使用了。 ``` // src/config/config.default export const oss = { accessKey: process.env.OSS_ACCESSKEY, // 54321 secret: process.env.OSS_SECRET // 12345 } ``` ## 常见错误[​](#常见错误 "常见错误的直接链接") 配置未生效的可能性很多,排查思路如下: * 1、检查 configuration 文件中是否显式配置 `importConfigs` 相关的文件或者目录 * 2、检查应用启动的环境,是否和配置文件一致,比如 prod 的配置肯定不会在 local 出现 * 3、检查是否将普通导出和方法回调导出混用,比如下面的混用的情况 ### 1、在构造器(constructor)中获取 @Config 注入的值[​](#1在构造器constructor中获取-config-注入的值 "1、在构造器(constructor)中获取 @Config 注入的值的直接链接") \*\*请不要在构造器中 \*\*获取 `@Config()` 注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('redisConfig') redisConfig; constructor() { console.log(this.redisConfig); // undefined } @Init() async initMethod() { console.log(this.redisConfig); // has value } } ``` ### 2、回调和导出写法混用[​](#2回调和导出写法混用 "2、回调和导出写法混用的直接链接") **下面是错误用法。** ``` export default (appInfo) => { const config = {}; // xxx return config; }; export const keys = '12345'; ``` `export const` 定义的值会被忽略。 ### 3、export default 和 export const 混用[​](#3export-default-和-export-const-混用 "3、export default 和 export const 混用的直接链接") **下面是错误用法。** ``` export default { keys: '12345', } export const anotherKey = '54321'; ``` 位于后面的配置将会被忽略。 ### 4、export= 和其他混用[​](#4export-和其他混用 "4、export= 和其他混用的直接链接") `export=` 混用的情况,如果后面有其他配置,会忽略 `export=` 的值。 ``` export = { a: 1 } export const b = 2; ``` 编译后结果: ``` export const b = 2; ``` --- # 运行环境 Node.js 应用一般通过 `NODE_ENV` 来获取环境变量,来满足不同环境下的不同需求。比如在 `production` 环境下,开启缓存,优化性能,而在 `development` 环境下,会打开所有的日志开关,输出详细的错误信息等等。 ## 指定运行环境[​](#指定运行环境 "指定运行环境的直接链接") 由于在一些情况下 `NODE_ENV` 会被一些工具包拦截注入,所以在 Midway 体系下,我们会根据 `MIDWAY_SERVER_ENV` 优先获取环境,而 `NODE_ENV` 作为第二优先级获取。 我们可以通过启动时增加环境变量来指定。 ``` MIDWAY_SERVER_ENV=prod npm start // 第一优先级 NODE_ENV=local npm start // 第二优先级 ``` 在 windows 环境,我们需要使用 [cross-env](https://www.npmjs.com/package/cross-env) 模块以达到同样的效果。 ``` cross-env MIDWAY_SERVER_ENV=prod npm start // 第一优先级 cross-env NODE_ENV=local npm start // 第二优先级 ``` ## 代码中获取环境[​](#代码中获取环境 "代码中获取环境的直接链接") Midway 在 app 对象上提供了 `getEnv()` 方法获取环境,面对不同的上层框架,Midway 都做了相应的处理,保使得在不同场景下,都拥有 `getEnv()` 方法。。 ``` import { Application } from '@midwayjs/koa'; // process.env.MIDWAY_SERVER_ENV=prod @Provide() export class UserService { @App() app: Application; async invoke() { console.log(this.app.getEnv()); // prod } } ``` 如果 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 都没有赋值,那么默认情况下,方法的返回值为 `prod` 。 信息 注意,你不能直接通过 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 来获取环境,这两个值都有可能为空,且 Midway 不会反向设置它。如需获取环境,请通过 app.getEnv() 获取其他框架提供的 API 方法获取。 ## 常见的环境变量值[​](#常见的环境变量值 "常见的环境变量值的直接链接") 一般来说,每个公司都有一些自己的环境变量值,下面是一些常见的环境变量值以及他们对应的说明。 | 值 | 说明 | | --------------------- | ------------ | | local | 本地开发环境 | | dev/daily/development | 日常开发环境 | | pre/prepub | 预生产环境 | | prod/production | 生产环境 | | test/unittest | 单元测试环境 | | benchmark | 性能测试环境 | ## 依赖注入容器中获取环境[​](#依赖注入容器中获取环境 "依赖注入容器中获取环境的直接链接") 在依赖注入容器初始化的过程中,Midway 默认初始化了一个 `EnvironmentService` 服务用来解析环境,并在整个生命周期中,持续保持这个服务对象。 具体请查看 [环境服务](/docs/3.0.0/built_in_service.md#midwayenvironmentservice)。 --- # 框架错误码 以下是框架内置的错误,随着时间推移,我们会不断增加。 | 错误码 | 错误名 | 错误描述 | | ------------- | ------------------------------------- | ---------------------------- | | MIDWAY\_10000 | 占位使用 | 未知错误 | | MIDWAY\_10001 | MidwayCommonError | 未分类的错误 | | MIDWAY\_10002 | MidwayParameterError | 参数类型错误 | | MIDWAY\_10003 | MidwayDefinitionNotFoundError | 依赖注入定义未找到 | | MIDWAY\_10004 | MidwayFeatureNoLongerSupportedError | 功能不再支持 | | MIDWAY\_10005 | MidwayFeatureNotImplementedError | 功能未实现 | | MIDWAY\_10006 | MidwayConfigMissingError | 配置项丢失 | | MIDWAY\_10007 | MidwayResolverMissingError | 依赖注入属性 resovler 未找到 | | MIDWAY\_10008 | MidwayDuplicateRouteError | 路由重复 | | MIDWAY\_10009 | MidwayUseWrongMethodError | 使用了错误的方法 | | MIDWAY\_10010 | MidwaySingletonInjectRequestError | 作用域混乱 | | MIDWAY\_10011 | MidwayMissingImportComponentError | 组件未导入 | | MIDWAY\_10012 | MidwayUtilHttpClientTimeoutError | http client 调用超时 | | MIDWAY\_10013 | MidwayInconsistentVersionError | 使用了不正确的依赖版本 | | MIDWAY\_10014 | MidwayInvalidConfigError | 无效的配置 | | MIDWAY\_10015 | MidwayDuplicateClassNameError | 重复的类名 | | MIDWAY\_10016 | MidwayDuplicateControllerOptionsError | 重复的控制器参数 | ## MIDWAY\_10001[​](#midway_10001 "MIDWAY_10001的直接链�接") **问题描述** 最通用的框架错误,在不分类的情况下会抛出,一般会将错误的详细内容写入错误信息 **解决方案** 排错以错误信息为准。 ## MIDWAY\_10002[​](#midway_10002 "MIDWAY_10002的直接链接") **问题描述** 方法的参数传入错误,可能类型不对或者参数格式有误。 **解决方案** 参考方法定义或者文档传入参数。 ## MIDWAY\_10003[​](#midway_10003 "MIDWAY_10003的直接链接") **问题描述** 一般出现在启动或者动态从容器中获取某个类的时候,如果该类未在容器中注册,就会报出 `xxx is not valid in current context`错误。 **解决方案** 可能的情况,比如在业务代码或者组件使用中: ``` // ... export class UserService {} // ... @Controller() export class HomeController { @Inject() userService: UserService; } ``` 如果 `UserService` 没有写 `@Provide` 或者隐式含有 `@Provide` 的装饰器,就会出现上述错误。 一般的报错是类似下面这个样子。 ``` userService in class HomeController is not valid in current context ``` 那么,意味着 `HomeController` 中的 `userService` 属性未在容器中找到,你可以顺着这个线索往下排查。 ## MIDWAY\_10004[​](#midway_10004 "MIDWAY_10004的直接链接") **问题描述** 使用的废弃的功能。 **解决方案** 不使用该功能。 ## MIDWAY\_10005[​](#midway_10005 "MIDWAY_10005的直接链接") **问题描述** 使用的方法或者功能暂时未实现。 **解决方案** 不使用该功能。 ## MIDWAY\_10006[​](#midway_10006 "MIDWAY_10006的直接链接") **问题描述** 未提供需要的配置项。 **解决方案** 排查配置对应的环境,是否包含该配置,如果没有,在配置文件中增加该配置即可。 ## MIDWAY\_10007[​](#midway_10007 "MIDWAY_10007的直接链接") **问题描述** 未找到容器注入的解析类型,当前版本不会出现该错误。 **解决方案** 无。 ## MIDWAY\_10008[​](#midway_10008 "MIDWAY_10008的直接链接") **问题描述** 检查到重复的路由。 **解决方案** 移除重复的路由部分。 ## MIDWAY\_10009[​](#midway_10009 "MIDWAY_10009的直接链接") **问题描述** 使用了错误的方法。 **解决方案** 当你在同步的 get 方法中包含了一个异步调用,则会提示使用 `getAsync` 方法,修改即可。 ## MIDWAY\_10010[​](#midway_10010 "MIDWAY_10010的直接链接") **问题描述** 当在单例中注入了一个未显式声明的请求作用域实例则会出现此错误,错误原因为 [作用域降级](/docs/3.0.0/container.md#%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%99%8D%E7%BA%A7)。 比如下面的代码,就会抛出此错误: ``` // ... @Provide() export class UserService {} // ... @Provide() @Scope(ScopeEnum.Singleton) export class LoginService { @Inject() userService: UserService; } ``` 经常在 `configuration` 或者中间件文件中出现该问题。 该错误是为了规避作用域自动降级,缓存了实例数据带来的风险。 **解决方案** * 1、如果你是错误的在单例中注入了请求作用域实例,请修改请求作用域代码为单例 * 2、如果你希望在单例中注入请求作用域来使用,并且能够清楚的知道作用域降级带来的后果(被缓存),请显式在类上声明作用域选项(表示允许降级)。 ``` @Provide() @Scope(ScopeEnum.Request, { allowDowngrade: true }) export class UserService {} ``` ## MIDWAY\_10011[​](#midway_10011 "MIDWAY_10011的直接链接") **问题描述** 当组件未在 `configuration` 文件中 `imports`,就使用了组件中的类,就会出现此错误。 **解决方案** 显式在 `src/configuration` 中的 `imports` 部分中显式引入组件。 ## MIDWAY\_10012[​](#midway_10012 "MIDWAY_10012的直接链接") **问题描述** 内置的 Http Client 超时会抛出此错误。 **解决方案** 正常的超时错误,检查为何超时,做好错误处理即可。 ## MIDWAY\_10013[​](#midway_10013 "MIDWAY_10013的直接链接") **问题描述** 当安装的组件和框架版本不匹配会抛出此错误。 一般会出现在框架发布了新版本之后,当项目开启了 lock 文件,使用了老版本的框架版本,并且安装了一个新组件之后。 **解决方案** 删除 lock 文件,重新安装依赖。 ## MIDWAY\_10014[​](#midway_10014 "MIDWAY_10014的直接链接") **问题描述** 当配置文件中存在 `export default` 和 `export const` 两种导出方式后会抛出该错误。 **解决方案** 请勿两种导出方式混用。 ## MIDWAY\_10015[​](#midway_10015 "MIDWAY_10015的直接链接") **问题描述** 当启动开启了重复类名检查(conflictCheck),如果代码扫描时在依赖注入容器中发现相同的类名,则会抛出该错误。 ``` // src/configuration.ts @Configuration({ // ... conflictCheck: true, }) export class MainConfiguration { // ... } ``` **解决方案** 修改类名,或者关闭重复类名检查。 ## MIDWAY\_10016[​](#midway_10016 "MIDWAY_10016的直接链接") **问题描述** 当添加了不同的控制器,使用了相同的 `prefix`,并且添加了不同的 `options`,比如中间件,会抛出该错误。 **解决方案** 将相同 `prefix` 的控制器代码进行合并,或者移除所有的 `options`。 --- # 异常处理 Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 异常处理器的执行位置处于中间件之后,所以它能拦截所有的中间件和业务抛出的错误。 ![err\_filter](https://img.alicdn.com/imgextra/i2/O1CN013pvSjT1nWvsLRE4vo_!!6000000005098-2-tps-2000-524.png) ## Http 异常[​](#http-异常 "Http 异常的直接链接") 在 Http 请求中,Midway 提供了通用的 `MidwayHttpError` 类型的异常,其继承于标准的 `MidwayError`。 ``` export class MidwayHttpError extends MidwayError { // ... } ``` 我们可以在请求的过程中抛出该错误,由于错误中包含状态码,Http 程序将会自动返回该状态码。 比如,下面的代码,抛出了包含 400 状态码的错误。 ``` import { MidwayHttpError } from '@midwayjs/core'; // ... async findAll() { throw new MidwayHttpError('my custom error', HttpStatus.BAD_REQUEST); } // got status: 400 ``` 但是一般我们很少这么做,大多数的业务的错误都是复用的,错误消息也基本是固定的,为了减少重复定义,我们可以自定义一些异常类型。 比如自定义一个状态码为 400 的 Http 异常,可以如下定义错误。 ``` // src/error/custom.error.ts import { HttpStatus } from '@midwayjs/core'; export class CustomHttpError extends MidwayHttpError { constructor() { super('my custom error', HttpStatus.BAD_REQUEST); } } ``` 然后在业务中抛出使用。 ``` import { CustomHttpError } from './error/custom.error'; // ... async findAll() { throw new CustomHttpError(); } ``` ## 异常处理器[​](#异常处理器 "异常处理器的直接链接") 内置的异常处理器用于标准的请求响应场景,它可以捕获所有请求中抛出的错误。 通过 `@Catch` 装饰器我们可以定义某一类异常的处理程序,我们可以轻松的捕获某一类型的错误,做出处理,也可以捕获全局的错误,返回统一的格式。 同时,框架也提供了一些默认的 Http 错误,放在 `httpError` 这个对象下。 比如捕获抛出的 `InternalServerErrorError` 错误。 我们可以将这一类异常处理器放在 `filter` 目录,比如 `src/filter/internal.filter.ts`。 ``` // src/filter/internal.filter.ts import { Catch, httpError, MidwayHttpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch(httpError.InternalServerErrorError) export class InternalServerErrorFilter { async catch(err: MidwayHttpError, ctx: Context) { // ... return 'got 500 error, ' + err.message; } } ``` `catch` 方法的参数为当前的错误,以及当前应用该异常处理器的上下文 `Context` 。我们可以简单的将响应的数据返回。 如果不写参数,那么会捕获所有的错误,不管是不是 HttpError,只在要请求中抛出的错误,都会被这里捕获。 ``` // src/filter/all.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class AllErrorFilter { async catch(err: Error, ctx: Context) { // ... } } ``` 定义的异常处理器只是一段普通的代码,我们还需要将它应用到我们某个框架的 app 中,比如 http 协议的 app。 我们可以在 `src/configuration.ts` 中将错误处理过滤器应用上,由于参数可以是数组,我们可以应用多个错误处理器。 ``` // src/configuration.ts import { Configuration, App, Catch } from '@midwayjs/core'; import { join } from 'path'; import * as koa from '@midwayjs/koa'; import { InternalServerErrorFilter } from './filter/internal.filter'; @Configuration({ imports: [ koa ], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useFilter([InternalServerErrorFilter]); } } ``` 信息 注意,某些非 Midway 的中间件或者框架内部设置的状态码,由于未使用错误抛出的形式,所以拦截不到,如果在业务中返回 400 以上的状态,请尽可能使用标准的抛出错误的形式,方便拦截器做处理。 ### 404 处理[​](#404-处理 "404 处理的直接链接") 框架内部,如果未匹配到路由,会抛出一个 `NotFoundError` 的异常。通过异常处理器,我们可以自定义其行为。 比如跳转到某个页面,或者返回特定的结果: ``` // src/filter/notfound.filter.ts import { Catch, httpError, MidwayHttpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch(httpError.NotFoundError) export class NotFoundFilter { async catch(err: MidwayHttpError, ctx: Context) { // 404 错误会到这里 ctx.redirect('/404.html'); // 或者直接返回一个内容 return { message: '404, ' + ctx.path } } } ``` ### 500 处理[​](#500-处理 "500 处理的直接链接") 当不传递装饰器参数时,将捕获所有的错误。 比如,捕获所有的错误,并返回特定的 JSON 结构,示例如下。 ``` // src/filter/default.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class DefaultErrorFilter { async catch(err: Error, ctx: Context) { // ... return { status: err.status ?? 500, message: err.message; } } } ``` 我们可以在 `src/configuration.ts` 中将错误处理过滤器应用上,由于参数可以是数组,我们可以应用多个错误处理器。 ``` import { Configuration, App, Catch } from '@midwayjs/core'; import { join } from 'path'; import * as koa from '@midwayjs/koa'; import { DefaultErrorFilter } from './filter/default.filter'; import { NotFoundFilter } from './filter/notfound.filter'; @Configuration({ imports: [ koa ], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useFilter([NotFoundFilter, DefaultErrorFilter]); } } ``` 使用异常处理器不需要考虑顺序,通用的错误处理器一定是最后被匹配,且一个 app 上有且只能有一个通用的错误处理器。 ## 派生异常处理[​](#派生异常处理 "派生异常处理的直接链接") 默认情况下,异常只会进行绝对匹配。 有时候我们需要去捕获所有的派生类,这个时候需要额外设置。 ``` import { Catch, MidwayError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; class CustomError extends MidwayError {} class CustomError2 extends MidwayError {} // 这里会捕获所有的子类 @Catch([MidwayError], { matchPrototype: true }) class TestFilter { catch(err, ctx) { // ... } } ``` 通过配置 `matchPrototype` 可以匹配所有的派生的类。 ## 异常日志[​](#异常日志 "异常日志的直接链接") Midway 内置了默认的异常处理行为。 如果 **没有匹配** 到异常处理器,都会被兜底的异常中间件拦截,记录。 反过来说,如果自定义了异常处理器,那么错误就会被当成正常的业务逻辑,请注意,这个时候底层抛出的异常就会作为业务正常的处理逻辑,而 **不会** 被日志记录。 你可以自行在异常处理器中打印日志。 ``` import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class DefaultErrorFilter { async catch(err: Error, ctx: Context) { // ... ctx.logger.error(err); // ... return 'got 500 error, ' + err.message; } } ``` ## 内置的 Http 异常[​](#内置的-http-异常 "内置的 Http 异常的直接链接") 下面这些框架内置的 Http 异常,都可以从 `@midwayjs/core` 中找到并使用,每个异常都已经包含默认的错误消息和状态码。 * `BadRequestError` * `UnauthorizedError` * `NotFoundError` * `ForbiddenError` * `NotAcceptableError` * `RequestTimeoutError` * `ConflictError` * `GoneError` * `PayloadTooLargeError` * `UnsupportedMediaTypeError` * `UnprocessableEntityError` * `TooManyRequestsError` * `InternalServerErrorError` * `NotImplementedError` * `BadGatewayError` * `ServiceUnavailableError` * `GatewayTimeoutError` 比如: ``` import { httpError } from '@midwayjs/core'; // ... async findAll() { // something wrong throw new httpError.InternalServerErrorError(); } // got status: 500 ``` --- # ESModule 使用指南 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 两个模块系统之间的互操作带来了巨大的挑战,并具有许多功能差异。 自 Node.js v16 之后,ESM 的支持相对已经稳定,TypeScript 的一些配合功能也相继落地。 在此基础上,Midway 支持了 ESM 格式的文件加载,业务也可以使用这种全新的模块加载方式来构建自己的业务。 警告 在没有了解 ESM 前,不建议用户使用。 推荐阅读: * [TypeScript 官方 ESM 指南](https://www.typescriptlang.org/docs/handbook/esm-node.html) * [Node.js 官方 ESM 文档](https://nodejs.org/api/esm.html) ## 脚手架[​](#脚手架 "脚手架的直接链接") 由于改动较多,Midway 提供了全新的 ESM 格式的脚手架,如有 ESM 的需求,我们推荐用户重新创建后再来开发业务。 ``` $ npm init midway@latest -y ``` 选择 esm 分组中的脚手架。 ## 和 CJS 项目的差异[​](#和-cjs-项目的差异 "和 CJS 项目的差异的直接链接") ### 1、package.json 的变化[​](#1packagejson-的变化 "1、package.json 的变化的直接链接") `package.json` 中的 type 必须设置为 `module`。 ``` { "name": "my-package", "type": "module", // ... "dependencies": { } } ``` ### 2、tsconfig.json 中的变化[​](#2tsconfigjson-中的变化 "2、tsconfig.json 中的变化的直接链接") `compilerOptions` 编译相关的选项需要设置为 `Node16` 或者 `NodeNext`。 ``` { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "Node16", "esModuleInterop": true, // ... } } ``` ### 3、工具链的变化[​](#3工具链的变化 "3、工具链的变化的直接链接") 由于原有开发工具链仅支持 CJS 代码,且社区的部分模块并没有做好 ESM 的支持,Midway 在 ESM 模式下,使用新的工具链。 * 开发命令,使用 mwtsc (仅做了 tsc 必要的包裹) * 测试和覆盖率命令,使用 mocha + ts-node,同时测试代码和测试的配置都有所调整 * 构建命令,使用 tsc 一些不再支持的功能 * alias path,请用 Node.js 自带的 [子路径导出](https://nodejs.org/api/packages.html#subpath-exports) 代替 * 构建时非 js 文件的拷贝,将非代码文件放到 src 外部,或者在 build 时添加自定义命令 具体差异可以参考 [脚手架](https://github.com/midwayjs/midway-boilerplate/blob/master/v3/midway-framework-koa-esm/boilerplate/_package.json) 进行核对。 ### 4、一些代码差异[​](#4一些代码差异 "4、一些代码差异的直接链接") 下面快速列出一些开发中 ESM 和 CJS 的差异。 1、ts 中,import 的文件必须指定后缀名,且后缀名为 js。 ``` import { helper } from "./foo.js"; // works in ESM & CJS ``` 2、你不能再使用 `module.exports` 或者 `exports.` 来导出。 ``` // ./foo.ts export function helper() { // ... } // ./bar.ts import { helper } from "./foo"; // only works in CJS ``` 3、你不能在代码中使用 `require` 只能使用 `import` 关键字。 4、你不能在代码中使用 `__dirname`,`__filename` 等和路径相关关键字 ``` // ESM solution import { dirname } from 'node:path' import { fileURLToPath } from 'node:url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(fileURLToPath(import.meta.url)) ``` 所有配置的部分,必须使用对象模式。 ``` import { Configuration } from '@midwayjs/core'; import DefaultConfig from './config/config.default.js'; import UnittestConfig from './config/config.unittest.js'; @Configuration({ importConfigs: [ { default: DefaultConfig, unittest: UnittestConfig, }, ], }) export class MainConfiguration { // ... } ``` --- # Alinode ## 准备工作[​](#准备工作 "准备工作的直接链接") 需要接入的应用是要部署在独立的服务获取云环境,可以接入互联网服务。 ## 创建服务[​](#创建服务 "创建服务的直接链接") **第一步** 登录阿里云,点击开通 [阿里云的 Node.js 性能平台](https://www.aliyun.com/product/nodejs) 的服务。 **第二步** 创建新应用,获取 APP ID 和 App Secret。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617267785895-dd0fb702-91c7-4b25-9c64-8a9358f2d254.png#align=left\&display=inline\&height=351\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=702\&originWidth=1548\&size=106487\&status=done\&style=none\&width=774) ## 安装监控依赖[​](#安装监控依赖 "安装监控依赖的直接链接") **第一步** 安装 Node.js 性能平台所需的组件 ``` # 安装版本管理工具 tnvm,安装过程出错参考:https://github.com/aliyun-node/tnvm $ wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash $ source ~/.bashrc # tnvm ls-remote alinode # 查看需要的版本 $ tnvm install alinode-v6.5.0 # 安装需要的版本 $ tnvm use alinode-v6.5.0 # 使用需要的版本 $ npm install @alicloud/agenthub -g # 安装 agenthub ``` 这里有三个部分 * 1、安装 tnvm(alinode 源) * 2、使用 tnvm 安装 alinode(替代默认的 node) * 3、安装 alinode 需要的数据采集器 安装完成后,可以检查一下,需要确保 `which node` 和 `which agenthub` 的路径中包括 `.tnvm` 即可。 ``` $ which node /root/.tnvm/versions/alinode/v3.11.4/bin/node $ which agenthub /root/.tnvm/versions/alinode/v3.11.4/bin/agenthub ``` 将 `创建新应用` 中获得的 `App ID` 和 `App Secret` 按如下所示保存为 `yourconfig.json`。比如放在项目根目录。 ``` { "appid": "****", "secret": "****", } ``` 启动插件: ``` agenthub start yourconfig.json ``` ## 启动 node 服务[​](#启动-node-服务 "启动 node 服务的直接链接") 在安装了服务器中,启动 Node 服务时,需要加入 ENABLE\_NODE\_LOG=YES 环境变量。 比如: ``` $ NODE_ENV=production ENABLE_NODE_LOG=YES node bootstrap.js ``` ## Docker 容器的方法[​](#docker-容器的方法 "Docker 容器的方法的直接链接") 关于 docker 容器的方法可以查看 [文档](https://help.aliyun.com/document_detail/66027.html?spm=a2c4g.11186623.6.580.261ba70feI6mWt)。 ## 其他[​](#其他 "其他的直接链接") 更多内容可以查看阿里云 Node.js 性能平台的 [文档](https://help.aliyun.com/document_detail/60338.html?spm=a2c4g.11186623.6.548.599312e6IkGO9v)。 --- # HTTP 请求 ## 简单的 HTTP 请求[​](#简单的-http-请求 "简单的 HTTP 请求的直接链接") Midway 内置了一个简单的 HTTP 请求客户端,无需引入三方包即可使用。 默认 Get 请求,返回数据为 Buffer。 内置的 Http 客户端只提供最简单的能力,仅满足大部分的前端接口数据获取,如需复杂的功能,比如文件上传等,请使用其他的客户端,如 fetch,axios,got 等。 ### 简单方法形式[​](#简单方法形式 "简单方法形式的直接链接") ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/'); // Buffer.isBuffer(result.data) => true ``` Get 请求,带上 Query,返回类型为 JSON。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { data: { a: 1, b: 2 }, dataType: 'json', // 返回的数据格式 }); // typeof result.data => 'object' // result.data.url => /?a=1&b=2 ``` 可以指定类型 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'json', }); ``` 返回 text 格式。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'text', }); ``` POST 请求并返回 JSON。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'POST', data: { a: 1, b: 2 }, dataType: 'json', contentType:'json', // 发送的 post 为 json }); // result.data ... ``` 警告 注意,请不要在请求中直接返回 result 对象,result 对象是标准的 httpResponse,在大部分场景下无法被直接序列化,会抛出对象循环的错误。 设置请求超时时间。 ``` import { makeHttpRequest } from '@midwayjs/core'; let err; // 超时会报错,注意 catch try { const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'text', timeout: 500, }); } catch (e) { err = e; } ``` ### 实例形式[​](#实例形式 "实例形式的直接链接") ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient(); const result = await httpclient.request('http://127.1:7001/'); // Buffer.isBuffer(result.data) => true ``` 和方法形式参数相同。 ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient(); const result = await httpclient.request('http://127.1:7001/', { method: 'POST', data: { a: 1, b: 2 }, dataType: 'json', contentType:'json', // 发送的 post 为 json }); // result.data ... ``` 示例形式,可以复用创建出的对象,并且每次请求,都可以带上一些固定的参数,比如 header。 ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient({ headers: { 'x-timeout': '5' }, method: 'POST', timeout: 2000 }); // 每次都会带上 headers const result = await httpclient.request('http://127.1:7001/'); ``` ## Axios 支持[​](#axios-支持 "Axios 支持的直接链接") Midway 包裹了 [axios](https://github.com/axios/axios) 包,使得在代码中可以简单的使用 axios 接口。 和 axios 的一些关系如下: * 接口完全一致 * 适配依赖注入写法,完整的类型定义 * 方便实例管理和配置统一 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/axios@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/axios": "^3.0.0", // ... }, } ``` ### 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path' @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 然后在业务代码中即可注入使用。 ### 使用默认 Axios 实例[​](#使用默认-axios-实例 "使用默认 Axios 实例的直接链接") 接口和 [axios](https://github.com/axios/axios) 一致。 ``` axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]]) axios.postForm(url[, data[, config]]) axios.putForm(url[, data[, config]]) axios.patchForm(url[, data[, config]]) ``` 使用示例: ``` import { HttpService } from '@midwayjs/axios'; @Provide() export class UserService { @Inject() httpService: HttpService; async invoke() { const url = 'https://midwayjs.org/resource/101010100.json'; const result = await this.httpService.get(url); // TODO result } } ``` ### 配置默认 Axios 实例[​](#配置默认-axios-实例 "配置默认 Axios 实例的直接链接") HttpService 实例等价于 `axios.create` ,所以可以有一些配置参数,这些参数了 axios 本身的参数相同,我们可以在 `src/config.default.ts` 中配置它。 比如: ``` export default { // ... axios: { default: { // 所有实例复用的配置 }, clients: { // 默认实例的配置 default: { baseURL: 'https://api.example.com', // `headers` are custom headers to be sent headers: { 'X-Requested-With': 'XMLHttpRequest' }, timeout: 1000, // default is `0` (no timeout) // `withCredentials` indicates whether or not cross-site Access-Control requests // should be made using credentials withCredentials: false, // default }, } } } ``` 更多的参数可以参考 [axios global config](https://github.com/axios/axios#config-defaults)。 ### 创建不同实例[​](#创建不同实例 "创建不同实例的直接链接") 和其他的服务多实例相同,配置不同的 key 即可。 ``` export default { // ... axios: { default: { // 所有实例复用的配置 }, clients: { default: { // 默认实例 }, customAxios: { // 自定义实例 } } } } ``` 使用方式如下: ``` import { HttpServiceFactory, HttpService } from '@midwayjs/axios'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(HttpServiceFactory, 'customAxios') customAxios: HttpService; async invoke() { const url = 'https://midwayjs.org/resource/101010100.json'; const result = await this.customAxios.get(url); // TODO result } } ``` ### 配置全局拦截器[​](#配置全局拦截器 "配置全局拦截器的直接链接") 如果使用的是默认的 Axios 实例,可以如下配置。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const httpService = await container.getAsync(axios.HttpService); httpService.interceptors.request.use( config => { // Do something before request is sent return config; }, error => { // Do something with request error return Promise.reject(error); } ); } } ``` 如果要给其他实例配置,可以参考下面的代码。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const httpServiceFactory = await container.getAsync(axios.HttpServiceFactory); const customAxios = httpServiceFactory.get('customAxios'); customAxios.interceptors.request.use( config => { //... }, error => { //... } ); } } ``` ### 扩展 AxiosRequestConfig 类型[​](#扩展-axiosrequestconfig-类型 "扩展 AxiosRequestConfig 类型的直接链接") 当前 Axios 库中 [issue](https://github.com/axios/axios/issues?q=is%3Aissue%20state%3Aopen%20AxiosRequestConfig) 有不少扩展 `AxiosRequestConfig` 类型的需求,但是 axios 本身并不支持扩展这个类型,其中的泛型仅限于设置 data 属性的类型。 Midway 中提供了 `AxiosRequestConfig` 的扩展,可以在组件层面增加新的属性。 ``` // interface.ts import '@midwayjs/axios'; declare module '@midwayjs/axios/dist/interface' { interface AxiosRequestConfig { retryDelay?: number; retry?: number; } } ``` ### 直接使用 Axios[​](#直接使用-axios "直接使用 Axios的直接链接") `@midayjs/axios`导出了原始的`axios`实例,在非应用环境中可以直接使用。 ``` import { Axios } from '@midwayjs/axios'; import { ReadStream, createWriteStream } from 'fs'; import { finished } from 'stream/promises'; async function download(url: string, filename: string) { const writer = await createWriteStream(filename); const res = Axios.get(url, { responseType: 'stream', }); res.data.pipe(writer); await finished(writer); return res; } ``` --- # 任务队列 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题。 示例如下: * 平滑处理峰值。可以在任意时间启动资源密集型任务,然后将这些任务添加到队列中,而不是同步执行。让任务进程以受控方式从队列中提取任务。也可以轻松添加新的队列消费者以扩展后端任务处理。 * 分解可能会阻塞 Node.js 事件循环的单一任务。比如用户请求需要像音频转码这样的 CPU 密集型工作,就可以将此任务委托给其他进程,从而释放面向用户的进程以保持响应。 * 提供跨各种服务的可靠通信渠道。例如,您可以在一个进程或服务中排队任务(作业),并在另一个进程或服务中使用它们。在任何流程或服务的作业生命周期中完成、错误或其他状态更改时,您都可以收到通知(通过监听状态事件)。当队列生产者或消费者失败时,它们的状态被保留,并且当节点重新启动时任务处理可以自动重新启动。 Midway 提供了 @midwayjs/bull 包作为 [Bull](https://github.com/OptimalBits/bull) 之上的抽象/包装器,[Bull](https://github.com/OptimalBits/bull) 是一种流行的、受良好支持的、高性能的基于 Node.js 的队列系统实现。该软件包可以轻松地将 Bull Queues 以友好的方式集成到您的应用程序中。 Bull 使用 Redis 来保存作业数据,在使用 Redis 时,Queue 架构是完全分布式,和平台无关。例如,您可以在一个(或多个)节点(进程)中运行一些 Queue 生产者、消费者,而在其他节点上的运行其他生产者和消费者。 本章介绍 @midwayjs/bull 包。我们还建议阅读 [Bull 文档](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md) 以了解更多背景和具体实施细节。 提示 * 1、从 v3.6.0 开始,原有任务调度 `@midwayjs/task` 模块废弃,如果查询历史文档,请参考 [这里](/docs/3.0.0/legacy/task.md)。 * 2、bull 是一个分布式任务管理系统,必须依赖 redis 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/bull@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull": "^3.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 bull 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { //... } ``` ## 一些概念[​](#一些概念 "一些概念的直接链接") Bull 将整个队列分为三个部分 * 1、Queue 队列,管理任务 * 2、Job,每个任务对象,可以对任务进行启停控制 * 3、Processor,任务处理,实际的逻辑执行部分 ## 基础配置[​](#基础配置 "基础配置的直接链接") bull 是一个分布式任务管理器,强依赖于 redis,在 `config.default.ts` 文件中配置。 ``` // src/config/config.default.ts export default { // ... bull: { // 默认的队列配置 defaultQueueOptions: { redis: `redis://127.0.0.1:32768`, } }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... bull: { defaultQueueOptions: { redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, } }, } ``` 所有的队列都会复用该配置。 ## 编写任务处理器[​](#编写任务处理器 "编写任务处理器的直接链接") 使用 `@Processor` 装饰器装饰一个类,用于快速定义一个任务处理器(这里我们不使用 Job,避免后续的歧义)。 `@Processor` 装饰器需要传递一个 Queue (队列)的名字,在框架启动时,如果没有名为 `test` 的队列,则会自动创建。 比如,我们在 `src/queue/test.queue.ts` 文件中编写如下代码。 ``` // src/queue/test.queue.ts import { Processor, IProcessor } from '@midwayjs/bull'; @Processor('test') export class TestProcessor implements IProcessor { async execute() { // ... } } ``` 在启动时,框架会自动查找并初始化上述处理器代码,同时自动创建一个名为 `test` 的 Queue。 ## 执行任务[​](#执行任务 "执行任务的直接链接") 当定义完 Processor 之后,由于并未指定 Processor 如何执行,我们还需要手动执行它。 通过获取对应的队列,我们可以很方便的来执行任务。 ### 手动执行任务[​](#手动执行任务 "手动执行任务的直接链接") 比如,我们可以在项目启动后执行。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; //... async onServerReady() { // 获取 Processor 相关的队列 const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue(); } } ``` ### 增加执行参数[​](#增加执行参数 "增加执行参数的直接链接") 我们也可以在执行时,附加一些默认参数。 ``` @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { // params.aaa => 1 } } // invoke const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue({ aaa: 1, bbb: 2, }); ``` ### 任务状态和管理[​](#任务状态和管理 "任务状态和管理的直接链接") 执行 `addJobToQueue` 后,我们可以获取到一个 `Job` 对象。 ``` // invoke const testQueue = this.bullFramework.getQueue('test'); const job = await testQueue?.addJobToQueue(); ``` 通过这个 Job 对象,我们可以做进度管理。 ``` // 更新进度 await job.progress(60); // 获取进度 const progress = await job.process(); // => 60 ``` 获取任务状态。 ``` const state = await job.getState(); // state => 'delayed' 延迟状态 // state => 'completed' 完成状态 ``` 更多的 Job API,请查看 [文档](https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md)。 ### 延迟执行[​](#延迟执行 "延迟执行的直接链接") 执行任务时,也有一些额外的选项。 比如,延迟 1s 执行。 ``` const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue({}, { delay: 1000 }); ``` ### 中间件和错误处理[​](#中间件和错误处理 "中间件和错误处理的直接链接") Bull 组件包含可以独立启动的 Framework,有着自己的 App 对象和 Context 结构。 我们可以对 bull 的 App 配置独立的中间件和错误过滤器。 ``` @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @App('bull') bullApp: bull.Application; //... async onReady() { this.bullApp.useMiddleare( /*中间件*/); this.bullApp.useFilter( /*过滤器*/); } } ``` ### 上下文[​](#上下文 "上下文的直接链接") 任务处理器执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { jobId: JobId; job: Job, from: new (...args) => IProcessor; } ``` 我们可以直接从 ctx 中访问当前的 Job 对象。 ``` // src/queue/test.queue.ts import { Processor, IProcessor, Context } from '@midwayjs/bull'; @Processor('test') export class TestProcessor implements IProcessor { @Inject() ctx: Context; async execute() { // ctx.jobId => xxxx } } ``` ### 更多任务选项[​](#更多任务选项 "更多任务选项的直接链接") 除了上面的 delay 之外,还有更多的执行选项。 | 选项 | 类型 | 描述 | | ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | priority | number | 可选的优先级值。范围从 1(最高优先级)到 MAX\_INT(最低优先级)。请注意,使用优先级对性能有轻微影响,因此请谨慎使用。 | | delay | number | 等待可以处理此作业的时间量(毫秒)。请注意,为了获得准确的延迟,服务器和客户端都应该同步它们的时钟。 | | attempts | number | 在任务完成之前尝试尝试的总次数。 | | repeat | RepeatOpts | 根据 cron 规范的重复任务配置,更多可以查看 [RepeatOpts](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueadd),以及下面的重复任务介绍。 | | backoff | number \| BackoffOpts | 任务失败时自动重试的回退设置。请参阅 [BackoffOpts](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueadd)。 | | lifo | boolean | 如果为 true,则将任务添加到队列的右端而不是左端(默认为 false)。 | | timeout | number | 任务因超时错误而失败的毫秒数。 | | jobId | number \| string | 覆盖任务 id - 默认情况下,任务 id 是唯一整数,但您可以使用此设置覆盖它。如果您使用此选项,则由您来确保 jobId 是唯一的。如果您尝试添加一个 id 已经存在的任务,它将不会被添加。 | | removeOnComplete | boolean \| number | 如果为 true,则在成功完成后删除任务。如果设置数字,则为指定要保留的任务数量。默认行为是任务信息保留在已完成列表中。 | | removeOnFail | boolean \| number | 如果为 true,则在所有尝试后都失败时删除任务。如果设置数字,指定要保留的任务数量。默认行为是将任务信息保留在失败列表中。 | | stackTraceLimit | number | 限制将在堆栈跟踪中记录的堆栈跟踪行的数量。 | ## 重复执行的任务[​](#重复执行的任务 "重复执行的任务的直接链接") 除了手动执行的方式,我们也可以通过 `@Processor` 装饰器的参数,快速配置任务的重复执行。 ``` import { Processor, IProcessor } from '@midwayjs/bull'; import { FORMAT } from '@midwayjs/core'; @Processor('test', { repeat: { cron: FORMAT.CRONTAB.EVERY_PER_5_SECOND } }) export class TestProcessor implements IProcessor { @Inject() logger; async execute() { // ... } } ``` ## 常用 Cron 表达式[​](#常用-cron-表达式 "常用 Cron 表达式的直接链接") 关于 Cron 表达式,格式如下。 ``` * * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional) ``` 常见表达式: * 每隔5秒执行一次:`*/5 * * * * *` * 每隔1分钟执行一次:`0 */1 * * * *` * 每小时的20分执行一次:`0 20 * * * *` * 每天 0 点执行一次:`0 0 0 * * *` * 每天的两点35分执行一次:`0 35 2 * * *` 可以使用 [在线工具](https://cron.qqe2.com/) 执行确认下一次执行的时间。 Midway 在框架侧提供了一些常用的表达式,放在 `@midwayjs/core` 中供大家使用。 ``` import { FORMAT } from '@midwayjs/core'; // 每分钟执行的 cron 表达式 FORMAT.CRONTAB.EVERY_MINUTE ``` 内置的还有一些其他的表达式。 | 表达式 | 对应时间 | | --------------------------------- | --------------- | | CRONTAB.EVERY\_SECOND | 每秒钟 | | CRONTAB.EVERY\_MINUTE | 每分钟 | | CRONTAB.EVERY\_HOUR | 每小时整点 | | CRONTAB.EVERY\_DAY | 每天 0 点 | | CRONTAB.EVERY\_DAY\_ZERO\_FIFTEEN | 每天 0 点 15 分 | | CRONTAB.EVERY\_DAY\_ONE\_FIFTEEN | 每天 1 点 15 分 | | CRONTAB.EVERY\_PER\_5\_SECOND | 每隔 5 秒 | | CRONTAB.EVERY\_PER\_10\_SECOND | 每隔 10 秒 | | CRONTAB.EVERY\_PER\_30\_SECOND | 每隔 30 秒 | | CRONTAB.EVERY\_PER\_5\_MINUTE | 每隔 5 分钟 | | CRONTAB.EVERY\_PER\_10\_MINUTE | 每隔 10 分钟 | | CRONTAB.EVERY\_PER\_30\_MINUTE | 每隔 30 分钟 | ## 高级配置[​](#高级配置 "高级配置的直接链接") ### 清理之前的任务[​](#清理之前的任务 "清理之前的任务的直接链接") 在默认情况下,框架会自动清理前一次未调度的 **重复执行任务**,保持每一次的重复执行的任务队列为最新。如果在某些环境不需要清理,可以单独关闭。 比如你不需要清理重复: ``` // src/config/config.prod.ts export default { // ... bull: { clearRepeatJobWhenStart: false, }, } ``` 提示 如果不清理,如果前一次队列为 10s 执行,现在修改为 20s 执行,则两个定时都会存储在 Redis 中,导致代码重复执行。 在日常的开发中,如果不清理,很容易出现代码重复执行这个问题。但是在集群部署的场景,多台服务器轮流重启的情况下,可能会导致定时任务被意外清理,请评估开关的时机。 也可以在启动时手动清理所有任务。 ``` // src/configuration.ts import { Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { join } from 'path'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [koa, bull], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; @Inject() bullFramework: bull.Framework; async onReady() { // 在这个阶段,装饰器队列还未创建,使用 API 提前手动创建队列,装饰器会复用同名队列 const queue = this.bullFramework.createQueue('user'); // 通过队列手动执行清理 await queue.obliterate({ force: true }); } } ``` ### 清理任务历史记录[​](#清理任务历史记录 "清理任务历史记录的直接链接") 当开启 Redis 后,默认情况下,bull 会记录所有的成功和失败的任务 key,这可能会导致 redis 的 key 暴涨,我们可以配置成功或者失败后清理的选项。 默认情况下 * 成功时保留的任务记录为 3 条 * 失败保留的任务记录为 10 条 也可以通过参数进行配置。 比如在装饰器配置。 ``` import { FORMAT } from '@midwayjs/core'; import { IProcessor, Processor } from '@midwayjs/bull'; @Processor('user', { repeat: { cron: FORMAT.CRONTAB.EVERY_MINUTE, }, removeOnComplete: 3, // 成功后移除任务记录,最多保留最近 3 条记录 removeOnFail: 10, // 失败后移除任务记录 }) export class UserService implements IProcessor { execute(data: any) { // ... } } ``` 也可以在全局 config 中配置。 ``` // src/config/config.default.ts export default { // ... bull: { defaultQueueOptions: { // 默认的任务配置 defaultJobOptions: { // 保留 10 条记录 removeOnComplete: 10, }, }, }, } ``` ### Redis 集群[​](#redis-集群 "Redis 集群的直接链接") 可以使用 bull 提供的 `createClient` 方式来接入自定义的 redis 实例,这样你可以接入 Redis 集群。 比如: ``` // src/config/config.default import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, // 一定要是false retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null // 一定要是null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { bull: { defaultQueueOptions: { createClient: (type, opts) => { return redisClientInstance; }, // 这些任务存储的 key,都是相同开头,以便区分用户原有 redis 里面的配置 prefix: '{midway-bull}', }, } } ``` ## 队列管理[​](#队列管理 "队列管理的直接链接") 队列是廉价的,每个 Job 都会绑定一个队列,在一些情况下,我们也可以手动对队列进行管理操作。 ### 手动创建队列[​](#手动创建队列 "手动创建队列的直接链接") 除了使用 `@Processor` 简单定义队列,我们还可以使用 API 进行创建。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; async onReady() { const testQueue = this.bullFramework.createQueue('test', { redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, prefix: '{midway-bull}', }); // ... } } ``` 通过 `createQueue` 手动创建队列后,队列依旧会自动保存。如果在启动时 `@Processor` 使用了该队列名,则会自动使用已经创建好的队列。 比如: ``` // 会自动使用上面手动创建的同名队列 @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { } } ``` ### 获取队列[​](#获取队列 "获取队列的直接链接") 我们可以简单的根据队列名获取队列。 ``` const testQueue = bullFramework.getQueue('test'); ``` 也可以通过装饰器来获取。 ``` import { InjectQueue, BullQueue } from '@midwayjs/bull'; import { Provide } from '@midwayjs/core'; @Provide() export class UserService { @InjectQueue('test') testQueue: BullQueue; async invoke() { await this.testQueue.pause(); // ... } } ``` ### 队列常用操作[​](#队列常用操作 "队列常用操作的直接链接") 暂停队列。 ``` await testQueue.pause(); ``` 继续队列。 ``` await testQueue.resume(); ``` 队列事件。 ``` // Local events pass the job instance... testQueue.on('progress', function (job, progress) { console.log(`Job ${job.id} is ${progress * 100}% ready!`); }); testQueue.on('completed', function (job, result) { console.log(`Job ${job.id} completed! Result: ${result}`); job.remove(); }); ``` 完整队列 API 请参考 [这里](https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md)。 ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-bull.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { clients: { // ... bullLogger: { fileLogName: 'midway-bull.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { bull: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`; }, } } ``` ## 关于 Redis 版本[​](#关于-redis-版本 "关于 Redis 版本的直接链接") 请尽可能选择最新的版本( >=5 ),目前在低版本 redis 上有发现定时任务创建失败的问题。 ## Bull UI[​](#bull-ui "Bull UI的直接链接") 在分布式场景中,我们可以资利用 Bull UI 来简化管理。 和 bull 组件类似,需要独立安装和启用。 ``` $ npm i @midwayjs/bull-board@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull-board": "^3.0.0", // ... }, } ``` 将 bull-board 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bull, bullBoard, ] }) export class MainConfiguration { //... } ``` 默认的访问路径为:`http://127.1:7001/ui`。 效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01j4wEFb1UacPxA06gs_!!6000000002534-2-tps-1932-1136.png) 可以通过配置进行基础路径的修改。 ``` // src/config/config.prod.ts export default { // ... bullBoard: { basePath: '/ui', }, } ``` 此外,组件提供了 `BullBoardManager` ,可以添加动态创建的队列。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bull, bullBoard ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; @Inject() bullBoardManager: bullBoard.BullBoardManager; async onServerReady() { const testQueue = this.bullFramework.createQueue('test', { // ... }); this.bullBoardManager.addQueue(new bullBoard.BullAdapter(testQueue); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、EVALSHA 错误[​](#1evalsha-错误 "1、EVALSHA 错误的直接链接") ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01KfjCKT1yypmNPDkIL_!!6000000006648-2-tps-3540-102.png) 这个问题基本明确,问题会出现在 redis 的集群版本上。 原因是 redis 会对 key 做 hash 来确定存储的 slot,集群下这一步 @midwayjs/bull 的 key 命中了不同的 slot。 解决方案: task 里的 prefix 配置用 包括,强制 redis 只计算 里的hash,例如 `prefix: '{midway-task}'`。 ### 2、EVAL inside MULTI is not allowed 错误[​](#2eval-inside-multi-is-not-allowed-错误 "2、EVAL inside MULTI is not allowed 错误的直接链接") 表现为 `queue.createBulk()`、`job.moveToFailed()` 等任务队列 API 调用无效,并出现下面的错误。 ``` ReplyError: EXECABORT Transaction discarded because of previous errors. at parseError (/node_modules/redis-parser/lib/parser.js:179:12) at parseType (/node_modules/redis-parser/lib/parser.js:302:14) { command: { name: 'exec', args: [] }, previousErrors: [ ReplyError: ERR 'EVAL' inside MULTI is not allowed at parseError (/node_modules/redis-parser/lib/parser.js:179:12) at parseType (/node_modules/redis-parser/lib/parser.js:302:14) { command: [Object] } ] } ``` 提示 常出现于使用阿里云 Redis 服务。 由于这些 API 依赖的 Redis Lua 脚本中使用了 EVAL 或者 EVALSHA,阿里云 Redis 使用代理模式连接时,会对 Lua 脚本调用做额外限制,包括 [不允许在 MULTI 事务中执行 EVAL 命令](https://help.aliyun.com/zh/redis/support/usage-of-lua-scripts?#section-8f7-qgv-dlv),文档中还提到可以通过参数配置 script\_check\_enable 关闭这一校验,但是验证无效。 解决方案: * 1、在阿里云控制台操作开启直连地址,将服务切换到直连模式 * 2、客户端切换成集群模式,参考上述「Redis 集群」章节,切换配置方式 --- # 任务队列 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题: * 平滑处理峰值。可以在任意时间启动资源密集型任务,然后将这些任务添加到队列中,而不是同步执行。让任务进程以受控方式从队列中提取任务。也可以轻松添加新的队列消费者以扩展后端任务处理。 * 分解可能会阻塞 Node.js 事件循环的单一任务。比如用户请求需要像音频转码这样的 CPU 密集型工作,就可以将此任务委托给其他进程,从而释放面向用户的进程以保持响应。 * 提供跨各种服务的可靠通信渠道。例如,您可以在一个进程或服务中排队任务(作业),并在另一个进程或服务中使用它们。在任何流程或服务的作业生命周期中完成、错误或其他状态更改时,您都可以收到通知(通过监听状态事件)。当队列生产者或消费者失败时,它们的状态被保留,并且当节点重新启动时任务处理可以自动重新启动。 Midway 提供了 `@midwayjs/bullmq` 包作为 [BullMQ](https://github.com/taskforcesh/bullmq) 之上的抽象/包装器。BullMQ 是 Bull 的下一代实现,提供了更好的性能和更多的功能。该软件包可以轻松地将 BullMQ 以友好的方式集成到您的应用程序中。 BullMQ 使用 Redis 来保存作业数据,在使用 Redis 时,Queue 架构是完全分布式,和平台无关。例如,您可以在一个(或多个)节点(进程)中运行一些 Queue 生产者、消费者,而在其他节点上的运行其他生产者和消费者。 提示 BullMQ 是一个分布式任务管理系统,必须依赖 redis 警告 由于 BullMQ 是 Bull 的升级版,从 v3.20 开始,将由 BullMQ 替代 Bull 组件,如需使用 Bull 组件,请参考 [Bull 文档](/docs/3.0.0/extensions/bull.md) 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/bullmq@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bullmq": "^3.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 bullmq 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ // ... bullmq ] }) export class MainConfiguration { //... } ``` ## 一些概念[​](#一些概念 "一些概念的直接链接") BullMQ 将整个队列分为以下几个部分: * Queue:队列,管理任务 * Job:每个任务对象,可以对任务进行启停控制 * Worker:任务处理器,实际的逻辑执行部分 * QueueEvents:队列事件,用于监听任务状态变化 * FlowProducer:任务流生产者,用于创建任务依赖关系 ## 基础配置[​](#基础配置 "基础配置的直接链接") bullmq 是一个分布式任务管理器,强依赖于 redis,在 `config.default.ts` 文件中配置。 ``` // src/config/config.default.ts export default { // ... bullmq: { defaultConnection: { host: '127.0.0.1', port: 6379, }, // 可选,队列前缀 defaultPrefix: '{midway-bullmq}', }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... bullmq: { defaultConnection: { port: 6379, host: '127.0.0.1', password: 'foobared', } }, } ``` 所有的队列、任务处理器、队列事件、任务流都会复用该配置。 ## 编写任务处理器[​](#编写任务处理器 "编写任务处理器的直接链接") 使用 `@Processor` 装饰器装饰一个类,用于快速定义一个任务处理器。 `@Processor` 装饰器需要传递一个 Queue(队列)的名字,在框架启动时,如果没有名为 `test` 的队列,则会自动创建。 比如,我们在 `src/processor/test.processor.ts` 文件中编写如下代码。 ``` import { Processor, IProcessor } from '@midwayjs/bullmq'; @Processor('test') export class TestProcessor implements IProcessor { async execute(data: any) { // 处理任务逻辑 console.log('processing job:', data); } } ``` ## 执行任务[​](#执行任务 "执行任务的直接链接") 当定义完 Processor 之后,由于并未指定 Processor 如何执行,我们还需要手动执行它。 ### 手动执行任务[​](#手动执行任务 "手动执行任务的直接链接") ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ bullmq ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; async onServerReady() { // 获取 Processor 相关的队列 const testQueue = this.bullmqFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue(); } } ``` ### 增加执行参数[​](#增加执行参数 "增加执行参数的直接链接") 我们也可以在执行时,附加一些参数。 ``` @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { // params.name => 'harry' } } // invoke const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({ aaa: 1, bbb: 2, }); ``` ### 任务状态和管理[​](#任务状态和管理 "任务状态和管理的直接链接") 执行 `addJobToQueue` 后,我们可以获取到一个 `Job` 对象。 ``` const testQueue = this.bullmqFramework.getQueue('test'); const job = await testQueue?.addJobToQueue(); // 更新进度 await job.updateProgress(60); // 获取进度 const progress = await job.progress; // => 60 // 获取任务状态 const state = await job.getState(); // state => 'delayed' 延迟状态 // state => 'completed' 完成状态 // state => 'failed' 失败状态 ``` ### 延迟执行[​](#延迟执行 "延迟执行的直接链接") 执行任务时,也有一些额外的选项。 比如,延迟 1s 执行。 ``` const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({}, { delay: 1000 }); ``` ### 任务重试[​](#任务重试 "任务重试的直接链接") BullMQ 支持任务失败重试机制。 ``` const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({}, { attempts: 3, // 最多重试 3 次 backoff: { // 重试策略 type: 'exponential', // 指数退避 delay: 1000 // 初始延迟 1 秒 } }); ``` ### 任务优先级[​](#任务优先级 "任务优先级的直接链接") 可以为任务设置优先级,优先级高的任务会优先执行。 ``` const testQueue = this.bullmqFramework.getQueue('test'); // priority 值越大优先级越高 await testQueue?.addJobToQueue({ priority: 1 }, { priority: 3 }); // 高优先级 await testQueue?.addJobToQueue({ priority: 2 }, { priority: 2 }); // 中优先级 await testQueue?.addJobToQueue({ priority: 3 }, { priority: 1 }); // 低优先级 ``` ### 中间件和错误处理[​](#中间件和错误处理 "中间件和错误处理的直接链接") BullMQ 组件包含可以独立启动的 Framework,有着自己的 App 对象和 Context 结构。 我们可以对 bullmq 的 App 配置独立的中间件和错误过滤器。 ``` @Configuration({ imports: [ bullmq ] }) export class MainConfiguration { @App('bullmq') bullmqApp: bullmq.Application; async onReady() { this.bullmqApp.useMiddleware(/*中间件*/); this.bullmqApp.useFilter(/*过滤器*/); } } ``` ### 上下文[​](#上下文 "上下文的直接链接") 任务处理器执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { jobId: string; job: Job; token?: string; from: new (...args) => IProcessor; } ``` 我们可以直接从 ctx 中访问当前的 Job 对象。 ``` import { Processor, IProcessor, Context } from '@midwayjs/bullmq'; @Processor('test') export class TestProcessor implements IProcessor { @Inject() ctx: Context; async execute(data: any) { // ctx.jobId => 当前任务ID // ctx.job => 当前任务对象 } } ``` ## 重复执行的任务[​](#重复执行的任务 "重复执行的任务的直接链接") 除了手动执行的方式,我们也可以通过 `@Processor` 装饰器的参数,快速配置任务的重复执行。 ``` import { Processor, IProcessor } from '@midwayjs/bullmq'; import { FORMAT } from '@midwayjs/core'; @Processor('test', { repeat: { pattern: FORMAT.CRONTAB.EVERY_PER_5_SECOND } }) export class TestProcessor implements IProcessor { async execute() { // 每 5 秒执行一次 } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 任务流(Flow Producer)[​](#任务流flow-producer "任务流(Flow Producer)的直接链接") BullMQ 支持创建任务依赖关系,形成任务流。 ``` const flowProducer = bullmqFramework.createFlowProducer({}, 'test-flow'); // 创建任务流 await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', data: { value: 1 }, children: [ { name: 'child-job', queueName: 'flow-queue-2', data: { value: 2 } } ] }); ``` ### 队列事件[​](#队列事件 "队列事件的直接链接") BullMQ 提供了丰富的事件系统,可以监听任务的各种状态变化。 ``` const eventQueue = bullmqFramework.createQueue('event-queue'); const queueEvents = eventQueue.createQueueEvents(); // 监听任务完成事件 queueEvents.on('completed', ({ jobId }) => { console.log(`Job ${jobId} completed!`); }); // 监听任务失败事件 queueEvents.on('failed', ({ jobId, failedReason }) => { console.log(`Job ${jobId} failed: ${failedReason}`); }); ``` ### 清理任务历史记录[​](#清理任务历史记录 "清理任务历史记录的直接链接") 当开启 Redis 后,默认情况下,bullmq 会记录所有的成功和失败的任务 key,这可能会导致 redis 的 key 暴涨,我们可以配置成功或者失败后清理的选项。 ``` // src/config/config.default.ts export default { bullmq: { defaultQueueOptions: { defaultJobOptions: { removeOnComplete: 3, // 成功后只保留最近 3 条记录 removeOnFail: 10, // 失败后只保留最近 10 条记录 } } } } ``` ### Redis 集群[​](#redis-集群 "Redis 集群的直接链接") bullmq 可以指定 connection 实例,你可以将自己创建的 Redis 实例配置到 `defaultConnection` 中,这样就可以接入 Redis 集群。 ``` // src/config/config.default.ts import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { bullmq: { defaultConnection: redisClientInstance, defaultPrefix: '{midway-bullmq}', } } ``` ### 获取任务处理器[​](#获取任务处理器 "获取任务处理器的直接链接") 通过内置的方法,我们可以获取到原始的任务处理器(Worker)。 可以启动任意多个 Worker 监听同一个队列,在这种情况下 BullMQ 会把队列中的任务轮流(round-robin)分配给这些 Worker。 当队列中有任务被添加时,BullMQ 会在这两个 Worker 之间自动分配任务。 我们可以通过方法 `getWorker` 获取到首个监听的 Worker 对象,也可以通过方法 `getWorkers` 获取到该队列监听的所有 Worker 对象。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ // ... bullmq, ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; async onServerReady() { const testWorker = this.bullmqFramework.getWorker('test'); const allWorkers = this.bullmqFramework.getWorkers('test'); } } ``` ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-bullmq.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { clients: { bullMQLogger: { fileLogName: 'midway-bullmq.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { bullmq: { contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`; }, } } ``` ## BullMQ 原始对象[​](#bullmq-原始对象 "BullMQ 原始对象的直接链接") 组件导出了 BullMQ 的原始对象,可以进行更多的操作。 ``` import { BullMQ } from '@midwayjs/bullmq'; ``` 你可以通过 `BullMQ` 对象,获取到 `Queue`、`Worker`、`FlowProducer` 等对象定义。 ## Bull UI[​](#bull-ui "Bull UI的直接链接") 在分布式场景中,我们可以资利用 Bull UI 来简化管理。 和 bull 组件类似,需要独立安装和启用。 ``` $ npm i @midwayjs/bull-board@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull-board": "^3.0.0", // ... }, } ``` 将 bull-board 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bullmq, bullBoard, ] }) export class MainConfiguration { //... } ``` 默认的访问路径为:`http://127.1:7001/ui`。 效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01j4wEFb1UacPxA06gs_!!6000000002534-2-tps-1932-1136.png) 可以通过配置进行基础路径的修改。 ``` // src/config/config.prod.ts export default { // ... bullBoard: { basePath: '/ui', }, } ``` 此外,组件提供了 `BullBoardManager` ,可以添加动态创建的队列。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bullmq, bullBoard ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; @Inject() bullBoardManager: bullBoard.BullBoardManager; async onServerReady() { const testQueue = this.bullmqFramework.createQueue('test', { // ... }); this.bullBoardManager.addQueue(new bullBoard.BullMQAdapter(testQueue) as any); } } ``` 由于最新 bull-board 要求最低 Node.js 版本为 v20,所以 Midway v3 无法将 bull-board 升级;在 v5.23.0 版本下的 `bull-board` 存在类型定义问题,采用 `as any` 的方式绕过。 --- # 文件上传 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用上传组件,支持 `file` (服务器临时文件) 和 `stream` (流)两种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 提示 本模块自 3.17.0 起替换 upload 组件。 和 upload 组件的差异为: * 1、配置的 key 从 `upload` 调整为 `busboy` * 2、中间件不再默认加载,手动可配置到全局或者路由 * 3、入参定义类型调整为 `UploadStreamFileInfo` * 4、`fileSize` 的配置有调整 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/busboy@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/busboy": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; @Configuration({ imports: [ // ...other components busboy ], // ... }) export class MainConfiguration {} ``` ## 配置中间件[​](#配置中间件 "配置中间件的直接链接") 组件中提供了 `UploadMiddleware` 这个中间件,可以将其配置到全局或者特定路由,推荐配置到特定路由,提升性能。 **路由中间件** ``` import { Controller, Post } from '@midwayjs/core'; import { UploadMiddleware } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', { middleware: [UploadMiddleware] }) async upload(/*...*/) { // ... } } ``` **全局中间件** * @midwayjs/koa * @midwayjs/web * @midwayjs/express * @midwayjs/faas ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @App('koa') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/web'; @Configuration({ // ... }) export class MainConfiguration { @App('egg') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/express'; @Configuration({ // ... }) export class MainConfiguration { @App('express') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/faas'; @Configuration({ // ... }) export class MainConfiguration { @App('faas') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ## 配置[​](#配置 "配置的直接链接") 组件使用 `busboy` 作为配置的 key。 ### 上传模式[​](#上传模式 "上传模式的直接链接") 上传分为三种模式,文件模式,流式模式以及新增的异步迭代器模式。 代码中使用 `@Files()` 装饰器获取上传的文件, `@Fields` 装饰器获取其他上传表单字段。 * 文件模式 * 异步迭代器模式 * 流模式 `file` 为默认值,配置 mode 为 `file` 字符串。 ``` // src/config/config.default.ts export default { // ... busboy: { mode: 'file', }, } ``` 在代码中获取上传的文件,支持同时上传多个文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadFileInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload(@Files() files: Array, @Fields() fields: Record) { /* files = [ { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // 服务器临时文件地址 mimeType: 'application/pdf', // mime fieldName: 'file' // field name }, ] */ } } ``` 使用 file 模式时, 获取的 `data` 为上传的文件在服务器的 `临时文件地址`,后续可以再通过 `fs.createReadStream` 等方式来处理此文件内容,支持同时上传多个文件,多个文件会以数组的形式存放。 每个数组内的对象包含以下几个字段 ``` export interface UploadFileInfo { /** * 上传的文件名 */ filename: string; /** * 上传文件 mime 类型 */ mimeType: string; /** * 上传服务端保存的路径 */ data: string; /** * 上传的表单字段名 */ fieldName: string; } ``` 从 `v3.18.0` 提供,替代原有的 `stream` 模式,该模式支持多个文件流式上传。 配置 mode 为 `asyncIterator` 字符串。 ``` // src/config/config.default.ts export default { // ... busboy: { mode: 'asyncIterator', }, } ``` 在代码中获取上传的文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload( @Files() fileIterator: AsyncGenerator, @Fields() fieldIterator: AsyncGenerator ) { // ... } } ``` 在该模式下,`@Files` 和 `@File` 装饰器会提供同一个 `AsyncGenerator` ,而 `@Fields` 会也同样会提供一个 `AsyncGenerator`。 通过循环 `AsyncGenerator` ,可以针对每个上传文件的 `ReadStream` 做处理。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy'; import { tmpdir } from 'os'; import { createWriteStream } from 'fs'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload( @Files() fileIterator: AsyncGenerator, @Fields() fieldIterator: AsyncGenerator ) { for await (const file of fileIterator) { const { filename, data } = file; const p = join(tmpdir, filename); const stream = createWriteStream(p); data.pipe(stream); } for await (const { name, value } of fieldIterator) { // ... } // ... } } ``` 注意,如果一次上传中任意一个文件抛出了错误,本次上传流会直接关闭,所有未传输完成的文件都会异常。 异步迭代器中的上传对象包含以下几个字段。 ``` export interface UploadStreamFieldInfo { /** * 上传的文件名 */ filename: string; /** * 上传文件 mime 类型 */ mimeType: string; /** * 上传文件的文件流 */ data: Readable; /** * 上传的表单字段名 */ fieldName: string; } ``` 异步迭代器中的 `@Fields` 的对象略有不同,返回的数据会包含 `name` 和 `value` 字段。 ``` export interface UploadStreamFieldInfo { /** * 表单名 */ name: string; /** * 表单值 */ value: any; } ``` 警告 不再推荐使用。 配置 mode 为 `stream` 字符串。 使用 stream 模式时,通过 `@Files` 中获取的 `data` 为 `ReadStream`,后续可以再通过 `pipe` 等方式继续将数据流转至其他 `WriteStream` 或 `TransformStream`。 使用 stream 模式时,仅同时上传一个文件,即 `@Files` 数组中只有一个文件数据对象。 另外,stream 模式 `不会` 在服务器上产生临时文件,所以获取到上传的内容后无需手动清理临时文件缓存。 提示 faas 场景实现方式视平台而定,如果平台不支持流式请求/响应但是业务开启了 `mode: 'stream'`,将采用先读取到内存,再模拟流式传输来降级处理。 在代码中获取上传的文件,流式模式下仅支持单个文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload(@Files() files: Array, @Fields() fields: Record { if (ctx.path === '/') { return [ '.jpg', '.jpeg', ]; } else { return [ '.jpg', ] }; }, // ... }, } ``` ### 上传文件 MIME 类型检查[​](#上传文件-mime-类型检查 "上传文件 MIME 类型检查的直接链接") 部分`恶意用户`,会尝试将 `.php` 等 WebShell 修改扩展名为 `.jpg`,来绕过基于扩展名的白名单过滤规则,在某些服务器环境内,这个 jpg 文件依然会被作为 PHP 脚本来执行,造成安全风险。 组件提供了 `mimeTypeWhiteList` 配置参数 **【请注意,此参数无默认值设置,即默认不校验】**,您可以通过此配置设置允许的文件 MIME 格式,规则为由数组 `[扩展名, mime, [...moreMime]]` 组成的 `二级数组`,例如: ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/busboy'; export default { // ... busboy: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: { '.jpg': 'image/jpeg', // 也可以设置多个 MIME type,比如下面的允许 .jpeg 后缀的文件是 jpg 或者是 png 两种类型 '.jpeg': ['image/jpeg', 'image/png'], // 其他类型 '.gif': 'image/gif', '.bmp': 'image/bmp', '.wbmp': 'image/vnd.wap.wbmp', '.webp': 'image/webp', } }, } ``` 您也可以使用组件提供的 `DefaultUploadFileMimeType` 变量,作为默认的 MIME 校验规则,它提供了常用的 `.jpg`、`.png`、`.psd` 等文件扩展名的 MIME 数据: ``` // src/config/config.default.ts import { uploadWhiteList, DefaultUploadFileMimeType } from '@midwayjs/busboy'; export default { // ... busboy: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: DefaultUploadFileMimeType, }, } ``` 文件格式与对应的 MIME 映射,您可以通过 `https://mimetype.io/` 这个网站来查询,对于文件的 MIME 识别,我们使用的是 [file-type@16](https://www.npmjs.com/package/file-type) 这个 npm 包,请注意它支持的文件类型。 信息 MIME 类型校验规则仅适用于使用 文件上传模式 `mode=file`,同时设置此校验规则之后,由于需要读取文件内容进行匹配,所以会稍微影响上传性能。 但是,我们依然建议您在条件允许的情况下,设置 `mimeTypeWhiteList` 参数,这将提升您的应用程序安全性。 你可以传递一个函数,可以根据不同的条件动态返回 MIME 规则。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... busboy: { mimeTypeWhiteList: (ctx) => { if (ctx.path === '/') { return { '.jpg': 'image/jpeg', }; } else { return { '.jpeg': ['image/jpeg', 'image/png'], } }; } }, } ``` ### Busboy 上传限制[​](#busboy-上传限制 "Busboy 上传限制的直接链接") 默认情况下没有限制,可以通过配置修改,数字类型,单位为 byte。 ``` // src/config/config.default.ts export default { // ... busboy: { // ... limits: { fileSize: 1024 } }, } ``` 除此之外,还可以设置一些其他的 [限制](https://github.com/mscdex/busboy/tree/master?tab=readme-ov-file#exports)。 ### 临时文件与清理[​](#临时文件与清理 "临时文件与清理的直接链接") 如果你使用了 `file` 模式来获取上传的文件,那么上传的文件会存放在您于 `config` 文件中设置的 `upload` 组件配置中的 `tmpdir` 选项指向的文件夹内。 你可以通过在配置中使用 `cleanTimeout` 来控制自动的临时文件清理时间,默认值为 `5 * 60 * 1000`,即上传的文件于 `5 分钟` 后自动清理,设置为 `0` 则视为不开启自动清理功能。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/busboy'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... busboy: { mode: 'file', tmpdir: join(tmpdir(), 'midway-busboy-files'), cleanTimeout: 5 * 60 * 1000, }, } ``` 你也可以在代码中通过调用 `await ctx.cleanupRequestFiles()` 来主动清理当前请求上传的临时文件。 ### 设置不同路由的配置[​](#设置不同路由的配置 "设置不同路由的配置的直接链接") 通过中间件的不同实例,可以对不同的路由做不同的配置,这种场景下会和全局配置合并,仅能覆盖一小部分配置。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadFileInfo, UploadMiddleware } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload1', { middleware: [ createMiddleware(UploadMiddleware, {mode: 'file'}) ]}) async upload1(@Files() files Array) { // ... } @Post('/upload2', { middleware: [ createMiddleware(UploadMiddleware, {mode: 'stream'}) ]}) async upload2(@Files() files Array) { // ... } } ``` 当前可以传递的配置包括 `mode` 以及 `busboy` 自带的 [配置](https://github.com/mscdex/busboy/tree/master?tab=readme-ov-file#exports)。 ## 内置错误[​](#内置错误 "内置错误的直接链接") 以下的错误在不同上传模式下均会自动触发。 * `MultipartInvalidFilenameError` 无效文件名 * `MultipartInvalidFileTypeError` 无效文件类型 * `MultipartFileSizeLimitError` 文件大小超出限制 * `MultipartFileLimitError` 文件数量超出限制 * `MultipartPartsLimitError` 上传 parts 数量超出限制 * `MultipartFieldsLimitError` fields 数量超出限制 * `MultipartError` 其余的 busbuy 错误 ## 安全提示[​](#安全提示 "安全提示的直接链接") 1. 请注意是否开启 `扩展名白名单` (whiteList),如果扩展名白名单被设置为 `null`,则会有可能被攻击者所利用上传 `.php`、`.asp` 等WebShell。 2. 请注意是否设置 `match` 或 `ignore` 规则,否则普通的 `POST/PUT` 等接口会有可能被攻击者利用,造成服务器负荷加重和空间大量占用问题。 3. 请注意是否设置 `文件类型规则` (fileTypeWhiteList),否则可能会被攻击者伪造文件类型进行上传。 ## 前端文件上传示例[​](#前端文件上传示例 "前端文件上传示例的直接链接") ### 1. html form 的形式[​](#1-html-form-的形式 "1. html form 的形式的直接链接") ```
Name:
File:
``` ### 2. fetch FormData 方式[​](#2-fetch-formdata-方式 "2. fetch FormData 方式的直接链接") ``` const fileInput = document.querySelector('#your-file-input') ; const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData, }); ``` ## Postman 测试示例[​](#postman-测试示例 "Postman 测试示例的直接链接") ![](https://img.alicdn.com/imgextra/i4/O1CN01iv9ESW1uIShNiRjBF_!!6000000006014-2-tps-2086-1746.png) --- # 缓存 Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装[​](#安装 "安装的直接链接") 首先安装相关的组件模块。 ``` $ npm i @midwayjs/cache@3 cache-manager --save $ npm i @types/cache-manager --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cache": "^3.0.0", "cache-manager": "^3.4.1", // ... }, "devDependencies": { "@types/cache-manager": "^3.4.0", // ... } } ``` ## 使用 Cache[​](#使用-cache "使用 Cache的直接链接") Midway 为不同的 cache 存储提供了统一的 API。默认内置了一个基于内存数据存储的数据中心。如果想要使用别的数据中心,开发者也可以切换到例如 mongodb、fs 等模式。 首先,引入 Cache 组件,在 `configuration.ts` 中导入: ``` import { Configuration, App } from '@midwayjs/core'; import * as cache from '@midwayjs/cache'; import { join } from 'path' @Configuration({ imports: [ // ... cache // 导入 cache 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 然后在业务代码中即可注入使用。 ``` import { Inject, Provide } from '@midwayjs/core'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cacheManager: CacheManager; // 依赖注入 CacheManager } ``` 通过提供的 API 来设置,获取缓存数据。 ``` import { Inject, Provide } from '@midwayjs/core'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cacheManager: CacheManager; async getUser(options: IUserOptions) { // 设置缓存内容 await this.cacheManager.set(`name`, 'stone-jin'); // 获取缓存内容 let result = await this.cacheManager.get(`name`); return result; } async getUser2(){ //获取缓存内容 let result = await this.cacheManager.get(`name`); return result; } async reset(){ await this.cacheManager.reset(); // 清空对应 store 的内容 } } ``` ### 设置缓存[​](#设置缓存 "设置缓存的直接链接") 我们通过 `await this.cache.set(key, value)` 方法进行设置,此处默认过期时间是10s。 你也可以手动设置 TTL(过期时间),如下: ``` await this.cacheManager.set(key, value, {ttl: 1000}); // ttl的单位为秒 ``` 如果你想要 Cache 不过期,则将 TTL 设置为 null 即可。 ``` await this.cacheManager.set(key, value, {ttl: null}); ``` 同时你也可以通过全局的 `config.default.ts` 中进行设置。 ``` export default { // ... cache: { store: 'memory', options: { max: 100, ttl: 10, // 修改默认的ttl配置 }, } } ``` ### 获取缓存[​](#获取缓存 "获取缓存的直接链接") ``` const value = await this.cacheManager.get(key); ``` 如果获取不到,则为 undefined。 ### 移除缓存[​](#移除缓存 "移除缓存的直接链接") 移除缓存,可以通过 del 方法。 ``` await this.cacheManager.del(key); ``` ### 清空整体store数据(此处是整体清除,需要重点⚠️)[​](#清空整体store数据此处是整体清除需要重点️ "清空整体store数据(此处是整体清除,需要重点⚠️)的直接链接") 比如用户设置了某个 redis 为 store,调用的话,包括非 cache 模块设置的也会清除。 ``` await this.cacheManager.reset(); // 这块需要注意 ``` ## 全局配置[​](#全局配置 "全局配置的直接链接") 当我们引用了这个 cache 组件后,我们能对其进行全局的配置。配置方法跟别的组件类似。 默认的配置: ``` export default { // ... cache: { store: 'memory', options: { max: 100, ttl: 10, }, } } ``` 例如用户可以修改默认的 TTL,也就是过期时间。 ## 其他Cache[​](#其他cache "其他Cache的直接链接") 用户也可以修改 store 方式,在 `config.default.ts` 中进行组件的配置: ``` import * as redisStore from 'cache-manager-ioredis'; export default { // ... cache: { store: redisStore, options: { host: 'localhost', // default value port: 6379, // default value password: '', db: 0, keyPrefix: 'cache:', ttl: 100 }, } } ``` 或者修改为 mongodb 的 cache。 危险 **再次注意⚠️:使用 redis 作为 cache 的时候,代码里面慎用 reset 方法,因为会把整个 redis 给 flushdb,简称数据清空。** ## 相关文档[​](#相关文档 "相关文档的直接链接") 由于 Midway Cache 是基于 cache-manager 封装,所以相关资料用户也可以查询:[cache-manger](https://www.npmjs.com/package/cache-manager)。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、set 和 get 无法得到相同值?[​](#1set-和-get-无法得到相同值 "1、set 和 get 无法得到相同值?的直接链接") 用户使用了 cache 模块,默认是内存式的,例如在本地用 dev 模式,由于是单进程的,那 set 和 ge t最终能达到相同的值。但是用户部署到服务器上面后,由于会有多 worker,相当于第一次请求,落在进程1上,然后第二次落在进程2上,这样获得到空了。 解决办法:参考 其他 Cache 的章节,配置 store 为分布式,例如 redis 的 store 等方式。 --- # 缓存 缓存是一个伟大而简单的技术,有助于提高你的应用程序的性能。本组件提供了缓存相关的能力,你可以将数据缓存到不同的数据源,也可以针对不同场景建立多级缓存,提高数据访问速度。 提示 Midway 提供基于 [cache-manager v5](https://github.com/node-cache-manager/node-cache-manager) 模块重新封装了缓存组件,原有的缓存模块基于 v3 开发不再迭代,如需查看老文档,请访问 [这里](/docs/extensions/cache.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装[​](#安装 "安装的直接链接") 首先安装相关的组件模块。 ``` $ npm i @midwayjs/cache-manager@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cache-manager": "^3.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as cacheManager from '@midwayjs/cache-manager'; import { join } from 'path' @Configuration({ imports: [ // ... cacheManager, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 使用缓存[​](#使用缓存 "使用缓存的直接链接") ### 1、配置缓存[​](#1配置缓存 "1、配置缓存的直接链接") 在使用前,你需要配置缓存所在的位置,比如内置的内存缓存,或者是引入 Redis 缓存,每个缓存对应了一个缓存的 Store。 下面的示例代码,配置了一个名为 `default` 的内存缓存。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', }, }, } } ``` 最常用的场景下,缓存会包含两个参数,配置 `max` 修改缓存的数量,配置 `ttl` 修改缓存的过期时间,单位毫秒。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', options: { max: 100, ttl: 10, }, }, }, } } ``` 提示 * `ttl` 的单位是毫秒 * `max` 代表缓存 key 的最大个数 * 不同的 Store 淘汰 key 的算法不同,内存缓存使用的淘汰算法是 LRU ### 2、使用缓存[​](#2使用缓存 "2、使用缓存的直接链接") 可以通过服务工厂的装饰器获取到实例,可以通过简单的 `get` 和 `set` 方法获取和保存缓存。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @InjectClient(CachingFactory, 'default') cache: MidwayCache; async invoke(name: string, value: string) { // 设置缓存 await this.cache.set(name, value); // 获取缓存 const data = await this.cache.get(name); // ... } } ``` 动态设置 `ttl` 过期时间。 ``` await this.cache.set('key', 'value', 1000); ``` 若要禁用缓存过期,可以将 `ttl` 配置属性设置为 0。 ``` await this.cache.set('key', 'value', 0); ``` 删除单个缓存。 ``` await this.cache.del('key'); ``` 清理整个缓存,可以使用 `reset` 方法。 ``` await this.cacheManager.reset(); ``` 危险 注意,清理整个缓存非常危险,如果使用了 Redis 作为缓存 store,将清空整个 Redis 数据。 除了装饰器之外,也可以通过 API 获取缓存实例。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Inject() cachingFactory: CachingFactory; async invoke() { const caching = await this.cachingFactory.get('default'); // ... } } ``` ### 3、配置多个缓存[​](#3配置多个缓存 "3、配置多个缓存的直接链接") 和其他组件一样,组件支持配置多个缓存实例。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', }, otherCaching: { store: 'memory', } }, } } ``` 可以注入不同的缓存实例。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @InjectClient(CachingFactory, 'default') cache: MidwayCache; @InjectClient(CachingFactory, 'otherCaching') customCaching: MidwayCache; } ``` ### 4、配置不同 Store[​](#4配置不同-store "4、配置不同 Store的直接链接") 组件基于 [cache-manager](https://github.com/node-cache-manager/node-cache-manager) 可以配置不同的缓存 Store,比如最常见的可以配置 Redis Store。 假如项目已经配置了一个 `Redis`,通过组件内置的 `createRedisStore` 方法,可以快速创建一个 Redis Store。 ``` import { createRedisStore } from '@midwayjs/cache-manager'; // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: createRedisStore('default'), options: { ttl: 10, } }, }, }, redis: { clients: { default: { port: 6379, host: '127.0.0.1', } } } } ``` `createRedisStore` 方法可以传递一个已经配置的 redis 实例名,可以和 redis 组件复用实例。 ### 5、配置三方 Store[​](#5配置三方-store "5、配置三方 Store的直接链接") 除了 Redis 之外,用户也可以自行选择 Cache-Manager 的 Store,列表可以参考 [这里](https://github.com/node-cache-manager/node-cache-manager?tab=readme-ov-file#store-engines)。 下面是一个配置 [node-cache-manager-ioredis-yet](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) 的例子。 ``` // src/config/config.default.ts import { redisStore } from 'cache-manager-ioredis-yet'; export default { cacheManager: { clients: { default: { store: redisStore, options: { port: 6379, host: 'localhost', ttl: 10, }, }, }, } } ``` ### 6、多级缓存[​](#6多级缓存 "6、多级缓存的直接链接") [cache-manager](https://github.com/node-cache-manager/node-cache-manager) 支持将多个缓存 Store 聚合到一起,实现多级缓存。 比如我可以创建一个多级缓存将多个缓存 Store 合并到一起。 ``` // src/config/config.default.ts import { createRedisStore } from '@midwayjs/cache-manager'; export default { cacheManager: { clients: { memoryCaching: { store: 'memory', }, redisCaching: { store: createRedisStore('default'), options: { ttl: 10, }, }, multiCaching: { store: ['memoryCaching', 'redisCaching'], options: { ttl: 100, }, }, }, }, redis: { clients: { default: { port: 6379, host: '127.0.0.1', }, }, }, }; ``` 这样 `multiCaching` 这个缓存实例就包含了两级缓存,缓存的优先级从上到下,在查找时,会先查找 `memoryCaching` ,如果内存缓存不存在 key,则继续查找 `redisCaching`。 ### 7、使用多级缓存[​](#7使用多级缓存 "7、使用多级缓存的直接链接") 和普通缓存类似,多级缓存除了 `set`、`get`、`del`方法外,还增加了 `mset` 、`mget`、`mdel` 方法。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayMultiCache } from '@midwayjs/cache-manager'; const userId2 = 456; const key2 = 'user_' + userId; const ttl = 5; @Provide() export class UserService { @InjectClient(CachingFactory, 'multiCaching') multiCache: MidwayMultiCache; async invoke() { // 设置到所有级别的缓存 await this.multiCache.set('foo2', 'bar2', ttl); // 从最高优先级的缓存 Store 中获取 key console.log(await this.multiCache.get('foo2')); // >> "bar2" // 调用每一个 Store 的 del 方法进行删除 await this.multiCache.del('foo2'); // 在所有缓存中设置多个 key,可以多个键值对 await this.multiCache.mset( [ ['foo', 'bar'], ['foo2', 'bar2'], ], ttl ); // mget() 从最高优先级的缓存中获取值 // 如果第一个缓存 Store 中不包含所有的 key, // 继续在下一个缓存 Store 中查找没有找到的 key。 // 这是递归地完成的,直到: // - 所有的 key 都已经查找到值 // - 所有的缓存 Store 都被查找过 console.log(await this.multiCache.mget('key', 'key2')); // >> ['bar', 'bar2'] // 调用每一个 Store 的 mdel 方法进行删除 await this.multiCache.mdel('foo', 'foo2'); } } ``` ### 8、自动刷新[​](#8自动刷新 "8、自动刷新的直接链接") 不管是普通缓存还是多级缓存,都支持后台刷新功能,只需要配置 `refreshThreshold` 的时间,单位为毫秒。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', options: { refreshThreshold: 3 * 1000, }, }, }, } } ``` 如果设置了 `refreshthreshold`,每次从缓存获取值之后,会检查 `ttl` 的值,如果剩余的 `ttl` 小于 `refreshthreshold` ,则系统将异步更新缓存,同时系统会返回旧值,直到 `ttl` 过期。 提示 * 在多级缓存的情况下,根据优先级顺序找到第一个包含 key 的 Store。 * 如果阈值较低且执行的函数比较慢,key 可能会过期,有可能会遇到并发更新的情况。 * 后台刷新机制目前只支持单个 key。 * 如果没有为 key 设置 `ttl`,则不会触发刷新机制。对于 redis,`ttl` 默认设置为-1。 ## 自动缓存[​](#自动缓存 "自动缓存的直接链接") ### 使用装饰器缓存方法[​](#使用装饰器缓存方法 "使用装饰器缓存方法的直接链接") 可以通过 `@Caching` 装饰器缓存方法的结果,比如缓存 http 响应或者服务调用的结果。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default') async getUser(name: string) { return name; } } ``` 当第一次调用 `getUser` 方法时,会正常执行逻辑,返回结果,装饰器会将结果缓存起来,第二次执行时,如果缓存未失效,则会从缓存中直接返回。 ### 指定缓存的 ttl[​](#指定缓存的-ttl "指定缓存的 ttl的直接链接") 也可以单独设置 `ttl` 。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default', 100) async getUser(name: string) { return name; } } ``` ### 手动指定缓存 key[​](#手动指定缓存-key "手动指定缓存 key的直接链接") 如果对自动生成的 key 不满意,可以手动指定缓存的 key。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default', 'customKey', 100) async getUser(name: string) { return name; } } ``` ### 带逻辑的缓存[​](#带逻辑的缓存 "带逻辑的缓存的直接链接") 如果你希望根据一些特定逻辑进行缓存,比如特定参数,或者特定的 Header,可以传递一个工具函数进行逻辑判断。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; function cacheBy({methodArgs, ctx, target}) { if (methodArgs[0] === 'harry' || methodArgs[0] === 'mike') { return 'cache1'; } } @Provide() export class UserService { @Caching('default', cacheBy, 100) async getUser(name: string) { return 'hello ' + name; } } ``` 上面的示例中,`cacheBy` 方法自定义了缓存的逻辑,当方法入参值为 `harry` 或者 `mike` 时,将返回缓存的 `key` ,而其他参数时则跳过缓存。 这个时候执行的结果为: ``` await userService.getUser('harry')); // hello harry await userService.getUser('mike')); // hello harry await userService.getUser('lucy')); // hello lucy ``` `@Caching` 装饰器可以在第二个参数中传递一个方法,这个方法的入参 options 为: * `methodArgs` 当前调用方法的实际参数 * `ctx` 如果是请求作用域,则是当前调用的上下文对象,如果是单例,则该对象为空对象 * `target` 当前调用的实例 方法的返回值为字符串或者布尔值,当返回字符串时,表示以该 key 将方法的结果缓存,当返回 `undefined` 或者 `null` 时,表示跳过缓存。 通过这些参数判断,我们可以实现非常灵活的自定义缓存逻辑。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、多进程下内存缓存 set 和 get 无法得到相同值[​](#1多进程下内存缓存-set-和-get-无法得到相同值 "1、多进程下内存缓存 set 和 get 无法得到相同值的直接链接") 这是正常现象,每个进程的数据是独立的,仅保存在当前进程中。如需跨进程缓存,请使用 Redis 这类分布式缓存系统。 --- # 验证码 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用验证码组件,支持 `图片验证码`、`计算表达式` 等类型验证码。 您也可以通过此组件,来实现 `短信验证码`、`邮件验证码` 等验证能力,但是注意,本组件本身不含发送短信、邮件功能。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/captcha@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/captcha": "^3.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件。 ``` import * as captcha from '@midwayjs/captcha'; @Configuration({ imports: [ // ...other components captcha ], }) export class MainConfiguration {} ``` ## 调用服务[​](#调用服务 "调用服务的直接链接") ``` import { Controller, Inject } from '@midwayjs/core'; import { CaptchaService } from '@midwayjs/captcha'; @Controller('/') export class HomeController { @Inject() ctx; @Inject() captchaService: CaptchaService; // 示例:获取图像验证码 @Get('/get-image-captcha') async getImageCaptcha() { const { id, imageBase64 } = await this.captchaService.image({ width: 120, height: 40 }); return { id, // 验证码 id imageBase64, // 验证码 SVG 图片的 base64 数据,可以直接放入前端的 img 标签内 } } // 示例:获取计算表达式验证码 @Get('/get-formula-captcha') async getFormulaCaptcha() { const { id, imageBase64 } = await this.captchaService.formula({ noise: 1 }); return { id, // 验证码 id imageBase64, // 验证码 SVG 图片的 base64 数据,可以直接放入前端的 img 标签内 } } // 验证验证码是否正确 @Post('/check-captcha') async getCaptcha() { const { id, answer } = this.ctx.request.body; const passed: boolean = await this.captchaService.check(id, answer); if (passed) { return 'passed'; } return 'error'; } // 示例:短信验证码 @Post('/sms-code') async sendSMSCode() { // 验证验证码是否正确 const { id, text: code } = await this.captchaService.text({ size: 4 }); await sendSMS(18888888888, code); return { id } } // 示例:邮件验证码 @Post('/email-code') async sendEmailCode() { // 验证验证码是否正确 const { id, text: code } = await this.captchaService.text({ type: 'number'}); await sendEmail('admin@example.com', code); return { id } } // 示例:将任意文本内容塞入验证码中 @Get('/test-text') async testText() { // 存入内容,获取验证码id const id: string = await this.captchaService.set('123abc'); // 根据验证码id,校验内容是否正确 const passed: boolean = await this.captchaService.check(id, '123abc'); return { passed: passed === true, } } } ``` ## 可用配置[​](#可用配置 "可用配置的直接链接") ``` interface CaptchaOptions { default?: { // 默认配置 // 验证码字符长度,默认 4 个字符 size?: number; // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; // 图形验证码配置,图形中包含一些字符 }, image?: { // 验证码字符长度,默认 4 个字符 size?: number; // 图像验证码中的字符类型,默认为 'mixed' // - 'mixed' 表示 0-9、A-Z 和 a-z // - 'letter' 表示 A-Z 和 a-z // - 'number' 表示 0-9 type?: 'mixed', // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; }, // 计算公式验证码配置,例如返回的图像内容为 1+2,需要用户填入 3 formula?: { // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; }, // 纯文本验证码配置,基于纯文本验证码可以实现短信验证码、邮件验证码 text?: { // 验证码字符长度,默认 4 个字符 size?: number; // 文本验证码中的字符类型,默认为 'mixed' // - 'mixed' 表示 0-9、A-Z 和 a-z // - 'letter' 表示 A-Z 和 a-z // - 'number' 表示 0-9 type?: 'mixed', }, // 验证码过期时间,默认为 1h expirationTime?: 3600, // 验证码存储的 key 前缀 idPrefix: 'midway:vc', } export const captcha: CaptchaOptions = { default: { // 默认配置 size: 4, noise: 1, width: 120, height: 40, }, image: { // 最终会合并 default 配置 type: 'mixed', }, formula: {}, // 最终会合并 default 配置 text: {}, // 最终会合并 default 配置 expirationTime: 3600, idPrefix: 'midway:vc', } ``` 更多配置请参考 [svg-captcha](https://github.com/produck/svg-captcha)。 ### 配置示例一[​](#配置示例一 "配置示例一的直接链接") 获取一个 包含 `5个纯英文字母` 的图像验证码,图像宽度 `200` 像素,高度 `50` 像素,并且包含 `3` 条干扰线。 因为图像验证码的配置 `image`, 会与 `default` 配置进行合并,所以可以只修改 `default` 配置: ``` export const captcha: CaptchaOptions = { default: { size: 5, noise: 3, width: 200, height: 50 }, image: { type: 'letter' } } ``` 当然,也可以 `不` 修改 `default` 配置,将宽度、高度等在 `image` 配置项中进行配置,取得 `同样`的效果: ``` export const captcha: CaptchaOptions = { image: { size: 5, noise: 3, width: 200, height: 50 type: 'letter' } } ``` ### 配置示例二[​](#配置示例二 "配置示例二的直接链接") 获取一个图像宽度 `100` 像素,高度 `60` 像素,并且包含 `2` 条干扰线的计算表达式验证码。 因为计算表达式验证码的配置 `formula` ,会与 `default` 配置合并,所以可以只修改 `default` 配置: ``` export const captcha: CaptchaOptions = { default: { noise: 2, width: 100, height: 60 }, } ``` 当然,也可以 `不` 修改 `default` 配置,将宽度、高度等在 `formula` 配置项中进行配置,取得 `同样`的效果: ``` export const captcha: CaptchaOptions = { formula: { noise: 2, width: 100, height: 60 } } ``` ## 组件依赖[​](#组件依赖 "组件依赖的直接链接") 验证码的内容存储基于 `@midwayjs/cache-manager` 组件,默认创建了一个名为 `captcha` 的缓存实例,将数据存储在 `memory` 中。 ``` export default { cacheManager: { clients: { captcha: { store: 'memory', }, }, }, }; ``` 如果要替换为 `redis` 或其他服务,请参照 `@midwayjs/cache-manager` 的 [文档](/docs/extensions/caching.md),对 cache 进行配置。 ## 效果[​](#效果 "效果的直接链接") **图片验证码** ![图片验证码](https://gw.alicdn.com/imgextra/i4/O1CN014cEzLH23vEniOgoyp_!!6000000007317-2-tps-120-40.png) **计算表达式** ![计算表达式](https://gw.alicdn.com/imgextra/i4/O1CN01u3Mj0q24lRx1md9pX_!!6000000007431-2-tps-120-40.png) ## 注意[​](#注意 "注意的直接链接") * 为了防止机器学习破解,使用的 `svg-captcha` 包为 [安全修复后](https://juejin.cn/post/6872656117839691789) 的版本。 --- # 角色鉴权 Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。 官网文档: ## Casbin 是什么[​](#casbin-是什么 "Casbin 是什么的直接链接") Casbin 可以: 1. 支持自定义请求的格式,默认的请求格式为`{subject, object, action}`。 2. 具有访问控制模型model和策略policy两个核心概念。 3. 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。 4. 支持内置的超级用户 例如:`root` 或 `administrator`。超级用户可以执行任何操作而无需显式的权限声明。 5. 支持多种内置的操作符,如 `keyMatch`,方便对路径式的资源进行管理,如 `/foo/bar` 可以映射到 `/foo*` Casbin 不能: 1. 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。 2. 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。 提示 注意: * 1、在 Midway v3.6.0 之后可用 * 2、Midway 只是封装了 Casbin 的 API 并提供简单的支持,策略规则编写请查看 [官方文档](https://casbin.org/) * 3、Casbin 不提供登录,只提供现有用户的鉴权,需要搭配 passport 等获取用户信息的组件来使用 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/casbin@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/casbin": "^3.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path' @Configuration({ imports: [ // ... casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 准备模型和策略[​](#准备模型和策略 "准备模型和策略的直接链接") 使用 Casbin 前需要定义模型和策略,这两个文件的内容贯穿本文,建议先去官网了解相关内容。 我们以一个基础的模型为例,比如: ``` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ g2 = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act || r.sub == "root" ``` 将其保存在项目根目录的 `basic_model.conf` 文件中。 以及包含下面内容的策略文件。 ``` p, superuser, user, read:any p, manager, user_roles, read:any p, guest, user, read:own g, alice, superuser g, bob, guest g, tom, manager g2, users_list, user g2, user_roles, user g2, user_permissions, user g2, roles_list, role g2, role_permissions, role ``` 将其保存在项目根目录的 `basic_policy.csv` 文件中。 ## 配置模型和策略[​](#配置模型和策略 "配置模型和策略的直接链接") 这里我们的策略将以文件形式进行演示。 配置如下: ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; export default (appInfo: MidwayAppInfo) => { return { // ... casbin: { modelPath: join(appInfo.appDir, 'basic_model.conf'), policyAdapter: join(appInfo.appDir, 'basic_policy.csv'), } }; } ``` ## 装饰器鉴权[​](#装饰器鉴权 "装饰器鉴权的直接链接") 有多种形式来使用 Casbin,这里以装饰器作为示例。 ### 定义资源[​](#定义资源 "定义资源的直接链接") 首先定义资源,比如放在 `src/resource.ts` 文件中,对应策略文件中对应的资源。 ``` export enum Resource { USERS_LIST = 'users_list', USER_ROLES = 'user_roles', USER_PERMISSIONS = 'user_permissions', ROLES_LIST = 'roles_list', ROLE_PERMISSIONS = 'role_permission', } ``` ### 配置获取用户的方式[​](#配置获取用户的方式 "配置获取用户的方式的直接链接") 在使用装饰器鉴权时,我们需要配置一个获取用户的方式,比如在 passport 组件之后,我们会从 `ctx.user` 上获取用户名。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; export default (appInfo: MidwayAppInfo) => { return { // ... casbin: { modelPath: join(appInfo.appDir, 'basic_model.conf'), policyAdapter: join(appInfo.appDir, 'basic_policy.csv'), usernameFromContext: (ctx) => { return ctx.user; } } }; } ``` ### 增加守卫[​](#增加守卫 "增加守卫的直接链接") 装饰器鉴权依赖守卫,我们可以在全局或者某些路由上开启,全局守卫使用请参考守卫章节。 比如,我们只在下面的 `findAllUsers` 方法上开启鉴权,`AuthGuard` 是 `@midwayjs/casbin` 提供的守卫,可以直接使用。 ``` import { Controller, Get, UseGuard } from '@midwayjs/core'; import { AuthGuard } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @Get('/users') async findAllUsers() { // ... } } ``` ### 定义权限[​](#定义权限 "定义权限的直接链接") 使用 `UsePermission` 装饰器定义路由需要的权限。 ``` import { Controller, Get, UseGuard } from '@midwayjs/core'; import { AuthActionVerb, AuthGuard, AuthPossession, UsePermission } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @UsePermission({ action: AuthActionVerb.READ, resource: Resource.USER_ROLES, possession: AuthPossession.ANY }) @Get('/users') async findAllUsers() { // ... } } ``` 没有权限读取 `USER_ROLES` 的用户不能调用 findAllUsers 方法,在请求时会返回 403 状态码。 比如,上面的 `bob` 用户访问则会返回 403, 而 `tom` 用户访问则正常返回。 `UsePermission` 需要提供一个对象参数,包括 `action`、`resource`、`possession` 和一个可选的 `isOwn` 的对象。 * `action` 是一个 `AuthActionVerb` 枚举,包含读,写等操作 * `resource` 资源字符串 * `possession` 是一个 `AuthPossession` 枚举 * `isOwn` 是一个接受`Context`(守卫 `canActivate`的参数)作为唯一参数并返回布尔值的函数。 `AuthZGuard` 使用它来确定用户是否是资源的所有者。 如果未定义,将使用返回 `false` 的默认函数。 可以同时定义多个权限,但只有当所有权限都满足时,才能访问该路由。 比如: ``` @UsePermissions({ action: AuthActionVerb.READ, resource: 'USER_ADDRESS', possession: AuthPossession.ANY }, { action; AuthActionVerb.READ, resource: 'USER_ROLES, possession: AuthPossession.ANY }) ``` 只有当用户被授予读取 `USER_ADDRESS` 和 `USER_ROLES` 这两个权限时,才能访问该路由。 ## API 鉴权[​](#api-鉴权 "API 鉴权的直接链接") Casbin 本身提供了一些通用的 API 和权限相关的功能。 我们可以通过直接注入 `CasbinEnforcerService` 服务来使用。 比如,我们可以在守卫或者中间件中编码。 ``` import { CasbinEnforcerService } from '@midwayjs/casbin'; import { Guard, IGuard } from '@midwayjs/core'; @Guard() export class UserGuard extends IGuard { @Inject() casbinEnforcerService: CasbinEnforcerService; async canActivate(ctx, clz, methodName) { // 用户登录了,并且是特定的方法,则检查权限 if (ctx.user && methodName === 'findAllUsers') { return await this.casbinEnforcerService.enforce(ctx.user, 'USER_ROLES', 'read'); } // 未登录用户不允许访问 return false; } } ``` 在启用守卫后,效果和上面的装饰器相同。 此外,`CasbinEnforcerService` 还有更多的 API,比如重新加载策略。 ``` await this.casbinEnforcerService.loadPolicy(); ``` ## 分布式策略存储[​](#分布式策略存储 "分布式策略存储的直接链接") 在多台机器部署的场景下,需要将策略存储到外部。 当前已经实现的适配器有: * Redis * Typeorm ### Redis Adapter[​](#redis-adapter "Redis Adapter的直接链接") 需要依赖 `@midwayjs/casbin-redis-adapter` 包和 redis 组件。 ``` $ npm i @midwayjs/casbin-redis-adapter @midwayjs/redis --save ``` 启用 redis 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... redis, casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 配置 redis 连接和 casbin 适配器。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { createAdapter } from '@midwayjs/casbin-redis-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... redis: { clients: { // 为 casbin 定义了一个连接 'node-casbin-official': { host: '127.0.0.1', port: 6379, password: '', db: '0', } } }, casbin: { policyAdapter: createAdapter({ // 配置了上面的连接名 clientName: 'node-casbin-official' }), // ... }, }; } ``` ### TypeORM Adapter[​](#typeorm-adapter "TypeORM Adapter的直接链接") 需要依赖 `@midwayjs/casbin-typeorm-adapter` 包和 typeorm 组件。 ``` $ npm i @midwayjs/casbin-typeorm-adapter @midwayjs/typeorm --save ``` 启用 typeorm 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as typeorm from '@midwayjs/typeorm'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... typeorm, casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 配置适配器,下面以 sqlite 存储为例,mysql 的配置可以查看 typeorm 组件。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { CasbinRule, createAdapter } from '@midwayjs/casbin-typeorm-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... typeorm: { dataSource: { // 为 casbin 定义了一个连接 'node-casbin-official': { type: 'sqlite', synchronize: true, database: join(appInfo.appDir, 'casbin.sqlite'), // 注意这里显式引入了 Entity entities: [CasbinRule], } } }, casbin: { policyAdapter: createAdapter({ // 配置了上面的连接名 dataSourceName: 'node-casbin-official' }), // ... } }; } ``` ## 监视器[​](#监视器 "监视器的直接链接") 使用分布式消息系统,例如 [etcd](https://github.com/coreos/etcd) 来保持多个Casbin执行器实例之间的一致性。 因此,我们的用户可以同时使用多个Casbin 执行器来处理大量的权限检查请求。 Midway 当前只提供一种 Redis 更新策略,如有其他需求,可以给我们提交 issue。 ### Redis Watcher[​](#redis-watcher "Redis Watcher的直接链接") 需要依赖 `@midwayjs/casbin-redis-adapter` 包和 redis 组件。 ``` $ npm i @midwayjs/casbin-redis-adapter @midwayjs/redis --save ``` 启用 redis 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... redis, casbin, ], // ... }) export class MainConfiguration { } ``` 使用示例: ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { createAdapter, createWatcher } from '@midwayjs/casbin-redis-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... redis: { clients: { 'node-casbin-official': { host: '127.0.0.1', port: 6379, db: '0', }, 'node-casbin-sub': { host: '127.0.0.1', port: 6379, db: '0', } } }, casbin: { // ... policyAdapter: createAdapter({ clientName: 'node-casbin-official' }), policyWatcher: createWatcher({ pubClientName: 'node-casbin-official', subClientName: 'node-casbin-sub', }) }, }; } ``` 注意,pub/sub 连接需要不同的客户端,上面代码定义了两个客户端。 pub 客户端可以和普通 Redis 客户端连接复用,而 sub 需要一个独立的客户端。 --- # cfork 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 文档在此: 由于 bootstrap.js 的特性,有时候不是很适合 pm2 来部署(比如集团内部,全局不安装,需要 API 启动)。 我们可以新增一个 `server.js` 用来做主进程的入口,将 `bootstrap.js` 作为每个子进程的启动入口。 ``` // server.js 'use strict'; const cfork = require('cfork'); const util = require('util'); const path = require('path'); const os = require('os'); // 获取 cpu 核数 const cpuNumbers = os.cpus().length; cfork({ exec: path.join(__dirname, './bootstrap.js'), count: cpuNumbers, }) .on('fork', (worker) => { console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid); }) .on('disconnect', (worker) => { console.warn( '[%s] [master:%s] wroker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state ); }) .on('exit', (worker, code, signal) => { const exitCode = worker.process.exitCode; const err = new Error( util.format( 'worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)', worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state ) ); err.name = 'WorkerDiedError'; console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack); }); ``` 最后启动 `node server.js` 即可。 --- # 代码染色 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的代码染色组件。 用于在 HTTP 场景展示调用链路耗时与各个方法的出入参,帮你更快地定位代码问题。 比如: * 代码执行缓慢 * 不知道是哪一个方法执行的慢:通过代码染色后,可以查看每一个 `方法的执行时长`。 * 代码执行错误 * 可能是方法没有调到:通过代码染色后,可以查看每一个 `方法的调用链`。 * 可能是方法调用参数出错:通过代码染色后,查看每一个`方法的入参和返回值` 使用效果: ![](https://gw.alicdn.com/imgextra/i1/O1CN017Zd6y628M2PvqJO7I_!!6000000007917-2-tps-2392-844.png) 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/code-dye@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/code-dye": "^3.0.0" // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 将 code-dye 组件配置到代码中。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as codeDye from '@midwayjs/code-dye'; @Configuration({ imports: [ // ... { component: codeDye, enabledEnvironment: ['local'], // 只在本地启用 } ], }) export class MainConfiguration {} ``` 提示 * 可以在 `本地` 或 `研发` 环境开启本组件,便于开发时定位问题,但是 `不建议` 在线上启用,会对线上访问性能产生影响。 ## 配置染色[​](#配置染色 "配置染色的直接链接") 可以通过`matchQueryKey` 配置,控制当 `query` 参数包含`matchQueryKey` 配置对应的值的时候,进入染色链路,例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchQueryKey: 'codeDyeABC', } } ``` 当请求接口 `http://127.0.0.1:7001/test?codeDyeABC=html` 时,就会判断 `query` 中是否存在 `codeDyeABC` 参数来决定是否染色,并根据参数对应的值,来响应不同的染色结果。 也可以通过`matchHeaderKey` 配置,控制当 `headers` 参数包含 `matchHeaderKey` 配置对应的值的时候,进入染色链路,例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchHeaderKey: 'codeDyeHeader', } } ``` 当请求接口 `http://127.0.0.1:7001/test` 时,就会判断请求的 `headers` 中是否存在 `codeDyeHeader` 参数来决定是否染色,并根据参数对应的值,来响应不同的染色结果。 ## 染色报告[​](#染色报告 "染色报告的直接链接") 开启了代码染色后,链路染色的结果,可以通过开启染色的不同参数值来配置,目前支持以下三种: * `html`:`对` 当前请求的结果进行处理,将染色信息添加到结果中,响应为 `html`,可以在浏览器上查看,效果可以查看此文档上面的图片效果展示。 * `json`:`对` 当前请求的结果进行处理,将染色信息添加到结果中,响应为 `json` 结构化信息。 * `log`:`不对` 当前请求的结果进行处理,染色的信息将会输出到日志中,不影响请求。 例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchQueryKey: 'codeDyeXXX', } } ``` 当请求接口 `http://127.0.0.1:7001/test?codeDyeXXX=html` 时,就会判断 `query` 中 `codeDyeXXX` 参数的值为 `html`,就将染色结果输出在当前请求的响应中,并且内容为 `html` 格式。 --- # Consul consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 本文介绍了如何用 consul 作为 midway 的服务注册发现中心,以及如何使用 consul来做软负载的功能。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | 感谢 [boostbob](https://github.com/boostbob) 提供的组件。 效果如下图: ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01e5cFZx1I0draeZynr_!!6000000000831-2-tps-1500-471.png) ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01iLYF8r1HQ0B3b47Fh_!!6000000000751-2-tps-1500-895.png) ## 安装组件[​](#安装组件 "安装组件的直接链接") 首先安装 consul 组件和类型: ``` $ npm i @midwayjs/consul@3 --save $ npm i @types/consul --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/consul": "^3.0.0", // ... }, "devDependencies": { "@types/consul": "^0.40.0", // ... } } ``` ## 目前支持的能力[​](#目前支持的能力 "目前支持的能力的直接链接") * 注册能力(可选) * 在停止服务的时候反注册(可选) * 服务选择(随机) * 暴露原始的 consul 对象 ## 启用组件[​](#启用组件 "启用组件的直接链接") ``` import * as consul from '@midwayjs/consul' @Configuration({ imports: [ // .. consul ], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration {} ``` ## 配置[​](#配置 "配置的直接链接") 配置 `config.default.ts` 文件: ``` // src/config/config.default export default { // ... consul: { provider: { // 注册本服务 register: true, // 应用正常下线反注册 deregister: true, // consul server 服务地址 host: '192.168.0.10', // consul server 服务端口 port: '8500', // 调用服务的策略(默认选取 random 具有随机性) strategy: 'random', }, service: { // 此处是当前这个 midway 应用的地址 address: '127.0.0.1', // 当前 midway 应用的端口 port: 7001, // 做泳道隔离等使用 tags: ['tag1', 'tag2'], name: 'my-midway-project' // others consul service definition } }, } ``` 打开我们 consul server 的 ui 地址,效果如下: ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01QI7A1d1dU3ECG8QxQ_!!6000000003738-2-tps-1500-471.png) 可以观察到 my-midway-project 项目已经注册完毕。 假如停止我们的 midway 项目。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01EDocUO1TIvRvpxXbw_!!6000000002360-2-tps-1500-401.png) 我们可以看到我们项目的状态就变为红色。 我们演示多台的情况,如下表现:(1台在线+1台不在线) ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01kfmul91eSxu5EiJE3_!!6000000003871-2-tps-1500-405.png) ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01PZrdpp21Sir5n3y9I_!!6000000006984-2-tps-1500-360.png) ## 作为客户端[​](#作为客户端 "作为客户端的直接链接") 例如我们作为客户端 A,需要调用服务 B 的接口,然后我们首先是查出 B 健康的服务,然后进行 http 请求。 此处为了方便理解,我们模拟查询刚刚注册的成功的服务: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/core'; import { BalancerService } from '@midwayjs/consul' @Provide() @Controller('/') export class HomeController { @Inject() balancerService: BalancerService; @Get('/') async home() { const service = await this.balancerService.getServiceBalancer().select('my-midway-project'); // output console.log(service) // ... } } ``` 输出的 service 的内容为: ``` { ID: 'c434e36b-1b62-c4e1-c4ec-76c5d3742ff8', Node: '1b2d5b8771cb', Address: '127.0.0.1', Datacenter: 'dc1', TaggedAddresses: { lan: '127.0.0.1', lan_ipv4: '127.0.0.1', wan: '127.0.0.1', wan_ipv4: '127.0.0.1' }, NodeMeta: { 'consul-network-segment': '' }, ServiceKind: '', ServiceID: 'my-midway-project:xxx:7001', ServiceName: 'my-midway-project', ServiceTags: [ 'tag1', 'tag2' ], ServiceAddress: 'xxxxx', ServiceTaggedAddresses: { lan_ipv4: { Address: 'xxxxx', Port: 7001 }, wan_ipv4: { Address: 'xxxxxx', Port: 7001 } }, ServiceWeights: { Passing: 1, Warning: 1 }, ServiceMeta: {}, ServicePort: 7001, ServiceEnableTagOverride: false, ServiceProxy: { MeshGateway: {}, Expose: {} }, ServiceConnect: {}, CreateIndex: 14, ModifyIndex: 14 } ``` 此时,我们只要通过 Address 和 ServicePort 去连接服务 B,比如做 http 请求。 如果需要查询不健康的,则 `select` 方法的第二个参数传入 false 值: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/core'; import { BalancerService } from '@midwayjs/consul' @Provide() @Controller('/') export class HomeController { @Inject() balancerService: BalancerService; @Get('/') async home() { const service = await this.balancerService .getServiceBalancer() .select('my-midway-project', false); console.log(service); // ... } } ``` ## 配置中心[​](#配置中心 "配置中心的直接链接") 同时 consul 也能作为一个服务配置的地方,如下代码: ``` import { Controller, Get, Inject } from '@midwayjs/core'; import * as Consul from 'consul'; @Controller('/') export class HomeController { @Inject('consul:consul') consul: Consul.Consul; @Get('/') async home() { await this.consul.kv.set(`name`, `juhai`) // let res = await this.consul.kv.get(`name`); // console.log(res); return 'Hello Midwayjs!'; } } ``` 我们调用 `kv.set` 方法,我们可以设置对应的配置,通过 `kv.get` 方法可以拿到对应的配置。 注意:在代码中,有同学出现,在每次请求中去 get 对应的配置,这时你的 QPS 多少对 Consul server 的压力。 所以在QPS比较大的情况,可以如下处理: ``` import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import * as Consul from 'consul'; @Provide() @Scope(ScopeEnum.Singleton) export class ConfigService { @Inject('consul:consul') consul: Consul.Consul; config: any; @Init() async init() { setInterval(()=>{ this.consul.kv.get(`name`).then(res=>{ this.config = res; }) }, 5000); this.config = await this.consul.kv.get(`name`); } async getConfig(){ return this.config; } } ``` 上面的代码,相当于定时去获取对应的配置,当每个请求进来的时候,获取 Scope 为 ScopeEnum.Singleton 服务的 `getConfig` 方法,这样每 5s 一次获取请求,就减少了对服务的压力。 Consul 界面上如下图: ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01V3P6uK1rIVs19JiWn_!!6000000005608-2-tps-1500-374.png) ![image.png](https://img.alicdn.com/imgextra/i2/O1CN014O2GyH1sMvIhmlbs4_!!6000000005753-2-tps-1500-667.png) 一共提供如下几种方法: * [get](https://www.npmjs.com/package/consul#kv-get),获取对应key的value * [keys](https://www.npmjs.com/package/consul#kv-keys),查询某个prefix的key的列表 * [set](https://www.npmjs.com/package/consul#kv-set),设置对应的key的值 * [del](https://www.npmjs.com/package/consul#kv-del),删除对应的key ## 其他说明[​](#其他说明 "其他说明的直接链接") 这样的好处,就是 A->B,B 也可以进行扩展,并且可以通过 tags 做泳道隔离。例如做单元隔离等。并且可以通过 ServiceWeights 做对应的权重控制。 Consul 还能做 Key/Value 的配置中心的作用,这个后续我们考虑支持。 ## 搭建 Consul 测试服务[​](#搭建-consul-测试服务 "搭建 Consul 测试服务的直接链接") 下面描述了单机版本的 consul 搭建流程。 ``` docker run -itd -P consul ``` 然后执行 `docker ps` ``` ➜ my_consul_app docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1b2d5b8771cb consul "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 0.0.0.0:32782->8300/tcp, 0.0.0.0:32776->8301/udp, 0.0.0.0:32781->8301/tcp, 0.0.0.0:32775->8302/udp, 0.0.0.0:32780->8302/tcp, 0.0.0.0:32779->8500/tcp, 0.0.0.0:32774->8600/udp, 0.0.0.0:32778->8600/tcp cocky_wing ``` 然后我们打开 8500 所对应的端口:(上图比如我的对应端口是 32779) [http://127.0.0.1:32779/ui/](http://127.0.0.1:32779/ui/dc1/kv) 打开后效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN014O2GyH1sMvIhmlbs4_!!6000000005753-2-tps-1500-667.png) 然后我们的 `config.default.ts` 中的port就是 32779 端口。 ## 下线服务[​](#下线服务 "下线服务的直接链接") 如果想要手动将consul界面上不需要的服务给下线掉,可以通过下面的方法: ``` import { Controller, Get, Inject, Provide } from '@midwayjs/core'; import * as Consul from 'consul' @Provide() @Controller('/') export class HomeController { @Inject('consul:consul') consul: Consul.Consul; @Get("/222") async home2(){ let res = await this.consul.agent.service.deregister(`my-midway-project:30.10.72.195:7002`); console.log(res); // ... } } ``` `deregister` 方法,对应 consul 界面上的名字。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01d5QMUJ1DULTKPSJsr_!!6000000000219-2-tps-1500-465.png) --- # 腾讯云对象存储(COS) 本文介绍了如何使用 midway 接入腾讯云 COS。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/cos@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cos": "^3.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as cos from '@midwayjs/cos'; import { join } from 'path' @Configuration({ imports: [ // ... cos // 导入 cos 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` // src/config/config.default export default { // ... cos: { client: { SecretId: '***********', SecretKey: '***********', }, }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default export default { // ... cos: { clients: { instance1: { SecretId: '***********', SecretKey: '***********', }, instance2: { SecretId: '***********', SecretKey: '***********', }, }, }, } ``` 更多参数可以查看 [cos-nodejs-sdk-v5](https://github.com/tencentyun/cos-nodejs-sdk-v5) 文档。 ## 使用 COS 服务[​](#使用-cos-服务 "使用 COS 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { COSService } from '@midwayjs/cos'; @Provide() export class UserService { @Inject() cosService: COSService; async invoke() { await this.cosService.sliceUploadFile({ Bucket: 'test-1250000000', Region: 'ap-guangzhou', Key: '1.zip', FilePath: './1.zip' }, } } ``` 可以使用 `COSServiceFactory` 获取不同的实例。 ``` import { COSServiceFactory } from '@midwayjs/cos'; import { join } from 'path'; @Provide() export class UserService { @Inject() cosServiceFactory: COSServiceFactory; async save() { const cos1 = await this.cosServiceFactory.get('instance1'); const cos2 = await this.cosServiceFactory.get('instance3'); //... } } ``` --- # 本地任务 和 bull 组件不同,cron 组件提供的是本地任务能力,即在每台机器的每个进程都会执行。如需不同机器或者不同进程之间只执行一次任务,请使用 [bull 组件](/docs/3.0.0/extensions/bull.md) 。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/cron@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cron": "^3.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; @Configuration({ imports: [ // ... cron ] }) export class MainConfiguration { //... } ``` ## 编写任务处理类[​](#编写任务处理类 "编写任务处理类的直接链接") 使用 `@Job` 装饰器装饰一个类,用于快速定义一个任务处理器。 比如,在 `src/job` 目录中创建一个 `sync.job.ts`,用于某些数据同步任务,代码如下: ``` // src/job/sync.job.ts import { Job, IJob } from '@midwayjs/cron'; import { FORMAT } from '@midwayjs/core'; @Job({ cronTime: FORMAT.CRONTAB.EVERY_PER_30_MINUTE, start: true, }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } } ``` `@Job` 装饰器用于修饰一个任务类,在初始化时,框架会自动将其转变为一个任务。 任务类需要实现 `IJob` 接口,实现 `onTick` 方法,每当任务触发时,会自动调用 `onTick` 方法。 此外,还有一个可选的 `onComplete` 方法,用于在 `onTick` 完成后执行。 ``` @Job({ cronTime: FORMAT.CRONTAB.EVERY_PER_30_MINUTE, start: true, }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } async onComplete() { // 记录一些数据等等,用处不是很大 } } ``` `@Job` 装饰器的常用参数如下: | 参数 | 类型 | 描述 | | --------- | ------- | ---------------------- | | cronTime | string | crontab 表达式 | | start | boolean | 是否自动启动任务 | | runOnInit | boolean | 是否在初始化就执行一次 | 更多参数,请参考 [Cron](https://github.com/kelektiv/node-cron)。 ## 任务管理[​](#任务管理 "任务管理的直接链接") 除了定时执行任务,我们还通过框架提供的 API,对任务进行手动管理。 比如,下面的代码仅仅定义了一个任务,但是不会启动执行。 ``` @Job('syncJob', { cronTime: '*/2 * * * * *', // 每隔 2s 执行 }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } } ``` 我们定义了一个名为 `syncJob` 的任务,并且给它了一个默认的调度时间。 ### 获取任务对象[​](#获取任务对象 "获取任务对象的直接链接") 我们可以通过两种方式获取任务对象。 通过`@InjectJob` 用来注入某个任务,参数为类本身或者任务名。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @InjectJob(DataSyncCheckerJob) syncJob: CronJob; @InjectJob('syncJob') syncJob2: CronJob; async onServerReady() { // this.syncJob === this.syncJob2 } } ``` 通过 Framework API 获取。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @Inject() cronFramework: cron.Framework; async onServerReady() { const syncJob = this.cronFramework.getJob(DataSyncCheckerJob); const syncJob2 = this.cronFramework.getJob('syncJob'); // syncJob === syncJob2 } } ``` 警告 注意,任务对象都必须在 `onServerReady` 生命周期或者启动之后才能获取。 ### 启停任务[​](#启停任务 "启停任务的直接链接") 我们可以在初始化或者某些程序执行完成之后,将这个任务启动。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @InjectJob(DataSyncCheckerJob) syncJob: CronJob; async onServerReady() { this.syncJob.start(); // ... this.syncJob.stop(); } } ``` ## 上下文[​](#上下文 "上下文的直接链接") 任务执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { job: CronJob; } ``` 这里的 `CronJob` 类型来自于 [Cron](https://github.com/kelektiv/node-cron) 包。 ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-cron.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { // ... clients: { // ... cronLogger: { fileLogName: 'midway-cron.log', }, } } } ``` ## 全局配置[​](#全局配置 "全局配置的直接链接") 可以针对 Job 进行一些全局配置,会和每个 Job 的配置进行合并。 ``` export default { cron: { defaultCronJobOptions: { // ... } } } ``` 这里的 `defaultCronJobOptions` 配置项请参考 [CronJobParameters](https://github.com/kelektiv/node-cron/blob/main/lib/job.js#L51) --- # 跨域 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用跨域组件,支持 `cors` 、`jsonp` 多种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/cross-domain --save ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 中引入组件。 ``` import * as crossDomain from '@midwayjs/cross-domain'; @Configuration({ imports: [ // ...other components crossDomain ], }) export class MainConfiguration {} ``` ## 什么是跨域[​](#什么是跨域 "什么是跨域的直接链接") 假设有两个网站: * **A.com**:这是你的网站,你想要从这里访问一些资源。 * **B.com**:这是另一个网站,它拥有你想要访问的资源。 ### 场景设定[​](#场景设定 "场景设定的直接链接") 1. **A.com** 是你的主网站,你在这里运行一些 JavaScript 代码。 2. **B.com** 拥有一些 API 接口,你想要通过 A.com 的 JavaScript 代码来调用这些 API 接口。 由于同源策略,浏览器默认不允许 A.com 的 JavaScript 代码直接访问 B.com 的资源。这是因为浏览器出于安全考虑,防止恶意网站读取其他网站的敏感数据。你想要在 A.com 上运行的 JavaScript 代码中发起一个请求到 B.com 的 API 接口,这个请求会被视为跨域请求。 简单来说,从 A.com 访问 B.com 的接口,就是跨域。 此外,跨域还有一些条件: * 1、同源策略是浏览器安全机制的一部分,所以一般只有浏览器访问才有跨域问题 * 2、当浏览器发起跨域请求时,它会根据当前源自动添加一个 `Origin` 头部到请求中,服务端也会根据 `origin` 头判断来源,进而做处理 所以,当你发现跨域设置不生效时,请检查: * 1、是否真的是跨域请求 * 2、是否真的从浏览器发起 * 3、是否请求带有 `origin` 头 ## 什么是 CORS[​](#什么是-cors "什么是 CORS的直接链接") 在前端代码调用后端服务中经常会碰到下面的错误,这就最为常见的跨域 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 错误。 ``` Access to fetch at 'http://127.0.0.1:7002/' from origin 'http://127.0.0.1:7001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. ``` 出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,`XMLHttpRequest` 和 [Fetch API](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API) 遵循[同源策略](https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy)。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。 CORS 机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 [`XMLHttpRequest`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest) 或 [Fetch](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API))使用 CORS,以降低跨源 HTTP 请求所带来的风险。 ## 常见的 CORS 配置[​](#常见的-cors-配置 "常见的 CORS 配置的直接链接") 下面列举几种跨域的解决方案,我们以 `fetch` 方法为例。 ### 未使用 `credentials`[​](#未使用-credentials "未使用-credentials的直接链接") 客户端。 ``` fetch(url); ``` 服务端配置。 ``` // src/config/config.default.ts export default { // ... cors: { origin: '*', }, } ``` ### 使用 `credentials`[​](#使用-credentials "使用-credentials的直接链接") 客户端。 ``` fetch(url, { credentials: "include", }); ``` 服务端配置 ``` // src/config/config.default.ts export default { // ... cors: { credentials: true, }, } ``` ### 限制 `origin` 来源[​](#限制-origin-来源 "限制-origin-来源的直接链接") 假如我们的网页地址为 `http://127.0.0.1:7001` 而接口为 `http://127.0.0.1:7002`。 客户端。 ``` fetch('http://127.0.0.1:7002/', { credentials: 'include' }) ``` 服务端配置,注意,由于启用了 `credentials`,这个时候 `origin` 字段不能为 `*`。 ``` // src/config/config.default.ts export default { // ... cors: { origin: 'http://127.0.0.1:7001', credentials: true, }, } ``` ## 更多 CORS 配置[​](#更多-cors-配置 "更多 CORS 配置的直接链接") 完整可用配置如下: ``` export const cors = { // 允许跨域的方法,【默认值】为 GET,HEAD,PUT,POST,DELETE,PATCH allowMethods: string |string[]; // 设置 Access-Control-Allow-Origin 的值,【默认值】会获取请求头上的 origin // 也可以配置为一个回调方法,传入的参数为 request,需要返回 origin 值 // 例如:http://test.midwayjs.org // 如果设置了 credentials,则 origin 不能设置为 * origin: string|Function; // 设置 Access-Control-Allow-Headers 的值,【默认值】会获取请求头上的 Access-Control-Request-Headers allowHeaders: string |string[]; // 设置 Access-Control-Expose-Headers 的值 exposeHeaders: string |string[]; // 设置 Access-Control-Allow-Credentials,【默认值】false // 也可以配置为一个回调方法,传入的参数为 request,返回值为 true 或 false credentials: boolean|Function; // 是否在执行报错的时候,把跨域的 header 信息写入到 error 对的 headers 属性中,【默认值】false keepHeadersOnError: boolean; // 设置 Access-Control-Max-Age maxAge: number; } ``` ## JSONP 配置[​](#jsonp-配置 "JSONP 配置的直接链接") 可以在 `src/config/config.default` 中进行 JSONP 配置。 ``` // src/config/config.default.ts export default { // ... jsonp: { callback: 'jsonp', limit: 512, }, } ``` --- # EggJS Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/web@3 egg --save $ npm i @midwayjs/egg-ts-helper --save-dev ``` 针对 EggJS 场景,这些包列举如下。 ``` "dependencies": { "@midwayjs/web": "^3.0.0", "@midwayjs/core": "^3.0.0", "egg": "^2.0.0", "egg-scripts": "^2.10.0" }, "devDependencies": { "@midwayjs/egg-ts-helper": "^1.0.1", }, ``` | @midwayjs/web | **必须**,Midway EggJS 适配层 | | ----------------------- | ------------------------------------------ | | @midwayjs/core | **必须**,Midway 核心包 | | egg | **必须**,EggJS 依赖包,提供定义等其他能力 | | egg-scripts | **可选**,EggJS 启动脚本 | | @midwayjs/egg-ts-helper | **可选**,EggJS 定义生成工具 | 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=egg-v3 my_project # npm v7 $ npm init midway -- --type=egg-v3 my_project ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as web from '@midwayjs/web'; import { join } from 'path'; @Configuration({ imports: [web], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: web.Application; async onReady() { // ... } } ``` ## 和默认 EggJS 的不同之处[​](#和默认-eggjs-的不同之处 "和默认 EggJS 的不同之处的直接链接") * 1、从 v3 开始,midway 提供了更多的组件,大部分 egg 内置插件默认禁用 * 2、baseDir 默认调整为 `src` 目录,服务器上为 `dist` 目录 * 3、禁用 egg-logger,全部替换为 @midwayjs/logger,不可切换 整个架构如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1614842824740-fc0c1432-3ace-4f77-b51f-15212984b168.png) ## 目录结构[​](#目录结构 "目录结构的直接链接") 除了 Midway 提供的目录结构外,EggJS 还有一些特殊的目录结构(不可变),整个结构如下。 ``` ➜ my_midway_app tree . ├── src | ├── app.ts ## EggJS 扩展 Worker 生命周期文件(可选) | ├── agent.ts ## EggJS 扩展 Agent 生命周期文件(可选) | ├── app ## EggJS 固定的根目录(可选) | │ ├── public ## EggJS 静态托管插件的默认目录(可配) | │ | └── reset.css | │ ├── view (可选) ## EggJS 模板渲染的默认目录(可配) | │ | └── home.tpl | │ └── extend (可选) ## EggJS 扩展目录(可配) | │ ├── helper.ts (可选) | │ ├── request.ts (可选) | │ ├── response.ts (可选) | │ ├── context.ts (可选) | │ ├── application.ts (可选) | │ └── agent.ts (可选) | │ | ├── config | | ├── plugin.ts | | ├── config.default.ts | | ├── config.prod.ts | | ├── config.test.ts (可选) | | ├── config.local.ts (可选) | | └── config.unittest.ts (可选) │ ├── controller ## Midway 控制器目录(推荐) │ ├── service ## Midway 服务目录(推荐) │ └── schedule ## Midway 定时器目录(推荐) │ ├── typings ## EggJS 定义生成目录 ├── test ├── package.json └── tsconfig.json ``` 以上是 EggJS 的目录结构全貌,其中包含了很多 EggJS 特有的目录,有一些在 Midway 体系中已经有相应的能力替代,可以直接替换。整个结构,基本上等价于将 EggJS 的目录结构移动到了 `src` 目录下。 由于 EggJS 是基于约定的框架,整个工程的目录结构是固定的,这里列举一些常用的约定目录。 | `src/app/public/**` | 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)。 | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `src/config/config.{env}.ts` | 用于编写配置文件,具体参见[配置](https://eggjs.org/zh-cn/basics/config.html)。 | | `src/config/plugin.js` | 用于配置需要加载的插件,具体参见[插件](https://eggjs.org/zh-cn/basics/plugin.html)。 | | `test/**` | 具体参见[单元测试](https://eggjs.org/zh-cn/core/unittest.html)。 | | `src/app.js` 和 `src/agent.js` | 用于自定义启动时的初始化工作,可选,具体参见[启动自定义](https://eggjs.org/zh-cn/basics/app-start.html)。关于`agent.js`的作用参见[Agent机制](https://eggjs.org/zh-cn/core/cluster-and-ipc.html#agent-%E6%9C%BA%E5%88%B6)。 | ## 配置定义[​](#配置定义 "配置定义的直接链接") Midway 在脚手架中提供了标准的 EggJS 的 TS 配置写法,MidwayConfig 中包括了 egg 中配置的定义和属性提示,结构如下。 ``` // src/config/config.default.ts import { MidwayConfig, MidwayAppInfo } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo) => { return { // use for cookie sign key, should change to your own and keep security keys: appInfo.name + '_xxxx', egg: { port: 7001, }, // security: { // csrf: false, // }, } as MidwayConfig; }; ``` 通过这样返回方法的形式,在运行期会被自动执行,合并进完整的配置对象。 这个函数的参数为 `MidwayAppConfig` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | 信息 注意,这里的 `baseDir` 和 `appDir` 和 EggJS 应用有所区别。 ## 使用 Egg 插件[​](#使用-egg-插件 "使用 Egg 插件的直接链接") 插件是 EggJS 的特色之一,`@midwayjs/web` 也支持 EggJS 的插件体系,但是在有 Midway 组件的情况下,尽可能优先使用 Midway 组件。 插件一般通过 npm 模块的方式进行复用。 ``` $ npm i egg-mysql --save ``` 然后需要在应用或框架的 `src/config/plugin.js` 中声明开启。 如果有 `export default` ,请写在其中。 ``` import { EggPlugin } from 'egg'; export default { static: false, // default is true mysql: { enable: true, package: 'egg-mysql' } } as EggPlugin; ``` 如果没有 `export default` ,可以直接导出。 ``` // src/config/plugin.ts // 使用 mysql 插件 export const mysql = { enable: true, package: 'egg-mysql', }; ``` 在开启插件之后,我们就可以在业务代码中使用插件提供的功能了。一般来说,插件会将对象挂载到 EggJS 的 `app` 和 `ctx` 之上,然后直接使用。 ``` app.mysql.query(sql, values); // egg 提供的方法 ``` 在 Midway 中可以通过 `@App` 获取 `app` 对象,以及在请求作用域中通过 `@Inject() ctx` 获取 `ctx` 对象,所以我们可以通过注入来获取插件对象。 ``` import { Provide, Inject, Get } from '@midwayjs/core'; import { Application, Context } from '@midwayjs/web'; @Provide() export class HomeController { @App() app: Application; @Inject() ctx: Context; @Get('/') async home() { this.app.mysql.query(sql, values); // 调用 app 上的方法(如果有的话) this.ctx.mysql.query(sql, values); // 调用挂载在 ctx 上的方法(如果有的话) } } ``` 此外,还可以通过 `@Plugin` 装饰器来直接注入 `app` 挂载的插件,默认情况下,如果不传参数,将以属性名作为 key。 ``` import { Provide, Get, Plugin } from '@midwayjs/core'; @Provide() export class HomeController { @Plugin() mysql: any; @Get('/') async home() { this.mysql.query(sql, values); } } ``` 信息 `@Plugin() mysql` 等价于 `app.mysql` 。 `@Plugin` 的作用就是从 app 对象上拿对应属性名的插件,所以 `@Plugin() xxx` 就等于 `app['xxx']` 。 ## Web 中间件[​](#web-中间件 "Web 中间件的直接链接") 中间件样例如下: ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/web'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime); }; } } ``` 警告 注意 1、如果要继续使用 EggJS 传统的函数式写法,必须将文件放在 `src/app/middleware` 下 2、egg 自带的内置中间件已经集成 应用中间件。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as egg from '@midwayjs/web'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [egg] // ... }) export class MainConfiguration { @App() app: egg.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 更多用法请参考 [Web 中间件](/docs/3.0.0/middleware.md) ## 中间件顺序[​](#中间件顺序 "中间件顺序的直接链接") 由于 egg 也有自己的中间件逻辑,在新版本中,我们将中间件加载顺序做了一定的处理,执行顺序如下: * 1、egg 框架中的中间件 * 2、egg 插件通过 config.coreMiddleware 添加的顺序 * 3、业务代码配置在 config.middleware 中配置的顺序 * 4、app.useMiddleware 添加的顺序 因为 midway 的中间件会后置加载,所以我们可以在 onReady 中进行自定义排序。 ## BodyParser[​](#bodyparser "BodyParser的直接链接") egg 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 和 `form` 类型。 如需 text 或者 xml,可以自行配置。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { formLimit: '1mb', jsonLimit: '1mb', textLimit: '1mb', xmlLimit: '1mb', }, } ``` 注意,使用 Postman 做 Post 请求时的类型选择: ![postman](https://img.alicdn.com/imgextra/i4/O1CN01QCdTsN1S347SuzZU5_!!6000000002190-2-tps-1017-690.png) ## 定时任务[​](#定时任务 "定时任务的直接链接") v3 开始请参考 [bull 组件](/docs/3.0.0/extensions/bull.md) 。 如需兼容之前的 [egg 定时任务](https://eggjs.org/zh-cn/basics/schedule.html) ,请照下列方法。 首先安装 `midway-schedule` 依赖。 ``` $ npm i midway-schedule --save ``` 添加到插件中即可。 ``` // src/config/plugin.ts export default { schedule: true, schedulePlus: { enable: true, package: 'midway-schedule', }, }; ``` 使用请参考上一版本文档。 ## 日志[​](#日志 "日志的直接链接") v3 开始无法使用 egg-logger,请参考 [日志](/docs/3.0.0/logger.md) 章节。 ## 异常处理[​](#异常处理 "异常处理的直接链接") EggJS 框架通过 [onerror](https://github.com/eggjs/egg-onerror) 插件提供了统一的错误处理机制,会作为 Midway 的兜底错误逻辑,和 [错误过滤器](/docs/3.0.0/error_filter.md) 不冲突。 对一个请求的所有处理方法(Middleware、Controller、Service)中抛出的任何异常都会被它捕获,并自动根据请求想要获取的类型返回不同类型的错误(基于 [Content Negotiation](https://tools.ietf.org/html/rfc7231#section-5.3.2))。 | 请求需求的格式 | 环境 | errorPageUrl 是否配置 | 返回内容 | | -------------- | ---------------- | --------------------- | ---------------------------------------------------- | | HTML & TEXT | local & unittest | - | onerror 自带的错误页面,展示详细的错误信息 | | HTML & TEXT | 其他 | 是 | 重定向到 errorPageUrl | | HTML & TEXT | 其他 | 否 | onerror 自带的没有错误信息的简单错误页(不推荐) | | JSON & JSONP | local & unittest | - | JSON 对象或对应的 JSONP 格式响应,带详细的错误信息 | | JSON & JSONP | 其他 | - | JSON 对象或对应的 JSONP 格式响应,不带详细的错误信息 | onerror 插件的配置中支持 errorPageUrl 属性,当配置了 errorPageUrl 时,一旦用户请求线上应用的 HTML 页面异常,就会重定向到这个地址。 在 `src/config/config.default.ts` 中 ``` // src/config/config.default.ts module.exports = { onerror: { // 线上页面发生异常时,重定向到这个页面上 errorPageUrl: '/50x.html', }, }; ``` ## 扩展 Application/Context/Request/Response[​](#扩展-applicationcontextrequestresponse "扩展 Application/Context/Request/Response的直接链接") ### 增加扩展逻辑[​](#增加扩展逻辑 "增加扩展逻辑的直接链接") 虽然 MidwayJS 并不希望直接将属性挂载到 koa 的 Context,App 上(会造成管理和定义的不确定性),但是 EggJS 的这项功能依旧可用。 文件位置如下。 ``` ➜ my_midway_app tree . ├── src │ ├── app │ │ └── extend │ │ ├── application.ts │ │ ├── context.ts │ │ ├── request.ts │ │ └── response.ts │ ├── config │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` 内容和原来的 EggJS 相同。 ``` // src/app/extend/context.ts export default { get hello() { return 'hello world'; }, }; ``` ### 增加扩展定义[​](#增加扩展定义 "增加扩展定义的直接链接") Context 请使用 Midway 的方式来扩展,请查看 [扩展上下文定义](/docs/context_definition.md)。 其余的部分,沿用 egg 的方式,请在 `src/interface.ts` 中扩展。 ``` // src/interface.ts declare module 'egg' { interface Request { // ... } interface Response { // ... } interface Application { // ... } } ``` 信息 业务自定义扩展的定义请 **不要放在根目录** `typings` 下,避免被 ts-helper 工具覆盖掉。 ## 使用 egg-scripts 部署[​](#使用-egg-scripts-部署 "使用 egg-scripts 部署的直接链接") 由于 EggJS 提供了默认的多进程部署工具 `egg-scripts` ,Midway 也继续支持这种方式,如果上层是 EggJS,推荐这种部署方式。 首先在依赖中,确保安装 `egg-scripts` 包。 ``` $ npm i egg-scripts --save ``` 添加 `npm scripts` 到 `package.json`: 在上面的代码构建之后,使用我们的 `start` 和 `stop` 命令即可完成启动和停止。 ``` "scripts": { "start": "egg-scripts start --daemon --title=********* --framework=@midwayjs/web", "stop": "egg-scripts stop --title=*********", } ``` 信息 `*********` 的地方是你的项目名。 > 注意:`egg-scripts` 对 Windows 系统的支持有限,参见 [#22](https://github.com/eggjs/egg-scripts/pull/22)。 #### **启动参数** ``` $ egg-scripts start --port=7001 --daemon --title=egg-server-showcase ``` Copy 如上示例,支持以下参数: * `--port=7001` 端口号,默认会读取环境变量 process.env.PORT,如未传递将使用框架内置端口 7001。 * `--daemon` 是否允许在后台模式,无需 nohup。若使用 Docker 建议直接前台运行。 * `--env=prod` 框架运行环境,默认会读取环境变量 process.env.EGG\_SERVER\_ENV, 如未传递将使用框架内置环境 prod。 * `--workers=2` 框架 worker 线程数,默认会创建和 CPU 核数相当的 app worker 数,可以充分的利用 CPU 资源。 * `--title=egg-server-showcase` is used to facilitate grep in ps processes. the default value is `egg-server-\${appname}`. * `--framework=yadan` 如果应用使用了[自定义框架](https://eggjs.org/zh-cn/advanced/framework.html),可以配置 package.json 的 egg.framework 或指定该参数。 * `--ignore-stderr` 忽略启动期的报错。 * `--https.key` 指定 HTTPS 所需密钥文件的完整路径。 * `--https.cert` 指定 HTTPS 所需证书文件的完整路径。 * 所有 [egg-cluster](https://github.com/eggjs/egg-cluster) 的 Options 都支持透传,如 --port 等。 更多参数可查看 [egg-scripts](https://github.com/eggjs/egg-scripts) 和 [egg-cluster](https://github.com/eggjs/egg-cluster) 文档。 信息 使用 egg-scripts 部署的日志会存放在 **用户目录** 下\*\*,\*\*比如 `/home/xxxx/logs` 。 ## 启动环境[​](#启动环境 "启动环境的直接链接") 原有 egg 使用 `EGG_SERVER_ENV` 中作为环境标志,在 Midway 中请使用 `MIDWAY_SERVER_ENV`。 ## State 类型定义[​](#state-类型定义 "State 类型定义的直接链接") 在 egg 底层的 koa 的 Context 中有一个特殊的 State 属性,通过和 Context 类似的方式可以扩展 State 定义。 ``` // src/interface.ts declare module '@midwayjs/web/dist/interface' { interface Context { abc: string; } interface State{ bbb: string; ccc: number; } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") ``` // src/config/config.default export default { // ... egg: { port: 7001, }, } ``` `@midwayjs/web` 所有参数如下: | 配置项 | 类型 | 描述 | | ----------------- | ------------------ | -------------------------------------- | | port | number | 必填,启动的端口 | | key | string | Buffer | | cert | string | Buffer | | ca | string | Buffer | | hostname | string | 监听的 hostname,默认 127.1 | | http2 | boolean | 可选,http2 支持,默认 false | | queryParseMode | simple\|extended | 默认为 extended | | queryParseOptions | `qs.IParseOptions` | 解析选项,当使用'simple'模式解析时可用 | 以上的属性,对本地和使用 `bootstrap.js` 部署的应用生效。 ### 修改端口[​](#修改端口 "修改端口的直接链接") 提示 注意,这个方式只会对本地研发,以及使用 bootstrap.js 文件部署的项目生效。 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 egg http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... egg: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... egg: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/3.0.0/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` ``` --- # ETCD etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中可以作为服务注册于发现,也可以作为 key-value 存储的中间件。 Midway 提供基于 [etcd3](https://github.com/microsoft/etcd3) 模块封装的组件,提供 etcd 的客户端调用能力。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/etcd@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/etcd": "^3.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as etcd from '@midwayjs/etcd'; import { join } from 'path' @Configuration({ imports: [ // ... etcd, ], // ... }) export class MainConfiguration { } ``` ## 配置默认客户端[​](#配置默认客户端 "配置默认客户端的直接链接") 大部分情况下,我们可以只使用默认客户端来完成功能。 ``` // src/config/config.default.ts export default { // ... etcd: { client: { host: [ '127.0.0.1:2379' ] }, }, } ``` ## 使用默认客户端[​](#使用默认客户端 "使用默认客户端的直接链接") 配置完成后,我们就可以在代码中使用了。 ``` import { Provide } from '@midwayjs/core'; import { ETCDService } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdService: ETCDService; async invoke() { await this.etcdService.put('foo').value('bar'); const fooValue = await this.etcdService.get('foo').string(); console.log('foo was:', fooValue); const allFValues = await this.etcdService.getAll().prefix('f').keys(); console.log('all our keys starting with "f":', allFValues); await this.etcdService.delete().all(); } } ``` 更多 API 请参考 ts 定义或者 [官网文档](https://microsoft.github.io/etcd3/classes/etcd3.html)。 ## 多实例配置[​](#多实例配置 "多实例配置的直接�链接") ``` // src/config/config.default.ts export default { // ... etcd: { clients: { instance1: { { host: [ '127.0.0.1:2379' ] }, }, instance2: { { host: [ '127.0.0.1:2379' ] }, } } }, } ``` ## 多实例获取[​](#多实例获取 "多实例获取的直接链接") ``` import { Provide } from '@midwayjs/core'; import { ETCDServiceFactory } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdServiceFactory: ETCDServiceFactory; async invoke() { const instance1 = this.etcdServiceFactory.get('instance1'); // ... const instance2 = this.etcdServiceFactory.get('instance2'); // ... } } ``` ## 动态创建实例[​](#动态创建实例 "动态创建实例的直接链接") ``` import { Provide } from '@midwayjs/core'; import { ETCDServiceFactory } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdServiceFactory: ETCDServiceFactory; async invoke() { const instance3 = await this.etcdServiceFactory.createInstance({ host: [ '127.0.0.1:2379' ] }, 'instance3'); // ... } } ``` --- # Express 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/express@3 --save $ npm i @types/body-parser @types/express @types/express-session --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/express": "^3.0.0", // ... }, "devDependencies": { "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", "@types/express-session": "^1.17.4", // ... } } ``` 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=express-v3 my_project # npm v7 $ npm init midway -- --type=express-v3 my_project ``` 针对 Express,Midway 提供了 `@midwayjs/express` 包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。 信息 我们使用的 Express 版本为 `v4` 。 ## 目录结构[​](#目录结构 "目录结构的直接链�接") ``` . ├── src │ ├── controller # controller接口的地方 │ ├── service # service逻辑处理的地方 | └── configuration.ts # 入口及生命周期配置、组件管理 ├── test ├── package.json └── tsconfig.json ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() {} } ``` ## 控制器(Controller)[​](#控制器controller "控制器(Controller)的直接链接") 整个请求控制器的写法和 Midway 适配其他框架的类似。为了和其他场景的框架写法一致,在请求的时候,Midway 将 Express 的 `req` 映射为 `ctx` 对象。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/express'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home(@Query() id) { console.log(id); // req.query.id === id return 'hello world'; // 简单返回,等价于 res.send('hello world'); } } ``` 你也可以额外注入 `req` 和 `res` 。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { Context, Response, NextFunction } from '@midwayjs/express'; @Controller('/') export class HomeController { @Inject() ctx: Context; // 即为 req @Inject() req: Context; @Inject() res: Response; @Get('/') async home(@Query() id) { // this.req.query.id === id } } ``` ## Web 中间件[​](#web-中间件 "Web 中间件的直接链接") Express 的中间件写法比较特殊,它的参数不同。 ``` import { Middleware } from '@midwayjs/core'; import { Context, Response, NextFunction } from '@midwayjs/express'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async ( req: Context, res: Response, next: NextFunction ) => { console.log('Request...'); next(); }; } } ``` 注意,这里我们导出了一个 `ReportMiddleware` 类,为了方便对接异步流程,`resolve` 返回可以是 async 函数。 Express 中的 next 方法,用于调用到下一个中间件,指的注意的是,Express 中间件并非洋葱模型,是单向调用。 ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 我们可以把上面编写的中间件应用到单个 Controller 上,也可以将中间件应用到单个路由上。 ``` import { Controller, Get, Provide } from '@midwayjs/core'; @Controller('/', { middleware: [ ReportMiddleware ]}) // controller 级别的中间件 export class HomeController { @Get('/', { middleware: [ ReportMiddleware ]}) // 路由级别的中间件 async home() { return 'hello world' } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 直接使用 Midway 提供的 `app.generateMiddleware` 方法,在入口处加载全局中间件。 ``` // src/configuration.ts import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { ReportMiddleware } from './middleware/report.middleware.ts' @Configuration({ imports: [express], }) export class MainConfiguration implements ILifeCycle { @App() app: express.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 除了加载 Class 形式的中间件外,也支持加载传统的 Express 中间件。 ``` // src/configuration.ts import { Configuration, ILifeCycle, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; @Configuration({ imports: [express], }) export class MainConfiguration implements ILifeCycle { @App() app: express.Application; async onReady() { this.app.useMiddleware((req, res, next) => { // xxx }); } } ``` 你可以通过注入 `app` 对象,来调用到所有 Express 上的方法。 ## 返回统一处理[​](#返回统一处理 "返回统一处理的直接链接") 由于 Express 中间件是单向调用,无法在返回时执行,为此我们额外设计了一个 `@Match` 装饰的过滤器,用于处理返回值的行为。 比如,我们可以定义针对全局返回的过滤器。 ``` // src/filter/globalMatch.filter.ts import { Match } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Match() export class GlobalMatchFilter { match(value, req, res) { // ... return { status: 200, data: { value }, }; } } ``` 也可以匹配特定的路由做返回。 ``` // src/filter/api.filter.ts import { Match } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Match((ctx: Context, res: Response) => { return ctx.path === '/api'; }) export class APIMatchFilter { match(value, req: Context, res: Response) { // ... return { data: { message: data: value, }, }; } } ``` 需要应用到 app 中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; import { APIMatchFilter } from './filter/api.filter'; import { GlobalMatchFilter } from 'filter/globalMatch.filter'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() { // ... this.app.useFilter([APIMatchFilter, GlobalMatchFilter]); } } ``` 注意,这类过滤器是按照添加的顺序来匹配执行。 ## 错误处理[​](#错误处理 "错误处理的直接链接") 和普通的项目相同,使用错误过滤器,但是参数略有不同。 ``` import { Catch } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Catch() export class GlobalError { catch(err: Error, req: Context, res: Response) { if (err) { return { status: err.status ?? 500, message: err.message, } } } } ``` 需要应用到 app 中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; import { GlobalError } from './filter/global.filter'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() { this.app.useMiddleware((req, res, next) => { next(); }); this.app.useFilter([GlobalError]); } } ``` 注意,`@Match` 和 `@Catch` 都是过滤器,在内部会自动判断做区分执行。。 ## Cookie[​](#cookie "Cookie的直接链接") `@midwayjs/express` 自带 `cookie parser` 功能,使用的是 `cookie-parser` 模块。 针对 Cookie,统一使用 `keys` 作为秘钥。 ``` // src/config/config.default export default { keys: ['key1', 'key2'], } ``` 获取 Cookie。 ``` const cookieValue = req.cookies['cookie-key']; ``` 设置 Cookie。 ``` res.cookie( 'cookie-key', 'cookie-value', cookieOptions ); ``` ## Session[​](#session "Session的直接链接") `@midwayjs/express` 内置了 Session 组件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 默认情况下为 `cookie-session` ,默认配置如下。 ``` // src/config/config.default export default { session: { name: 'MW_SESS', resave: true, saveUninitialized: true, cookie: { maxAge: 24 * 3600 * 1000, // ms httpOnly: true, // sameSite: null, }, } } ``` 我们可以通过简单的 API 来设置 session。 ``` @Controller('/') export class HomeController { @Inject() req; @Get('/') async get() { // set all this.req.session = req.query; // set value this.req.session.key = 'abc'; // get const key = this.req.session.key; // remove this.req.session = null; // set max age this.req.session.maxAge = Number(req.query.maxAge); // ... } } ``` ## BodyParser[​](#bodyparser "BodyParser的直接链接") `@midwayjs/express` 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 、`text`和 `urlencoded` 类型。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { json: { enable: true, limit: '1mb', strict: true, }, raw: { enable: false, limit: '1mb', }, text: { enable: true, limit: '1mb', }, urlencoded: { enable: true, extended: false, limit: '1mb', parameterLimit: 1000, }, }, } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/express` 的配置样例如下: ``` // src/config/config.default export default { // ... express: { port: 7001, }, } ``` 所有属性描述如下: | 属性 | 类型 | 描述 | | ------------ | ------------------------------------------ | ------------------------------------------------------- | | port | number | 可选,启动的端口 | | globalPrefix | string | 可选,全局的 http 前缀 | | keys | string\[] | 可选,Cookies 签名,如果上层未写 keys,也可以在这里设置 | | hostname | string | 可选,监听的 hostname,默认 127.1 | | key | string \| Buffer \| Array\ | 可选,Https key,服务端私钥 | | cert | string \| Buffer \| Array\ | 可选,Https cert,服务端证书 | | ca | string \| Buffer \| Array\ | 可选,Https ca | | http2 | boolean | 可选,http2 支持,默认 false | ### 修改端口[​](#修改端口 "修改端口的直接链接") 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 Express http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... express: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... express: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/3.0.0/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... express: { key: join(__dirname, '../ssl/ssl.key'), cert: join(__dirname, '../ssl/ssl.pem'), }, } ``` ### 修改上下文日志[​](#修改上下文日志 "修改上下文日志的直接链接") 可以单独修改 express 框架的上下文日志。 ``` export default { express: { contextLoggerFormat: info => { // 等价 req const req = info.ctx; const userId = req?.['session']?.['userId'] || '-'; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${userId} - ${Date.now() - req.startTime}ms ${req.method}] ${info.message}`; } // ... }, }; ``` --- # gRPC gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 本篇内容演示了如何在 Midway 体系下,提供 gRPC 服务,以及调用 gRPC 服务的方法。 Midway 当前采用了最新的 gRPC 官方推荐的 [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) 进行开发,并提供了一些工具包,用于快速发布服务和调用服务。 我们使用的模块为 `@midwayjs/grpc` ,既可以独立发布服务,又可以接入其它框架调用 gRPC 服务。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | **调用服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | **其他** | 描述 | | | -------------------- | -- | | 可作为主框架独立使用 | ✅ | | 可独立添加中间件 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/grpc@3 --save $ npm i @midwayjs/grpc-helper --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/grpc": "^3.0.0", // ... }, "devDependencies": { "@midwayjs/grpc-helper": "^1.0.0", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 提示 不管是提供服务还是调用服务,都需要开启组件。 `@midwayjs/grpc` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as grpc from '@midwayjs/grpc'; @Configuration({ imports: [grpc], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as grpc from '@midwayjs/grpc'; @Configuration({ imports: [koa, grpc], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 大致的目录结构如下,`src/provider` 是提供 gRPC 服务的目录。 ``` . ├── package.json ├── proto ## proto 定义文件 │ └── helloworld.proto ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── provider ## gRPC 提供服务的文件 │ └── greeter.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 定义服务接口[​](#定义服务接口 "定义服务接口的直接链接") 在微服务中,定义一个服务需要特定的接口定义语言(IDL)来完成,在 gRPC中 默认使用 Protocol Buffers 作为序列化协议。 序列化协议独立于语言和平台,提供了多种语言的实现,Java,C++,Go 等等,每一种实现都包含了相应语言的编译器和库文件。所以 gRPC 是一个提供和调用都可以跨语言的服务框架。 一个gRPC服务的大体架构可以用官网上的一幅图表示。 ![](https://img.alicdn.com/imgextra/i3/O1CN01kpIyg51k8i5DtcGpZ_!!6000000004639-2-tps-621-445.png) Protocol Buffers 协议的文件,默认的后缀为 `.proto` 。.proto后缀的IDL文件,并通过其编译器生成特定语言的数据结构、服务端接口和客户端Stub代码。 信息 由于 proto 文件可以跨语言使用,为了方便共享,我们一般将 proto 文件放在 src 目录外侧,方便其他工具复制分发。 下面是一个基础的 `proto/helloworld.proto` 文件。 ``` syntax = "proto3"; package helloworld; service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } ``` proto3 表示的是第三版的 protobuf 协议,是 gRPC 目前推荐的版本,“语法简单,功能更全”。 我们可以用 `service` 格式,定义服务体,其中可以包含方法。同时,我们可以更加细致的通过 `message` 描述服务具体的请求参数和响应参数。 我们可以从 [Google 的官网文档](https://developers.google.com/protocol-buffers/docs/overview#simple) 中查看更多细节。 信息 大家会看到,这和 Java 中的 Class 非常相像,每个结构就相当于 Java 中的一个类。 ### 编写 proto 文件[​](#编写-proto-文件 "编写 proto 文件的直接链接") 现在我们再来看之前的服务,是不是就很好理解了。 ``` syntax = "proto3"; package helloworld; // 服务的定义 service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // 服务的请求参数 message HelloRequest { string name = 1; } // 服务的响应参数 message HelloReply { string message = 1; } ``` 我们定义了一个名为 `Greeter` 的服务,包含一个 `HelloRequest` 结构的请求体,以及返回 `HelloReply` 结构的响应体。 接下去,我们将对这个服务给大家做演示。 ### 生成代码定义[​](#生成代码��定义 "生成代码定义的直接链接") 传统的 gRPC 框架,需要用户手动编写 proto 文件,以及生成 js 服务,最后再根据 js 生成的服务再编写实现,在 Midway 体系下,我们提供了一个 grpc-helper 工具包来加速这个过程。 如果没有安装,可以先安装。 ``` $ npm i @midwayjs/grpc-helper --save-dev ``` grpc-helper 工具的作用,是将用户提供的 proto 文件,生成对应可读的 ts interface 文件。 我们可以添加一个脚本,方便这个过程。 ``` { "scripts": { "generate": "tsproto --path proto --output src/domain" } } ``` 然后执行 `npm run generate` 。 上述命令执行后,会在代码的 `src/domain` 目录中生成 proto 文件对应的服务接口定义。 信息 不管是提供 gRPC 服务还是调用 gRPC 服务,都要先生成定义。 生成的代码如下,包含有一个命名空间(namespace),以及命名空间下的两个 TypeScript Interface, `Greeter` 用于编写服务端实现, `GreeterClient` 用于编写客户端实现。 ``` /** * This file is auto-generated by grpc-helper */ import * as grpc from '@midwayjs/grpc'; // 生成的命名空间 export namespace helloworld { // 服务端使用的定义 export interface Greeter { // Sends a greeting sayHello(data: HelloRequest): Promise; } // 客户端使用的定义 export interface GreeterClient { // Sends a greeting sayHello(options?: grpc.IClientOptions): grpc.IClientUnaryService; } // 请求体结构 export interface HelloRequest { name?: string; } // 响应体结构 export interface HelloReply { message?: string; } } ``` 信息 每当 proto 文件被修改时,就需要重新生成对应的服务定义,然后将对应的方法实现。 ## 提供 gRPC 服务(Provider)[​](#提供-grpc-服务provider "提供 gRPC 服务(Provider)的直接链接") ### 编写服务提供方(Provider)[​](#编写服务提供方provider "编写服务提供方(Provider)的直接链接") 在 `src/provider` 目录中,我们创建 `greeter.ts` ,内容如下 ``` import { MSProviderType, Provider, GrpcMethod, } from '@midwayjs/core'; import { helloworld } from '../domain/helloworld'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { return { message: 'Hello ' + request.name }; } } ``` 信息 注意,@Provider 装饰器和 @Provide 装饰器不同,前者用于提供服务,后者用于依赖注入容器扫描标识的类。 我们使用 `@Provider` 暴露出一个 RPC 服务, `@Provider` 的第一个参数为 RPC 服务类型,这个参数是个枚举,这里选择 GRPC 类型。 `@Provider` 的第二个参数为 RPC 服务的元数据,这里指代的是 gRPC 服务的元数据。这里需要写入 gRPC 的 package 字段,即 proto 文件中的 package 字段(这里的字段用于和 proto 文件加载后的字段做对应)。 对于普通的 gRPC 服务接口(UnaryCall),我们只需要使用 `@GrpcMethod()` 装饰器修饰即可。修饰的方法即为服务定义本身,入参为 proto 中定义好的入参,return 值即为定义好的响应体。 信息 注意,生成的 Interface 是为了更好的编写服务代码,规范结构,请务必按照定义编写。 ### 配置服务[​](#配置服务 "配置服务的直接链接") 配置内容如下。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpcServer: { services: [ { protoPath: join(appInfo.appDir, 'proto/hero.proto'), package: 'hero', }, { protoPath: join(appInfo.appDir, 'proto/helloworld.proto'), package: 'helloworld', } ], } }; } ``` services 字段是数组,意味着 Midway 项目可以同时发布多个 gRPC 服务。每个 service 的结构为: | 属性 | 类型 | 描述 | | --------- | ------ | -------------------------- | | protoPath | string | 必选,proto 文件的绝对路径 | | package | string | 必选,服务对应的 package | 除了 Service 配置之外,还有一些其他的配置。 | 属性 | 类型 | 描述 | | ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- | | url | string | 可选,gRPC 服务地址,默认 6565 端口,比如 'localhost:6565' | | loaderOptions | Object | 可选,proto file loader 的 options | | credentials | ServerCredentials | 可选,grpc Server binding 时的 credentials 参数选项 | | serverOptions | ChannelOptions | 可选,grpc Server 的 [自定义 options](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js#supported-channel-options) | ### 提供安全证书[​](#提供安全证书 "提供安全证书的直接链接") 可以通过 `credentials` 参数传递安全证书。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; import { ServerCredentials } from '@midwayjs/grpc'; import { readFileSync } from 'fs'; import { join } from 'path'; const cert = readFileSync(join(__dirname, './cert/server.crt')); const pem = readFileSync(join(__dirname, './cert/server.pem')); const key = readFileSync(join(__dirname, './cert/server.key')); export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpcServer: { // ... credentials: ServerCredentials.createSsl(cert, [{ private_key: key, cert_chain: pem }]); } }; } ``` ### 编写单元测试[​](#编写单元测试 "编写单元测试的直接链接") `@midwayjs/grpc` 库提供了一个 `createGRPCConsumer` 方法,用于实时调用客户端,一般我们用这个方法做测试。 警告 这个方法每次调用会实时连接,不建议将该方法用在生产环境。 在测试中写法如下。 ``` import { createApp, close } from '@midwayjs/mock'; import { Framework, createGRPCConsumer } from '@midwayjs/grpc'; import { join } from 'path'; import { helloworld } from '../src/domain/helloworld'; describe('test/index.test.ts', () => { it('should create multiple grpc service in one server', async () => { const baseDir = join(__dirname, '../'); // 创建服务 const app = await createApp(); // 调用服务 const service = await createGRPCConsumer({ package: 'helloworld', protoPath: join(baseDir, 'proto', 'helloworld.proto'), url: 'localhost:6565' }); const result = await service.sayHello().sendMessage({ name: 'harry' }); expect(result.message).toEqual('Hello harry'); await close(app); }); }); ``` ## 调用 gRPC 服务(Consumer)[​](#调用-grpc-服务consumer "调用 gRPC 服务(Consumer)的直接链接") 我们编写一个 gRPC 服务来调用上面的暴露的服务。 信息 事实上,你可以在 Web 的 Controller,或者 Service 等其他地方来调用,这里只是做一个示例。 ### 调用配置[​](#调用配置 "调用配置的直接链接") 你需要在 `src/config/config.default.ts` 中增加你需要调用的目标服务以及它的 proto 文件信息。 比如,这里我们填写了上面暴露的服务本身,以及该服务的 proto,包名等信息(函数形式)。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpc: { services: [ { url: 'localhost:6565', protoPath: join(appInfo.appDir, 'proto/helloworld.proto'), package: 'helloworld', }, ], }, }; } ``` ### 代码调用[​](#代码调用 "代码调用的直接链接") 配置完后,我们就可以在代码里调用了。 `@midwayjs/grpc` 提供了 `clients` ,可以方便的获取到已配置的服务。我们只需要在需要注入的地方,注入这个对象即可。 比如: ``` import { Provide, Inject, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; } ``` 我们通过 `clients` 获取到对方服务的客户端实例,然后调用即可。 ``` import { Provide, Inject, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; async invoke() { // 获取服务 const greeterService = this.grpcClients.getService( 'helloworld.Greeter' ); // 调用服务 const result = await greeterService.sayHello() .sendMessage({ name: 'harry' }); // 返回结果 return result; } } ``` 我们也可以利用 `@Init` 装饰器,将需要调用的服务缓存到属性上。这样可以在其他方法调用时复用。 示例如下。 ``` import { GrpcMethod, MSProviderType, Provider, Inject, Init, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provider(MSProviderType.GRPC, { package: 'hero' }) export class HeroService implements hero.HeroService { // 注入客户端 @Inject() grpcClients: Clients; greeterService: helloworld.GreeterClient; @Init() async init() { // 赋值一个服务实例 this.greeterService = this.grpcClients.getService( 'helloworld.Greeter' ); } @GrpcMethod() async findOne(data) { // 调用服务 const result = await greeterService.sayHello() .sendMessage({ name: 'harry' }); // 返回结果 return result; } } ``` ## 流式服务[​](#流式服务 "流式服务的直接链接") gRPC 的流式服务用于减少连接,让服务端或者客户端不需要等待即可执行任务,从而提高执行效率。 gRPC 的流式服务分为三种,以服务端角度来说,为 * 服务端接收流(客户端推) * 服务端响应流(服务端推) * 双向流 下面我们将一一介绍。 ### 流式 proto 文件[​](#流式-proto-文件 "流式 proto 文件的直接链接") 流式的 proto 文件写法不同,需要在希望使用流式的地方将参数标记为 `stream` 。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; int32 num = 2; } message Num { int32 id = 1; int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } // 双向流 rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 该服务生成的接口定义为: ``` import { IClientDuplexStreamService, IClientReadableStreamService, IClientUnaryService, IClientWritableStreamService, IClientOptions, } from '@midwayjs/grpc'; export namespace math { export interface AddArgs { id?: number; num?: number; } export interface Num { id?: number; num?: number; } /** * server interface */ export interface Math { add(data: AddArgs): Promise; addMore(data: AddArgs): Promise; // 服务端推,客户端读 sumMany(data: AddArgs): Promise // 客户端端推,服务端读 addMany(num: AddArgs): Promise; } /** * client interface */ export interface MathClient { add(options?: IClientOptions): IClientUnaryService; addMore(options?: IClientOptions): IClientDuplexStreamService; // 服务端推,客户端读 sumMany(options?: IClientOptions): IClientReadableStreamService; // 客户端端推,服务端读 addMany(options?: IClientOptions): IClientWritableStreamService; } } ``` ### 服务端推送[​](#服务端推送 "服务端推送的直接链接") 客户端调用一次,服务端可以多次返回。通过 `@GrpcMethod()` 的参数来标识流式类型。 可用的类型为: * `GrpcStreamTypeEnum.WRITEABLE` 服务端输出流(单工) * `GrpcStreamTypeEnum.READABLE` 客户端输出流(单工),服务端接受多次 * `GrpcStreamTypeEnum.DUPLEX` 双工流 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.WRITEABLE }) async sumMany(args: math.AddArgs) { this.ctx.write({ num: 1 + args.num }); this.ctx.write({ num: 2 + args.num }); this.ctx.write({ num: 3 + args.num }); this.ctx.end(); } // ... } ``` 服务端使用 `ctx.write` 方法来返回数据,由于是服务端流,可以返回多次。 返回结束后,请使用 `ctx.end()` 方法关闭流。 客户端,调用一次,接受多次数据。 比如下面的累加逻辑。 Promise 写法,会等待服务端数据都返回再做处理。 ``` // 服务端推送 let total = 0; let result = await service.sumMany().sendMessage({ num: 1, }); result.forEach(data => { total += data.num; }); // total = 9; ``` 事件写法,实时处理。 ``` // 服务端推送 let call = service.sumMany().getCall(); call.on('data', data => { // do something }); call.sendMessage({ num: 1, }); ``` ### 客户端推送[​](#客户端推送 "客户端推送的直接链接") 客户端调用多次,服务端接收多次数据,返回一个结果。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.READABLE})` 的参数来标识流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { sumDataList: number[] = []; @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.READABLE, onEnd: 'sumEnd' }) async addMany(data: math.Num) { this.sumDataList.push(data); } async sumEnd(): Promise { const total = this.sumDataList.reduce((pre, cur) => { return { num: pre.num + cur.num, } }); return total; } // ... } ``` 客户端每次调用,都会触发一次 `addMany` 方法。 在客户端发送 `end` 事件之后,会调用 `@GrpcMethod` 装饰器上的 `onEnd` 参数指定的方法,该方法的返回值即为最后客户端拿到的值。 客户端示例如下: ``` // 客户端推送 const data = await service.addMany() .sendMessage({num: 1}) .sendMessage({num: 2}) .sendMessage({num: 3}) .end(); // data.num = 6 ``` ### 双向流[​](#双向流 "双向流的直接链接") 客户端可以调用多次,服务端也可以接收多次数据,返回多个结果,类似于传统的 TCP 通信。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.DUPLEX})` 的参数来标识双工流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.DUPLEX, onEnd: 'duplexEnd' }) async addMore(message: math.AddArgs) { this.ctx.write({ id: message.id, num: message.num + 10, }); } async duplexEnd() { console.log('got client end message'); } // ... } ``` 服务端可以随时使用 `ctx.write` 返回数据,也可以使用 `ctx.end` 来关闭流。 客户端示例: 对于双工通信的客户端,由于无法保证调用、返回的顺序,我们需要使用监听的模式来消费结果。 ``` const clientStream = service.addMore().getCall(); let total = 0; let idx = 0; duplexCall.on('data', (data: math.Num) => { total += data.num; idx++; if (idx === 2) { duplexCall.end(); // total => 29 } }); duplexCall.write({ num: 3, }); duplexCall.write({ num: 6, }); ``` 如果希望保证调用顺序,我们也提供了保证顺序的双向流调用方法,但是需要在 proto 中定义一个固定的 id,来确保顺序。 比如我们的 Math.proto,对每个入参和出参,都增加了一个固定的 id,所以可以固定顺序。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } message Num { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 固定顺序的客户端调用方式如下: ``` // 保证顺序的双向流 const t = service.addMore(); const result4 = await new Promise((resolve, reject) => { let total = 0; // 第一次调用和返回 t.sendMessage({ num: 2 }) .then(res => { expect(res.num).toEqual(12); total += res.num; }) .catch(err => console.error(err)); // 第二次调用和返回 t.sendMessage({ num: 5 }).then(res => { expect(res.num).toEqual(15); total += res.num; resolve(total); }) .catch(err => console.error(err)); t.end(); }); // result4 => 27 ``` 默认的 id 为 `id` ,如果服务端定义不同,需要修改,可以在客户端调用时传递。 ``` // 保证顺序的双向流 const t = service.addMore({ messageKey: 'uid' }); ``` ## 元数据(Metadata)[​](#元数据metadata "元数据(Metadata)的直接链接") gRPC 的元数据等价于 HTTP 的上下文。 服务端通过 `ctx.sendMetadata` 方法返回元数据,也可以通过 `ctx.metadata` 获取客户端传递的元数据。 ``` import { MSProviderType, Provider, GrpcMethod, } from '@midwayjs/core'; import { helloworld } from '../domain/helloworld'; import { Context, Metadata } from '@midwayjs/grpc'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @Inject() ctx: Context; @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { // 客户端传递的元数据 console.log(this.ctx.metadata); // 创建元数据 const meta = new Metadata(); this.ctx.metadata.add('xxx', 'bbb'); this.ctx.sendMetadata(meta); return { message: 'Hello ' + request.name }; } } ``` 客户端通过方法的 options 参数传递元数据。 ``` import { Metadata } from '@midwayjs/grpc'; const meta = new Metadata(); meta.add('key', 'value'); const result = await service.sayHello({ metadata: meta, }).sendMessage({ name: 'harry' }); ``` 获取元数据相对麻烦一些。 普通一元调用(UnaryCall)获取元数据需要使用 `sendMessageWithCallback` 方法。 ``` const call = service.sayHello().sendMessageWithCallback({ name: 'zhangting' }, (err) => { if (err) { reject(err); } }); call.on('metadata', (meta) => { // output meta }); ``` 其他流式服务,可以通过 `getCall()` 方法获取原始客户端流对象,从而直接订阅。 ``` // 获取服务,注意,这里没有 await const call = service.addMany().getCall(); call.on('metadata', (meta) => { // output meta }); ``` ## 超时处理[​](#超时处理 "超时处理的直接链接") 我们可以在调用服务时传递参数,单位毫秒。 ``` const result = await service.sayHello({ timeout: 5000 }).sendMessage({ name: 'harry' }); ``` --- # HTTP 代理 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的 HTTP 请求代理组件,支持 GET、POST 等多种请求方法。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/http-proxy@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/http-proxy": "^3.0.0" // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件 ``` // ... import * as proxy from '@midwayjs/http-proxy'; @Configuration({ imports: [ // ...other components proxy, ], }) export class MainConfiguration {} ``` ## 配置[​](#配置 "配置的直接链接") 代理配置定义如下: ``` // 代理配置类型 export interface HttpProxyConfig { // 匹配要代理的 URL 正则表达式 match: RegExp; // 替换匹配到的链接的 host,将请求代理到此地址 host?: string; // 通过正则的表达式捕获组处理代理地址 target?: string; // 转发请求超时时间,默认为0不设置超时时间 proxyTimeout?: number; // 忽略代理请求转发的 header 中的字段 ignoreHeaders?: { [key: string]: boolean; }; } ``` 代理支持单个代理和多个代理。 单个代理配置 ``` // src/config/config.default.ts export default { httpProxy: { match: /\/tfs\//, host: 'https://gw.alicdn.com', }, }; ``` 多个代理配置 ``` // src/config/config.default.ts // 代理配置类型 export default { httpProxy: { default: { // 一些每个策略复用的值,会和底下的策略进行合并 }, strategy: { gw: { // https://gw.alicdn.com/tfs/TB1.1EzoBBh1e4jSZFhXXcC9VXa-48-48.png match: /\/tfs\//, host: 'https://gw.alicdn.com', }, g: { // https://g.alicdn.com/mtb/lib-mtop/2.6.1/mtop.js match: /\/bdimg\/(.*)$/, target: 'https://sm.bdimg.com/$1', }, httpBin: { // https://httpbin.org/ match: /\/httpbin\/(.*)$/, target: 'https://httpbin.org/$1', }, }, }, }; ``` ## 示例:使用 host 配置代理[​](#示例使用-host-配置代理 "示例:使用 host 配置代理的直接链接") ``` export default { httpProxy: { match: /\/tfs\//, host: 'https://gw.alicdn.com', }, }; ``` 当请求您的站点路径为: `https://yourdomain.com/tfs/test.png` 时,`match` 字段配置的正则表达式成功匹配,那么就将原始请求路径中的 `host` 部分 `https://yourdomain.com` 替换为配置的 `https://gw.alicdn.com`,从而发起代理请求到 `https://gw.alicdn.com/tfs/test.png`,并把响应结果返回给请求您站点的用户。 ## 示例:使用 target 配置代理[​](#示例使用-target-配置代理 "示例:使用 target 配置代理的直接链接") ``` export default { httpProxy: { match: /\/httpbin\/(.*)$/, target: 'https://httpbin.org/$1', }, }; ``` 当请求您的站点路径为: `https://yourdomain.com/httpbin/get?name=midway` 时,`match` 字段配置的正则表达式成功匹配,同时正则的捕获组中有结果 `['get?name=midway']` ,那么就将原始请求路径中的 `$1` 部分替换为捕获组中的第 1 个数据(index: 0)的 `get?name=midway`,从而发起代理请求到 `https://httpbin.org/get?name=midway`,并把响应结果返回给请求您站点的用户。 --- # 多语言 Midway 提供了多语言组件,让业务可以快速指定不同的语言,展示不同的文案,也可以在 HTTP 场景配合请求参数,请求头等方式来使用。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/i18n@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/i18n": "^3.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 i18n 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as i18n from '@midwayjs/i18n'; @Configuration({ imports: [ // ... i18n ] }) export class MainConfiguration { //... } ``` ## 使用[​](#使用 "使用的直接链接") 组件提供了 `MidwayI18nService` 服务,用于翻译多语言文本。 使用 `translate` 方法,传入不同的文本关键字和参数,返回不同语言的文本内容。 ``` @Controller('/') export class UserController { @Inject() i18nService: MidwayI18nService; @Get('/') async index(@Query('username') username: string) { return this.i18nService.translate('HELLO_MESSAGE', { args: { username }, }); } } ``` ## 配置多语言文案[​](#配置多语言文案 "配置多语言文案的直接链接") 你可以在配置文件中直接配置,但是大多数情况下,文案会很多,有时候甚至可能文案在远端服务上,这个时候直接配置就不太现实。 一般来说,我们会将文案单独放到某个文案配置目录中,比如 `src/locales` 。 以 `src/locale` 这个目录为例,我们举个例子,结构如下: ``` . ├── src │ ├── locales | │ ├── en_US.json | │ └── zh_CN.json │ └── controller │ └── home.controller.ts ├── package.json └── tsconfig.json ``` 这里我们建了两个多语言的文件,`en_US.json` 和 `zh_CN.json`,分别代表英文和中文。 文件内容分别如下: ``` // src/locales/en_US.json { "hello": "Hello {username}", "email": "email id", "login": "login account", "createdAt": "register date" } ``` ``` // src/locales/zh_CN.json { "hello": "你好 {username}", "email": "邮箱", "login": "帐号", "createdAt": "注册时间" } ``` 每行一个字符串对,是一个标准的 JSON 格式内容,也可以使用 js/ts 文件,花括号中是可替换的参数占位。 同时,需要在配置中加入这两个 JSON,其中 `default` 是语言的默认分组。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), }, zh_CN: { default: require('../locale/zh_CN'), } }, } } ``` 这样就可以使用了,使用输出如下。 ``` this.i18nService.translate('hello', { args: { username: 'harry', }, locale: 'en_US', }); // output: Hello harry. this.i18nService.translate('hello', { args: { username: 'harry', }, locale: 'zh_CN', }); // output: 你好 harry. ``` ## 多语言文案分组[​](#多语言文案分组 "多语言文案分组的直接链接") 在如下配置中,用户配置的多语言文案在 `default` 分组中。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), }, zh_CN: { default: require('../locale/zh_CN'), } }, } } ``` 这样做的好处是,在其他组件或者业务代码中,我们也可以使用不同的分组名,来添加其他的多语言文案。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), user: require('../locale/user_en_US'), }, zh_CN: { default: require('../locale/zh_CN'), user: require('../locale/user_zh_CN'), } }, } } ``` 在代码中,如果调用非默认分组,需要指定分组参数。 ``` this.i18nService.translate('user.hello', { args: { username: 'harry', }, group: 'user', // 指定其他分组 locale: 'en_US', }); ``` ## 多语言文案格式[​](#多语言文案格式 "多语言文案格式的直接链接") 多语言文本中可以添加参数,参数可以有 `对象` 和 `数组` 两种形式。 对象形式如下,使用花括号作为占位符。 ``` Hello {username} ``` 使用时,通过配置传递,按对象 key 覆盖变量。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: { username }, }); } ``` 数组形式如下,使用数字作为占位符。 ``` Hello {0} ``` 使用时,通过配置传递,格式是数组形式,按数组顺序覆盖数字变量。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: [username] }); } ``` ## 动态添加多语言文案[​](#动态添加多语言文案 "动态添加多语言文案的直接链接") 有时候,多语言文案可能放在远端,比如数据库等,我们可以通过 `addLocale` 方法进行动态添加。 比如,在配置加载后,代码使用前。 ``` // configuration.ts // ... @Configuration({ imports: [ koa, i18n ] }) export class MainConfiguration { @Inject() i18nService: MidwayI18nService; async onReady() { this.i18nService.addLocale('zh_TW', { hello: '你好,{username} 美麗的世界' }); } // ... } ``` 在代码中就可以使用。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: [username], locale: 'zh_TW' }); } ``` ## 通过参数指定当前语言[​](#通过参数指定当前语言 "通过参数指定当前语言的直接链接") 一般情况下,默认语言为 `en_US`,用户的浏览器访问一般会自带 `Accept-Language` 头,所以会正确识别语言。比如用中文浏览器访问,就能正常显示中文。 除此之外,在 HTTP 场景下可以通过 URL Query,Cookie,Header 来指定语言。 优先级从上到下: * query: /?locale=en-US * cookie: locale=zh-TW * header: Accept-Language: zh-CN,zh;q=0.5 当传递了这些参数之后,多语言数据会自动保存到当前用户的 Cookie 中,下次请求会直接用该设定好的语言。 ## 手动设置语言[​](#手动设置语言 "手动设置语言的直接链接") 可以通过调用 `saveRequestLocale` 设置当前语言。 ``` async index() { // ... this.i18nService.saveRequestLocale('zh_CN'); } ``` 如果开启了 `writeCookie` 配置,设置后会保存到当前用户的 Cookie 中,下次请求会使用该设置。 ## 语言选择优先级[​](#语言选择优先级 "语言选择优先级的直接链接") 这些多种设置语言的方式,有着不同的优先级,如下优先级从高到低: * 1、`i18nService.translate` 方法显式指定的语言 * 2、通过其他装饰器设置的语言,比如 `@Validate` 装饰器的参数(本质是调用了`i18nService.translate` 方法) * 3、通过 `saveRequestLocale` API 直接设置的当前语言 * 4、通过浏览器 Query,Cookie,Header 设置的语言(本质是调用了 `saveRequestLocale`) * 5、i18n 组件配置中的默认语言 ## 关于语言大小写[​](#关于语言大小写 "关于语言大小写的直接链接") 在代码内部,我们会将所有的多语言,fallback 规则,写入的文本串,返回的 locale 结果,使用下面的规则替代 * 1、使用中划线代替下划线 * 2、使用小写代替大写 即所有的 `en_US` 都会变成 `en-us`,`zh_CN` 会变成 `zh-cn`。 这样做会安全的适配 URL 和 Cookie。 ## View 中使用[​](#view-中使用 "View 中使用的直接链接") 在 Web 类型的框架中,我们默认添加了 locals 变量支持,可以在模板引擎中使用。 假设我们使用的模板引擎是 [Nunjucks](/docs/3.0.0/extensions/render.md),可以直接引用到 `i18n` 方法。 多语言文案如下: ``` { "hello": "Hello {username}", } ``` 模板如下: ``` {{ i18n('hello', user) }} ``` 示例如下: ``` // ... @Controller('/') export class UserController { @Inject() ctx: Context; @Get('/') async index() { await this.ctx.render('index', { // 注意这里是整个对象传递给模板 user: { username: 'harry', } }); } } ``` i18n 方法定义如下: ``` function i18n(templateName: string, args: Record) { // ... } ``` 方法名可以通过配置修改。 ``` // src/config/config.default.ts export default { // ... i18n: { localsField: 'i18n', } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") 大部分情况下,你只需要在配置 `localeTable` 添加你自己的多语言翻译即可。 下面是完整的配置,你可以在配置定义中找到。 ``` // src/config/config.default.ts export default { // ... i18n: { // 默认语言 "en_US" defaultLocale: 'en_US', // 把你的翻译文本放到这里 localeTable: { en_US: { // group name default: { // hello: 'hello' } }, zh_CN: { // group name default: { // hello: '你好' } }, }, // 语言映射,可以用 * 号通配 fallbacks: { // 'en_*': 'en_US', // pt: 'pt-BR', }, // 是否将请求参数写入 cookie writeCookie: true, resolver: { // url query 参数,默认是 "locale" queryField: 'locale', cookieField: { // Cookie 里的 key,默认是 "locale" fieldName: 'locale', // Cookie 域名,默认为空,代表当前域名有效 cookieDomain: '', // Cookie 默认的过期时间,默认一年 cookieMaxAge: FORMAT.MS.ONE_YEAR, }, }, localsField: 'i18n', } } ``` ### 回写 Cookie[​](#回写-cookie "回写 Cookie的直接链接") 默认情况下,多语言组件会将当前用户的语言回写到 Cookie 中,避免下次请求再进行查找以提高性能,我们可以通过配置关闭这个行为。 ``` // src/config/config.default.ts export default { // ... i18n: { writeCookie: false, } } ``` ### 请求解析配置[​](#请求解析配置 "请求解析配置的直接链接") HTTP 场景下,我们提供了通过参数指定当前语言的能力。 默认情况下,组件通过下面的字段来查找。 * query 的 `locale` 字段 * cookie 的 `locale` 字段 * header 的 `Accept-Language` 部分 我们可以通过配置修改查询的字段。 比如,修改 Query 的字段。 ``` // src/config/config.default.ts export default { // ... i18n: { resolver: { queryField: 'abc' }, } } ``` 我们就可以通过 `/?abc=en-US` 来请求修改语言。 如果不希望通过请求来设置语言,可以将整个 `resolver` 解析关闭,对 Cookie 的回写也将同时停止。 ``` // src/config/config.default.ts export default { // ... i18n: { resolver: false, } } ``` ## 常用语言[​](#常用语言 "常用语言的直接链接") | 语言 | 语言包名 | | ---------------- | -------- | | 阿拉伯 | ar\_EG | | 亞美尼亞 | hy\_AM | | 保加利亚语 | bg\_BG | | 加泰罗尼亚语 | ca\_ES | | 捷克语 | cs\_CZ | | 丹麦语 | da\_DK | | 德语 | de\_DE | | 希腊语 | el\_GR | | 英语 | en\_GB | | 英语(美式) | en\_US | | 西班牙语 | es\_ES | | 爱沙尼亚语 | et\_EE | | 波斯语 | fa\_IR | | 芬兰语 | fi\_FI | | 法语(比利时) | fr\_BE | | 法语 | fr\_FR | | 希伯来语 | he\_IL | | 印地语 | hi\_IN | | 克罗地亚语 | hr\_HR | | 匈牙利 | hu\_HU | | 冰岛语 | is\_IS | | 印度尼西亚语 | id\_ID | | 意大利语 | it\_IT | | 日语 | ja\_JP | | 格鲁吉亚语 | ka\_GE | | 卡纳达语 | kn\_IN | | 韩语/朝鲜语 | ko\_KR | | 库尔德语 | ku\_IQ | | 拉脱维亚语 | lv\_LV | | 马来语 | ms\_MY | | 蒙古语 | mn\_MN | | 挪威 | nb\_NO | | 尼泊尔语 | ne\_NP | | 荷兰语(比利时) | nl\_BE | | 荷兰语 | nl\_NL | | 波兰语 | pl\_PL | | 葡萄牙语(巴西) | pt\_BR | | 葡萄牙语 | pt\_PT | | 斯洛伐克语 | sk\_SK | | 塞尔维亚 | sr\_RS | | 斯洛文尼亚 | sl\_SI | | 瑞典语 | sv\_SE | | 泰米尔语 | ta\_IN | | 泰语 | th\_TH | | 土耳其语 | tr\_TR | | 罗马尼亚语 | ro\_RO | | 俄罗斯语 | ru\_RU | | 乌克兰语 | uk\_UA | | 越南语 | vi\_VN | | 简体中文 | zh\_CN | | 繁体中文 | zh\_TW | ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、测试配置全局语言不生效[​](#1测试配置全局语言不生效 "1、测试配置全局语言不生效的直接链接") 一般场景下,你 **无需** 配置全局语言,因为浏览器访问会自动带上语言信息,比如中文浏览器自动返回中文,英文浏览器自动返回英文。 假如你明确希望测试全局设置的效果,请务必按下面操作: * 1、如果使用的是浏览器,请清空页面 cookie 再访问,因为 cookie 中会记录上一次用户的语言信息 * 2、如果使用的是 Postman 等工具,请不要带上 cookie 以及语言相关的 Header,Query 等字段 ### 2、测试返回的语言非预期[​](#2测试返回的语言非预期 "2、测试返回的语言非预期的直接链接") 请使用浏览器进行测试,不要使用 Postman。 由于 Postman 请求不会带有浏览器语言相关的 Header,所以服务端无法自动判断语言。 如果你一定要使用 Postman,请参考浏览器请求,加上 `Accept-Language` Header。 --- # 信息查看 Midway 提供了 info 组件,用于展示应用的基本信息,方便排查问题。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/info@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/info": "^3.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 info 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ // ... info ] }) export class MainConfiguration { //... } ``` 在有些情况下,为了不想让应用信息透出,我们指定在特殊环境下生效。 ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ koa, { component: info, enabledEnvironment: ['local'], // 只在本地启用 } ] }) export class MainConfiguration { //... } ``` ## 查看信息[​](#查看信息 "查看信息的直接链接") 在默认情况下,info 组件会为 Http 场景自动添加一个中间件,我们可以通过 `/_info` 来访问。 默认情况下,会展示系统,进程,以及配置等关键信息。 效果如下: ![info](https://img.alicdn.com/imgextra/i3/O1CN01TCkSvr28x8T7gtnCl_!!6000000007998-2-tps-797-1106.png) ## 修改访问路由[​](#修改访问路由 "修改访问路由的直接链接") 为了安全,我们可以调整访问的路由。 ``` // src/config/config.default.ts export default { // ... info: { infoPath: '/_my_info', } } ``` ## 隐藏信息[​](#隐藏信息 "隐藏信息的直接链接") 默认情况下,info 组件会隐藏秘钥等信息。我们可以配置增减隐藏的关键字,这个配置会对 **环境变量** 以及 **多环境配置** 生效。 关键字可以使用通配符,比如增加一些关键字。 ``` // src/config/config.default.ts import { DefaultHiddenKey } from '@midwayjs/info'; export default { // ... info: { hiddenKey: DefaultHiddenKey.concat(['*abc', '*def', '*bbb*']), } } ``` ## 调用 API[​](#调用-api "调用 API的直接链接") info 组件默认提供了 `InfoService` 用于在非 Http 或是自定义的场景来使用。 比如: ``` import { Provide } from '@midwayjs/core'; import { InfoService } from '@midwayjs/info'; @Provide() export class userService { @Inject() inforService: InfoService async getInfo() { // 应用信息,应用名等 this.inforService.projectInfo(); // 系统信息 this.inforService.systemInfo(); // 堆内存,cpu 等 this.inforService.resourceOccupationInfo(); // midway 框架的信息 this.inforService.softwareInfo(); // 当前使用的环境配置 this.inforService.midwayConfig(); // 依赖注入容器中的服务 this.inforService.midwayService(); // 系统时间,时区,启动时常 this.inforService.timeInfo(); // 环境变量 this.inforService.envInfo(); // 依赖信息 this.inforService.dependenciesInfo(); // 网络信息 this.inforService.networkInfo(); } } ``` --- # JWT `JSON Web Token` (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为`JSON`对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 Midway 提供了 jwt 组件,简单提供了一些 jwt 相关的 API,可以基于它做独立的鉴权和校验。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/jwt@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/jwt": "^3.0.0" // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 jwt 组件配置到代码中。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import { IMidwayContainer } from '@midwayjs/core'; import * as jwt from '@midwayjs/jwt'; @Configuration({ imports: [ // ... jwt, ], }) export class MainConfiguration { // ... } ``` ## 基础配置[​](#基础配置 "基础配置的直接链接") 然后在配置中设置,默认未加密。 ``` // src/config/config.default.ts export default { // ... jwt: { secret: 'xxxxxxxxxxxxxx', // fs.readFileSync('xxxxx.key') sign: { // signOptions expiresIn: '2d', // https://github.com/vercel/ms }, verify: { // verifyOptions }, decode: { // decodeOptions } }, }; ``` 更多配置请查看 ts 定义。 ## 常用 API[​](#常用-api "常用 API的直接链接") Midway 将 jwt 常用 API 提供为同步和异步两种形式。 ``` import { Provide, Inject } from '@midwayjs/core'; import { JwtService } from '@midwayjs/jwt'; @Provide() export class UserService { @Inject() jwtService: JwtService; async invoke() { // 同步 API this.jwtService.signSync(payload, secretOrPrivateKey, options); this.jwtService.verifySync(token, secretOrPublicKey, options); this.jwtService.decodeSync(token, options); // 异步 API await this.jwtService.sign(payload, secretOrPrivateKey, options); await this.jwtService.verify(token, secretOrPublicKey, options); await this.jwtService.decode(token, options); } } ``` 这些 API 都来自于 [node-jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) 基础库,如果不了解请阅读原版文档。 ## 中间件示例[​](#中间件示例 "中间件示例的直接链接") 一般,jwt 还会配合中间件来完成鉴权,下面是一个自定义 jwt 鉴权的中间件示例。 ``` // src/middleware/jwt.middleware import { Inject, Middleware, httpError } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/koa'; import { JwtService } from '@midwayjs/jwt'; @Middleware() export class JwtMiddleware { @Inject() jwtService: JwtService; public static getName(): string { return 'jwt'; } resolve() { return async (ctx: Context, next: NextFunction) => { // 判断下有没有校验信息 if (!ctx.headers['authorization']) { throw new httpError.UnauthorizedError(); } // 从 header 上获取校验信息 const parts = ctx.get('authorization').trim().split(' '); if (parts.length !== 2) { throw new httpError.UnauthorizedError(); } const [scheme, token] = parts; if (/^Bearer$/i.test(scheme)) { try { //jwt.verify方法验证token是否有效 await this.jwtService.verify(token, { complete: true, }); } catch (error) { //token过期 生成新的token const newToken = getToken(user); //将新token放入Authorization中返回给前端 ctx.set('Authorization', newToken); } await next(); } }; } // 配置忽略鉴权的路由地址 public match(ctx: Context): boolean { const ignore = ctx.path.indexOf('/api/admin/login') !== -1; return !ignore; } } ``` 然后在入口启用中间件即可。 ``` // src/configuration.ts import { Configuration, App, IMidwayContainer, IMidwayApplication} from '@midwayjs/core'; import * as jwt from '@midwayjs/jwt'; @Configuration({ imports: [ // ... jwt, ], }) export class MainConfiguration { @App() app: IMidwayApplication; async onReady(applicationContext: IMidwayContainer): Promise { // 添加中间件 this.app.useMiddleware([ // ... JwtMiddleware, ]); } } ``` ## 原始 JWT 对象[​](#原始-jwt-对象 "原始 JWT 对象的直接链接") 可以通过导出的 `Jwt` 对象引用到原始实例上的对象和方法。 ``` import { Jwt } from '@midwayjs/jwt'; // Jwt.TokenExpiredError ``` --- # Kafka 在复杂系统的架构中,事件流是很重要的一环,包括从事件源中(数据库、传感器、移动设备等)以事件流的方式去实时捕获数据,持久化事件流方便检索,并实时和回顾操作处理响应事件流。 应用于支付和金融交易、实施跟踪和监控汽车等行业信息流动、捕获分析物联网数据等等。 在 Midway中,我们提供了订阅 Kafka 的能力,专门来满足用户的这类需求。 相关信息: **订阅服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 基础概念[​](#基础概念 "基础概念的直接链接") 分布式流处理平台 * 发布订阅(流)信息 * 容错(故障转移)存储信息(流),存储事件流 * 在消息流发生的时候进行处理,处理事件流 理解 Producer(生产者) * 发布消息到一个主题或多个 topic (主题)。 理解 Consumer(主题消费者) * 订阅一个或者多个 topic,并处理产生的信息。 理解 Stream API * 充当一个流处理器,从 1 个或多个 topic 消费输入流,并生产一个输出流到1个或多个输出 topic,有效地将输入流转换到输出流。 理解 Broker * 已发布的消息保存在一组服务器中,称之为 Kafka 集群。集群中的每一个服务器都是一个代理(Broker)。 消费者可以订阅一个或多个主题(topic),并从Broker拉数据,从而消费这些已发布的消息。 ![image.png](https://kafka.apache.org/images/streams-and-tables-p1_p4.png) 提示 从 v3.19 开始,Kafka 组件做了一次重构,Kafka 组件的配置、使用方法和之前都有较大差异,原有使用方式兼容,但是文档不再保留。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 安装 `@midwayjs/kafka` 模块。 ``` $ npm i @midwayjs/kafka --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/kafka": "^3.0.0", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/kafka` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as kafka from '@midwayjs/kafka'; @Configuration({ imports: [ kafka ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as kafka from '@midwayjs/kafka'; @Configuration({ imports: [ koa, kafka ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 由于 Kafka 分为 **消费者(Consumer)** 和 **生产者(Producer)** 两部分,两个可以独立使用,我们将分别介绍。 ## 消费者(Consumer)[​](#消费者consumer "消费者(Consumer)的直接链接") ### 目录结构[​](#目录结构 "目录结构的直接链接") 我们一般把消费者放在 consumer 目录。比如 `src/consumer/user.consumer.ts` 。 ``` ➜ my_midway_app tree . ├── src │ ├── consumer │ │ └── user.consumer.ts │ ├── interface.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` ### 基础配置[​](#基础配置 "基础配置的直接链接") 通过 `consumer` 字段和 `@KafkaConsumer` 装饰器,我们可以配置多个消费者。 比如,下面的 `sub1` 和 `sub2` 就是两个不同的消费者。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { // ... }, sub2: { // ... }, } } } ``` 最简单的消费者配置需要几个字段,Kafka 的连接配置、消费者配置以及订阅配置。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { // ... }, consumerOptions: { // ... }, subscribeOptions: { // ... }, }, } } } ``` 比如: ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, consumerOptions: { groupId: 'groupId-test-1', }, subscribeOptions: { topics: ['topic-test-1'], } }, } } } ``` 完整可配置参数包括: * `connectionOptions`:Kafka 的连接配置,即 `new Kafka(consumerOptions)` 的参数 * `consumerOptions`:Kafka 的消费者配置,即 `kafka.consumer(consumerOptions)` 的参数 * `subscribeOptions`:Kafka 的订阅配置,即 `consumer.subscribe(subscribeOptions)` 的参数 * `consumerRunConfig`:消费者运行配置,即 `consumer.run(consumerRunConfig)` 的参数 这些参数的详细说明,可以参考 [KafkaJS Consumer](https://kafka.js.org/docs/consuming) 文档。 ### 复用 Kafka 实例[​](#复用-kafka-实例 "复用 Kafka 实例的直接链接") 如果如果需要复用 Kafka 实例,可以通过 `kafkaInstanceRef` 字段来指定。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, consumerOptions: { groupId: 'groupId-test-1', }, subscribeOptions: { topics: ['topic-test-1'], } }, sub2: { kafkaInstanceRef: 'sub1', consumerOptions: { groupId: 'groupId-test-2', }, subscribeOptions: { topics: ['topic-test-2'], } } } } } ``` 注意,上述的 `sub1` 和 `sub2` 是两个不同的消费者,但是它们共享同一个 Kafka 实例,且 `sub2` 的 `groupId` 需要和 `sub1` 不同。 用 Kafka SDK 写法类似如下: ``` const kafka = new Kafka({ clientId: 'my-app', brokers: ['localhost:9092'], }); const consumer1 = kafka.consumer({ groupId: 'groupId-test-1' }); const consumer2 = kafka.consumer({ groupId: 'groupId-test-2' }); ``` ### 消费者实现[​](#消费者实现 "消费者实现的直接链接") 我们可以在目录中提供一个标准的消费者实现,比如 `src/consumer/sub1.consumer.ts`。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachMessagePayload } from '@midwayjs/kafka'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { async eachMessage(payload: EachMessagePayload) { // ... } } ``` `sub1` 是消费者名称,使用的是配置中的 `sub1` 消费者。 也可以实现 `eachBatch` 方法,处理批量消息。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachBatchPayload } from '@midwayjs/kafka'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { async eachBatch(payload: EachBatchPayload) { // ... } } ``` ### 消息上下文[​](#消息上下文 "消息上下文的直接链接") 和其他消息订阅机制一样,消息本身通过 `Context` 字段来传递。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachMessagePayload, Context } from '@midwayjs/kafka'; import { Inject } from '@midwayjs/core'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { @Inject() ctx: Context; async eachMessage(payload: EachMessagePayload) { // ... } } ``` `Context` 字段包括几个属性: | 属性 | 类型 | 描述 | | ------------ | ------------------------------------ | ---------- | | ctx.payload | EachMessagePayload, EachBatchPayload | 消息内容 | | ctx.consumer | Consumer | 消费者实例 | 你可以通过 `ctx.consumer` 来调用 Kafka 的 API,比如 `ctx.consumer.commitOffsets` 来手动提交偏移量或者 `ctx.consumer.pause` 来暂停消费。 ## 生产者(Producer)[​](#生产者producer "生产者(Producer)的直接链接") ### 基础配置[​](#基础配置-1 "基础配置的直接链接") 服务生产者也需要创建实例,配置本身使用了 [服务工厂](/docs/service_factory.md) 的设计模式。 配置如下: ``` // src/config/config.default export default { kafka: { producer: { clients: { pub1: { // ... }, pub2: { // ... } } } } } ``` 每个 Producer 实例的配置,同样包括 `connectionOptions` 和 `producerOptions`。 ``` // src/config/config.default export default { kafka: { producer: { clients: { pub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, producerOptions: { // ... } } } } } } ``` 具体参数可以参考 [KafkaJS Producer](https://kafka.js.org/docs/producing) 文档。 此外,由于 Kafka Consumer 和 Producer 都可以从同一个 Kafka 实例创建,所以它们可以复用同一个 Kafka 实例。 Producer 后于 Consumer 创建,也同样可以使用 `kafkaInstanceRef` 字段来复用 Kafka 实例。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, } }, producer: { clients: { pub1: { kafkaInstanceRef: 'sub1', } } } } } ``` ### 使用 Producer[​](#使用-producer "使用 Producer的直接链接") Producer 不存在默认实例,由于使用了服务工厂的设计模式,所以可以通过 `@InjectClient()` 来注入。 ``` // src/service/user.service.ts import { Provide, InjectClient } from '@midwayjs/core'; import { KafkaProducerFactory, Producer } from '@midwayjs/kafka'; @Provide() export class UserService { @InjectClient(KafkaProducerFactory, 'pub1') producer: Producer; async invoke() { await this.producer.send({ topic: 'topic-test-1', messages: [{ key: 'message-key1', value: 'hello consumer 11 !' }], }); } } ``` ## Admin[​](#admin "Admin的直接链接") Kafka 的 Admin 功能,可以用来创建、删除、查看主题,查看配置和 ACL 等。 ### 基础配置[​](#基础配置-2 "基础配置的直接链接") 和 Producer 类似,Admin 也使用了服务工厂的设计模式。 ``` // src/config/config.default export default { kafka: { admin: { clients: { admin1: { // ... } } } } } ``` 同样的,Admin 也可以复用 Kafka 实例。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, } }, admin: { clients: { admin1: { kafkaInstanceRef: 'sub1', } } } } } ``` ### 使用 Admin[​](#使用-admin "使用 Admin的直接链接") Admin 不存在默认实例,由于使用了服务工厂的设计模式,所以可以通过 `@InjectClient()` 来注入。 ``` // src/service/admin.service.ts import { Provide, InjectClient } from '@midwayjs/core'; import { KafkaAdminFactory, Admin } from '@midwayjs/kafka'; @Provide() export class AdminService { @InjectClient(KafkaAdminFactory, 'admin1') admin: Admin; } ``` 更多的 Admin 使用方法,可以参考 [KafkaJS Admin](https://kafka.js.org/docs/admin) 文档。 ## 组件日志[​](#组件日志 "组件日志的直接链接") Kafka 组件默认使用 `kafkaLogger` 日志,默认会将 `ctx.logger` 记录在 `midway-kafka.log`。 你可以通过配置修改。 ``` // src/config/config.default export default { midwayLogger: { clients: { kafkaLogger: { fileLogName: 'midway-kafka.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { kafka: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.message}`; }, } } ``` ## 获取 KafkaJS 模块[​](#获取-kafkajs-模块 "获取 KafkaJS 模块的直接链接") KafkaJS 模块,可以通过 `@midwayjs/kafka` 的 `KafkaJS` 字段来获取。 ``` import { KafkaJS } from '@midwayjs/kafka'; const { ConfigResourceTypes } = KafkaJS; // ... ``` ## 关于分区的警告[​](#关于分区的警告 "关于分区的警告的直接链接") 如果你使用的是 KafkaJS 的 v2.0.0 版本,你可能会看到如下的警告: ``` 2024-11-04 23:47:28.228 WARN 31729 KafkaJS v2.0.0 switched default partitioner. To retain the same partitioning behavior as in previous versions, create the producer with the option "createPartitioner: Partitioners.LegacyPartitioner". See the migration guide at https://kafka.js.org/docs/migration-guide-v2.0.0#producer-new-default-partitioner for details. Silence this warning by setting the environment variable "KAFKAJS_NO_PARTITIONER_WARNING=1" { timestamp: '2024-11-04T15:47:28.228Z', logger: 'kafkajs' } ``` 这个警告是由于 KafkaJS 的 v2.0.0 版本默认使用了新的分区器,如果接受新的分区器行为,但想要关闭这个警告消息,可以通过设置环境变量 `KAFKAJS_NO_PARTITIONER_WARNING=1` 来消除这个警告。 或者显示声明分区器。 ``` // src/config/config.default import { KafkaJS } from '@midwayjs/kafka'; const { Partitioners } = KafkaJS; export default { kafka: { producer: { clients: { pub1: { // ... producerOptions: { createPartitioner: Partitioners.DefaultPartitioner, // ... createPartitioner: Partitioners.LegacyPartitioner, }, }, }, }, } } ``` 建议你查看 KafkaJS v2.0.0 的 [迁移指南](https://kafka.js.org/docs/migration-guide-v2.0.0#producer-new-default-partitioner) 了解更多细节。 ## 参考文档[​](#参考文档 "参考文档的直接链接") * [KafkaJS](https://kafka.js.org/docs/introduction) * [apache kafka官网](https://kafka.apache.org/intro) --- # Koa Koa 是一个非常轻量易用的 Web 框架。本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 Midway 默认的示例都是基于该包。 `@midwayjs/koa` 包默认使用 `koa@2` 以及集成了 `@koa/router` 作为路由基础能力,并默认内置了 `session` 和 `body-parser` 功能。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/koa@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/koa": "^3.0.0", // ... }, } ``` 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=koa-v3 my_project # npm v7 $ npm init midway -- --type=koa-v3 my_project ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { join } from 'path'; @Configuration({ imports: [koa], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... } } ``` ## BodyParser[​](#bodyparser "BodyParser的直接链接") `@midwayjs/koa` 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 和 `form` 类型。 如需 text 或者 xml,可以自行配置。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { enableTypes: ['json', 'form', 'text', 'xml'], formLimit: '1mb', jsonLimit: '1mb', textLimit: '1mb', xmlLimit: '1mb', }, } ``` 注意,使用 Postman 做 Post 请求时的类型选择: ![postman](https://img.alicdn.com/imgextra/i4/O1CN01QCdTsN1S347SuzZU5_!!6000000002190-2-tps-1017-690.png) 关闭 bodyParser 中间件。 ``` // src/config/config.default export default { // ... bodyParser: { enable: false, // ... }, } ``` ## Cookie 和 Session[​](#cookie-和-session "Cookie 和 Session的直接链接") `@midwayjs/koa` 默认封装了 `cookies` 解析和 `Session` 的支持,可以查看 [Cookies 和 Session](/docs/3.0.0/cookie_session.md)。 ## 扩展 Context[​](#扩展-context "扩展 Context的直接链接") 在一些场景下,需要对 Context 做扩展。 如果希望挂在一些临时的请求相关的对象数据,可以使用 `ctx.setAttr(key, value)` API 来实现,比如组件里自用的数据。 如果实在有扩展 Context 的诉求,可以使用 koa 自带的 API。 比如,我们在 `configuration.ts` 中做扩展提供了一个 `render()` 方法。 ``` import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady(container) { Object.defineProperties(app.context, { render: { value: async function (...args) { // ... }, }, }); } } ``` 但是这样做无法直接让 Context 包含 Typescript 定义,需要额外增加定义,请参考 [扩展上下文定义](/docs/3.0.0/context_definition.md)。 ## 获取 Http Server[​](#获取-http-server "获取 Http Server的直接链接") 在一些特殊情况下,你需要获取到原始的 Http Server,我们可以在服务器启动后获取。 ``` import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @Inject() framework: koa.Framework; async onServerReady(container) { const server = this.framework.getServer(); // ... } } ``` ## State 类型定义[​](#state-类型定义 "State 类型定义的直接链接") 在 koa 的 Context 中有一个特殊的 State 属性,通过和 Context 类似的方式可以扩展 State 定义。 ``` // src/interface.ts declare module '@midwayjs/koa/dist/interface' { interface Context { abc: string; } interface State{ bbb: string; ccc: number; } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/koa` 的配置样例如下: ``` // src/config/config.default export default { // ... koa: { port: 7001, }, } ``` 所有属性描述如下: | 属性 | 类型 | 描述 | | --------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | port | number | 可选,启动的端口 | | globalPrefix | string | 可选,全局的 http 前缀 | | keys | string\[] | 可选,Cookies 签名,如果上层未写 keys,也可以在这里设置 | | hostname | string | 可选,监听的 hostname,默认 127.1 | | key | string \| Buffer \| Array\ | 可选,Https key,服务端私钥 | | cert | string \| Buffer \| Array\ | 可选,Https cert,服务端证书 | | ca | string \| Buffer \| Array\ | 可选,Https ca | | http2 | boolean | 可选,http2 支持,默认 false | | proxy | boolean | 可选,是否开启代理,如果为 true 则对于 request 请求中的 ip 优先从 Header 字段中 X-Forwarded-For 获取,默认 false | | subdomainOffset | number | 可选,子域名的偏移量,默认 2 | | proxyIpHeader | string | 可选,获取代理 ip 的字段名,默认为 X-Forwarded-For | | maxIpsCount | number | 可选,获取的 ips 最大数量,默认为 0(全部返回) | | serverTimeout | number | 可选,服务端超时配置,默认为 2 \* 60 \* 1000(2 分钟),单位毫秒 | | serverOptions | Record\ | 可选,http Server [选项](https://nodejs.org/docs/latest/api/http.html#httpcreateserveroptions-requestlistener) | ### 修改端口[​](#修改端口 "修改端口的直接链接") 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 koa http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... koa: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/3.0.0/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### 反向代理配置[​](#反向代理配置 "反向代理配置的直接链接") 如果使用了 Nginx 等反向代理,请开启 `proxy` 配置。 ``` // src/config/config.default export default { // ... koa: { proxy: true, }, } ``` 默认使用 `X-Forwarded-For` Header,如果代理配置不同,请自行配置不同的 Header。 ``` // src/config/config.default export default { // ... koa: { proxy: true, proxyIpHeader: 'X-Forwarded-Host' }, } ``` ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... koa: { key: join(__dirname, '../ssl/ssl.key'), cert: join(__dirname, '../ssl/ssl.pem'), }, } ``` ### favicon 设置[​](#favicon-设置 "favicon 设置的直接链接") 默认情况下,浏览器会发起一个 `favicon.ico` 的请求。 框架提供了一个默认中间件,用来处理该请求,你可以指定一个 `favicon` 的 Buffer。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... siteFile: { favicon: readFileSync(join(__dirname, '../static/fav.ico')), }, } ``` 如果开启了 `@midwayjs/static-file` 组件,那么会优先使用组件的静态文件托管。 关闭中间件。 ``` // src/config/config.default export default { // ... siteFile: { enable: false, // ... }, } ``` ### 修改上下文日志[​](#修改上下文日志 "修改上下文日志的直接链接") 可以单独修改 koa 框架的上下文日志。 ``` export default { koa: { contextLoggerFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... }, }; ``` ### Query 数组解析[​](#query-数组解析 "Query 数组解析的直接链接") 默认情况下,koa 使用 `querystring` 解析 query 参数,当碰到数组时,会将数组的数据拆开。 比如: ``` GET /query?a[0]=1&a[1]=2 ``` 拿到的结果是: ``` { "a[0]": 1, "a[1]": 2, } ``` 框架提供了一些参数来处理这种情况。 ``` // src/config/config.default export default { // ... koa: { queryParseMode: 'extended', // ... }, } ``` `queryParseMode` 参数可以选择 `extended`、 `strict`、`first` 三种值。 当 `queryParseMode` 有值时,会使用 `qs` 模块处理 query,效果同 `koa-qs` 模块。 当请求参数为 `/query?a=1&b=2&a=3&c[0]=1&c[1]=2'` 时。 默认效果(使用 `querystring`) ``` { "a": ["1", "3" ], "b": "2", "c[0]": "1", "c[1]": "2" } ``` `extended` 效果 ``` { "a": ["1", "3" ], "b": ["2"], "c": ["1", "2"] } ``` `strict` 效果 ``` { "a": ["1", "3" ], "b": "2", "c": ["1", "2"] } ``` `first` 效果 ``` { "a": "1", "b": "2", "c": "1" } ``` ### 超时配置[​](#超时配置 "超时配置的直接链接") RequestTiemout 和 ServerTimeout 是两种不同的超时情况。 * `serverTimeout`:用于设置服务器接收到请求后,等待客户端发送数据的超时时间。如果在该时间内客户端没有发送任何数据,则服务器将关闭连接。此超时适用于整个请求-响应周期,包括请求头、请求主体以及响应。 * `requestTimeout`:用于设置服务器等待客户端发送完整请求的超时时间。这个超时是针对请求头和请求主体的,服务器将在该时间内等待客户端发送完整的请求。如果在超时时间内没有收到完整的请求,则服务器将中止该请求。 默认情况下,`serverTimeout` 为 0,不会触发超时。 如有需求,可以通过配置修改,单位毫秒。 ``` // src/config/config.default export default { // ... koa: { serverTimeout: 100_000 }, } ``` 如果程序出现 `ERR_HTTP_REQUEST_TIMEOUT` 这个错误,说明是触发了 `requestTimeout`,默认为 `300_000` (五分钟),单位毫秒,可以通过以下配置修改。 ``` // src/config/config.default export default { // ... koa: { serverOptions: { requestTimeout: 600_000 } }, } ``` --- # MikroORM 本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。 MikroORM 的官网文档在 [这里](https://mikro-orm.io/docs)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 关于升级[​](#关于升级 "关于升级的直接链接") * 从 `v3.14.0` 版本的组件开始,支持 mikro v5/v6 版本,由于 mikro v5 到 v6 有较大的变化,如从 mikro 老版本升级请提前阅读 [Upgrading from v5 to v6](https://mikro-orm.io/docs/upgrading-v5-to-v6) * 组件示例已更新为 v6 版本 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 mikro 组件,提供接入 mikro-orm 的能力。 ``` $ npm i @midwayjs/mikro@3 @mikro-orm/core --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/mikro": "^3.0.0", "@mikro-orm/core": "^6.0.2", // ... }, "devDependencies": { // ... } } ``` 同时,还需要引入对应数据库的适配包。 比如: ``` { "dependencies": { // sqlite "@mikro-orm/sqlite": "^6.0.2", // mysql "@mikro-orm/mysql": "^6.0.2", }, "devDependencies": { // ... } } ``` 更多驱动程序请查看 [官方文档](https://mikro-orm.io/docs/usage-with-sql/)。 ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 mikro 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mikro from '@midwayjs/mikro'; import { join } from 'path'; @Configuration({ imports: [ // ... mikro // 加载 mikro 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ## 基础使用[​](#基础使用 "基础使用的直接链接") 和其他 orm 框架类似,都是分为几个步骤: * 1、定义 Entity * 2、配置数据源 * 3、获取 EntityModel 进行调用 下面的更多 Entity 代码请查看 [示例](https://github.com/midwayjs/midway/tree/main/packages/mikro/test/fixtures/base-fn-origin)。 ### 目录结构[​](#目录结构 "目录结构的直接链接") 一个基础的参考目录结构如下。 ``` MyProject ├── src │ ├── config │ │ └── config.default.ts │ ├── entity │ │ ├── book.entity.ts │ │ ├── index.ts │ │ └── base.ts │ ├── configuration.ts │ └── service ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` ### 定义 Entity[​](#定义-entity "定义 Entity的直接链接") 定义基础的 Entity。 ``` // src/entity/BaseEntity.ts import { PrimaryKey, Property } from '@mikro-orm/core'; export abstract class BaseEntity { @PrimaryKey() id!: number; @Property() createdAt: Date = new Date(); @Property({ onUpdate: () => new Date() }) updatedAt: Date = new Date(); } ``` 定义实际的 Entity,包含一对多,多对多等关系。 ``` // src/entity/book.entity.ts import { Cascade, Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core'; import { Author, BookTag, Publisher } from './index'; import { BaseEntity } from './base'; @Entity() export class Book extends BaseEntity { @Property() title: string; @ManyToOne(() => Author) author: Author; @ManyToOne(() => Publisher, { cascade: [Cascade.PERSIST, Cascade.REMOVE], nullable: true }) publisher?: Publisher; @ManyToMany(() => BookTag) tags = new Collection(this); @Property({ nullable: true }) metaObject?: object; @Property({ nullable: true }) metaArray?: any[]; @Property({ nullable: true }) metaArrayOfStrings?: string[]; constructor(title: string, author: Author) { super(); this.title = title; this.author = author; } } ``` ### 配置数据源[​](#配置数据源 "配置数据源的直接链接") mikro v5 和 v6 略有不同。 * mikro v6 * mikro v5 ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { join } from 'path'; import { SqliteDriver } from '@mikro-orm/sqlite'; export default (appInfo) => { return { mikro: { dataSource: { default: { dbName: join(__dirname, '../../test.sqlite'), driver: SqliteDriver, // 这里使用了 sqlite 做示例 allowGlobalContext: true, // 实体形式 entities: [Author, Book, BookTag, Publisher, BaseEntity], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], } } } } } ``` ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { join } from 'path'; export default (appInfo) => { return { mikro: { dataSource: { default: { dbName: join(__dirname, '../../test.sqlite'), type: 'sqlite', // 这里使用了 sqlite 做示例 allowGlobalContext: true, // 实体形式 entities: [Author, Book, BookTag, Publisher, BaseEntity], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], } } } } } ``` 提示 mikro 的 `entities` 字段配置已经经过框架处理,该字段配置请不要参考原始文档。 ### 增删查改[​](#增删查改 "增删查改的直接链接") 在业务代码中,可以使用 `InjectRepository` 注入 `Repository` 对象执行简单的查询操作。其它的增删改操作可以通过配合`EntityManger `的 `persist` 和 `flush` 接口来实现,使用 `InjectEntityManager` 可以直接注入 `EntityManager` 对象,也可以通过`repository.getEntityManager()`获取。 警告 * 1、从 5.7 版本开始,MikroORM 将原来 `Repository` 上 `persist` 和 `flush` 等接口标为*弃用*,并计划在 v6 版本中 [彻底移除](https://github.com/mikro-orm/mikro-orm/discussions/3989),建议直接调用`EntityManager`上的相关接口 * 2、v6 已经彻底 [弃用](https://mikro-orm.io/docs/upgrading-v5-to-v6#removed-methods-from-entityrepository) 上述接口 ``` // src/service/book.service.ts import { Book } from './entity/book.entity'; import { Provide } from '@midwayjs/core'; import { InjectEntityManager, InjectRepository } from '@midwayjs/mikro'; import { QueryOrder } from '@mikro-orm/core'; import { EntityManager, EntityRepository } from '@mikro-orm/mysql'; // 需要使用数据库驱动对应的类来执行操作 @Provide() export class BookService { @InjectRepository(Book) bookRepository: EntityRepository; @InjectEntityManager() em: EntityManager; async queryByRepo() { // 使用Repository查询 const books = await this.bookRepository.findAll({ populate: ['author'], orderBy: { title: QueryOrder.DESC }, limit: 20, }); return books; } async createBook() { const book = new Book({ title: 'b1', author: { name: 'a1', email: 'e1' } }); // 标记保存Book this.em.persist(book); // 执行所有变更 await this.em.flush(); return book; } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的数据源对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { MikroDataSourceManager } from '@midwayjs/mikro'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(MikroDataSourceManager); const orm = dataSourceManager.getDataSource('default'); const connection = orm.em.getConnection(); // ... } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/mikro'; import { MikroORM, IDatabaseDriver, Connection } from '@mikro-orm/core'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: MikroORM>; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: MikroORM>; async onReady(container: IMidwayContainer) { // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 可以通过配置将 midway 的 logger 添加到 mikro 中,用于记录 sql 等信息。 ``` // src/config/config.default.ts exporg default { midwayLogger: { clients: { mikroLogger: { // ... } } }, mikro: { dataSource: { default: { entities: [Author, Book, BookTag, Publisher, BaseEntity], // ... logger: 'mikroLogger', } }, } } ``` 默认情况下 mikro 自带颜色,也会将其写入文件,可以通过配置关闭。 ``` // src/config/config.default.ts exporg default { midwayLogger: { clients: { mikroLogger: { transports: { console: { autoColors: false, }, file: { fileLogName: 'mikro.log', }, }, } } }, mikro: { dataSource: { default: { entities: [Author, Book, BookTag, Publisher, BaseEntity], // ... logger: 'mikroLogger', colors: false, } }, } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Node 版本[​](#1node-版本 "1、Node 版本的直接链接") Mikro-orm 对 Node 版本有一些限制,必须为 `>=14.0.0` ,所以 `@midwayjs/mikro` 组件的使用规则也如此。 ### 2、Identity Map[​](#2identity-map "2、Identity Map的直接链接") Mikro-orm 内部查询有一个 [Identity Map](https://mikro-orm.io/docs/identity-map) 的概念,Midway 已经在所有的内置 Framework 的中间件内置加入了该功能,如果在非请求链路调用场景下使用,比如 `src/configuration` 中,可以开启 `allowGlobalContext` 选项。 ### 3、多库的支持[​](#3多库的支持 "3、多库的支持的直接链接") 和其他数据库一样,Midway 支持多数据源的配置。 ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { SqlHighlighter } from '@mikro-orm/sql-highlighter'; import { join } from 'path'; export default (appInfo) => { return { mikro: { dataSource: { custom1: { // ... }, custom2: { // ... } } } } } ``` 注意在使用时,需要传递来自哪个数据源。 ``` // ... @Provide() export class BookController { @InjectRepository(Book, 'custom1') bookRepository: EntityRepository; async findBookAndQuery() { // ... } } ``` --- # MongoDB 在这一章节中,我们选择 [Typegoose](https://github.com/typegoose/typegoose) 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 简单的来说,Typegoose 使用 TypeScript 编写 Mongoose 模型的 “包装器”,它的大部分能力还是由 [mongoose](https://www.npmjs.com/package/mongoose) 库来提供的。 也可以直接选择 [mongoose](https://www.npmjs.com/package/mongoose) 库来使用,我们会分别描述。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | 提示 * 1、当前模块从 v3.4.0 开始已经重构,历史写法兼容,如果查询历史文档,请参考 [这里](/docs/3.0.0/legacy/mongodb.md)。 * 2、如果代码中有读取配置,注意 `mongoose.clients` 可能会读不到,请使用 `mongoose.dataSource`。 ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 如果想使用新版本的用法,请参考下面的流程,将老代码进行修改,新老代码请勿混用。 升级方法: * 1、无需再使用 `EntityModel` 装饰器 * 3、在 `src/config.default` 的 `mongoose` 部分配置调整,参考下面的数据源配置部分 * 3.1 修改为数据源的形式 `mongoose.dataSource` * 3.2 将实体模型在数据源的 `entities` 字段中声明 ## Mongoose 版本依赖[​](#mongoose-版本依赖 "Mongoose 版本依赖的直接链接") mongoose 和你服务器使用的 MongoDB Server 的版本也有着一定的关系,如下,请务必注意。 * MongoDB Server 2.4.x: mongoose ^3.8 or 4.x * MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x * MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x * MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x * MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x * MongoDB Server 3.6.x: mongoose 5.x * MongoDB Server 4.0.x: mongoose ^5.2.0 * MongoDB Server 4.2.x: mongoose ^5.7.0 * MongoDB Server 4.4.x: mongoose ^5.10.0 * MongoDB Server 5.x: mongoose ^6.0.0 **mongoose 相关的依赖比较复杂,且对应不同的版本,现阶段,我们使用的主要是 mongoose v5 和 v6。** 信息 从 mongoose\@v5.11.0 开始,mongoose 官方支持了定义,所以不再需要安装 @types/mongoose 依赖包。 安装包依赖版本如下: **支持 MongoDB Server 6.x** ``` "dependencies": { "mongoose": "^7.0.0", "@typegoose/typegoose": "^10.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 5.x** ``` "dependencies": { "mongoose": "^6.0.7", "@typegoose/typegoose": "^9.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 4.4.x** 以下版本不需要安装额外定义包。 ``` "dependencies": { "mongoose": "^5.13.3", "@typegoose/typegoose": "^8.0.0", // 使用 typegoose 需要安装此依赖 }, ``` 以下版本需要安装额外定义包(不推荐)。 ``` "dependencies": { "mongodb": "3.6.3", // mongoose 内部写死了该版本 "mongoose": "~5.10.18", "@typegoose/typegoose": "^7.0.0", // 使用 typegoose 需要安装此依赖 }, "devDependencies": { "@types/mongodb": "3.6.3", // 只能使用此版本 "@types/mongoose": "~5.10.3", } ``` 其余的 MongoDB 安装模块类似,未测。 ## 使用 Typegoose[​](#使用-typegoose "使用 Typegoose的直接链接") ### 1、安装组件[​](#1安装组件 "1、安装组件的直接链接") 安装 Typegoose 组件,提供访问 MongoDB 的能力。 **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/typegoose@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/typegoose": "^3.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; @Configuration({ imports: [ typegoose // 加载 typegoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` 信息 在该组件中,midway 只是做了简单的配置规则化,并将其注入到初始化流程中。 ### 2、简单的目录结构[​](#2简单的目录结构 "2、简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── user.ts // 实体文件 │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ### 3、创建实体文件[​](#3创建实体文件 "3、创建实体文件的直接链接") 比如在 `src/entity/user.ts` 中。 ``` import { prop } from '@typegoose/typegoose'; export class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 等价于使用 mongoose 的下列代码 ``` const userSchema = new mongoose.Schema({ name: String, jobs: [{ type: String }] }); const User = mongoose.model('User', userSchema); ``` 信息 所以说,typegoose 只是简化了 model 的创建过程。 ### 4、配置连接信息[​](#4配置连接信息 "4、配置连接信息的直接链接") 在 `src/config/config.default.ts` 中加入连接的配置。 ``` import { User } from '../entity/user'; export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, // 关联实体 entities: [ User ] } } }, } ``` 如需以目录扫描形式关联,请参考 [数据源管理](/docs/3.0.0/data_source.md)。 ### 5、引用实体,调用数据库[​](#5引用实体调用数据库 "5、引用实体,调用数据库的直接链接") 示例代码如下: ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typegoose'; import { ReturnModelType } from '@typegoose/typegoose'; import { User } from '../entity/user'; @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; async getTest(){ // create data const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties // find data const user = await this.userModel.findById(id).exec(); console.log(user) } } ``` ### 6、多库的情况[​](#6多库的情况 "6、多库的情况的直接链接") 首先定义多个实体。 ``` class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } class User2 { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 将实体配置到多个数据源。 在 `src/config/config.default.ts` 中加入数据源的配置。 ``` import { User, User2 } from '../entity/user'; export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, entities: [ User ] }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, entities: [ User2 ] } } }, } ``` 定义实例时使用固定的连接,在扫描 dataSource 配置 Model 会自动关联 mongoose连接(`getModelForClass(Model, { existingConnection: conn })`)。 ``` @Provide() export class TestService{ @InjectEntityModel(User) userModel: ReturnModelType; @InjectEntityModel(User2) user2Model: ReturnModelType; async getTest(){ const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties const user = await this.userModel.findById(id).exec(); console.log(user) const { _id: id2 } = await this.user2Model.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User2); // an "as" assertion, to have types for all properties const user2 = await this.user2Model.findById(id2).exec(); console.log(user2) } } ``` ### 7、关于 schemaOptions[​](#7关于-schemaoptions "7、关于 schemaOptions的直接链接") Typegoose 预留了一个 `setGlobalOptions` 方法用来设置 [schemaOptions](https://typegoose.github.io/typegoose/docs/api/decorators/model-options#schemaoptions) 和一些其他全局性的 [配置](https://typegoose.github.io/typegoose/docs/api/decorators/model-options#options-1)。 我们可以在项目配置加载时设置它。 ``` // srcconfiguration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; import * as Typegoose from '@typegoose/typegoose'; @Configuration({ // ... }) export class MainConfiguration { async onConfigLoad() { Typegoose.setGlobalOptions({ schemaOptions: { // ... }, options: { allowMixed: Severity.ERROR } }); // ... } } ``` ## 直接使用 mongoose[​](#直接使用-mongoose "直接使用 mongoose的直接链接") mongoose 组件是 typegoose 的基础组件,有时候我们可以直接使用它。 ### 1、安装组件[​](#1安装组件-1 "1、安装组件的直接链接") **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/mongoose@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/mongoose": "^3.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` ### 2、开启组件[​](#2开启组件 "2、开启组件的直接链接") 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mongoose from '@midwayjs/mongoose'; @Configuration({ imports: [ mongoose // 加载 mongoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ### 2、配置[​](#2配置 "2、配置的直接链接") 和 typegoose 相同,或者说 typegoose 使用的就是 mongoose 的配置。 不管是单库还是多库,数据源配置都是类似的。 单库: ``` export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '**********' } } } }, } ``` 多库: ``` export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` ### 3、使用[​](#3使用 "3、使用的直接链接") 当我们希望获取到原始的连接对象时,可以直接使用封装好的 `MongooseConnectionService` 对象。 ``` import { Provide, Inject, Init } from '@midwayjs/core'; import { MongooseDataSourceManager } from '@midwayjs/mongoose'; import { Schema, Document } from 'mongoose'; interface User extends Document { name: string; email: string; avatar: string; } @Provide() export class TestService { @Inject() dataSourceManager: MongooseDataSourceManager; @Init() async init() { // get default connection this.conn = this.dataSourceManager.getDataSource('default'); } async invoke(){ const schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, avatar: String }); const UserModel = this.conn.model('User', schema); const doc = new UserModel({ name: 'Bill', email: 'bill@initech.com', avatar: 'https://i.imgur.com/dM7Thhn.png' }); await doc.save(); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、E002: You are using a NodeJS Version below 12.22.0[​](#1e002-you-are-using-a-nodejs-version-below-12220 "1、E002: You are using a NodeJS Version below 12.22.0的直接链接") 在新版本 @typegoose/typegoose (v8, v9) 中增加了 Node 版本的校验,如果你的 Node.js 版本低于 v12.22.0,就会出现这个提示。 普通情况下,请升级 Node.js 到这个版本以上即可解决。 在特殊场景下,比如 Serverless 无法修改 Node.js 版本且版本低于 v12.22 的情况下,由于 v12 版本子版本其实都可以,可以通过临时修改 process.version 绕过。 ``` // src/configuration.ts Object.defineProperty(process, 'version', { value: 'v12.22.0', writable: true, }); // other code export class MainConfiguration {} ``` --- # MQTT MQTT是用于物联网 (IoT) 的OASIS标准消息传递协议。它被设计为非常轻量级的发布/订阅消息传输,非常适合以较小的代码占用空间和最小的网络带宽连接远程设备。MQTT目前广泛应用于汽车、制造、电信、石油和天然气等行业。 相关信息: | 描述 | | | ----------------- | ------------ | | 可用于标准项目 | ✅ | | 可用于 Serverless | 可以发布消息 | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 版本要求[​](#版本要求 "版本要求的直接链接") 由于 [mqtt](https://github.com/mqttjs/MQTT.js) 库本身的要求,所需要的版本为 **Node.js >= 16** ## 前置依赖[​](#前置依赖 "前置依赖的直接链接") 由于 MQTT 需要 Broker 作为中转传输,你需要自行部署 MQTT Broker 服务,本文档不提供 MQTT 服务本身的部署指导。 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 mqtt 组件。 ``` $ npm i @midwayjs/mqtt@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/mqtt": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件 ``` // ... import * as mqtt from '@midwayjs/mqtt'; @Configuration({ imports: [ // ...other components mqtt, ], }) export class MainConfiguration {} ``` 由于 MQTT 分为 **订阅者(subscriber)** 和 \*\*发布者(publisher)\*\*两部分,两个可以独立使用,我们将分别介绍。 ## 订阅服务[​](#订阅服务 "订阅服务的直接链接") ### 基础配置[​](#基础配置 "基础配置的直接链接") 通过 `sub` 字段和 `@MqttSubscriber` 装饰器,我们可以配置多个订阅者。 比如,下面的 `sub1` 和 `sub2` 就是两个不同的订阅者。 ``` // src/config/config.default export default { mqtt: { sub: { sub1: { // ... }, sub2: { // ... } } } } ``` 最简单的订阅者配置需要几个字段,订阅的地址和订阅的 Topic。 ``` // src/config/config.default export default { mqtt: { sub: { sub1: { connectOptions: { host: 'test.mosquitto.org', port: 1883, }, subscribeOptions: { topicObject: 'test', }, }, sub2: { // ... } } } } ``` `sub1` 订阅者配置了 `connectOptions` 和 `subscribeOptions` ,分别代表连接配置和订阅配置。 ### 订阅实现[​](#订阅实现 "订阅实现的直接链接") 我们可以在目录中提供一个标准的订阅器实现,比如 `src/consumer/sub1.subscriber.ts`。 ``` // src/consumer/sub1.subscriber.ts import { ILogger, Inject } from '@midwayjs/core'; import { Context, IMqttSubscriber, MqttSubscriber } from '@midwayjs/mqtt'; @MqttSubscriber('sub1') export class Sub1Subscriber implements IMqttSubscriber { @Inject() ctx: Context; async subscribe() { // ... } } ``` `@MqttSubscriber` 装饰器声明了一个订阅类实现,它的参数为订阅者的名字,比如我们配置文件中的 `sub1`。 `IMqttSubscriber` 接口约定了一个 `subscribe` 方法,每当接收到新的消息时,这个方法就会被执行。 和其他消息订阅机制一样,消息本身通过 `Context` 字段来传递。 ``` // ... export class Sub1Subscriber implements IMqttSubscriber { @Inject() ctx: Context; async subscribe() { const payload = this.ctx.message.toString(); // ... } } ``` `Context` 字段包括几个 mqtt 属性。 | 属性 | 类型 | 描述 | | ----------- | ------------------------------ | ---------------- | | ctx.topic | string | 订阅 Topic | | ctx.message | Buffer | 消息内容 | | ctx.packet | IPublishPacket(来自 mqtt 库) | publish 的包信息 | ## 消息发布[​](#消息发布 "消息发布的直接链接") ### 基础配置[​](#基础配置-1 "基础配置的直接链接") 消息发布也需要创建实例,配置本身使用了 [服务工厂](/docs/service_factory.md) 的设计模式。 比如多实例配置如下: ``` // src/config/config.default export default { mqtt: { pub: { clients: { default: { host: 'test.mosquitto.org', port: 1883, }, pub2: { // ... } } } } } ``` 上面的配置创建了名为 `default` 和 `pub2` 的两个实例。 ### 使用发布者[​](#使用发布者 "使用发布者的直接链接") 如果实例名为 `default` ,则可以使用默认的消息发布类。 比如: ``` // src/service/user.service.ts import { Provide, Inject } from '@midwayjs/core'; import { DefaultMqttProducer } from '@midwayjs/mqtt'; @Provide() export class UserService { @Inject() producer: DefaultMqttProducer; async invoke() { // 同步发布消息 this.producer.publish('test', 'hello world'); // 异步发布 await this.producer.publishAsync('test', 'hello world'); // 增加配置 await this.producer.publishAsync('test', 'hello world', { qos: 2 }); } } ``` 也可以使用内置的工厂类 `MqttProducerFactory` 注入不同的实例。 ``` // src/service/user.service.ts import { Provide, Inject } from '@midwayjs/core'; import { MqttProducerFactory, DefaultMqttProducer } from '@midwayjs/mqtt'; @Provide() export class UserService { @InjectClient(MqttProducerFactory, 'pub2') producer: DefaultMqttProducer; async invoke() { // ... } } ``` ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-mqtt.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { // ... mqttLogger: { fileLogName: 'midway-mqtt.log', }, } } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { mqtt: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.message}`; }, } } ``` --- # TypeORM [TypeORM](https://github.com/typeorm/typeorm) 是 `node.js` 现有社区最成熟的对象关系映射器(`ORM` )。本文介绍如何在 Midway 中使用 TypeORM 。 提示 本模块是从 v3.4.0 开始为新版本,模块名有变化,历史写法部分兼容,如果查询历史文档,请参考 [这里](/docs/3.0.0/legacy/orm.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 旧模块为 `@midwayjs/orm` ,新模块为 `@midwayjs/typeorm`,区别如下: * 1、包名不同 * 2、在 `src/config.default` 的部分配置调整 * 2.1 配置文件中的 key 不同 (orm => typeorm) * 2.2修改为数据源的形式 `typeorm.dataSource` * 2.3 实体模型类或者实体模型类的路径,需要在数据源的 `entities` 字段中声明 * 2.4 Subscriber 需要在数据源的 `subscribers` 字段中声明 * 3、不再使用 `EntityModel` 装饰器,直接使用 typeorm 提供的能力 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 typeorm 组件,提供数据库 ORM 能力。 ``` $ npm i @midwayjs/typeorm@3 typeorm --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/typeorm": "^3.0.0", "typeorm": "~0.3.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 orm 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as orm from '@midwayjs/typeorm'; import { join } from 'path'; @Configuration({ imports: [ // ... orm // 加载 typeorm 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 信息 * Oracle driver 比较特殊,需要查看 [文档](https://github.com/oracle/node-oracledb) * 不建议使用 typeorm 链接 mongodb,请使用 mongoose 组件 ## 简单的目录结构[​](#简单的目录结构 "简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── photo.entity.ts // 实体文件 │ │ └── photoMetadata.entity.ts │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ## 入门[​](#入门 "入门的直接链接") 下面,我们将以 mysql 举例。 ### 1、创建 Model[​](#1创建-model "1、创建 Model的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `photo` 举例。新建 entity 目录,在其中添加实体文件 `photo.entity.ts` ,一个简单的实体如下。 ``` // entity/photo.entity.ts export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 ### 2、定义实体模型[​](#2定义实体模型 "2、定义实体模型的直接链接") 我们使用 `Entity` 来定义一个实体模型类。 ``` // entity/photo.entity.ts import { Entity } from 'typeorm'; @Entity('photo') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 如果表名和当前的实体名不同,可以在参数中指定。 ``` // entity/photo.entity.ts import { Entity } from 'typeorm'; @Entity('photo_table_name') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 这些实体列也可以使用 [typeorm\_generator](/docs/tool/typeorm_generator.md) 工具生成。 ### 3、添加数据库列[​](#3添加数据库列 "3、添加数据库列的直接链接") 通过 typeorm 提供的 `@Column` 装饰器来修饰属性,每一个属性对应一个列。 ``` // entity/photo.entity.ts import { Entity, Column } from 'typeorm'; @Entity() export class Photo { @Column() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` 现在 `id` , `name` , `description` ,`filename` , `views` , `isPublished` 列将添加到 `photo` 表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 `@Column`装饰器中显式指定列类型来使用数据库支持的任何列类型。 我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。 数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 [官方文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/entities.md#%E5%88%97%E9%80%89%E9%A1%B9)。 ### 4、创建主键列[​](#4创建主键列 "4、创建主键列的直接链接") 每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 `@PrimaryColumn` 装饰器。 ``` // entity/photo.entity.ts import { Entity, Column, PrimaryColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 5、创建自增主键列[​](#5创建自增主键列 "5、创建自增主键列的直接链接") 现在,如果要设置自增的 id 列,需要将 `@PrimaryColumn` 装饰器更改为 `@PrimaryGeneratedColumn` 装饰器: ``` // entity/photo.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 6、列数据类型[​](#6列数据类型 "6、列数据类型的直接链接") 接下来,让我们调整数据类型。默认情况下,字符串映射到类似 `varchar(255)` 的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。 ``` // entity/photo.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryGeneratedColumn() id: number; @Column({ length: 100 }) name: string; @Column('text') description: string; @Column() filename: string; @Column("double") views: number; @Column() isPublished: boolean; } ``` 示例,不同列名 ``` @Column({ length: 100, name: 'custom_name' }) name: string; ``` 此外还有有几种特殊的列类型可以使用: * `@CreateDateColumn` 是一个特殊列,自动为实体插入日期。 * `@UpdateDateColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。 * `@VersionColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。 * `@DeleteDateColumn` 是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。 比如: ``` @CreateDateColumn({ type: 'timestamp', }) createdDate: Date; ``` 列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](https://github.com/typeorm/typeorm/blob/master/docs/entities.md#column-types)。 提示 `CreateDateColumn` 和 `UpdateDateColumn` 是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。 ### 7、配置连接信息和实体模型[​](#7配置连接信息和实体模型 "7、配置连接信息和实体模型的直接链接") 请参考 [配置](/docs/env_config.md) 章节,增加配置文件。 然后在 `config.default.ts` 中配置数据库连接信息。 ``` // src/config/config.default.ts import { Photo } from '../entity/photo.entity'; export default { // ... typeorm: { dataSource: { default: { /** * 单数据库实例 */ type: 'mysql', host: '*******', port: 3306, username: '*******', password: '*******', database: undefined, synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true,注意会丢数据 logging: false, // 配置实体模型 entities: [Photo], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配 entities: [ 'entity', // 特定目录 '**/*.entity.{j,t}s', // 通配加后缀匹配 ] } } }, } ``` 提示 * 1. 如果使用的数据库已经有表结构同步的功能,比如云数据库,最好不要开启。如果一定要使用,synchronize 配置最好仅在开发阶段,或者第一次使用,避免造成一致性问题。 * 2. `entities` 字段配置已经经过框架处理,该字段配置请不要参考原始文档。 `type` 字段你可以使用其他的数据库类型,包括`mysql`, `mariadb`, `postgres`, `cockroachdb`, `sqlite`, `mssql`, `oracle`, `cordova`, `nativescript`, `react-native`, `expo`, or `mongodb` 比如 sqlite,需要以下信息。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { type: 'sqlite', database: path.join(__dirname, '../../test.sqlite'), synchronize: true, logging: true, // ... } } }, } ``` 信息 注意:synchronize 字段用于同步表结构。使用 `synchronize: true` 进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。 ### 8、使用 Model 插入数据库数据[​](#8使用-model-插入数据库数据 "8、使用 Model 插入数据库数据的直接链接") 在常见的 Midway 文件中,使用 `@InjectEntityModel` 装饰器注入我们配置好的 Model。我们所需要做的只是: * 1、创建实体对象 * 2、执行 `save()` ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // save async savePhoto() { // create a entity object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // save entity const photoResult = await this.photoModel.save(photo); // save success console.log('photo id = ', photoResult.id); } } ``` ### 9、查询数据[​](#9查询数据 "9、查询数据的直接链接") 更多的查询参数,请查询 [find文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/find-options.md)。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhotos() { // find All let allPhotos = await this.photoModel.find({}); console.log("All photos from the db: ", allPhotos); // find first let firstPhoto = await this.photoModel.findOne({ where: { id: 1 } }); console.log("First photo from the db: ", firstPhoto); // find one by name let meAndBearsPhoto = await this.photoModel.findOne({ where: { name: "Me and Bears" } }); console.log("Me and Bears photo from the db: ", meAndBearsPhoto); // find by views let allViewedPhotos = await this.photoModel.find({ where: { views: 1 } }); console.log("All viewed photos: ", allViewedPhotos); let allPublishedPhotos = await this.photoModel.find({ where: { isPublished: true } }); console.log("All published photos: ", allPublishedPhotos); // find and get count let [allPhotos, photosCount] = await this.photoModel.findAndCount({}); console.log("All photos: ", allPhotos); console.log("Photos count: ", photosCount); } } ``` ### 10、更新数据库[​](#10更新数据库 "10、更新数据库的直接链接") 现在,让我们从数据库中加载一个 Photo,对其进行更新并保存。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { let photoToUpdate = await this.photoModel.findOne({ where: { id: 1, }, }); photoToUpdate.name = "Me, my friends and polar bears"; await this.photoModel.save(photoToUpdate); } } ``` ### 11、删除数据[​](#11删除数据 "11、删除数据的直接链接") `remove` 用于删除给定的实体或实体数组。`delete` 用于按给定的 ID 或者条件删除。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { /*...*/ const photo = await this.photoModel.findOne({ where: { id: 1, }, }); // 删除单个 await this.photoModel.remove(photo) // 删除多个 await this.photoModel.remove([photo1, photo2, photo3]); // 按 id 删除 await this.photoModel.delete(1); await this.photoModel.delete([1, 2, 3]); await this.photoModel.delete({ name: "Timber" }); } } ``` 现在,ID = 1的 Photo 将从数据库中删除。 此外还有软删除的方法。 ``` await this.photoModel.softDelete(1); // 使用 restore 方法恢复; await this.photoModel.restore(1); ``` ### 12、创建一对一关联[​](#12创建一对一关联 "12、创建一对一关联的直接链接") 让我们与另一个类创建一对一的关系。让我们在 `entity/photoMetadata.entity.ts` 中创建一个新类。这个类包含 photo 的其他元信息。 ``` import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo.entity'; @Entity() export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column("int") height: number; @Column("int") width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string; @OneToOne(type => Photo) @JoinColumn() photo: Photo; } ``` 在这里,我们使用一个名为 `@OneToOne` 的新装饰器。它允许我们在两个实体之间创建一对一的关系。`type => Photo`是一个函数,它返回我们要与其建立关系的实体的类。 由于语言的特殊性,我们被迫使用一个返回类的函数,而不是直接使用该类。我们也可以将其写为 `() => Photo` ,但是我们使用 `type => Photo`作为惯例来提高代码的可读性。类型变量本身不包含任何内容。 我们还添加了一个 `@JoinColumn`装饰器,它指示关系的这一侧将拥有该关系。关系可以是单向或双向的。关系只有一方可以拥有。关系的所有者端需要使用@JoinColumn装饰器。 如果您运行该应用程序,则会看到一个新生成的表,该表将包含一列,其中包含用于 Photo 关系的外键。 ``` +-------------+--------------+----------------------------+ | photo_metadata | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | height | int(11) | | | width | int(11) | | | comment | varchar(255) | | | compressed | boolean | | | orientation | varchar(255) | | | photoId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 接下去我们要在代码中关联他们。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { PhotoMetadata } from './entity/photoMetadata.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(PhotoMetadata) photoMetadataModel: Repository; async updatePhoto() { // create a photo let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create a photo metadata let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; metadata.photo = photo; // this way we connect them // first we should save a photo await this.photoModel.save(photo); // photo is saved. Now we need to save a photo metadata await this.photoMetadataModel.save(metadata); // done console.log("Metadata is saved, and relation between metadata and photo is created in the database too"); } } ``` ### 13、反向关系映射[​](#13反向关系映射 "13、反向关系映射的直接链接") 关系映射可以是单向或双向的。当在 PhotoMetadata 和 Photo之间的关系是单向的。关系的所有者是PhotoMetadata,而 Photo对 PhotoMetadata 是一无所知的。这使得从 Photo 端访问 PhotoMetadata 变得很复杂。若要解决此问题,我们添加一个反向的关系映射,使 PhotoMetadata 和 Photo之间变成双向关联。让我们修改我们的实体。 ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo'; @Entity() export class PhotoMetadata { /* ... other columns */ @OneToOne(type => Photo, photo => photo.metadata) @JoinColumn() photo: Photo; } ``` ``` import { Entity } from 'typeorm'; import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata.entity'; @Entity() export class Photo { /* ... other columns */ @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo) metadata: PhotoMetadata; } ``` `photo => photo.metadata` 是一个返回反向映射关系的函数。在这里,我们显式声明 Photo 类的 metadata 属性用于关联 PhotoMetadata。除了传递返回 photo 属性的函数外,您还可以直接将字符串传递给 `@OneToOne` 装饰器,例如 `“metadata”` 。但是我们使用了这种函数回调的方法来让我们的代码写法更简单。 请注意,只会在关系映射的一侧使用 `@JoinColumn` 装饰器。无论您放置此装饰器的哪一侧,都是关系的所有者。关系的拥有方在数据库中包含带有外键的列。 ### 14、加载对象及其依赖关系[​](#14加载对象及其依赖关系 "14、加载对象及其依赖关系的直接链接") 现在,让我们尝试在单个查询中一起加载出 Photo 和 PhotoMetadata。有两种方法可以执行此操作,使用 `find *` 方法或使用 `QueryBuilder` 功能。让我们首先使用 `find *` 方法。 `find *` 方法允许您使用 `FindOneOptions` / `FindManyOptions` 接口指定对象。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel.find({ relations: [ 'metadata' ] }); // typeorm@0.2.x } } ``` 在这里,photos 的值是一个数组,包含了整个数据库的查询结果,并且每个 photo 对象都包含其关联的 metadata 属性。在[此文档](https://github.com/typeorm/typeorm/blob/master/docs/find-options.md)中了解有关 `Find Options` 的更多信息。 使用 `Find Options` 很简单,但如果需要更复杂的查询,则应改用 `QueryBuilder` 。 `QueryBuilder` 允许以优雅的方式使用更复杂的查询。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel .createQueryBuilder('photo') .innerJoinAndSelect('photo.metadata', 'metadata') .getMany(); } } ``` `QueryBuilder`允许创建和执行几乎任何复杂的 SQL 查询。使用 `QueryBuilder` 时,请像创建 SQL 查询一样思考。在此示例中,“photo” 和 “metadata” 是应用于所选 photos 的别名。您可以使用别名来访问所选数据的列和属性。 ### 15、使用级联操作自动保存关联对象[​](#15使用级联操作自动保存关联对象 "15、使用级联操作自动保存关联对象的直接链接") 在我们希望在每次保存另一个对象时都自动保存关联的对象,这个时候可以在关系中设置级联。让我们稍微更改照片的 `@OneToOne` 装饰器。 ``` export class Photo { /// ... other columns @OneToOne(type => PhotoMetadata, metadata => metadata.photo, { cascade: true, }) metadata: PhotoMetadata; } ``` 使用 `cascade` 允许我们现在不再单独保存 Photo 和 PhotoMetadata,由于级联选项,元数据对象将被自动保存。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { PhotoMetadata } from './entity/photoMetadata.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { // create photo object let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create photo metadata object let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; photo.metadata = metadata; // this way we connect them // save a photo also save the metadata await this.photoModel.save(photo); // done console.log("Photo is saved, photo metadata is saved too"); } } ``` 注意,我们现在设置 Photo 的元数据,而不需要像之前那样设置元数据的 Photo 属性。这仅当您从 Photo 这边将 Photo 连接到 PhotoMetadata 时,级联功能才有效。如果在 PhotoMetadata 侧设置,则不会自动保存。 ### 16、创建多对一/一对多关联[​](#16创建多对一一对多关联 "16、创建多对一/一对多关联的直接链接") 让我们创建一个多对一/一对多关系。假设一张照片有一个作者,每个作者可以有很多照片。首先,让我们创建一个 Author 类: ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from 'typeorm'; import { Photo } from './entity/photo.entity'; @Entity() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below photos: Photo[]; } ``` `Author` 包含了一个反向关系。 `OneToMany` 和 `ManyToOne` 需要成对出现。 现在,将关系的所有者添加到 Photo 实体中: ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata.entity'; import { Author } from './author.entity'; @Entity() export class Photo { /* ... other columns */ @ManyToOne(type => Author, author => author.photos) author: Author; } ``` 在多对一/一对多关系中,所有者方始终是多对一。这意味着使用 `@ManyToOne` 的类将存储相关对象的 ID。 运行应用程序后,ORM 将创建 `author` 表: ``` +-------------+--------------+----------------------------+ | author | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | +-------------+--------------+----------------------------+ ``` 它还将修改 `photo` 表,添加新的 `author` 列并为其创建外键: ``` +-------------+--------------+----------------------------+ | photo | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | | description | varchar(255) | | | filename | varchar(255) | | | isPublished | boolean | | | authorId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` ### 17、创建多对多关联[​](#17创建多对多关联 "17、创建多对多关联的直接链接") 让我们创建一个多对一/多对多关系。假设一张照片可以在许多相册中,并且每个相册可以包含许多照片。让我们创建一个 `Album` 类。 ``` import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm'; @Entity() export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany(type => Photo, photo => photo.albums) @JoinTable() photos: Photo[]; } ``` `@JoinTable` 用来指明这是关系的所有者。 现在,将反向关联添加到 `Photo` 。 ``` export class Photo { /// ... other columns @ManyToMany(type => Album, album => album.photos) albums: Album[]; } ``` 运行应用程序后,ORM将创建一个 album\_photos\_photo\_albums 联结表: ``` +-------------+--------------+----------------------------+ | album_photos_photo_albums | +-------------+--------------+----------------------------+ | album_id | int(11) | PRIMARY KEY FOREIGN KEY | | photo_id | int(11) | PRIMARY KEY FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 现在,让我们将相册和照片插入数据库: ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Album } from './entity/album.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(Album) albumModel: Repository async updatePhoto() { // create a few albums let album1 = new Album(); album1.name = "Bears"; await this.albumModel.save(album1); let album2 = new Album(); album2.name = "Me"; await this.albumModel.save(album2); // create a few photos let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.albums = [album1, album2]; await this.photoModel.save(photo); // now our photo is saved and albums are attached to it // now lets load them: const loadedPhoto = await this.photoModel.findOne(1, { relations: ["albums"] }); // typeorm@0.2.x } } ``` `loadedPhoto` 的值为: ``` { id: 1, name: "Me and Bears", description: "I am near polar bears", filename: "photo-with-bears.jpg", albums: [{ id: 1, name: "Bears" }, { id: 2, name: "Me" }] } ``` ### 18、使用 QueryBuilder[​](#18使用-querybuilder "18、使用 QueryBuilder的直接链接") 您可以使用QueryBuilder来构建几乎任何复杂的SQL查询。例如,您可以这样做: ``` let photos = await this.photoModel .createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it. .innerJoinAndSelect("photo.metadata", "metadata") .leftJoinAndSelect("photo.albums", "album") .where("photo.isPublished = true") .andWhere("(photo.name = :photoName OR photo.name = :bearName)") .orderBy("photo.id", "DESC") .skip(5) .take(10) .setParameters({ photoName: "My", bearName: "Mishka" }) .getMany(); ``` 该查询选择所有带有 “My” 或 “Mishka” 名称的已发布照片。它将从位置 5 开始返回结果(分页偏移),并且将仅选择 10 个结果(分页限制)。选择结果将按 ID 降序排列。该照片的相册将 left-Joined,元数据将自动关联。 您将在应用程序中大量使用查询生成器。在 [此处](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/select-query-builder.md) 了解有关QueryBuilder的更多信息。 ### 19、Event Subscriber[​](#19event-subscriber "19、Event Subscriber的直接链接") typeorm 提供了一个事件订阅机制,方便在做一些数据库操作时的日志输出,为此 midway 提供了一个 `EventSubscriberModel` 装饰器,用来标注事件订阅类,代码如下。 ``` import { EventSubscriberModel } from '@midwayjs/typeorm'; import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm'; @EventSubscriberModel() export class EverythingSubscriber implements EntitySubscriberInterface { /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { console.log(`BEFORE ENTITY INSERTED: `, event.entity); } /** * Called before entity insertion. */ beforeUpdate(event: UpdateEvent) { console.log(`BEFORE ENTITY UPDATED: `, event.entity); } /** * Called before entity insertion. */ beforeRemove(event: RemoveEvent) { console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity insertion. */ afterInsert(event: InsertEvent) { console.log(`AFTER ENTITY INSERTED: `, event.entity); } /** * Called after entity insertion. */ afterUpdate(event: UpdateEvent) { console.log(`AFTER ENTITY UPDATED: `, event.entity); } /** * Called after entity insertion. */ afterRemove(event: RemoveEvent) { console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity is loaded. */ afterLoad(entity: any) { console.log(`AFTER ENTITY LOADED: `, entity); } } ``` 这个订阅类提供了一些常用的接口,用来在数据库操作时执行一些事情。 同时,我们需要把订阅类加到配置中。 ``` // src/config/config.default.ts import { EverythingSubscriber } from '../event/subscriber'; export default { // ... typeorm: { dataSource: { default: { // ... entities: [Photo], // 传入订阅类 subscribers: [EverythingSubscriber] } } }, } ``` ## Repository API[​](#repository-api "Repository API的直接链接") 更多 API 请查看 [官网文档](https://github.com/typeorm/typeorm/blob/master/docs/repository-api.md)。 ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 多数据库支持[​](#多数据库支持 "多数据库支持的直接链接") 有时候,我们一个应用中会有多个数据库连接(Connection)的情况,这个时候会有多个配置。我们使用 DataSource 标准的 \*\*对象的形式 \*\*来定义配置。 比如下面定义了 `default` 和 `test` 两个数据库连接(Connection)。 ``` import { join } from 'path'; export default { typeorm: { dataSource: { default: { type: 'sqlite', database: join(__dirname, '../../default.sqlite'), // ... }, test: { type: 'mysql', host: '127.0.0.1', port: 3306, // ... } } } } ``` 在使用时,需要指定模型归属于哪个连接(Connection)。 ``` import { InjectEntityModel } from '@midwayjs/typeorm'; import { User } from './entity/user.entity'; export class XXX { @InjectEntityModel(User, 'test') testUserModel: Repository; //... } ``` ### 列值转换[​](#列值转换 "列值转换的直接链接") 我们可以在实体定义中处理列值转换。 利用列装饰器的 `transformer` 参数,可以进行出入参的处理,比如对时间格式化。 ``` import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; import * as dayjs from 'dayjs'; const dateTransformer = { from: (value: Date | number) => { return dayjs(typeof value === 'number' ? value: value.getTime()).format('YYYY-MM-DD HH:mm:ss'); }, to: () => new Date(), }; @Entity() export class Photo { // ... @CreateDateColumn({ type: 'timestamp', transformer: dateTransformer, }) createdAt: Date; } ``` ### 指定默认数据源[​](#指定默认数据源 "指定默认数据源的直接链接") 在包含多个数据源时,可以指定默认的数据源。 ``` export default { // ... typeorm: { dataSource: { default1: { // ... }, default2: { // ... }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default1', }, }; ``` ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的 DataSource 对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(TypeORMDataSourceManager); const conn = dataSourceManager.getDataSource('default'); console.log(dataSourceManager.isConnected(conn)); } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource } from 'typeorm'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: DataSource; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: DataSource; async onReady(container: IMidwayContainer) { // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 数据源在未配置日志对象时,组件会自动创建一个 `typeormLogger`,用于保存执行的 SQL 信息,方便排查问题和 SQL 审核。 默认配置为: ``` export default { midwayLogger: { clients: { typeormLogger: { fileLogName: 'midway-typeorm.log', enableError: false, level: 'info', }, }, } } ``` 我们可以使用普通日志的配置方式进行调整,如果不希望生成日志,可以配置关闭。 ``` export default { // ... typeorm: { default: { // 所有数据源关闭 logging: false, }, dataSource: { default: { // 单个数据源关闭 logging: false, }, }, }, }; ``` ### 事务[​](#事务 "事务的直接链接") typeorm 的事务需要先获取到数据源,然后开启事务。 ``` import { Provide, Inject } from '@midwayjs/core'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; import { UserDTO } from '../entity/user'; @Provide() export class UserService { @Inject() dataSourceManager: TypeORMDataSourceManager; async updateUser(user: UserDTO) { // get dataSource const dataSource = this.dataSourceManager.getDataSource('default'); // start transaction await dataSource.transaction(async (transactionalEntityManager) => { // run code await transactionalEntityManager.save(UserDTO, user); }); } } ``` 更多的细节,可以参考 [文档](https://github.com/typeorm/typeorm/blob/master/docs/transactions.md)。 ### CLI[​](#cli "CLI的直接链接") TypeORM 默认提供了一个 CLI,用来创建 entity,migration 等,更多文档请查看 [这里](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/using-cli.md)。 由于 TypeORM 的默认配置和 Midway 不同,我们提供了一个简单的修改版本,用于适配 Midway 的数据源配置。 检查安装情况: ``` $ npx mwtypeorm -h ``` 常用的命令有 **创建空 Entity** 将会创建一个 `src/entity/User.ts` 文件。 ``` $ npx mwtypeorm entity:create src/entity/User ``` **创建 Migration** 将会根据现有数据源生成一个 `src/migration/******-photo.entity.ts` 文件。 比如配置如下: ``` export default { typeorm: { dataSource: { 'default': { // ... entities: [ '**/entity/*.entity{.ts,.js}' ], migrations: [ '**/migration/*.ts' ], }, }, } ``` 可以执行下面的命令,将修改后的 Entity 生成迁移文件。 ``` $ npx mwtypeorm migration:generate -d ./src/config/config.default.ts src/migration/photo ``` 警告 注意:上面的 entities 配置由于需要再 CLI 和 Midway 间复用,采用了两者都支持的扫描写法。 ### 关于表结构同步[​](#关于表结构同步 "关于表结构同步的直接链接") * 如果你已有表结构,想自动创建 Entity,使用 [生成器](https://www.npmjs.com/package/typeorm-model-generator) * 如果已经有 Entity 代码,想创建表结构请使用配置中的 `synchronize: true` ,注意可能会丢失数据 * 如果已经上线,但是又修改了表结构,可以使用 CLI 中的 `migration:generate` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Handshake inactivity timeout[​](#handshake-inactivity-timeout "Handshake inactivity timeout的直接链接") 一般是网络原因,如果本地出现,可以 ping 但是telnet不通,可以尝试执行如下命令: ``` $ sudo sysctl -w net.inet.tcp.sack=0 ``` ### 关于 mysql 时间列的时区展示[​](#关于-mysql-时间列的时区展示 "关于 mysql 时间列的时区展示的直接链接") 一般情况下,数据库中保存的是 UTC 时间,如果你希望返回当前时区的时间,可以使用下面的方式 **1、检查 mysql 数据库所在的环境** 比如下面默认的时区其实就是系统 UTC 时间,可以调整为 `+08:00`。 ``` mysql> show global variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | UTC | | time_zone | SYSTEM | +------------------+--------+ 2 rows in set (0.05 sec) ``` **2、检查服务代码部署的环境** 尽量和数据库所在的环境一致,如果不一致,请在配置中设置 `timezone` (设置为和 mysql 一致)。 ``` export default { typeorm: { dataSource: { default: { type: 'mysql', // ... timezone: '+08:00', }, }, }, } ``` ### 时间列返回字符串[​](#时间列返回字符串 "时间列返回字符串的直接链接") 配置 dateStrings 可以使 mysql 返回时间按 DATETIME 格式返回,只对 mysql 生效。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { //... dateStrings: true, } } }, } ``` 如果使用了 `@CreateDateColumn` 和 `@UpdateDateColumn` ,可以调整实体返回类型。 ``` @UpdateDateColumn({ name: "gmt_modified", type: 'timestamp' }) gmtModified: string; @CreateDateColumn({ name: "gmt_create", type: 'timestamp', }) gmtCreate: string; ``` 效果如下: **配置前:** ``` gmtModified: 2021-12-13T03:49:43.000Z, gmtCreate: 2021-12-13T03:49:43.000Z ``` **配置后:** ``` gmtModified: '2021-12-13 11:49:43', gmtCreate: '2021-12-13 11:49:43' ``` ### 同时安装 mysql 和 mysql2[​](#同时安装-mysql-和-mysql2 "同时安装 mysql 和 mysql2的直接链接") 在 node\_modules 中同时有 mysql 和 mysql2 时,typeorm 会自动加载 mysql,而不是 mysql2。 这个时候如需使用 mysql2,请指定 driver。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { //... type: 'mysql', driver: require('mysql2'), } } }, } ``` ### Cannot read properties of undefined (reading 'getRepository')[​](#cannot-read-properties-of-undefined-reading-getrepository "Cannot read properties of undefined (reading 'getRepository')的直接链接") 一般是配置不正确,可以考虑两方面的配置: * 1、检查 `config.default.ts` 中的 `entities` 配置是否正确 * 2、检查 `configuration.ts` 文件,确认是否引入 orm --- # 阿里云对象存储(OSS) 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 `@midwayjs/oss` 组件就是在 midway 体系下用于对接 OSS 服务的 sdk。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 前置条件[​](#前置条件 "前置条件的直接链接") 使用 OSS 组件,你需要提前申请一个 OSS Bucket。Bucket 是 OSS 的存储库的概念,你的文件都将存储在这个库里。 * OSS 对象存储官网: * 什么是对象存储: ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/oss` 是主要的功能包。 ``` $ npm i @midwayjs/oss@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/oss": "^3.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as oss from '@midwayjs/oss'; import { join } from 'path' @Configuration({ imports: [ // ... oss // 导入 oss 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置 OSS[​](#配置-oss "配置 OSS的直接链接") OSS 组件需要配置后才能使用。需要填写 OSS 的 bucket、accessKeyId、accessKeySecret 等必要信息。 支持普通 oss 客户端和 oss 集群客户端,基于 [ali-oss](https://github.com/ali-sdk/ali-oss/) 这个包。 比如: **普通的 oss bucket 配置** ``` // src/config/config.default export default { // ... oss: { // normal oss bucket client: { accessKeyId: 'your access key', accessKeySecret: 'your access secret', bucket: 'your bucket name', endpoint: 'oss-cn-hongkong.aliyuncs.com', timeout: '60s', }, }, } ``` **集群(cluster) 模式的 oss bucket 配置,需要配置多个** ``` // src/config/config.default export default { // ... oss: { // need to config all bucket information under cluster client: { clusters: [{ endpoint: 'host1', accessKeyId: 'id1', accessKeySecret: 'secret1', }, { endpoint: 'host2', accessKeyId: 'id2', accessKeySecret: 'secret2', }], schedule: 'masterSlave', //default is `roundRobin` timeout: '60s', }, }, } ``` **STS 模式** ``` // src/config/config.default export default { // ... oss: { // if config.sts == true, oss will create STS client client: { sts: true, accessKeyId: 'your access key', accessKeySecret: 'your access secret', }, }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 可以直接获取 `OSSService`,然后调用接口,比如,保存文件。 ``` import { OSSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossService: OSSService; async saveFile() { const localFile = join(__dirname, 'test.log'); const result = await this.ossService.put('/test/test.log', localFile); // => result.url } } ``` 如果配置的是 STS 模式,客户端可以使用 `OSSSTSService` 。 ``` import { OSSSTSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() stsService: OSSSTSService; async saveFile() { const roleArn = '******'; // 这里是阿里云角色的 arn const result = await this.stsService.assumeRole(roleArn); // result.credentials.AccessKeyId // result.credentials.AccessKeySecret; // result.credentials.SecurityToken; } } ``` 更多的 OSS 客户端 API,请查看 [OSS 文档](https://github.com/ali-sdk/ali-oss)。 ## 使用多个 OSS Bucket[​](#使用多个-oss-bucket "使用多个 OSS Bucket的直接链接") 有些应用需要访问多个 oss bucket,那么就需要配置 `oss.clients`。 ``` // src/config/config.default export default { // ... oss: { clients: { bucket1: { bucket: 'bucket1', // ... }, bucket2: { bucket: 'bucket2', // ... }, }, // client, clients,createInstance 方法共享的配置 default: { endpoint: '', accessKeyId: '', accessKeySecret: '', }, }, // other custom config bucket3: { bucket: 'bucket3', // ... }, } ``` 可以使用 `OSSServiceFactory` 获取不同的实例。 ``` import { OSSServiceFactory } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossServiceFactory: OSSServiceFactory; @Config('bucket3') bucket3Config; async saveFile() { // 默认获取的类型是 OSSService const bucket1 = this.ossServiceFactory.get('bucket1'); const bucket2 = this.ossServiceFactory.get('bucket2'); // 如果是 STS,需要设置泛型联系 // const bucket1 = this.ossServiceFactory.get('bucket1'); // 会合并 config.bucket3 和 config.oss.default const bucket3 = await this.ossServiceFactory.createInstance(this.bucket3Config, 'bucket3'); // 传了名字之后也可以从 factory 中获取 bucket3 = this.ossServiceFactory.get('bucket3'); } } ``` --- # 链路追踪 Midway 采用社区最新的 [open-telemetry](https://opentelemetry.io/) 方案,其前身是知名的 OpenTracing 和 OpenCensus 规范,现阶段也是 CNCF 的孵化项目,社区许多知名的大公司如 Amazon,Dynatrace,Microsoft,Google,Datadog,Splunk 等都有使用。 [open-telemetry](https://opentelemetry.io/) 提供了通用的 Node.js 接入方案,以供应商无关的方式将数据接收,处理,导出,支持向一个或多个开源或者商业化的采集端发送可观测的数据(比如阿里云 SLS,Jaeger,Prometheus,Fluent Bit 等)。 Midway 提供了接入 [open-telemetry](https://opentelemetry.io/) 的 Node.js 方案,并提供了一些简单的使用 API。 信息 [open-telemetry](https://opentelemetry.io/) 的 Tracing 部分当前 Node.js SDK 已经 Release 1.0.0,可以在生产使用,Metrics 部分未正式发布,我们依旧在跟进(编码)中。 ## 使用须知[​](#使用须知 "使用须知的直接链接") [open-telemetry](https://opentelemetry.io/) 基于 Node.js 的 Async\_Hooks 的稳定 API 实现,经过我们的测试,在最新的 Node.js v14/v16 性能影响已经很小,可以在生产使用,在 v12 情况下虽然可以使用,但是性能依旧有不小的损失,请尽可能在 Node.js >= v14 的版本下使用。 ## 安装基础依赖[​](#安装基础依赖 "安装基础依赖的直接链接") ``` # Node.js 的 api 抽象 $ npm install --save @opentelemetry/api # Node.js 的 api 实现 $ npm install --save @opentelemetry/sdk-node # 常用 Node.js 模块的埋点实现 $ npm install --save @opentelemetry/auto-instrumentations-node # jaeger 输出器 $ npm install --save @opentelemetry/exporter-jaeger ``` 以上的包均为 [open-telemetry](https://opentelemetry.io/) 的官方包。 ## 启用 open-telemetry[​](#启用-open-telemetry "启用 open-telemetry的直接链接") [open-telemetry](https://opentelemetry.io/) 的模块请尽可能加在代码的最开始(比框架还要早),所以在不同场景中,我们有不同的添加方式。 ### 使用 bootstrap 部署[​](#使用-bootstrap-部署 "使用 bootstrap 部署的直接链接") 如果使用 `bootstrap.js` 部署,你可以加在 `bootstrap.js` 的最顶部,示例代码如下。 ``` const process = require('process'); const { NodeSDK, node, resources } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions') const { JaegerExporter } = require('@opentelemetry/exporter-jaeger') // Midway 启动文件 const { Bootstrap } = require('@midwayjs/bootstrap'); // https://www.npmjs.com/package/@opentelemetry/exporter-jaeger const tracerAgentHost = process.env['TRACER_AGENT_HOST'] || '127.0.0.1' const jaegerExporter = new JaegerExporter({ host: tracerAgentHost, }); // 初始化一个 open-telemetry 的 SDK const sdk = new NodeSDK({ // 设置追踪服务名 resource: new resources.Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'my-app', }), // 配置当前的导出方式,比如这里配置了一个输出到控制台的,也可以配置其他的 Exporter,比如 Jaeger traceExporter: new node.ConsoleSpanExporter(), // 配置当前导出为 jaeger // traceExporter: jaegerExporter, // 这里配置了默认自带的一些监控模块,比如 http 模块等 // 若初始化时间很长,可注销此行,单独配置需要的 instrumentation 条目 instrumentations: [getNodeAutoInstrumentations()] }); // 初始化 SDK,成功启动之后,再启动 Midway 框架 sdk.start() // 在进程关闭时,同时关闭数据采集 process.on('SIGTERM', () => { sdk.shutdown() .then(() => console.log('Tracing terminated')) .catch((error) => console.log('Error terminating tracing', error)) .finally(() => process.exit(0)); }); Bootstrap .configure(/**/) .run(); ``` ### 使用 egg-scripts 部署[​](#使用-egg-scripts-部署 "使用 egg-scripts 部署的直接链接") egg-scripts 由于未提供入口部署,必须采用 `--require` 的形式加载额外的文件。 我们在根目录添加一个 `otel.js` (注意是 js 文件),内容如下。 ``` const process = require('process'); const { NodeSDK, node, resources } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); // 初始化一个 open-telemetry 的 SDK const sdk = new NodeSDK({ // 配置当前的导出方式,比如这里配置了一个输出到控制台的,也可以配置其他的 Exporter,比如 Jaeger traceExporter: new node.ConsoleSpanExporter(), // 这里配置了默认自带的一些监控模块,比如 http 模块等 instrumentations: [getNodeAutoInstrumentations()] }); // 初始化 SDK sdk.start() // 在进程关闭时,同时关闭数据采集 process.on('SIGTERM', () => { sdk.shutdown() .then(() => console.log('Tracing terminated')) .catch((error) => console.log('Error terminating tracing', error)) .finally(() => process.exit(0)); }); ``` 修改 `package.json` 中的启动命令。 ``` { // ... "scripts": { "start": "egg-scripts start --daemon --title=**** --framework=@midwayjs/web --require=./otel.js", }, } ``` ### 开发调试入口[​](#开发调试入口 "开发调试入口的直接链接") `midway-bin` 使用 `--entryFile` 参数指定入口文件 例如 `package.json` 文件 ``` { "scripts": { "start": "cross-env NODE_ENV=local midway-bin dev --ts --entryFile=bootstrap.js" } } ``` ## 常用概念[​](#常用概念 "常用概念的直接链接") [open-telemetry](https://opentelemetry.io/) 提供了一些抽象封装,将监控的整个过程包装为几个步骤,每个步骤都可自定义配置,其也有一些用户不太理解的术语,在下面做一些解释。 完整的英文概念请参考 [Concepts](https://opentelemetry.io/docs/concepts/)。 ### API[​](#api "API的直接链接") 用于生成和关联 Tracing、Metrics 和 Logs 记录数据的数据类型和操作的一组 API 抽象,具体表现为 `@opentelemetry/api` 这个包,里面是一些接口和空实现。 ### SDK[​](#sdk "SDK的直接链接") API 的特定语言实现,比如 Node.js 的实现(`@opentelemetry/sdk-node`),其他监控平台的采集 SDK 实现等等。 ### Instrumentations[​](#instrumentations "Instrumentations的直接链接") [open-telemetry](https://opentelemetry.io/) 提供了一些常见库的 shim 代码,使用 hooks 或者 monkey-patching 的方法来拦截方法,自动在特定方法调用时保存链路数据,支持 http,gRPC , redis,mysql 等模块,用户直接配置即可使用。 比如上面示例引入的 `@opentelemetry/auto-instrumentations-node` 就是一个已经默认封装好常用库的 instrumentations 集合包,里面包括了大部分会用到的库,具体的依赖请参考 [Github](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/metapackages/auto-instrumentations-node/package.json)。 ### Exporter[​](#exporter "Exporter的直接链接") 将接收到的链路数据发送到特定端的实现,比如 Jaeger,zipkin 等。 ## 示例[​](#示例 "示例的直接链接") ### 添加三方 instrumentation[​](#添加三方-instrumentation "添加三方 instrumentation的直接链接") 在 SDK 初始化时,添加到 `instrumentations `数组中即可。 ``` const { RedisInstrumentation } = require('@opentelemetry/instrumentation-redis'); // ... // 初始化一个 open-telemetry 的 SDK const sdk = new NodeSDK({ // ... // 这里仅是添加的示例,如果使用了 auto-instrumentations-node,已经包含了下面的 instrumentation instrumentations: [ new RedisInstrumentation(), ] }); ``` ### 添加 Jaeger Exporter[​](#添加-jaeger-exporter "添加 Jaeger Exporter的直接链接") 这里以 Jaeger Exporter 作为示例,其他 Exporter 类似。 先添加依赖。 ``` $ npm install --save @opentelemetry/exporter-jaeger @opentelemetry/propagator-jaeger ``` 在 SDK 中配置。 ``` const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerPropagator } = require('@opentelemetry/propagator-jaeger'); // ... const exporter = new JaegerExporter({ tags: [], // optional // You can use the default UDPSender host: 'localhost', // optional port: 6832, // optional // OR you can use the HTTPSender as follows // endpoint: 'http://localhost:14268/api/traces', maxPacketSize: 65000 // optional }); // 初始化一个 open-telemetry 的 SDK const sdk = new NodeSDK({ traceExporter: exporter, textMapPropagator: new JaegerPropagator() // ... }); ``` 具体参数请参考: * [opentelemetry-exporter-jaeger](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-exporter-jaeger/README.md) * [opentelemetry-propagator-jaeger](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-propagator-jaeger/README.md) ### 阿里云 ARMS[​](#阿里云-arms "阿里云 ARMS的直接链接") 阿里云应用实时监控服务([ARMS](https://www.aliyun.com/product/arms/))已经支持了 open-telemetry 格式的指标,同时提供一个 sdk 进行接入。 首先,安装 `opentelemetry-arms`。 ``` # arms sdk $ npm install --save opentelemetry-arms ``` 然后在启动时添加环境变量参数以及 `-r` 参数即可。 ``` $ SERVICE_NAME=nodejs-opentelemetry-express AUTHENTICATION=**** ENDPOINT=grpc://**** node -r opentelemetry-arms bootstrap.js ``` 提示 * 1、这种方式接入,无需在` bootstrap.js` 中添加代码。 * 2、默认 sdk 仅提供了 http/express/koa 模块的链路支持,未包含其他 instrumentations,如有需求,可以拷贝源码至 `bootstrap.js` 中自定义。 ## 框架能力支持[​](#框架能力支持 "框架能力支持的直接链接") 注意,组件只是包裹了 otel 的接口,如果不需要下述接口使用,无需安装本组件 先安装依赖。 ``` $ npm i @midwayjs/otel@3 --save ``` 启用 `otel` 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as otel from '@midwayjs/otel'; @Configuration({ imports: [ // ... otel ] }) export class MainConfiguration { } ``` ### ctx.traceId[​](#ctxtraceid "ctx.traceId的直接链接") 组件提供了 `ctx.traceId` 字段。 你可以在支持的组件下进行获取(egg/koa)。 ``` ctx.traceId => ***** ``` ### 装饰器支持[​](#装饰器支持 "装饰器支持的直接链接") Midway 针对用户侧的需求,添加一个装饰器用于增加链路节点。 Otel 组件提供了一个 @Trace 装饰器,可以添加在方法上。 ``` export class UserService { @Trace('user.get') async getUser() { // ... } } ``` 该装饰器需要传入一个节点名字,这样链路会自动添加一个该方法的链路节点,并记录执行的时间,方法执行成功或者失败。 --- # 身份验证 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Nodejs 中最流行的 Passport 库。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 从 v3.4.0 开始 Midway 自行维护 passport,将不再需要引入社区包和类型包。 ## 一些概念[​](#一些概念 "一些概念的直接链接") passport 是社区使用较多的身份验证库,通过称为策略的可扩展插件进行身份验证请求。 它本身包含几个部分: * 1、验证的策略,比如 jwt 验证,github 验证,oauth 验证等,passport 最为丰富的也是这块 * 2、执行策略之后,中间件的逻辑处理和配置,比如成功或者失败后的跳转,报错等 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 安装 `npm i @midwayjs/passport` 和相关策略依赖。 ``` ## 必选 $ npm i @midwayjs/passport@3 --save ## 可选 ## 下面安装本地策略 $ npm i passport-local --save $ npm i @types/passport-local --save-dev ## 下面安装 Github 策略 $ npm i passport-github --save ## 下面安装 Jwt 策略 $ npm i passport-jwt --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/passport": "^3.0.0", // 本地策略 "passport-local": "^1.0.0" // Jwt 策略 "passport-jwt": "^4.0.0", // Github 策略 "passport-github": "^1.1.0", // ... }, "devDependencies": { // 本地策略 "@types/passport-local": "^1.0.34", // Jwt 策略 "@types/passport-jwt": "^3.0.6", // Github 策略 "@types/passport-github": "^1.1.7", // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先启用组件。 ``` // src/configuration.ts import { join } from 'path'; import { ILifeCycle } from '@midwayjs/core'; import { Configuration } from '@midwayjs/core'; import * as passport from '@midwayjs/passport'; @Configuration({ imports: [ // ... passport, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle {} ``` ## 策略示例[​](#策略示例 "策略示例的直接链接") 这里我们以使用本地认证策略,和 Jwt 策略作为演示。 ### 示例:本地策略[​](#示例本地策略 "示例:本地策略的直接链接") 我们以 `passport-local` 来介绍 Passport 策略在 Midway 中如何使用, `passport-local` 的官方文档示例如下,通过 `passport.use` 加载一个策略,策略的验证逻辑是一个 `verify` 方法,包含 callback 参数,其余的策略的参数都在构造器中。 ``` passport.use( // 初始化一个策略 new LocalStrategy({ usernameField: 'username', passwordField: 'password', passReqToCallback: true, session: false }, function verify(username, password, done) { User.findOne({ username: username }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } if (!user.verifyPassword(password)) { return done(null, false); } return done(null, user); }); } ) ); ``` Midway 对此进行了改造,通过 `@CustomStrategy` 和 `PassportStrategy` 类继承一个 Passport 现有策略。 异步的 `validate` 方法代替原有的 `verify` 方法,`validate` 方法返回验证后的用户结果,方法的参数和原有对应的策略一致。 在 Midway 中编写的效果如下: ``` // src/strategy/local.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, IStrategyOptions } from 'passport-local'; import { Repository } from 'typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { UserEntity } from './user'; import * as bcrypt from 'bcrypt'; @CustomStrategy() export class LocalStrategy extends PassportStrategy(Strategy) { @InjectEntityModel(UserEntity) userModel: Repository; // 策略的验证 async validate(username, password) { const user = await this.userModel.findOneBy({ username }); if (!user) { throw new Error('用户不存在 ' + username); } if (!await bcrypt.compare(password, user.password)) { throw new Error('密码错误 ' + username); } return user; } // 当前策略的构造器参数 getStrategyOptions(): IStrategyOptions { return { usernameField: 'username', passwordField: 'password', passReqToCallback: true, session: false }; } } ``` 提示 注意:validate 方法是社区策略 verify 的 Promise 化替代方法,你无需在最后传递 callback 参数。 在 `passport-local` 的官方文档中,实现完策略后,需要作为中间件加载到业务中,比如: ``` app.post('/login/password', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })); ``` 提示 这里的 `local` 是 `passport-local` 内部的名字。 在 Midway 中,也需要将上述实现的 `LocalStrategy` 通过中间件加载。 自定义一个中间件继承 `PassportMiddleware` 扩展出的基础中间件,示例如下。 ``` // src/middleware/local.middleware.ts import { Middleware } from '@midwayjs/core'; import { PassportMiddleware, AuthenticateOptions } from '@midwayjs/passport'; import { LocalStrategy } from '../strategy/local.strategy'; @Middleware() export class LocalPassportMiddleware extends PassportMiddleware(LocalStrategy) { // 设置 AuthenticateOptions getAuthenticateOptions(): Promise | AuthenticateOptions { return { failureRedirect: '/login', }; } } ``` 将中间件加载到全局或者路由。 ``` // src/controller.ts import { Post, Inject, Controller } from '@midwayjs/core'; import { LocalPassportMiddleware } from '../middleware/local.middleware'; @Controller('/') export class LocalController { @Post('/passport/local', { middleware: [LocalPassportMiddleware] }) async localPassport() { console.log('local user: ', this.ctx.state.user); return this.ctx.state.user; } } ``` 使用 curl 模拟一次请求。 ``` curl -X POST http://localhost:7001/passport/local -d '{"username": "demo", "password": "1234"}' -H "Content-Type: application/json" 结果 {"username": "demo", "password": "1234"} ``` 警告 注意:如果将中间件放到全局,记得忽略需要登录的路由,否则请求会死循环。 ### 示例:Jwt 策略[​](#示例jwt-策略 "示例:Jwt 策略的直接链接") 首先需要 **额外安装** 依赖和策略: ``` $ npm i @midwayjs/jwt passport-jwt --save ``` 额外启用 jwt 组件。 ``` // configuration.ts import { join } from 'path'; import * as jwt from '@midwayjs/jwt'; import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as passport from '@midwayjs/passport'; @Configuration({ imports: [ // ... jwt, passport, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle {} ``` 然后在配置中设置,默认未加密,请不要把敏感信息存放在 payload 中。 ``` // src/config/config.default.ts export default { // ... jwt: { secret: 'xxxxxxxxxxxxxx', // fs.readFileSync('xxxxx.key') expiresIn: '2d', // https://github.com/vercel/ms }, }; ``` ``` // src/strategy/jwt.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; import { Config } from '@midwayjs/core'; @CustomStrategy() export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { @Config('jwt') jwtConfig; async validate(payload) { return payload; } getStrategyOptions(): any { return { secretOrKey: this.jwtConfig.secret, jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), }; } } ``` 提示 注意:validate 方法是社区策略 verify 的 Promise 化替代方法,你无需在最后传递 callback 参数。 ``` // src/middleware/jwt.middleware.ts import { Middleware } from '@midwayjs/core'; import { PassportMiddleware, AuthenticateOptions } from '@midwayjs/passport'; import { JwtStrategy } from '../strategy/jwt.strategy'; @Middleware() export class JwtPassportMiddleware extends PassportMiddleware(JwtStrategy) { getAuthenticateOptions(): Promise | AuthenticateOptions { return {}; } } ``` ``` import { Post, Inject, Controller } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { JwtService } from '@midwayjs/jwt'; import { JwtPassportMiddleware } from '../middleware/jwt.middleware'; @Controller('/') export class JwtController { @Inject() jwt: JwtService; @Inject() ctx: Context; @Post('/passport/jwt', { middleware: [JwtPassportMiddleware] }) async jwtPassport() { console.log('jwt user: ', this.ctx.state.user); return this.ctx.state.user; } @Post('/jwt') async genJwt() { return { t: await this.jwt.sign({ msg: 'Hello Midway' }), }; } } ``` 使用 curl 模拟请求 ``` curl -X POST http://127.0.0.1:7001/jwt 结果 {"t": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} curl http://127.0.0.1:7001/passport/jwt -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 结果 {"msg": "Hello Midway","iat": 1635468727,"exp": 1635468827} ``` ## 自定义其他策略[​](#自定义其他策略 "自定义其他策略的直接链接") `@midwayjs/passport` 支持自定义[其他策略](http://www.passportjs.org/packages/),这里以 Github OAuth 为例。 首先 `npm i passport-github`,之后编写如下代码: ``` // github-strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, StrategyOptions } from 'passport-github'; const GITHUB_CLIENT_ID = 'xxxxxx', GITHUB_CLIENT_SECRET = 'xxxxxxxx'; @CustomStrategy() export class GithubStrategy extends PassportStrategy(Strategy, 'github') { async validate(...payload) { return payload; } getStrategyOptions(): StrategyOptions { return { clientID: GITHUB_CLIENT_ID, clientSecret: GITHUB_CLIENT_SECRET, callbackURL: 'https://127.0.0.1:7001/auth/github/cb', }; } } ``` ``` // src/middleware/github.middleware.ts import { AuthenticateOptions, PassportMiddleware } from '@midwayjs/passport'; import { Middleware } from '@midwayjs/core'; import { GithubStrategy } from './githubStrategy'; @Middleware() export class GithubPassportMiddleware extends PassportMiddleware(GithubStrategy) { getAuthenticateOptions(): AuthenticateOptions | Promise { return {}; } } ``` ``` // src/controller/auth.controller.ts import { Controller, Get, Inject } from '@midwayjs/core'; import { GithubPassportMiddleware } from '../../middleware/github'; @Controller('/oauth') export class AuthController { @Inject() ctx; @Get('/github', { middleware: [GithubPassportMiddleware] }) async githubOAuth() {} @Get('/github/cb', { middleware: [GithubPassportMiddleware] }) async githubOAuthCallback() { return this.ctx.state.user; } } ``` ## 策略选项[​](#策略选项 "策略选项的直接链接") | 选项 | 类型 | 描述 | | ------------------- | ------- | ------------------------------------------------- | | failureRedirect | string | 失败跳转的 url | | session | boolean | 默认 true,开启后,会自动将用户信息设置到 session | | sessionUserProperty | string | 设置到 session 上的 key,默认 user | | userProperty | string | 设置到 ctx.state 或者 req 上的 key,默认 user | | successRedirect | string | 用户认证成功后跳转的地址 | ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Failed to serialize user into session[​](#1failed-to-serialize-user-into-session "1、Failed to serialize user into session的直接链接") 由于 passport 默认会尝试将 user 数据写入 session,如果无需将用户保存到 session,可以将 session 支持关闭。 ``` // src/config/config.default export default { // ... passport: { session: false, }, }; ``` 如果明确需要保存数据到 Session,则需要重写 `PassportStrategy`的 User 的序列化方法,请不要保存特别大的数据。 比如自己实现的本地策略。 ``` // src/strategy/local.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Repository } from 'typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { UserEntity } from './user'; import * as bcrypt from 'bcrypt'; @CustomStrategy() export class LocalStrategy extends PassportStrategy(Strategy) { // ... serializeUser(user, done) { // 可以只保存用户名 done(null, user.username); } deserializeUser(id, done) { // 这里不是异步方法,你可以从其他地方根据用户名,反查用户数据。 const user = getUserFromDataBase(id); done(null, user); } } ``` --- # pm2 [PM2](https://github.com/Unitech/pm2) 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 ## 安装[​](#安装 "安装的直接链接") 我们一般会把 pm2 安装到全局。 ``` $ npm install pm2 -g # 命令行安装 pm2 ``` ## 常用命令[​](#常用命令 "常用命令的直接链接") ``` $ pm2 start # 启动一个服务 $ pm2 list # 列出当前的服务 $ pm2 stop # 停止某个服务 $ pm2 restart # 重启某个服务 $ pm2 delete # 删除某个服务 $ pm2 logs # 查看服务的输出日志 ``` 比如, `pm2 list`,就会以表格显示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616560437389-b193a0d0-b463-49f1-a347-8dec20e7504d.png) pm2 的服务都有一个数组 id,你可以用 id 快速操作它。 比如: ``` $ pm2 stop 1 # 停止编号为 1 的服务 $ pm2 delete 1 # 删除编号为 1 的服务 ``` 使用 `--name` 参数添加一个应用名。 ``` $ pm2 start ./bootstrap.js --name test_app ``` 然后你可以用这个应用名来操作启停。 ``` $ pm2 stop test_app $ pm2 restart test_app ``` ## 启动应用[​](#启动应用 "启动应用的直接链接") Midway 应用一般使用 `npm run start` 做线上部署。其对应的命令为 `NODE_ENV=production node bootstrap.js`。 信息 部署前需要执行编译 npm run build 对应的 pm2 命令为 ``` $ NODE_ENV=production pm2 start ./bootstrap.js --name midway_app -i 4 ``` * \--name 用于指定应用名 * -i 用于指定启动的实例数(进程),会使用 cluster 模式启动 效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616562075255-088155ee-7c4f-4eae-b5c5-db826f78b519.png) ## Docker 容器启动[​](#docker-容器启动 "Docker 容器启动的直接链接") 在 Docker 容器中,后台启动的代码都会被退出,达不到预期效果。pm2 使用另一个命令来支持容器启动。 请将命令修改为 pm2-runtime start 。 ``` $ NODE_ENV=production pm2-runtime start ./bootstrap.js --name midway_app -i 4 ``` 具体的 pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 --- # 进程 Agent midway 封装了 `@midwayjs/process-agent` 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 举例: * 如果使用 pm2、cluster、多进程进行部署方式,使用内存的 cache,那这个 cache 在自己的进程内。 * prometheus,获取 `/metrics` 的时候,需要把所有进程的数据收集上来,而不是某个进程的 * 健康检查,如果有4个进程,如果有一个进程不正常了,健康检查应该检查失败。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装方法[​](#安装方法 "安装方法的直接链接") 使用方法: ``` $ npm install @midwayjs/process-agent@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/process-agent": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") `configuration.ts` 使用方法: ``` import * as processAgent from '@midwayjs/process-agent'; @Configuration({ imports: [ // ... processAgent ], }) export class MainConfiguration { } ``` ## 使用方法[​](#使用方法 "使用方法的直接链接") 业务代码 UserService: ``` import { Provide, Inject } from '@midwayjs/core'; import { TestService } from './test'; @Provide() export class UserService { @Inject() testService: TestService; async getUser() { let result = await this.testService.setData(1); return result; } } ``` 然后调用 testService 的时候,希望只在主进程执行: ``` import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { RunInPrimary } from '@midwayjs/process-agent'; @Provide() @Scope(ScopeEnum.Singleton) export class TestService { data: any = 0; @RunInPrimary() async setData(b){ this.data = b; return this.data; } @RunInPrimary() async getData(){ return this.data; } } ``` 注意,执行返回的数据只限于可序列化的数据,比如普通 JSON,不支持包含方法等无法序列化的数据。 ## 效果描述[​](#效果描述 "效果描述的直接链接") 假设采用pm2 或者 egg-script 等多进程方式启动,假设这是个请求 首先: * 1、设置 setData * 2、然后获取 getData 如果没有 RunInPrimary 这个装饰器,那请求可能落在进程2,或者进程3,那可能没有获取更新的data。 所以 RunInPrimary 能确保这个函数执行能落到主进程去。 ## 功能征集[​](#功能征集 "功能征集的直接链接") 如果有其他类似相关功能,觉得可以放在这个包里面的,欢迎在评论区,或者 [issue](https://github.com/midwayjs/midway/issues) 里面帮忙提一下,我们会跟大家一起讨论和实现。 --- # Prometheus Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 Grafana 是一个开源的度量分析与可视化套件。纯 Javascript 开发的前端工具,通过访问库(如 InfluxDB),展示自定义报表、显示图表等。Grafana 支持许多不同的数据源。每个数据源都有一个特定的查询编辑器,该编辑器定制的特性和功能是公开的特定数据来源。而 Prometheus 正好是其支持的数据源之一。 本篇介绍了 Midway 如何接入 Grafana + Prometheus。 接入效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617259935548-a2df4339-3229-4391-bd3d-4ba8e6979d4d.png) ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 首先安装 Midway 提供的指标监控组件: ``` $ npm install @midwayjs/prometheus@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/prometheus": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `configuration.ts` 中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as prometheus from '@midwayjs/prometheus'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [ // ... prometheus ], importConfigs: [join(__dirname, 'config')], }) export class MainConfiguration {} ``` 启动我们的应用,此时访问的时候多了一个 `${host}:${port}/metrics` 。 信息 Prometheus 基于 HTTP 获取监控数据,请包含 web/koa/express 其中任一组件。 访问接口,返回如下,里面的内容是当前的指标。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260048533-4f725824-9471-40c9-be8b-6dcbf27d9cca.png) ## 其他配置[​](#其他配置 "其他配置的直接链接") 指标组件也提供了相关的配置,方便开发者进行配置。 可以在 `config.default.ts` 中,修改 prometheus 的配置。 ``` // src/config/config.default export default { // ... prometheus: { labels: { APP_NAME: 'demo_project', }, }, } ``` 更多的配置,我们可以查看定义进行配置。 通过配置,我们例如可以归类哪些 node 是同一个应用,因为我们部署的时候,node 程序是分布式的。例如上面我们加了 APP\_NAME,用来区分不同的应用,这样在监控指标中,我们可以区分不同的应用。 ## 数据采集[​](#数据采集 "数据采集的直接链接") 我们前面在 Midway 中引入的组件主要是在 Node 中加了指标模块。接下来我们需要让 Prometheus 来采集我们的指标数据。 如果开发者所在部门已经有 Prometheus+grafana 了,则只需将应用的指标地址上报给 PE 或者通过接口上报即可。此处我们假设大家没有 Prometheus+grafana,然后按照下面描述进行操作。 ## 搭建 Prometheus[​](#搭建-prometheus "搭建 Prometheus的直接链接") 此处我们通过 docker-compose 来搭建 Prometheus, docker-compose.yml 文件如下: ``` version: '2.2' services: tapi: logging: driver: 'json-file' options: max-size: '50m' image: prom/prometheus restart: always volumes: - ./prometheus_data:/prometheus_data:rw - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./targets.json:/etc/prometheus/targets.json command: - '--storage.tsdb.path=/prometheus_data' - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention=10d' - '--web.enable-lifecycle' ports: - '9090:9090' ``` `prometheus.yml` 文件如下: ``` global: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. scrape_configs: - job_name: 'node' file_sd_configs: - refresh_interval: 1m files: - '/etc/prometheus/targets.json' - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] ``` 然后采集的 `targets.json` 如下:下面文件里面 `${ip}` 替换为 Node.js 应用所在服务器的 ip 地址。 ``` [ { "targets": ["${ip}:7001"], "labels": { "env": "prod", "job": "api" } } ] ``` 然后我们启动 `docker-compose.yml` 文件, ``` $ docker-compose up ``` 至此,Prometheus 已经会去拉取我们 Node 应用程序的指标数据了。 如果想要更新 target 怎么做: 修改了这个 targets.json 文件后,通过 prometheus 的 reload 方法进行热加载。 方法如下: ``` $ curl -X POST http://${prometheus的ip}:9090/-/reload ``` 然后我们可以查看 prometheus 的页面也可以确认是否生效,界面地址: ``` http://${prometheus的ip}:9090/classic/targets ``` 接下来就是如何展示这些采集到的数据了。 ## 数据展示[​](#数据展示 "数据展示的直接链接") 我们可以借助 Grafana 来展示我们的数据。 此处我们简单通过 Docker 来搭建一下 Grafana: ``` $ docker run -d --name=grafana -p 3000:3000 grafana/grafana ``` 也可以将 grafana 和 prometheus 放在一起使用 docker-compose 统一管理。 将 grafana 添加到 `docker-compose.yml`, 示例如下: ``` version: '2.2' services: tapi: logging: driver: 'json-file' options: max-size: '50m' image: prom/prometheus restart: always volumes: - ./prometheus_data:/prometheus_data:rw # prometheus Data mapping directory - ./prometheus.yml:/etc/prometheus/prometheus.yml # prometheus Configuration mapping file - ./targets.json:/etc/prometheus/targets.json command: - '--storage.tsdb.path=/prometheus_data' - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention=10d' - '--web.enable-lifecycle' ports: - '9090:9090' grafana: image: grafana/grafana container_name: "grafana0" ports: - "3000:3000" restart: always volumes: - "./grafana_data:/var/lib/grafana" # grafana data mapping directory - "./grafana_log:/var/log/grafana" # grafana log mapping directory ``` 重启 `docker-compose.yml` 文件 ``` docker-compose restart ``` ![](https://cdn.nlark.com/yuque/0/2022/png/525744/1667300763153-5ee476a7-00ff-4899-92ba-5985995b4862.png) 完成以上任意一种, 然后我们访问 127.0.0.1:3000,默认账号密码:admin:admin。 访问后效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260561047-c2643a69-6258-491b-937d-9bfc4558252f.png) 然后我们让 Grafana 接入我们的 Prometheus 数据源: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260581029-1e2e06a8-3054-4ad8-96b5-d50ab9bb1612.png) 然后我们点击 Grafana 添加图表: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725466020-28793a78-c03b-48fa-bf16-0c9c8ecc1a94.png) 这边 ID 选择 14403,然后点击 load,然后点击下一步,然后点击 import 后,就能看到我们刚刚接入的效果了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725497338-a32a8982-d51f-4e74-b511-dc10a7c66d80.png) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725514630-4f654f10-ef3a-41f7-b403-02832d3ef7d8.png) 这样开发者可以运维自己的 Node 程序了,例如,是否最近引入了一个 NPM 包导致了什么内存泄漏的情况,是否最近有应用重启的情况了。 当然还能支持其他的自定义操作。 ## Socket-io 场景[​](#socket-io-场景 "Socket-io 场景的直接链接") 使用方法: ``` $ npm install @midwayjs/prometheus-socket-io@3 --save ``` 使用方法: ``` import { Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as prometheus from '@midwayjs/prometheus'; import * as prometheusSocketIo from '@midwayjs/prometheus-socket-io'; @Configuration({ imports: [prometheus, prometheusSocketIo], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration {} ``` 然后在/metrics 这边就能看到 socket-io 的数据了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1631090438583-d925c13c-371a-4037-9f53-edaa34580aab.png) 一共新增 8 个指标。 后续会提供 Grafana 的模版 ID 给大家使用。 ## 功能介绍[​](#功能介绍 "功能介绍的直接链接") * 根据 appName 进行分类 * 查看不同 path 的 qps 情况 * 查看不同 status 的分布情况 * 查询不同 path 的 rt 情况 * 进程的 CPU 使用情况 * 进程的内存使用情况 * 堆栈情况 * Event Loop * 等 --- # RabbitMQ 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务A负责产生消息给消息队列,而服务B则负责消费消息队列中的任务。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01SYMbCz1moVSVLl7S2_!!6000000005001-2-tps-646-251.png) 在Midway中,我们提供了订阅rabbitMQ的能力,专门来满足用户的这类需求。 相关信息: **订阅服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ❌ | ## 基础概念[​](#基础概念 "基础概念的直接链接") RabbitMQ 的概念较为复杂,其基于高级消息队列协议即 Advanced Message Queuing Protocol(AMQP),如果第一次接触请阅读一下相关的参考文档。 AMQP 有一些概念,Queue、Exchange 和 Binding 构成了 AMQP 协议的核心,包括: * Producer:消息生产者,即投递消息的程序。 * Broker:消息队列服务器实体。 * Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。 * Binding:绑定,它的作用就是把 Exchange 和 Queue 按照路由规则绑定起来。 * Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 * Consumer:消息消费者,即接受消息的程序。 简单的理解,消息通过 Publisher 发布到 Exchange(交换机),Consumer 通过订阅 Queue 来接受消息,Exchange 和 Queue 通过路由做连接。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01fLrucw1FVNbCx4NqG_!!6000000000492-2-tps-700-328.png) ## 消费者(Consumer)使用方法[​](#消费者consumer使用方法 "消费者(Consumer)使用方法的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") Midway 提供了订阅 rabbitMQ 的能力,并能够独立部署和使用。安装 `@midwayjs/rabbitmq` 模块及其定义。 ``` $ npm i @midwayjs/rabbitmq@3 --save $ npm i amqplib --save $ npm i @types/amqplib --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/rabbitmq": "^3.0.0", "amqplib": "^0.10.1", // ... }, "devDependencies": { "@types/amqplib": "^0.8.2", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/rabbmitmq` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as rabbitmq from '@midwayjs/rabbitmq'; @Configuration({ imports: [ rabbitmq ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as rabbitmq from '@midwayjs/rabbitmq'; @Configuration({ imports: [ koa, rabbitmq ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ### 目录结构[​](#目录结构 "目录结构的直接链接") 我们一般把能力分为生产者和消费者,而订阅正是消费者的能力。 我们一般把消费者放在 consumer 目录。比如 `src/consumer/userConsumer.ts` 。 ``` ➜ my_midway_app tree . ├── src │ ├── consumer │ │ └── user.consumer.ts │ ├── interface.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` 代码示例如下。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @Inject() ctx: Context; @RabbitMQListener('tasks') async gotData(msg: ConsumeMessage) { this.ctx.channel.ack(msg); } } ``` `@Consumer` 装饰器,提供消费者标识,并且它的参数,指定了某种消费框架的类型,比如,我们这里指定了 `MSListenerType.RABBITMQ` 这个类型,指的就是 rabbitMQ 类型。 标识了 `@Consumer` 的类,对方法使用 `@RabbitMQListener` 装饰器后,可以绑定一个 RabbitMQ 的队列(Queue)。 方法的参数为接收到的消息,类型为 `ConsumeMessage` 。如果返回值需要确认,则需要对服务端进行 `ack` 操作,明确接收到的数据。 如果需要订阅多个队列,可以使用多个方法,也可以使用多个文件。 ### RabbitMQ 消息上下文[​](#rabbitmq-消息上下文 "RabbitMQ 消息上下文的直接链接") 订阅 `RabbitMQ` 数据的上下文,和 Web 同样的,其中包含一个 `requestContext` ,和每次接收消息的数据绑定。 从 ctx 上可以取到 `channel` ,整个 ctx 的定义为: ``` export type Context = { channel: amqp.Channel; requestContext: IMidwayContainer; }; ``` 可以从框架获取定义 ``` import { Context } from '@midwayjs/rabbitmq'; ``` ### 配置消费者[​](#配置消费者 "配置消费者的直接链接") 我们需要在配置中指定 rabbitmq 的地址。 ``` // src/config/config.default import { MidwayConfig } from '@midwayjs/core'; export default { // ... rabbitmq: { url: 'amqp://localhost' } } as MidwayConfig; ``` 更多配置: | 属性 | 描述 | | ------------- | -------------------------------- | | url | rabbitMQ 的连接信息 | | socketOptions | amqplib.connect 的第二个参数 | | reconnectTime | 队列断连后的重试时间,默认 10 秒 | ### Fanout Exchange[​](#fanout-exchange "Fanout Exchange的直接链接") Fanout 是一种特定的交换机,如果满足匹配(binding),就往 Exchange 所绑定的 Queue 发送消息。Fanout Exchange 会忽略 RoutingKey 的设置,直接将 Message 广播到所有绑定的 Queue 中。 即所有订阅该交换机的 Queue 都会收到消息。 比如,下面我们添加了两个 Queue,订阅了相同的交换机。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/core'; import { Context, Application } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('abc', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, } }) async gotData(msg: ConsumeMessage) { this.logger.info('test output1 =>', msg.content.toString('utf8')); // TODO } @RabbitMQListener('bcd', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, } }) async gotData2(msg: ConsumeMessage) { this.logger.info('test output2 =>', msg.content.toString('utf8')); // TODO } } ``` 订阅的 abc 和 bcd 队列,绑定了相同的交换机 logs,最终的结果是,两个方法都会被调用。 ### Direct Exchange[​](#direct-exchange "Direct Exchange的直接链接") Direct Exchange 是 RabbitMQ 默认的 Exchange,完全根据 RoutingKey 来路由消息。设置 Exchange 和 Queue 的 Binding 时需指定 RoutingKey(一般为 Queue Name),发消息时也指定一样的 RoutingKey,消息就会被路由到对应的Queue。 下面的示例代码,我们不填写 Queue Name,只添加一个 routingKey,交换机类型为 direct。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/core'; import { Context, Application } from '../../../../../src'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('', { exchange: 'direct_logs', exchangeOptions: { type: 'direct', durable: false, }, routingKey: 'direct_key', exclusive: true, consumeOptions: { noAck: true, } }) async gotData(msg: ConsumeMessage) { // TODO } } ``` direct 类型的消息,会根据 routerKey 做定向过滤,所以只有特定订阅能收到消息。 ### 装饰器参数[​](#装饰器参数 "装饰器参数的直接链接") `@RabbitMQListener` 装饰器的第一个参数为 queueName,代表需要监听的队列。 第二个参数是一个对象,包含队列,交换机等参数,详细定义如下: ``` export interface RabbitMQListenerOptions { exchange?: string; /** * queue options */ exclusive?: boolean; durable?: boolean; autoDelete?: boolean; messageTtl?: number; expires?: number; deadLetterExchange?: string; deadLetterRoutingKey?: string; maxLength?: number; maxPriority?: number; pattern?: string; /** * prefetch */ prefetch?: number; /** * router */ routingKey?: string; /** * exchange options */ exchangeOptions?: { type?: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string; durable?: boolean; internal?: boolean; autoDelete?: boolean; alternateExchange?: string; arguments?: any; }; /** * consumeOptions */ consumeOptions?: { consumerTag?: string; noLocal?: boolean; noAck?: boolean; exclusive?: boolean; priority?: number; arguments?: any; }; } ``` ### 本地测试[​](#本地测试 "本地测试的直接链接") Midway 提供了一个简单的测试方法用于测试订阅某个数据。 `@midwayjs/mock` 工具提供了一个 `createRabbitMQProducer` 的方法,用于创建一个生产者,通过它,你可以创建一个队列(Queue),以及向这个队列发消息。 然后,我们启动一个 app,就可以自动监听到这个队列中的数据,并执行后续逻辑。 ``` import { createRabbitMQProducer, close, creatApp } from '@midwayjs/mock'; describe('/test/index.test.ts', () => { it('should test create message and get from app', async () => { // create a queue and channel const channel = await createRabbitMQProducer('tasks', { isConfirmChannel: true, mock: false, url: 'amqp://localhost', }); // send data to queue channel.sendToQueue('tasks', Buffer.from('something to do')) // create app and got data const app = await creatApp(); // wait a moment await close(app); }); }); ``` **示例一** 创建一个 fanout exchange。 ``` const manager = await createRabbitMQProducer('tasks-fanout', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'logs'; // Write a message const msg = "Hello World!"; // 声明交换机 manager.assertExchange(ex, 'fanout', { durable: false }) // 'fanout' will broadcast all messages to all the queues it knows // 启动服务 const app = await creatApp('base-app-fanout', { url: 'amqp://localhost', reconnectTime: 2000 }); // 发送到交换机,由于不持久化,需要等订阅服务起来之后再发 manager.sendToExchange(ex, '', Buffer.from(msg)) // 等一段时间 await sleep(5000); // 校验结果 // 关闭 producer await manager.close(); // 关闭 app await close(app); ``` **示例二** 创建一个 direct exchange。 ``` /** * direct 类型的消息,根据 routerKey 做定向过滤 */ const manager = await createRabbitMQProducer('tasks-direct', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'direct_logs'; // Write a message const msg = "Hello World!"; // 声明交换机 manager.assertExchange(ex, 'direct', { durable: false }) // 'fanout' will broadcast all messages to all the queues it knows const app = await creatApp('base-app-direct', { url: 'amqp://localhost', reconnectTime: 2000 }); // 这里指定 routerKey,发送到交换机 manager.sendToExchange(ex, 'direct_key', Buffer.from(msg)) // 校验结果 await manager.close(); await close(app); ``` ## 生产者(Producer)使用方法[​](#生产者producer使用方法 "生产者(Producer)使用方法的直接链接") 生产者(Producer)也就是第一节中的消息产生者,简单的来说就是会创建一个客户端,将消息发送到 RabbitMQ 服务。 注意:当前 Midway 并没有使用组件来支持消息发送,这里展示的示例只是使用纯 SDK 在 Midway 中的写法。 ### 安装依赖[​](#安装依赖-1 "安装依赖的直接链接") ``` $ npm i amqplib amqp-connection-manager --save $ npm i @types/amqplib --save-dev ``` ### 调用服务发送消息[​](#调用服务发送消息 "调用服务发送消息的直接链接") 比如,我们在 service 文件下,新增一个 `rabbitmq.ts` 文件。 ``` import { Provide, Scope, ScopeEnum, Init, Autoload, Destroy } from '@midwayjs/core'; import * as amqp from 'amqp-connection-manager' @Autoload() @Provide() @Scope(ScopeEnum.Singleton) // Singleton 单例,全局唯一(进程级别) export class RabbitmqService { private connection: amqp.AmqpConnectionManager; private channelWrapper; @Init() async connect() { // 创建连接,你可以把配置放在 Config 中,然后注入进来 this.connection = await amqp.connect('amqp://localhost'); // 创建 channel this.channelWrapper = this.connection.createChannel({ json: true, setup: function(channel) { return Promise.all([ // 绑定队列 channel.assertQueue("tasks", { durable: true }), ]); } }); } // 发送消息 public async sendToQueue(queueName: string, data: any) { return this.channelWrapper.sendToQueue(queueName, data); } @Destroy() async close() { await this.channelWrapper.close(); await this.connection.close(); } } ``` 大概就是创建了一个用来封装消息通信的 service,同时他是全局唯一的 Singleton 单例。由于增加了 `@AutoLoad` 装饰器,可以自执行初始化。 这样基础的调用服务就抽象好了,我们只需要在用到的地方,调用 `sendToQueue` 方法即可。 比如: ``` @Provide() export class UserService { @Inject() rabbitmqService: RabbitmqService; async invoke() { // TODO // 发送消息 await this.rabbitmqService.sendToQueue('tasks', {hello: 'world'}); } } ``` ## 参考文档[​](#参考文档 "参考文档的直接链接") * [理解 RabbitMQ Exchange](https://zhuanlan.zhihu.com/p/37198933) * [RabbitMQ for Node.js in 30 steps](https://github.com/Gurenax/node-rabbitmq) --- # Redis 这里介绍如何快速在 Midway 中使用 Redis。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/redis` 是主要的功能包。 ``` $ npm i @midwayjs/redis@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/redis": "^3.0.0", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `src/configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import { join } from 'path'; @Configuration({ imports: [ // ... redis // 导入 redis 组件 ], importConfigs: [ join(__dirname, 'config') ], }) export class MainConfiguration { } ``` ## 配置 Redis[​](#配置-redis "配置 Redis的直接链接") **单客户端配置** ``` // src/config/config.default.ts export default { // ... redis: { client: { port: 6379, // Redis port host: "127.0.0.1", // Redis host password: "auth", db: 0, }, }, } ``` **Sentinel 配置** ``` // src/config/config.default.ts export default { // ... redis: { client: { sentinels: [{ // Sentinel instances port: 26379, // Sentinel port host: '127.0.0.1', // Sentinel host }], name: 'mymaster', // Master name password: 'auth', db: 0 }, }, } ``` **Cluster 模式配置,需要配置多个** ``` // src/config/config.default.ts export default { // ... redis: { // Cluster Redis client: { cluster: true, nodes: [{ host: 'host', port: 'port', },{ host: 'host', port: 'port', }], redisOptions: { family: '', password: 'xxxx', db: 'xxx' } } }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default.ts export default { // ... redis: { // Multi Redis clients: { instance1: { host: 'host', port: 'port', password: 'password', db: 'db', }, instance2: { host: 'host', port: 'port', password: 'password', db: 'db', }, }, }, } ``` 更多参数可以查看 [ioredis 文档](https://github.com/luin/ioredis/blob/master/API.md#new_Redis_new)。 ## 使用 Redis 服务[​](#使用-redis-服务 "使用 Redis 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { RedisService } from '@midwayjs/redis'; @Provide() export class UserService { @Inject() redisService: RedisService; async invoke() { // 简单设置 await this.redisService.set('foo', 'bar'); // 设置过期时间,单位秒 await this.redisService.set('foo', 'bar', 'EX', 10); // 获取数据 const result = await this.redisService.get('foo'); // result => bar } } ``` 可以使用 `RedisServiceFactory` 获取不同的实例。 ``` import { RedisServiceFactory } from '@midwayjs/redis'; import { join } from 'path'; @Provide() export class UserService { @Inject() redisServiceFactory: RedisServiceFactory; async save() { const redis1 = this.redisServiceFactory.get('instance1'); const redis2 = this.redisServiceFactory.get('instance3'); //... } } ``` 也可以通过装饰器获取。 ``` import { RedisServiceFactory, RedisService } from '@midwayjs/redis'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(RedisServiceFactory, 'instance1') redis1: RedisService; @InjectClient(RedisServiceFactory, 'instance3') redis2: RedisService; async save() { //... } } ``` --- # 模板渲染 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ❌ | ## 使用 ejs[​](#使用-ejs "使用 ejs的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") 选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-ejs@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/view-ejs": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ### 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as view from '@midwayjs/view-ejs'; import { join } from 'path' @Configuration({ imports: [ view // 导入 ejs 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ### 配置[​](#配置 "配置的直接链接") 配置后缀,映射到指定的引擎。 ``` // src/config/config.default.ts export default { // ... view: { mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` ### 使用[​](#使用 "使用的直接链接") 注意,默认的 view 目录为 `${appDir}/view` ,在其中创建一个 `hello.ejs` 文件。 目录结构如下: ``` ➜ my_midway_app tree . ├── src │ └── controller ## Controller 目录 │ └── home.ts ├── view ## 模板目录 │ └── hello.ejs ├── test ├── package.json └── tsconfig.json ``` 我们在模板里写一些 ejs 格式的内容,比如: ``` // view/hello.ejs hello <%= data %> ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await this.ctx.render('hello.ejs', { data: 'world', }); } } ``` ### 配置后缀[​](#配置后缀 "配置后缀的直接链接") 默认后缀为 `.html` ,为了改成习惯的 `.ejs` 后缀,我们可以加一个 `defaultExtension` 配置。 ``` // src/config/config.default.ts export default { // ... view: { defaultExtension: '.ejs', mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` 这样我们在渲染时不需要增加后缀。 ``` @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await this.ctx.render('hello', { data: 'world', }); } } ``` ### 默认渲染引擎[​](#默认渲染引擎 "默认渲染引擎的直接链接") 我们可以通过 `defaultViewEngine` 来设置默认的渲染引擎。 其作用是,当遇到的模板后缀,比如 `.html` 未在配置的 `mapping` 字段中找到时,使用该 `defaultViewEngine` 字段指定的引擎来渲染。 ``` // src/config/config.default.ts export default { // ... view: { defaultViewEngine: 'ejs', mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` 这样,如果模板是 `.html` 后缀,由于 `mapping` 中未指定,依旧会使用 `ejs` 来渲染。 ### 配置多个模板目录[​](#配置多个模板目录 "配置多个模板目录的直接链接") 如果我们需要将代码封装为组件提供,就需要支持不同的模板目录。 默认的模板目录在 `${appDir}/view`。我们可以在 `rootDir` 字段增加其他的目录。 ``` // src/config/config.default.ts // 修改默认 view 组件的 default 目录 export default { // ... view: { rootDir: { default: path.join(__dirname, './view'), } }, } // 其他组件需要增加目录的配置 export default { // ... // view 组件的配置 view: { rootDir: { anotherRoot: path.join(__dirname, './view'), } }, } ``` 通过对象合并的机制,使得所有的 `rootDir` 都能合并到一起,组件内部会获取 values 做匹配。 ## 使用 Nunjucks[​](#使用-nunjucks "使用 Nunjucks的直接链接") 和 ejs 类似,引入对应组件即可。 1、选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-nunjucks@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/view-nunjucks": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` 2、引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path' @Configuration({ imports: [ view // 导入 nunjucks 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 3、增加 nunjucks 的配置,比如默认使用 nunjucks。 ``` export default { // ... view: { defaultViewEngine: 'nunjucks', mapping: { '.nj': 'nunjucks', }, }, } ``` 4、在 view 目录增加模板 ``` // view/test.nj hi, {{ user }} ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await ctx.render('test.nj', { user: 'midway' }); } } ``` 访问后会输出 `hi, midway` 。 如果有自定义 filter 的需求,可以在入口处增加,比如下面增加了一个名为 `hello` 的 filter。 ``` import { App, Configuration, Inject } from '@midwayjs/core'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path' @Configuration({ imports: [view], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { @App() app; @Inject() env: view.NunjucksEnvironment; async onReady(){ this.env.addFilter('hello', (str) => { return 'hi, ' + str; }); } } ``` 在模板里可以使用 ``` {{ name | hello }} ``` 然后渲染 ``` // controller // ... await ctx.render('test.nj', { name: 'midway' }); ``` 也会输出 `hi, midway` 。 ## 自定义模板引擎[​](#自定义模板引擎 "自定义模板引擎的直接链接") 默认我们只提供了 ejs 和 nunjucks 的模板引擎,你也可以编写自己的模板引擎代码。 ### 实现模板引擎[​](#实现模板引擎 "实现模板引擎的直接链接") 首先需要创建一个请求作用域的模板引擎类,它将在每个请求执行时初始化。你需需要实现其中的 `render` 和 `renderString` 方法。如果你的模板引擎不支持某个方法,可以抛出异常。 ``` // lib/view.ts import { Provide, Config } from '@midwayjs/core'; import { IViewEngine } from '@midwayjs/view'; @Provide() export class MyView implements IViewEngine { @Config('xxxx') viewConfig; async render(name: string, locals?: Record, options?: RenderOptions) { return myengine.render(name, locals, options); } async renderString(tpl: string, locals?: Record, options?: RenderOptions) { throw new Error('not implement'); } }; ``` 这两个方法接受类似的三个参数,`renderString` 第一个参数需要传入待解析的模板内容本身,而 `render` 方法会解析模板文件。 `render(name, locals, viewOptions)` * name: 从 `root`(默认是 `/view` ) 相对的 path * locals: 模板需要的数据 * viewOptions: 每次渲染的模板参数,可覆盖的配置,可以在配置文件中重写,其中包含几个参数: * root: 模板的绝对路径 * name: 调用 render 方法的原始 name 值 * locals: 调用 render 方法的原始 locals 值 `renderString(tpl, locals, viewOptions)` * tpl: 模板名 * locals: 和 `render` 一样 * viewOptions: 和 `render` 一样 ### 注册模板引擎[​](#注册模板引擎 "注册模板引擎的直接链接") 在实现自定义的模板引擎后,我们需要在启动入口注册它。 通过引入 `ViewManager` ,我们可以使用 `use` 方法注册自定义模板引擎。 ``` // src/configuration.ts import { Configuration, Inject, Provide } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as view from '@midwayjs/view'; import { MyView } from './lib/my'; @Configuration({ imports: [koa, view], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { @Inject() viewManager: view.ViewManager; async onReady(){ this.viewManager.use('ejs', MyView); } } ``` ## 注意事项[​](#注意事项 "注意事项的直接链接") 如需在 egg(@midwayjs/web) 场景下使用,请在 `plugin.ts` 中关闭 view 和其相关插件。 ``` import { EggPlugin } from 'egg'; export default { // ... view: false, } as EggPlugin; ``` 否则会出现下面类似的错误。 ``` TypeError: Cannot set property view of # which has only a getter ``` --- # 安全 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用安全组件,支持 `csrf` 、`xss` 等多种安全策略。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装使用[​](#安装使用 "安装使用的直接链接") 1、安装依赖 ``` $ npm i @midwayjs/security --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/security": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` 2、在 configuration 中引入组件 ``` import * as security from '@midwayjs/security'; @Configuration({ imports: [ // ...other components security ], }) export class MainConfiguration {} ``` *** ## 防范常见的安全威胁[​](#防范常见的安全威胁 "防范常见的安全威胁的直接链接") ### 一、CSRF[​](#一csrf "一、CSRF的直接链接") CSRF(Cross-site request forgery 跨站请求伪造),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。 #### 1. 令牌同步模式[​](#1-令牌同步模式 "1. 令牌同步模式的直接链接") 通过响应页面时将 token 渲染到页面上,在开启 `csrf` 配置后,通过 `ctx.csrf` 可以获取到 `csrf token`,可以再返回页面 html 时同步输出 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { return `
title:
`; } } ``` 传递 CSRF token 的字段(上述示例中的 `_csrf`)可以在配置中改变,请查看下述 `配置 -> csrf`。 #### 2. Cookies 模式[​](#2-cookies-模式 "2. Cookies 模式的直接链接") 在 CSRF 默认配置下,token 会被设置在 Cookie 中,可以再前端页面中通过 JS 从 Cookies 中获取,然后再 ajax/fetch 等请求中添加到 `header`、`query` 或 `body` 中。 ``` const csrftoken = Cookies.get('csrfToken'); fetch('/api/post', { method: 'POST', headers: { 'x-csrf-token': csrftoken }, ... }); ``` 默认配置下,框架会将 `CSRF token` 存在 `Cookie` 中,以方便前端 JS 发起请求时获取到。但是所有的子域名都可以设置 Cookie,因此当我们的应用处于无法保证所有的子域名都受控的情况下,存放在 `Cookie` 中可能有被 `CSRF` 攻击的风险。框架提供了一个配置项 `useSession`,可以将 token 存放到 Session 中。 当 `CSRF token` 存储在 `Cookie` 中时,一旦在同一个浏览器上发生用户切换,新登陆的用户将会依旧使用旧的 token(之前用户使用的),这会带来一定的安全风险,因此在每次用户登陆的时候都必须调用 `ctx.rotateCsrfSecret()` 刷新 `CSRF token`,例如: ``` @Controller('/') export class HomeController { @Inject() ctx; @Inject() userService; @Get('/login') async login(@Body('username') username: string, @Body('password') password: string) { const user = await userService.login({ username, password }); this.ctx.session = { user }; this.ctx.rotateCsrfSecret(); return { success: true }; } } ``` ### 二、XSS[​](#二xss "二、XSS的直接链接") `XSS`(cross-site scripting 跨站脚本攻击)攻击是最常见的 Web 攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。 `XSS` 攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。 #### 1. 反射型的 XSS 攻击[​](#1-反射型的-xss-攻击 "1. 反射型的 XSS 攻击的直接链接") 主要是由于服务端接收到客户端的不安全输入,在客户端触发代码执行从而发起 `Web` 攻击。 例如:在某搜索网站搜索时,搜索结果会显示搜索的关键词。搜索关键词填入 ``, 点击搜索后,若页面程序没有对关键词进行处理,这段代码就会直接在页面上执行,弹出 alert。 框架提供了 `ctx.security.escape()` 方法对字符串进行 XSS 过滤。 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { const str = ``; const escapedStr = this.ctx.security.escape(str); // <script>alert("xss") </script> return escapedStr; } } ``` 另外当网站输出的内容是作为 js 脚本的。这个时候需要使用 `ctx.security.js()` 来进行过滤。 还有一种情况,有时候我们需要在 `js` 中输出 `json` ,若未做转义,易被利用为 `XSS` 漏洞。框架提供了 `ctx.security.json(变量)` 来提供 json encode,防止 XSS 攻击。 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { return ``; } } ``` #### 2. 存储型的 XSS 攻击[​](#2-存储型的-xss-攻击 "2. 存储型的 XSS 攻击的直接链接") 通过提交带有恶意脚本的内容存储在服务器上,当其他人看到这些内容时发起 Web 攻击,比如一些网站的评论框中,用户恶意将一些代码作为评论内容,若没有过滤,其他用户看到这个评论时恶意代码就会执行。 框架提供了 `ctx.security.html()` 来进行过滤。 #### 3. 其他 XSS 的防范方式[​](#3-其他-xss-的防范方式 "3. 其他 XSS 的防范方式的直接链接") 浏览器自身具有一定针对各种攻击的防范能力,他们一般是通过开启 Web 安全头生效的。框架内置了一些常见的 Web 安全头的支持。 **CSP** `Content Security Policy`,简称 `CSP`,主要是用来定义页面可以加载哪些资源,减少 `XSS` 的发生。 默认关闭(可通过 `csp: {enable: true}` 配置开启),开启后可以有效的防止 `XSS` 攻击的发生。要配置 `CSP` , 需要对 `CSP` 的 `policy` 策略有了解,具体细节可以参考 [阿里聚安全 - CSP是什么?](https://www.zhihu.com/question/21979782/answer/122682029) **X-Download-Options:noopen** 默认开启(可通过 `noopen: {enable: false}` 配置关闭),禁用 IE 下下载框 Open 按钮,防止 IE 下下载文件默认被打开 XSS。 **X-Content-Type-Options:nosniff** 禁用 IE8 自动嗅探 mime 功能,默认关闭(可通过 `nosniff: {enable: true}` 配置开启),例如 text/plain 却当成 text/html 渲染,特别当本站点 serve 的内容未必可信的时候。 **X-XSS-Protection** IE 提供的一些 XSS 检测与防范,默认开启(可通过 `xssProtection: {enable: false}` 配置关闭) close 默认值 false,即设置为 1; mode=block *** ## 配置[​](#配置 "配置的直接链接") 默认配置如下: ``` // src/config/config.default export default { // ... // 默认配置 security: { csrf: { enable: true, type: 'ctoken', useSession: false, cookieName: 'csrfToken', sessionName: 'csrfToken', headerName: 'x-csrf-token', bodyName: '_csrf', queryName: '_csrf', refererWhiteList: [], }, xframe: { enable: true, value: 'SAMEORIGIN', }, csp: { enable: false, }, hsts: { enable: false, maxAge: 365 * 24 * 3600, includeSubdomains: false, }, noopen: { enable: false, }, nosniff: { enable: false, }, xssProtection: { enable: true, value: '1; mode=block', }, }, } ``` ### csrf[​](#csrf "csrf的直接链接") | 配置项 | 类型 | 作用描述 | 默认值 | | ---------------- | ------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------------------- | | enable | boolean | 是否开启 | true | | type | 'all' / 'any' / 'ctoken' / 'referer' | csrf 校验类型,all/any 等于 ctoken + referer | 'ctoken' 从query/header/body 中获取 csrf token;;'referer' 则可以通过 refererWhiteList 配置白名单 | | useSession | boolean | csrf token 是否存放在 session 中 | false,默认存放在 cookies 中 | | cookieName | string | token 在 cookie 中存放的 字段 | 'csrfToken' | | sessionName | string | token 在 session 中存放的 字段 | 'csrfToken' | | headerName | string | token 在 header 中存放的 字段 | 'x-csrf-token' | | bodyName | string | token 在 body 中存放的 字段 | '\_csrf' | | queryName | string | token 在 query 中存放的 字段 | '\_csrf' | | refererWhiteList | Array\ | 允许的来源白名单 | \[] | #### 配置 refererWhiteList 不生效?[​](#配置-refererwhitelist-不生效 "配置 refererWhiteList 不生效?的直接链接") * 原因一:refererWhiteList 中需要配置 referer 的 host 部分,例如 referer 为 `https://midway-demo.com:1234/docs`,则 refererWhiteList 中需要配置 `midway-demo.com:1234`。 * 原因二:refererWhiteList 仅在 csrf 配置中 type 为 `referer` 的情况下生效,默认 type 为 `ctoken`,需要修改为 `referer`。 * 原因三:发送的http请求中的 referer 字段不是一个标准的 url 地址(例如没有加上请求协议等),参考 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer) 文档 ### xframe[​](#xframe "xframe的直接链接") xframe 用来配置 `X-Frame-Options` 响应头,用来给浏览器指示允许一个页面可否在 `frame`, `iframe`, `embed` 或者 `object` 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免 `clickjacking` 攻击。 `X-Frame-Options` 有三个可能的值: * X-Frame-Options: deny:页面不允许在 frame 中展示 * X-Frame-Options: sameorigin:该页面可以在相同域名页面的 frame 中展示 * X-Frame-Options: allow-from [https://example.com/:该页面可以在指定来源的](https://example.com/%EF%BC%9A%E8%AF%A5%E9%A1%B5%E9%9D%A2%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%9D%A5%E6%BA%90%E7%9A%84) frame 中展示 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | ------------------ | ------------ | | enable | boolean | 是否开启 | true | | value | string | X-Frame-Options 值 | 'SAMEORIGIN' | ### hsts[​](#hsts "hsts的直接链接") `HTTP Strict Transport Security`(通常简称为 `HSTS` )是一个安全功能,它告诉浏览器只能通过 `HTTPS` 访问当前资源,而不是 `HTTP`。 | 配置项 | 类型 | 作用描述 | 默认值 | | ----------------- | ------- | ------------------------------------------------------------------------------- | ------------------------ | | enable | boolean | 是否开启 | false | | maxAge | number | 在浏览器收到这个请求后的多少 `秒` 时间内凡是访问这个域名下的请求都使用HTTPS请求 | `365 * 24 * 3600` 即一年 | | includeSubdomains | boolean | 此规则是否适用于该网站的所有子域名 | false | ### csp[​](#csp "csp的直接链接") HTTP 响应头 `Content-Security-Policy` 允许站点管理者控制指定的页面加载哪些资源。这将帮助防止跨站脚本攻击(XSS)。 | 配置项 | 类型 | 作用描述 | 默认值 | | ---------- | --------------------------------------------------------- | ---------------- | ------ | | enable | boolean | 是否开启 | false | | policy | Object\ | 策略列表 | | | reportOnly | boolean | 是否开启 | false | | supportIE | boolean | 是否支持IE浏览器 | false | 详细的 `policy` 配置可以参考: [Content Security Policy (CSP) 是什么?阿里聚安全](https://www.zhihu.com/question/21979782/answer/122682029) ### noopen[​](#noopen "noopen的直接链接") 用于指定 `IE 8` 以上版本的用户不打开文件而直接保存文件。在下载对话框中不显式“打开”选项。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | -------- | ------ | | enable | boolean | 是否开启 | false | ### nosniff[​](#nosniff "nosniff的直接链接") 开启后,如果从 `script` 或 `stylesheet` 读入的文件的 `MIME` 类型与指定 `MIME` 类型不匹配,不允许读取该文件。用于防止 `XSS` 等跨站脚本攻击。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | -------- | ------ | | enable | boolean | 是否开启 | false | ### xssProtection[​](#xssprotection "xssProtection的直接链接") 用于启用浏览器的XSS过滤功能,以防止 `XSS` 跨站脚本攻击。 `X-XSS-Protection` 响应头是 `IE`,`Chrome` 和 `Safari` 的一个特性,当检测到跨站脚本攻击 (XSS (en-US))时,浏览器将停止加载页面。若网站设置了良好的 `Content-Security-Policy` 来禁用内联 JavaScript ('unsafe-inline'),现代浏览器不太需要这些保护, 但其仍然可以为尚不支持 `CSP` 的旧版浏览器的用户提供保护。 `X-XSS-Protection` 可以配置下述四个值 * `0`: 禁止XSS过滤。 * `1`:启用XSS过滤(通常浏览器是默认的)。 如果检测到跨站脚本攻击,浏览器将清除页面(删除不安全的部分)。 * `1;mode=block`:启用XSS过滤。 如果检测到攻击,浏览器将不会清除页面,而是阻止页面加载。 * `1; report=`: Chromium only,启用XSS过滤。 如果检测到跨站脚本攻击,浏览器将清除页面并使用CSP report-uri (en-US)指令的功能发送违规报告。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | --------------------- | --------------- | | enable | boolean | 是否开启 | false | | value | string | X-XSS-Protection 配置 | `1; mode=block` | --- # Sequelize 本文档介绍如何在 Midway 中使用 Sequelize。 提示 当前模块从 v3.4.0 开始已经重构,历史写法兼容,如果查询历史文档,请参考 [这里](/docs/3.0.0/legacy/sequelize.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 如果想使用新版本的用法,请参考下面的流程,将老代码进行修改,新老代码不能混用。 升级方法: * 1、请在业务依赖中显式添加 `sequelize` 和 `sequelize-typescript` * 2、不再使用 `BaseTable` 装饰器,而直接使用 `sequelize-typescript` 包导出的 `Table` 装饰器 * 3、在 `src/config.default` 的 `sequelize` 部分配置调整,参考下面的数据源配置部分 * 3.1 修改为数据源的形式 `sequelize.dataSource` * 3.2 将实体模型在数据源的 `entities` 字段中声明 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/sequelize@3 sequelize sequelize-typescript --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/sequelize": "^3.0.0", "sequelize": "^6.21.3", "sequelize-typescript": "^2.1.0" // ... }, "devDependencies": { // ... } } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 下面的文档,我们将以 `mysql2` 作为示例。 ### Directory structure[​](#directory-structure "Directory structure的直接链接") 一个基础的参考目录结构如下。 ``` MyProject ├── src │ ├── config │ │ └── config.default.ts │ ├── entity │ │ └── person.entity.ts │ ├── configuration.ts │ └── service ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 文件中启用组件。 ``` import { Configuration, ILifeCycle } from '@midwayjs/core'; import { join } from 'path'; import * as sequelize from '@midwayjs/sequelize'; @Configuration({ imports: [ // ... sequelize, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle { // ... } ``` ## 模型定义[​](#模型定义 "模型定义的直接链接") ### 1、创建 Model(Entity)[​](#1创建-modelentity "1、创建 Model(Entity)的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 Sequelize 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `person` 举例。新建 entity 目录,在其中添加实体文件 `person.entity.ts` ,一个简单的实体如下。 ``` // src/entity/person.entity.ts import { Table, Model, Column, HasMany } from 'sequelize-typescript'; @Table export class Hobby extends Model { @Column name: string; } @Table export class Person extends Model { @Column name: string; @Column birthday: Date; @HasMany(() => Hobby) hobbies: Hobby[]; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 `@Table` 装饰器可以在不传递任何参数的情况下使用,更多参数请查看 [定义选项](https://sequelize.org/v5/manual/models-definition.html#configuration) 。 ``` @Table({ timestamps: true, ... }) export class Person extends Model {} ``` ### 2、主键[​](#2主键 "2、主键的直接链接") 主键 (id) 将从基类 Model 继承。 一般来说主键是 Integer 类型并且是自增的。 主键设置有两种方法,设置 `@Column({primaryKey: true})` 或者 `@PrimaryKey`。 比如: ``` import { Table, Model, PrimaryKey } from 'sequelize-typescript'; @Table export class Person extends Model { @PrimaryKey name: string; } ``` ### 3、时间列[​](#3时间列 "3、时间列的直接链接") 主要指代的是 `@CreatedAt`, `@UpdatedAt`, `@DeletedAt` 单个装饰器标注的列。 比如: ``` import { Table, Model, CreatedAt, UpdatedAt, DeletedAt } from 'sequelize-typescript'; @Table export class Person extends Model { @CreatedAt creationDate: Date; @UpdatedAt updatedOn: Date; @DeletedAt deletionDate: Date; } ``` | 装饰器 | 描述 | | ------------ | ----------------------------------------------------------------------- | | `@CreatedAt` | 会设置 `timestamps=true` 和 `createdAt='creationDate'` | | `@UpdatedAt` | 会设置 `timestamps=true` 和 `updatedAt='updatedOn'` | | `@DeletedAt` | 会设置 `timestamps=true`, `paranoid=true` 和 `deletedAt='deletionDate'` | ### 4、普通列[​](#4普通列 "4、普通列的直接链接") @Column 装饰器用于标注普通列,可以在不传递任何参数的情况下使用。 但是因此需要能够自动推断 js 类型(详见[类型推断](https://github.com/sequelize/sequelize-typescript#type-inference))。 ``` import { Table, Model, Column } from 'sequelize-typescript'; @Table export class Person extends Model { @Column name: string; } ``` 或者指定列类型。 ``` import { Table, Column, DataType } from 'sequelize-typescript'; @Table export class Person extends Model { @Column(DataType.TEXT) name: string; } ``` 更多类型描述,请参考 [这里](https://sequelize.org/v5/manual/models-definition.html#configuration)。 比如: ``` import { Table, Model, Column, DataType } from 'sequelize-typescript' @Table export class Person extends Model { @Column({ type: DataType.FLOAT, comment: 'Some value', ... }) value: number; } ``` | 装饰器 | 描述 | | ------------------------------------ | ------------------------------------------------------------------------------------------------- | | `@Column` | 使用推导的 [dataType](https://sequelize.org/v5/manual/models-definition.html#data-types) 作为类型 | | `@Column(dataType: DataType)` | 显式设置 [dataType](https://sequelize.org/v5/manual/models-definition.html#data-types) | | `@Column(options: AttributeOptions)` | 设置 [attribute options](https://sequelize.org/v5/manual/models-definition.html#configuration) | ## 数据源配置[​](#数据源配置 "数据源配置的直接链接") 新版本我们启用了 [数据源机制](/docs/3.0.0/data_source.md),在 `src/config.default.ts` 中配置: ``` // src/config/config.default.ts import { Person } from '../entity/person.entity'; export default { // ... sequelize: { dataSource: { // 第一个数据源,数据源的名字可以完全自定义 default: { database: 'test4', username: 'root', password: '123456', host: '127.0.0.1', port: 3306, encrypt: false, dialect: 'mysql', define: { charset: 'utf8' }, timezone: '+08:00', // 本地的时候,可以通过 sync: true 直接 createTable sync: false, // 实体形式 entities: [Person], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], }, // 第二个数据源 default2: { // ... }, }, }, }; ``` ## 模型关联[​](#模型关联 "模型关联的直接链接") 可以通过 `HasMany` 、`@HasOne` 、`@BelongsTo`、`@BelongsToMany` 和 `@ForeignKey` 装饰器在模型中直接描述关系。 提示 你不需要在数据库中创建外键也可以使用这个功能。 ### 一对多[​](#一对多 "一对多的直接链接") ``` import { Table, Model, Column, ForeignKey, BelongsTo, HasMany } from 'sequelize-typescript'; @Table export class Player extends Model { @Column name: string; @Column num: number; @ForeignKey(() => Team) @Column teamId: number; @BelongsTo(() => Team) team: Team; } @Table export class Team extends Model { @Column name: string; @HasMany(() => Player) players: Player[]; } ``` `sequelize-typescript` 会在内部进行关联,会自动查询出相关的依赖。 比如通过 `find` 查询。 ``` const team = await Team.findOne({ include: [Player] }); team.players.forEach((player) => { console.log(`Player ${player.name}`); }); ``` ### 多对多[​](#多对多 "多对多的直接链接") ``` import { Table, Model, Column, ForeignKey, BelongsToMany } from 'sequelize-typescript'; @Table export class Book extends Model { @BelongsToMany(() => Author, () => BookAuthor) authors: Author[]; } @Table export class Author extends Model { @BelongsToMany(() => Book, () => BookAuthor) books: Book[]; } @Table export class BookAuthor extends Model { @ForeignKey(() => Book) @Column bookId: number; @ForeignKey(() => Author) @Column authorId: number; } ``` 上面的类型,在某些场景下是不安全的,比如上面的 `BookAuthor`,`Author` 的 `books` 的类型,可能会丢失某些属性,需要手动设置。 ``` @BelongsToMany(() => Book, () => BookAuthor) books: Array; ``` ### 一对一[​](#一对一 "一对一的直接链接") 对于一对一,使用 `@HasOne(...)`(关系的外键存在于另一个模型上)和 `@BelongsTo(...)`(关系的外键存在于此模型上)。 比如: ``` import { Table, Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { User } from './user.entity'; @Table export class Photo extends Model { @ForeignKey(() => User) @Column({ comment: '用户Id', }) userId: number; @BelongsTo(() => User) user: User; @Column({ comment: '名字', }) name: string; } @Table export class User extends Model { @Column name: string; } ``` ### 模型循环依赖[​](#模型循环依赖 "模型循环依赖的直接链接") 如果你使用了 `@BelongsTo` 装饰器,很容易触发一个模型循环依赖的错误,比如: ``` ReferenceError: Cannot access 'Photo' before initialization ``` 你可以将类型使用 `ReturnType` 包裹起来。 ``` import { Table, Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { User } from './user.entity'; @Table export class Photo extends Model { // ... @BelongsTo(() => User) user: ReturnType<() => User>; } ``` ## 静态操作方法[​](#静态操作方法 "静态操作方法的直接链接") 如果是单个数据源,可以使用下面的静态方法。 ### 保存[​](#保存 "保存的直接链接") 在需要调用的地方,使用实体模型来操作。 ``` import { Provide } from '@midwayjs/core'; import { Person } from '../entity/person.entity'; @Provide() export class PersonService { async createPerson() { const person = new Person({ name: 'bob', age: 99 }); await person.save(); } } ``` ### 查找和更新[​](#查找和更新 "查找和更新的直接链接") ``` import { Provide } from '@midwayjs/core'; import { Person } from '../entity/person.entity'; @Provide() export class PersonService { async updatePerson() { const person = await Person.findOne(); // 更新 person.age = 100; await person.save(); await Person.update( { name: 'bobby', }, { where: { id: 1 }, } ); } } ``` ## Repository 模式[​](#repository-模式 "Repository 模式的直接链接") Repository 模式可以将查找、创建等静态操作从模型定义中分离出来。它还支持与多个 sequelize 实例(多数据源)一起使用。 ### 启动 Repository 模式[​](#启动-repository-模式 "启动 Repository 模式的直接链接") 和数据源配置相同,只是多了一个属性。 ``` // src/config/config.default.ts import { Person } from '../entity/person.entity'; export default { // ... sequelize: { dataSource: { default: { // ... entities: [Person], // 多了这一个 repositoryMode: true, }, }, sync: false, }, }; ``` 如果是多个数据源,务必在每个数据源都开启该属性,开启后,原有的静态操作方法不再可用。 你需要使用 `Repository` 的操作方式。 ### 使用 Repository 模式[​](#使用-repository-模式 "使用 Repository 模式的直接链接") 基本 API 和静态操作相同,Midway 对其进行了一些简单包裹,使用 `InjectRepository` 装饰器可以在服务中注入 `Repository`。 ``` import { Controller, Get } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import { Photo } from '../entity/photo.entity'; import { User } from '../entity/user.entity'; import { Op } from 'sequelize'; import { Repository } from 'sequelize-typescript'; @Controller('/') export class HomeController { @InjectRepository(User) userRepository: Repository; @InjectRepository(Photo) photoRepository: Repository; @Get('/') async home() { // 查询 let result = await this.photoRepository.findAll(); console.log(result); // 新增 await this.photoRepository.create({ name: '123', }); // 删除 await this.photoRepository.destroy({ where: { name: '123', }, }); // 联合查询 // SELECT * FROM photo WHERE name = "23" OR name = "34"; let result = await this.photoRepository.findAll({ where: { [Op.or]: [{ name: '23' }, { name: '34' }], }, }); // => result // 连表查询 let result = await this.userRepository.findAll({ include: [Photo] }); // => result } } ``` 关于 OP 的更多用法: ### 多库的支持[​](#多库的支持 "多库的支持的直接链接") 在 Repository 模式下,我们可以在 `InjectRepository` 参数中指定特定的数据源。 ``` import { Controller } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import { Photo } from '../entity/photo.entity'; import { User } from '../entity/user.entity'; import { Repository } from 'sequelize-typescript'; @Controller('/') export class HomeController { // 指定某个数据源 @InjectRepository(User, 'default') userRepository: Repository; // ... } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 数据源同步配置[​](#数据源同步配置 "数据源同步配置的直接链接") sequelize 在同步数据源时可以添加 sync 的参数。 ``` export default { // ... sequelize: { dataSource: { default: { sync: true, syncOptions: { force: false, alter: true, }, }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default', }, }; ``` ### 指定默认数据源[​](#指定默认数据源 "指定默认数据源的直接链接") 在包含多个数据源时,可以指定默认的数据源。 ``` export default { // ... sequelize: { dataSource: { default1: { // ... }, default2: { // ... }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default1', }, }; ``` ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的 sequelize 对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { SequelizeDataSourceManager } from '@midwayjs/sequelize'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(SequelizeDataSourceManager); const conn = dataSourceManager.getDataSource('default'); await conn.authenticate(); } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/sequelize'; import { Sequelize } from 'sequelize-typescript'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: Sequelize; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: Sequelize; async onReady(container: IMidwayContainer) { // ... } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Dialect needs to be explicitly supplied as of v4.0.0[​](#1dialect-needs-to-be-explicitly-supplied-as-of-v400 "1、Dialect needs to be explicitly supplied as of v4.0.0的直接链接") 原因为配置中数据源没有指定 `dialect` 字段,确认数据源的结构,格式以及配置合并的结果。 ### 2、生成实体列[​](#2生成实体列 "2、生成实体列的直接链接") 请参考社区提供的模块,如 [sequelize-typescript-generator](https://github.com/spinlud/sequelize-typescript-generator) ### 3、Raw Query[​](#3raw-query "3、Raw Query的直接链接") 如果遇到比较复杂的,可以使用 [raw query 方法](https://sequelize.org/v5/manual/raw-queries.html) ### 4、TS2612 错误[​](#4ts2612-错误 "4、TS2612 错误的直接链接") 如果你的模型列报了 TS2612 错误,比如: ``` src/entity/AesTenantConfigInfo.ts:29:6 - error TS2612: Property 'id' will overwrite the base property in 'Model'. If this is intentional, add an initializer. Otherwise, add a 'declare' modifier or remove the redundant declaration. 29 id?: number; ~~ ``` 可以将其赋一个空值。 ``` import { Table, Column } from 'sequelize-typescript'; @Table export class User extends Model { @Column({ primaryKey: true, autoIncrement: true, type: DataType.BIGINT, }) id?: number = undefined; } ``` ## 其他[​](#其他 "其他的直接链接") * 上面的文档,翻译自 sequelize-typescript,更多 API ,请参考 [英文文档](/docs/3.0.0/extensions/\(https://github.com/sequelize/sequelize-typescrip\)) * 一些 [案例](https://github.com/ddzyan/midway-practice) --- # SocketIO Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01YTye6U22gICvarVur_!!6000000007149-2-tps-1204-352.png) Midway 提供了对 Socket.io 的支持和封装,能够简单的创建一个 Socket.io 服务。本篇内容演示了如何在 Midway 体系下,提供 Socket.io 服务的方法。 Midway 当前采用了最新的 [Socket.io (v4.0.0)](https://socket.io/docs/v4) 进行开发。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 Socket.io 的依赖。 ``` $ npm i @midwayjs/socketio@3 --save ## 客户端可选 $ npm i @types/socket.io-client socket.io-client --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/socket.io": "^3.0.0", // 客户端可选 "socket.io-client": "^4.4.1", // ... }, "devDependencies": { // 客户端可选 "@types/socket.io-client": "^1.4.36", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/socket.io` 可以作为独立主框架使用。 ``` import { Configuration } from '@midwayjs/core'; import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [socketio], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [koa, socketio], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 下面是 Socket.io 项目的基础目录结构,和传统应用类似,我们创建了 `socket` 目录,用户存放 Soscket.io 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## socket.io 服务的文件 │ └── hello.controller.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## Socket.io 工作原理[​](#socketio-工作原理 "Socket.io 工作原理的直接链接") Socket.io 服务器和 Socket.io 客户端(浏览器,Node.js 或另一种编程语言)之间的双向通道通过 [WebSocket连接](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) 建立起来,在不可用时,将使用 HTTP 长轮询作为备用手段。 Socket.io 代码是基于 Engine.io 库搭建起来的,是属于 Engine.io 的上层实现。Engine.io 负责整个服务端和客户端连接的部分,包括连接检查,传输方式等等。而 Socket.io 负责上层的重连,封包缓冲,广播等等特性。 Socket.io(Engine.io)实现了两种 Transports(传输方式)。 第一种是 HTTP 长轮询。HTTP Get 请求用于 long-running(长连接),Post 请求用于 short-running(短连接)。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01xhdZHA1XTEpUue7CQ_!!6000000002924-2-tps-1778-1068.png) 第二种是 WebSocket 协议,直接基于 [WebSocket Connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 实现。它在服务器和客户端之间提供了双向且低延迟的通信通道。 在默认的情况下,Socket.io 会先采用 HTTP 长轮询进行连接,并发送一个类似下面结构的数据。 ``` { "sid": "FSDjX-WRwSA4zTZMALqx", // 连接的 session id "upgrades": ["websocket"], // 可升级的协议 "pingInterval": 25000, // 心跳时间间隔 "pingTimeout": 20000 // 心跳超时时间 } ``` 当当前的服务满足升级到 WebSocket 协议的要求时,会自动升级到 WebSocket 协议,如下图。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01QHZi9x1mz2ZLecco3_!!6000000005024-2-tps-585-216.png) * 1、第一次握手,传输 sid 等结构 * 2、使用 HTTP 长轮询发送数据 * 3、使用 HTTP 长轮询返回数据 * 4、升级协议,使用 WebSocket 协议发送数据 * 5、当协议升级后,关闭之前的长轮询 之后就开始正常的 WebSocket 通信了。 ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController` 装饰器定义 Socket 服务。 ``` @WSController('/') export class HelloController { // ... } ``` `@WSController` 的入参,指代了每个 Socket 的 Namespace(非 path)。如果不提供 Namespace,每个 Socket.io 会自动创建一个 `/` 的 Namespace,并且将客户端连接都归到其中。 信息 这里的 namespace 支持字符串和正则。 当 Namespace 有客户端连接时,会触发 `connection` 事件,我们在代码中可以使用 `@OnWSConnection()` 装饰器来修饰一个方法,当每个客户端第一次连接到该 Namespace 时,将自动调用该方法。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod() { console.log('on client connect', this.ctx.id); } } ``` 信息 这里的 ctx 等价于 socket 实例。 ## 消息和响应[​](#消息和响应 "消息和响应的直接链接") Socket.io 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()` 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, Provide, OnWSMessage, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') async gotMessage(data) { console.log('on data got', this.ctx.id, data); } } ``` 注意,由于 Socket.io 在一个事件中可以传递多个数据,这里的参数可以是多个。 ``` @OnWSMessage('myEvent') async gotMessage(data1, data2, data3) { // ... } ``` 当获取到数据之后,通过业务逻辑处理数据,然后将结果返回给客户端,返回的时候,我们也是通过另一个事件发送给客户端。 通过 `@WSEmit` 装饰器来将方法的返回值返回给客户端。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { return 'hello world'; // 这里将 hello world 字符串返回给客户端 } } ``` 上面的代码,我们的方法返回值 hello world,将自动发送给客户端监听的 `myEventResult` 事件。 ## Socket 中间件[​](#socket-中间件 "Socket 中间件的直接链接") Socket 中的中间件的写法和 [Web 中间件 ](/docs/3.0.0/middleware.md)相似,但是加载的时机略有不同。 由于 Socket 有连接和接收消息两个阶段,所以中间件以此分为几类。 * 全局 Connection 中间件,会对所有 namespace 下的 connection 生效 * 全局 Message 中间件,会对所有 namespace 下的 message 生效 * Controller 中间件,会对单个 namespace 下的 connection 和 message 生效 * Connection 中间件,会对单个 namespace 下的 connection 生效 * Message 中间件,会对单个 namespace 下的 message 生效 ### 中间件写法[​](#中间件写法 "中间件写法的直接链接") 注意,中间件必须通过 `return` 返回结果。 ``` // src/middleware/socket.middleware.ts import { Middleware } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/socketio'; @Middleware() export class SocketMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... return await next(); } } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 和 Web 中间件类似,通过 `socket.io` 的 app 实例,注册中间件。 ``` import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [ socketio ], // ... }) export class MainConfiguration { @App('socketIO') app: Application; async onReady() { // 可以注册全局 connection 中间件 this.app.useConnectionMiddleware(SocketMiddleware); // 也可以注册全局 Message 中间件 this.app.useMiddleware(SocketMiddleware); } } ``` ### Namespace 中的中间件[​](#namespace-中的中间件 "Namespace 中的中间件的直接链接") 通过装饰器,注册不同阶段的中间件。 比如 Namespace 级别的中间件,会对单个 namespace 下的 connection 和 message 生效。 ``` // ... // Namespace 级别的中间件 @WSController('/api', { middleware: [SocketMiddleware]}) export class APIController { } ``` Connection 中间件,在连接时生效。 ``` // ... @WSController('/api') export class APIController { // Connection 触发时的中间件 @OnWSConnection({ middleware: [SocketMiddleware] }) init() { // ... } } ``` Message 中间件,接收到特定消息时生效。 ``` // ... @WSController('/api') export class APIController { // Message 触发时的中间件 @OnWSMessage('my', { middleware: [SocketMiddleware] }) @WSEmit('ok') async gotMyMessage() { // ... } } ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") 由于 socket.io 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway 框架一起启动)。 当作为独立框架启动时,需要指定端口。 ``` // src/config/config.default export default { // ... socketIO: { port: 3000, }, } ``` 当作为副框架启动时(比如和 http ,由于 http 在单测时未指定端口(使用 supertest 自动生成),无法很好的测试,可以仅在测试环境显式指定一个端口。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, socketIO: { port: 3000, }, } ``` 提示 * 1、这里的端口仅为 WebSocket 服务在测试时启动的端口 * 2、koa 中的端口为 null,即意味着在测试环境下,不配置端口,不会启动 http 服务 和其他 Midway 测试方法一样,我们使用 `createApp` 启动项目。 ``` import { createApp, close } from '@midwayjs/mock' // 这里使用的 Framework 定义,以主框架为准 import { Framework } from '@midwayjs/koa'; describe('/test/index.test.ts', () => { it('should create app and test socket.io', async () => { const app = await createApp(); //... await close(app); }); }); ``` 你可以直接使用 `socket.io-client` 来测试。也可以使用 Midway 提供的基于 `socket.io-client` 模块封装的测试客户端。 假如我们的服务端处理逻辑如下(返回客户端传递的数据相加的结果): ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 测试代码如下: ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 拿到结果返回 const data = await new Promise(resolve => { client.on('myEventResult', resolve); // 发送事件 client.send('myEvent', 1, 2, 3); }); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 如果多个客户端,也可以使用更简单的写法,使用 node 自带的 `events` 模块的 `once` 方法来优化,就会变成下面的代码。 ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 用事件的 promise 写法监听 const gotEvent = once(client, 'myEventResult'); // 发送事件 client.send('myEvent', 1, 2, 3); // 等待返回 const [data] = await gotEvent; // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 等待回执(ack)的消息[​](#等待回执ack的消息 "等待回执(ack)的消息�的直接链接") Socket.io 支持一种直接返回消息的写法。当客户端传递消息的时候,如果最后一个参数为一个 function(callback),则服务端可以拿到这个 callback,将数据直接返回给客户端,不需要创建一个新的消息。 我们的服务代码不需要变化, `@midwayjs/socketio` 内部会判断最后一个参数,自动返回给客户端。 比如,服务端代码: ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 客户端测试代码: ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 发送事件,这里使用了 await 的写法 const data = await client.sendWithAck('myEvent', 1, 2, 3); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` ## 常见的消息和广播[​](#常见的消息和广播 "常见的消息和广播的直接链接") 以下面的代码示例举例: ``` import { Context, Application } from '@midwayjs/socketio'; import { WSController, OnWSMessage, WSEmit, App, Inject } from '@midwayjs/core'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @App('socketIO') app: Application; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { // TODO } } ``` 发送给客户端(也可以用装饰器形式直接 return)。 ``` this.ctx.emit("hello", "can you hear me?", 1, 2, "abc"); ``` 发送给的所有除发件人以外的所有客户端。 ``` this.ctx.broadcast.emit("broadcast", "hello friends!"); ``` 发送给所有在 `game` 房间的客户端(除了发送者)。 ``` this.ctx.to("game").emit("nice game", "let's play a game"); ``` 发送给所有的 `game1` 和 `game2` 房间的客户端(除了发送者)。 ``` this.ctx.to("game1").to("game2").emit("nice game", "let's play a game (too)"); ``` 发送给所有 `game` 房间的客户端,包括发送者。 ``` this.app.in("game").emit("big-announcement", "the game will start soon"); ``` 给 `myNamespace` 命名空间的客户端广播,包括发送者。 ``` // 从 app 发送 this.app.of("myNamespace").emit("bigger-announcement", "the tournament will start soon"); // 从 ctx 发送 this.ctx.nsp.emit("bigger-announcement", "the tournament will start soon"); ``` 发送到特定的 namespace 和 room,包括发送者。 ``` // 从 app 发送 this.app.of("myNamespace").to("room").emit("event", "message"); // 从 ctx 发送 this.ctx.nsp.emit("bigger-announcement", "the tournament will start soon"); ``` 发送给所有连接到当前节点上的客户端(多个节点的时候,就是多进程) ``` this.app.local.emit("hi", "my lovely babies"); ``` ## Application(io 对象)[​](#applicationio-对象 "Application(io 对象)的直接链接") 传统的 Socket.io 服务端创建代码如下: ``` const io = require("socket.io")(3000); io.on("connection", socket => { // ... }); ``` 在 `@midwayjs/socketio` 框架中,Application 实例即为该 io 实例,类型和能力保持一致。即通过 `@App` 装饰器注入的 app 实例,即为 io 对象。 我们可以通过该对象做一些全局的事情。 比如获取所有的 socket 实例。 ``` // 返回所有的 socket 实例 const sockets = await app.fetchSockets(); // 返回所有的在 room1 的 socket 实例 const sockets = await app.in("room1").fetchSockets(); // 返回特定 socketId 的实例 const sockets = await app.in(theSocketId).fetchSockets(); ``` 多框架下,主框架一般为 Web 框架,我们可以通过指定 key 获取 Socket.io 的 app。 ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Controller, App } from '@midwayjs/core'; @Controller() export class UserController { @App('socketIO') socketApp: SocketApplication; } ``` 这样我们可以通过 `@midwayjs/socketio` 的 app 对象(等价于 io),调用现有的 socket 连接。 比如,HTTP 请求调用进来对特定 namespace 下的所有客户端广播: ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Provide, Controller, App, Get } from '@midwayjs/core'; @Controller() export class UserController { @App('socketIO') socketApp: SocketApplication; @Get() async invoke() { // 对 / 下的连接做广播 this.socketApp.of('/').emit('hi', 'everyone'); } } ``` 更多的 io API,请参考 [Socket.io Server instance 文档](https://socket.io/docs/v4/server-instance/)。 ## Socket 部署[​](#socket-部署 "Socket 部署的直接链接") ### Socket 服务端口[​](#socket-服务端口 "Socket 服务端口的直接链接") `@midwayjs/socketio` 的配置样例如下: ``` // src/config/config.default export default { // ... socketIO: { port: 7001, }, } ``` 当 `@midwayjs/socketio` 和其他 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` 同时启用时,可以复用http 端口。 ``` // src/config/config.default export default { // ... koa: { port: 7001, }, socketIO: { // 这里不配置即可 }, } ``` ### Nginx 配置[​](#nginx-配置 "Nginx 配置的直接链接") 一般来说,我们的 Node.js 服务前都会有 Nginx 等类似的反向代理服务,这里以 Nginx 的配置为例。 ``` http { server { listen 80; server_name example.com; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://localhost:7001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } } ``` ## 配置[​](#配置 "配置的直接链接") ### 可用配置[​](#可用配置 "可用配置的直接链接") | 属性 | 类型 | 描述 | | -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | port | number | 可选,如果传递了该端口,socket.io 内部会创建一个该端口的 HTTP 服务,并将 socket 服务 attach 在其之上。如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | path | string | 可选,服务端 path | | adapter | object | 分布式处理的适配器,比如可以配置 redis-adapter | | connectTimeout | number | 客户端超时时间,单位 ms,默认值 *45000* | 更多的启动选项,请参考 [Socket.io 文档](https://socket.io/docs/v4/server-api/#new-Server-httpServer-options)。 ## 适配器[​](#适配器 "适配器的直接链接") 适配器是用于 Socket.io 在分布式部署时,在多台机器,多个进程能够进行通信的一层适配层,当前 socket.io 官方提供的适配器有几种: * 1、cluster-adapter 用于在单台机器,多进程之间适配 * 2、redis-adapter 用于在多台机器,多个进程之间适配 在分布式场景下,我们一般使用 redis-adapater 来实现功能。 ### 配置 redis 适配器[​](#配置-redis-适配器 "配置 redis 适配器的直接链接") `@midwayjs/socketio` 提供了一个适配器(adapter)的入口配置,只需要初始化适配器实例,传入即可。 提示 Socket.io 官方已经更新了原有的适配器包名,现在的包名为 `@socket.io/redis-adapter`(原来叫 `socket.io-redis`),配置有更新,迁移参考请查看 [官方文档](https://github.com/socketio/socket.io-redis-adapter#migrating-from-socketio-redis)。 安装如下: ``` $ npm i @socket.io/redis-adapter --save ``` 新版本配置的示例如下,更多的配置可以参考 [官方文档](https://github.com/socketio/socket.io-redis-adapter): ``` // src/config/config.default import { createAdapter } from '@socket.io/redis-adapter'; import Redis from 'ioredis'; // github 文档创建 redis 实例 const pubClient = new Redis(/* redis 配置 */); const subClient = pubClient.duplicate(); export default { // ... socketIO: { adapter: createAdapter(pubClient, subClient) }, } ``` 通过使用 `@socket.io/redis-adapter` 适配器运行 Socket.io,可以在不同的进程或服务器中运行多个 Socket.io 实例,这些实例都可以相互广播和发送事件。 此外,还有一些 Adapter 上的特殊 API,具体可以查看 [文档](https://github.com/socketio/socket.io-redis-adapter#api)。 ## 粘性会话[​](#粘性会话 "粘性会话的直接链接") 由于 Node.js 经常在启动时使用多进程(cluster)模式,如果同一个会话(sid)无法多次访问到同一个进程上,socket.io 就会报错。 解决办法有两种。 ### 使用 WebSocket 协议[​](#使用-websocket-协议 "使用 WebSocket 协议的直接链接") 最简单的方法,只启用 WebSocket 协议(禁用长轮询),这样就可以规避上述问题。 你需要在服务端和客户端同时配置。 ``` // 服务端 export default { // ... socketIO: { // ... transports: ['websocket'], }, } // 客户端 const socket = io("http://127.0.0.1:7001", { transports: ['websocket'] }); ``` ### 调整进程模型[​](#调整进程模型 "调整进程模型的直接链接") 这是相对复杂的方法,但是在 pm2 部署的场景下,既要支持粘性会话又要启用轮询支持,这是唯一的解法。 第一步,禁用配置中启动的端口,比如: ``` // src/config/config.default export default { koa: { // port: 7001, }, socketIO: { // ... }, }; ``` 如果开发需要,可以在 `config.local` 中加上端口,或者直接在 `package.json` 的 scripts 中加上端口。 ``` "scripts": { "dev": "cross-env NODE_ENV=local midway-bin dev --ts --port=7001", }, ``` 第二步,调整你的 `bootstrap.js` 文件内容,使其变为下面的代码。 ``` const { Bootstrap, ClusterManager, setupStickyMaster } = require('@midwayjs/bootstrap'); const http = require('http'); // 创建一个进程管理器,处理子进程 const clusterManager = new ClusterManager({ exec: __filename, count: 4, sticky: true, // 开启粘性会话支持 }); if (clusterManager.isPrimary()) { // 主进程启动一个 http server 做监听 const httpServer = http.createServer(); setupStickyMaster(httpServer); // 启动子进程 clusterManager.start().then(() => { // 监听端口 httpServer.listen(7001); console.log('main process is ok'); }); clusterManager.onStop(async () => { // 停止时关闭 http server await httpServer.close(); }); } else { // 子进程逻辑 Bootstrap .run() .then(() => { console.log('child is ready'); }); } ``` 在 pm2 启动时,无需指定 `-i` 参数来启动 worker,直接 `pm2 --name=xxx ./bootstrap.js` 使其只启动一个进程。 ## 常见 API[​](#常见-api "常见 API的直接链接") ### 获取连接数[​](#获取连接数 "获取连接数的直接链接") ``` const count = app.engine.clientsCount; // 获取所有的连接数 const count = app.of('/').sockets.size; // 获取单个 namespace 里的连接数 ``` ### 修改 sid 生成[​](#修改-sid-生成 "修改 sid 生成的直接链接") ``` const uuid = require("uuid"); app.engine.generateId = (req) => { return uuid.v4(); // must be unique across all Socket.IO servers } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 服务端/客户端没连上,没响应[​](#服务端客户端没连上没响应 "服务端/客户端没连上,没响应的直接链接") 1、端口服务端和客户端一致 ``` export default { koa: { port: 7001, // 这里的端口 } } // 或者 export default { socketIO: { port: 7001, // 这里的端口 } } ``` 和下面的端口要一致。 ``` // socket.io client const socket = io('************:7001', { //... }); // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ port: 7001 }); ``` 2、服务端的 path 和客户端的 path 要保持一致。path 指的是启动参数的部分。 ``` // config.default export default { socketIO: { path: '/testPath' // 这里是服务端 path } } ``` 和下面的 path 要一致 ``` // socket.io client const socket = io('************:7001', { path: '/testPath' // 这里是客户端的 path }); // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ path: '/testPath' }); ``` 3、服务端的 namespace 和客户端的 namespace 要保持一致。 ``` // server @WSController('/test') // 这里是服务端的 namespace export class HelloController { } // socket.io client const io = require("socket.io-client") io('*****:3000/test', {}); // 这里是客户端的 namespace // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ namespace: '/test', }); ``` ### 配置 CORS[​](#配置-cors "配置 CORS的直接链接") 如果出现跨域错误,需要在启动的时候配置 cors 信息。 ``` // config.default export default { socketIO: { cors: { origin: "http://localhost:8080", methods: ["GET", "POST"] } } } ``` 具体参数可以参考 [Socket.io Handling CORS](https://socket.io/docs/v4/handling-cors/)。 --- # 静态文件托管 midway 提供了基于 [koa-static-cache](https://github.com/koajs/static-cache) 模块的静态资源托管组件。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ❌ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/static-file@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/static-file": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as staticFile from '@midwayjs/static-file'; import { join } from 'path' @Configuration({ imports: [ koa, staticFile ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 使用[​](#使用 "使用的直接链接") 默认情况下,会托管项目根目录下的 `public` 目录中的内容。 比如: ``` ➜ my_midway_app tree . ├── src ├── public | ├── index.html │ └── hello.js │ ├── test ├── package.json └── tsconfig.json ``` 我们可以直接使用路径访问 `GET /public/index.html` 并获取相应的结果。 ## 配置[​](#配置 "配置的直接链接") ### 修改默认行为[​](#修改默认行为 "修改默认行为的直接链接") 资源的托管使用的是 `dirs` 字段,其中有一个 `default` 属性,我们可以修改它。 ``` // {app_root}/src/config/config.default.ts export default { // ... staticFile: { dirs: { default: { prefix: '/', dir: 'xxx', }, } }, } ``` `dirs` 中的对象值,会和 `staticFile` 下的值合并后,传入 `koa-static-cache` 中间件中。 ### 增加新的目录[​](#增加新的目录 "增加新的目录的直接链接") 可以对 dirs 做修改,增加一个新的目录。key 不重复即可,value 会和默认的配置合并。 ``` // {app_root}/src/config/config.default.ts export default { // ... staticFile: { dirs: { default: { prefix: '/', dir: 'xxx', }, another: { prefix: '/', dir: 'xxx', }, } // ... }, } ``` ### 可用配置[​](#可用配置 "可用配置的直接链接") 支持所有的 [koa-static-cache](https://github.com/koajs/static-cache) 配置,默认配置如下: | 属性名 | 默认值 | 描述 | | ------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | dirs | `{"default": {prefix: "/public", "dir": "xxxx"}}` | 托管的目录,为了支持多个目录,是个对象。
除了 default 之外,其他的 key 可以随意添加,dirs 中的对象值会和外部默认值做合并 | | dynamic | true | 动态加载文件,而不是在初始化读取后做缓存 | | preload | false | 是否在初始化缓存 | | maxAge | prod 为 31536000,其他为 0 | 缓存的最大时间 | | buffer | prod 为 true,其余为 false | 使用 buffer 字符返回 | 更多配置,请参考 [koa-static-cache](https://github.com/koajs/static-cache) 。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、函数下路由未生效[​](#1函数下路由未生效 "1、函数下路由未生效的直接链接") 函数路由需要显式配置才能生效,一般来说,会添加一个通配的路由用于静态文件,如 `/*`,或者 `/public/*`。 ``` import { Provide, ServerlessTrigger, ServerlessTriggerType, } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloHTTPService { @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/public/*', method: 'get', }) async handleStaticFile() { // 这个函数可以没有方法体,只是为了让网关注册一个额外的路由 } } ``` ### 2、默认 index.html[​](#2默认-indexhtml "2、默认 index.html的直接链接") 由于 [koa-static-cache](https://github.com/koajs/static-cache) 不支持默认 `index.html` 的配置,可以通过它的 alias 功能来解决。 可以配置把 `/` 指向到 `/index.html` 即可,不支持通配和正则。 ``` export default { // ... staticFile: { dirs: { default: { prefix: '/', alias: { '/': '/index.html', }, }, }, // ... }, } ``` ### 3、egg(@midwayjs/web)下不生效的情况[​](#3eggmidwayjsweb下不生效的情况 "3、egg(@midwayjs/web)��下不生效的情况的直接链接") 由于 egg 自带了静态托管插件,如果开启了 static 插件,会和此组件冲突。 如需使用本组件,请务必关闭 egg 插件。 ``` // src/config/plugin.ts import { EggPlugin } from 'egg'; export default { // ... static: false, } as EggPlugin; ``` ### 4、Internal Server Error, real status: 500[​](#4internal-server-error-real-status-500 "4、Internal Server Error, real status: 500的直接链接") 如果使用staticFile配置的静态目录不存在,则服务可能会抛出500错误,请确保您配置的静态目录已被正确创建。 --- # Swagger 基于最新的 [OpenAPI 3.0.3](https://swagger.io/specification/) 实现了新版的 Swagger 组件。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ❌ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm install @midwayjs/swagger@3 --save $ npm install swagger-ui-dist --save-dev ``` 如果想要在服务器上输出 Swagger API 页面,则需要将 `swagger-ui-dist` 安装到依赖中。 ``` $ npm install swagger-ui-dist --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/swagger": "^3.0.0", // 如果你希望在服务器上使用 "swagger-ui-dist": "^4.2.1", // ... }, "devDependencies": { // 如果你不希望在服务器上使用 "swagger-ui-dist": "^4.2.1", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `configuration.ts` 中增加组件。 ``` import { Configuration } from '@midwayjs/core'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [ // ... swagger ] }) export class MainConfiguration { } ``` 可以配置启用的环境,比如下面的代码指的是 **只在 local 环境下启用**。 ``` import { Configuration } from '@midwayjs/core'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [ // ... { component: swagger, enabledEnvironment: ['local'] } ] }) export class MainConfiguration { } ``` 然后启动项目,访问地址: * UI: * JSON: 路径可以通过 `swaggerPath` 参数配置。 ## 数据类型[​](#数据类型 "数据类型的直接链接") ### 自动类型提取[​](#自动类型提取 "自动类型提取的直接链接") Swagger 组件会识别各个 `@Controller` 中每个路由方法的 `@Body()`、`@Query()`、`@Param()` 装饰器,提取路由方法参数和类型。 比如下面的代码: ``` @Get('/') async home( @Query('uid') uid: number, @Query('tid') tid: string, @Query('isBoolean') isBoolean: boolean, ) { // ... } ``` 基础的布尔,字符串,数字类型展示效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01KGk0B325xe6cV5HCo_!!6000000007593-2-tps-1110-854.png) ### 类型和 Schema[​](#类型和-schema "类型和 Schema的直接链接") 我们常在参数使用对象,并使用定义好的类作为类型,这个时候 swagger 组件也能自动识别,同时也能和普通的类型进行组合识别。 比如下面的代码: ``` @Post('/:id', { summary: 'test'}) async create(@Body() createCatDto: CreateCatDto, @Param('id') id: number) { // ... } ``` `CreateCatDto` 类型的定义如下,我们使用 `ApiProperty` 将其中的每个属性都进行了定义。 ``` import { ApiProperty } from "@midwayjs/swagger"; export class CreateCatDto { @ApiProperty({ example: 'Kitty', description: 'The name of the Catname'}) name: string; @ApiProperty({ example: '1', description: 'The name of the Catage'}) age: number; @ApiProperty({ example: 'bbbb', description: 'The name of the Catbreed'}) breed: string; } ``` 效果如下,组件会自动提取其中的两个参数: ![swagger1](https://img.alicdn.com/imgextra/i2/O1CN01qpyb7k1uheVEFq8CI_!!6000000006069-2-tps-1220-1046.png) 同时,由于在类中定义了每个属性的 example,会自动填入示例值。 在 Swagger 中,每个类型都会有一个 `Schema` 来描述,我们已经定义了一个 `CreateCatDto` 的 Schema,看起来就像是下面的样子。 注意,我们会重复用到这些 Schema。 ![swagger2](https://img.alicdn.com/imgextra/i2/O1CN01iZYONb1tAqW35GM3C_!!6000000005862-2-tps-1050-694.png) ### 基础类型[​](#基础类型 "基础类型的直接链接") 通过给 `@ApiProperty(...)` 装饰器中设置 type,我们可以定义常见的类型。 大多数情况下,基础类型无需显式声明 `type` ,可自动识别。 **字符串** ``` @ApiProperty({ type: 'string', // ... }) name: string; ``` **布尔类型** ``` @ApiProperty({ type: 'boolean', example: 'true', // ... }) isPure: boolean; ``` **数字类型** ``` @ApiProperty({ type: 'number', example: '1', description: 'The name of the Catage' }) age: number; ``` 此外,也可以使用 format 字段来定义更为精确的长度。 ``` @ApiProperty({ type: 'integer', format: 'int32', example: '1', description: 'The name of the Catage' }) age: number; ``` ### 数组类型[​](#数组类型 "数组类型的直接链接") 如果是数组类型,我们可以配置 type 字段来定义,同时通过 `items` 的 `type` 来指定类型。 ``` @ApiProperty({ type: 'array', items: { type: 'string', }, example: ['1'], description: 'The name of the Catage' }) breeds: string[]; ``` ### 枚举类型[​](#枚举类型 "枚举类型的直接链接") 如果是枚举类型,可以通过配置 enmu 字段来定义。 ``` enum HelloWorld { One = 'One', Two = 'Two', Three = 'Three', } @ApiProperty({ enum: ['One', 'Two', 'Three'], description: 'The name of the Catage' }) hello: HelloWorld; ``` 如果该字段在最顶层,展示效果如下: ![swagger3](https://img.alicdn.com/imgextra/i1/O1CN015M37MU1KgtdNfqsgp_!!6000000001194-0-tps-1406-426.jpg) ### 复杂对象类型[​](#复杂对象类型 "复杂对象类型的直接链接") 如果某个属性的类型是个现有的复杂类型,我们可以使用 `type` 来指定这个复杂的类型。 ``` export class Cat { /** * The name of the Catcomment * @example Kitty */ @ApiProperty({ example: 'Kitty', description: 'The name of the Cat'}) name: string; @ApiProperty({ example: 1, description: 'The age of the Cat' }) age: number; @ApiProperty({ example: '2022-12-12 11:11:11', description: 'The age of the CatDSate' }) agedata?: Date; @ApiProperty({ example: 'Maine Coon', description: 'The breed of the Cat', }) breed: string; } export class CreateCatDto { // ... @ApiProperty({ type: Cat, // 这里无需指定 example }) related: Cat; } ``` 效果如下: ![](https://img.alicdn.com/imgextra/i3/O1CN01KADwTb1rkS4gJExuP_!!6000000005669-2-tps-1376-1070.png) ### 复杂对象数组类型[​](#复杂对象数组类型 "复杂对象数组类型的直接链接") 如果某个属性的类型是个复杂的数组类型,写法略有不同。 首先`type` 必须声明为 `array`,除了设置`type`,我们还可以使用 `getSchemaPath` 方法额外导入一个不同的类型(上面的复杂对象也可以使用它设置$ref)。 此外,如果 `Cat` 类型没有在其他属性的 `type` 字段中声明过,需要使用 `@ApiExtraModel` 装饰器额外声明引入外部类型。 ``` import { ApiProperty, getSchemaPath, ApiExtraModel } from '@midwayjs/swagger'; class Cat { // ... } @ApiExtraModel(Cat) export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { $ref: getSchemaPath(Cat), } }) relatedList: Cat[]; } ``` 效果如下: ![](https://img.alicdn.com/imgextra/i1/O1CN01h4sQJ41dP0uq4fgi7_!!6000000003727-2-tps-1332-666.png) ### 循环依赖[​](#循环依赖 "循环依赖的直接链接") 当类之间具有循环依赖关系时,请使用惰性函数提供类型信息。 比如 `type` 字段的循环。 ``` class Photo { // ... @ApiProperty({ type: () => Album }) album: Album; } class Album { // ... @ApiProperty({ type: () => Photo }) photo: Photo; } ``` `getSchemaPath` 也可以使用。 ``` export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { $ref: () => getSchemaPath(Cat) } }) relatedList: Cat[]; } ``` ## 请求定义[​](#请求定义 "请求定义的直接链接") [OpenAPI](https://swagger.io/specification/) 定义的 paths 就是各个路由路径,且每个路由路径都有 HTTP 方法的定义,比如 GET、POST、DELETE、PUT 等。 ### Query 定义[​](#query-定义 "Query 定义的直接链接") 使用 `@ApiQuery` 来定义 Query 数据。 基础使用,会自动识别 `@Query` 装饰器。 ``` @Get('/get_user') async getUser(@Query('name') name: string) { return 'hello'; } ``` 如果 `@Query` 以对象形式,需要在 `@ApiQuery` 指定一个 name 参数,对象类型需要配合 `@ApiProperty` 使用,否则表单会变为只读形式。 ``` export class UserDTO { @ApiProperty() name: string; } @Get('/get_user') @ApiQuery({ name: 'query' }) async getUser(@Query() dto: UserDTO) { // ... } ``` ### Body 定义[​](#body-定义 "Body 定义的直接链接") 使用 `@ApiBody` 来定义 Body 数据。 `@Body` 对象类型需要配合 `@ApiProperty` 使用。 ``` export class UserDTO { @ApiProperty() name: string; } @Post('/update_user') async upateUser(@Body() dto: UserDTO) { // ... } ``` 如需其他细节,请使用 `@ApiBody` 增强。 注意,Swagger 规定,`Body` 定义只能存在一个,如果配置了 `@ApiBody` ,则类型提取的数据会自动被覆盖。 比如下面示例中,`Body` 的类型会被替换为 `Cat`。 ``` @ApiBody({ type: Cat }) async upateUser(@Body() dto: UserDTO) { // ... } ``` ### 文件上传定义[​](#文件上传定义 "文件上传定义的直接链接") 文件上传是 Post 请求中较为特殊的一类场景。 可以通过在 DTO 中定义属性来实现多个文件以及 `Fields` 的类型。 ``` import { ApiProperty, BodyContentType } from "@midwayjs/swagger"; export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { type: 'string', format: 'binary', } }) files: any; } // ... @Post('/test1') @ApiBody({ contentType: BodyContentType.Multipart, schema: { type: CreateCatDto, } }) async upload1(@Files() files, @Fields() fields) { // ... } ``` Swagger UI 中展示: ![swagger6](https://img.alicdn.com/imgextra/i3/O1CN01w9dZxe1YQJv3uOycZ_!!6000000003053-0-tps-1524-1118.jpg) 如果不需要多个文件,使用 schema 定义即可。 ``` export class CreateCatDto { // ... @ApiProperty({ type: 'string', format: 'binary', }) file: any; } ``` Swagger UI 中展示: ![swagger4](https://img.alicdn.com/imgextra/i3/O1CN01KlDHNt24mMglN1fyH_!!6000000007433-0-tps-1598-434.jpg) ### 请求 Header[​](#请求-header "请求 Header的直接链接") 通过 `@ApiHeader({...})` 装饰器来定义 Header 参数。 ``` @ApiHeader({ name: 'x-test-one', description: 'this is test one' }) @ApiTags(['hello']) @Controller('/hello') export class HelloController {} ``` ![](https://img.alicdn.com/imgextra/i1/O1CN01n8Xgn729GphI6XzXk_!!6000000008041-2-tps-1234-584.png) ### 请求 Response[​](#请求-response "请求 Response的直接链接") 可以使用 `@ApiResponse({...})` 来自定义请求 Response。 ``` @Get('/:id') @ApiResponse({ status: 200, description: 'The found record', type: Cat, }) findOne(@Param('id') id: string, @Query('test') test: any): Cat { return this.catsService.findOne(+id); } ``` 还提供了其他不需要设置 status 的装饰器: * `@ApiOkResponse()` * `@ApiCreatedResponse()` * `@ApiAcceptedResponse()` * `@ApiNoContentResponse()` * `@ApiMovedPermanentlyResponse()` * `@ApiBadRequestResponse()` * `@ApiUnauthorizedResponse()` * `@ApiNotFoundResponse()` * `@ApiForbiddenResponse()` * `@ApiMethodNotAllowedResponse()` * `@ApiNotAcceptableResponse()` * `@ApiRequestTimeoutResponse()` * `@ApiConflictResponse()` * `@ApiTooManyRequestsResponse()` * `@ApiGoneResponse()` * `@ApiPayloadTooLargeResponse()` * `@ApiUnsupportedMediaTypeResponse()` * `@ApiUnprocessableEntityResponse()` * `@ApiInternalServerErrorResponse()` * `@ApiNotImplementedResponse()` * `@ApiBadGatewayResponse()` * `@ApiServiceUnavailableResponse()` * `@ApiGatewayTimeoutResponse()` * `@ApiDefaultResponse()` HTTP 请求返回的数据模型定义也可以通过指定 type,当然这个数据模型需要通过装饰器 `@ApiProperty` 来描述各个字段。 ``` import { ApiProperty } from '@midwayjs/swagger'; export class Cat { @ApiProperty({ example: 'Kitty', description: 'The name of the Cat'}) name: string; @ApiProperty({ example: 1, description: 'The age of the Cat' }) age: number; @ApiProperty({ example: 'Maine Coon', description: 'The breed of the Cat', }) breed: string; } ``` Swagger 还支持带前缀 `x-` 的扩展字段,可以使用 `@ApiExtension(x-..., {...})` 装饰器。 ``` @ApiExtension('x-hello', { hello: 'world' }) ``` 当不希望通过 type 来定义 model 类型时,我们可以通过在 Controller 中或者 Model Class 中加入 `@ApiExtraModel` 来增加额外的 `schema` 类型描述。 ``` @ApiExtraModel(TestExtraModel) @Controller() class HelloController { @Post('/:id', { summary: 'test'}) @ApiResponse({ status: 200, content: { 'application/json': { schema: { properties: { data: { '$ref': getSchemaPath(TestExtraModel)} } } } } }) async create(@Body() createCatDto: CreateCatDto, @Param('id') id: number): Promise { return this.catsService.create(createCatDto); } } // or @ApiExtraModel(TestExtraModel) class TestModel { @ApiProperty({ item: { $ref: getSchemaPath(TestExtraModel) }, description: 'The name of the Catage' }) one: TestExtraModel; } ``` ### 泛型返回数据[​](#泛型返回数据 "泛型返回数据的直接链接") Swagger 本身不支持泛型数据,泛型作为 Typescript 的一种类型,会在构建期抹掉,在运行时无法读取。 我们可以用一些取巧的方式来定义。 比如,我们需要将返回值增加一些通用的包裹结构。 ``` { code: 200, message: 'xxx', data: any } ``` 为此,我们可以编写一个方法,入参是返回的 data,返回一个包裹的类。 ``` import { Type } from '@midwayjs/swagger'; type Res = { code: number; message: string; data: T; } export function SuccessWrapper(ResourceCls: Type): Type> { class Successed { @ApiProperty({ description: '状态码' }) code: number; @ApiProperty({ description: '消息' }) message: string; @ApiProperty({ type: ResourceCls, }) data: T; } return Successed; } ``` 我们可以基于这个方法,来实现我们自己的返回类。 ``` class ViewCat extends SuccessWrapper(Cat) {} ``` 在使用的时候,可以直接指定这个类即可。 ``` @Get('/:id') @ApiResponse({ status: 200, description: 'The found record', type: ViewCat, }) async findOne(@Param('id') id: string, @Query('test') test: any): ViewCat { // ... } ``` ### 更多的定义示例[​](#更多的定义示例 "更多的定义示例的直接链接") Swagger 中还有更多的写法,框架都进行了支持,更多用法可以查看我们的 [测试用例](https://github.com/midwayjs/midway/blob/main/packages/swagger/test/parser.test.ts)。 ## 授权验证[​](#授权验证 "授权验证的直接链接") 组件可以通过添加授权验证配置来设置验证方式,我们支持配置 `basic`、`bearer`、`cookie`、`oauth2`、`apikey`、`custom`。 可以使用 `auth` 字段定义验证类型。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'basic', }, }, } ``` 支持数组,配置多个验证类型。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: [ { name: 'basicAuth1', authType: 'basic', }, { name: 'basicAuth2', authType: 'basic', } ], }, } ``` ### basic[​](#basic "basic的直接链接") 启用 basic 验证 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BasicAuth', authType: 'basic', description: 'Basic Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 basic | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiBasicAuth() // 默认使用 'basic' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiBasicAuth()` 装饰器有默认值 `'basic'`。如果配置文件中的 `name` 字段不是 `'basic'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'BasicAuth' 时 @ApiBasicAuth('BasicAuth') @Controller('/hello') export class HelloController {} ``` ### bearer[​](#bearer "bearer的直接链接") 启用 bearer 验证(bearerFormat 为 JWT) ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BearerAuth', authType: 'bearer', description: 'Bearer Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 bearer | | bearerFormat | 可选,bearer 类型默认为 JWT | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiBearerAuth() // 默认使用 'bearer' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiBearerAuth()` 装饰器有默认值 `'bearer'`。如果配置文件中的 `name` 字段不是 `'bearer'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'BearerAuth' 时 @ApiBearerAuth('BearerAuth') @Controller('/hello') export class HelloController {} ``` ### oauth2[​](#oauth2 "oauth2的直接链接") OAuth2 是 OpenAPI 里最复杂但最强大的认证类型,所有授权交互流程都能被描述清楚,swagger-ui 全自动支持。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'testOAuth2' authType: 'oauth2', flows: { implicit: { authorizationUrl: 'http://example.org/api/oauth/dialog', scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' } }, authorizationCode: { authorizationUrl: 'https://example.com/api/oauth/dialog', tokenUrl: 'https://example.com/api/oauth/token', scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' } }, }, }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 必选,你的 API Key 的字段名 | | authType | 固定为 oauth2 | | flows | 必选,四种授权模式 | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | flows 是其中最复杂的字段配置,包括不同的参数,目前主要使用 **authorizationCode** 和 **clientCredentials**。 | **Flow 类型** | **简介** | **适用场景** | **当前状态** | | --------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------ | | **authorizationCode** | 标准授权码模式。用户通过授权服务器跳转登录,拿到授权码后再换取 access token。支持前端+后端安全配合。 | Web 应用、移动端应用(如 Google 登录、GitHub OAuth)。现代主流通用模式。 | ✅ 推荐使用(最安全、最通用) | | **clientCredentials** | 客户端凭证模式。没有用户参与,直接用 client\_id 和 client\_secret 拿 token,机器与机器之间认证。 | 微服务、后台服务、系统集成、API 网关 | ✅ 推荐使用(服务器到服务器通信首选) | | **password** | 密码模式。直接用用户名和密码换取 token,跳过授权服务器跳转。 | 内部系统、测试、历史遗留系统。风险高,暴露用户密码。 | ❌ 已废弃(RFC 6749 明确不推荐新系统使用) | | **implicit** | 隐式模式。前端单页应用直接在浏览器获取 token,不经后端,早期为避免前端暴露 client\_secret 设计。 | 早期 SPA、浏览器端应用。现已被 authorizationCode + PKCE 替代。 | ❌ 已废弃(OAuth 2.1 标准已移除) | 上述四种 Flow 类型可用的参数如下: | **参数** | **描述** | authorizationCode | clientCredentials | password | implicit | | ---------------- | ------------------------ | ----------------- | ----------------- | -------- | -------- | | authorizationUrl | 用户授权页面跳转地址 | ✅ 必须 | ❌ 无 | ❌ 无 | ✅ 必须 | | tokenUrl | 获取 access token 的地址 | ✅ 必须 | ✅ 必须 | ✅ 必须 | ❌ 无 | | refreshUrl | 刷新 access token 的地址 | ⚪ 可选 | ⚪ 可选 | ⚪ 可选 | ⚪ 可选 | | scopes | 授权范围,权限粒度控制 | ✅ 必须 | ✅ 必须 | ✅ 必须 | ✅ 必须 | 在控制器层面生效。 ``` @ApiOAuth2(['read:pets']) // 必须指定权限范围,默认使用 'oauth2' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiOAuth2()` 装饰器有默认值 `'oauth2'`。如果配置文件中的 `name` 字段不是 `'oauth2'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'testOAuth2' 时 @ApiOAuth2(['read:pets'], 'testOAuth2') @Controller('/hello') export class HelloController {} ``` ### cookie[​](#cookie "cookie的直接链接") 启用 cookie 验证,底层会转换为 apikey。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'cookie', securityName: 'testforcookie', cookieName: 'connect.sid', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | securityName | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 cookie | | cookieName | cookie 中的 key | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiCookieAuth() // 默认使用 'cookie' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiCookieAuth()` 装饰器有默认值 `'cookie'`。如果配置文件中的 `name` 字段不是 `'cookie'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'testforcookie' 时 @ApiCookieAuth('testforcookie') @Controller('/hello') export class HelloController {} ``` ### apikey[​](#apikey "apikey的直接链接") apiKey 是 OpenAPI 里最灵活的认证模式。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'x-api-key', authType: 'apikey', in: 'header', description: 'ApiKey Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------------------------------------------- | | name | 必选,你的 API Key 的字段名(header 里的名字 / query 参数名 / cookie 名) | | authType | 固定为 apikey,注意是小写 | | in | API Key 放在请求的哪个位置,可选值:header / query / cookie | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiSecurity('api_key') // 必须指定名称,无默认值 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiSecurity()` 装饰器必须指定名称参数,与配置文件中的 `name` 字段保持一致。 ### custom 验证[​](#custom-验证 "custom 验证的直接链接") 自定义验证方式,需要自己设计参数配置 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'custom', name: 'mycustom' // ... }, }, } ``` 在控制器层面生效。 ``` @ApiSecurity('mycustom') @Controller('/hello') export class HelloController {} ``` ### 全局开启验证[​](#全局开启验证 "全局开启验证的直接链接") 一般情况下仅对特定的路由开启验证,如需全局开启,可以在某个验证方式上添加 `addSecurityRequirements` 属性。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BasicAuth', authType: 'basic', description: 'Basic Auth', addSecurityRequirements: true, }, }, } ``` ### 忽略验证[​](#忽略验证 "忽略验证的直接链接") 可以使用 `@ApiExcludeSecurity` 来忽略设置,支持类和方法。 ``` @Controller('/api') @ApiSecurity('api_key') class APIController { @Post('/update_user') async updateUser() { // ... } @Get('/get_user') @ApiExcludeSecurity() async getUser() { // ... } } ``` ## 更多配置[​](#��更多配置 "更多配置的直接链接") ### 路由标签[​](#路由标签 "路由标签的直接链接") Swagger 可以对每个路由添加标签,进行分组。 标签添加有两种形式。 * 添加到控制器 * @ApiTags 和 @ApiOperation 默认情况下,框架会根据 Controller 的路径来生成标签,比如下面的代码,会生成一个 `hello` 的标签,这个标签会应用到这个控制器所有的路由上。 ``` @Controller('/hello') export class HelloController {} ``` 如果需要自定义标签,可以通过 `@ApiTags([...])` 来自定义 Controller 标签。 ``` @ApiTags(['hello']) @Controller('/hello') export class HelloController {} ``` 从 `v3.17.3` 开始,可以通过配置 `isGenerateTagForController` 来控制是否自动生成 Controller 标签。 ``` // src/config/config.default.ts export default { swagger: { isGenerateTagForController: false } } ``` 可以将 `@ApiTags` 标签直接加在路由方法上。 ``` // ... export class HomeController { @ApiTags(['bbb']) @Get('/') async home(): Promise { // ... } } ``` 也可以通过 `@ApiOperation` 来添加标签。 ``` // ... export class HomeController { @ApiOperation({ tags: ['bbb'] }) @Get('/') async home(): Promise { // ... } } ``` `@ApiTags` 的优先级比 `@ApiOperation` 更高,如果两者同时存在,`@ApiTags` 会覆盖 `@ApiOperation`。 同理,路由上的 `@ApiTags` 也会覆盖控制器上的 `@ApiTags`。 可以通过配置给 Tag 添加描述。 ``` // src/config/config.default.ts export default { swagger: { tags: [ { name: 'api', description: 'API Document' }, { name: 'hello', description: 'Other Router' }, ] } } ``` ### 忽略路由[​](#忽略路由 "忽略路由的直接链接") 配置 `@ApiExcludeController` 可以忽略整个 Controller 的路由。 ``` @ApiExcludeController() @Controller('/hello') export class HelloController {} ``` 配置 `@ApiExcludeEndpoint` 可以忽略单个路由。 ``` @Controller('/hello') export class HelloController { @ApiExcludeEndpoint() @Get() async getUser() { // ... } } ``` 如果需要满足更加动态的场景,可以通过配置路由过滤器来批量过滤。 ``` // src/config/config.default.ts import { RouterOption } from '@midwayjs/core'; export default { // ... swagger: { routerFilter: (url: string, options: RouterOption) => { return url === '/hello/getUser'; } }, } ``` `routerFilter` 用来传入一个过滤函数,包含 `url` 和 `routerOptions` 两个参数。`routerOptions` 中包含了路由基础信息。 每当匹配到一个路由时,会自动执行 `routerFilter` 方法,当 `routerFilter` 返回 true 时,代表这个路由将会被过滤。 ### 完整参数配置[​](#完整参数配置 "完整参数配置的直接链接") Swagger 组件提供了和 [OpenAPI](https://swagger.io/specification/) 一致的参数配置能力,可以通过自定义配置来实现。 配置项如下: ``` /** * see https://swagger.io/specification/ */ export interface SwaggerOptions { /** * 默认值: My Project * https://swagger.io/specification/#info-object title 字段 */ title?: string; /** * 默认值: This is a swagger-ui for midwayjs project * https://swagger.io/specification/#info-object description 字段 */ description?: string; /** * 默认值: 1.0.0 * https://swagger.io/specification/#info-object version 字段 */ version?: string; /** * https://swagger.io/specification/#info-object contact 字段 */ contact?: ContactObject; /** * https://swagger.io/specification/#info-object license 字段 */ license?: LicenseObject; /** * https://swagger.io/specification/#info-object termsOfService 字段 */ termsOfService?: string; /** * https://swagger.io/specification/#openapi-object externalDocs 字段 */ externalDocs?: ExternalDocumentationObject; /** * https://swagger.io/specification/#openapi-object servers 字段 */ servers?: Array; /** * https://swagger.io/specification/#openapi-object tags 字段 */ tags?: Array; /** * 可以参考 https://swagger.io/specification/#security-scheme-object */ auth?: AuthOptions | AuthOptions[]; /** * 默认值: /swagger-ui * 访问 swagger ui 的路径 */ swaggerPath?: string; /** * 对路由 tag 进行 ascii 排序 * 可以使用 1-xxx、2-xxx、3-xxx 来定义 tag */ tagSortable?: boolean; /** * UI 展示中需要用到的配置 * 可以参考 https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#display */ displayOptions?: { deepLinking?: boolean; displayOperationId?: boolean; defaultModelsExpandDepth?: number; defaultModelExpandDepth?: number; defaultModelRendering?: 'example' | 'model'; displayRequestDuration?: boolean; docExpansion?: 'list' | 'full' | 'none'; filter?: boolean | string; maxDisplayedTags?: number; showExtensions?: boolean; showCommonExtensions?: boolean; useUnsafeMarkdown?: boolean; tryItOutEnabled?: boolean; }; documentOptions?: { /** * 自定义 operationIdFactory,用于生成 operationId * @default () => controllerKey_webRouter.methodKey */ operationIdFactory?: ( controllerKey: string, webRouter: RouterOption ) => string; }; } /** * 继承自 https://swagger.io/specification/#security-scheme-object */ export interface AuthOptions extends Omit { /** * 验权类型 * basic => http basic 验证 * bearer => http jwt 验证 * cookie => cookie 方式验证 * oauth2 => 使用 oauth2 * apikey => apiKey * custom => 自定义方式 */ authType: AuthType; /** * https://swagger.io/specification/#security-scheme-object type 字段 */ type?: SecuritySchemeType; /** * authType = cookie 时可以修改,通过 ApiCookie 装饰器关联的名称 */ securityName?: string; /** * authType = cookie 时可以修改,cookie 的名称 */ cookieName?: string; } ``` ## 装饰器列表[​](#装饰器列表 "装饰器列表的直接链接") 组件所有装饰器参考了 [@nestjs/swagger](https://github.com/nestjs/swagger) 的设计,都带 `Api` 前缀。这里列出全部装饰器: | 装饰器 | 支持模式 | | ----------------------- | ----------------- | | `@ApiBody` | Method | | `@ApiExcludeEndpoint` | Method | | `@ApiExcludeController` | Controller | | `@ApiHeader` | Controller/Method | | `@ApiHeaders` | Controller/Method | | `@ApiOperation` | Method | | `@ApiProperty` | Model Property | | `@ApiPropertyOptional` | Model Property | | `@ApiResponseProperty` | Model Property | | `@ApiQuery` | Method | | `@ApiResponse` | Method | | `@ApiTags` | Controller/Method | | `@ApiExtension` | Method | | `@ApiBasicAuth` | Controller/Method | | `@ApiBearerAuth` | Controller/Method | | `@ApiCookieAuth` | Controller/Method | | `@ApiOAuth2` | Controller/Method | | `@ApiSecurity` | Controller/Method | | `@ApiExcludeSecurity` | Controller/Method | | `@ApiParam` | Method | | `@ApiExtraModel` | Controller | ## UI 渲染[​](#ui-渲染 "UI 渲染的直接链接") ### 从 Swagger-ui-dist 渲染[​](#从-swagger-ui-dist-渲染 "从 Swagger-ui-dist 渲染的直接链接") 默认情况下,如果安装了 `swagger-ui-dist` 包,组件会默认会调用 `renderSwaggerUIDist` 渲染 swagger ui,如果需要传递 swagger-ui 的 options,可以 通过 `swaggerUIRenderOptions` 选项。 ``` // src/config/config.default.ts import { renderSwaggerUIDist } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderSwaggerUIDist, swaggerUIRenderOptions: { // ... } }, } ``` 如果希望调整 UI 的配置,可以使用自定义文件的方式替换默认的 `swagger-initializer.js`。 ``` // src/config/config.default.ts import { AppInfo } from '@midwayjs/core'; import { renderSwaggerUIDist } from '@midwayjs/swagger'; import { join } from 'path'; export default (appInfo: AppInfo) { return { // ... swagger: { swaggerUIRender: renderSwaggerUIDist, swaggerUIRenderOptions: { customInitializer: join(appInfo.appDir, 'resource/swagger-initializer.js'), } }, } } ``` 自定义的 `swagger-initializer.js` 内容大致如下: ``` window.onload = function() { window.ui = SwaggerUIBundle({ url: "/index.json", dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout", persistAuthorization: true, }); }; ``` 其中的 url 指向当前的 swagger json,可以自行修改,完整的 `swagger-ui` 配置请参考 [这里](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md)。 ### 从 unpkg 等 CDN 地址渲染[​](#从-unpkg-等-cdn-地址渲染 "从 unpkg 等 CDN 地址渲染的直接链接") 如果未安装 `swagger-ui-dist` 包,会自动使用 `renderSwaggerUIRemote` 方法进行渲染,默认由 `unpkg.com` 提供 cdn 资源。 ``` // src/config/config.default.ts import { renderSwaggerUIRemote } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderSwaggerUIRemote, swaggerUIRenderOptions: { // ... } }, } ``` ### 仅提供 Swagger JSON[​](#仅提供-swagger-json "仅提供 Swagger JSON的直接链接") 如果仅希望提供 Swagger JSON,可以配置 `renderJSON` 仅渲染 JSON ,无需引入 `swagger-ui-dist` 包。 ``` // src/config/config.default.ts import { renderJSON } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderJSON, }, } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### `@Get` 等路由注解中的 `summary` 或者 `description` 不生效[​](#get-等路由注解中的-summary-或者-description-不生效 "get-等路由注解中的-summary-或者-description-不生效的直接链接") 当存在 `@ApiOperation` 时候,将优先使用 `@ApiOperation` 中的 `summary` 或者 `description`,所以在 `@ApiOperation` 与 `@Get` 等路由注解中,只需要写一个即可。 --- # TableStore 本文介绍了如何使用 midway 接入阿里云 TableStore。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/tablestore@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/tablestore": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as tablestore from '@midwayjs/tablestore'; import { join } from 'path' @Configuration({ imports: [ tablestore // 导入 tablestore 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` // src/config/config.default export default { // ... tableStore: { client: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default export default { // ... tableStore: { clients: { db1: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, db2: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, }, }, } ``` 更多参数可以查看 [aliyun tablestore sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk) 文档。 ## 使用 TableStore 服务[​](#使用-tablestore-服务 "使用 TableStore 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { TableStoreService } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async invoke() { await this.tableStoreService.putRow(params); } } ``` 可以使用 `TableStoreServiceFactory` 获取不同的实例。 ``` import { TableStoreServiceFactory } from '@midwayjs/tablestore'; import { join } from 'path'; @Provide() export class UserService { @Inject() tableStoreServiceFactory: TableStoreServiceFactory; async save() { const db1 = await this.tableStoreServiceFactory.get('db1'); const db2 = await this.tableStoreServiceFactory.get('db2'); //... } } ``` 示例:getRow ``` import { join } from 'path'; import { TableStoreService, Long, CompositeCondition, SingleColumnCondition, LogicalOperator, ComparatorType } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async getInfo() { const data = await tableStoreService.getRow({ tableName: "sampleTable", primaryKey: [{ 'gid': Long.fromNumber(20013) }, { 'uid': Long.fromNumber(20013) }], columnFilter: condition }); // TODO } } ``` 如示例所示,原有的 tablestore 包中导出的类型,应该都已经被 @midwayjs/tablestore 代理和接管,更多具体方法参数可以查看 [示例](https://github.com/midwayjs/midway/tree/2.x/packages/tablestore/test/sample)。 --- # 标签组件 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用标签组件。 ### 使用场景[​](#使用场景 "使用场景的直接链接") 标签是一种抽象化的服务端常用系统化能力,可用于多种用途,如: * 组织管理资源 * 实现分类系统(面向内容、人群等) * 资源管理系统 * 图片添加各种颜色标签、物体和场景标签,通过标签筛选图片 * 视频等素材标签 * 访问控制 * 权限系统(管理员、编辑、游客) * 状态系统(编辑中、已发布等) 基于标签系统提供的增删改查,以及通过标签,对绑定了标签的 `实体` 进行增删改查,能够很方便的实现更多高级的业务逻辑。 标签系统就是为了这种业务场景,让服务端基于标签能力,实现更高效、便捷的业务开发。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ### 如何使用?[​](#如何使用 "如何使用?的直接链接") 1. 安装依赖 ``` $ npm i @midwayjs/tags --save ``` 2. 在 configuration 中引入组件 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as tags from '@midwayjs/tags'; @Configuration({ imports: [ // ... tags ], }) export class MainConfiguration {} ``` 3. 添加配置 ``` // src/config/config.local.ts export default { tags: { clients: { 'tagGroup1': { // 使用 本机内存 作为数据存储 dialectType: 'memory', }, }, } } ``` 4. 在代码中调用 ``` // src/testTags.ts import { Provide, Inject, InjectClient } from '@midwayjs/core'; import { TagServiceFactory, TagClient } from '@midwayjs/tags'; @Provide() export class TestTagsService { @Inject() tags: TagServiceFactory; // 相当于 this.tags.get('tagGroup1') @InjectClient(TagServiceFactory, 'tagGroup1') tagClient: TagClient; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/tags/list', method: 'get'}) async listTags() { // 也可以直接使用 this.tagClient const tagClient: TagClient = this.tags.get('tagGroup1'); // add new tag const tagInfo = await tagClient.new({ name: 'test-tag-name', desc: 'tag desc', }); /* tagInfo = { success: true, id: 1, } */ // list top 20 tags const tags = await tagClient.list({ count: true }); /* tags: { list: [ { id: 1, name: 'test-tag-name', desc: 'tag desc' } ], total: 1 } */ return tags; } } ``` ### 方法[​](#方法 "方法的直接链接") #### 新增标签 new[​](#新增标签-new "新增标签 new的直接链接") ``` new(tagDefine: { // 标签名,在同一个 group 里面不能重复 name: string; // 标签描述 desc?: string; }): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 删除标签 remove[​](#删除标签-remove "删除标签 remove的直接链接") 删除标签也会删除和这个标签绑定的实体关系 ``` remove(tagIdOrName: number | string): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 更新标签 update[​](#更新标签-update "更新标签 update的直接链接") 更细一个标签的基础信息 ``` update(tagIdOrName: number | string, params: Partial< { name: string; desc?: string; }>): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 列举标签 list[​](#列举标签-list "列举标签 list的直接链接") 搜索标签,支持分页 ``` list(listOptions?: { // 搜索的标签,支持传入标签 id 和标签名 tags?: Array; // 检索的时候标签是采用交集还是并集,取值为 and 和 or type?: MATCH_TYPE; count?: boolean; pageSize?: number; page?: number; }): Promise<{ // 标签列表 list: { id: number; name: string; desc: string; createAt: number; updateAt: number; }[]; // 标签总数 total?: number; }>; ``` #### 绑定实体 bind[​](#绑定实体-bind "绑定实体 bind的直接链接") 绑定实体的意思就是将其他的任何东西绑定到一个标签上,这里的实体可以是一张图片、也可以是一个文件,实体的id由用户自己控制 ``` bind(bindOptions: { // 标签列表 tags: Array; // 不存在标签的话自动创建标签,并绑定,默认为false autoCreateTag?: boolean; // 实体id objectId: number, }): Promise<{ success: boolean; message: string; }> ``` #### 解绑实体 unbind[​](#解绑实体-unbind "解绑实体 unbind的直接链接") ``` unbind(unbindOptions: { // 解绑的多个标签,标签id或者是标签 name tags: Array, // 实体id objectId: number, }): Promise<{ success: boolean; message: string; }> ``` #### 根据标签列举实体 listObjects[​](#根据标签列举实体-listobjects "根据标签列举实体 listObjects的直接链接") ``` listObjects(listOptions?: { // 标签id或者是标签 name tags?: Array; count?: boolean; // 检索的时候标签是采用交集还是并集,取值为 and 和 or type?: MATCH_TYPE; pageSize?: number; page?: number; }): Promise<{ // 实体的 id 列表 list: number[]; // 实体总数 total?: number; }>; ``` #### 根据实体获取标签 listObjectTags[​](#根据实体获取标签-listobjecttags "根据实体获取标签 listObjectTags的直接链接") ``` listObjectTags(listOptions?: { // 实体id objectId: number; count?: boolean; pageSize?: number; page?: number; }): Promise<{ list: { // 标签列表 name: string; desc?: string; id: number; createAt: number; updateAt: number; }[]; // 标签总数 total?: number; }>; ``` ### 配置[​](#配置 "配置的直接链接") Tags 支持内存存储(默认)和 mysql 数据库存储两种方式,下面是一个配置的示例: ``` // src/config/config.local.ts export default { tags: { clients: { 'tagGroup1': { // 使用 本机内存 作为数据存储 dialectType: 'memory', }, 'tagGroup2': { // 使用 mysql 作为数据存储 dialectType: 'mysql', // 自动同步表结构 sync: true, // mysql 连接实例 instance: mysqlConnection.promise(), }, }, } } ``` #### 内存存储配置[​](#内存存储配置 "内存存储配置的直接链接") | 配置 | 值类型 | 默认值 | 配置描述 | | ----------- | --------------- | ------ | ------------------------------- | | dialectType | string `memory` | - | 配置为 `memory`,则启用内存存储 | #### Mysql 存储配置[​](#mysql-存储配置 "Mysql 存储配置的直接链接") 如果要使用 Mysql 数据库作为数据存储,那么需要将 Mysql 的 `数据库连接对象` 传入 tags 的配置中。 | 配置 | 值类型 | 默认值 | 配置描述 | | -------------- | ----------------------------------------------------------- | ------- | ---------------------------------------------------------------------- | | dialectType | string `mysql` | - | 配置为 `mysql`,则启用 Mysql 存储 | | sync | boolean | `false` | 自动同步 Tags 的表结构,Tags组件会创建两张数据表,详见下方的数据表信息 | | instance | `{ query: (sql: string, placeholder?: any[])}: Promise<[]>` | - | Mysql 连接的示例,需要提供一个 query 方法,可以查看下面的示例 | | tablePrefix | string | - | 数据表前缀 | | tableSeparator | string | `_` | 数据表的拼接分隔符 | 下面是使用 `mysql2` 这个 npm 包进行数据库连接的示例: ``` // src/config/config.local.ts const mysql = require('mysql2'); export default () => { const connection = mysql.createConnection({ host: 'db4free.net', user: 'tag***', password: 'tag***', database: 'tag***', charset: 'utf8', }); return { tags: { clients: { 'tagGroup': { dialectType: 'mysql', sync: true, instance: { // 包含 query 的mysql连接实例 query: (...args) => { return connection.promise().query(...args); } }, }, }, } } } ``` 你也可以考虑在 `configuration.ts` 中的 `onConfigLoad` 生命周期中进行数据库连接,这样的好处是在关闭时,可以关闭数据库连接: ``` // src/configuration.ts import { Config, Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as tags from '@midwayjs/tags'; import { ITagMysqlDialectOption } from '@midwayjs/tags'; const mysql = require('mysql2'); @Configuration({ imports: [ tags ], }) export class MainConfiguration { connection; @Config() tags; async onConfigLoad(container) { // 创建 mysql 连接 this.connection = mysql.createConnection({ host: 'db4free.net', user: 'tag***', password: 'tag***', database: 'tag***', charset: 'utf8', }); let dialect: ITagMysqlDialectOption = { dialectType: 'mysql', sync: true, instance: { query: (...args) => { return this.connection.promise().query(...args); } } }; return { tags: dialect } } async onStop() { // 关闭 mysql 连接 this.connection.close(); } } ``` ##### 数据表信息[​](#数据表信息 "数据表信息的直接链接") Tags 组件需要两种数据表来存储数据,分别是 `tag` 和 `relationship`,这两张表在数据库中真实的表名,是通过配置中的 `表名前缀`、`表名分隔符` 和 `客户端名/分组名` 进行拼接的,例如: ``` const clientName = 'local-test'; const { tablePrefix = 'a', tableSeparator = '_' } = tagOptions; const tagTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}tag`; // tagTableName: a_local-test_tag const relationshipTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}relationship` // relationshipTableName: a_local-test-relationship ``` 当你在配置中启用 `sync` 的自动表结构同步时,如果没有这两张表,就会根据下述的表结构创建对应的数据表: `tag` 表结构: ``` CREATE TABLE `tag` ( `id` BIGINT unsigned NOT NULL AUTO_INCREMENT, `group` varchar(32) NULL, `name` varchar(32) NULL, `descri` varchar(128) NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, `update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) ``` `relationship` 表结构: ``` CREATE TABLE `relationship` ( `id` BIGINT unsigned NOT NULL AUTO_INCREMENT, `tid` BIGINT unsigned NOT NULL, `oid` BIGINT unsigned NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, `update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) ``` --- # 租户 这里介绍如何快速在 Midway 中使用租户组件。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 租户定义[​](#租户定义 "租户定义的直接链接") 租户管理是中后台业务开发过程中经常需要的功能。 在开发中,不同的用户需要保存在不同的数据源、命名空间或是区域中,这些不同的数据区域我们统称为 “租户”。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/tenant` 是主要的功能包。 ``` $ npm i @midwayjs/tenant@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/tenant": "^3.0.0", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `src/configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as tenant from '@midwayjs/tenant'; @Configuration({ imports: [ // ... tenant, ], }) export class MainConfiguration { } ``` ## 租户信息存取[​](#租户信息存取 "租户信息存取的直接链接") 不同的租户数据相互隔离,一般来说,每个用户数据都会关联相关的租户信息,在用户认证拿到用户信息之后,获取其对应的租户数据,以便后续数据读写使用。 在 Midway 中,可以将租户数据保存在请求对象 ctx 中,后续的所有请求作用域对象可以使用。但是租户信息仅仅在请求链路中使用是不够的,需要在不同的作用域都生效,这就需要新的架构来支持。 组件提供了一个 `TenantManager` 来管理租户信息。 你需要在每个请求链路中保存租户信息,之后才能获取。 租户信息的格式可以按需求定义。 比如: ``` interface TenantInfo { id: string; name: string; } ``` 比如,在中间件中保存。 ``` import { TenantManager } from '@midwayjs/tenant'; import { Middleware, Inject } from '@midwayjs/core'; @Middleware() class TenantMiddleware { @Inject() tenantManager: TenantManager; resolve() { return async(ctx, next) => { // 请求链路中设置租户信息 await this.tenantManager.setCurrentTenant({ id: '123', name: '我的租户' }); } } } ``` 在后续的单例服务中获取。 ``` import { TenantManager } from '@midwayjs/tenant'; import { Inject, Singleton } from '@midwayjs/core'; import { TenantInfo } from '../interface'; @Singleton() class TenantService { @Inject() tenantManager: TenantManager; async getTenantInfo() { const tenantInfo = await this.tenantManager.getCurrentTenant(); if (tenantInfo) { console.log(tenantInfo.name); // output => 我的租户 } } } ``` 提示 * 1、租户信息一定会关联请求,如有需求,你可以在不同的 Framework 中都加入中间件 * 2、每个请求保存的租户信息是隔离的 * 3、不管是单例还是请求作用域,你都仅能获取到当前请求对应的租户数据 --- # 文件上传 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用上传组件,支持 `file` (服务器临时文件) 和 `stream` (流)两种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/upload@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/upload": "^3.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") ``` import { Configuration } from '@midwayjs/core'; import * as upload from '@midwayjs/upload'; @Configuration({ imports: [ // ...other components upload ], // ... }) export class MainConfiguration {} ``` 3、在代码中获取上传的文件 ``` import { Controller, Inject, Post, Files, Fields } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx; @Post('/upload') async upload(@Files() files, @Fields() fields) { /* files = [ { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // mode 为 file 时为服务器临时文件地址 fieldname: 'test1', // 表单 field 名 mimeType: 'application/pdf', // mime }, { filename: 'test.pdf', // 文件原名 data: ReadStream, // mode 为 stream 时为服务器临时文件地址 fieldname: 'test2', // 表单 field 名 mimeType: 'application/pdf', // mime }, // ...file 下支持同时上传多个文件 ] */ return { files, fields } } } ``` 警告 如果同时开启了 swagger 组件,请务必添加上传参数的类型(装饰器对应的类型,以及 @ApiBody 中的 type),否则会报错,更多请参考 swagger 的文件上传章节。 ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") 默认配置如下,一般情况下无需修改。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { // mode: UploadMode, 默认为file,即上传到服务器临时目录,可以配置为 stream mode: 'file', // fileSize: string, 最大上传文件大小,默认为 10mb fileSize: '10mb', // whitelist: string[],文件扩展名白名单 whitelist: uploadWhiteList.filter(ext => ext !== '.pdf'), // tmpdir: string,上传的文件临时存储路径 tmpdir: join(tmpdir(), 'midway-upload-files'), // cleanTimeout: number,上传的文件在临时目录中多久之后自动删除,默认为 5 分钟 cleanTimeout: 5 * 60 * 1000, // base64: boolean,设置原始body是否是base64格式,默认为false,一般用于腾讯云的兼容 base64: false, // 仅在匹配路径到 /api/upload 的时候去解析 body 中的文件信息 match: /\/api\/upload/, }, } ``` ### 上传模式 - file[​](#上传模式---file "上传模式 - file的直接链接") `file` 为默认值,也是框架的推荐值。 配置 upload 的 mode 为 `file` 字符串,或使用 `@midwayjs/upload` 包导出的 `UploadMode.File` 来配置。 使用 file 模式时,通过 `this.ctx.files` 中获取的 `data` 为上传的文件在服务器的 `临时文件地址`,后续可以再通过 `fs.createReadStream` 等方式来获取到此文件内容。 使用 file 模式时,支持同时上传多个文件,多个文件会以数组的形式存放在 `this.ctx.files` 中。 警告 当采取 `file` 模式时,由于上传组件会在接收到请求时,会根据请求的 `method` 和 `headers` 中的部分标志性内容进行匹配,如果认为是一个文件上传请求,就会对请求进行解析,将其中的文件 `写入` 到服务器的临时缓存目录,您可以通过本组件的 `match` 或 `ignore` 配置来设置允许解析文件的路径。 配置 `match` 或 `ignore`后,则可以保证您的普通 post 等请求接口,不会被用户非法用作上传,可以 `避免` 服务器缓存被充满的风险。 您可以查看下面的 `配置 允许(match) 或 忽略(ignore)的上传路径` 章节,来进行配置。 ### 上传模式 - stream[​](#上传模式---stream "上传模式 - stream的直接链接") 配置 upload 的 mode 为 `stream` 字符串,或使用 `@midwayjs/upload` 包导出的 `UploadMode.Stream` 来配置。 使用 stream 模式时,通过 `this.ctx.files` 中获取的 `data` 为 `ReadStream`,后续可以再通过 `pipe` 等方式继续将数据流转至其他 `WriteStream` 或 `TransformStream`。 使用 stream 模式时,仅同时上传一个文件,即 `this.ctx.files` 数组中只有一个文件数据对象。 另外,stream 模式 `不会` 在服务器上产生临时文件,所以获取到上传的内容后无需手动清理临时文件缓存。 提示 faas 场景实现方式视平台而定,如果平台不支持流式请求/响应但是业务开启了 `mode: 'stream'`,将采用先读取到内存,再模拟流式传输来降级处理。 ### 上传白名单[​](#上传白名单 "上传白名单的直接链接") 通过 `whitelist` 属性,配置允许上传的文件后缀名,配置 `null` 则不校验后缀名。 警告 如果配置为 `null`,则不对上传文件后缀名进行校验,如果采取文件上传模式 (mode=file),则会有可能被攻击者所利用,上传 `.php`、`.asp` 等后缀的 WebShell 实现攻击行为。 当然,由于 `@midwayjs/upload` 组件会对上传后的临时文件采取 `重新随机生成` 文件名写入,只要开发者 `不将` 上传后的临时文件地址返回给用户,那么即使用户上传了一些不被预期的文件,那也无需过多担心会被利用。 如果上传的文件后缀不匹配,会响应 `400` error,默认值如下: ``` '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.wbmp', '.webp', '.tif', '.psd', '.svg', '.js', '.jsx', '.json', '.css', '.less', '.html', '.htm', '.xml', '.pdf', '.zip', '.gz', '.tgz', '.gzip', '.mp3', '.mp4', '.avi', ``` 可以通过 `@midwayjs/upload` 包中导出的 `uploadWhiteList` 获取到默认的后缀名白名单。 另外,midway 上传组件,为了避免部分 `恶意用户`,通过某些技术手段来`伪造`一些可以被截断的扩展名,所以会对获取到的扩展名的二进制数据进行过滤,仅支持 `0x2e`(即英文点 `.`)、`0x30-0x39`(即数字 `0-9`)、`0x61-0x7a`(即小写字母 `a-z`) 范围内的字符作为扩展名,其他字符将会被自动忽略。 从 v3.14.0 开始,你可以传递一个函数,可以根据不同的条件动态返回白名单。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { whitelist: (ctx) => { if (ctx.path === '/') { return [ '.jpg', '.jpeg', ]; } else { return [ '.jpg', ] }; }, // ... }, } ``` ### MIME 类型检查[​](#mime-类型检查 "MIME 类型检查的直接链接") 部分`恶意用户`,会尝试将 `.php` 等 WebShell 修改扩展名为 `.jpg`,来绕过基于扩展名的白名单过滤规则,在某些服务器环境内,这个 jpg 文件依然会被作为 PHP 脚本来执行,造成安全风险。 因此,`@midwayjs/upload` 组件提供了 `mimeTypeWhiteList` 配置参数 **【请注意,此参数无默认值设置,即默认不校验】**,您可以通过此配置设置允许的文件 MIME 格式,规则为由数组 `[扩展名, mime, [...moreMime]]` 组成的 `二级数组`,例如: ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; export default { // ... upload: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: { '.jpg': 'image/jpeg', // 也可以设置多个 MIME type,比如下面的允许 .jpeg 后缀的文件是 jpg 或者是 png 两种类型 '.jpeg': ['image/jpeg', 'image/png'], // 其他类型 '.gif': 'image/gif', '.bmp': 'image/bmp', '.wbmp': 'image/vnd.wap.wbmp', '.webp': 'image/webp', } }, } ``` 您也可以使用 `@midwayjs/upload` 组件提供的 `DefaultUploadFileMimeType` 变量,作为默认的 MIME 校验规则,它提供了常用的 `.jpg`、`.png`、`.psd` 等文件扩展名的 MIME 数据: ``` // src/config/config.default.ts import { uploadWhiteList, DefaultUploadFileMimeType } from '@midwayjs/upload'; export default { // ... upload: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: DefaultUploadFileMimeType, }, } ``` 文件格式与对应的 MIME 映射,您可以通过 `https://mimetype.io/` 这个网站来查询,对于文件的 MIME 识别,我们使用的是 [file-type@16](https://www.npmjs.com/package/file-type) 这个 npm 包,请注意它支持的文件类型。 信息 MIME 类型校验规则仅适用于使用 文件上传模式 `mode=file`,同时设置此校验规则之后,由于需要读取文件内容进行匹配,所以会稍微影响上传性能。 但是,我们依然建议您在条件允许的情况下,设置 `mimeTypeWhiteList` 参数,这将提升您的应用程序安全性。 从 v3.14.0 开始,你可以传递一个函数,可以根据不同的条件动态返回 MIME 规则。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { mimeTypeWhiteList: (ctx) => { if (ctx.path === '/') { return { '.jpg': 'image/jpeg', }; } else { return { '.jpeg': ['image/jpeg', 'image/png'], } }; } }, } ``` ### 配置 match 或 ignore[​](#配置-match-或-ignore "配置 match 或 ignore的直接链接") 当开启了 upload 组件后,当请求的 `method` 为 `POST/PUT/DELETE/PATCH` 之一时,如果判断请求的 `headers['content-type']` 中包含 `multipart/form-data` 及 `boundary` 时,将会 `**自动进入**` 上传文件解析逻辑。 这会造成:如果用户可能手动分析了网站的请求信息,手动调用任一一个 `post` 等类型的接口,将一个文件进行上传,就会触发 `upload` 组件的解析逻辑,在临时目录创建临时的已上传文件缓存,对网站服务器产生不必要的`负荷`,严重时可能会`影响`服务器正常业务逻辑处理。 所以,您可以在配置中添加 `match` 或 `ignore` 配置,来设置哪些 api 路径是允许进行上传的。 ### 同名 Field[​](#同名-field "同名 Field的直接链接") 从 v3.16.6 开始,组件支持同名 Field。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { allowFieldsDuplication: true }, } ``` 开启 `allowFieldsDuplication` 之后,同名的 Field 会被合并为数组。 ``` import { Controller, Inject, Post, Files, Fields } from '@midwayjs/core'; @Controller('/') export class HomeController { @Post('/upload') async upload(@Files() files, @Fields() fields) { /* fields = { name: ['name1', 'name2'], otherName: 'nameOther' // ... } */ } } ``` ## 临时文件与清理[​](#临时文件与清理 "临时文件与清理的直接链接") 如果你使用了 `file` 模式来获取上传的文件,那么上传的文件会存放在您于 `config` 文件中设置的 `upload` 组件配置中的 `tmpdir` 选项指向的文件夹内。 你可以通过在配置中使用 `cleanTimeout` 来控制自动的临时文件清理时间,默认值为 `5 * 60 * 1000`,即上传的文件于 `5 分钟` 后自动清理,设置为 `0` 则视为不开启自动清理功能。 你也可以在代码中通过调用 `await ctx.cleanupRequestFiles()` 来主动清理当前请求上传的临时文件。 ## 安全提示[​](#安全提示 "安全提示的直接链接") 1. 请注意是否开启 `扩展名白名单` (whiteList),如果扩展名白名单被设置为 `null`,则会有可能被攻击者所利用上传 `.php`、`.asp` 等WebShell。 2. 请注意是否设置 `match` 或 `ignore` 规则,否则普通的 `POST/PUT` 等接口会有可能被攻击者利用,造成服务器负荷加重和空间大量占用问题。 3. 请注意是否设置 `文件类型规则` (fileTypeWhiteList),否则可能会被攻击者伪造文件类型进行上传。 ## 前端文件上传示例[​](#前端文件上传示例 "前端文件上传示例的直接链接") ### 1. html form 的形式[​](#1-html-form-的形式 "1. html form 的形式的直接链接") ```
Name:
File:
``` ### 2. fetch FormData 方式[​](#2-fetch-formdata-方式 "2. fetch FormData 方式的直接链接") ``` const fileInput = document.querySelector('#your-file-input') ; const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData, }); ``` ## Postman 测试示例[​](#postman-测试示例 "Postman 测试示例的直接链接") ![](https://img.alicdn.com/imgextra/i4/O1CN01iv9ESW1uIShNiRjBF_!!6000000006014-2-tps-2086-1746.png) --- # 参数校验 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 [joi](https://joi.dev/api/) 。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 背景[​](#背景 "背景的直接链接") 最常用参数校验的地方是 控制器(Controller),同时你也可以在任意的 Class 中使用这个能力。 我们以控制器(Controller)中使用为例,还是那个 user。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ └── user.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 普通情况下,我们从 `body` 上拿到所有 Post 结果,并进行一些校验。 ``` // src/interface.ts export interface User { id: number; firstName: string; lastName: string; age: number; } // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: User) { if (!user.id || typeof user.id !== 'number') { throw new Error('id error'); } if (user.age <= 30) { throw new Error('age not match'); } // xxx } } ``` 如果每个方法都需要这么校验,会非常的繁琐。 针对这种情况,Midway 提供了 Validate 组件。 配合 `@Validate` 和 `@Rule` 装饰器,用来 **快速定义校验的规则**,帮助用户 **减少这些重复的代码**。 注意,从 v3 开始,`@Rule` 和 `@Validate` 装饰器从 `@midwayjs/validate` 中导出。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/validate@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/validate": "^3.0.0" // ... }, "devDependencies": { // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `configuration.ts` 中增加组件。 ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as validate from '@midwayjs/validate'; import { join } from 'path'; @Configuration({ imports: [koa, validate], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... } } ``` ## 定义检查规则[​](#定义检查规则 "定义检查规则的直接链接") 按照上面的逻辑,我们需要 **重新定义一个新的 Class**,因为装饰器只能装饰在实际的 Class 上,而不是 interface。 为了方便后续处理,我们将 user 放到一个 `src/dto` 目录中。 > Data Transfer Object(数据传输对象)DTO 是一组需要跨进程或网络边界传输的聚合数据的简单容器。它不应该包含业务逻辑,并将其行为限制为诸如内部一致性检查和基本验证之类的活动。 ``` // src/dto/user.ts import { Rule, RuleType } from '@midwayjs/validate'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } ``` 由于这个类属于一个 `PlainObject` ,也不需要被依赖注入管理,我们不需要提供 `@Provide` 装饰器。 这个 User Class 提供了三个属性和他们对应的校验规则。 * `id` 一个必填的数字类型 * `firstName` 一个必填的字符串类型 * `lastName` 一个可选的最长为 10 的字符串类型 * `age` 一个最大不超过 60 的数字 `@Rule` 装饰器用于 **修饰需要被校验的属性**,它的参数为 `RuleType` 对象提供的校验规则的链式方法。 信息 这里的 `RuleType` 即为 joi 对象本身。 [joi](https://joi.dev/api/) 提供了非常多的校验类型,还可以对对象和数组中的字段做校验,还有例如字符串常用的 `RuleType.string().email()` ,以及 `RuleType.string().pattern(/xxxx/)` 正则校验等,具体可以查询 [joi](https://joi.dev/api/) 的 API 文档。 ## 校验参数[​](#校验参数 "校验参数的直接链接") 定义完类型之后,就可以直接在业务代码中使用了。 ``` // src/controller/home.ts import { Controller, Get, Provide, Body } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO) { // user.id } } ``` 所有的校验代码都通通不见了,业务变的更纯粹了,当然,记得要把原来的 user interface 换成 Class。 一旦校验失败,浏览器或者控制台就会报出类似的错误。 ``` ValidationError: "id" is required ``` 同时,由于定义了 `id` 的类型,在拿到字符串的情况下,会自动将 id 变为数字。 ``` async updateUser(@Body() user: UserDTO ) { // typeof user.id === 'number' } ``` 如果需要对方法级别单独配置信息,可以使用 `@Validate` 装饰器,比如单独配置错误状态。 ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; import { Validate } from '@midwayjs/validate'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') @Validate({ errorStatus: 422, }) async updateUser(@Body() user: UserDTO) { // user.id } } ``` 一般情况下,使用全局默认配置即可。 ## 通用场景校验[​](#通用场景校验 "通用场景校验的直接链接") 如果参数不是 DTO,可以使用 `@Valid` 装饰器进行校验,`@Valid` 装饰器可以直接传递一个 Joi 规则。 ``` // src/controller/home.ts import { Controller, Get, Query } from '@midwayjs/core'; import { Valid, RuleType } from '@midwayjs/validate'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Get('/') async getUser(@Valid(RuleType.number().required()) @Query('id') id: number) { // ... } } ``` 在非 Web 场景下,没有 `@Body` 等 Web 类装饰器的情况下,也可以使用 `@Valid` 装饰器来进行校验,如果不传参数,也会复用 DTO 规则。 比如在服务中: ``` import { Valid } from '@midwayjs/validate'; import { Provide } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Provide() export class UserService { async updateUser(@Valid() user: UserDTO) { // ... } } ``` 如果参数不是 DTO,不存在规则,也可以通过参数传递一个 Joi 格式的校验规则。 ``` import { Valid, RuleType } from '@midwayjs/validate'; import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async updateUser(@Valid(RuleType.number().required()) userAge: number) { // ... } } ``` ## 校验管道[​](#校验管道 "校验管道的直接链接") 如果你的参数是基础类型,比如 `number`, `string`, `boolean`,则可以使用组件提供的管道进行校验。 默认的 Web 参数装饰器都可以在第二个参数传入管道。 比如: ``` import { ParseIntPipe } from '@midwayjs/validate'; import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number) { // ... } } ``` `ParseIntPipe` 管道可以将字符串,数字数据转换为数字,这样从请求参数获取到的 `age` 字段则会通过管道的校验并转换为数字格式。 可以使用 的内置管道有: * `ParseIntPipe` * `ParseFloatPipe` * `ParseBoolPipe` * `DefaultValuePipe` `ParseIntPipe` 用于将参数转为整形数字。 ``` import { ParseIntPipe } from '@midwayjs/validate'; // ... async update(@Body('age', [ParseIntPipe]) age: number) { return age; } update({ age: '12'} ); => 12 update({ age: '12.2'} ); => Error update({ age: 'abc'} ); => Error ``` `ParseFloatPipe` 用于将参数转为浮点型数字数字。 ``` import { ParseFloatPipe } from '@midwayjs/validate'; // ... async update(@Body('size', [ParseFloatPipe]) size: number) { return size; } update({ size: '12.2'} ); => 12.2 update({ size: '12'} ); => 12 ``` `ParseBoolPipe` 用于将参数转为布尔值。 ``` import { ParseBoolPipe } from '@midwayjs/validate'; // ... async update(@Body('isMale', [ParseBoolPipe]) isMale: boolean) { return isMale; } update({ isMale: 'true'} ); => true update({ isMale: '0'} ); => Error ``` `DefaultValuePipe` 用于设定默认值。 ``` import { DefaultValuePipe } from '@midwayjs/validate'; // ... async update(@Body('nickName', [new DefaultValuePipe('anonymous')]) nickName: string) { return nickName; } update({ nickName: undefined} ); => 'anonymous' ``` ## 自定义校验管道[​](#自定义校验管道 "自定义校验管道的直接链接") 如果默认的管道不满足需求,可以通过继承,快速实现一个自定义校验管道,组件已经提供了一个 `ParsePipe` 类用于快速编写。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validate'; @Pipe() export class ParseCustomDataPipe extends ParsePipe { getSchema(): RuleType.AnySchema { // ... } } ``` `getSchema` 方法用于返回一个符合 `Joi` 格式的校验规则。 比如 `ParseIntPipe` 的代码如下,管道执行时会自动获取这个 schema 进行校验,并在校验成功后将值返回。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validate'; @Pipe() export class ParseIntPipe extends ParsePipe { getSchema() { return RuleType.number().integer().required(); } } ``` ## 校验规则[​](#校验规则 "校验规则的直接链接") ### 常见的校验写法[​](#常见的校验写法 "常见的校验写法的直接链接") ``` RuleType.number().required(); // 数字,必填 RuleType.string().empty(''); // 字符串非必填 RuleType.number().max(10).min(1); // 数字,最大值和最小值 RuleType.number().greater(10).less(50); // 数字,大于 10,小于 50 RuleType.string().max(10).min(5); // 字符串,长度最大 10,最小 5 RuleType.string().length(20); // 字符串,长度 20 RuleType.string().pattern(/^[abc]+$/); // 字符串,匹配正则格式 RuleType.object().length(5); // 对象,key 数量等于 5 RuleType.array().items(RuleType.string()); // 数组,每个元素是字符串 RuleType.array().max(10); // 数组,最大长度为 10 RuleType.array().min(10); // 数组,最小长度为 10 RuleType.array().length(10); // 数组,长度为 10 RuleType.string().allow(''); // 非必填字段传入空字符串 export enum DeviceType { iOS = 'ios', Android = 'android', } RuleType.string().valid(...Object.values(DeviceType)) // 根据枚举值校验 ``` ### 级联校验[​](#级联校验 "级联校验的直接链接") Midway 支持每个校验的 Class 中的属性依旧是一个对象。 我们给 `UserDTO` 增加一个属性 `school` ,并且赋予一个 `SchoolDTO` 类型。 ``` import { Rule, RuleType, getSchema } from '@midwayjs/validate'; export class SchoolDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.string()) address: string; } export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; // 复杂对象 @Rule(getSchema(SchoolDTO).required()) school: SchoolDTO; // 对象数组 @Rule(RuleType.array().items(getSchema(SchoolDTO)).required()) schoolList: SchoolDTO[]; } ``` 这个时候, `@Rule` 装饰器的参数可以为需要校验的这个类型本身。 ### 继承校验[​](#继承校验 "继承校验的直接链接") Midway 支持校验继承方式,满足开发者抽离通用的对象属性的时候做参数校验。 例如我们下面 `CommonUserDTO` 抽离接口的通用的一些属性,然后 `UserDTO` 作为特殊接口需要的特定参数。 ``` import { Rule, RuleType } from '@midwayjs/validate'; export class CommonUserDTO { @Rule(RuleType.string().required()) token: string; @Rule(RuleType.string()) workId: string; } export class UserDTO extends CommonUserDTO { @Rule(RuleType.string().required()) name: string; } ``` 老版本需要在子类上面加,新版本不需要啦~ 信息 如果属性名相同,则取当前属性的规则进行校验,不会和父类合并。 ### 多类型校验[​](#多类型校验 "多类型校验的直接链接") 从 v3.4.5 开始,Midway 支持某个属性的不同类型的校验。 例如某个类型,既可以是可以普通类型,又可以是一个复杂类型。 ``` import { Rule, RuleType, getSchema } from '@midwayjs/validate'; export class SchoolDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.string()) address: string; } export class UserDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.alternatives([RuleType.string(), getSchema(SchoolDTO)]).required()) school: string | SchoolDTO; } ``` 我们可以使用 `getSchema` 方法,从某个 DTO 拿到当前的 joi schema,从而进行复杂的逻辑处理。 ### 从原有 DTO 创建新 DTO[​](#从原有-dto-创建新-dto "从原有 DTO 创建新 DTO的直接链接") 有时候,我们会希望从某个 DTO 中获取一部分属性,变成一个新的 DTO 类。 Midway 提供了 `PickDto` 和 `OmitDto` 两个方法根据现有的的 DTO 类型创建新的 DTO。 `PickDto` 用于从现有的 DTO 中获取一些属性,变成新的 DTO,而 `OmitDto` 用于将其中某些属性剔除,比如: ``` // src/dto/user.ts import { Rule, RuleType, PickDto } from '@midwayjs/validate'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } // 继承出一个新的 DTO export class SimpleUserDTO extends PickDto(UserDTO, ['firstName', 'lastName']) {} // const simpleUser = new SimpleUserDTO(); // 只包含了 firstName 和 lastName 属性 // simpleUser.firstName = xxx export class NewUserDTO extends OmitDto(UserDTO, ['age']) {} // const newUser = new NewUserDTO(); // newUser.age 定义和属性都不存在 // 使用 async login(@Body() user: NewUserDTO) { // ... } ``` ### 复用校验规则[​](#复用校验规则 "复用校验规则的直接链接") 如果很多字段都是字符串必填,或者类似需求,写 `RuleType.string().required()` 有点长,可以将重复的部分赋值为新的规则对象,进行复用。 ``` // 自己在一个文件中定义一下你们部门的规范或常用的 const requiredString = RuleType.string().required(); export class UserDTO { @Rule(requiredString) // 这样就不用写上面这么长的了 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; } // 自己在一个文件中定义一下你们部门的规范或常用的 const maxString = (length) => RuleType.string().max(length); export class UserDTO { @Rule(requiredString) // 同上 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; @Rule(maxString(50)) // 这样通过换个参数即可 info: string; @Rule(maxString(50).required()) // 这样也行 info2: string; } ``` ## 多语言[​](#多语言 "多语言的直接链接") 在 Validate 中,同时依赖了 [i18n](/docs/3.0.0/extensions/i18n.md) 组件来实现校验消息的国际化。 默认情况下,提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,所以在请求失败时,会返回当前浏览器访问所指定的语言。 ### 通过装饰器指定语言[​](#通过装饰器指定语言 "通过装饰器指定语言的直接链接") 默认情况下,会跟着 i18n 组件的 `defaultLocale` 以及浏览器访问语言的情况来返回消息,不过,我们可以在装饰器中指定当前翻译的语言,比如: ``` @Controller('/user') export class UserController { @Post('/') @Validate({ locale: 'en_US', }) async getUser(@Body() bodyData: UserDTO) { // ... } } ``` ### 通过参数指定语言[​](#通过参数指定语言 "通过参数指定语言的直接链接") 除了装饰器指定,我们也可以使用标准的 i18n 通过参数指定语言的方式。 比如 Query 参数。 ``` Get /user/get_user?locale=zh_CN ``` 更多的参数用法请参考 [i18n](/docs/3.0.0/extensions/i18n.md) 组件。 ### 其他语言的翻译[​](#其他语言的翻译 "其他语言的翻译的直接链接") 默认情况下,Midway 提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,如果还需要额外的翻译,可以配置在 i18n 中。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { // 增加翻译 zh_TW: { validate: require('../../locales/zh_TW.json'), }, }, }; ``` 如果可以的话,我们希望你将翻译提交给 Midway 官方,让大家都能使用。 ## 自定义错误文本[​](#自定义错误文本 "自定义错误文本的直接链接") ### 指定单个规则的文本[​](#指定单个规则的文本 "指定单个规则的文本的直接链接") 如果只想定义某个 DTO 中某个规则的错误消息,可以简单指定。 ``` export class UserDTO { @Rule(RuleType.number().required().error(new Error('my custom message'))) id: number; } ``` 这个 `id` 属性上的所有规则,只要有验证失败的,都会返回你的自定义消息。 ### 全局指定部分文本[​](#全局指定部分文本 "全局指定部分文本的直接链接") 通过配置 i18n 组件的 `validate` 多语言文本表,你可以选择性的替换大部分的校验文本,所有的规则都会应用该文本。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { zh_CN: { validate: { 'string.max': 'hello world', }, }, }, }, }; ``` 这里的 `validate` 是 `@midwayjs/validate` 组件在 i18n 组件中配置的语言表关键字。 由于 [默认的语言表](https://github.com/midwayjs/midway/tree/main/packages/validate/locales) 也是对象形式,我们可以很方便的找到其中的字段,进行替换。 由于这些文本区分语言,所以需要谨慎处理,比如,替换不同的语言。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { zh_CN: { validate: { 'string.max': '字符超长', }, }, en_US: { validate: { 'string.max': 'string is too long', }, }, }, }, }; ``` ### 完全自定义错误文本[​](#完全自定义错误文本 "完全自定义错误文本的直接链接") 如果希望完全自定义错误文本,可以通过替换内置的语言翻译文本来解决。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { localeTable: { // 替换中文翻译 zh_CN: { validate: require('../../locales/custom.json'), }, }, }, }; ``` ## 默认配置[​](#默认配置 "默认配置的直接链接") 我们可以对 validate 组件做一些配置。 | 配置项 | 类型 | 描述 | | ----------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | errorStatus | number | 当校验出错时,返回的 Http 状态码,在 http 场景生效,默认 422 | | locale | string | 校验出错文本的默认语言,当前有 `en_US` 和 `zh_CN` 两种,默认为 `en_US`,会根据 i18n 组件的规则切换 | | validationOptions | joi 的 ValidationOptions 选项 | 常用的有 allowUnknown,stripUnknown 等选项,如果配置,那么全局的校验都允许出现没有定义的字段,更多的请查看 joi 的 [ValidationOptions 选项](https://joi.dev/api/?v=17.6.0#anyvalidatevalue-options)。 | ## 独立的校验服务[​](#独立的校验服务 "独立的校验服务的直接链接") 组件底层提供了单例的 `ValidateService` 校验服务类,如有必要,可以在中间件或者独立的服务中使用。事实上,所有的校验装饰器,最终都会走到这个方法。 `ValidateService` 提供了一个 `validate` 方法,用于校验 DTO。 我们以上面定义的 `UserDTO` 为例。 ``` import { ValidateService } from '@midwayjs/validate'; export class UserService { @Inject() validateService: ValidateService; async inovke() { // ... const result = this.validateService.validate(UserDTO, { name: 'harry', nickName: 'harry', }); // 失败返回 result.error // 成功返回 result.value } } ``` `validate` 方法返回的 result 包含 `error` 和 `value` 两个属性。失败会返回 `MidwayValidationError` 错误,成功会返回格式化好的 DTO 对象。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、允许未定义的字段[​](#1允许未定义的字段 "1、允许未定义的字段的直接链接") 由于部分用户在参数校验的时候,希望允许出现没有定义的字段,可以在全局配置,以及装饰器上分别设置,前者对全局生效,后者对单个校验生效。 ``` // src/config/config.default.ts export default { // ... validate: { validationOptions: { allowUnknown: true, // 全局生效 }, }, }; ``` 或者在装饰器上。 ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate({ validationOptions: { allowUnknown: true, }, }) async updateUser(@Body() user: UserDTO) { // user.id } } ``` ### 2、剔除参数中的未定义属性[​](#2剔除参数中的未定义属性 "2、剔除参数中的未定义属性的直接链接") 也同样是 validationOptions 的属性,可以直接剔除传入的参数中的某些属性。 ``` // src/config/config.default.ts export default { // ... validate: { validationOptions: { stripUnknown: true, // 全局生效 }, }, }; ``` 或者在装饰器上。 ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate({ validationOptions: { stripUnknown: true, }, }) async updateUser(@Body() user: UserDTO) {} } ``` ### 3、处理校验错误[​](#3处理校验错误 "3、处理校验错误的直接�链接") 上面提到,Midway 会在校验失败时抛出 `MidwayValidationError` 错误,我们可以在 [异常处理器](/docs/3.0.0/error_filter.md) 中处理。 比如: ``` // src/filter/validate.filter import { Catch } from '@midwayjs/core'; import { MidwayValidationError } from '@midwayjs/validate'; import { Context } from '@midwayjs/koa'; @Catch(MidwayValidationError) export class ValidateErrorFilter { async catch(err: MidwayValidationError, ctx: Context) { // ... return { status: 422, message: '校验参数错误,' + err.message, }; } } ``` ### 4、临时禁用全局校验[​](#4临时禁用全局校验 "4、临时禁用全局校验的直接链接") 开启组件后,只要参数使用了 DTO,就会自动被校验,如果某个参数临时无需验证,可以使用下面的写法。 ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: Partial) {} } ``` --- # WebSocket [ws](https://www.npmjs.com/package/ws) 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. 这种可以持续连接的特性使得 WebSocket 特别适合用于适合用于游戏或者聊天室等使用场景。 Midway 提供了对 [ws](https://www.npmjs.com/package/ws) 模块的支持和封装,能够简单的创建一个 WebSocket 服务。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 WebSocket 的依赖。 ``` $ npm i @midwayjs/ws@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/ws": "^3.0.0", // ... }, } ``` ## 开启组件[​](#开启组件 "开启组件的��直接链接") `@midwayjs/ws` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [ws], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 下面是 WebSocket 项目的基础目录结构,和传统应用类似,我们创建了 `socket` 目录,用户存放 WebSocket 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## ws 服务的文件 │ └── hello.controller.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController` 装饰器定义 WebSocket 服务。 ``` import { WSController } from '@midwayjs/core'; @WSController() export class HelloSocketController { // ... } ``` 当有客户端连接时,会触发 `connection` 事件,我们在代码中可以使用 `@OnWSConnection()` 装饰器来修饰一个方法,当每个客户端第一次连接服务时,将自动调用该方法。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; import * as http from 'http'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod(socket: Context, request: http.IncomingMessage) { console.log(`namespace / got a connection ${this.ctx.readyState}`); } } ``` 信息 这里的 ctx 等价于 WebSocket 实例。 ## 消息和响应[​](#消息和响应 "消息和响应的直接链接") WebSocket 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()` 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, OnWSMessage, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') async gotMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } } ``` 我们可以通过 `@WSBroadCast` 装饰器将消息发送到所有连接的客户端上。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') @WSBroadCast() async gotMyMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } @OnWSDisConnection() async disconnect(id: number) { console.log('disconnect ' + id); } } ``` 通过 `@OnWSDisConnection` 装饰器,在客户端断连时,做一些额外处理。 ## WebSocket Server 实例[​](#websocket-server-实例 "WebSocket Server 实例的直接链接") 该组件提供的 App 即为 WebSocket Server 实例本身,我们可以如下获取。 ``` import { Controller, App } from '@midwayjs/core'; import { Application } from '@midwayjs/ws'; @Controller() export class HomeController { @App('webSocket') wsApp: Application; } ``` 比如,我们可以在其他 Controller 或者 Service 中广播消息。 ``` import { Controller, App } from '@midwayjs/core'; import { Application } from '@midwayjs/ws'; @Controller() export class HomeController { @App('webSocket') wsApp: Application; async invoke() { this.wsApp.clients.forEach(ws => { // ws.send('something'); }); } } ``` ## 心跳检查[​](#心跳检查 "心跳检查的直接链接") 有时服务器和客户端之间的连接可能会中断,服务器和客户端都不知道连接的断开情况。 可以通过启用 `enableServerHeartbeatCheck` 配置心跳检查主动断开请求。 ``` // src/config/config.default export default { // ... webSocket: { enableServerHeartbeatCheck: true, }, } ``` 默认检查时间为 `30*1000` 毫秒,可以通过 `serverHeartbeatInterval` 进行修改,配置单位为毫秒。 ``` // src/config/config.default export default { // ... webSocket: { serverHeartbeatInterval: 30000, }, } ``` 这一配置每隔一段时间会自动发送 `ping` 包,客户端若没有在下一个时间间隔返回消息,则会被自动 `terminate` 。 客户端如果希望知道服务端的状态,可以通过监听 `ping` 消息来实现。 ``` import WebSocket from 'ws'; function heartbeat() { clearTimeout(this.pingTimeout); // 每次接收 ping 之后,延迟等待,如果下一次未拿到服务端 ping 消息,则认为出现问题 this.pingTimeout = setTimeout(() => { // 重连或者中止 }, 30000 + 1000); } const client = new WebSocket('wss://websocket-echo.com/'); // ... client.on('ping', heartbeat); ``` ## 鉴权[​](#鉴权 "鉴权的直接链接") 在 WebSocket 连接建立之前,您可能需要对客户端进行身份验证。从 v3.20.9 开始 Midway 提供了 `onWebSocketUpgrade` 方法来在 WebSocket 握手前进行鉴权。 ### 设置鉴权处理器[​](#设置鉴权处理器 "设置鉴权处理器的直接链接") 您可以在应用启动时设置鉴权处理器: ``` import { Configuration, Inject } from '@midwayjs/core'; import { Framework } from '@midwayjs/ws'; @Configuration() export class WSConfiguration { @Inject() wsFramework: Framework; async onReady() { // 设置升级前鉴权处理器 this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { // 从 URL 参数中获取 token const url = new URL(request.url, `http://${request.headers.host}`); const token = url.searchParams.get('token'); // 验证 token if (token === 'valid-token') { return true; // 允许连接 } return false; // 拒绝连接 }); } } ``` ### 鉴权处理器参数[​](#鉴权处理器参数 "鉴权处理器参数的直接链接") 鉴权处理器接收三个参数: * `request`: HTTP 请求对象 (`http.IncomingMessage`) * `socket`: 原始 socket 对象 * `head`: WebSocket 握手的头部数据 (`Buffer`) 处理器需要返回一个 `Promise`: * `true`: 允许 WebSocket 连接 * `false`: 拒绝 WebSocket 连接 ### 获取鉴权信息[​](#获取鉴权信息 "获取鉴权信息的直接链接") 您可以从多个来源获取鉴权信息: **URL 参数** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const url = new URL(request.url, `http://${request.headers.host}`); const token = url.searchParams.get('token'); const userId = url.searchParams.get('userId'); // 验证逻辑 return await this.validateToken(token, userId); }); ``` **请求头** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const authorization = request.headers.authorization; if (!authorization) { return false; } const token = authorization.replace('Bearer ', ''); return await this.validateToken(token); }); ``` **Cookie** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const cookie = request.headers.cookie; if (!cookie) { return false; } // 解析 cookie 获取 session 信息 const sessionId = this.parseCookie(cookie).sessionId; return await this.validateSession(sessionId); }); ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") ### 配置测试端口[​](#配置测试端口 "配置测试端口的直接链接") 由于 ws 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway 框架一起启动)。 当作为独立框架启动时,需要指定端口。 ``` // src/config/config.default export default { // ... webSocket: { port: 3000, }, } ``` 当作为副框架启动时(比如和 http ,由于 http 在单测时未指定端口(使用 supertest 自动生成),无法很好的测试,可以仅在测试环境显式指定一个端口。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, webSocket: { port: 3000, }, } ``` 提示 * 1、这里的端口仅为 WebSocket 服务在测试时启动的端口 * 2、koa 中的端口为 null,即意味着在测试环境下,不配置端口,不会启动 http 服务 ### 测试代码[​](#测试代码 "测试代码的直接链接") 和其他 Midway 测试方法一样,我们使用 `createApp` 启动项目。 ``` import { createApp, close } from '@midwayjs/mock' // 这里使用的 Framework 定义,以主框架为准 import { Framework } from '@midwayjs/koa'; describe('/test/index.test.ts', () => { it('should create app and test webSocket', async () => { const app = await createApp(); //... await close(app); }); }); ``` ### 测试客户端[​](#测试客户端 "测试客户端的直接链接") 你可以直接使用 `ws` 来测试。也可以使用 Midway 提供的基于 `ws` 模块封装的测试客户端。 比如: ``` import { createApp, close, createWebSocketClient } from '@midwayjs/mock'; import { sleep } from '@midwayjs/core'; // ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); const result = await new Promise(resolve => { client.on('message', (data) => { // xxxx resolve(data); }); // 发送事件 client.send(1); }); // 判断结果 expect(JSON.parse(result)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); ``` 使用 node 自带的 `events` 模块的 `once` 方法来优化,就会变成下面的代码。 ``` import { sleep } from '@midwayjs/core'; import { once } from 'events'; import { createApp, close, createWebSocketClient } from '@midwayjs/mock'; // ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(process.cwd()); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); // 发送事件 client.send(1); // 用事件的 promise 写法监听 let gotEvent = once(client, 'message'); // 等待返回 let [data] = await gotEvent; // 判断结果 expect(JSON.parse(data)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 配置[​](#配置 "配置的直接链接") ## 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/ws` 的配置样例如下: ``` // src/config/config.default export default { // ... webSocket: { port: 7001, }, } ``` 当 `@midwayjs/ws` 和其他 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` 同时启用时,可以复用端口。 ``` // src/config/config.default export default { // ... koa: { port: 7001, }, webSocket: { // 这里不配置即可 }, } ``` | 属性 | 类型 | 描述 | | ------ | ---------- | -------------------------------------------------------------------------------------------------------------------------- | | port | number | 可选,如果传递了该端口,ws 内部会创建一个该端口的 HTTP 服务。如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | server | httpServer | 可选,当传递 port 时,可以指定一个已经存在的 webServer | 更多的启动选项,请参考 [ws 文档](https://github.com/websockets/ws)。 --- # 关于 Alias Path 我们并不建议使用 Alias Path, Node 和 TS 原生不支持这个功能,即使有,现在也是通过各种 Hack 手段来实现(从 v18 开始,Node.js 已经有 exports 的方案,但是类型还未支持,可以等后续)。 如果你一定想要使用,请往下看。 ## 本地开发的支持(dev 阶段)[​](#本地开发的支持dev-阶段 "本地开发的支持(dev 阶段)的直接链接") tsc 将 ts 编译成 js 的时候,并不会去转换 import 的模块路径,因此当你在 `tsconfig.json` 中配置了 paths 之后,如果你在 ts 中使用 paths 并 import 了对应模块,编译成 js 的时候就有大概率出现模块找不到的情况。 解决办法是,要么不用 paths ,要么使用 paths 的时候只用来 import 一些声明而非具体值,再要么就可以使用 [tsconfig-paths](https://github.com/dividab/tsconfig-paths) 来 hook 掉 node 中的模块路径解析逻辑,从而支持 `tsconfig.json` 中的 paths。 ``` $ npm i tsconfig-paths --save-dev ``` 使用 tsconfig-paths 可以在 `src/configuration.ts` 中引入。 ``` // src/configuration.ts import 'tsconfig-paths/register'; // ... ``` 信息 上述的方法只会对 dev 阶段( ts-node)生效。 ## 测试的支持(jest test)[​](#测试的支持jest-test "测试的支持(jest test)的直接链接") 在测试中,由于 Jest 的环境比较特殊,需要对 alias 再做一次处理,可以利用 Jest 的配置文件中的 `moduleNameMapper` 功能来替换加载到的模块,变相实现 alias 的功能。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], moduleNameMapper: { '^@/(.*)$': '/src/$1' } }; ``` 注意,这里使用的 alias 前缀是 @符号,如果是其他的 alias 名,请自行修改。 ## 运行时的支持[​](#运行时的支持 "运行时的支持的直接链接") `tsconfig-paths` 是在 ts 运行后在内存中替换路径,编译后依旧会输出带 @符号的路径,使得部署后找不到文件,社区有一些库会在 ts 编译做一些替换支持。 比如: * ## 其他[​](#其他 "其他的直接链接") 老版本 CLI 中预埋了一个 mwcc 编译器,基于固定 TS 版本在构建器替换 Alias 内容,但是由于依赖 TS 私有 API 导致无法升级 TS 版本,无法享受到新版本的功能。 我们从 CLI 2.0 版本开始,移除了这个编译器。 --- # 常见框架问题 ## 多个 @midwayjs/core 警告[​](#多个-midwayjscore-警告 "多个 @midwayjs/core 警告的直接链接") `@midwayjs/core` 包一般来说,npm 会让相同的依赖在 node\_modules 存在一份实例,其余的模块都会通过软链(link)链接到 node\_modules/@midwayjs/core。 我们会用到下面的命令,`npm ls` 会列出项目底下某个包的依赖树。 ``` $ npm ls @midwayjs/core ``` 比如下图所示。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Td86gC1tQsKjRB8XU_!!6000000005897-2-tps-541-183.png) 灰色的 `deduped` 指的就是该包是被 npm 软链到同一个模块,是正常的。 我们再来看下有问题的示例。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01gsnexD1i6lA7kM48q_!!6000000004364-2-tps-1010-308.png) 这是一个 lerna 项目,最下面的 demo-docs 中的 decorator 包,后面没有 **deduped** 标示,说明这个包是独立存在的,是错误的。 根据这个思路,我们可以逐步排查为什么会出现这种情况。 比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装。 我们可以按照下面的思路逐步排查: * 1、包含不同版本的 decorator 包(比如,package-lock 锁包,或者依赖写死版本) * 2、未正确使用 lerna 的 hoist 模式(比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装) ## xxx is not valid in current context[​](#xxx-is-not-valid-in-current-context "xxx is not valid in current context的直接链接") 这个是当依赖注入容器中某个属性所关联的类在依赖注入容器中找不到爆出的。这个错误展示的可能会递归,比较深。 比如: ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01sTvqNX1NiDcoiyS2a_!!6000000001603-2-tps-1053-141.png) 错误核心就是第一个属性,在某个类中找不到。 比如上图的核心就是 `packageBuildInfoHsfService` 这个注入的类找不到。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01BBe4gu1KHhqnT0S75_!!6000000001139-2-tps-765-166.png) 这个时候,就需要去对应的类中去看,是否是 provide 出来的名字被自定义了。 常见的问题有: * 1、Provide 装饰器导出的名字不对,无法和属性对应 * 2、Provide 为空的话,大概率是大小写没写对 * 3、注入是组件的话,可能是漏了组件名 简单的解法:`@Inject` 装饰器不加参数,属性的定义写明确的类,这样 midway 可以自动找到对应的类并注入(不适用于多态的情况)。 ``` @Inject() service: PackageBuildInfoHsfService; ``` ## TypeError: (0 ,decorator\_1.Framework) is not a function[​](#typeerror-0-decorator_1framework-is-not-a-function "TypeError: (0 ,decorator_1.Framework) is not a function的直接链接") 原因为使用了错误的版本,比如低版本的框架,使用了高版本的组件(2.x 的框架使用了 3.x 的组件)。 ![](https://img.alicdn.com/imgextra/i3/O1CN01G7gzCj1EkCpW1gaJl_!!6000000000389-2-tps-1461-491.png) 解法:确认自己的框架大版本(@midwayjs/core 的版本即为框架版本),选择对应的文档,对应的组件使用。 --- # 常见 git 问题 ## 文件名大小写问题[​](#文件名大小写问题 "文件名大小写问题的直接链接") 由于 git 默认对大小写不敏感,如果文件名从小写变成了大写之后,无法发现文件有变化导致没有提交到仓库。 更可怕的是 mac 也是大小写不敏感,经常出现到本地可以运行,到服务器就执行错误的情况。 为此,我们最好把 git 的默认大小写关闭。 下面的命令。 ``` $ git config core.ignorecase false ## 对当前项目生效 $ git config --global --add core.ignorecase false ## 对全局生效 ``` ## windows 下换行问题[​](#windows-下换行问题 "windows 下换行问题的直接链接") 在 Windows 上创建或者克隆代码,开发或者提交时,可能出现如下错误: ``` Delete `␍`eslint(prettier/prettier) ``` 原因如下: 由于历史原因,windows下和linux下的文本文件的换行符不一致。 * Windows在换行的时候,同时使用了回车符 CR(carriage-return character) 和换行符 LF(linefeed character) * 而Mac和Linux系统,仅仅使用了换行符 LF * 老版本的Mac系统使用的是回车符 CR | Windows | Linux/Mac | Old Mac(pre-OSX | | ------- | --------- | --------------- | | CRLF | LF | CR | | '\n\r' | '\n' | '\r' | 因此,文本文件在不同系统下创建和使用时就会出现不兼容的问题。 解决方案如下: 设置全局 git 文本换行 ``` $ git config --global core.autocrlf false ``` 注意:git 全局配置之后,你需要重新拉取代码。 如您使用的是vscode编辑器,解决方案如下: 在编辑器右下角将`CRLF`手动更改为`LF` 此方法仅可修改当前文件的换行符,使用vscode新建文件换行符还为`CRLF`,可在`settings.json`中增加以下配置 ``` "files.eol": "\n", ``` 参考: * [Delete `␍`eslint(prettier/prettier) 错误的解决方案](https://juejin.cn/post/6844904069304156168) * [配置 Git 处理行结束符](https://docs.github.com/cn/github/getting-started-with-github/configuring-git-to-handle-line-endings) --- # 常见 npm 问题 ## 1、不希望生成 package-lock.json[​](#1不希望生成-package-lockjson "1、不希望生成 package-lock.json的直接链接") 在某些时候,锁版本不是特别好用,反而会出现不少奇怪的问题,我们会禁用 npm 的生成 `package-lock.json` 文件的功能。 可以输入下面的命令。 ``` $ npm config set package-lock false ``` ## 2、Maximum call stack size exceeded 报错[​](#2maximum-call-stack-size-exceeded-报错 "2、Maximum call stack size exceeded 报错的直接链接") 一般在 npm install 之后,再 npm install 某个包导致的。 解法: * 1、删除 node\_modules * 2、删除 package-lock.json * 3、重新 npm install 如果还有问题,可以尝试使用 node v14/npm6 重试。 ## 3、Python/Canvas 报错[​](#3pythoncanvas-报错 "3、Python/Canvas 报错的直接链接") 出现在使用 node v15/npm7 安装 jest 模块。 比如: ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01fctCcQ2191p8aMfDd_!!6000000006941-2-tps-1623-295.png) 解决方案:npm i 时添加 `--legacy-peer-deps` 参数。 原因:测试框架 Jest 依赖 jsdom,npm7 会自动安装其 peerDependencies 中依赖的 canvas 包, 而 canvas 的安装编译需要有python3环境。 --- # 常见 TS 问题 TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 ## 依赖包定义错误[​](#依赖包定义错误 "依赖包定义错误的直接链接") 如果依赖包和项目本身的 TS 版本不一致,在编译时会出现错误。 可以在 `tsconfig.json` 关闭依赖包的检查。 ``` { "compilerOptions": { "skipLibCheck": true }, } ``` ## TS2564 初始化未赋值错误[​](#ts2564-初始化未赋值错误 "TS2564 初始化未赋值错误的直接链接") 错误如下: ``` error TS2564: Property 'name' has no initializer and is not definitely assigned in the constructor. ``` 原因为开启了 TS 的初始化属性检查,如果没有初始化赋值就会报错。 处理方法: 第一种:移除 tsconfig.json 的检查规则 ``` { "strictPropertyInitialization": false // 或者移除 } ``` 第二种:属性加感叹号 ``` export class HomeController { @Inject() userService!: UserService; } ``` ## TS6133 对象声明未使用错误[​](#ts6133-对象声明未使用错误 "TS6133 对象声明未使用错误的直接链接") 错误如下: ``` error TS6133: 'app' is declared but its value is never read. ``` 原因为开启了 TS 的对象未使用检查,如果声明了但是没有使用就会报错。 处理方法: 第一种:移除未定义的变量 第二种:移除 tsconfig.json 的检查规则 ``` { "compilerOptions": { "noUnusedLocals": false }, } ``` ## tsconfig 中定义 typings 不生效[​](#tsconfig-中定义-typings-不生效 "tsconfig 中定义 typings 不生效的直接链接") 在 tsconfig.json 中,如果定义了 typeRoots,且定义了 include,如果 include 中不包含 typeRoot 中的内容,则会在 dev/build 时报错。 此为 ts/ts-node 的问题,issue 见 [#782](https://github.com/TypeStrong/ts-node/issues/782) [#22217](https://github.com/microsoft/TypeScript/issues/22217) 比如: ``` "typeRoots": [ "./node_modules/@types", "./typings" ], "include": [ "src", "typings" ], "exclude": [ "dist", "node_modules" ], ``` 上述,如果 include 中不写 typings,则会在 dev/build 时找不到定义而报错。 --- # 守卫 从 v3.6.0 开始,Midway 提供守卫能力。 守卫会根据运行时出现的某些条件(例如权限,角色,访问控制列表等)来确定给定的请求是否由路由处理程序处理。 普通的应用程序中,一般会在中间件中处理这些逻辑,但是中间件的逻辑过于通用,同时也无法很优雅的去和路由方法进行结合,为此我们在中间件之后,进入路由方法之前设计了守卫,可以方便的进行方法鉴权等处理。 下面的代码,我们将以 `@midwayjs/koa` 举例。 ## 编写守卫[​](#编写守卫 "编写守卫的直接链接") 一般情况下,我们会在 `src/guard` 文件夹中编写守卫。 创建一个 `src/guard/auth.guard.ts` ,用于验证路由是否能被用户访问。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── guard │ │ └── auth.guard.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` Midway 使用 `@Guard` 装饰器标识守卫,示例代码如下。 ``` import { IMiddleware, Guard, IGuard } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // ... } } ``` `canActivate` 方法用于在请求中验证是否可以访问后续的方法,当返回 true 时,后续的方法会被执行,当 `canActivate` 返回 false 时,会抛出 403 错误码。 ## 使用守卫[​](#使用守卫 "使用守卫的直接链接") 守卫可以被应用到不同的框架上,在 http 下,可以应用到全局,Controller 和方法上,在其他的 Framework 实现中,仅能在方法上使用。 ### 路由守卫[​](#路由守卫 "路由守卫的直接链接") 在写完守卫之后,我们需要把它应用到各个控制器路由之上。 使用 `UseGuard` 装饰器,我们可以应用到类和方法上。 ``` import { Controller } from '@midwayjs/core'; import { AuthGuard } from '../guard/auth.guard'; @UseGuard(AuthGuard) @Controller('/') export class HomeController { } ``` 在方法上应用守卫。 ``` import { Controller, Get } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; import { AuthGuard } from '../guard/auth.guard'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @Get('/', { middleware: [ ReportMiddleware ]}) async home() { } } ``` 也可以传入数组。 ``` @UseGuard([AuthGuard, Auth2Guard]) ``` ### 全局守卫[​](#全局守卫 "全局守卫的直接链接") 我们需要在应用启动前,加入当前框架的守卫列表中,`useGuard` 方法,可以把守卫加入到守卫列表中。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { AuthGuard } from './guard/auth.guard'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useGuard(AuthGuard); } } ``` 同理可以添加多个守卫。 ``` async onReady() { this.app.useGuard([AuthGuard, Auth2Guard]); } ``` ## 自定义错误[​](#自定义错误 "自定义错误的直接链接") 默认情况下,守卫的 `canActivate` 方法当返回 false 时,框架会抛出 403 错误(`ForbiddenError`)。 你也可以在守卫中自行决定需要抛出的错误。 ``` import { IMiddleware, Guard, IGuard, httpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // ... if (methodName ==='xxx') { throw new httpError.ForbiddenError(); } return true; } } ``` 提示 注意全局错误处理器也会拦截守卫抛出的错误。 ## 和中间件的区别[​](#和中间件的区别 "和中间件的区别的直接链接") 守卫会在全局中间件 **之后**,路由方法业务逻辑 **之前** 执行。 中间件一般编写通用的处理逻辑,比如登录,用户识别,安全校验等,而守卫由于在路由内部,更适合做基于路由的权限控制。 中间件中虽然有路由信息,但是无法明确得知具体进入的是哪个实际的路由控制器(除非额外查询匹配),而守卫已经进入了路由方法,在性能方面有比较大的优势。 ## 基于角色的鉴权示例[​](#基于角色的鉴权示例 "基于角色的鉴权示例的直接链接") 一般情况下,我们会把方法访问和角色关联起来,下面我们来简单实现一个基于用户角色的访问控制。 首先,我们定义一个 `@Role` 装饰器,用于设定方法的访问权限。 ``` // src/decorator/role.decorator.ts import { savePropertyMetadata } from '@midwayjs/core'; export const ROLE_META_KEY = 'role:name' export function Role(roleName: string | string[]): MethodDecorator { return (target, propertyKey, descriptor) => { roleName = [].concat(roleName); // 只保存元数据 savePropertyMetadata(ROLE_META_KEY, roleName, target, propertyKey); }; } ``` 编写一个守卫,用于角色鉴权。 ``` import { IMiddleware, Guard, IGuard, getPropertyMetadata } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { ROLE_META_KEY } from '../decorator/role.decorator.ts'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // 从类元数据上获取角色信息 const roleNameList = getPropertyMetadata(ROLE_META_KEY, supplierClz, methodName); if (roleNameList && roleNameList.length && context.user.role) { // 假设中间件已经拿到了用户角色信息,保存到了 context.user.role 中 // 直接判断是否包含该角色 return roleNameList.includes(context.user.role); } return false; } } ``` 在路由上使用该守卫。 ``` import { Controller, Get } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; import { AuthGuard } from '../guard/auth.guard'; @UseGuard(AuthGuard) @Controller('/user') export class HomeController { // 只允许 admin 访问 @Role(['admin']) @Get('/getUserRoles') async getUserRoles() { // ... } } ``` 只有当 `ctx.user.role` 返回了 `admin` 的时候,才会被允许访问 `/getUserRoles` 路由。 --- # 接口开发 ## 路由[​](#路由 "路由的直接链接") 在 Midway Hooks 中,你可以通过 `@midwayjs/hooks` 提供的 `Api()` 函数来快速创建接口。 Hello World 示例: /src/hello.ts ``` import { Api, Get, } from '@midwayjs/hooks'; export default Api( Get(), // Http Path: /api/hello, async () => { return 'Hello World!'; } ); ``` 一个 API 接口由以下部分组成: * `Api()`:定义接口函数 * `Get(path?: string)`:指定 Http 触发器,指定请求方法为 GET,可选参数 `path` 为接口路径,不指定路径的情况下会根据`函数名 + 文件名`生成路径,默认带有 `/api` 前缀 * `Handler: async (...args: any[]) => { ... }`:用户逻辑,处理请求并返回结果 你也可以指定路径,例子如下。 /src/hello.ts ``` import { Api, Get, } from '@midwayjs/hooks'; export default Api( Get('/hello'), // Http Path: /hello, async () => { return 'Hello World!'; } ); ``` ## 请求上下文(Context / Request / Response)[​](#请求上下文context--request--response "请求上下文(Context / Request / Response)的直接链接") 你可以通过 `@midwayjs/hooks` 提供的 `useContext` 来获取请求上下文对象。 以使用 [Koa](https://koajs.com/) 框架为例,那么 `useContext` 将返回 Koa 的 [Context](https://koajs.com/#context) 对象。 基础示例: 1. 获取请求 Method 和 Path ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); return { method: ctx.method, path: ctx.path, }; }); ``` 2. 设置返回的 Header ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.set('X-Powered-By', 'Midway'); return 'Hello World!'; }); ``` 同时我们也可以通过 `SetHeader()` 来设置 Header。 ## Http 触发器[​](#http-触发器 "Http 触发器的直接链接") | 触发器 | 注释 | | ------------------------ | --------------------------- | | `All(path?: string)` | 接受所有 Http Method 的请求 | | `Get(path?: string)` | 接受 GET 请求 | | `Post(path?: string)` | 接受 POST 请求 | | `Put(path?: string)` | 接受 PUT 请求 | | `Delete(path?: string)` | 接受 DELETE 请求 | | `Patch(path?: string)` | 接受 PATCH 请求 | | `Head(path?: string)` | 接受 HEAD 请求 | | `Options(path?: string)` | 接受 OPTIONS 请求 | ## 请求 Request[​](#请求-request "请求 Request的直接链接") ### 传递参数 Data[​](#传递参数-data "传递参数 Data的直接链接") 在 Midway Hooks 中,接口的入参就是声明函数的参数。 基础示例如下: ``` import { Api, Post, } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 你可以用两种方式来调用接口。 1. 全栈项目:基于零 Api,导入接口并调用 2. 手动调用:使用 fetch 在 Http 下,`Handler(...args: any[])` 的入参,可以在手动请求时通过设置 Http Body 的 args 参数来传递参数。 * 全栈应用(零 Api) * 手动调用 ``` import say from './api'; const response = await say('Midway'); console.log(response); // Hello Midway! ``` ``` fetch('/api/say', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ args: ['Midway'], }), }) .then((res) => res.text()) .then((res) => console.log(res)); // Hello Midway! ``` ### 查询参数 Query[​](#查询参数-query "查询参数 Query的直接链接") 查询参数可以实现在 URL 上传递参数的方式,使用该功能时,必须通过 `Query` 声明类型。 如果希望接口路径是 `/articles?page=0&limit=10`,可以这样写。 ``` import { Api, Get, Query, useContext, } from '@midwayjs/hooks'; export default Api( Get(), Query<{ page: string; limit: string; }>(), async () => { const ctx = useContext(); return { page: ctx.query.page, limit: ctx.query.limit, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getArticles from './api'; const response = await getArticles({ query: { page: '0', limit: '10' }, }); console.log(response); // { page: '0', limit: '10' } ``` ``` fetch('/api/articles?page=0&limit=10') .then((res) => res.json()) .then((res) => console.log(res)); // { page: '0', limit: '10' } ``` ### 路径参数 Params[​](#路径参数-params "路径参数 Params的直接链接") 路径参数可以实现动态路径和从路径中获取参数的功能。使用该功能时,必须手动设置路径,并通过 `Params` 声明类型。 如果希望接口路径是 `/article/100`,并获取 id 为 `100` 的值,可以这样写: ``` import { Api, Get, Params, useContext, } from '@midwayjs/hooks'; export default Api( Get('/article/:id'), Params<{ id: string }>(), async () => { const ctx = useContext(); return { article: ctx.params.id, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getArticle from './api/article'; const response = await getArticle({ params: { id: '100' }, }); console.log(response); // { article: '100' } ``` ``` fetch('/article/100') .then((res) => res.json()) .then((res) => console.log(res)); // { article: '100' } ``` ### 请求头 Headers[​](#请求头-headers "请求头 Headers的直接链接") 请求头可以实现通过 Http Headers 传递参数的功能,使用该功能时,必须通过 `Headers` 声明类型。 如果希望请求 `/auth`,并在 `Request Headers` 中 传递 token,可以这样写: ``` import { Api, Get, Headers, useContext, } from '@midwayjs/hooks'; export default Api( Get('/auth'), Headers<{ token: string }>(), async () => { const ctx = useContext(); return { token: ctx.headers.token, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getAuth from './api/auth'; const response = await getAuth({ headers: { token: '123456' }, }); console.log(response); // { token: '123456' } ``` ``` fetch('/auth', { headers: { token: '123456', }, }) .then((res) => res.json()) .then((res) => console.log(res)); // { token: '123456' } ``` ## 响应 Response[​](#响应-response "响应 Response的直接链接") ### 状态码 HttpCode[​](#状态码-httpcode "状态码 HttpCode的直接链接") 支持 `HttpCode(status: number)` * SetHeader * 手动设置 ``` import { Api, Get, HttpCode, } from '@midwayjs/hooks'; export default Api( Get(), HttpCode(201), async () => { return 'Hello World!'; } ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.status = 201; return 'Hello World!'; }); ``` ### 响应头 SetHeader[​](#响应头-setheader "响应头 SetHeader的直接链接") 支持 `SetHeader(key: string, value: string)` * SetHeader * 手动设置 ``` import { Api, Get, SetHeader, } from '@midwayjs/hooks'; export default Api( Get(), SetHeader('X-Powered-By', 'Midway'), async () => { return 'Hello World!'; } ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.set('X-Powered-By', 'Midway'); return 'Hello World!'; }); ``` ### 重定向 Redirect[​](#重定向-redirect "重定向 Redirect的直接链接") 支持: `Redirect(url: string, code?: number = 302)` * Redirect * 手动设置 ``` import { Api, Get, Redirect, } from '@midwayjs/hooks'; export default Api( Get('/demo'), Redirect('/hello'), async () => {} ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api( Get('/demo'), async () => { const ctx = useContext(); ctx.redirect('/hello'); } ); ``` ### 返回值类型 ContentType[​](#返回值类型-contenttype "返回值类型 ContentType的直接链接") 支持: `ContentType(type: string)`。 * ContentType * 手动设置 ``` import { Api, Get, ContentType, } from '@midwayjs/hooks'; export default Api( Get(), ContentType('text/html'), async () => { return '

Hello World!

'; } ); ``` ``` import { Api, Get, ContentType, } from '@midwayjs/hooks'; export default Api( Get(), ContentType('text/html'), async () => { return '

Hello World!

'; } ); ``` --- # Hooks Midway Hooks 可以通过使用 `Hooks` 函数来获取运行时上下文。 ## 语法[​](#语法 "语法的直接链接") Hooks 需要在 Api 接口中使用。 有效的例子: ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); console.log(ctx.method); // ... }); ``` 无效例子: ``` import { useContext } from '@midwayjs/hooks'; const ctx = useContext(); // will throw error ``` ## 支持的 Hooks[​](#支持的-hooks "支持的 Hooks的直接链接") ### useContext[​](#usecontext "useContext的直接链接") `useContext()` 函数将返回本次请求相关的上下文,返回的 `Context` 与底层使用的框架决定。 以使用 [Koa](https://koajs.com/) 框架为例,那么 `useContext` 将返回 Koa 的 [Context](https://koajs.com/#context) 对象。 以获取请求 Method 和 Path 为例。 ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); return { method: ctx.method, path: ctx.path, }; }); ``` 你可以通过泛型来标注当前上下文的类型。 ``` // Koa import { Context } from '@midwayjs/koa'; const ctx = useContext(); // FaaS import { Context } from '@midwayjs/faas'; const ctx = useContext(); ``` ## 创建可复用的 Hooks[​](#创建可复用的-hooks "创建可复用的 Hooks的直接链接") 你可以创建可复用的 Hooks,以便在多个接口中使用。 ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; function useIp() { const ctx = useContext(); return ctx.ip; } export default Api(Get(), async () => { const ip = useIp(); return { ip, }; }); ``` 一体化调用: ``` import getIp from './api'; const { ip } = await getIp(); console.log(ip); // 127.0.0.1 ``` --- # 前端请求客户端 在 Midway Hooks 的全栈应用中,我们使用 `@midwayjs/rpc` 作为默认的请求客户端。所有生成的接口都会通过 `@midwayjs/rpc` 来调用服务端。 ## 配置[​](#配置 "配置的直接链接") `@midwayjs/rpc` 提供了 `setupHttpClient` 方法来配置请求客户端(📢 `setupHttpClient` 应放置于前端代码的入口处。)。 支持的配置项如下: ``` type SetupOptions = { baseURL?: string; withCredentials?: boolean; fetcher?: Fetcher; middleware?: Middleware[]; }; type Fetcher = ( req: HttpRequestOptions, options: SetupOptions ) => Promise; type Middleware = ( ctx: Context, next: () => Promise ) => void; type Context = { req: HttpRequestOptions; res: any; }; type HttpRequestOptions = { url: string; method: HttpMethod; data?: { args: any[]; }; // query & headers query?: Record; headers?: Record; }; ``` ### baseURL: string[​](#baseurl-string "baseURL: string的直接链接") 设置请求的基础 URL,默认为 `/`。 ``` import { setupHttpClient } from '@midwayjs/rpc'; setupHttpClient({ baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:7001' : 'https://api.example.com', }); ``` ### withCredentials: boolean[​](#withcredentials-boolean "withCredentials: boolean的直接链接") 默认为 `false`。具体可参考:[MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials) ``` import { setupHttpClient } from '@midwayjs/rpc'; setupHttpClient({ withCredentials: true, }); ``` ### fetcher: Fetcher[​](#fetcher-fetcher "fetcher: Fetcher的直接链接") `@midwayjs/rpc` 默认使用 [redaxios](https://github.com/developit/redaxios) 作为请求客户端,一个遵循 axios api 的 mini 客户端。 通过设置 `fetcher`,可以替换默认的请求客户端。此处以使用 `axios` 作为默认的请求客户端为例。 ``` import axios from 'axios'; import { setupHttpClient } from '@midwayjs/rpc'; import type { Fetcher } from '@midwayjs/rpc'; const fetcher: Fetcher = async ( req, options ) => { const response = await axios({ method: req.method, url: req.url, data: req.data, params: req.query, headers: req.headers, baseURL: options.baseURL, withCredentials: options.withCredentials, }); return response.data; }; setupHttpClient({ fetcher }); ``` ### middleware: Middleware\[][​](#middleware-middleware "middleware: Middleware\[]的直接链接") 在 `@midwayjs/rpc` 中,我们可以设置中间件来用于打印参数,返回值处理错误等。 以打印当前请求的地址与返回值为例: ``` import { setupHttpClient } from '@midwayjs/rpc'; import type { Middleware } from '@midwayjs/rpc'; const logger: Middleware = async ( ctx, next ) => { console.log(`<-- ${ctx.req.url}`); await next(); console.log( `--> ${ctx.req.url} ${ctx.res}` ); }; setupHttpClient({ middleware: [logger], }); ``` 你也可以用于统一处理错误: 使用默认 `fetcher` 的情况下,`err` 类型参考:[Axios Response Schema](https://axios-http.com/docs/res_schema)。 ``` import { setupHttpClient } from '@midwayjs/rpc'; import type { Middleware } from '@midwayjs/rpc'; const ErrorHandler: Middleware = async ( ctx, next ) => { try { await next(); } catch (err) { switch (err.status) { case 401: location.href = '/login'; break; case 500: alert('Internal Server Error'); break; default: alert( `Unknown Error, status: ${err.status}` ); break; } } }; setupHttpClient({ middleware: [ErrorHandler], }); ``` --- # 使用 Midway 组件 Midway 提供了一系列的组件,包含 Cache / Http / Redis 等。 而在 Midway Hooks 中,我们可以直接使用 Midway 组件,来快速实现功能。 ## 引入组件[​](#引入组件 "引入组件的直接链接") Midway Hooks 在 `configuration.ts` 中使用 `createConfiguration()` 来配置项目,其 Api 与 `@midwayjs/decorator` 提供的 `@Configuration()` 一致。 以 `@midwayjs/cache` 组件为例: ``` import { createConfiguration, hooks, } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; import { join } from 'path'; import * as cache from '@midwayjs/cache'; export default createConfiguration({ imports: [cache, Koa, Hooks()], importConfigs: [ join(__dirname, 'config'), ], }); ``` 你可以通过 `imports` 来导入组件,`importConfigs` 来导入配置文件。 ## 使用组件[​](#使用组件 "使用组件的直接链接") 在 `@midwayjs/cache` 中,提供了 `CacheManager` 类来操作缓存。 在 Midway Hooks 中,你可以通过 `@midwayjs/hooks` 提供的 `useInject(class)` 来在运行时获取类的实例。 ``` import { Api, Get, useInject, } from '@midwayjs/hooks'; import { CacheManager } from '@midwayjs/cache'; export default Api(Get(), async () => { const cache = await useInject( CacheManager ); await cache.set('name', 'Midway'); const result = await cache.get( `name` ); return `Hello ${result}!`; }); ``` 这里的 `useInject(CacheManager)` 与 `@Inject() cache: CacheManager` 的功能是一致的。 --- # 项目配置 我们通过项目根目录下的 `midway.config.ts` 来配置项目,具体的配置项如下。 > 如果是纯接口项目,因为需要在生成环境读取配置,因此请使用 JavaScript,配置文件名: `midway.config.js` ## source: string[​](#source-string "source: string的直接链接") 配置后端根目录,纯服务接口下默认为 `./src`,全栈应用下默认为 `./src/api`。 ## routes: RouteConfig\[][​](#routes-routeconfig "routes: RouteConfig\[]的直接链接") 启用文件系统路由并配置,默认为 `undefined`。具体格式参考 [简易模式 & 文件系统路由](/docs/3.0.0/hooks/file-route.md)。 ## dev.ignorePattern: IgnorePattern[​](#devignorepattern-ignorepattern "dev.ignorePattern: IgnorePattern的直接链接") 配置全栈应用下,本地开发的哪些请求应该忽略,不进入服务端处理。 ## build.outDir: string[​](#buildoutdir-string "build.outDir: string的直接链接") 配置全栈应用的输出目录,默认为 `./dist`。 ## vite: ViteConfig[​](#vite-viteconfig "vite: ViteConfig的直接链接") 仅 `import { defineConfig } from '@midwayjs/hooks-kit'` 时可用。 配置全栈应用下 Vite 的配置,具体配置项参考 [Vite](https://vitejs.dev/config/)。 例子: ``` import react from '@vitejs/plugin-react'; import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ vite: { plugins: [react()], }, }); ``` --- # 跨域 CORS 在 Midway Hooks 中,可以通过 [@koa/cors](https://github.com/koajs/cors) 来配置跨域功能。 ## 使用方法[​](#使用方法 "使用方法的直接链接") 安装 `@koa/cors` 依赖。 ``` npm install @koa/cors ``` 在 `configuration.ts` 启用 `@koa/cors` 中间件。 ``` import { createConfiguration, hooks, } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; import cors from '@koa/cors'; export default createConfiguration({ imports: [ Koa, hooks({ middleware: [ cors({ origin: '*' }), ], }), ], }); ``` 支持的[配置项](https://github.com/koajs/cors#corsoptions)如下: ``` /** * CORS middleware * * @param {Object} [options] * - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header * - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH' * - {String|Array} exposeHeaders `Access-Control-Expose-Headers` * - {String|Array} allowHeaders `Access-Control-Allow-Headers` * - {String|Number} maxAge `Access-Control-Max-Age` in seconds * - {Boolean|Function(ctx)} credentials `Access-Control-Allow-Credentials`, default is false. * - {Boolean} keepHeadersOnError Add set headers to `err.header` if an error is thrown * @return {Function} cors middleware * @api public */ ``` --- # 调试 得益于编辑器的支持,我们可以快速的在本地调试应用。 ## VSCode[​](#vscode "VSCode的直接链接") ### JavaScript Debug Terminal[​](#javascript-debug-terminal "JavaScript Debug Terminal的直接链接") 在 VSCode 中创建 JavaScript Debug Terminal。 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789601759-d2634846-49f7-4487-be6f-0dc9e5f80082.png#clientId=u3a1b2f6d-ebe0-4\&from=paste\&height=192\&id=p5BOe\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=192\&originWidth=375\&originalType=binary\&size=31856\&status=done\&style=none\&taskId=u7286159b-9369-4d17-8a6a-c43a6f52556\&width=375) 在命令行中运行命令(如 `npm start`),将自动启用调试模式。 ### Debug Scripts[​](#debug-scripts "Debug Scripts的直接链接") 打开 `package.json`,查看 `scripts` 上方的 `debug` 按钮 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789617835-64b2099a-6b94-41c4-81fa-4f0bb0763ebb.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=225\&id=u459844f5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=225\&originWidth=565\&originalType=binary\&size=26636\&status=done\&style=none\&taskId=u3838b111-c93e-41e0-81ce-01c1bdd6ad4\&width=565) 选择 `start` 命令,既可正常的启动调试模式 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789623261-57851b50-421e-45fa-9dd9-95ac7d48776e.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=170\&id=ue315d401\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=170\&originWidth=427\&originalType=binary\&size=19905\&status=done\&style=none\&taskId=u8b079aa2-8376-4014-b48b-ed27ef66da6\&width=427) ## Jetbrains (WebStorm/IDEA...)[​](#jetbrains-webstormidea "Jetbrains (WebStorm/IDEA...)的直接链接") 打开 `package.json`,选择你要执行的 `scripts` ,并点击 `debug` 按钮,即可启动本地调试。 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789628840-eb403a2a-a864-4fd6-8f57-3f576c9b3417.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=176\&id=uc2a06ce8\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=176\&originWidth=548\&originalType=binary\&size=28656\&status=done\&style=none\&taskId=ucb4c5c34-6e56-47c9-a724-4ed700dce9d\&width=548) --- # 部署 Midway Hooks 支持 Api Server 与一体化两种模式。 ## Api Server 部署[​](#api-server-部署 "Api Server 部署的直接链接") Api Server 部署可以参考:[启动和部署](/docs/deployment.md)。 如果使用单文件部署,可以参考示例:[hooks-api-bundle-starter](https://github.com/midwayjs/hooks/blob/main/examples/api-bundle/readme.md) ## 一体化部署[​](#一体化部署 "一体化部署的直接链接") 一体化的构建产物中包含前后端,根据部署的难易程度,可以分为以下几类。 * 前后端部署在同一服务器上,由后端托管 HTML & 静态资源 & 提供接口 * 静态资源部署至 CDN,后端托管 HTML & 提供接口 * 静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口 接下来我将介绍三种部署模式如何落地,优势及存在的问题。 ### 前后端部署在同一服务器上[​](#前后端部署在同一服务器上 "前后端部署在同一服务器上的直接链接") 这是全栈套件默认的部署模式。 优势:最简单,将打包后的产物直接上传至服务器,启动后即可提供服务 劣势: * 后端服务需要处理 & 发送文件 * 静态资源不在 CDN,不同地域的访问速度不稳定 整体部署架构如图所示: ![](https://img.alicdn.com/imgextra/i1/O1CN01GYtN9n1T2tbEXWOwf_!!6000000002325-2-tps-2064-648.png) ### 静态资源部署至 CDN,后端托管 HTML & 提供接口[​](#静态资源部署至-cdn后端托管-html--提供接口 "静态资源部署至 CDN,后端托管 HTML & 提供接口的直接链接") 这也是当前前端主流的部署模式。 优势: * 静态资源由 CDN 托管,保证用户访问速度 * 后端托管 HTML,确保返回的 HTML 文件是最新的 劣势: * 后端仍需要托管 HTML,仍需要处理 & 发送文件,且如果服务宕机则页面无法访问 整体访问架构如图所示: ![](https://img.alicdn.com/imgextra/i4/O1CN01ue3LJg1HeernvfxgQ_!!6000000000783-55-tps-267-367.svg) #### 指定静态资源公共域名[​](#指定静态资源公共域名 "指定静态资源公共域名的直接链接") 在全栈套件项目中使用时,可以通过设置 `midway.config.ts` 中 `vite.base` 选项,来指定静态资源的公共域名。 ``` import react from '@vitejs/plugin-react'; import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ vite: { plugins: [react()], base: 'https://cdn.example.com', }, }); ``` 此时访问页面时,静态资源会指向 CDN 的地址。 #### 部署静态文件[​](#部署静态文件 "部署静态文件的直接链接") 全栈套件项目中,默认的构建目录为 dist,其中 `dist/_clients` 为前端静态资源目录。 如下所示: ``` dist ├── _client │   ├── assets │   │   ├── index.85bb4f15.js │   │   ├── index.b779b14d.css │   │   └── vendor.346bc0da.js │   ├── index.html │   ├── logo.png │   └── manifest.json ├── _serve │   └── index.js ├── book.js ├── configuration.js ├── date.js ├── midway.config.js └── star.js ``` 你需要自行将 `_client` 目录下的文件上传至 CDN,而在部署后端时,仍然保留 `_client/index.html` 文件,以供后端托管使用。 ### 静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口[​](#静态资源部署至-cdnhtml-由单独的服务托管cdn--nginx--etc后端仅提供接口 "静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口的直接链接") 这也是前端目前主流的部署模式。 优势: * 后端仅提供 API 接口,不需要处理 & 发送文件 * 静态资源由 CDN 托管,保证用户访问速度 * HTML 由单独服务托管,保证访问是页面是最新版本,后端服务宕机不影响页面展示 * 架构可拓展,可增加更多节点应对意外情况,如在后端前置增加网关节点,在后端服务宕机时切换至备用服务等 劣势: * 复杂,对 CI / CD 流水线及基建要求高 整体访问架构如图所示 ![](https://img.alicdn.com/imgextra/i1/O1CN01i78JiC1yinvfLq84b_!!6000000006613-55-tps-323-367.svg) 部署工作流如下: ![](https://img.alicdn.com/imgextra/i2/O1CN018oAQf71h1QxHtRHYY_!!6000000004217-2-tps-1728-1680.png) #### 全栈套件部署指南[​](#全栈套件部署指南 "全栈套件部署指南的直接链接") 需要默认禁用全栈套件的 index.html 托管能力,此时全栈套件在构建时不会生成 `index.html` 的托管函数,仅提供 Api 服务。 ``` import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ static: false, }); ``` 在你的 CI / CD 工作流中,需要针对以下文件做单独处理。 * index.html:部署至单独的托管服务,如 Nginx / CDN 等,该服务只负责静态页面渲染 * 静态资源:部署至 CDN,如 Aliyun OSS 等,该服务可以提供静态资源的 CDN 加速 * Api 服务:部署至你的服务器中 最终的域名可能如下: * index.html: * 静态资源: * Api 服务: 或者 [https://example.com/api(需要设置反向代理)](https://example.com/api%EF%BC%88%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%EF%BC%89) --- # 简易模式 & 文件系统路由 ## 简易模式[​](#简易模式 "简易模式的直接链接") 在 Midway Hooks 中,我们提供了一个简易模式,可以使用纯函数来快速创建接口。 📢 注意: * 简易模式需启用文件路由系统,需要在 `midway.config.js` 中启用 `routes` 配置。 * 纯函数自动生成的路由仅支持 `GET` 和 `POST` 方法,且全栈应用中,不支持传递 `Query / Params / Header` 参数 * 简易模式下,仍可以使用 `Api()` 定义路由,且支持手动定义路径,拼接的路径将自动加上 `basePath` ### Get 请求[​](#get-请求 "Get 请求的直接链接") ``` import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } ``` 一体化调用: ``` import { getPath } from './api/lambda'; const path = await getPath(); console.log(path); // /api/getPath ``` 手动调用: ``` fetcher .get('/api/getPath') .then((res) => { console.log(res.data); // /api/getPath }); ``` ### Post 请求[​](#post-请求 "Post 请求的直接链接") ``` import { useContext } from '@midwayjs/hooks'; export async function post( name: string ) { const ctx = useContext(); return { message: `Hello ${name}!`, method: ctx.method, }; } ``` 一体化调用: ``` import { post } from './api/lambda'; const response = await post('Midway'); console.log(response.data); // { message: 'Hello Midway!', method: 'POST' } ``` 手动调用: ``` fetch('/api/post', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ args: ['Midway'], }), }).then((res) => { console.log(res.data); // { message: 'Hello Midway!', method: 'POST' } }); ``` ### 通过 `Api()` 创建路由[​](#通过-api-创建路由 "通过-api-创建路由的直接链接") 简易模式下,我们仍支持通过 `Api()` 创建路由。 无效的例子:`Api(Get('/specify_path'))`,简易模式下不支持手动指定路径。 有效的例子,导出了两个路由。 ``` import { Api, Get, } from '@midwayjs/hooks'; import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } export default Api(Get(), async () => { return 'Hello Midway!'; }); ``` ## 文件系统路由[​](#文件系统路由 "文件系统路由的直接链接") 在 `midway.config.js` 中启用 `routes` 配置即启用文件路由系统 + 简易模式。 配置示例如下: ``` import { defineConfig } from '@midwayjs/hooks'; export default defineConfig({ source: './src/apis', routes: [ { baseDir: 'lambda', basePath: '/api', }, ], }); ``` 字段解释: * source: 后端目录,默认为 `./src/apis`,你也可以指定为 `./src/functions` 等自定义目录 * routes: 路由配置,默认为数组 * baseDir: 函数文件夹,文件夹下任意 `.ts` 文件导出的异步函数都会生成为 Api 接口 * basePath: 生成的 Api 地址前缀 ### Index 路由[​](#index-路由 "Index 路由的直接链接") 我们会将目录下 `index.ts` 文件,作为根路由。 * `/lambda/index.ts` → `/` * `/lambda/about/index.ts` → `/about` ### 嵌套路由[​](#嵌套路由 "嵌套路由的直接链接") 嵌套的文件也将生成嵌套的路由
* `/lambda/about.ts` → `/about` * `/lambda/blog/index.ts` → `/blog` * `/lambda/about/contact.ts` → `/about/contact` ### 导出方法与对应路由[​](#导出方法与对应路由 "导出方法与对应路由的直接链接") 默认导出的方法则会生成为根路径,而具名方法则会在路径上拼接函数名。 在此以 `/lambda/about.ts` 为例 * `export default () => {}` → `/about` * `export function contact ()` → `/about/contact` ### 通配路由[​](#通配路由 "通配路由的直接链接") 如果需要生成通配符路由,例如:`/api/*` ,用于匹配 /api、/api/about、/api/about/a/b/c 等。文件名按 `[...file]` 命名即可。 📢 推荐在通配路由中,只使用 `export default` 方法导出函数,从而避免不必要的路由冲突 示例: * `/lambda/[...index].ts` → `/api/*` * `/lambda/[...user].ts` → `/api/user/*` * `/lambda/about/[...contact].ts` → `/api/about/contact/*` ### 路径参数[​](#路径参数 "路径参数的直接链接") 如果需要生成动态路径参数,文件名按 `[file]` 格式命名即可。 例子: * `/lambda/[name]/project.ts` → `/api/about/:name/project` * `/about/midwayjs/project` -> `{ name: 'midwayjs' }` * `/lambda/[type]/[page].ts` → `/api/about/:type/:page` * `/blog/1` -> `{ type: 'blog', page: '1' }` * `/articles/3` -> `{ type: 'articles', page: '3' }` 使用路径参数时,后端接口仅支持使用 `Api()` 开发,并使用 `Params` 标注类型。 以 `/lambda/[name]/project.ts` 为例: ``` // lambda/[name]/project.ts import { Api, Get, Params, useContext, } from '@midwayjs/hooks'; export default Api( Get(), Params<{ name: string }>(), async () => { const ctx = useContext(); return { name: ctx.params.name, }; } ); ``` 一体化调用: ``` import getProject from './api/[name]/project'; const response = await getProject({ params: { name: 'midwayjs' }, }); console.log(response); // { name: 'midwayjs' } ``` 手动调用: ``` fetch('/api/about/midwayjs/project') .then((res) => res.json()) .then((res) => console.log(res)); // { name: 'midwayjs' } ``` --- # 全栈套件 在 Midway Hooks 中,我们提供了 `@midwayjs/hooks-kit` 来快速开发全栈应用。目前我们提供了以下可直接使用的模版: * [react](https://github.com/midwayjs/hooks/blob/main/examples/react) * [vue](https://github.com/midwayjs/hooks/blob/main/examples/vue) * [prisma](https://github.com/midwayjs/hooks/blob/main/examples/prisma) ## 命令行界面[​](#命令行界面 "命令行界面的直接链接") 在使用了 `@midwayjs/hooks-kit` 的项目中,可以在 npm scripts 中使用 hooks 可执行文件,或者通过 `npx hooks` 运行。下面是通过脚手架创建的 Midway 全栈项目中默认的 npm scripts: ``` { "scripts": { "dev": "hooks dev", // 启动开发服务器 "start": "hooks start", // 启动生产服务器,使用前请确保已运行 `npm run build` "build": "hooks build" // 为生产环境构建产物 } } ``` 在使用命令行时,可以通过命令行参数传入选项,具体选项可以通过 --help 参考。 如:`hooks build --help` 输出: ``` Usage: $ hooks build [root] Options: --outDir [string] output directory (default: dist) --clean [boolean] clean output directory before build (default: false) -h, --help Display this message ``` --- # 介绍 警告 一体化方案将逐步停止维护,已有项目可以继续使用,新建项目请谨慎选择。 Midway 的一体化方案,是以 Midway Hooks 为主函数式全栈框架,支持四大核心特性:"零" Api & 类型安全 & 全栈套件 & 强大后端。 ## 和标准项目差异[​](#和标准项目差异 "和标准项目差异的直接链接") 一体化方案,基于标准项目,在其之上扩展出了一层前端适配层,在复用所有标准项目能力的同时,又可以和前端进行无缝协作开发,即在项目中,既有前端代码,又有 Node 代码。 ## 特性介绍[​](#特性介绍 "特性介绍的直接链接") ### 零 Api[​](#零-api "零 Api的直接链接") 在 Midway Hooks 全栈应用中开发的后端接口函数,可以直接导入并调用,无需前后端手写 Ajax 胶水层。以下是一个简单的例子: 后端代码: ``` import { Api, Post, } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 前端调用: ``` import say from './api'; const response = await say('Midway'); console.log(response); // Hello Midway! ``` ### 类型安全与运行时安全[​](#类型安全与运行时安全 "类型安全与运行时安全的直接链接") 使用 `@midwayjs/hooks` 提供的 [Validate](/docs/3.0.0/hooks/validate.md) 校验器,可以实现从前端到后端的类型安全 + 运行时安全链路。以下是一个简单的例子: 后端代码: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; export default Api( Post('/hello'), Validate(z.string(), z.number()), async (name: string, age: number) => { return `Hello ${name}, you are ${age} years old.`; } ); ``` 一体化调用: ``` import hello from './api'; try { await hello(null, null); } catch (error) { console.log(error.message); // 'name must be a string' console.log(error.status); // 422 } ``` 整个过程中。 * 前端:基于类型,静态校验输入参数,并获取类型提示 * 后端:校验前端传入参数 * 数据库等业务逻辑:使用正确的数据 通过这种方式,我们可以低成本的实现静态类型安全 + 运行时安全。 ### 全栈套件[​](#全栈套件 "全栈套件的直接链接") 在 Midway Hooks 中,我们提供了 `@midwayjs/hooks-kit` 来快速开发全栈应用。 你可以通过 `hooks dev` 来启动全栈应用,`hooks build` 来打包全栈应用,同时在服务端你也可以使用 `hooks start` 一键启动应用。 解决你在使用全栈应用时的后顾之忧。 ### 强大后端[​](#强大后端 "强大后端的直接链接") Midway Hooks 基于 Midway 开发。 Midway 是一个有着 8 年历史的 Node.js 框架,具有强大的后端功能,包含 Cache / Redis / Mongodb / Task / Config 等 Web 下常用的组件。 而这些你在使用 Midway Hooks 时都可以无缝享受到。 ## 创建应用[​](#创建应用 "创建应用的直接链接") Midway Hooks 目前提供了如下模板: * 全栈应用 * [react](https://github.com/midwayjs/hooks/blob/main/examples/react) * [vue](https://github.com/midwayjs/hooks/blob/main/examples/vue) * [prisma](https://github.com/midwayjs/hooks/blob/main/examples/prisma) * Api Server * [api](https://github.com/midwayjs/hooks/blob/main/examples/api) 基于指定创建应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/ ``` 创建 react 模版的全栈应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/react ./hooks-app ``` 创建 api 模版的应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/api ./hooks-app ``` ## 下一步[​](#下一步 "下一步的直接链接") * 了解如何开发接口并提供给前端调用:[接口开发](/docs/3.0.0/hooks/api.md) * 如何使用和创建可复用的 Hooks:[Hooks](/docs/3.0.0/hooks/builtin-hooks.md) * 如何在运行时校验用户参数:[校验器](/docs/3.0.0/hooks/validate.md) --- # Web 中间件 Midway Hooks 支持通过函数 + `useContext()` 来定义 Web 中间件。 ## 语法[​](#语法 "语法的直接链接") 中间件仅有 `next` 一个参数,`ctx` 需要通过 `useContext` 获得。你也可以在中间件中使用任意的 `Hooks`。 ### 基础示例[​](#基础示例 "基础示例的直接链接") 以记录请求日志为例: ``` import { Context } from '@midwayjs/koa'; import { useContext } from '@midwayjs/hooks'; const logger = async (next: any) => { const ctx = useContext(); console.log( `<-- [${ctx.method}] ${ctx.url}` ); const start = Date.now(); await next(); const cost = Date.now() - start; console.log( `--> [${ctx.method}] ${ctx.url} ${cost}ms` ); }; ``` ## 全局中间件[​](#全局中间件 "全局中间件的直接链接") 全局中间件在 `configuration.ts` 中定义,此处定义的中间件对所有接口生效。 ``` import { hooks, createConfiguration, } from '@midwayjs/hooks'; import logger from './logger'; // Global Middleware export default createConfiguration({ imports: [ hooks({ middleware: [logger], }), ], }); ``` ## 文件级中间件[​](#文件级中间件 "文件级中间件的直接链接") 文件级中间件在 Api 文件中定义,通过导出的 `config.middleware`,该中间件对文件内所有 Api 函数生效。 ``` import { ApiConfig, Api, Get, } from '@midwayjs/hooks'; import logger from './logger'; // File Level Middleware export const config: ApiConfig = { middleware: [logger], }; export default Api(Get(), async () => { return 'Hello World!'; }); ``` ## 单函数中间件[​](#单函数中间件 "单函数中间件的直接链接") 通过 `Middleware(...middlewares: HooksMiddleware[])` 定义的中间件仅对单个函数生效 ``` import { Api, Get, Middleware, } from '@midwayjs/hooks'; import logger from './logger'; export default Api( Get(), Middleware(logger), async () => { return 'Hello World!'; } ); ``` ## 使用 Koa 中间件[​](#使用-koa-中间件 "使用 Koa 中间件的直接链接") 你可以在上述的例子中直接传入 Koa 中间件。 以 [@koa/cors](https://www.npmjs.com/package/@koa/cors) 为例 全局启用: ``` import { hooks, createConfiguration, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; // Global Middleware export default createConfiguration({ imports: [ hooks({ middleware: [logger, cors()], }), ], }); ``` 文件级别启用: ``` import { ApiConfig, Api, Get, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; // File Level Middleware export const config: ApiConfig = { middleware: [logger, cors], }; export default Api(Get(), async () => { return 'Hello World!'; }); ``` 函数级别启用: ``` import { Api, Get, Middleware, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; export default Api( Get(), Middleware(logger, cors), async () => { return 'Hello World!'; } ); ``` --- # Prisma ORM 在 Midway Hooks 中,我们推荐使用 [Prisma](https://prisma.io/) 来构建数据库,并实现我们静态类型安全的目标。 [Prsima](https://www.prisma.io/) 是面向 Node.js & TypeScript 设计的 ORM,它提供了一系列友好的功能(Schema 定义、客户端生成、完全的 TypeScript 支持),可以帮助用户快速构建应用。 ## Example[​](#example "Example的直接链接") 我们提供了一个简单的例子 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/prisma/README.md),来演示在 Midway Hooks 如何使用 Prisma。 下面我也会简单介绍,Midway Hooks 配合 Prisma 开发应用会有多么的简单。 ### 数据库 Schema[​](#数据库-schema "数据库 Schema的直接链接") 例子基于 sqlite,数据库 Schema 如下: ``` model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] } model Post { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt title String content String? published Boolean @default(false) viewCount Int @default(0) author User? @relation(fields: [authorId], references: [id]) authorId Int? } ``` 具体的数据库设置 & 初始数据填充工作,参考 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/prisma/README.md) 文档即可。 ### 初始化 Prisma[​](#初始化-prisma "初始化 Prisma的直接链接") 在项目的 src/api 下新建 prisma 文件,使用如下代码即可初始化 Client。 ``` import { PrismaClient } from '@prisma/client'; export const prisma = new PrismaClient(); ``` #### 使用代理镜像[​](#使用代理镜像 "使用代理镜像的直接链接") Prisma 在安装时会根据平台动态下载可执行文件,如果你的网络环境不好,可以通过环境变量来设置镜像。 ``` PRISMA_ENGINES_MIRROR=https://registry.npmmirror.com/-/binary/prisma/ ``` 相关 Issue: [mirror prisma](https://github.com/cnpm/mirrors/issues/248) ### 查询数据[​](#查询数据 "查询数据的直接链接") 以获取所有发布的文章为例,你可以通过生成的 Prisma Client 快速完成操作。 后端代码: ``` import { Api, Get, } from '@midwayjs/hooks'; import { prisma } from './prisma'; export default Api(Get(), async () => { const posts = await prisma.post.findMany({ where: { published: true }, include: { author: true }, }); return posts; }); ``` 一体化调用: ``` import fetchFeeds from '../api/feeds'; fetchFeeds().then((feeds) => { console.log(feeds); }); ``` ### 增加数据[​](#增加数据 "增加数据的直接链接") 以注册登录为例,基于一体化调用 + Prisma 生成的客户端,可以在简单的几行代码中完成所有的工作。 包含: * 前端类型提示 * 后端参数校验 * 数据库操作 ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; import { prisma } from './prisma'; export const signUp = Api( Post(), Validate( z.string(), z.string().email() ), async ( name: string, email: string ) => { const result = await prisma.user.create({ data: { name, email, }, }); return result; } ); ``` 一体化调用: ``` import { signUp } from '../api/feeds'; signUp('John', 'test@test.com').then( (user) => { console.log(user); } ); ``` ### 更多示例[​](#更多示例 "更多示例的直接链接") 关于 Prisma 的更多示例,可以参考 [Prisma 官网文档](https://www.prisma.io/)。 --- # 静态类型安全 + 运行时安全 使用 [Prisma](/docs/3.0.0/hooks/prisma.md) 和 `@midwayjs/hooks` 提供的 [Validate](/docs/3.0.0/hooks/validate.md) 校验器,可以实现从前端到后端再到数据库的类型安全 + 运行时安全链路。 以 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/fullstack/prisma/README.md) 中的 `POST /api/post` 接口为例,代码如下: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { prisma } from './prisma'; import { z } from 'zod'; const PostSchema = z.object({ title: z.string().min(1), content: z.string().min(1), authorEmail: z.string().email(), }); export const createPost = Api( Post('/api/post'), Validate(PostSchema), async ( post: z.infer ) => { const result = await prisma.post.create({ data: { title: post.title, content: post.content, author: { connect: { email: post.authorEmail, }, }, }, }); return result; } ); ``` 前端调用: ``` import { createPost } from '../api/post'; await createPost({ title: 'Hello Midway', content: 'Hello Prisma', authorEmail: 'test@test.com', }); ``` 此时,前端基于 Zod 的 Schema 获取类型提示,后端则使用 `Validate` 校验器进行类型检查,最终调用 `prisma.post.create` 方法来创建用户。 整个过程中。 * 前端:基于类型,静态校验输入参数,并获取类型提示 * 后端:校验前端传入参数 * 数据库:使用正确的数据 通过这种方式,我们可以低成本的实现静态类型安全 + 运行时安全。 --- # 测试 在 Midway Hooks 中,我们可以快速的对 Http 接口进行测试。 ## 接口测试[​](#接口测试 "接口测试的直接链接") 此处以 Hello World 为例,我们在 `src/hello.ts` 中,导出了一个接口,代码如下。 ``` import { Api, Get } from '@midwayjs/hooks'; export default Api(Get('/hello'), async () => { return 'Hello World!'; }); ``` 在测试中,你可以通过 `@midwayjs/mock` 去启动应用,并调用接口完成测试。 ### 通过 `@midwayjs/hooks` 调用[​](#通过-midwayjshooks-调用 "通过-midwayjshooks-调用的直接链接") `@midwayjs/hooks` 提供了 `getApiTrigger(api: ApiFunction)` 方法,可以用于获取触发器。 以上面的 `hello` 接口为例,`getApiTrigger(hello)` 将返回: ``` { "type": "HTTP", "method": "GET", "path": "/hello" } ``` 在此,我们使用 `@midwayjs/mock` 提供的 `createHttpRequest` 方法来调用接口。`createHttpRequest` 的使用文档可以参考 [supertest](https://github.com/visionmedia/supertest)。 ``` // src/hello.test.ts import { close, createApp, createHttpRequest, } from '@midwayjs/mock'; import { Framework, IMidwayKoaApplication, } from '@midwayjs/koa'; import { getApiTrigger, HttpTriger } from '@midwayjs/hooks'; import hello from './hello'; describe('test koa with api router', () => { let app: IMidwayKoaApplication; beforeAll(async () => { app = await createApp(); }); afterAll(async () => { await close(app); }); test('Hello World', async () => { const trigger = getApiTrigger(hello); const response = await createHttpRequest(app) .get(trigger.path) .expect(200); expect(response.text).toBe('Hello World!'); }); }); ``` ### 手动调用[​](#手动调用 "手动调用的直接链接") 手动调用的情况下,需要填入 `Path` 等参数。 ``` test('Hello World', async () => { const response = await createHttpRequest(app) .get('/hello') .expect(200); expect(response.text).toBe('Hello World!'); }); ``` ### 请求参数 Data[​](#请求参数-data "请求参数 Data的直接链接") 后端代码: ``` import { Api, Post } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 测试代码: ``` test('Hello World', async () => { const trigger = getApiTrigger(say); const response = await createHttpRequest(app) .post(trigger.path) .send({ args: ['Midway'] }) .expect(200); expect(response.text).toBe('Hello Midway!'); }); ``` ### 查询参数 Query[​](#查询参数-query "查询参数 Query的直接链接") 后端代码: ``` import { Api, Get, Query, useContext, } from '@midwayjs/hooks'; export default Api( Get('/hello'), Query<{ name: string }>(), async () => { const ctx = useContext(); return `Hello ${ctx.query.name}!`; } ); ``` 测试代码: ``` test('Hello World', async () => { const trigger = getApiTrigger(hello); const response = await createHttpRequest(app) .get(trigger.path) .query({ name: 'Midway' }) .expect(200); expect(response.text).toBe('Hello Midway!'); }); ``` ### 路径参数 Params[​](#路径参数-params "路径参数 Params的直接链接") 后端代码: ``` import { Api, Get, Params, useContext } from '@midwayjs/hooks' export default Api( Get('/article/:id'), Params<{ id: string }>(, async () => { const ctx = useContext() return { article: ctx.params.id } } ) ``` 测试代码: ``` test('Get Article', async () => { const response = await createHttpRequest(app) .get('/article/1') .expect(200); expect(response.body).toEqual({ article: '1' }); }); ``` ### 请求头 Headers[​](#请求头-headers "请求头 Headers的直接链接") 后端代码: ``` import { Api, Get, Headers, useContext, } from '@midwayjs/hooks'; export default Api( Get('/auth'), Headers<{ token: string }>(), async () => { const ctx = useContext(); return { token: ctx.headers.token, }; } ); ``` 测试代码: ``` test('Auth', async () => { const response = await createHttpRequest(app) .get('/auth') .set('token', '123456') .expect(200); expect(response.body).toEqual({ token: '123456' }); }); ``` --- # 文件上传 Midway Hooks 提供了 `@midwayjs/hooks-upload` 并配合 `@midwayjs/upload` 来实现纯函数 + 一体化项目中的文件上传功能。 ## 起步[​](#起步 "起步的直接链接") 安装依赖: ``` npm install @midwayjs/upload @midwayjs/hooks-upload ``` ## 使用[​](#使用 "使用的直接链接") ### 启用 upload 组件[​](#启用-upload-组件 "启用 upload 组件的直接链接") 在后端目录的 `configuration.ts` 中启用 `@midwayjs/upload` 组件,具体支持的配置项可查看 [文件上传](/docs/extensions/upload.md) ``` import { createConfiguration, hooks } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; + import * as upload from '@midwayjs/upload'; /** * setup midway server */ export default createConfiguration({ imports: [ Koa, hooks(), + upload ], importConfigs: [{ default: { keys: 'session_keys' } }], }); ``` ### 创建接口[​](#创建接口 "创建接口的直接链接") 在后端目录下,新建接口文件。 ``` import { Api } from '@midwayjs/hooks'; import { Upload, useFiles, } from '@midwayjs/hooks-upload'; export default Api( Upload('/api/upload'), async () => { const files = useFiles(); return files; } ); ``` > 一体化调用 ``` import upload from './api/upload'; function Form() { const [file, setFile] = React.useState(null); const handleSubmit = async ( e: React.FormEvent ) => { e.preventDefault(); const files = { images: file }; const response = await upload({ files, }); console.log(response); }; const handleOnChange = ( e: React.ChangeEvent ) => { console.log(e.target.files); setFile(e.target.files); }; return (

Hooks File Upload

); } ``` > 手动调用(通过 FormData 上传) ``` const input = document.getElementById('file'); const formdata = new FormData(); formdata.append('file', input.files[0]); fetch('/api/upload', { method: 'POST', body: formdata, }) .then((res) => res.json()) .then((res) => console.log(res)); ``` ## Api[​](#api "Api的直接链接") ### Upload(path?: string)[​](#uploadpath-string "Upload(path?: string)的直接链接") 声明上传接口,可以指定路径。默认为 `POST` 接口,只支持 `multipart/form-data` 类型的请求。 ### useFiles()[​](#usefiles "useFiles()的直接链接") 在函数中使用 `useFiles()` 可以获取上传的文件。返回值为 Object,key 为上传时的字段名。有多个文件字段名相同时,Value 为 Array。 ``` // frontend await upload({ pdf }); // backend const files = useFiles(); { pdf: { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // mode 为 file 时为服务器临时文件地址 fieldname: 'test1', // 表单 field 名 mimeType: 'application/pdf', // mime } } ``` ### useFields()[​](#usefields "useFields()的直接链接") 返回 FormData 中非文件的字段。 ``` // frontend const formdata = new FormData(); formdata.append('name', 'test'); post(formdata); // backend const fields = useFields(); // { name: 'test' } ``` --- # 参数校验 ## 校验[​](#校验 "校验的直接链接") Midway Hooks 使用 [zod@3](https://www.npmjs.com/package/zod) 作为校验器,并提供 `Validate(...schemas: any[])` 校验用户入参,`ValidateHttp(options)` 函数来校验 Http 结构。 使用前请安装 [zod](https://www.npmjs.com/package/zod)。 ``` npm install zod ``` ## Validate[​](#validate "Validate的直接链接") `Validate` 传入的 Schema 顺序与用户入参顺序匹配。 ### 基础示例[​](#�基础示例 "基础示例的直接链接") ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; export default Api( Post('/hello'), Validate(z.string(), z.number()), async (name: string, age: number) => { return `Hello ${name}, you are ${age} years old.`; } ); ``` 一体化调用: ``` import hello from './api'; try { await hello(null, null); } catch (error) { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .post('/hello', { args: [null, null], }) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` ### 错误处理[​](#错误处理 "错误处理的直接链接") 通过 Try/Catch 可以捕捉到校验失败的错误。 ``` try { // 调用接口 } catch (error) { console.log(error.data.code); // VALIDATION_FAILED console.log( JSON.parse(error.data.message) ); } ``` `error.data.message` 包含完整的[错误信息](https://zod.js.org/docs/errors/),你需要使用 `JSON.parse` 解析,解析后的示例如下: ``` [ { code: 'invalid_type', expected: 'string', received: 'number', path: [0, 'name'], message: 'Expected string, received number', }, ]; ``` 其中: * `message`: 错误信息 * `path` 参数代表错误路径,如 `0` 代表第一个参数校验出错,`name` 代表是 `name` 字段校验出错。 你可以手动解析错误消息,并展示给用户。 ### ValidateHttp[​](#validatehttp "ValidateHttp的直接链接") ValidateHttp(options) 支持传入 `options` 参数,类型如下。 ``` type ValidateHttpOption = { query?: z.Schema; params?: z.Schema; headers?: z.Schema; data?: z.Schema[]; }; ``` 以校验 `Query` 参数为例。 后端代码: ``` import { Api, Get, Query, useContext, ValidateHttp, } from '@midwayjs/hooks'; import { z } from 'zod'; const QuerySchema = z.object({ searchString: z.string().min(5), }); export const filterPosts = Api( Get('/api/filterPosts'), Query>(), ValidateHttp({ query: QuerySchema }), async () => { const ctx = useContext(); return ctx.query.searchString; } ); ``` 一体化调用: ``` import filterPosts from './api'; try { await filterPosts({ query: { searchString: '' }, }); } catch (error) { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .get( '/api/filterPosts?searchString=1' ) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` ## TypeScript 支持[​](#typescript-支持 "TypeScript 支持的直接链接") 你可以通过 zod 内置的 TypeScript 功能,来实现复杂类型的推导与校验。 示例如下: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; const Project = z.object({ name: z.string(), description: z.string(), owner: z.string(), members: z.array(z.string()), }); export default Api( Post('/project'), Validate(Project), async ( // { name: string, description: string, owner: string, members: string[] } project: z.infer ) => { return project; } ); ``` 一体化调用: ``` import createProject from './api'; try { await createProject({ name: 1, description: 'test project', owner: 'test', members: ['test'], }); } catch (error) { console.log(error.message); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .post('/project', { args: [ { name: 1, description: 'test project', owner: 'test', members: ['test'], }, ], }) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` --- # 如何安装 Node.js 环境 ## 使用场景[​](#使用场景 "使用场景的直接链接") 一般来说,直接从 [Node.js 官网](https://nodejs.org/)下载对应的安装包,即可完成环境配置。 但在**本地开发**的时候,经常需要快速更新或切换版本。 社区有 [nvm](https://github.com/creationix/nvm)、[n](https://github.com/tj/n) 等方案,我们推荐跨平台的 [nvs](https://github.com/jasongin/nvs)。 * nvs 是跨平台的。 * nvs 是基于 Node 编写的,我们可以参与维护。 > 友情提示:Node 12.x 和 14.x 分别于2022和2023年4月结束生命期(EOL),请尽快升级到 16 或者 18 。 **PS:nvs 我们一般只用于本地开发,线上参见:**[科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) *** ## 如何安装[​](#如何安装 "如何安装的直接链接") ### Linux / macOS 环境[​](#linux--macos-环境 "Linux / macOS 环境的直接链接") 通过 Git Clone 对应的项目即可。 ``` $ export NVS_HOME="$HOME/.nvs" $ git clone https://github.com/jasongin/nvs --depth=1 "$NVS_HOME" $ . "$NVS_HOME/nvs.sh" install ``` ### Windows 环境[​](#windows-环境 "Windows 环境的直接链接") 由于 Windows 环境配置比较复杂,所以还是推荐使用 `msi` 文件完成初始化工作。 访问 [nvs/releases](https://github.com/jasongin/nvs/releases) 下载最新版本的 `nvs.msi`,然后双击安装即可。 *** ## 配置镜像地址[​](#配置镜像地址 "配置镜像地址的直接链接") 在国内由于大家都懂的原因,需要把对应的镜像地址修改下: ``` $ nvs remote node https://npmmirror.com/mirrors/node/ $ nvs remote default node chakracore https://github.com/nodejs/node-chakracore/releases/ chakracore-nightly https://nodejs.org/download/chakracore-nightly/ nightly https://nodejs.org/download/nightly/ node https://nodejs.org/dist/ ``` *** ## 使用指南[​](#使用指南 "使用指南的直接链接") 通过以下命令,即可非常简单的安装 Node.js 最新的 LTS 版本。 ``` # 安装最新的 LTS 版本 $ nvs add lts # 配置为默认版本 $ nvs link lts ``` 安装其他版本: ``` # 安装其他版本尝尝鲜 $ nvs add 12 # 查看已安装的版本 $ nvs ls # 在当前 Shell 切换版本 $ nvs use 12 ``` 更多指令参见 `nvs --help` 。 *** ## 共用 npm 全局模块[​](#共用-npm-全局模块 "共用 npm 全局模块的直接链接") 使用 `nvs` 时,默认的 `prefix` 是当前激活的 Node.js 版本的安装路径。 带来一个问题是:切换版本之后,之前安装全局命令模块需要重新安装,非常不方便。 解决方案是配置统一的全局模块安装路径到 `~/.npm-global`,如下: ``` $ mkdir -p ~/.npm-global $ npm config set prefix ~/.npm-global ``` 还需配置环境变量到 `~/.bashrc` 或 `~/.zshrc` 文件里面: ``` $ echo "export PATH=~/.npm-global/bin:$PATH" >> ~/.zshrc $ source ~/.zshrc ``` *** ## Mac Silicon 芯片使用低版本 Node.js[​](#mac-silicon-芯片使用低版本-nodejs "Mac Silicon 芯片使用低版本 Node.js的直接链接") 如果你使用的是 Apple 芯片,由于 Node.js 16 以下没有 arm64 的芯片支持构建版本,所以没法直接安装。 幸运的是,有一些解决方法可以使 Node.js 14与 Mac Silicon一起使用。Apple提供了Rosetta,这是一款翻译应用程序,允许为Intel芯片 (或上一代Mac) 构建的应用程序在 Apple Silicon下运行。 有两个步骤: * 1、安装 Rosetta * 2、切换到 intel 环境,安装低版本 Node.js **安装 Rosetta** 打开终端,执行 ``` $ /usr/sbin/softwareupdate --install-rosetta --agree-to-license ``` **切换环境,安装低版本 Node.js** * 1、打开终端,执行 `arch` ,确认运行的是 `arm64` * 2、执行 `arch -x86_64 zsh`,开启新的终端 * 3、执行 `arch` ,确认运行的是 `i386` * 4、安装低版本 Node.js,你可以使用上面提到的 nvs 或者 nvm 来安装 ## 相关阅读[​](#相关阅读 "相关阅读的直接链接") * [科普文:Node.js 安全攻防 - 如何伪造和获取用户真实 IP ?](https://zhuanlan.zhihu.com/p/62265144) * [科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) * [科普文:为什么不能在服务器上 npm install ?](https://zhuanlan.zhihu.com/p/39209596) * [Using NodeJs 14 with Mac Silicon (M1)](https://devzilla.io/using-nodejs-14-with-mac-silicon-m1) --- # 如何更新 Midway ## 什么时候要更新 Midway[​](#什么时候要更新-midway "什么时候要更新 Midway的直接链接") 一般来说,在下面的情况下,你可能需要更新: * 1、Midway 发了新版本之后,你希望用到新功能的时候 * 2、你安装了一个新的组件且带有 lock 文件的时候 * 3、出现方法找不到的错误的时候 * ... 等等 比如出现下面错误的时候 1、一般是装了组件的新包,但是老的 @midwayjs/core 未包含该方法从而报错。 ![](https://img.alicdn.com/imgextra/i3/O1CN01dDNRZr1MBPewPo7Xg_!!6000000001396-2-tps-1196-317.png) 2、一般原因为 mock 依赖的 @midwayjs/core 版本没这个方法,说明版本不对,可能是错误引用了版本,也可能是版本太低 ![](https://img.alicdn.com/imgextra/i3/O1CN01HVMJKP1xNuFO2Wv73_!!6000000006432-2-tps-1055-135.png) 3、新装组件的时候,我们发现某个包的版本实例不止一个 ![](https://img.alicdn.com/imgextra/i3/O1CN01jZxQu91YBCs0N9S9Y_!!6000000003020-2-tps-1133-43.png) ## 更新注意事项[​](#更新注意事项 "更新注意事项的直接链接") 危险 midway 项目的依赖使用 lerna 发布,**请不要**: * 1、单独升级某个 @midwayjs/\* 的包 * 2、将 package.json 中的版本号移除 ^ 符号 ## 检查包版本异常[​](#检查包版本异常 "检查包版本异常的直接链接") 你可以使用下面的命令在项目根目录执行进行检查。 ``` # 社区用户 $ npx midway-version # 内部用户 $ tnpx @ali/midway-version ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version # 内部用户 $ pnpx @ali/midway-version ``` ## 使用工具更新版本[​](#使用工具更新版本 "使用工具更新版本的直接链接") 你可以使用下面的命令在项目根目录执行进行更新提示。 ``` # 社区用户 $ npx midway-version -u # 内部用户 $ tnpx @ali/midway-version -u ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version -u # 内部用户 $ pnpx @ali/midway-version -u ``` 如果你希望将更新写入到 `package.json` 中,请使用下面的命令。 ``` # 社区用户 $ npx midway-version -u -w # 内部用户 $ tnpx @ali/midway-version -u -w ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version -u -w # 内部用户 $ pnpx @ali/midway-version -u -w ``` 提示 更新的版本会写入 `package.json` 和 `package-lock.json`,并需要重新安装依赖。 ## 手动更新版本[​](#手动更新版本 "手动更新版本的直接链接") ### 普通项目更新[​](#普通项目更新 "普通项目更新的直接链接") 普通使用 npm/yarn 的项目,升级请按照下面的流程 * 1、删除 package-lock.json 或者 yarn.lock * 2、彻底删除 node\_modules(比如 rm -rf node\_modules) * 3、重新安装依赖( npm install 或者 yarn) **我们不保证使用其他工具、cli 单独升级包的效果。** ### lerna 项目更新[​](#lerna-项目更新 "lerna 项目更新的直接链接") 使用 lerna 开发项目,由于有 hoist 模式的存在,升级请按照下面的流程(以 lerna3 为例) * 1、清理子包的 node\_modules,比如(lerna clean --yes) * 2、删除主包的 node\_modules(比如 rm -rf node\_modules) * 3、删除 package-lock.json 或者 yarn.lock * 4、重新安装依赖( npm install && lerna bootstrap) **我们不保证使用其他工具、cli 单独升级包的效果。** ## 大版本更新[​](#大版本更新 "大版本更新的直接链接") 请手动修改版本号,比如从 `^1.0.0` 修改为 `^2.0.0` 。 ## 查看当前包版本[​](#查看当前包版本 "查看当前包版本的直接链接") Midway 包采用标准的 Semver 版本进行管理和发布,在 `package.json` 指定的版本一般为 `^` 开头,表示在大版本范围内都兼容。 比如,`package.json` 中 `@midwayjs/core` 为 `^2.3.0` ,那么按照 npm 安装规则,会安装 `2.x` 这个版本下最新的 latest 版本。 所以实际安装的版本高于 `package.json` 中指定的版本都是正常的。 你可以使用 `npm ls 包名` 来查看具体的版本,比如 `npm ls @midwayjs/core` 来查看 `@midwayjs/core` 的版本。 ## 版本匹配查询[​](#版本匹配查询 "版本匹配查询的直接链接") 由于 lerna 发包有一定的依赖性,比如修改到的包才会更新,就会出现 **midway 下的包版本不一定完全一致的情况。** 比如,`@midwayjs/web` 的版本高于 `@midwayjs/core`,这都是很正常的。 midway 每次发布会提交一个 [@midwayjs/version ](https://www.npmjs.com/package/@midwayjs/version)的包,其中包含了我们每个版本,以及该版本的包所匹配的全部包版本,请 [访问这里](https://github.com/midwayjs/midway/tree/2.x/packages/version/versions) 查看。 目录中的文件名按照 `@midwayjs/decorator版本 - @midwayjs/core版本.json` 规则创建,每个版本对应一个 JSON 文件。 文件内容以包名作为 key,以可兼容匹配的版本名作为值。 比如,当前文件 decorator(v2.10.18)和 core(v2.10.18) 所能兼容的 egg-layer 包版本为 v2.10.18 和 v2.10.19。 如果 decorator 和 core 组合的文件名未找到,或者文件里的版本不匹配,都说明 **版本可能产生了问题**。 内容示例如下: ``` { "@midwayjs/egg-layer": [ "2.10.18", "2.10.19" ], "@midwayjs/express-layer": "2.10.18", "@midwayjs/faas-typings": "2.10.7", "@midwayjs/koa-layer": "2.10.18", "@midwayjs/runtime-engine": "2.10.14", "@midwayjs/runtime-mock": "2.10.14", "@midwayjs/serverless-app": "2.10.18", "@midwayjs/serverless-aws-starter": "2.10.14", "@midwayjs/serverless-fc-starter": "2.10.18", "@midwayjs/serverless-fc-trigger": "2.10.18", "@midwayjs/serverless-http-parser": "2.10.7", "@midwayjs/serverless-scf-starter": "2.10.14", "@midwayjs/serverless-scf-trigger": "2.10.18", "@midwayjs/static-layer": "2.10.18", "@midwayjs/bootstrap": "2.10.18", "@midwayjs/cache": "2.10.18", "@midwayjs/consul": "2.10.18", "@midwayjs/core": "2.10.18", "@midwayjs/decorator": "2.10.18", "@midwayjs/faas": "2.10.18", "@midwayjs/grpc": "2.10.18", "@midwayjs/logger": "2.10.18", "midway-schedule": "2.10.18", "midway": [ "2.10.18", "2.10.19" ], "@midwayjs/mock": "2.10.18", "@midwayjs/prometheus": "2.10.18", "@midwayjs/rabbitmq": "2.10.18", "@midwayjs/socketio": "2.10.18", "@midwayjs/task": [ "2.10.18", "2.10.19" ], "@midwayjs/typegoose": "2.10.18", "@midwayjs/version": [ "2.10.18", "2.10.19" ], "@midwayjs/express": "2.10.18", "@midwayjs/koa": "2.10.18", "@midwayjs/web": [ "2.10.18", "2.10.19" ] } ``` --- # 介绍 Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 Midway 基于 TypeScript 开发,结合了`面向对象(OOP + Class + IoC)`与`函数式(FP + Function + Hooks)`两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验。 ## 为什么要有 Midway[​](#为什么要有-midway "为什么要有 Midway的直接链接") 社区上也有很多类似的框架,那为什么还需要 Midway ? 原因有三点: 1. Midway 是阿里内部一直持续在研发的框架,需要有面向应用层面的框架来和集团场景对接 2. 全量使用 TypeScript 是未来一段时间的趋势,面向未来去迭代和研发是作为架构组创新的要求 3. 虽然社区已经有 nest 这样的框架,但是这些产品的维护、协作、修改都会受到商业化产品的制约,也无法做到需求的快速迭代和安全性保障,整体的研发理念也和我们不同,为此,我们需要有一套自研的框架体系 ## 我们的优势[​](#我们的优势 "我们的优势的直接链接") 1. Midway 框架是在内部已经使用 5 年以上的 Node.js 框架,有着长期投入和持续维护的团队做后盾 2. 已经在每年的大促场景经过考验,稳定性无须担心 3. 丰富的组件和扩展能力,例如数据库,缓存,定时任务,进程模型,部署以及 Web,Socket 甚至 Serverless 等新场景的支持 4. 一体化调用方案可以方便快捷和前端页面协同开发 5. 良好的 TypeScript 定义支持 6. 国产化文档和沟通容易简单 ## 多编程范式[​](#多编程范式 "多编程范式的直接链接") Midway 支持面向对象与函数式两种编程范式,你可以根据实际研发的需要,选择不同的编程范式来开发应用。 ### 面向对象(OOP + Class + IoC)[​](#面向对象oop--class--ioc "面向对象(OOP + Class + IoC)的直接链接") Midway 支持面向对象的编程范式,为应用提供更优雅的架构。 下面是基于面向对象,开发路由的示例。 ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context @Get('/') async home() { return { message: 'Hello Midwayjs!', query: this.ctx.ip } } } ``` ### 函数式(FP + Function + Hooks)[​](#函数式fp--function--hooks "函数式(FP + Function + Hooks)的直接链接") Midway 也支持函数式的编程范式,为应用提供更高的研发效率。 下面是基于函数式,开发路由接口的示例。 ``` // src/api/index.ts import { useContext } from '@midwayjs/hooks' import { Context } from '@midwayjs/koa'; export default async function home () { const ctx = useContext() return { message: 'Hello Midwayjs!', query: ctx.ip } } ``` ## 环境准备工作[​](#环境准备工作 "环境准备工作的直接链接") Midway 运行请预先安装 Node.js 环境和 npm,在国内可以使用 cnpm。 * 操作系统:支持 macOS,Linux,Windows * 运行环境:建议选择 [LTS 版本](http://nodejs.org/),最低要求 **12.11.0**。 在经过不断迭代之后,Midway 的版本要求如下: | Midway 版本 | 开发环境 Node.js 版本要求 | 部署环境 Node.js 版本要求 | | -------------- | ------------------------- | ------------------------- | | >=v3.9.0 | >= v14,推荐 LTS 版本 | >= v12.11.0 | | 3.0.0 \~ 3.9.0 | >= v12,推荐 LTS 版本 | >= v12.0.0 | | 2.x | >= v12,推荐 LTS 版本 | >= v10.0.0 | 如果需要帮助,请参考 [如何安装 Node.js 环境](/docs/3.0.0/how_to_install_nodejs.md)。 ## 正确的提问[​](#正确的提问 "正确的提问的直接链接") * ✅ 在 [github issue](https://github.com/midwayjs/midway/issues) 提问,可追踪,可沉淀,可 Star * 1、描述你的问题,提供尽可能详细的复现方法,框架版本,场景(Serverless 还是应用) * 2、尽可能提供报错截图,堆栈信息,最小复现的 repo ## 答疑分享群[​](#答疑分享群 "答疑分享群的直接链接") 群里会有热心的朋友,也会有新版本发布推送。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01LyI8r91S91RsKsD29_!!6000000002203-0-tps-3916-2480.jpg) ## 官方宣传渠道[​](#官方宣传渠道 "官方宣传渠道的直接链接") * [哔哩哔哩](https://space.bilibili.com/1746017680),会提供更新信息和教程 --- # MongoDB 提示 本文档从 v3.4.0 版本起废弃。 在这一章节中,我们选择 [Typegoose](https://github.com/typegoose/typegoose) 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 简单的来说,Typegoose 使用 TypeScript 编写 Mongoose 模型的 “包装器”,它的大部分能力还是由 [mongoose](https://www.npmjs.com/package/mongoose) 库来提供的。 也可以直接选择 [mongoose](https://www.npmjs.com/package/mongoose) 库来使用,我们会分别描述。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## Mongoose 版本依赖[​](#mongoose-版本依赖 "Mongoose ��版本依赖的直接链接") mongoose 和你服务器使用的 MongoDB Server 的版本也有着一定的关系,如下,请务必注意。 * MongoDB Server 2.4.x: mongoose ^3.8 or 4.x * MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x * MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x * MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x * MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x * MongoDB Server 3.6.x: mongoose 5.x * MongoDB Server 4.0.x: mongoose ^5.2.0 * MongoDB Server 4.2.x: mongoose ^5.7.0 * MongoDB Server 4.4.x: mongoose ^5.10.0 * MongoDB Server 5.x: mongoose ^6.0.0 **mongoose 相关的依赖比较复杂,且对应不同的版本,现阶段,我们使用的主要是 mongoose v5 和 v6。** 信息 从 mongoose\@v5.11.0 开始,mongoose 官方支持了定义,所以不再需要安装 @types/mongoose 依赖包。 安装包依赖版本如下: **支持 MongoDB Server 5.x** ``` "dependencies": { "mongoose": "^6.0.7", "@typegoose/typegoose": "^9.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 4.4.x** 以下版本不需要安装额外定义包。 ``` "dependencies": { "mongoose": "^5.13.3", "@typegoose/typegoose": "^8.0.0", // 使用 typegoose 需要安装此依赖 }, ``` 以下版本需要安装额外定义包(不推荐)。 ``` "dependencies": { "mongodb": "3.6.3", // mongoose 内部写死了该版本 "mongoose": "~5.10.18", "@typegoose/typegoose": "^7.0.0", // 使用 typegoose 需要安装此依赖 }, "devDependencies": { "@types/mongodb": "3.6.3", // 只能使用此版本 "@types/mongoose": "~5.10.3", } ``` 其余的 MongoDB 安装模块类似,未测。 ## 使用 Typegoose[​](#使用-typegoose "使用 Typegoose的直接链接") ### 1、安装组件[​](#1安装组件 "1、安装组件的直接链接") 安装 Typegoose 组件,提供访问 MongoDB 的能力。 **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/typegoose@3 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/typegoose": "^3.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; @Configuration({ imports: [ typegoose // 加载 typegoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` 信息 在该组件中,midway 只是做了简单的配置规则化,并将其注入到初始化流程中。 ### 2、配置连接信息[​](#2配置连接信息 "2、配置连接信息的直接链接") 在 `src/config/config.default.ts` 中加入连接的配置。 ``` export default { // ... mongoose: { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } }, } ``` ### 3、简单的目录结构[​](#3简单的目录结构 "3、简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── user.ts // 实体文件 │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ### 3、创建实体文件[​](#3创建实体文件 "3、创建实体文件的直接链接") ``` import { prop } from '@typegoose/typegoose'; import { EntityModel } from '@midwayjs/typegoose'; @EntityModel() export class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 等价于使用 mongoose 的下列代码 ``` const userSchema = new mongoose.Schema({ name: String, jobs: [{ type: String }] }); const User = mongoose.model('User', userSchema); ``` 信息 所以说,typegoose 只是简化了 model 的创建过程。 ### 4、引用实体,调用数据库[​](#4引用实体调用数据库 "4、引用实体,调用数据库的直接链接") 示例代码如下: ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typegoose'; import { ReturnModelType } from '@typegoose/typegoose'; import { User } from '../entity/user'; @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; async getTest(){ // create data const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties // find data const user = await this.userModel.findById(id).exec(); console.log(user) } } ``` ### 5、多库的情况[​](#5多库的情况 "5、多库的情况的直接链接") 首先配置多个连接。 在 `src/config/config.default.ts` 中加入连接的配置,`default` 代表了默认的连接。 ``` export default { // ... mongoose: { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` 定义实例时使用固定的连接,比如: ``` @EntityModel() // 默认使用了 default 连接 class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } @EntityModel({ connectionName: 'db1' // 这里使用了 db1连接 }) class User2 { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 在使用时,注入特定的连接 ``` @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; @InjectEntityModel(User2) user2Model: ReturnModelType; async getTest(){ const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties const user = await this.userModel.findById(id).exec(); console.log(user) const { _id: id2 } = await this.user2Model.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User2); // an "as" assertion, to have types for all properties const user2 = await this.user2Model.findById(id2).exec(); console.log(user2) } } ``` ## 直接使用 mongoose[​](#直接使用-mongoose "直接使用 mongoose的直接链接") mongoose 组件是 typegoose 的基础组件,有时候我们可以直接使用它。 ### 1、安装组件[​](#1安装组件-1 "1、安装组件的直接链接") **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/mongoose --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/mongoose": "^3.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` ### 2、开启组件[​](#2开启组件 "2、开启组件的直接链接") 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mongoose from '@midwayjs/mongoose'; @Configuration({ imports: [ mongoose // 加载 mongoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ### 2、配置[​](#2配置 "2、配置的直接链接") 和 typegoose 相同,或者说 typegoose 使用的就是 mongoose 的配置。 单库: ``` export default { // ... mongoose: { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '**********' } } }, } ``` 多库: ``` export default { // ... mongoose: { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` ### 3、使用[​](#3使用 "3、使用的直接链接") 在只有一个默认连接或者直接使用 default 连接时,我们可以直接使用封装好的 `MongooseConnectionService` 对象来创建 model。 ``` import { Provide, Inject } from '@midwayjs/core'; import { MongooseConnectionService } from '@midwayjs/mongoose'; import { Schema, Document } from 'mongoose'; interface User extends Document { name: string; email: string; avatar: string; } @Provide() export class TestService { @Inject() conn: MongooseConnectionService; async invoke(){ const schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, avatar: String }); const UserModel = this.conn.model('User', schema); const doc = new UserModel({ name: 'Bill', email: 'bill@initech.com', avatar: 'https://i.imgur.com/dM7Thhn.png' }); await doc.save(); } } ``` 如果配置了多个其他连接,请从工厂方法中获取连接后再使用。 ``` import { MongooseConnectionServiceFactory } from '@midwayjs/mongoose'; import { Schema } from 'mongoose'; @Provide() export class TestService { @Inject() connFactory: MongooseConnectionServiceFactory; async invoke(){ // get db1 connection const conn = this.connFactory.get('db1'); // get default connection const defaultConn = this.connFactory.get('default'); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、E002: You are using a NodeJS Version below 12.22.0[​](#1e002-you-are-using-a-nodejs-version-below-12220 "1、E002: You are using a NodeJS Version below 12.22.0的直接链接") 在新版本 @typegoose/typegoose (v8, v9) 中增加了 Node 版本的校验,如果你的 Node.js 版本低于 v12.22.0,就会出现这个提示。 普通情况下,请升级 Node.js 到这个版本以上即可解决。 在特殊场景下,比如 Serverless 无法修改 Node.js 版本且版本低于 v12.22 的情况下,由于 v12 版本子版本其实都可以,可以通过临时修改 process.version 绕过。 ``` // src/configuration.ts Object.defineProperty(process, 'version', { value: 'v12.22.0', writable: true, }); // other code export class MainConfiguration {} ``` --- # TypeORM 提示 本文档从 v3.4.0 版本起废弃。 [TypeORM](https://github.com/typeorm/typeorm) 是 `node.js` 现有社区最成熟的对象关系映射器(`ORM` )。Midway 和 TypeORM 搭配,使开发更简单。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 orm 组件,提供数据库 ORM 能力。 ``` $ npm i @midwayjs/orm@3 typeorm --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/orm": "^3.0.0", "typeorm": "~0.3.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 orm 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as orm from '@midwayjs/orm'; import { join } from 'path'; @Configuration({ imports: [ // ... orm // 加载 orm 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class ContainerConfiguratin { } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 信息 To make the\*\* Oracle driver work\*\*, you need to follow the installation instructions from [their](https://github.com/oracle/node-oracledb) site. ## 简单的目录结构[​](#简单的目录结构 "简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── photo.ts // 实体文件 │ │ └── photoMetadata.ts │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ## 入门[​](#入门 "入门的直接链接") 下面,我们将以 mysql 举例。 ### 1、创建 Model[​](#1创建-model "1、创建 Model的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `photo` 举例。新建 entity 目录,在其中添加实体文件 `photo.ts` ,一个简单的实体如下。 ``` // entity/photo.ts export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 ### 2、添加实体模型装饰器[​](#2添加实体模型装饰器 "2、添加实体模型装饰器的直接链接") 我们使用 `EntityModel` 来定义一个实体模型类。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 警告 注意,这里的 EntityModel 是 midway 做了封装的特殊装饰器,为了和 midway 更好的结合使用。请不要直接使用 typeorm 中的 Entity。 如果表名和当前的实体名不同,可以在参数中指定。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo_table_name') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 这些实体列也可以使用 [typeorm\_generator](/docs/tool/typeorm_generator.md) 工具生成。 ### 3、添加数据库列[​](#3添加数据库列 "3、添加数据库列的直接链接") 通过 typeorm 提供的 `@Column` 装饰器来修饰属性,每一个属性对应一个列。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column } from 'typeorm'; @EntityModel() export class Photo { @Column() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` 现在 `id` , `name` , `description` ,`filename` , `views` , `isPublished` 列将添加到 `photo` 表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 `@Column`装饰器中显式指定列类型来使用数据库支持的任何列类型。 我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。 数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 [官方文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/entities.md#%E5%88%97%E9%80%89%E9%A1%B9)。 ### 4、创建主键列[​](#4创建主键列 "4、创建主键列的直接链接") 每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 `@PrimaryColumn` 装饰器。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 5、创建自增主键列[​](#5创建自增主键列 "5、创建自增主键列的直接链接") 现在,如果要设置自增的 id 列,需要将 `@PrimaryColumn` 装饰器更改为 `@PrimaryGeneratedColumn` 装饰器: ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 6、列数据类型[​](#6列数据类型 "6、列数据类型的直接链接") 接下来,让我们调整数据类型。默认情况下,字符串映射到类似 `varchar(255)` 的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column({ length: 100 }) name: string; @Column('text') description: string; @Column() filename: string; @Column("double") views: number; @Column() isPublished: boolean; } ``` 示例,不同列名 ``` @Column({ length: 100, name: 'custom_name' }) name: string; ``` 此外还有有几种特殊的列类型可以使用: * `@CreateDateColumn` 是一个特殊列,自动为实体插入日期。 * `@UpdateDateColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。 * `@VersionColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。 * `@DeleteDateColumn` 是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。 列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](https://github.com/typeorm/typeorm/blob/master/docs/entities.md#column-types)。 提示 `CreateDateColumn` 和 `UpdateDateColumn` 是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。 ### 7、配置连接信息[​](#7配置连接信息 "7、配置连接信息的直接链接") 请参考 [配置](/docs/env_config.md) 章节,增加配置文件。 然后在 `config.default.ts` 中配置数据库连接信息。 ``` // src/config/config.default.ts export default { // ... orm: { /** * 单数据库实例 */ type: 'mysql', host: '', port: 3306, username: '', password: '', database: undefined, synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true logging: false, }, } ``` 默认存储的是 utc 时间(推荐)。 也可以配置时区(不建议) ``` // src/config/config.default.ts export default { // ... orm: { // ... timezone: '+08:00', }, } ``` 这个 `type` 字段你可以使用其他的数据库类型,包括`mysql`, `mariadb`, `postgres`, `cockroachdb`, `sqlite`, `mssql`, `oracle`, `cordova`, `nativescript`, `react-native`, `expo`, or `mongodb` 比如 sqlite,则只需要以下信息。 ``` // src/config/config.default.ts export default { // ... orm: { type: 'sqlite', database: path.join(__dirname, '../../test.sqlite'), synchronize: true, logging: true, }, } ``` 信息 注意:synchronize 字段用于同步表结构。使用 `synchronize: true` 进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。 ### 8、使用 Model 插入数据库数据[​](#8使用-model-插入数据库数据 "8、使用 Model 插入数据库数据的直接链接") 在常见的 Midway 文件中,使用 `@InjectEntityModel` 装饰器注入我们配置好的 Model。我们所需要做的只是: * 1、创建实体对象 * 2、执行 `save()` ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // save async savePhoto() { // create a entity object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // save entity const photoResult = await this.photoModel.save(photo); // save success console.log('photo id = ', photoResult.id); } } ``` ### 9、查询数据[​](#9查询数据 "9、查询数据的直接链接") 更多的查询参数,请查询 [find文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/find-options.md)。 自 typeorm\@0.3.0 起,查询 API 有所变化。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhotos() { // find All let allPhotos = await this.photoModel.find(); // v0.2.x let allPhotos = await this.photoModel.find({}); // v0.3.x console.log("All photos from the db: ", allPhotos); // find first let firstPhoto = await this.photoModel.findOne(1); let firstPhoto = await this.photoModel.findOne({ // v0.3.x where: { id: 1 } }); console.log("First photo from the db: ", firstPhoto); // find one by name // v0.2.x let meAndBearsPhoto = await this.photoModel.findOne({ name: "Me and Bears" }); // v0.3.x let meAndBearsPhoto = await this.photoModel.findOne({ where: { name: "Me and Bears" } }); console.log("Me and Bears photo from the db: ", meAndBearsPhoto); // find by views // v0.2.x let allViewedPhotos = await this.photoModel.find({ views: 1 }); // v0.3.x let allViewedPhotos = await this.photoModel.find({ where: { views: 1 } }); console.log("All viewed photos: ", allViewedPhotos); // v0.2.x let allPublishedPhotos = await this.photoModel.find({ isPublished: true }); // v0.3.x let allPublishedPhotos = await this.photoModel.find({ where: { isPublished: true } }); console.log("All published photos: ", allPublishedPhotos); // find and get count // v0.2.x let [allPhotos, photosCount] = await this.photoModel.findAndCount(); // v0.3.x let [allPhotos, photosCount] = await this.photoModel.findAndCount({}); console.log("All photos: ", allPhotos); console.log("Photos count: ", photosCount); } } ``` ### 10、更新数据库[​](#10更新数据库 "10、更新数据库的直接链接") 现在,让我们从数据库中加载一个 Photo,对其进行更新并保存。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { let photoToUpdate = await this.photoModel.findOne(1); photoToUpdate.name = "Me, my friends and polar bears"; await this.photoModel.save(photoToUpdate); } } ``` ### 11、删除数据[​](#11删除数据 "11、删除数据的直接链接") ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { /*...*/ let photoToRemove = await this.photoModel.findOne(1); // typeorm@0.2.x await this.photoModel.remove(photoToRemove); } } ``` 现在,ID = 1的 Photo 将从数据库中删除。 此外还有软删除的方法。 ``` await this.photoModel.softDelete(1); ``` ### 12、创建一对一关联[​](#12创建一对一关联 "12、创建一对一关联的直接链接") 让我们与另一个类创建一对一的关系。让我们在 `entity/photoMetadata.ts` 中创建一个新类。这个类包含 photo 的其他元信息。 ``` import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { EntityModel } from '@midwayjs/orm'; import { Photo } from "./photo"; @EntityModel() export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column("int") height: number; @Column("int") width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string; @OneToOne(type => Photo) @JoinColumn() photo: Photo; } ``` 在这里,我们使用一个名为 `@OneToOne` 的新装饰器。它允许我们在两个实体之间创建一对一的关系。`type => Photo`是一个函数,它返回我们要与其建立关系的实体的类。 由于语言的特殊性,我们被迫使用一个返回类的函数,而不是直接使用该类。我们也可以将其写为 `() => Photo` ,但是我们使用 `type => Photo`作为惯例来提高代码的可读性。类型变量本身不包含任何内容。 我们还添加了一个 `@JoinColumn`装饰器,它指示关系的这一侧将拥有该关系。关系可以是单向或双向的。关系只有一方可以拥有。关系的所有者端需要使用@JoinColumn装饰器。 如果您运行该应用程序,则会看到一个新生成的表,该表将包含一列,其中包含用于 Photo 关系的外键。 ``` +-------------+--------------+----------------------------+ | photo_metadata | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | height | int(11) | | | width | int(11) | | | comment | varchar(255) | | | compressed | boolean | | | orientation | varchar(255) | | | photoId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 接下去我们要在代码中关联他们。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(PhotoMetadata) photoMetadataModel: Repository; async updatePhoto() { // create a photo let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create a photo metadata let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; metadata.photo = photo; // this way we connect them // first we should save a photo await this.photoModel.save(photo); // photo is saved. Now we need to save a photo metadata await this.photoMetadataModel.save(metadata); // done console.log("Metadata is saved, and relation between metadata and photo is created in the database too"); } } ``` ### 13、反向关系映射[​](#13反向关系映射 "13、反向关系映射的直接链接") 关系映射可以是单向或双向的。当在 PhotoMetadata 和 Photo之间的关系是单向的。关系的所有者是PhotoMetadata,而 Photo对 PhotoMetadata 是一无所知的。这使得从 Photo 端访问 PhotoMetadata 变得很复杂。若要解决此问题,我们添加一个反向的关系映射,使 PhotoMetadata 和 Photo之间变成双向关联。让我们修改我们的实体。 ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo'; @EntityModel() export class PhotoMetadata { /* ... other columns */ @OneToOne(type => Photo, photo => photo.metadata) @JoinColumn() photo: Photo; } ``` ``` import { EntityModel } from '@midwayjs/orm'; import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata'; @EntityModel() export class Photo { /* ... other columns */ @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo) metadata: PhotoMetadata; } ``` `photo => photo.metadata` 是一个返回反向映射关系的函数。在这里,我们显式声明 Photo 类的 metadata 属性用于关联 PhotoMetadata。除了传递返回 photo 属性的函数外,您还可以直接将字符串传递给 `@OneToOne` 装饰器,例如 `“metadata”` 。但是我们使用了这种函数回调的方法来让我们的代码写法更简单。 请注意,只会在关系映射的一侧使用 `@JoinColumn` 装饰器。无论您放置此装饰器的哪一侧,都是关系的所有者。关系的拥有方在数据库中包含带有外键的列。 ### 14、加载对象及其依赖关系[​](#14加载对象及其依赖关系 "14、加载对象及其依赖关系的直接链接") 现在,让我们尝试在单个查询中一起加载出 Photo 和 PhotoMetadata。有两种方法可以执行此操作,使用 `find *` 方法或使用 `QueryBuilder` 功能。让我们首先使用 `find *` 方法。 `find *` 方法允许您使用 `FindOneOptions` / `FindManyOptions` 接口指定对象。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel.find({ relations: [ 'metadata' ] }); // typeorm@0.2.x } } ``` 在这里,photos 的值是一个数组,包含了整个数据库的查询结果,并且每个 photo 对象都包含其关联的 metadata 属性。在[此文档](https://github.com/typeorm/typeorm/blob/master/docs/find-options.md)中了解有关 `Find Options` 的更多信息。 使用 `Find Options` 很简单,但如果需要更复杂的查询,则应改用 `QueryBuilder` 。 `QueryBuilder` 允许以优雅的方式使用更复杂的查询。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel .createQueryBuilder('photo') .innerJoinAndSelect('photo.metadata', 'metadata') .getMany(); } } ``` `QueryBuilder`允许创建和执行几乎任何复杂的 SQL 查询。使用 `QueryBuilder` 时,请像创建 SQL 查询一样思考。在此示例中,“photo” 和 “metadata” 是应用于所选 photos 的别名。您可以使用别名来访问所选数据的列和属性。 ### 15、使用级联操作自动保存关联对象[​](#15使用级联操作自动保存关联对象 "15、使用级联操作自动保存关联对象的直接链接") 在我们希望在每次保存另一个对象时都自动保存关联的对象,这个时候可以在关系中设置级联。让我们稍微更改照片的 `@OneToOne` 装饰器。 ``` export class Photo { /// ... other columns @OneToOne(type => PhotoMetadata, metadata => metadata.photo, { cascade: true, }) metadata: PhotoMetadata; } ``` 使用 `cascade` 允许我们现在不再单独保存 Photo 和 PhotoMetadata,由于级联选项,元数据对象将被自动保存。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { // create photo object let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create photo metadata object let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; photo.metadata = metadata; // this way we connect them // save a photo also save the metadata await this.photoModel.save(photo); // done console.log("Photo is saved, photo metadata is saved too"); } } ``` 注意,我们现在设置 Photo 的元数据,而不需要像之前那样设置元数据的 Photo 属性。这仅当您从 Photo 这边将 Photo 连接到 PhotoMetadata 时,级联功能才有效。如果在 PhotoMetadata 侧设置,则不会自动保存。 ### 16、创建多对一/一对多关联[​](#16创建多对一一对多关联 "16、创建多对一/一对多关联的直接链接") 让我们创建一个多对一/一对多关系。假设一张照片有一个作者,每个作者可以有很多照片。首先,让我们创建一个 Author 类: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm"; import { Photo } from './entity/photo'; @EntityModel() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below photos: Photo[]; } ``` `Author` 包含了一个反向关系。 `OneToMany` 和 `ManyToOne` 需要成对出现。 现在,将关系的所有者添加到 Photo 实体中: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm"; import { PhotoMetadata } from "./photoMetadata"; import { Author } from "./author"; @Entity() export class Photo { /* ... other columns */ @ManyToOne(type => Author, author => author.photos) author: Author; } ``` 在多对一/一对多关系中,所有者方始终是多对一。这意味着使用 `@ManyToOne` 的类将存储相关对象的 ID。 运行应用程序后,ORM 将创建 `author` 表: ``` +-------------+--------------+----------------------------+ | author | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | +-------------+--------------+----------------------------+ ``` 它还将修改 `photo` 表,添加新的 `author` 列并为其创建外键: ``` +-------------+--------------+----------------------------+ | photo | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | | description | varchar(255) | | | filename | varchar(255) | | | isPublished | boolean | | | authorId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` ### 17、创建多对多关联[​](#17创建多对多关联 "17、创建多对多关联的直接链接") 让我们创建一个多对一/多对多关系。假设一张照片可以在许多相册中,并且每个相册可以包含许多照片。让我们创建一个 `Album` 类。 ``` import { EntityModel } from '@midwayjs/orm'; import { PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm"; @EntityModel() export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany(type => Photo, photo => photo.albums) @JoinTable() photos: Photo[]; } ``` `@JoinTable` 用来指明这是关系的所有者。 现在,将反向关联添加到 `Photo` 。 ``` export class Photo { /// ... other columns @ManyToMany(type => Album, album => album.photos) albums: Album[]; } ``` 运行应用程序后,ORM将创建一个 album\_photos\_photo\_albums 联结表: ``` +-------------+--------------+----------------------------+ | album_photos_photo_albums | +-------------+--------------+----------------------------+ | album_id | int(11) | PRIMARY KEY FOREIGN KEY | | photo_id | int(11) | PRIMARY KEY FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 现在,让我们将相册和照片插入数据库: ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(Album) albumModel: Repository async updatePhoto() { // create a few albums let album1 = new Album(); album1.name = "Bears"; await this.albumModel.save(album1); let album2 = new Album(); album2.name = "Me"; await this.albumModel.save(album2); // create a few photos let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.albums = [album1, album2]; await this.photoModel.save(photo); // now our photo is saved and albums are attached to it // now lets load them: const loadedPhoto = await this.photoModel.findOne(1, { relations: ["albums"] }); // typeorm@0.2.x } } ``` `loadedPhoto` 的值为: ``` { id: 1, name: "Me and Bears", description: "I am near polar bears", filename: "photo-with-bears.jpg", albums: [{ id: 1, name: "Bears" }, { id: 2, name: "Me" }] } ``` ### 18、使用 QueryBuilder[​](#18使用-querybuilder "18、使用 QueryBuilder的直接链接") 您可以使用QueryBuilder来构建几乎任何复杂的SQL查询。例如,您可以这样做: ``` let photos = await this.photoModel .createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it. .innerJoinAndSelect("photo.metadata", "metadata") .leftJoinAndSelect("photo.albums", "album") .where("photo.isPublished = true") .andWhere("(photo.name = :photoName OR photo.name = :bearName)") .orderBy("photo.id", "DESC") .skip(5) .take(10) .setParameters({ photoName: "My", bearName: "Mishka" }) .getMany(); ``` 该查询选择所有带有 “My” 或 “Mishka” 名称的已发布照片。它将从位置 5 开始返回结果(分页偏移),并且将仅选择 10 个结果(分页限制)。选择结果将按 ID 降序排列。该照片的相册将 left-Joined,元数据将自动关联。 您将在应用程序中大量使用查询生成器。在 [此处](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/select-query-builder.md) 了解有关QueryBuilder的更多信息。 ### 19、Event Subscriber[​](#19event-subscriber "19、Event Subscriber的直接链接") typeorm 提供了一个事件订阅机制,方便在做一些数据库操作时的日志输出,为此 midway 提供了一个 `EventSubscriberModel` 装饰器,用来标注事件订阅类,代码如下。 ``` import { Provide } from '@midwayjs/core'; import { EventSubscriberModel } from '@midwayjs/orm'; import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm'; @Provide() @EventSubscriberModel() export class EverythingSubscriber implements EntitySubscriberInterface { /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { console.log(`BEFORE ENTITY INSERTED: `, event.entity); } /** * Called before entity insertion. */ beforeUpdate(event: UpdateEvent) { console.log(`BEFORE ENTITY UPDATED: `, event.entity); } /** * Called before entity insertion. */ beforeRemove(event: RemoveEvent) { console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity insertion. */ afterInsert(event: InsertEvent) { console.log(`AFTER ENTITY INSERTED: `, event.entity); } /** * Called after entity insertion. */ afterUpdate(event: UpdateEvent) { console.log(`AFTER ENTITY UPDATED: `, event.entity); } /** * Called after entity insertion. */ afterRemove(event: RemoveEvent) { console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity is loaded. */ afterLoad(entity: any) { console.log(`AFTER ENTITY LOADED: `, entity); } } ``` 这个订阅类提供了一些常用的接口,用来在数据库操作时执行一些事情。 ### 20、OrmConnectionHook[​](#20ormconnectionhook "20、OrmConnectionHook的直接链��接") 在 3.4.0(不包含) 之前的版本中, Midway 封装提供了一种 Hook 机制,用于监听数据库连接与断连事件;代码如下。 ``` import { Provide } from '@midwayjs/core'; import { OrmConnectionHook, OrmHook } from '@midwayjs/orm'; import { Connection, ConnectionOptions } from 'typeorm'; @Provide() @OrmHook() export class OrmConnectionListener implements OrmConnectionHook { /** * Called before connection create * @param opts * @returns */ async beforeCreate(opts?: ConnectionOptions): Promise { console.log('BEFORE CONNECTION CREATE'); return opts; } /** * Called after connection create * @param conn * @param opts * @returns */ async afterCreate(conn?: Connection, opts?: ConnectionOptions): Promise { console.log('AFTER CONNECTION CREATE'); return conn; } /** * Called before connection close * @param conn * @param connectionName * @returns */ async beforeClose(conn?: Connection, connectionName?: string): Promise { console.log('BEFORE CONNECTION CLOSE'); return conn; } /** * Called after connection close * @param conn * @returns */ async afterClose(conn?: Connection): Promise { console.log('AFTER CONNECTION CLOSE'); return conn; } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 多数据库支持[​](#多数据库支持 "多数据库支持的直接链接") 有时候,我们一个应用中会有多个数据库连接(Connection)的情况,这个时候会有多个配置。我们使用**对象的形式**来定义配置。 比如下面定义了 `default` 和 `test` 两个数据库连接(Connection)。 ``` import {join} from 'path'; export default { orm: { default: { type: 'sqlite', database: join(__dirname, '../../default.sqlite'), logging: true, }, test: { type: 'mysql', host: '127.0.0.1', port: 3306, username: '*********', password: '*********', database: undefined, synchronize: true, logging: false, } } } ``` 在使用时,需要指定模型归属于哪个连接(Connection)。 ``` // entity/photo.ts import { InjectEntityModel } from '@midwayjs/orm'; import { User } from './model/user'; export class XXX { @InjectEntityModel(User, 'test') testUserModel: Repository; //... } ``` 同样的,在使用注入 Model 时,需要指定连接。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo', { connectionName: 'test' }) export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` ### 获取连接池[​](#获取连接池 "获取连接池的直接链接") ``` import { Configuration } from '@midwayjs/core'; import { getConnection } from 'typeorm'; @Configuration() export class MainConfiguration { async onReady() { const conn = getConnection('default'); console.log(conn.isConnected); } } ``` ### Hooks 场景支持[​](#hooks-场景支持 "Hooks 场景支持的直接链接") 针对函数式编程的场景,我们提供了简化的函数式写法。 ``` import { useEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; export async function getPhoto() { // get model const photoModel = useEntityModel(Photo); const photo = new Photo(); // create entity photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.views = 1; photo.isPublished = true; // find const newPhoto = await photoModel.save(photo); return 'hello world'; } ``` ### 关于表结构同步[​](#关于表结构同步 "关于表结构同步的直接链接") * 如果你已有表结构,想自动创建 Entity,使用 [生成器](/docs/3.0.0/tool/typeorm_generator.md) * 如果已经有 Entity 代码,想创建表结构请使用配置中的 `synchronize: true` 。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Handshake inactivity timeout[​](#handshake-inactivity-timeout "Handshake inactivity timeout的直接链接") 一般是网络原因,如果本地出现,可以 ping 但是telnet不通,可以尝试执行如下命令: ``` $ sudo sysctl -w net.inet.tcp.sack=0 ``` ### 关于 mysql 时间列的当前时区展示[​](#关于-mysql-时间列的当前时区展示 "关于 mysql 时间列的当前时区展示的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,一般情况下,数据库中保存的是 UTC 时间,如果你希望返回当前时区的时间,可以使用下面的方式。 在配置时,开启时间转字符串的选项。 ``` // src/config/config.default.ts export default { // ... orm: { //... dateStrings: true, }, } ``` 实体中的时间列需要列类型。 ``` @EntityModel() export class Photo { //... @UpdateDateColumn({ name: "gmt_modified", type: 'timestamp' }) gmtModified: Date; @CreateDateColumn({ name: "gmt_create", type: 'timestamp' }) gmtCreate: Date; } ``` 这样,输出的时间字段就是当前的时区了。 效果如下: **配置前:** ``` gmtModified: 2021-12-13T03:49:43.000Z, gmtCreate: 2021-12-13T03:49:43.000Z ``` **配置后:** ``` gmtModified: '2021-12-13 11:49:43', gmtCreate: '2021-12-13 11:49:43' ``` ### 关于时间列的默认值[​](#关于时间列的默认值 "关于时间列的默认值的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,那么注意,typeorm 是在建表语句中自动添加了默认值,如果表是用户自建的,该字段会由于没有默认值而写入 00:00:00 的时间。 解决方案有两个 **1、修改表的默认值** 或者 **2、修改代码中列的默认值** **如果不想修改表,而想修改代码,请参考下面的代码。** ``` @Column({ default: () => "NOW()", type: 'timestamp' }) createdOn: Date; @Column({ default: () => "NOW()", type: 'timestamp' }) modifiedOn: Date; ``` ### 同时安装 mysql 和 mysql2[​](#同时安装-mysql-和-mysql2 "同时安装 mysql 和 mysql2的直接链接") 在 node\_modules 中同时有 mysql 和 mysql2 时,typeorm 会自动加载 mysql,而不是 mysql2。 这个时候如需使用 mysql2,请指定 driver。 ``` // src/config/config.default.ts export default { // ... orm: { //... type: 'mysql', driver: require('mysql2'), }, } ``` --- # Sequelize 提示 本文档从 v3.4.0 版本起废弃。 本文档介绍如何在 Midway 中使用 Sequelize 模块。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## 使用方法:[​](#使用方法 "使用方法:的直接链接") ``` $ npm i @midwayjs/sequelize@3 sequelize --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/sequelize": "^3.0.0", "sequelize": "^6.13.0" // ... }, "devDependencies": { // ... } } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` ## 引入模块[​](#引入模块 "引入模块的直接链接") 在 configuration.ts 文件中 ``` import { App, Configuration, ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/web'; import { join } from 'path'; import * as sequelize from '@midwayjs/sequelize'; @Configuration({ imports: [sequelize], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle { @App() app: Application; async onReady() {} } ``` ## 配置[​](#配置 "配置的直接链接") 在 config.default.ts 中配置: ``` // src/config/config.default.ts export default { // ... sequelize: { dataSource: { default: { database: 'test4', username: 'root', password: '123456', host: '127.0.0.1', // 此处支持idb上面vipserver key的那种方式,也支持aliyun的地址。 port: 3306, encrypt: false, dialect: 'mysql', define: { charset: 'utf8' }, timezone: '+08:00', logging: console.log, }, }, sync: false, // 本地的时候,可以通过sync: true直接createTable }, }; ``` ## 业务层[​](#业务层 "业务层的直接链接") ### 定义 Entity[​](#定义-entity "定义 Entity的直接链接") ``` import { Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { BaseTable } from '@midwayjs/sequelize'; import { User } from './User'; @BaseTable export class Photo extends Model { @ForeignKey(() => User) @Column({ comment: '用户Id', }) userId: number; @BelongsTo(() => User) user: User; @Column({ comment: '名字', }) name: string; } ``` ``` import { Model, Column, HasMany } from 'sequelize-typescript'; import { BaseTable } from '@midwayjs/sequelize'; import { Photo } from './Photo'; @BaseTable export class User extends Model { @Column name!: string; @HasMany(() => Photo) Photo: Photo[]; } ``` ### 使用 Entity:[​](#使用-entity "使用 Entity:的直接链接") #### 查询列表[​](#查询列表 "查询列表的直接链接") ``` import { Config, Controller, Get, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { let result = await Photo.findAll(); console.log(result); return 'hello world'; } } ``` 增加数据: ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/add') async home() { let result = await Photo.create({ name: '123', }); console.log(result); return 'hello world'; } } ``` #### 删除:[​](#删除 "删除:的直接链接") ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { await Photo.destroy({ where: { name: '123', }, }); return 'hello world'; } } ``` #### 查找单个:[​](#查找单个 "查找单个:的直接链接") ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { let result = await Photo.findOne({ where: { name: '123', }, }); return 'hello world'; } } ``` #### 联合查询:[​](#联合查询 "联合查询:的直接链接") ``` import { Controller, Get, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; import { Op } from 'sequelize'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { // SELECT * FROM photo WHERE name = "23" OR name = "34"; let result = await Photo.findAll({ where: { [Op.or]: [{ name: '23' }, { name: '34' }], }, }); console.log(result); return 'hello world'; } } ``` #### 连表查询[​](#连表查询 "连表查询的直接链接") ``` import { Controller, Get, Provide } from '@midwayjs/core'; import { User } from '../entity/User'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/users') export class HomeController { @Get('/') async home() { let result = await User.findAll({ include: [Photo] }); console.log(result); return 'hello world'; } } ``` 关于 OP 的更多用法: midway + sequelize 完整使用案例 如果遇到比较复杂的,可以使用 raw query 方法: --- # 任务调度 提示 本文档从 v3.6.0 版本起废弃。 @midwayjs/task 是为了解决任务系列的模块,例如分布式定时任务、延迟任务调度。例如每日定时报表邮件发送、订单2小时后失效等工作。 分布式定时任务依赖 bull,其通过 redis 进行实现,所以配置中,需要配置额外的 Redis,本地定时任务基于 Cron 模块,不需要额外配置。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | **其他** | 描述 | | | -------------------- | -- | | 可作为主框架独立使用 | ✅ | | 包含自定义日志 | ✅ | | 可独立添加中间件 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 首先安装 Midway 提供的任务组件: ``` $ npm install @midwayjs/task@3 @types/bull --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/task": "^3.0.0", // ... }, "devDependencies": { "@types/bull": "^3.15.8", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `configuration.ts` 中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as task from '@midwayjs/task'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [task], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { } ``` ## 分布式定时任务[​](#分布式定时任务 "分布式定时任务的直接链接") 这是我们最常用的定时任务方式。 分布式定时任务,可以做到分布在多个进程,多台机器去执行单一定时任务方式。 分布式定义任务依赖 Redis 服务,需要提前申请。 ### 配置[​](#配置 "配置的直接链接") 在 `config.default.ts` 文件中配置对应的模块信息: ``` // src/config/config.default.ts export default { // ... task: { redis: `redis://127.0.0.1:32768`, // 任务依赖redis,所以此处需要加一个redis prefix: 'midway-task', // 这些任务存储的key,都是midway-task开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... task: { // ioredis的配置 https://www.npmjs.com/package/ioredis redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, prefix: 'midway-task', // 这些任务存储的 key,都是 midway-task 开头,以便区分用户原有redis 里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task 等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }, } ``` ### 代码使用[​](#代码使用 "代码使用的直接链接") ``` import { Provide, Inject, Task, FORMAT } from '@midwayjs/core'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每分钟执行一次,并且是分布式任务 @Task({ repeat: { cron: FORMAT.CRONTAB.EVERY_MINUTE} }) async test() { console.log(this.helloService.getName()) } } ``` ### 设置进度[​](#设置进度 "设置进度的直接链接") 例如我们在做音视频或者发布这种比较耗时的任务的时候,我们希望能设置进度。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01WPYaAz21NgV3VNzjV_!!6000000006973-2-tps-576-454.png) 相当于第二个参数,将 bull 的 job 传递给了用户。用户可以通过 `job.progress` 来设置进度。 然后查询进度: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Controller, Get } from '@midwayjs/core'; @Controller() export class HelloController{ @Inject() queueService: QueueService; @Get("/get-queue") async getQueue(@Query() id: string){ return await this.queueService.getClassQueue(TestJob).getJob(id); } } ``` ### 任务的相关内容[​](#任务的相关内容 "任务的相关内容的直接链接") ``` let job = await this.queueService.getClassQueue(TestJob).getJob(id) ``` 然后 job 上面有类似停止的方法,或者查看进度的方法。 ### 启动就触发[​](#启动就触发 "启动就触发的直接链接") 有朋友由于只有一台机器,希望重启后立马能执行一下对应的定时任务。 ``` import { Configuration, Context, ILifeCycle, IMidwayBaseApplication, IMidwayContainer } from '@midwayjs/core'; import { Queue } from 'bull'; import { join } from 'path'; import * as task from '@midwayjs/task'; import { QueueService } from '@midwayjs/task'; @Configuration({ imports: [ task ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration implements ILifeCycle { async onServerReady(container: IMidwayContainer, app?: IMidwayBaseApplication): Promise { // Task这块的启动后立马执行 let result: QueueService = await container.getAsync(QueueService); // 此处第一个是你任务的类名,第二个任务的名字也就是装饰器Task的函数名 let job: Queue = result.getQueueTask(`HelloTask`, 'task') // 表示立即执行。 job.add({}, {delay: 0, repeat: null}) // LocalTask的启动后立马执行 const result = await container.getAsync(QueueService); let job = result.getLocalTask(`HelloTask`, 'task'); // 参数1:类名 参数2: 装饰器TaskLocal的函数名 job(); // 表示立即执行 } } ``` ## 常用 Cron 表达式[​](#常用-cron-表达式 "常用 Cron 表达式的直接链接") 关于 Task 任务的配置: ``` * * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional) ``` 常见表达式: * 每隔5秒执行一次:`*/5 * * * * *` * 每隔1分钟执行一次:`0 */1 * * * *` * 每小时的20分执行一次:`0 20 * * * *` * 每天 0 点执行一次:`0 0 0 * * *` * 每天的两点35分执行一次:`0 35 2 * * *` 可以使用 [在线工具](https://cron.qqe2.com/) 执行确认下一次执行的时间。 Midway 在框架侧提供了一些常用的表达式,放在 `@midwayjs/core` 中供大家使用。 ``` import { FORMAT } from '@midwayjs/core'; // 每分钟执行的 cron 表达式 FORMAT.CRONTAB.EVERY_MINUTE ``` 内置的还有一些其他的表达式。 | 表达式 | 对应时间 | | --------------------------------- | --------------- | | CRONTAB.EVERY\_SECOND | 每秒钟 | | CRONTAB.EVERY\_MINUTE | 每分钟 | | CRONTAB.EVERY\_HOUR | 每小时整点 | | CRONTAB.EVERY\_DAY | 每天 0 点 | | CRONTAB.EVERY\_DAY\_ZERO\_FIFTEEN | 每天 0 点 15 分 | | CRONTAB.EVERY\_DAY\_ONE\_FIFTEEN | 每天 1 点 15 分 | | CRONTAB.EVERY\_PER\_5\_SECOND | 每隔 5 秒 | | CRONTAB.EVERY\_PER\_10\_SECOND | 每隔 10 秒 | | CRONTAB.EVERY\_PER\_30\_SECOND | 每隔 30 秒 | | CRONTAB.EVERY\_PER\_5\_MINUTE | 每隔 5 分钟 | | CRONTAB.EVERY\_PER\_10\_MINUTE | 每隔 10 分钟 | | CRONTAB.EVERY\_PER\_30\_MINUTE | 每隔 30 分钟 | ## 手动触发任务[​](#手动触发任务 "手动触发任务的直接链接") 任务的定义,通过 `@Queue` 装饰器,定义一个任务类,必须含有一个 `async execute()` 方法。 ``` import { Provide, Inject, Queue } from '@midwayjs/core'; @Queue() export class HelloTask{ async execute(params){ console.log(params); } } ``` 触发: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Inject } from '@midwayjs/core'; @Provide() export class UserTask{ @Inject() queueService: QueueService; async execute(params = {}){ // 3秒后触发分布式任务调度。 const xxx = await this.queueService.execute(HelloTask, params, {delay: 3000}); } } ``` 3 秒后,会触发 HelloTask 这个任务。 提示 注意,如果没触发,请检查上面的 params,保证其不为空。 ## 运维[​](#运维 "运维的直接链接") ### 日志[​](#日志 "日志的直接链接") 在Midway Task Component上面,增加了两个日志: * midway-task.log * midway-task-error.log 分别在task、localTask、queue触发开始和结束的时候会打印对应的日志。 task日志基本配置: ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... }, taskLog: { disableConsole: false, // 是否禁用打印到控制台,默认禁用 level: 'warn', // 服务器默认warn consoleLevel: 'warn', }, } }, } as MidwayConfig; ``` 分布式的Task触发日志: ``` logger.info(`task start.`) // 异常情况: logger.error(err.stack) logger.info(`task end.`) ``` 非分布式的LocalTask触发日志: ``` logger.info(`local task start.`) // 异常情况: // logger.error(`${e.stack}`) logger.info(`local task end.`) ``` 任务队列的触发日志: ``` logger.info(`queue process start.`) // 异常情况: // logger.error(`${e.stack}`) logger.info(`queue process end.`) ``` ### 排查问题链路:[​](#排查问题链路 "排查问题链路:的直接链接") ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01xL1mQE25kMZnB5ygb_!!6000000007564-2-tps-1614-847.png) 用户可以搜索这个相同的id,找到同一次请求的日志。 为了方便用户在自己的业务代码中串联对应的日志,我在ctx上面挂了traceId变量。 例如异常情况:当异常的时候,**本地可以在控制台和 midway-task.log 栏内看到这个错误相关的情况:** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01WYBjbL1lGKHmsdSnH_!!6000000004791-2-tps-1964-324.png) ### traceId[​](#traceid "traceId的直接链接") localTask 则是自己生成了一个 uuid 的 id 作为 traceId。 task 和 queue 则采用 job 的 id 作为 traceId。 ### 业务内部的代码[​](#业务内部的代码 "业务内部的代码的直接链接") 在 service 内可以通过 inject 注入 logger,或者注入 ctx 拿 logger 变量 ``` import { App, Inject, Provide, Queue } from '@midwayjs/core'; import { Application } from "@midwayjs/koa"; @Queue() export class QueueTask{ @App() app: Application; @Inject() logger; async execute(params){ this.logger.info(`====>QueueTask execute`) this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 或者 ``` import { App, Inject, Provide, Queue } from '@midwayjs/core'; import { Application } from "@midwayjs/koa"; @Queue() export class QueueTask{ @App() app: Application; @Inject() ctx; async execute(params){ this.ctx.logger.info(`====>QueueTask execute`) this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 打印的日志 ``` 2021-07-30 13:00:13,101 INFO 5577 [Queue][12][QueueTask] queue process start. 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] ====>QueueTask execute 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] queue process end. ``` ## 本地定时任务[​](#本地定时任务 "本地定时任务的直接链接") 本地定时任务和分布式任务不同,无需依赖和配置 Redis,只能做到单进程的事情,即每台机器的每个进程都会被执行。 ``` import { Provide, Inject, TaskLocal, FORMAT } from '@midwayjs/core'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每分钟执行一次 @TaskLocal(FORMAT.CRONTAB.EVERY_MINUTE) async test(){ console.log(this.helloService.getName()) } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、EVALSHA错误[​](#1evalsha错误 "1、EVALSHA错误的直接链接") ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01KfjCKT1yypmNPDkIL_!!6000000006648-2-tps-3540-102.png) 这个问题基本明确,问题会出现在 redis 的集群版本上。原因是 redis 会对 key 做 hash 来确定存储的 slot,集群下这一步 @midwayjs/task 的 key 命中了不同的 slot。临时的解决办法是 task 里的 prefix 配置用 包括,强制 redis 只计算 里的hash,例如 `prefix: '{midway-task}'`。 ### 2、历史日志删除[​](#2历史日志删除 "2、历史日志删除的直接链接") 当每次redis执行完他会有日志,那么如何让其在完成后删除: ``` import { Provide, Task } from '@midwayjs/core'; import { IUserOptions } from '../interface'; @Provide() export class UserService { async getUser(options: IUserOptions) { return { uid: options.uid, username: 'mockedName', phone: '12345678901', email: 'xxx.xxx@xxx.com', }; } @Task({ repeat: { cron: '* * * * * *'}, removeOnComplete: true // 加了一行这个 }) async test(){ console.log(`====`) } } ``` 目前是否默认删除,需要跟用户沟通。 ### 3、配置 Redis 集群[​](#3配置-redis-集群 "3、配置 Redis 集群的直接链接") 你可以使用 bull 提供的 `createClient` 方式来接入自定义的 redis 实例,这样你可以接入 Redis 集群。 比如: ``` // src/config/config.default import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, // 一定要是false retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null // 一定要是null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { task: { createClient: (type, opts) => { return redisClientInstance; }, prefix: '{midway-task}', // 这些任务存储的key,都是相同开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 } } } } ``` --- # 生命周期 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 ## 项目生命周期[​](#项目生命周期 "项目生命周期的直接链接") 框架提供了这些生命周期函数供开发人员处理: * 配置文件加载,我们可以在这里去修改配置(`onConfigLoad`) * 依赖注入容器准备完毕,可以在这个阶段做大部分的事情(`onReady`) * 服务启动完成,可以拿到 server(`onServerReady`) * 应用即将关闭,在这里清理资源(`onStop`) Midway 的生命周期是通过 `src/configuration.ts` 文件,实现 ILifeCycle 接口,就可以在项目启动时候自动加载。 接口定义如下。 ``` interface ILifeCycle { /** * 在应用配置加载后执行 */ onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在依赖注入容器 ready 的时候执行 */ onReady(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用服务启动后执行 */ onServerReady?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用停止的时候执行 */ onStop?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在健康检查时执行 */ onHealthCheck?(container: IMidwayContainer): Promise; } ``` ### onConfigLoad[​](#onconfigload "onConfigLoad的直接链接") 一般用于修改项目的配置文件。 举个例子。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onConfigLoad(): Promise { // 直接返回数据,会自动合并到配置中 return { test: 1 } } } ``` 这个时候,`@Config` 拿到的配置就包含了返回的数据,具体可以参考 [异步初始化配置](/docs/3.0.0/env_config.md#%E5%BC%82%E6%AD%A5%E5%88%9D%E5%A7%8B%E5%8C%96%E9%85%8D%E7%BD%AE) 章节。 ### onReady[​](#onready "onReady的直接链接") onReady 是一个大部分场景下都会使用到的生命周期。 信息 注意,这里的 ready 指的是依赖注入容器 ready,并不是应用 ready,所以你可以对应用做任意扩展,比如添加中间件,连接数据库等等。 我们需要在初始化时提前连接一个数据库,由于在类中,所以也可以通过 `@Inject` 装饰器注入 db 这样一个数据库的连接工具类,这个实例包含 connect 和 close 两个函数: ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { // 建立数据库连接 await this.db.connect(); } async onStop(): Promise { // 关闭数据库连接 await this.db.close(); } } ``` 这样,我们就能够在应用启动时建立数据库连接,而不是在请求响应时再去创建。同时,在应用停止时,也可以优雅的关闭数据库连接。 除此之外,通过这个方式,可以对默认注入的对象做扩充。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as sequelize from 'sequelize'; @Configuration() export class MainConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer): Promise { // 三方包对象 container.registerObject('sequelize', sequelize); } } ``` 在其他的类中可以直接注入使用。 ``` export class IndexHandler { @Inject() sequelize; async handler() { console.log(this.sequelize); } } ``` ### onServerReady[​](#onserverready "onServerReady的直接链接") 当要获取框架的服务对象,端口等信息时,就需要用到这个生命周期。 我们以 `@midwayjs/koa` 为例,在启动时获取它的 Server。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { async onServerReady(container: IMidwayContainer): Promise { // 获取到 koa 中暴露的 Framework const framework = await container.getAsync(koa.Framework); const server = framework.getServer(); // ... } } ``` ### onStop[​](#onstop "onStop的直接链接") 我们可以在这个阶段清理一些资源,比如关闭连接等。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { // 建立数据库连接 await this.db.connect(); } async onStop(): Promise { // 关闭数据库连接 await this.db.close(); } } ``` ### onHealthCheck[​](#onhealthcheck "onHealthCheck的直接链接") 当内置的健康检查服务调用状态获取 API 时,所有组件的该方法都被自动执行。 下面模拟了一个 db 健康检查的方法。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, HealthResult } from '@midwayjs/core'; @Configuration({ namespace: 'db' }) export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { await this.db.connect(); } async onHealthCheck(): Promise { try { const result = await this.db.isConnect(); if (result) { return { status: true, }; } else { return { status: false, reason: 'db is disconnect', }; } } catch (err) { return { status: false, reason: err.message, }; } } } ``` 上述 `onHealthCheck` 中,调用了一个 `isConnect` 的状态检查,根据结果返回了固定的 `HealthResult` 类型格式。 注意,外部调用 `onHealthCheck` 可能会非常频繁,请尽可能保持检查逻辑的可靠性和效率,确保不会对检查依赖有较大的压力。同时请自行处理检查超时后资源释放的逻辑,避免资源频繁请求却未返回结果,导致内存泄露的风险。 ## 全局对象生命周期[​](#全局对象生命周期 "全局对象生命周期的直接链接") 所谓对象生命周期,指的是每个对象,在依赖注入容器中创建,销毁的事件。我们通过这些生命周期,可以在对象创建后,销毁时做一些操作。 ``` export interface IObjectLifeCycle { onBeforeObjectCreated(/**...**/); onObjectCreated(/**...**/); onObjectInit(/**...**/); onBeforeObjectDestroy(/**...**/); } ``` `ILifeCycle` 定义中已经包含了这些阶段。 警告 注意,对象生命周期 API 会影响整个依赖注入容器以及业务的使用,请谨慎操作。 ### onBeforeObjectCreated[​](#onbeforeobjectcreated "onBeforeObjectCreated的直接链接") 在业务对象实例创建前执行,框架内部的某些对象由于已经初始化,无法被拦截。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeCreatedOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectCreated(Clzz: new (...args), options: ObjectBeforeCreatedOptions): Promise { // ... } } ``` 这里入参有两个参数: * `Clzz` 当前待创建对象的原型类 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ----------------------- | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | | options.constructorArgs | any\[] | 构造器入参 | ### onObjectCreated[​](#onobjectcreated "onObjectCreated的直接链接") 在对象实例创建后执行,这个阶段可以替换创建的对象。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectCreatedOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectCreatedOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ----------------------- | ------------------ | ------------------ | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | | options.replaceCallback | (ins: any) => void | 对象替换的回调方法 | **示例:动态添加属性** ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promise { // 每个创建的对象都会添加一个 _name 的属性 ins._name = 'xxxx'; // ... } } ``` **示例:替换对象** ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promise { // 之后每个创建的对象都会被替换为 { bbb: 'aaa' } options.replaceCallback({ bbb: 'aaa' }); // ... } } ``` ### onObjectInit[​](#onobjectinit "onObjectInit的直接链接") 在对象实例创建后执行异步初始化方法后执行。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectInit(ins: any, options: ObjectInitOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ------------------ | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | 信息 在这个阶段也可以动态给对象附加属性,方法等,和 `onObjectCreated` 的区别是,这个阶段是在初始化方法执行之后。 ### onBeforeObjectDestroy[​](#onbeforeobjectdestroy "onBeforeObjectDestroy的直接链接") 在对象实例销毁前执行。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeDestroyOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectDestroy(ins: any, options: ObjectBeforeDestroyOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ------------------ | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | --- # 日志(v2) 提示 本文档为 `@midwayjs/logger` v2.0 版本的文档。 Midway 为不同场景提供了一套统一的日志接入方式。通过 `@midwayjs/logger` 包导出的方法,可以方便的接入不同场景的日志系统。 Midway 的日志系统基于社区的 [winston](https://github.com/winstonjs/winston),是现在社区非常受欢迎的日志库。 实现的功能有: * 日志分级 * 按大小和时间自动切割 * 自定义输出格式 * 统一错误日志 ## 日志路径和文件[​](#日志路径和文件 "日志路径和文件的直接链接") Midway 会在日志根目录创建一些默认的文件。 * `midway-core.log` 框架、组件打印信息的日志,对应 `coreLogger` 。 * `midway-app.log` 应用打印信息的日志,对应 `appLogger` * `common-error.log` 所有错误的日志(所有 Midway 创建出来的日志,都会将错误重复打印一份到该文件中) 本地开发和服务器部署时的 **日志路径** 和 **日志等级** 不同,具体请参考 [配置日志根目录](#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95) 和 [框架的默认等级](#%E6%A1%86%E6%9E%B6%E7%9A%84%E9%BB%98%E8%AE%A4%E7%AD%89%E7%BA%A7)。 ## 默认日志对象[​](#默认日志对象 "默认日志对象的直接链接") Midway 默认在框架提供了三种不同的日志,对应三种不同的行为。 | 日志 | 释义 | 描述 | 常见使用 | | ----------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | coreLogger | 框架,组件层面的日志 | 默认会输出控制台日志和文本日志 `midway-core.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 框架和组件的错误,一般会打印到其中。 | | appLogger | 业务层面的日志 | 默认会输出控制台日志和文本日志 `midway-app.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 业务使用的日志,一般业务日志会打印到其中。 | | 上下文日志(复用 appLogger 的配置) | 请求链路的日志 | 默认使用 `appLogger` 进行输出,除了会将错误日志发送到 `common-error.log` 之外,还增加了上下文信息。 | 修改日志输出的标记(Label),不同的框架有不同的请求标记,比如 HTTP 下就会输出路由信息。 | ## 使用日志[​](#使用日志 "使用日志的直接链接") Midway 的常用日志使用方法。 ### 上下文日志[​](#上下文日志 "上下文日志的直接链接") 上下文日志是关联框架上下文对象(Context) 的日志。 我们可以通过 [获取到 ctx 对象](/docs/3.0.0/req_res_app.md) 后,使用 `ctx.logger` 对象进行日志打印输出。 比如: ``` ctx.logger.info("hello world"); ctx.logger.debug('debug info'); ctx.logger.warn('WARNNING!!!!'); // 错误日志记录,直接会将错误日志完整堆栈信息记录下来,并且输出到 errorLog 中 // 为了保证异常可追踪,必须保证所有抛出的异常都是 Error 类型,因为只有 Error 类型才会带上堆栈信息,定位到问题。 ctx.logger.error(new Error('custom error')); ``` 在执行后,我们能在两个地方看到日志输出: * 控制台看到输出。 * 日志目录的 midway-app.log 文件中 输出结果: ``` 2021-07-22 14:50:59,388 INFO 7739 [-/::ffff:127.0.0.1/-/0ms GET /api/get_user] hello world ``` 在注入的形式中,我们也可以直接使用 `@Inject() logger` 的形式来注入 `ctx.logger` ,和直接调用 `ctx.logger` 等价。 比如: ``` import { Get, Inject, Controller, Provide } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Controller() export class HelloController { @Inject() logger: ILogger; @Inject() ctx; @Get("/") async hello(){ // ... // this.logger === ctx.logger } } ``` ### 应用日志(App Logger)[​](#应用日志app-logger "应用日志(App Logger)的直接链接") 如果我们想做一些应用级别的日志记录,如记录启动阶段的一些数据信息,可以通过 App Logger 来完成。 ``` import { Configuration, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Configuration() export class MainConfiguration implements ILifeCycle { @Logger() logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` 注意,这里使用的是 `@Logger()` 装饰器。 ### CoreLogger[​](#corelogger "CoreLogger的直接链接") 在组件或者框架层面的研发中,我们会使用 coreLogger 来记录日志。 ``` @Configuration() export class MainConfiguration implements ILifeCycle { @Logger('coreLogger') logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` ## 输出方法和格式[​](#输出方法和格式 "输出方法和格式的直接链接") Midway 的日志对象继承与 winston 的日志对象,一般情况下,只提供 `error()` , `warn()` , `info()` , `debug` 四种方法。 示例如下。 ``` logger.debug('debug info'); logger.info('启动耗时 %d ms', Date.now() - start); logger.warn('warning!'); logger.error(new Error('my error')); ``` ### 默认的输出行为[​](#默认的输出行为 "默认的输出行为的直接链接") 在大部分的普通类型下,日志库都能工作的很好。 比如: ``` logger.info('hello world'); // 输出字符串 logger.info(123); // 输出数字 logger.info(['b', 'c']); // 输出数组 logger.info(new Set([2, 3, 4])); // 输出 Set logger.info(new Map([['key1', 'value1'], ['key2', 'value2']])); // 输出 Map ``` > Midway 针对 winston 无法输出的 `Array` , `Set` , `Map` 类型,做了特殊定制,使其也能够正常的输出。 不过需要注意的是,日志对象在一般情况下,只能传入一个参数,它的第二个参数有其他作用。 ``` logger.info('plain error message', 321); // 会忽略 321 ``` ### 错误输出[​](#错误输出 "错误输出的直接链接") 针对错误对象,Midway 也对 winston 做了定制,使其能够方便的和普通文本结合到一起输出。 ``` // 输出错误对象 logger.error(new Error('error instance')); // 输出自定义的错误对象 const error = new Error('named error instance'); error.name = 'NamedError'; logger.error(error); // 文本在前,加上 error 实例 logger.info('text before error', new Error('error instance after text')); ``` 警告 注意,错误对象只能放在最后,且有且只有一个,其后面的所有参数都会被忽略。 ### 格式化内容[​](#格式化内容 "格式化内容的直接链接") 基于 `util.format` 的格式化方式。 ``` logger.info('%s %d', 'aaa', 222); ``` 常用的有 * `%s` 字符串占位 * `%d` 数字占位 * `%j` json 占位 更多的占位和详细信息,请参考 node.js 的 [util.format](https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_format_format_args) 方法。 ### 输出自定义对象或者复杂类型[​](#输出自定义对象或者复杂类型 "输出自定义对象或者复杂类型的直接链接") 基于性能考虑,Midway(winston)大部分时间只会输出基本类型,所以当输出的参数为高级对象时,**需要用户手动转换为需要打印的字符串**。 如下示例,将不会得到希望的结果。 ``` const obj = {a: 1}; logger.info(obj); // 默认情况下,输出 [object Object] ``` 需要手动输出希望打印的内容。 ``` const obj = {a: 1}; logger.info(JSON.stringify(obj)); // 可以输出格式化文本 logger.info(obj.a); // 直接输出属性值 logger.info('%j', a); // 直接占位符输出整个 json ``` ### 纯输出内容[​](#纯输出内容 "纯输出内容的直接链接") 特殊场景下,我们需要单纯的输出内容,不希望输出时间戳,label 等和格式相关的信息。这种需求我们可以使用 `write` 方法。 `write` 方法是个非常底层的方法,并且不管什么级别的日志,它都会写入到文件中。 虽然 `write` 方法在每个 logger 上都有,但是我们只在 `IMidwayLogger` 定义中提供它,我们希望你能明确的知道自己希望调用它。 ``` (logger as IMidwayLogger).write('hello world'); // 文件中只会有 hello world ``` ## 日志类型定义[​](#日志类型定义 "日志类型定义的直接链接") 默认的情况,用户应该使用最简单的 `ILogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; // 获取上下文日志 async getUser() { this.logger.info('hello user'); } } ``` `ILogger` 定义只提供最简单的 `debug` , `info` , `warn` 以及 `error` 方法。 在某些场景下,我们需要更为复杂的定义,比如修改日志属性或者动态调节,这个时候需要使用更为复杂的 `IMidwayLogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { IMidwayLogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: IMidwayLogger; // 获取上下文日志 async getUser() { this.logger.disableConsole(); // 禁止控制台输出 this.logger.info('hello user'); // 这句话在控制台看不到 this.logger.enableConsole(); // 开启控制台输出 this.logger.info('hello user'); // 这句话在控制台可以看到 } } ``` `IMidwayLogger` 的定义可以参考 interface 中的描述,或者查看 [代码](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ## 日志基本配置[​](#日志基本配置 "日志基本配置的直接链接") 我们可以在配置文件中配置日志的各种行为。 Midway 中的的日志配置包含 **全局配置** 和 **单个日志配置** 两个部分,两者配置会合并和覆盖。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... } } }, } as MidwayConfig; ``` 如上所述,`clients` 配置段中的每个对象都是一个独立的日志配置项,其配置会和 `default` 段落合并后创建 logger 实例。 如果你发现没有定义,请将 `@midawyjs/logger` 在 `src/interface.ts` 中显式声明一次。 ``` // ... import type {} from '@midwayjs/logger'; ``` ## 配置日志等级[​](#配置日志等级 "配置日志等级的直接链接") winston 的日志等级分为下面几类,日志等级依次降低(数字越大,等级越低): ``` const levels = { none: 0, error: 1, trace: 2, warn: 3, info: 4, verbose: 5, debug: 6, silly: 7, all: 8, } ``` 在 Midway 中,为了简化,一般情况下,我们只会使用 `error` , `warn` , `info` , `debug` 这四种等级。 日志等级表示当前可输出日志的最低等级。比如当你的日志 level 设置为 `warn` 时,仅 `warn` 以及更高的 `error` 等级的日志能被输出。 在 Midway 中,针对不同的输出行为,可以配置不同的日志等级。 * `level` 写入文本的日志等级 * `consoleLevel` 控制台输出的日志等级 ### 框架的默认等级[​](#框架的默认等级 "框架的默认等级的直接链接") 在 Midway 中,有着自己的默认日志等级。 * 在开发环境下(local,test,unittest),文本和控制台日志等级统一为 `info` 。 * 在服务器环境(除开发环境外),为减少日志数量,`coreLogger` 日志等级为 `warn` ,而其他日志为 `info`。 ### 调整日志等级[​](#调整日志等级 "调整日志等级的直接链接") 一般情况下,我们不建议调整全局默认的日志等级,而是调整特定的 logger 的日志等级,比如: 调整 `coreLogger` 或者 `appLogger` 。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { clients: { coreLogger: { level: 'warn', consoleLevel: 'warn' // ... }, appLogger: { level: 'warn', consoleLevel: 'warn' // ... } } }, } as MidwayConfig; ``` 特殊场景,也可以临时调整全局的日志等级。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', consoleLevel: 'warn' }, // ... }, } as MidwayConfig; ``` ## 配置日志根目录[​](#配置日志根目录 "配置日志根目录的直接链接") 默认情况下,Midway 会在本地开发和服务器部署时输出日志到 **日志根目录**。 * 本地的日志根目录为 `${app.appDir}/logs/项目名` 目录下 * 服务器的日志根目录为用户目录 `${process.env.HOME}/logs/项目名` (Linux/Mac)以及 `${process.env.USERPROFILE}/logs/项目名` (Windows)下,例如 `/home/admin/logs/example-app`。 我们可以配置日志所在的根目录。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { dir: '/home/admin/logs', }, // ... }, } as MidwayConfig; ``` ## 配置日志切割(轮转)[​](#配置日志切割轮转 "配置日志切割(轮转)的直接链接") 默认行为下,同一个日志对象 **会生成两个文件**。 以 `midway-core.log` 为例,应用启动时会生成一个带当日时间戳 `midway-core.YYYY-MM-DD` 格式的文件,以及一个不带时间戳的 `midway-core.log` 的软链文件。 > windows 下不会生成软链 为方便配置日志采集和查看,该软链文件永远指向最新的日志文件。 当凌晨 `00:00` 时,会生成一个以当天日志结尾 `midway-core.log.YYYY-MM-DD` 的形式的新文件。 同时,当单个日志文件超过 200M 时,也会自动切割,产生新的日志文件。 可以通过配置调整按大小的切割行为。 ``` export default { midwayLogger: { default: { maxSize: '100m', }, // ... }, } as MidwayConfig; ``` ## 配置日志清理[​](#配置日志清理 "配置日志清理的直接链接") 默认情况下,日志会存在 31 天。 可以通过配置调整该行为,比如改为保存 3 天。 ``` export default { midwayLogger: { default: { maxFiles: '3d', }, // ... }, } as MidwayConfig; ``` ## 高级配置[​](#高级配置 "高级配置的直接链接") 如果用户不满足于默认的日志对象,也可以自行创建和修改。 ### 增加自定义日志[​](#增加自定义日志 "增加自定义日志的直接链接") 可以如下配置: ``` export default { midwayLogger: { clients: { abcLogger: { fileLogName: 'abc.log' // ... } } // ... }, } as MidwayConfig; ``` 自定义的日志可以通过 `@Logger('abcLogger')` 获取。 更多的日志选项可以参考 interface 中 [LoggerOptions 描述](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ### 配置日志输出格式[​](#配置日志输出格式 "配置日志输出格式的直接链接") 显示格式指的是日志输出时单行文本的字符串结构。Midway 对 Winston 的日志做了定制,提供了一些默认对象。 每个 logger 对象,都可以配置一个输出格式,显示格式是一个返回字符串结构的方法,参数为 Winston 的 [info 对象](https://github.com/winstonjs/logform#info-objects)。 ``` export default { midwayLogger: { clients: { appLogger: { format: info => { return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.labelText}${info.message}`; } // ... }, customOtherLogger: { format: info => { return 'xxxx'; } } } // ... }, } as MidwayConfig; ``` info 对象的默认属性如下: | **属性名** | **描述** | **示例** | | ----------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | timestamp | 时间戳,默认为 `'YYYY-MM-DD HH:mm:ss,SSS` 格式。 | 2020-12-30 07:50:10,453 | | level | 小写的日志等级 | info | | LEVEL | 大写的日志等级 | INFO | | pid | 当前进程 pid | 3847 | | labelText | 标签的聚合文本 | \[abcde] | | message | 普通消息 + 错误消息 + 错误堆栈的组合 | 1、普通文本,如 `123456` , `hello world`
2、错误文本(错误名+堆栈)Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18)
3、普通文本+错误文本 hello world Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18) | | stack | 错误堆栈 | | | originError | 原始错误对象 | 错误实例本身 | | originArgs | 原始的用户入参 | \[ 'a', 'b', 'c' ] | ### 获取自定义上下文日志[​](#获取自定义上下文日志 "获取自定义上下文日志的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,他们的关系如下。 ``` // 伪代码 const contextLogger = customLogger.createContextLogger(ctx); ``` `@Inject` 只能注入默认的上下文日志,我们可以通过 `ctx.getLogger` 方法获取其他 **自定义日志** 对应的 **上下文日志**。上下文日志和 ctx 关联,同一个上下文会相同的 key 会获取到同一个日志对象,当 ctx 被销毁,日志对象也会被回收。 ``` import { Provide } from '@midwayjs/core'; import { IMidwayLogger } from '@midwayjs/logger'; import { Context } from '@midwayjs/koa'; @Provide() export class UserService { @Inject() ctx: Context; async getUser() { // 这里获取的是 customLogger 对应的上下文日志对象 const customLogger = this.ctx.getLogger('customLogger'); customLogger.info('hello world'); } } ``` ### 配置上下文日志输出格式[​](#配置上下文日志输出格式 "配置上下文日志输出格式的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,但是我们可以单独配置日志对象的对应的上下文日志格式。 上下文日志的 info 对象中多了 ctx 对象,我们以修改 `customLogger` 的上下文日志为例。 ``` export default { midwayLogger: { clients: { customLogger: { contextFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... } } // ... }, } as MidwayConfig; ``` 则你在使用上下文日志输出时,会默认变成你 format 的样子。 ``` ctx.getLogger('customLogger').info('hello world'); // 2021-01-28 11:10:19,334 INFO 9223 [2ms POST] hello world ``` 注意,由于 `App Logger` 是所有框架默认的日志对象,较为特殊,现有部分框架默认配置了其上下文格式,导致在 `midwayLogger` 字段中配置无效。 为此你需要单独修改某一框架的上下文日志格式配置,请跳转到不同的框架查看。 * [修改 koa 的上下文日志格式](/docs/3.0.0/extensions/koa.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 egg 的上下文日志格式](/docs/3.0.0/extensions/egg.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 express 的上下文日志格式](/docs/3.0.0/extensions/express.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) ### 日志默认 Transport[​](#日志默认-transport "日志默认 Transport的直接链接") 每个日志包含几个默认的 Transport。 | 名称 | 默认行为 | 描述 | | ----------------- | -------- | ------------------------------ | | Console Transport | 开启 | 用于输出到控制台 | | File Transport | 开启 | 用于输出到文本文件 | | Error Transport | 开启 | 用于将错误输出到特定的错误日志 | | JSON Transport | 关闭 | 用于输出 JSON 格式的文本 | 可以通过配置进行修改。 **示例:只开启控制台输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableFile: false, enableError: false, // ... } } // ... }, } as MidwayConfig; ``` **示例:关闭控制台输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableConsole: false, // ... } } // ... }, } as MidwayConfig; ``` **示例:开启文本和 JSON 同步输出,关闭错误输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableConsole: false, enableFile: true, enableError: false, enableJSON: true, // ... } } // ... }, } as MidwayConfig; ``` ### 自定义 Transport[​](#自定义-transport "自定义 Transport的直接链接") 框架提供了扩展 Transport 的功能,比如,你可以写一个 Transport 来做日志的中转,上传到别的日志库等能力。 比如下面的示例,我们就将日志中转到另一个本地文件中。 ``` import { EmptyTransport } from '@midwayjs/logger'; class CustomTransport extends EmptyTransport { log(info, callback) { const levelLowerCase = info.level; if (levelLowerCase === 'error' || levelLowerCase === 'warn') { writeFileSync(join(logsDir, 'test.log'), info.message); } callback(); } } ``` 我们可以初始化,加到 logger 中,也可以单独对 Transport 设置 level。 ``` const customTransport = new CustomTransport({ level: 'warn', }); logger.add(customTransport); ``` 这样,原有的 logger 打印日志时,会自动执行该 Transport。 所有的 Transport 是附加在原有的 logger 实例之上(非 context logger),如需 ctx 数据,可以从 info 获取,注意判空。 ``` class CustomTransport extends EmptyTransport { log(info, callback) { if (info.ctx) { // ... } else { // ... } callback(); } } ``` 我们也可以使用依赖注入的方式来定义 Transport。 ``` import { EmptyTransport, IMidwayLogger } from '@midwayjs/logger'; import { MidwayLoggerService, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum) export class CustomTransport extends EmptyTransport { log(info, callback) { // ... callback(); } } // src/configuration.ts @Configuration(/*...*/) export class MainConfiguration { @Inject() loggerService: MidwayLoggerService; @Inject() customTransport: CustomTransport; async onReady() { const appLogger = this.loggerService.getLogger('customLogger') as IMidwayLogger; appLogger.add(this.customTransport); } } ``` ### 延迟初始化[​](#延迟初始化 "延迟初始化的直接链接") 可以使用 `lazyLoad` 配置让日志延迟初始化。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { level: 'DEBUG', }, customLoggerB: { lazyLoad: true, }, } // ... }, } as MidwayConfig; ``` `customLoggerA` 会在框架启动时立即初始化,而 `customLoggerB` 会在业务实际第一次使用 `getLogger` 或者 `@Logger` 注入时才被初始化。 这个功能非常适合动态化创建日志,但是配置却希望合并到一起的场景。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、服务器环境日志不输出[​](#1服务器环境日志不输出 "1、服务器环境日志不输出的直接链接") 服务器环境,默认日志等级为 warn,即 `logger.warn` 才会打印输出,请查看 ”日志等级“ 部分。 我们不推荐在服务器环境打印太多的日志,只打印必须的内容,过多的日志输出影响性能,也影响快速定位问题。 ### 2、服务器没有控制台日志[​](#2服务器没有控制台日志 "2、服务器没有控制台日志的直接链接") 一般来说,服务器控制台日志(console)是关闭的,只会输出到文件中,如有特殊需求,可以单独调整。 --- # 日志 Midway 为不同场景提供了一套统一的日志接入方式。通过 `@midwayjs/logger` 包导出的方法,可以方便的接入不同场景的日志系统。 实现的功能有: * 日志分级 * 按大小和时间自动切割 * 自定义输出格式 * 统一错误日志 提示 当前版本为 3.0 的日志 SDK 文档,如需 2.0 版本,请查看 [这个文档](/docs/logger.md)。 ## 从 2.0 升级到 3.0[​](#从-20-升级到-30 "从 2.0 升级到 3.0的直接链接") 从 midway v3.13.0 开始,支持使用 3.0 版本的 `@midwayjs/logger`。 将 `package.json` 中的依赖版本升级,注意是 `dependencies` 依赖。 ``` { "dependencies": { - "@midwayjs/logger": "2.0.0", + "@midwayjs/logger": "^3.0.0" } } ``` 如果在配置中没有了 midwayLogger 的类型提示,你需要在 `src/interface.ts` 中加入日志库的引用。 ``` // src/interface.ts + import type {} from '@midwayjs/logger'; ``` 在大部分场景下,两个版本是兼容的,但是由于是大版本升级,肯定会有一定的差异性,完整的 Breaking Change 变化,请查看 [变更文档](https://github.com/midwayjs/logger/blob/main/BREAKING-3.md)。 ## 日志路径和文件[​](#日志路径和文件 "日志路径和文件的直接链接") Midway 会在日志根目录创建一些默认的文件。 * `midway-core.log` 框架、组件打印信息的日志,对应 `coreLogger` 。 * `midway-app.log` 应用打印信息的日志,对应 `appLogger`,在 `@midawyjs/web` 中,该文件是 `midway-web.log` * `common-error.log` 所有错误的日志(所有 Midway 创建出来的日志,都会将错误重复打印一份到该文件中) 本地开发和服务器部署时的 **日志路径** 和 **日志等级** 不同,具体请参考 [配置日志根目录](#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95) 和 [框架的默认等级](#%E6%A1%86%E6%9E%B6%E7%9A%84%E9%BB%98%E8%AE%A4%E7%AD%89%E7%BA%A7)。 ## 默认日志对象[​](#默认日志对象 "默认日志对象的直接链接") Midway 默认在框架提供了三种不同的日志,对应三种不同的行为。 | 日志 | 释义 | 描述 | 常见使用 | | ----------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | | coreLogger | 框架,组件层面的日志 | 默认会输出控制台日志和文本日志 `midway-core.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 框架和组件的错误,一般会打印到其中。 | | appLogger | 业务层面的日志 | 默认会输出控制台日志和文本日志 `midway-app.log` ,并且默认会将错误日志发送到 `common-error.log` ,在 `@midawyjs/web` 中,该文件是 `midway-web.log`。 | 业务使用的日志,一般业务日志会打印到其中。 | | 上下文日志(复用 appLogger 的配置) | 请求链路的日志 | 默认使用 `appLogger` 进行输出,除了会将错误日志发送到 `common-error.log` 之外,还增加了上下文信息。 | 不同的协议有不同的请求日志格式,比如 HTTP 下就会输出路由信息。 | ## 使用日志[​](#使用日志 "使用日志的直接链接") Midway 的常用日志使用方法。 ### 上下文日志[​](#上下文日志 "上下文日志的直接链接") 上下文日志是关联框架上下文对象(Context) 的日志。 我们可以通过 [获取到 ctx 对象](/docs/3.0.0/req_res_app.md) 后,使用 `ctx.logger` 对象进行日志打印输出。 比如: ``` ctx.logger.info("hello world"); ctx.logger.debug('debug info'); ctx.logger.warn('WARNNING!!!!'); // 错误日志记录,直接会将错误日志完整堆栈信息记录下来,并且输出到 errorLog 中 // 为了保证异常可追踪,必须保证所有抛出的异常都是 Error 类型,因为只有 Error 类型才会带上堆栈信息,定位到问题。 ctx.logger.error(new Error('custom error')); ``` 在执行后,我们能在两个地方看到日志输出: * 控制台看到输出。 * 日志目录的 midway-app.log 文件中 输出结果: ``` 2021-07-22 14:50:59,388 INFO 7739 [-/::ffff:127.0.0.1/-/0ms GET /api/get_user] hello world ``` 在注入的形式中,我们也可以直接使用 `@Inject() logger` 的形式来注入 `ctx.logger` ,和直接调用 `ctx.logger` 等价。 比如: ``` import { Get, Inject, Controller, Provide } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Controller() export class HelloController { @Inject() logger: ILogger; @Inject() ctx; @Get("/") async hello(){ // ... // this.logger === ctx.logger } } ``` ### 应用日志(App Logger)[​](#应用日志app-logger "应用日志(App Logger)的直接链接") 如果我们想做一些应用级别的日志记录,如记录启动阶段的一些数据信息,可以通过 App Logger 来完成。 ``` import { Configuration, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Configuration() export class MainConfiguration implements ILifeCycle { @Logger() logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` 注意,这里使用的是 `@Logger()` 装饰器。 ### CoreLogger[​](#corelogger "CoreLogger的�直接链接") 在组件或者框架层面的研发中,我们会使用 coreLogger 来记录日志。 ``` @Configuration() export class MainConfiguration implements ILifeCycle { @Logger('coreLogger') logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` ## 输出方法和格式[​](#输出方法和格式 "输出方法和格式的直接链接") Midway 的日志对象提供 `error()` , `warn()` , `info()` , `debug()`,`write()` 五种方法。 示例如下。 ``` logger.debug('debug info'); logger.info('启动耗时 %d ms', Date.now() - start); logger.warn('warning!'); logger.error(new Error('my error')); logger.write('abcdef'); ``` 提示 `write` 方法用于输出用户的原始格式日志。 基于 `util.format` 的格式化方式。 ``` logger.info('%s %d', 'aaa', 222); ``` 常用的有 * `%s` 字符串占位 * `%d` 数字占位 * `%j` json 占位 更多的占位和详细信息,请参考 node.js 的 [util.format](https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_format_format_args) 方法。 ## 日志类型定义[​](#日志类型定义 "日志类型定义的直接链接") 大部分情况下,用户应该使用 `@midwayjs/core` 中最简单的 `ILogger` 定义。 ``` import { Provide, Logger, ILogger } from '@midwayjs/core'; @Provide() export class UserService { @Inject() logger: ILogger; async getUser() { this.logger.info('hello user'); } } ``` `ILogger` 定义只提供最简单的 `debug` , `info` , `warn` 以及 `error` 方法。 在某些场景下,我们需要更为复杂的定义,这个时候需要使用 `@midwayjs/logger` 提供的 `ILogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; async getUser() { // ... } } ``` `ILogger` 的定义可以参考 interface 中的描述,或者查看 [代码](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ## 日志配置[​](#日志配置 "日志配置的直接链接") ### 基本配置结构[​](#基本配置结构 "基本配置结构的直接链接") 我们可以在配置文件中配置日志的各种行为。 Midway 中的的日志配置包含 **全局配置** 和 **单个日志配置** 两个部分,两者配置会合并和覆盖。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... } } }, } as MidwayConfig; ``` 如上所述,`clients` 配置段中的每个对象都是一个独立的日志配置项,其配置会和 `default` 段落合并后创建 logger 实例。 ### 默认 Transport[​](#默认-transport "默认 Transport的直接链接") 在日志模块中,默认内置了 `console`,`file`,`error` ,`json` 四个 Transport,其中 Midway 默认启用了 `console`,`file`,`error` ,更多信息可以通过配置进行修改。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { console: { // console transport 配置 }, file: { // file transport 配置 }, error: { // error transport 配置 }, } }, // ... }, } as MidwayConfig; ``` 如果不需要某个 transport,可以设置为 `false`。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { console: false, } }, // ... }, } as MidwayConfig; ``` ### 配置日志等级[​](#配置日志等级 "配置日志等级的直接链接") 在 Midway 中,一般情况下,我们只会使用 `error` , `warn` , `info` , `debug` 这四种等级。 日志等级表示当前可输出日志的最低等级。比如当你的日志 level 设置为 `warn` 时,仅 `warn` 以及更高的 `error` 等级的日志能被输出。 在 Midway 中,有着自己的默认日志等级。 * 在开发环境下(local,test,unittest),文本和控制台日志等级统一为 `info` 。 * 在服务器环境,为减少日志数量,`coreLogger` 日志等级为 `warn` ,而其他日志为 `info`。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', }, // ... }, } as MidwayConfig; ``` logger 的 level 和 Transport 的 level 可以分开设置,Tranport 的 level 优先级高于 logger 的 level。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // logger 的 level level: 'info', transports: { file: { // file transport 的 level level: 'warn' } } }, // ... }, } as MidwayConfig; ``` 我们也可以调整特定的 logger 的日志等级,比如: 调整 `coreLogger` 或者 `appLogger` 。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { clients: { coreLogger: { level: 'warn', // ... }, appLogger: { level: 'warn', // ... } } }, } as MidwayConfig; ``` 特殊场景,也可以临时调整全局的日志等级。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', transports: { console: { level: 'warn' } } }, // ... }, } as MidwayConfig; ``` ### 配置日志根目录[​](#配置日志根目录 "配置日志根目录的直接链接") 默认情况下,Midway 会在本地开发和服务器部署时输出日志到 **日志根目录**。 * 本地的日志根目录为 `${app.appDir}/logs/项目名` 目录下 * 服务器的日志根目录为用户目录 `${process.env.HOME}/logs/项目名` (Linux/Mac)以及 `${process.env.USERPROFILE}/logs/项目名` (Windows)下,例如 `/home/admin/logs/example-app`。 我们可以配置日志所在的根目录,注意,要将所有 Transport 的路径都修改。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { file: { dir: '/home/admin/logs', }, error: { dir: '/home/admin/logs', }, } }, // ... }, } as MidwayConfig; ``` ### 配置日志切割(轮转)[​](#配置日志切割轮转 "配置日志切割(轮转)的直接链接") 默认行为下,同一个日志对象 **会生成两个文件**。 以 `midway-core.log` 为例,应用启动时会生成一个带当日时间戳 `midway-core.YYYY-MM-DD` 格式的文件,以及一个不带时间戳的 `midway-core.log` 的软链文件。 > windows 下不会生成软链 为方便配置日志采集和查看,该软链文件永远指向最新的日志文件。 当凌晨 `00:00` 时,会生成一个以当天日志结尾 `midway-core.log.YYYY-MM-DD` 的形式的新文件。 同时,当单个日志文件超过 200M 时,也会自动切割,产生新的日志文件。 可以通过配置调整按大小的切割行为。 ``` export default { midwayLogger: { default: { transports: { file: { maxSize: '100m', }, error: { maxSize: '100m', }, } }, // ... }, } as MidwayConfig; ``` ### 配置日志清理[​](#配�置日志清理 "配置日志清理的直接链接") 默认情况下,日志会存在 7 天。 可以通过配置调整该行为,比如改为保存 3 天。 ``` export default { midwayLogger: { default: { transports: { file: { maxFiles: '3d', }, error: { maxFiles: '3d', }, } }, // ... }, } as MidwayConfig; ``` 也可以配置数字,表示最多保留日志文件的个数。 ``` export default { midwayLogger: { default: { transports: { file: { maxFiles: '3', }, error: { maxFiles: '3d', }, } }, // ... }, } as MidwayConfig; ``` ### 配置自定义日志[​](#配置自定义日志 "配置自定义日志的直接链接") 可以如下配置: ``` export default { midwayLogger: { clients: { abcLogger: { fileLogName: 'abc.log' // ... } } // ... }, } as MidwayConfig; ``` 自定义的日志可以通过 `@Logger('abcLogger')` 获取。 更多的日志选项可以参考 interface 中 [LoggerOptions 描述](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ### 配置日志输出格式[​](#配置日志输出格式 "配置日志输出格式的直接链接") 显示格式指的是日志输出时单行文本的字符串结构。 每个 logger 对象,都可以配置一个输出格式,显示格式是一个返回字符串结构的方法,参数为一个 info 对象。 ``` import { LoggerInfo } from '@midwayjs/logger'; export default { midwayLogger: { clients: { appLogger: { format: (info: LoggerInfo) => { return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.labelText}${info.message}`; } // ... }, customOtherLogger: { format: (info: LoggerInfo) => { return 'xxxx'; } } } // ... }, } as MidwayConfig; ``` info 对象的默认属性如下: | **属性名** | **描述** | **示例** | | ----------- | ------------------------------------------------ | ----------------------- | | timestamp | 时间戳,默认为 `'YYYY-MM-DD HH:mm:ss,SSS` 格式。 | 2020-12-30 07:50:10,453 | | level | 小写的日志等级 | info | | LEVEL | 大写的日志等级 | INFO | | pid | 当前进程 pid | 3847 | | message | util.format 的结果 | | | args | 原始的用户入参 | \[ 'a', 'b', 'c' ] | | ctx | 使用 ContextLogger 时关联的上下文对象 | | | originError | 原始错误对象,遍历参数后获取,性能较差 | 错误实例本身 | | originArgs | 同 args,仅做兼容老版本使用 | | ### 获取自定义上下文日志[​](#获取自定义上下文日志 "获取自定义上下文日志的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,他们的关系如下。 ``` // 伪代码 const contextLogger = customLogger.createContextLogger(ctx); ``` `@Inject` 只能注入默认的上下文日志,我们可以通过 `ctx.getLogger` 方法获取其他 **自定义日志** 对应的 **上下文日志**。上下文日志和 ctx 关联,同一个上下文会相同的 key 会获取到同一个日志对象,当 ctx 被销毁,日志对象也会被回收。 ``` import { Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() export class UserService { @Inject() ctx: Context; async getUser() { // 这里获取的是 customLogger 对应的上下文日志对象 const customLogger = this.ctx.getLogger('customLogger'); customLogger.info('hello world'); } } ``` ### 配置上下文日志输出格式[​](#配置上下文日志输出格式 "配置上下文日志输出格式的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,但是我们可以单独配置日志对象的对应的上下文日志格式。 上下文日志的 info 对象中多了 ctx 对象,我们以修改 `customLogger` 的上下文日志为例。 ``` export default { midwayLogger: { clients: { customLogger: { contextFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... } } // ... }, } as MidwayConfig; ``` 则你在使用上下文日志输出时,会默认变成你 format 的样子。 ``` ctx.getLogger('customLogger').info('hello world'); // 2021-01-28 11:10:19,334 INFO 9223 [2ms POST] hello world ``` 注意,由于 `App Logger` 是所有框架默认的日志对象,较为特殊,现有部分框架默认配置了其上下文格式,导致在 `midwayLogger` 字段中配置无效。 为此你需要单独修改某一框架的上下文日志格式配置,请跳转到不同的框架查看。 * [修改 koa 的上下文日志格式](/docs/3.0.0/extensions/koa.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 egg 的上下文日志格式](/docs/3.0.0/extensions/egg.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 express 的上下文日志格式](/docs/3.0.0/extensions/express.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) ### 配置延迟初始化[​](#配置延迟初始化 "配置延迟初始化的直接链接") 可以使用 `lazyLoad` 配置让日志延迟初始化。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { // .. }, customLoggerB: { lazyLoad: true, }, } // ... }, } as MidwayConfig; ``` `customLoggerA` 会在框架启动时立即初始化,而 `customLoggerB` 会在业务实际第一次使用 `getLogger` 或者 `@Logger` 注入时才被初始化。 这个功能非常适合动态化创建日志,但是配置却希望合并到一起的场景。 ### 配置关联日志[​](#配置关联日志 "配置关联日志的直接链接") 日志对象可以配置一个关联的日志对象名。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { aliasName: 'customLoggerB', // ... }, } // ... }, } as MidwayConfig; ``` 当使用 API 获取时,不同的名字将取到同样的日志对象。 ``` app.getLogger('customLoggerA') => customLoggerA app.getLogger('customLoggerB') => customLoggerA ``` ### 配置控制台输出颜色[​](#配置控制台输出颜色 "配置控制台输出颜色的直接链接") 控制台输出时,在命令行支持颜色输出的情况下,针对不同的的日志等级会输出不同的颜色,如果不支持颜色,则不会显示。 你可以通过配置直接关闭颜色输出。 ``` export default { midwayLogger: { default: { transports: { console: { autoColors: false, } } } // ... }, } as MidwayConfig; ``` ### 配置 JSON 输出[​](#配置-json-输出 "配置 JSON 输出的直接链接") 通过开启 `json` Transport,可以将日志输出为 JSON 格式。 比如所有 logger 开启。 ``` export default { midwayLogger: { default: { transports: { file: false, json: { fileLogName: 'midway-app.json.log' } } } // ... }, } as MidwayConfig; ``` 或者单个 logger 开启。 ``` export default { midwayLogger: { default: { // ... }, clients: { appLogger: { transports: { json: { // ... } } } } }, } as MidwayConfig; ``` `json` Transport 的配置格式和 `file` 相同,输出略有不同。 比如我们可以修改 `format` 中输出的内容,默认情况下,输出至少会包含 `level` 和 `pid` 字段 ``` export default { midwayLogger: { default: { transports: { json: { format: (info: LoggerInfo & {data: string}) => { info.data = 'custom data'; return info; } } } } // ... }, } as MidwayConfig; ``` 输出为: ``` {"data":"custom data","level":"info","pid":89925} {"data":"custom data","level":"debug","pid":89925} ``` ## 自定义 Transport[​](#自定义-transport "自定义 Transport的直接链接") 框架提供了扩展 Transport 的功能,比如,你可以写一个 Transport 来做日志的中转,上传到别的日志库等能力。 ### 继承现有 Transport[​](#继承现有-transport "继承现有 Transport的直接链接") 如果是写入到新的文件,可以通过使用 `FileTransport` 来实现。 ``` import { FileTransport, isEnableLevel, LoggerLevel, LogMeta } from '@midwayjs/logger'; // Transport 的配置 interface CustomOptions { // ... } class CustomTransport extends FileTransport { log(level: LoggerLevel | false, meta: LogMeta, ...args) { // 判断 level 是否满足当前 Transport if (!isEnableLevel(level, this.options.level)) { return; } // 使用内置的格式化方法格式化消息 let buf = this.format(level, meta, args) as string; // 加上换行符 buf += this.options.eol; // 写入自己想写的日志 if (this.options.bufferWrite) { this.bufSize += buf.length; this.buf.push(buf); if (this.buf.length > this.options.bufferMaxLength) { this.flush(); } } else { // 没启用缓存,则直接写入 this.logStream.write(buf); } } } ``` 在使用前,需要注册到日志库中。 ``` import { TransportManager } from '@midwayjs/logger'; TransportManager.set('custom', CustomTransport); ``` 之后就可以在配置中使用这个 Transport 了。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { custom: { dir: 'xxxx', fileLogName: 'xxx', // ... } } } }, } as MidwayConfig; ``` 这样,原有的 logger 打印日志时,会自动执行该 Transport。 ### 完全自定义 Transport[​](#完全自定义-transport "完全自定义 Transport的直接链接") 除了写入文件之外,也可以将日志投递到远端服务,比如下面的示例,将日志中转到另一个服务。 注意,Transport 是一个可异步执行的操作,但是 logger 本身不会等待 Transport 执行返回。 ``` import { Transport, ITransport, LoggerLevel, LogMeta } from '@midwayjs/logger'; // Transport 的配置 interface CustomOptions { // ... } class CustomTransport extends Transport implements ITransport { log(level: LoggerLevel | false, meta: LogMeta, ...args) { // 使用内置的格式化方法格式化消息 let msg = this.format(level, meta, args) as string; // 异步写入日志库 remoteSdk.send(msg).catch(err => { // 记录下错误或者忽略 console.error(err); }); } } ``` ## 动态 API[​](#动态-api "动态 API的直接链接") 通过 `getLogger` 方法动态获取日志对象。 ``` // 获取 coreLogger const coreLogger = app.getLogger('coreLogger'); // 获取默认的 contextLogger const contextLogger = ctx.getLogger(); // 获取特定 logger 创建出来的 contextLogger,等价于 customALogger.createContextLogger(ctx) const customAContextLogger = ctx.getLogger('customA'); ``` 框架内置的 `MidwayLoggerService` 也拥有上述的 API。 ``` import { MidwayLoggerService } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() export class MainConfiguration { @Inject() loggerService: MidwayLoggerService; @Inject() ctx: Context; async getUser() { // get custom logger const customLogger = this.loggerService.getLogger('customLogger'); // 创建 context logger const customContextLogger = this.loggerService.createContextLogger(this.ctx, customLogger); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、服务器环境日志不输出[​](#1服务器环境日志不输出 "1、服务器环境日志不输出的直接链接") 我们不推荐在服务器环境打印太多的日志,只打印必须的内容,过多的日志输出影响性能,也影响快速定位问题。 如需调整日志等级,请查看 ”配置日志等级“ 部分。 ### 2、服务器没有控制台日志[​](#2服务器没有控制台日志 "2、服务器没有控制台日志的直接链接") 一般来说,服务器控制台日志(console)是关闭的,只会输出到文件中,如有特殊需求,可以单独调整。 ### 3、部分 Docker 环境启动失败[​](#3部分-docker-环境启动失败 "3、部分 Docker 环境启动失败的直接链接") 检查日志写入的目录当前应用启动的用户是否有权限。 ### 4、如果有老的配置如何转换[​](#4如果有老的配置如何转换 "4、如果有老的配置如何转换的直接链��接") 新版本日志库已经兼容老配置,一般情况下无需额外处理,老配置和新配置在合并时有优先级关系,请查看 [变更文档](https://github.com/midwayjs/logger/blob/main/BREAKING-3.md)。 为了减少排查问题,在使用新版本日志库时请尽可能使用新配置格式。 --- # Web 中间件 Web 中间件是在控制器调用 **之前** 和 \*\*之后(部分)\*\*调用的函数。 中间件函数可以访问请求和响应对象。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01h6hYvW1ogNexjJ3Nl_!!6000000005254-2-tps-2196-438.png) 不同的上层 Web 框架中间件形式不同,Midway 标准的中间件基于 [洋葱圈模型](https://eggjs.org/zh-cn/intro/egg-and-koa.html#midlleware)。而 Express 则是传统的队列模型。 Koa 和 EggJs 可以在 **控制器前后都被执行**,在 Express 中,中间件 **只能在控制器之前** 调用,将在 Express 章节单独介绍。 下面的代码,我们将以 `@midwayjs/koa` 举例。 ## 编写中间件[​](#编写中间件 "编写中间件的直接链接") 一般情况下,我们会在 `src/middleware` 文件夹中编写 Web 中间件。 创建一个 `src/middleware/report.middleware.ts` 。我们在这个 Web 中间件中打印了控制器(Controller)执行的时间。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── middleware ## 中间件目录 │ │ └── report.middleware.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` Midway 使用 `@Middleware` 装饰器标识中间件,完整的中间件示例代码如下。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // 控制器前执行的逻辑 const startTime = Date.now(); // 执行下一个 Web 中间件,最后执行到控制器 // 这里可以拿到下一个中间件或者控制器的返回值 const result = await next(); // 控制器之后执行的逻辑 console.log(Date.now() - startTime); // 返回给上一个中间件的结果 return result; }; } static getName(): string { return 'report'; } } ``` 简单来说, `await next()` 则代表了下一个要执行的逻辑,这里一般代表控制器执行,在执行的前后,我们可以进行一些打印和赋值操作,这也是洋葱圈模型最大的优势。 注意,Midway 对传统的洋葱模型做了一些微调,使得其可以获取到下一个中间件的返回值,同时,你也可以将这个中间件的结果,通过 `return` 方法返回给上一个中间件。 这里的静态 `getName` 方法,用来指定中间件的名字,方便排查问题。 ## 使用中间件[​](#使用中间件 "使用中间件的直接链接") Web 中间件在写完之后,需要应用到请求流程之中。 根据应用到的位置,分为两种: * 1、全局中间件,所有的路由都会执行的中间件,比如 cookie、session 等等 * 2、路由中间件,单个/部分路由会执行的中间件,比如某个路由的前置校验,数据处理等等 他们之间的关系一般为: ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01oQZ5Rk1jReqck6YMn_!!6000000004545-2-tps-2350-584.png) ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 在写完中间件之后,我们需要把它应用到各个控制器路由之上。 `@Controller` 装饰器的第二个参数,可以让我们方便的在某个路由分组之上添加中间件。 ``` import { Controller } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; @Controller('/', { middleware: [ ReportMiddleware ] }) export class HomeController { } ``` Midway 同时也在 `@Get` 、 `@Post` 等路由装饰器上都提供了 middleware 参数,方便对单个路由做中间件拦截。 ``` import { Controller, Get } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; @Controller('/') export class HomeController { @Get('/', { middleware: [ ReportMiddleware ]}) async home() { } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 所谓的全局中间件,就是对所有的路由生效的 Web 中间件。 我们需要在应用启动前,加入当前框架的中间件列表中,`useMiddleware` 方法,可以把中间件加入到中间件列表中。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 你可以同时添加多个中间件。 ``` async onReady() { this.app.useMiddleware([ReportMiddleware1, ReportMiddleware2]); } ``` ## 忽略和匹配路由[​](#忽略和匹配路由 "忽略和匹配路由的直接链接") 在中间件执行时,我们可以添加路由忽略的逻辑。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... }; } ignore(ctx: Context): boolean { // 下面的路由将忽略此中间件 return ctx.path === '/' || ctx.path === '/api/auth' || ctx.path === '/api/login'; } static getName(): string { return 'report'; } } ``` 同理,也可以添加匹配的路由,只有匹配到的路由才会执行该中间件。`ignore` 和 `match` 同时只有一个会生效。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... }; } match(ctx: Context): boolean { // 下面的匹配到的路由会执行此中间件 if (ctx.path === '/api/index') { return true; } } static getName(): string { return 'report'; } } ``` 除此之外,`match` 和 `ignore` 还可以是普通字符串或者正则,以及他们的数组形式。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { // 字符串 match = '/api/index'; // 正则 match = /^\/api/; // 数组 match = ['/api/index', '/api/user', /^\/openapi/, ctx => { if (ctx.path === '/api/index') { return true; } }]; } ``` 我们也可以在初始化阶段对属性进行修改,比如: ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { // 某个中间件的配置 @Config('report') reportConfig; @Init() async init() { // 动态合并一些规则 if (this.reportConfig.match) { this.match = ['/api/index', '/api/user'].concat(this.reportConfig.match); } else if (this.reportConfig.ignore) { this.match = [].concat(this.reportConfig.ignore); } } } ``` ## 复用中间件[​](#复用中间件 "复用中间件的直接链接") 中间件的本质是函数,函数可以传递不同的配置来复用中间件,但是在 class 场景下较难实现。Midway 提供了 `createMiddleware` 方法辅助 class 场景下创建不同的中间件函数。 可以在 `useMiddleware` 阶段使用 `createMiddleare` 复用。 ``` // src/configuration.ts import { App, Configuration, createMiddleare } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // 添加 ReportMiddleware 中间件 this.app.useMiddleware(ReportMiddleware); // 添加一个不同参数的 ReportMiddleware this.app.useMiddleware(createMiddleare(ReportMiddleware, { text: 'abc' }, 'anotherReportMiddleare')); } } ``` 我们可以在中间件中获取到这个参数,从而执行不同的逻辑,。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { initData = 'text1'; resolve(_, options?: { text: string; }) { return async (ctx: Context, next: NextFunction) => { this.ctx.setAttr('data', options?.text || this.initData); return await next(); }; } } ``` `createMiddleare` 方法定义如下,包含三个参数。 ``` function createMiddleware(middlewareClass: new (...args) => IMiddleware, options, name?: string); ``` | 参数 | 描述 | | --------------- | ---------------- | | middlewareClass | 中间件类 | | options | 传递的自定义参数 | | name | 可选,中间件名称 | `options` 可以传递中间件的自定义函数,在逻辑中可以自行进行处理。 `name` 字段用于中间件的排序和展示,一般会选择一个和原中间件名不同的字符串。 `createMiddleare` 方法还可以在路由中间件使用。 ``` import { Controller, Get, createMiddleware } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; const anotherMiddleware = createMiddleware(ReportMiddleware, { // ... }); @Controller('/') export class HomeController { @Get('/', { middleware: [anotherMiddleware], }) async home() {} } ``` 注意,装饰器会在框架启动前加载,这个时候 `createMiddleware` 的参数无法从框架配置中获取,一般为固定的对象值。 ## 函数中间件[​](#函数中间件 "函数中间件的直接链接") Midway 依旧支持函数中间件的形式,并且可以使用 `useMiddleware` 来加入到中间件列表。 ``` // src/middleware/another.middleware.ts export async function fnMiddleware(ctx, next) { // ... await next(); // ... } // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; import { fnMiddleware } from './middleware/another.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // add middleware this.app.useMiddleware([ReportMiddleware, fnMiddleware]); } } ``` 这样的话,社区很多 koa 三方中间件都可以比较方便的接入。 ## 使用社区中间件[​](#使用社区中间件 "使用社区中间件的直接链接") 我们以 `koa-static` 举例。 在 `koa-static` 文档中,是这样写的。 ``` const Koa = require('koa'); const app = new Koa(); app.use(require('koa-static')(root, opts)); ``` 那么, `require('koa-static')(root, opts)` 这个,其实就是返回的中间件方法,我们直接导出,并且调用 `useMiddleware` 即可。 ``` async onReady() { // add middleware this.app.useMiddleware(require('koa-static')(root, opts)); } ``` 如果中间件支持在路由上引入,比如: ``` const Koa = require('koa'); const app = new Koa(); app.get('/controller', require('koa-static')(root, opts)); ``` 我们也可以将中间件看成普通函数,放在装饰器参数中。 ``` const staticMiddleware = require('koa-static')(root, opts); // ... class HomeController { @Get('/controller', {middleware: [staticMiddleware]}) async getMethod() { // ... } } ``` 也可以作为作为路由方法体使用。 ``` const staticMiddleware = require('koa-static')(root, opts); // ... class HomeController { @Get('/controller') async getMethod(ctx, next) { // ... return staticMiddleware(ctx, next); } } ``` 提示 三方中间件写法有很多种,上面只是列出最基本的使用方式。 ## 获取中间件名[​](#获取中间件名 "获取中间件名的直接链接") 每个中间件应当有一个名字,默认情况下,类中间件的名字将依照下面的规则获取: * 1、当 `getName()` 静态方法存在时,以其返回值作为名字 * 2、如果不存在 `getName()` 静态方法,将使用类名作为中间件名 一个好认的中间件名在手动排序或者调试代码时有很大的作用。 ``` @Middleware() export class ReportMiddleware implements IMiddleware { // ... static getName(): string { return 'report'; // 中间件名 } } ``` 函数中间件也是类似,定义的方法名就是中间件的名字,比如下面的 `fnMiddleware` 。 ``` export async function fnMiddleware(ctx, next) { // ... await next(); // ... } ``` 假如三方中间件导出了一个匿名的中间件函数,那么你可以使用 `_name` 来添加一个名字。 ``` const fn = async (ctx, next) => { // ... await next(); // ... }; fn._name = 'fnMiddleware'; ``` 我们可以使用 `getMiddleware().getNames()` 来获取当前中间件列表中的所有中间件名。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; import { fnMiddleware } from './middleware/another.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // add middleware this.app.useMiddleware([ReportMiddleware, fnMiddleware]); // output console.log(this.app.getMiddleware().getNames()); // => report, fnMiddleware } } ``` ## 中间件顺序[​](#中间件顺序 "中间件顺序的直接链接") 有时候,我们需要在组件或者应用中修改中间件的顺序。 Midway 提供了 `insert` 系列的 API,方便用户快速调整中间件。 我们需要先使用 `getMiddleware()` 方法获取中间件列表,然后对其进行操作。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // 把中间件添加到最前面 this.app.getMiddleware().insertFirst(ReportMiddleware); // 把中间件添加到最后面,等价于 useMiddleware this.app.getMiddleware().insertLast(ReportMiddleware); // 把中间件添加到名为 session 的中间件之后 this.app.getMiddleware().insertAfter(ReportMiddleware, 'session'); // 把中间件添加到名为 session 的中间件之前 this.app.getMiddleware().insertBefore(ReportMiddleware, 'session'); } } ``` ## 常见示例[​](#常见示例 "常见示例的直接链接") ### 中间件中获取请求作用域实例[​](#中间件中获取请求作用域实例 "中间件中获取请求作用域实例的直接链接") 由于 Web 中间件在生命周期的特殊性,会在应用请求前就被加载(绑定)到路由上,所以无法和请求关联。中间件类的作用域 **固定为单例(Singleton)**。 由于 **中间件实例为单例**,所以中间件中注入的实例和请求不绑定,**无法获取到 ctx**,无法使用 `@Inject()` 注入请求作用域的实例,只能获取 Singleton 的实例。 比如,**下面的代码是错误的。** ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { @Inject() userService; // 这里注入的实例和上下文不绑定,无法获取到 ctx resolve() { return async (ctx: Context, next: NextFunction) => { // TODO await next(); }; } } ``` 如果要获取请求作用域的实例,可以使用从请求作用域容器 `ctx.requestContext` 中获取,如下面的方法。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const userService = await ctx.requestContext.getAsync(UserService); // TODO userService.xxxx await next(); }; } } ``` ### 统一返回数据结构[​](#统一返回数据结构 "统一返回数据结构的直接链接") 比如在 `/api` 返回的所有数据都是用统一的结构,减少 Controller 中的重复代码。 我们可以增加一个类似下面的中间件代码。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class FormatMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const result = await next(); return { code: 0, msg: 'OK', data: result, } }; } match(ctx) { return ctx.path.indexOf('/api') !== -1; } } ``` 上面的仅是正确逻辑返回的代码,如需错误的返回包裹,可以使用 [过滤器](/docs/3.0.0/error_filter.md)。 ### 关于中间件返回 null 的情况[​](#关于中间件返回-null-的情况 "关于中间件返回 null 的情况的直接链接") 在 koa/egg 下,如果中间件中返回 null 值,会使得状态码变为 204,如果需要返回其他状态码(如 200),需要在中间件中显式额外赋值状态码。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class FormatMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const result = await next(); if (result === null) { ctx.status = 200; } return { code: 0, msg: 'OK', data: result, } }; } match(ctx) { return ctx.path.indexOf('/api') !== -1; } } ``` --- # 使用组件 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 ## 启用组件[​](#启用组件 "启用组件的直接链接") 组件一般以 npm 包形式进行复用。每个组件都是一个可以被直接 `require` 的代码包。我们以 `@midwayjs/validate` 组件为例。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "@midwayjs/validate": "^3.0.0" } } ``` 我们需要在代码中启用这个组件,Midway 的组件加载能力设计在 `src/configuration.ts` 文件中。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as validate from '@midwayjs/validate'; @Configuration({ imports: [validate], }) export class MainConfiguration {} ``` ## 不同环境启用组件[​](#不同环境启用组件 "不同环境启用组件的直接链接") 有时候,我们需要在特殊环境下才使用组件,比如本地开发时。 `imports` 属性可以传入对象数组,我们可以在对象中针对组件启用的环境进行配置。 比如常用的 `info` 组件,为了安全考虑,我们就可以只让他在本地环境启用。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ { component: info, enabledEnvironment: ['local'], }, ], }) export class MainConfiguration {} ``` * `component` 用于指定组件对象,组件对象必须包含一个 `Configuration` 导出的属性 * `enabledEnvironment` 组件启用的环境数组 ## 开发组件[​](#开发组件 "开发组件的直接链接") 参见文档:[组件开发](/docs/3.0.0/component_development.md)。 --- # 关于 Midway 启动慢的问题 Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 一般 Mac 都是 SSD,所以基本没有问题,而 Windows 会有出现,构建后执行无此问题。 如下图所示。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523014939-40121f9c-bc19-4f9e-a7e6-e744d409a9ea.png) ## 如何判断[​](#如何判断 "如何判断的直接链接") 1、先清理下 ts-node 缓存。 在临时目录中有一个 `ts-node-*` 的目录,删除即可(不知道临时目录的可以在命令行执行 `require('os').tmpdir()` 输出查看)。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523402032-7e9c162a-762e-4cba-82b4-8ae63fe37280.png) 删了下面类似的这个目录。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523340452-7924affe-96b5-4544-85b7-e41ace4206e8.png) 2、用 ts-node 启动 Midway 执行下面的启动命令。 ``` // midway v1 cross-env DEBUG=midway* NODE_ENV=local midway-bin dev --ts // midway v2 cross-env NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 会出现每个文件的 require 时长,如果时间比较久一般就是了。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523470970-1812326a-39d9-4b39-af57-7723f80f6e17.png) ## 解决问题[​](#解决问题 "解决问题的直接链接") 由于 `TS_NODE_TYPE_CHECK` 内部会启动一个 Server,在文件特别的多的情况下,每次 require 都会做类型检查,如果造成严重启动影响,建议关闭。**代价是启动运行时不会做类型校验,由于一般在编辑器里已经有提示,运行时不再做检查也可以。** 在执行命令前增加下面两个环境变量。 ``` TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true ``` 比如: ``` cross-env TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 下面是使用相同的项目的对比效果。 | | 第一次执行(无缓存) | 第二次执行(有缓存) | | ------------ | -------------------- | -------------------- | | 不加优化参数 | 约 258s | 约 5.6s | | 加优化参数 | 约 15s | 约 4.7s | | | | | ## 其他[​](#其他 "其他的直接链接") 如果任有问题,请提交你的仓库 + node\_modules 给我们。 --- # 数据模拟 Midway 提供了内置的在开发和测试时模拟数据的能力。 ## 测试时 Mock[​](#测试时-mock "测试时 Mock的直接链接") `@midwayjs/mock` 提供了一些更为通用的 API,用于在测试时进行模拟。 ### 模拟上下文[​](#模拟上下文 "模拟上下文的直接链接") 使用 `mockContext` 方法来模拟上下文。 ``` import { mockContext } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); // 模拟上下文 mockContext(app, 'user', 'midway'); const result1 = await createHttpRequest(app).get('/'); // ctx.user => midway // ... }); ``` 如果你的数据比较复杂,或者带有逻辑,也可以使用回调形式。 ``` import { mockContext } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); // 模拟上下文 mockContext(app, (ctx) => { ctx.user = 'midway'; }); }); ``` 注意,这个 mock 行为是在所有中间件之前执行。 ### 模拟 Session[​](#模拟-session "模拟 Session的直接链接") 使用 `mockSession` 方法来模拟 Session。 ``` import { mockSession } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); mockSession(app, 'user', 'midway'); const result1 = await createHttpRequest(app).get('/'); // ctx.session.user => midway // ... }); ``` ### 模拟 Header[​](#模拟-header "模拟 Header的直接链接") 使用 `mockHeader` 方法来模拟 Header。 ``` import { mockHeader } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); mockHeader(app, 'x-abc', 'bbb'); const result1 = await createHttpRequest(app).get('/'); // ctx.headers['x-abc'] => bbb // ... }); ``` ### 模拟类属性[​](#模拟类属性 "模拟类属性的直接链接") 使用 `mockClassProperty` 方法来模拟类的属性。 假如有下面的服务类。 ``` @Provide() export class UserService { data; async getUser() { return 'hello'; } } ``` 我们可以在使用时进行模拟。 ``` import { mockClassProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { mockClassProperty(UserService, 'data', { bbb: 1 }); // userService.data => {bbb: 1} // ... }); ``` 也可以模拟方法。 ``` import { mockClassProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); // userService.getUser() => 'midway' // ... }); ``` ### 模拟普通对象属性[​](#模拟普通对象属性 "模拟普通对象属性的直接链接") 使用 `mockProperty` 方法来模拟对象的属性。 ``` import { mockProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const a = {}; mockProperty(a, 'name', 'hello'); // a['name'] => 'hello' // ... }); ``` 也可以模拟方法。 ``` import { mockProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const a = {}; mockProperty(a, 'getUser', async () => { return 'midway'; }); // a.getUser() => 'midway' // ... }); ``` ### 分组[​](#分组 "分组的直接链接") 从 `3.19.0` 开始,Midway 的 mock 功能支持通过分组来管理不同的 mock 数据。你可以在创建 mock 时指定一个分组名称,这样可以在需要时单独恢复或清理某个分组的 mock 数据。 ``` import { mockContext, restoreMocks } from '@midwayjs/mock'; it('should test mock with groups', async () => { const app = await createApp(); // 创建普通对象的 mock const a = {}; mockProperty(a, 'getUser', async () => { return 'midway'; }, 'group1'); // 创建上下文的 mock mockContext(app, 'user', 'midway', 'group1'); mockContext(app, 'role', 'admin', 'group2'); // 恢复单个分组 restoreMocks('group1'); // 恢复所有分组 restoreAllMocks(); }); ``` 通过分组,你可以更灵活地管理和控制 mock 数据,特别是在复杂的测试场景中。 ### 清理 mock[​](#清理-mock "清理 mock的直接链接") 在每次调用 `close` 方法时,会自动清理所有的 mock 数据。 如果希望手动清理,也可以执行方法 `restoreAllMocks` 。 ``` import { restoreAllMocks } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { restoreAllMocks(); // ... }); ``` 从 `3.19.0` 开始,支持指定 group 清理。 ``` import { restoreMocks } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { restoreMocks('group1');(); // ... }); ``` ## 标准 Mock 服务[​](#标准-mock-服务 "标准 Mock 服务的直接链接") Midway 提供了标准的 MidwayMockService 服务,用于在代码中进行模拟数据。 `@midwayjs/mock` 中的各种模拟方法,底层皆调用了此服务。 具体 API 请参考 [内置服务](/docs/3.0.0/built_in_service.md#midwaymockservice) ## 开发期 Mock[​](#开发期-mock "开发期 Mock的直接链接") 每当后端服务没有上线,或者在开发阶段未准备好数据的时候,就需要用到开发期模拟的能力。 ### 编写模拟类[​](#编写模拟类 "编写模拟类的直接链接") 一般情况下,我们会在 `src/mock` 文件夹中编写开发期使用的模拟数据,我们的模拟行为实际是一段逻辑代码。 提示 不要对模拟数据放在代码中不习惯,事实上它是逻辑的一部分。 我们举个例子,假如现在有一个获取 Index 数据的服务,但是服务还未开发完毕,我们只能编写模拟代码。 ``` // src/service/indexData.service.ts import { Singleton, makeHttpRequest, Singleton } from '@midwayjs/core'; @Singleton() export class IndexDataService { @Config('index') indexConfig: {indexUrl: string}; private indexData; async load() { // 从远端获取数据 this.indexData = await this.fetchIndex(this.indexConfig.indexUrl); } public getData() { if (!this.indexData) { // 数据不存在,就加载一次 this.load(); } return this.indexData; } async fetchIndex(url) { return makeHttpRequest>(url, { method: 'GET', dataType: 'json', }); } } ``` 提示 上面的代码,故意抽离了 `fetchIndex` 方法,用来方便后续的模拟行为。 当接口未开发完毕的时候,我们本地开发就很困难,常见的做法是定义一份 JSON 数据, 比如,创建一个 `src/mock/indexData.mock.ts` ,用于初始化的服务接口模拟。 ``` // src/mock/indexData.mock.ts import { Mock, ISimulation } from '@midwayjs/core'; @Mock() export class IndexDataMock implements ISimulation { } ``` `@Mock` 用于代表它是一个模拟类,用于模拟一些业务行为,`ISimulation` 是需要业务实现的一些接口。 比如,我们要模拟接口的数据。 ``` // src/mock/indexData.mock.ts import { App, IMidwayApplication, Inject, Mock, ISimulation, MidwayMockService } from '@midwayjs/core'; import { IndexDataService } from '../service/indexData.service'; @Mock() export class IndexDataMock implements ISimulation { @App() app: IMidwayApplication; @Inject() mockService: MidwayMockService; async setup(): Promise { // 使用 MidwayMockService API 模拟属性 this.mockService.mockClassProperty(IndexDataService, 'fetchIndex', async (url) => { // 根据逻辑返回不同的数据 if (/current/.test(url)) { return { data: require('./resource/current.json'), }; } else if (/v7/.test(url)) { return { data: require('./resource/v7.json'), }; } else if (/v6/.test(url)) { return { data: require('./resource/v6.json'), }; } }); } enableCondition(): boolean | Promise { // 模拟类启用的条件 return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` 上面的代码中,`enableCondition` 是必须实现的方法,代表当前模拟类的启用条件,比如上面的代码仅在 `local` ,`test` 和 `unittest` 环境下生效。 ### 模拟时机[​](#模拟时机 "模拟时机的直接链接") 模拟类包含一些模拟的时机,都已经定义在 `ISimulation` 接口中,比如: ``` export interface ISimulation { /** * 最开始的模拟时机,在生命周期 onConfigLoad 之后执行 */ setup?(): Promise; /** * 在生命周期关闭时执行,一般用于数据清理 */ tearDown?(): Promise; /** * 在每种框架初始化时执行,会传递当前框架的 app */ appSetup?(app: IMidwayApplication): Promise; /** * 在每种框架的请求开始时执行,会传递当前框架的 app 和 ctx */ contextSetup?(ctx: IMidwayContext, app: IMidwayApplication): Promise; /** * 每种框架的请求结束时执行,在错误处理之后 */ contextTearDown?(ctx: IMidwayContext, app: IMidwayApplication): Promise; /** * 每种框架的停止时执行 */ appTearDown?(app: IMidwayApplication): Promise; /** * 模拟的执行条件,一般是特定环境,或者特定框架下 */ enableCondition(): boolean | Promise; } ``` 基于上面的接口,我们实现非常自由的模拟逻辑。 比如,在不同的框架上添加不同的中间件。 ``` import { App, IMidwayApplication, Mock, ISimulation } from '@midwayjs/core'; @Mock() export class InitDataMock implements ISimulation { @App() app: IMidwayApplication; async appSetup(app: IMidwayApplication): Promise { // 针对不同的框架类型,添加不同的测试中间件 if (app.getNamespace() === 'koa') { app.useMiddleware(/*...*/); app.useFilter(/*...*/); } if (app.getNamespace() === 'bull') { app.useMiddleware(/*...*/); app.useFilter(/*...*/); } } enableCondition(): boolean | Promise { return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` --- # 服务器启动失败排查 应用启动失败是非常常见的现象,逻辑错误,编译错误,配置错误,环境问题,都有可能导致你的项目无法启动。 ## 快速定位代码问题[​](#快速定位代码问题 "快速定位代码问题的直接链接") 大多数情况下,我们说的启动失败一般都是服务器环境启动失败,下面以 Linux 为例。 1、使用 `ps aux | grep node` 检查进程是否存在,进程数量是否正确 2、打开 [项目的日志目录](/docs/logger_v3.md#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95),查看 `common-error.log` 文件的内容,根据最新的堆栈来排查原因 3、启动的控制台日志,比如 `pm2 logs` 相关的信息 大多数问题都会在日志中发现,请尽可能养成登录机器查看日志的习惯,这是开发者必备的技能。 ## 可能的环境问题[​](#可能的环境问题 "可能的环境问题的直接链接") 除了代码本身的问题之外,环境可能也会带来一些问题,这些问题查起来就比较困难,往往和系统,权限,环境变量,启动参数,网络环境,甚至内核本身有关系。 下面列举一些可能的情况。 ### 1、文件不完整或不是最新[​](#1文件不完整或不是最新 "1、文件不完整或不是最新的直接链接") 确保的你的项目在部署前执行过以下的流程 * 1、使用 `npm run dev` 或者类似命令本地启动并运行成功 * 2、使用 `npm run build` 已经将 ts 文件编译为 js 文件,在根目录生成出 `dist` 目录 * 3、使用 `npm run start` 在本地使用 js 文件执行成功 检查服务器上的文件,目录结构是否完整,比如: * 1、`node_modules` 目录是否存在 * 2、`dist` 目录以及其中的 js 文件是否存在,或者为最新 ### 2、启动用户的权限问题[​](#2启动用户的权限问题 "2、启动用户的权限问题的直接链接") 我们一般会使用一个普通账户来执行,比如 admin 账户,而不是使用 sudo 去部署。 * 1、检查用户是否用创建目录,启动 node 的权限 * 2、检查项目的服务端日志目录是否有写入的权限 ### 3、启动端口冲突[​](#3启动端口冲突 "3、启动端口冲突的直接链接") 如果你启动了多个 Node.js 项目,如果使用了相同的端口,那么就会抛出端口重复使用的错误。 --- # 管道 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: * 1、数据的校验 * 2、参数的转换 ## 组件提供的管道[​](#组件提供的管道 "组件提供的管道的直接链接") `@midwayjs/validate` 默认提供了验证管道,只需要启用组件即可使用。 例如: ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO ) { // ... } } ``` `@Body` 装饰器已经被自动注册了 `ValidatePipe` ,如果 `UserDTO` 是一个已经经过 `@Rule` 装饰器修饰的 DTO,会自动校验并转换。 如果使用了基础类型,则也可以通过数据转换管道进行校验和转换。 例如: ``` import { ParseIntPipe } from '@midwayjs/validate'; @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number ) { // ... } } ``` `ParseIntPipe` 管道可以将字符串,数字数据转换为数字,这样从请求参数获取到的 `age` 字段则会通过管道的校验并转换为数字格式。 除此之外,还提供了 `ParseBoolPipe` ,`ParseFloatPipe` 等更多数据转换管道,具体请查看 [Validate 组件](/docs/3.0.0/extensions/validate.md)。 ## 自定义管道[​](#自定义管道 "自定义管道的直接链接") 管道可以是一个实现 `PipeTransform` 接口的类或者方法,我们一般将管道放在 `src/pipe` 目录。 比如: ``` // src/pipe/validate.pipe.ts import { Pipe, PipeTransform, TransformOptions } from '@midwayjs/core'; @Pipe() export class ValidatePipe implements PipeTransform { transform(value: T, options: TransformOptions): R { return value; } } ``` `PipeTransform` 是每个管道必须要实现的泛型接口。泛型 `T` 表明输入的 `value` 的类型,`R` 表明 `transfrom()` 方法的返回类型。 为实现 `PipeTransfrom`,每个管道必须声明 `transfrom()` 方法。该方法有两个参数: * `value` * `options` `value` 是当前处理的参数值,`options` 是当前处理的选项,包含以下属性。 ``` export TransformOptions { metaType: TSDesignType; metadata: Record; target: any; methodName: string; } ``` | 参数 | 描述 | | ---------- | ----------------------------------------------------------------------------------- | | metaType | 一个 ts 元数据类型的解析对象,包含 `name` 、`originDesign`、`isBaseType` 三个属性。 | | metadata | 参数装饰器的元数据对象 | | target | 当前装饰的实例本身 | | methodName | 当前参数装饰器装饰器的方法名 | ## 绑定管道[​](#绑定管道 "绑定管道的直接链接") 管道必须依附在参数装饰器上使用。 在自定义装饰器的选项中,我们可以透传管道参数达到应用管道的目的。 例如我们自定义一个 `RegValid` 参数装饰器,用于传入正则和另一个管道参数: ``` import { PipeUnionTransform, createCustomParamDecorator } from '@midwayjs/core'; function RegValid(reg: RegExp, pipe: PipeUnionTransform) { return createCustomParamDecorator('reg-valid', { reg, }, { // ... pipes: [pipe] }); } ``` `createCustomParamDecorator` 的第三个参数支持传入一个 `pipes` 属性,我们需要将管道传入其中,这样管道就会和装饰器绑定,在后续的运行中自动执行。 具体可以查询 [自定义装饰器](/docs/3.0.0/custom_decorator.md) 中的参数装饰器章节。 `RegValid` 装饰器用于正则的校验,实现部分我们暂时忽略。 另外,我们再定义一个管道用于截取数据。 ``` @Pipe() export class CutPipe implements PipeTransform { transform(value: number, options: TransformOptions): string { return String(value).slice(5); } } ``` 现在我们可以使用他们了。 ``` class UserService { async invoke(@RegValid(/\d{11}/, CutPipe) phoneNumber: string) { return phoneNumber; } } invoke(13712345678) => '345678' ``` ## 默认绑定的管道[​](#默认绑定的管道 "默认绑定的管道的直接链接") 假如我们希望向一个现成的参数装饰器能拥有管道能力,但是不希望该装饰器有管道参数。 就像内置的 `@Query` 等装饰器,没有管道参数,却可以在 validate 组件启用时自动执行管道逻辑。 我们使用 `decoratorService` 提供的反向注册 API,这在跨组件提供能力时非常有用。 我们以上面编写的 `RegValid` 为例。 ``` @Configuration({ // ... }) export class MainConfiguration { @Inject() decoratorService: MidwayDecoratorService; async onReady(container: IMidwayContainer) { // register default pipe this.decoratorService.registerParameterPipes('reg-valid', [ CutPipe, ]); } } ``` `registerParameterPipes` 方法用于向某一种参数装饰器隐式注册一些管道,上述实例中,`reg-valid` 是自定义参数的 key,通过 key 我们可以向这个参数装饰器注册。 这些管道会在显式传入的管道之前被默认执行。 这样在使用时,即使我们不传递管道参数,也依旧会执行管道。 ``` class UserService { async invoke(@RegValid(/\d{11}/) phoneNumber: string) { return phoneNumber; } } invoke(13712345678) => '345678' ``` --- # 流程控制 有些场景下,我们希望把一个完整的任务拆分成不同的阶段,每个阶段执行的逻辑相对独立,同时又可以通过并行或者串行的方式提升整体的执行效率。在 Midway 中我们实现了一个优化的 Pipeline 模式。 ## Pipeline[​](#pipeline "Pipeline的直接链接") 在 Node.js 的 Stream 实现中,可以使用 `a.pipe(b).pipe(c).pipe(d)` 这样,把多个 Stream 串连起来。但是这样只能顺序执行的 pipe 实现不一定能够满足不同的业务场景。 在 Midway 中我们使用 `@Pipeline` 装饰器,可以创建一个继承与 `IPipelineHandler` 接口的实例,可以将多个 `IValveHandler` 实例串联起来执行。 `IValveHandler` 就是具体的任务阶段执行单位。整个 IPipelineHandler 执行方式可以是 parallel、series、concat、waterfall (很熟悉是吧?我们参考了 [async](https://github.com/caolan/async) 库提供的方法能力命名)。 Pipeline 执行时期的上下文 IPipelineContext 可以用来存储 Pipeline 入参、上一次 IValveHandler 实例的执行结果、上一次的中间产物等等,提供了非常大的灵活性。 ## 类型定义[​](#类型定义 "类型定义的直接链接") ### IPipelineHandler[​](#ipipelinehandler "IPipelineHandler的直接链接") ``` interface IPipelineHandler { /** * 并行执行,使用 Promise.all * @param opts 执行参数 */ parallel(opts: IPipelineOptions): Promise>; /** * 并行执行,最终 result 为数组 * @param opts 执行参数 */ concat(opts: IPipelineOptions): Promise>; /** * 串行执行,使用 foreach await * @param opts 执行参数 */ series(opts: IPipelineOptions): Promise>; /** * 串行执行,使用 foreach await,最终 result 为数组 * @param opts 执行参数 */ concatSeries(opts: IPipelineOptions): Promise>; /** * 串行执行,但是会把前者执行结果当成入参,传入到下一个执行中去,最后一个执行的 valve 结果会被返回 * @param opts 执行参数 */ waterfall(opts: IPipelineOptions): Promise>; } ``` * 白名单机制 使用 Pipeline 装饰器时,如果填写了数组参数,那么方法执行函数中的 valves 入参只能是装饰器数组参数中的项。当然,valves 是可选项,不填默认就以装饰器数组参数为准。例如,`@Pipeline(['a', 'b', 'c'])` 那么 series 等执行函数中可选参数 `opts.valves` 数组必须是 `['a', 'b', 'c']` 或者其子集,如果不填则以 `['a', 'b', 'c']` 逻辑顺序来执行。 ### 返回结果[​](#返回结果 "返回结果的直接链接") IPipelineResult 的类型如下。 ``` /** * pipeline 执行返回结果 */ export interface IPipelineResult { /** * 是否成功 */ success: boolean; /** * 异常信息(如果有则返回) */ error?: { /** * 异常出在那个 valve 上 */ valveName?: string; /** * 异常信息 */ message?: string; /** * 原始 Error */ error?: Error; }; /** * 返回结果 */ result: T; } ``` ## 使用举例[​](#使用举例 "使用举例的直接链接") 1. 假设有这样一个场景,我们需要一次性获取页面上的数据信息、当前用户信息以及有几个 Tab。那么我们先声明返回的数据类型 ``` class VideoDto { videoId: string; videoUrl: string; videoTitle: string; } class AccountDto { id: string; nick: string; isFollow: boolean; } class TabDto { tabId: string; title: string; index: number; } interface HomepageDto { videos: VideoDto[]; account: AccountDto; tab: TabDto; } ``` 2. 实现一个 TestService 来封装一下返回的这些数据 ``` @Provide() class TestService { // 返回当前登录用户信息 async getAccount(args: any): Promise { return { id: 'test_account_id', nick: 'test hello', isFollow: true, }; } // 返回视屏列表 async getVideos(args: any): Promise { return [{ videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video' }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video' }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video' }]; } // 返回tab页面 async getTab(args: any): Promise { return { title: 'test tab', tabId: 'firstTab', index: 0 }; } } ``` 3. 将几个任务封装拆分成不同的 IValveHandler 实现 ``` // 返回视屏信息的 @Provide() class VideoFeeds implements IValveHandler { alias = 'videos'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { return this.service.getVideos(ctx.args); } } // 返回账户信息的 @Provide() class AccountMap implements IValveHandler { alias = 'account'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 return this.service.getAccount(ctx.args); } } // 返回tab信息的 @Provide() class CrowFeeds implements IValveHandler { alias = 'tab'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 return this.service.getTab(ctx.args); } } // 捕捉整个错误异常的 @Provide() class ErrorFeeds implements IValveHandler { alias = 'tab'; @Inject() service: TestService; async invoke(ctx: IPipelineContext): Promise { // 获取数据执行逻辑 throw new Error('this is error feeds'); } } ``` ### parallel[​](#parallel "parallel的直接链接") 通过该方法执行的结果,最终返回的是一个 object 对象,且每个 IValveHandler 实现 alias 作为对象返回值的 key ``` class StageTest { // 这里声明一个 pipeline @Pipeline([VideoFeeds, AccountMap, CrowFeeds]) stages: IPipelineHandler; async runParallel(): Promise { // 这里并发执行 videoFeeds、accountMap、crowFeeds return this.stages.parallel({ args: {aa: 123} }); // 返回的 result 结构 /* { // 以 accountMap 的 alias account 作为返回对象的 key account: { id: 'test_account_id', nick: 'test hello', isFollow: true, }, // 以 videoFeeds 的 alias video 作为返回对象的 key video: [ { videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video' }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video' }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video' } ], // 以 crowFeeds 的 alias tab 作为返回对象的 key tab: { title: 'test tab', tabId: 'firstTab', index: 0 } } */ } } ``` ### concat[​](#concat "concat的直接链接") 执行方式同 parallel 只不过最终返回结果 result 是一个数组 ``` class StageTest { // 这里声明一个 pipeline @Pipeline([VideoFeeds, AccountMap, CrowFeeds]) stages: IPipelineHandler; async runConcat(): Promise { // 这里并发执行 videoFeeds、accountMap、crowFeeds return this.stages.concat({ args: {aa: 123} }); // 这里返回的 result 是一个数组 /* [ // 以 videoFeeds 作为第一个返回对象 [ { videoId: '123', videoUrl: 'https://www.taobao.com/xxx.mp4', videoTitle: 'test 1 video' }, { videoId: '234', videoUrl: 'https://www.taobao.com/xxx234.mp4', videoTitle: 'test 2 video' }, { videoId: '456', videoUrl: 'https://www.taobao.com/xxx456.mp4', videoTitle: 'test 3 video' } ], // 以 accountMap 作为第二个返回对象 { id: 'test_account_id', nick: 'test hello', isFollow: true, }, // 以 crowFeeds 作为第三个返回对象 { title: 'test tab', tabId: 'firstTab', index: 0 } ] */ } } ``` ### series[​](#series "series的直接链接") 这里 series 是串行执行,按照 Pipeline 装饰器参数顺序,一个一个执行下去,且 IPipelienContext 中的 prev 就是前一个 valve,current 是当前,next 即下一个即将执行的 valve ``` class StageTest { // 这里声明一个 pipeline @Pipeline([VideoFeeds, AccountMap, CrowFeeds]) stages: IPipelineHandler; async runSeries(): Promise { // 这里串行执行 videoFeeds、accountMap、crowFeeds return this.stages.series({ args: {aa: 123} }); // 这里返回的 result 是一个对象,结果同 parallel 返回的对象拼装规则 } } ``` ### concatSeries[​](#concatseries "concatSeries的直接链接") 原理同 series,只不过返回结果是一个数组 ``` class StageTest { // 这里声明一个 pipeline @Pipeline([VideoFeeds, AccountMap, CrowFeeds]) stages: IPipelineHandler; async runConcatSeries(): Promise { // 这里串行执行 videoFeeds、accountMap、crowFeeds return this.stages.concatSeries({ args: {aa: 123} }); // 这里返回的 result 是一个数组,同 concat 返回对象拼装 } } ``` ### waterfall[​](#waterfall "waterfall的直接链接") 串行执行,最终只返回最后一个 valve 执行结果 ``` @Provide() class StageOne implements IValveHandler { async invoke(ctx: IPipelineContext): Promise { if (ctx.args.aa !== 123) { throw new Error('args aa is undefined'); } ctx.set('stageone', 'this is stage one'); ctx.set('stageone_date', Date.now()); if (ctx.info.current !== 'stageOne') { throw new Error('current stage is not stageOne'); } if (ctx.info.next !== 'stageTwo') { throw new Error('next stage is not stageTwo'); } if (ctx.info.prev) { throw new Error('stageOne prev stage is not undefined'); } return 'stageone'; } } @Provide() class StageTwo implements IValveHandler { async invoke(ctx: IPipelineContext): Promise { const keys = ctx.keys(); if (keys.length !== 2) { throw new Error('keys is not equal'); } ctx.set('stagetwo', ctx.get('stageone') + 1); ctx.set('stagetwo_date', Date.now()); // 验证是否是执行 stageOne 返回的结果 if (ctx.info.prevValue !== 'stageone') { throw new Error('stageone result empty'); } if (ctx.info.current !== 'stageTwo') { throw new Error('current stage is not stageTwo'); } if (ctx.info.next) { throw new Error('stageTwo next stage is not undefined'); } if (ctx.info.prev !== 'stageOne') { throw new Error('prev stage is not stageOne'); } return 'stagetwo'; } } class StageTest { // 这里声明一个 pipeline @Pipeline([StageOne, StageTwo]) stages: IPipelineHandler; async runStagesWaterfall(): Promise { // 这里通过串行方式执行,可以看到 stageTwo 中做了校验,prevValue 即 stageOne 执行的结果 return this.stages.waterfall({ args: {aa: 123} }); } } ``` --- # 快速入门 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 ## 环境准备[​](#环境准备 "环境准备的直接链接") * 操作系统:支持 macOS,Linux,Windows * 运行环境:[Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C) ## 初始化项目[​](#初始化项目 "初始化项目的直接链接") 我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目。 ``` $ npm init midway@latest -y ``` 选择 `koa-v3` 项目进行初始化创建,项目名可以自定,比如 `weather-sample`。 现在可以启动应用来体验下。 ``` $ npm run dev $ open http://localhost:7001 ``` 同时,我们也提供了完整的实例,可以在 `npm init midway` 之后,选择 `quick-start` 项目,创建即可,方便对照学习。 ## 编写 Controller[​](#编写-controller "编写 Controller的直接链接") 如果你熟悉 Web 开发或 MVC,就知道第一步我们需要编写 [Controller 和 Router](/docs/3.0.0/controller.md)。 在脚手架创建的文件中,我们已经有了一些文件,我们暂时忽略他们。 在 `controller` 目录中,新建一个 `src/controller/weather.controller.ts` 文件,内容如下。 ``` import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class WeatherController { // 这里是装饰器,定义一个路由 @Get('/weather') async getWeatherInfo(): Promise { // 这里是 http 的返回,可以直接返回字符串,数字,JSON,Buffer 等 return 'Hello Weather!'; } } ``` 现在我们可以通过访问 `/weather` 接口返回数据了。 ## 添加参数处理[​](#添加参数处理 "添加参数处理的直接链接") 在示例中,我们需要一个 URL 参数来动态展示不同城市的天气。 通过添加 `@Query` 装饰器,我们可以获取到 URL 上的参数。 ``` import { Controller, Get, Query } from '@midwayjs/core'; @Controller('/') export class WeatherController { @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { return cityId; } } ``` 除了 `@Query` 装饰器,Midway 也提供了其他请求参数的获取,可以查看 [路由和控制](/docs/3.0.0/controller.md) 文档。 ## 编写 Service[​](#编写-service "编写 Service的直接链接") 在实际项目中,Controller 一般用来接收请求参数,校验参数,不会包括特别复杂的逻辑,复杂而复用的逻辑,我们应该封装为 Service 文件。 我们来添加一个 Service 用来获取天气信息,其中包括一个 http 请求,获取远端的数据。 代码如下: ``` // src/service/weather.service.ts import { Provide, makeHttpRequest } from '@midwayjs/core'; @Provide() export class WeatherService { async getWeather(cityId: string) { return makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); } } ``` 信息 * 1、`makeHttpRequest` 方法是 Midway 内置的 http 请求方法,更多参数请查看 [文档](/docs/3.0.0/extensions/axios.md) 然后我们来添加定义,良好的类型定义可以帮助我们减少代码错误。 在 `src/interface.ts` 文件中,我们增加天气信息的数据定义。 ``` // src/interface.ts // ... export interface WeatherInfo { weatherinfo: { city: string; cityid: string; temp: string; WD: string; WS: string; SD: string; AP: string; njd: string; WSE: string; time: string; sm: string; isRadar: string; Radar: string; } } ``` 这样,我们就可以在 Service 中进行标注了。 ``` import { Provide, makeHttpRequest } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; @Provide() export class WeatherService { async getWeather(cityId: string): Promise { const result = await makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); if (result.status === 200) { return result.data as WeatherInfo; } } } ``` 信息 * 1、这里使用 `@Provide` 装饰器修饰类,便于后续 Controller 注入该类 同时,我们修改下之前的 Controller 文件。 ``` import { Controller, Get, Inject, Query } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; import { WeatherService } from '../service/weather.service'; @Controller('/') export class WeatherController { @Inject() weatherService: WeatherService; @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { return this.weatherService.getWeather(cityId); } } ``` 信息 * 1、这里使用 `@Inject` 装饰器注入 `WeatherService`,是 Midway 依赖注入的标准用法,可以查看 [这里](/docs/3.0.0/service.md) 了解更多 * 2、这里也同步修改了方法的返回值类型 到这里,我们可以请求 `http://127.0.0.1:7001/weather?cityId=101010100` 查看返回的结果。 你的第一个 Midway 接口已经开发完成了,你可以在前端代码中直接调用了,接下去,我们将利用这个接口完成一个服务端渲染的页面。 ## 模板渲染[​](#模板渲染 "模板渲染的直接链接") 从这里开始,我们需要用到一些 Midway 的扩展能力。 Midway 对应的扩展包我们称为 “组件”,也是标准的 npm 包。 这里我们需要用到 `@midwayjs/view-nunjucks` 组件。 可以使用下面的命令安装。 ``` $ npm i @midwayjs/view-nunjucks --save ``` 安装完成后,我们在 `src/configuration.ts` 文件中启用组件。 ``` // ... import * as view from '@midwayjs/view-nunjucks'; @Configuration({ imports: [ koa, // ... view ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { // ... } ``` 信息 * 1、`configuration` 文件是 Midway 的生命周期入口文件,承担了组件开关,配置加载和生命周期管理的作用 * 2、`imports` 就使用来导入(开启)组件的方法 在 `src/config/config.default.ts` 中配置组件,指定为 `nunjucks` 模板。 ``` import { MidwayConfig } from '@midwayjs/core'; export default { // ... view: { defaultViewEngine: 'nunjucks', }, } as MidwayConfig; ``` 在根目录(非 src 里)添加模板 `view/info.html` 文件,内容如下: ``` 天气预报

{{city}}({{WD}}{{WS}})

{{temp}}

气压

湿度

``` 同时,我们调整 Controller 的代码,将返回 JSON 变为模板渲染。 ``` // src/controller/weather.controller.ts import { Controller, Get, Inject, Query } from '@midwayjs/core'; import { WeatherService } from '../service/weather.service'; import { Context } from '@midwayjs/koa'; @Controller('/') export class WeatherController { @Inject() weatherService: WeatherService; @Inject() ctx: Context; @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { const result = await this.weatherService.getWeather(cityId); if (result) { await this.ctx.render('info', result.weatherinfo); } } } ``` 到这一步,我们访问 `http://127.0.0.1:7001/weather?cityId=101010100` 已经可以看到渲染的模板内容了。 ## 错误处理[​](#错误处理 "错误处理的直接链接") 别忘了,我们还有一些异常的逻辑需要处理。 一般来说,每个对外的调用都需要做异常捕获,并且将异常转变为我们自己业务的错误,这样才能有更好的体验。 为此,我们需要定义一个我们自己的业务错误,创建一个 `src/error/weather.error.ts` 文件。 ``` // src/error/weather.error.ts import { MidwayError } from '@midwayjs/core'; export class WeatherEmptyDataError extends MidwayError { constructor(err?: Error) { super('weather data is empty', { cause: err, }); if (err?.stack) { this.stack = err.stack; } } } ``` 然后,我们调整 Service 代码抛出异常。 ``` // src/service/weather.service.ts import { Provide, makeHttpRequest } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; import { WeatherEmptyDataError } from '../error/weather.error'; @Provide() export class WeatherService { async getWeather(cityId: string): Promise { if (!cityId) { throw new WeatherEmptyDataError(); } try { const result = await makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); if (result.status === 200) { return result.data as WeatherInfo; } } catch (error) { throw new WeatherEmptyDataError(error); } } } ``` 信息 * 1、将 http 的调用请求进行错误捕获,将错误包裹,返回一个我们系统的业务错误 * 2、如有必要,我们可以定义更多的错误,分配错误 Code 等 到这一步,我们还需要将异常进行业务处理,比如有多个位置抛出 `WeatherEmptyDataError` 时,我们需要统一的格式返回。 错误处理器可以完成这个功能,我们需要创建一个 `src/filter/weather.filter.ts` 文件,内容如下: ``` //src/filter/weather.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { WeatherEmptyDataError } from '../error/weather.error'; @Catch(WeatherEmptyDataError) export class WeatherErrorFilter { async catch(err: WeatherEmptyDataError, ctx: Context) { ctx.logger.error(err); return '

weather data is empty

'; } } ``` 然后应用到当前的框架中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { WeatherErrorFilter } from './filter/weather.filter'; // ... @Configuration({ // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... // add filter this.app.useFilter([WeatherErrorFilter]); } } ``` 这样,当每次请求中获取到了 `WeatherEmptyDataError` 错误,会使用相同的返回值返回给浏览器,同时会在日志中记录原始的错误信息。 异常处理的更多信息,可以查阅 [文档](/docs/3.0.0/error_filter.md)。 ## 数据模拟[​](#数据模拟 "数据模拟的直接链接") 在编写代码时,我们的接口经常还处在无法使用的阶段,为了尽可能降低影响,可以使用模拟数据来代替。 比如我们的天气接口,就可以在本地和测试环境模拟掉。 我们需要创建一个 `src/mock/data.mock.ts` 文件,内容如下: ``` // src/mock/data.mock.ts import { Mock, ISimulation, App, Inject, IMidwayApplication, MidwayMockService, } from '@midwayjs/core'; import { WeatherService } from '../service/weather.service'; @Mock() export class WeatherDataMock implements ISimulation { @App() app: IMidwayApplication; @Inject() mockService: MidwayMockService; async setup(): Promise { const originMethod = WeatherService.prototype.getWeather; this.mockService.mockClassProperty( WeatherService, 'getWeather', async cityId => { if (cityId === '101010100') { return { weatherinfo: { city: '北京', cityid: '101010100', temp: '27.9', WD: '南风', WS: '小于3级', SD: '28%', AP: '1002hPa', njd: '暂无实况', WSE: '<3', time: '17:55', sm: '2.1', isRadar: '1', Radar: 'JC_RADAR_AZ9010_JB', }, }; } else { return originMethod.apply(this, [cityId]); } } ); } enableCondition(): boolean | Promise { // 模拟类启用的条件 return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` `WeatherDataMock` 类用于模拟天气数据,其中的 `setup` 方法,用于实际的初始化模拟,其中,我们使用了内置的 `MidwayMockService` 的 `mockClassProperty` 方法,将 `WeatherService` 的 `getWeather` 方法模拟掉。 在模拟过程中,我们仅仅将单个城市的数据进行了处理,其他依旧走了原来的接口。 `enableCondition` 用于标识这个模拟类在哪些场景下生效,比如我们上面的代码就仅在本地和测试环境生效。 这样,当本地开发和测试时,我们请求 `101010100` 的数据,将直接被拦截和返回,且在部署到服务器环境后,也不会受到影响。 数据模拟还有更多的接口可以使用,可以查阅 [文档](/docs/3.0.0/mock.md)。 ## 单元测试[​](#单元测试 "单元测试的直接链接") Midway 默认使用 jest 作为基础的测试框架,一般我们的测试文件会放在根目录的 `test` 目录中,以 `*.test.ts` 作为后缀。 比如我们要测试编写的 `/weather` 接口。 我们需要测试它的成功和失败两种状态。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/koa'; describe('test/controller/weather.test.ts', () => { let app: Application; beforeAll(async () => { // create app app = await createApp(); }); afterAll(async () => { // close app await close(app); }); it('should test /weather with success request', async () => { // make request const result = await createHttpRequest(app).get('/weather').query({ cityId: 101010100 }); expect(result.status).toBe(200); expect(result.text).toMatch(/北京/); }); it('should test /weather with fail request', async () => { const result = await createHttpRequest(app).get('/weather'); expect(result.status).toBe(200); expect(result.text).toMatch(/weather data is empty/); }); }); ``` 执行测试: ``` $ npm run test ``` 就这么简单,更多请参见 [测试](/docs/3.0.0/testing.md)。 信息 * 1、jest 测试时,以单文件作为单位,使用 `beforeAll` 和 `afterAll` 控制 app 的启停 * 2、使用 `createHttpRequest` 来创建一个测试请求 * 3、使用 expect 来断言返回的结果是否符合预期 ## 继续学习[​](#继续学习 "继续学习的直接链接") 恭喜你,你对 Midway 已经有了一些初步的认识,我们来简单的回顾一下。 * 1、我们使用 `npm init midway` 来创建了示例 * 2、使用 `@Controller` 装饰器定义路由和控制器类 * 3、使用 `@Query` 获取请求参数 * 4、使用 `@Provide` 和 `@Inject` 注入服务类 * 5、使用 `imports` 启用组件,并配置了 nunjucks 模板 * 6、自定义了错误,并使用错误过滤器来拦截错误,返回自定义的数据 * 7、使用 jest 创建了测试,添加了成功和失败的测试用例 以上的这些,仅仅是 Midway 的一小部分内容,随着使用的深入,会使用到更多的能力。 你可以从 [创建](/docs/3.0.0/quickstart.md) 开始,去选择 Midway 不同场景下的解决方案,也可以继续深入 [路由和控制器](/docs/3.0.0/controller.md) 的部分,增加一些请求方法,也可以了解 [Web 中间件](/docs/3.0.0/middleware.md) 或者 [依赖注入](/docs/3.0.0/container.md) 相关的知识。 --- # 创建第一个应用 ## 技术选型[​](#技术选型 "技术选型的直接链接") Midway 有多套技术方案可以选择,我们以部署的方式来做区分: | 技术选型 | 描述 | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | 纯 Node.js 项目 | Midway 传统项目,纯 Node.js 研发,以 `@midwayjs/koa` 为代表的模块,最完整的支持后端项目,采用 **依赖注入 + Class** 为技术栈。 | | Serverless 项目 | Midway 为 Serverless 场景单独开发的技术栈,以 `@midwayjs/faas` 为代表的模块,使用轻量的方式接入不同的 Serverless 平台。 | | 一体化项目 | Midway 创新技术方案,采用前后端一体化开发方式,节省前后端联调时间,以 `@midwayjs/hooks` 为代表的模块,使用 **函数式** 为主要编码范式。 | 提示 本章节及后续的文档将以 **纯 Node.js 项目** 作为基础示例,如需使用 Serverless 项目,请跳转到 [Serverless](/docs/3.0.0/serverless/serverless_intro.md),如需了解一体化项目,请访问 [一体化](/docs/3.0.0/hooks/intro.md) 。 ## 快速初始化[​](#快速初始化 "快速初始化的直接链接") 使用 `npm init midway` 查看完整的脚手架列表,选中某个项目后,Midway 会自动创建示例目录,代码,以及安装依赖。 ``` $ npm init midway@latest -y ``` 针对 v3 项目,请选择 `koa-v3`,注意 [Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C)。 示例将创建一个类似下面的目录结构,其中最精简的 Midway 项目示例如下。 ``` ➜ my_midway_app tree . ├── src ## midway 项目源码 │ └── controller ## Web Controller 目录 │ └── home.controller.ts ├── test ├── package.json └── tsconfig.json ``` 整个项目包括了一些最基本的文件和目录。 * `src` 整个 Midway 项目的源码目录,你之后所有的开发源码都将存放于此 * `test` 项目的测试目录,之后所有的代码测试文件都在这里 * `package.json` Node.js 项目基础的包管理配置文件 * `tsconfig.json` TypeScript 编译配置文件 除了整个目录,我们还有一些其他的目录,比如 `controller` 目录。 ## 开发习惯[​](#开发习惯 "开发习惯的直接链接") Midway 对目录没有特别的限制,但是我们会遵守一些简单的开发习惯,将一部分常用的文件进行归类,放到一些默认的文件夹中。 以下 ts 源码文件夹均在 `src` 目录下。 常用的有: * `controller` Web Controller 目录 * `middleware` 中间件目录 * `filter` 过滤器目录 * `aspect` 拦截器 * `service` 服务逻辑目录 * `entity` 或 `model` 数据库实体目录 * `config` 业务的配置目录 * `util` 工具类存放的目录 * `decorator` 自定义装饰器目录 * `interface.ts` 业务的 ts 定义文件 随着不同场景的出现,目录的习惯也会不断的增加,具体的目录内容会体现在不同的组件功能中。 ## Web 框架选择[​](#web-框架选择 "Web 框架选择的直接链接") Midway 设计之初就可以兼容多种上层框架,比如常见的 `Express`、`Koa` 和 `EggJS` 。 从 v3 开始,我们使用 Koa 来做基础示例的演示。 这些上层框架在 Midway 中都以组件的能力提供,都可以使用 Midway 提供的装饰器能力,但是 Midway 不会对特有的能力做出封装,比如 Egg.js 的插件体系,或者 Express 的中间件能力,如果你对其中的某个框架比较熟悉,或者希望使用特定框架的能力,就可以选择它作为你的主力 Web 框架。 | 名称 | 描述 | | ----------------- | --------------------------------------------------------------------------------------------------------- | | @midwayjs/koa | 默认,Koa 是一个 Express 的替代框架,它默认支持了异步中间件等能力,是第二大通用的 Node.js Web 框架。 | | @midwayjs/web | Egg.js 是国内相对常用的 Web 框架,包含一些默认插件。 | | @midwayjs/express | Express 是一个众所周知的 node.js 简约 Web 框架。 这是一个经过实战考验,适用于生产的库,拥有大量社区资源。 | 如果你希望替代默认的 Web 框架,请参考对应的 [egg](/docs/3.0.0/extensions/egg.md) 或者 [express](/docs/3.0.0/extensions/express.md) 章节。 ## 启动项目[​](#启动项目 "启动项目的直接链接") ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 `http://127.0.0.1:7001` ,浏览器会打印出 `Hello midwayjs!` 的信息。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01KoUxO91jydMw41Vv4_!!6000000004617-2-tps-1268-768.png) 如果需要修改开发的启动端口,可以在 `package.json` 的 scripts 段落里修改,如修改为 6001: * 使用 mwtsc * 使用 @midwayjs/cli ``` "scripts": { //... "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js --port 6001", }, ``` ``` "scripts": { //... "dev": "cross-env NODE_ENV=local midway-bin dev --ts --port=6001", }, ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### windows eslint 报错[​](#windows-eslint-报错 "windows eslint 报错的直接链接") 警告 Windows 可能会碰到 eslint 报错的问题,请关注 [windows 下换行问题](/docs/3.0.0/faq/git_problem.md#XCAgm)。 --- # Midway 维护计划 下表是 Midway 整体的维护节奏和计划。 | Release | Status | Initial Release | Active LTS Start | Maintenance LTS Start | End-of-life | | -------------------- | ------------------- | --------------- | ---------------- | --------------------- | ----------- | | midway v1(inner v6) | **End-of-Life** | 2018-06-14 | 2018-10 | 2020-04 | 2022-04 | | midway v2(inner v7) | **End-of-Life** | 2020-10 | 2021-02 | 2021-10 | 2024-04 | | midway v3(inner v8) | **Maintenance LTS** | 2022-01 | 2022-06 | 2023-10 | | | midway v4(inner v9) | **Development** | | | | | --- # Application 和 Context Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 比如我们前面示例中的 `@midwayjs/koa` ,就是一个提供 Http 服务的组件,下面我们将以这个组件为例,来介绍内置对象。 每个使用的 Web 框架会提供自己独特的能力,这些独特的能力都会体现在各自的 **上下文**(Context)和 **应用**(Application)之上。 ## 定义约定[​](#定义约定 "定义约定的直接链接") 为了简化使用,所有的暴露协议的组件会导出 **上下文**(Context)和 **应用**(Application)定义,我们都保持一致。即 `Context` 和 `Application` 。 比如: ``` import { Application, Context } from '@midwayjs/koa'; import { Application, Context } from '@midwayjs/faas'; import { Application, Context } from '@midwayjs/web'; import { Application, Context } from '@midwayjs/express'; ``` 且非 Web 框架,我们也保持了一致。 ``` import { Application, Context } from '@midwayjs/socketio'; import { Application, Context } from '@midwayjs/grpc'; import { Application, Context } from '@midwayjs/rabbitmq'; ``` ## Application[​](#application "Application的直接链接") Application 是某一个组件中的应用对象,在不同的组件中,可能有着不同的实现。Application 对象上会包含一些统一的方法,这些方法统一来自于 `IMidwayApplication` 定义。 ``` import { Application } from '@midwayjs/koa'; ``` ### 获取方式[​](#获取方式 "获取方式的直接链接") 在所有被依赖注入容器管理的类中,都可以使用 `@App()` 装饰器来获取 **当前最主要** 的 Application。 比如: ``` import { App, Controller, Get } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; @Controller('/') export class HomeController { @App() app: Application; @Get('/') async home() { // this.app.getConfig() // this.app.getEnv() } } ``` ### Main Application[​](#main-application "Main Application的直接链接") Midway 应用对外暴露的协议是组件带来的,每个组件都会暴露自己协议对应的 Application 对象。 这就意味着在一个应用中会包含多个 Application,我们默认约定,在 `src/configuration.ts` 中第一个引入的 Application 即为 **Main Application** (**主要的 Application**)。 比如,下面的 koa 中的 Application 实例即为 **Main Application** (**主要的 Application**)。 ``` // src/configuration.ts import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws] }) export class MainConfiguration implements ILifeCycle { // ... } ``` 事实上 Application 都实现与 `IMidwayApplication` 接口,如果使用通用的 API,没有差别。 成为 Main Application 稍微有一些优势: * 在大部分的场景下,使用 `@App()` 即可注入获取,无需其他参数 * 优先初始化 比如在多个导出 Application 组件需要加载中间件的情况下,可以简单的编码。 ``` // src/configuration.ts import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws] }) export class MainConfiguration implements ILifeCycle { @App() koaApp: koa.Application; @App('webSocket') wsApp: ws.Application; async onReady() { this.koaApp.useMiddleweare(...); this.wsApp.useMiddleweare(...); } } ``` 非主要的 Application,需要通过 `@App()` 装饰器的参数或者 [ApplicationManager](/docs/3.0.0/built_in_service.md#midwayapplicationmanager) 来获取。 `@App()` 装饰器的参数为组件的 `namespace`。 常见的 namespace 如下: | Package | Namespace | | ------------------ | --------- | | @midwayjs/web | egg | | @midwayjs/koa | koa | | @midwayjs/express | express | | @midwayjs/grpc | gRPC | | @midwayjs/ws | webSocket | | @midwayjs/socketio | socketIO | | @midwayjs/faas | faas | | @midwayjs/kafka | kafka | | @midwayjs/rabbitmq | rabbitMQ | | @midwayjs/bull | bull | ### getAppDir[​](#getappdir "getAppDir的直接链接") 用于获取项目根目录路径。 ``` this.app.getAppDir(); // => /my_project ``` ### getBaseDir[​](#getbasedir "getBaseDir的直接链接") 用于获取项目 TypeScript 基础路径,默认开发中为 `src` 目录,编译后为 `dist` 目录。 ``` this.app.getBaseDir(); // => /my_project/src ``` ### getEnv[​](#getenv "getEnv的直接链接") 获取当前项目环境。 ``` this.app.getEnv(); // => production ``` ### getApplicationContext[​](#getapplicationcontext "getApplicationContext的直接链接") 获取当前全局依赖注入容器。 ``` this.app.getApplicationContext(); ``` ### getConfig[​](#getconfig "getConfig的直接链接") 获取配置。 ``` // 获取所有配置 this.app.getConfig(); // 获取特定 key 配置 this.app.getConfig('koa'); // 获取多级配置 this.app.getConfig('midwayLoggers.default.dir'); ``` ### getLogger[​](#getlogger "getLogger的直接链接") 获取某个 Logger,不传参数,默认返回 appLogger。 ``` this.app.getLogger(); // => app logger this.app.getLogger('custom'); // => custom logger ``` ### getCoreLogger[​](#getcorelogger "getCoreLogger的直接链接") 获取 Core Logger。 ``` this.app.getCoreLogger(); ``` ### getProjectName[​](#getprojectname "getProjectName的直接链接") 获取项目名,一般从 `package.json` 中获取。 ### setAttr & getAttr[​](#setattr--getattr "setAttr & getAttr的直接链接") 直接在 Application 上挂载一个对象会导致定义和维护的困难。 在大多数情况下,用户需要的是临时的全局数据存储的方式,比如在一个应用或者组件内部跨文件临时存取一个数据,从一个类保存,另一个类获取。 为此 Midway 提供了一个全局数据存取的 API,解决这类需求。 ``` this.app.setAttr('abc', { a: 1, b: 2, }); ``` 在另一个地方获取即可。 ``` const value = this.app.getAttr('abc'); console.log(value); // { a: 1, b: 2 } ``` ### getNamespace[​](#getnamespace "getNamespace的直接链接") 通过 `getNamespace` API ,可以获取到当前 app 归属的组件的 [框架的类型](#main-application)(即组件的 `namespace`)。 比如在 `koa` 组件中。 ``` this.app.getNamespace(); // 'koa' ``` ## Context[​](#context "Context的直接链接") Context 是一个**请求级别的对象**,在每一次收到用户请求时,框架会实例化一个 Context 对象, 在 Http 场景中,这个对象封装了这次用户请求的信息,或者其他获取请求参数,设置响应信息的方法,在 WebSocket,Rabbitmq 等场景中,Context 也有各自的属性,以框架的定义为准。 下面的 API 是每个上下文实现通用的属性或者接口。 ### 获取方式[​](#获取方式-1 "获取方式的直接链接") 在 \*\*默认的请求作用域 \*\*中,也就是说在 控制器(Controller)或者普通的服务(Service)中,我们可以使用 `@Inject` 来注入对应的实例。 比如可以这样获取到对应的 ctx 实例。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // ... } } ``` 由于 `ctx` 是一个框架内置 ctx 实例关键字,如果你希望用不同的属性名,也可以通过修改装饰器参数。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject('ctx') customContextName: Context; @Get('/') async home() { // ... } } ``` 如果一个服务可以被多个上层框架调用,由于不同框架提供的 ctx 类型不同,可以通过类型组合来解决。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { Context as BullContext } from '@midwayjs/bull'; @Provide() export class UserService { @Inject() ctx: Context & BullContext; async getUser() { // ... } } ``` 除了显式声明外,在拦截器或者装饰器设计的时候,由于我们无法得知用户是否写了 ctx 属性,还可以通过内置的 `REQUEST_OBJ_CTX_KEY` 字段来获取。 比如: ``` import { Inject, Controller, Get, REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { ctx.logger.info(this.ctx === this[REQUEST_OBJ_CTX_KEY]); // => true } } ``` ### requestContext[​](#requestcontext "requestContext的直接链接") Midway 会为每个 Context 挂载一个 `requestContext` 属性,即请求作用域下的依赖注入容器,用来创建请求作用域下的对象。 ``` const userService = await this.ctx.requestContext.getAsync(UserService); // ... ``` ### logger[​](#logger "logger的直接链接") 请求作用域下的默认 logger 对象,包含上下文数据。 ``` this.ctx.logger.info('xxxx'); ``` ### startTime[​](#starttime "startTime的直接链接") 上下文执行开始的时间。 ``` this.ctx.startTime // 1642820640502 ``` ### setAttr & getAttr[​](#setattr--getattr-1 "setAttr & getAttr的直接链接") 和 `app` 上的方法相同,这些方法的数据是保存在请求链路中,随着请求销毁,你可以在其中放一些请求的临时数据。 ``` this.ctx.setAttr('abc', { a: 1, b: 2, }); ``` 在另一个地方获取即可。 ``` const value = this.ctx.getAttr('abc'); console.log(value); // { a: 1, b: 2 } ``` ### getLogger[​](#getlogger-1 "getLogger的直接链接") 获取某个自定义 Logger 对应的上下文日志。 ``` this.ctx.getLogger('custom'); // => custom logger ``` ### getApp[​](#getapp "getApp的直接链接") 从 ctx 上获取当前框架类型的 app 对象。 ``` const app = this.ctx.getApp(); // app.getConfig(); ``` --- # 重试机制 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 很多时候,我们在某些容易失败,或者异步的方法调用上,需要多次使用 `try` 去包裹函数,同时处理错误。 比如: ``` // 定义了一个异步函数 async function invoke(id) { // 一些远程调用逻辑 } async invokeNew() { let error; try { return await invoke(1); } catch(err) { error = err; } try { return await invoke(2); } catch(err) { error = err; } if (error) { // .... } } ``` 我们可能会尝试多次调用 `invoke`执行,同时配合 try/catch 的异常捕获,导致业务代码写起来重复且冗长。 ## 定义重试函数[​](#定义重试函数 "定义重试函数的直接链接") 我们可以使用 `retryWithAsync`方法进行包裹,简化整个流程。 ``` import { retryWithAsync } from '@midwayjs/core'; async function invoke(id) { // ... } async function someServiceMethod() { // 默认调用,加上重试两次,最多执行三次 const invokeNew = retryWithAsync(invoke, 2); try { return await invokeNew(1); } catch(err) { // err } } ``` 包裹后的方法参数和返回值,和原有方法完全一致。 当在重试周期内调用成功,未抛出错误,则会将成功的返回值返回。 如果失败,则会抛出 `MidwayRetryExceededMaxTimesError` 异常。 如果在类中使用,可能要注意 `this` 的指向。 示例如下: ``` import { retryWithAsync } from '@midwayjs/core'; export class UserService { async getUserData(userId: string) { // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote, 2, { receiver: this, } ); // invoke return getUserDataOrigin(userId); } async getUserDataFromRemote(userId: string) { // get data from remote } } ``` ## this 绑定[​](#this-绑定 "this 绑定的直接链接") 从 Midway v3.5.1 起,增加了一个 `receiver` 参数,用于在类的场景下绑定 this,用于处理: * 1、方法正确的 this 指向 * 2、包裹方法定义的正确性 ``` // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote, 2, { receiver: this, // 此参数用于处理 this 指向 } ); ``` 如果没有该参数,代码需要写成下面的样子才能绑定 this,同时返回的 `getUserDataOrigin` 方法的定义才正确。 ``` // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote.bind(this) as typeof this.getUserDataFromRemote, 2, { receiver: this, } ); ``` ## 重试次数[​](#重试次数 "重试次数的直接链接") `retryWithAsync` 提供了第二个参数,用于声明额外的重试次数,默认为 1(仅重试一次)。 这个值指代的是在默认调用后,额外重试的次数。 ## 同步的重试[​](#同步的重试 "同步的重试的直接链接") 和 `retryWithAsync` 类似,我们也提供了 `retryWith` 这个同步方法,参数和 `retryWithAsync` 几乎相同,不再额外描述。 ## 重试延迟[​](#重试延迟 "重试延迟的直接链接") 为了避免频繁重试对服务端造成压力,可以设置重试的间隔。 比如: ``` const invokeNew = retryWithAsync(invoke, 2, { retryInterval: 2000, // 执行失败后,2s 后继续重试 }); ``` 提示 同步方法 `retryWith` 没有该属性。 ## 抛出的错误[​](#抛出的错误 "抛出的错误的直接链接") 默认情况下,如果超过重试次数,则会抛出 `MidwayRetryExceededMaxTimesError` 异常。 `MidwayRetryExceededMaxTimesError` 是框架默认的异常,可以进行错误过滤器的捕获梳理,或者从其属性中拿到原始的异常进行处理。 ``` import { retryWithAsync, MidwayRetryExceededMaxTimesError } from '@midwayjs/core'; async function invoke(id) { // ... } async function someServiceMethod() { // 默认调用,加上重试两次,最多执行三次 const invokeNew = retryWithAsync(invoke, 2); try { return await invokeNew(1); } catch(err) { // err.name === 'MidwayRetryExceededMaxTimesError' // err.cause instanceof CustomError => true } } async invokeNew() { throw new CustomError('customError'); } ``` 如果希望直接抛出原始的 error 对象,可以通过配置参数。 比如: ``` const invokeNew = retryWithAsync(invoke, 2, { throwOriginError: true, }); ``` --- # Web 路由表 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 从 v3.4.0 开始,路由服务将作为 Midway 内置服务提供。 在应用启动,onReady 生命周期以及之后可用。 ## 获取路由表服务[​](#获取路由表服务 "获取路由表服务的直接链接") 已默认实例化,可以直接注入使用。 ``` import { Configuration, Inject, MidwayWebRouterService, MidwayServerlessFunctionService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { // Web 路由 const routes = await this.webRouterService.getFlattenRouterTable(); // serverless 函数 const routes = await this.serverlessFunctionService.getFunctionList(); } } ``` `MidwayServerlessFunctionService` 仅在 Serverless 场景下生效,方法和 `MidwayWebRouterService` 几乎相同。 ## 路由信息定义[​](#路由信息定义 "路由信息定义的直接链接") 每个路由信息由一个 `RouterInfo` 定义表示,包含一些属性。 定义如下: ``` export interface RouterInfo { /** * router prefix */ prefix: string; /** * router alias name */ routerName: string; /** * router path, without prefix */ url: string | RegExp; /** * request method for http, like get/post/delete */ requestMethod: string; /** * invoke function method */ method: string; description: string; summary: string; /** * router handler function key,for IoC container load */ handlerName: string; /** * serverless func load key */ funcHandlerName: string; /** * controller provideId */ controllerId: string; /** * router middleware */ middleware: any[]; /** * controller middleware in this router */ controllerMiddleware: any[]; /** * request args metadata */ requestMetadata: any[]; /** * response data metadata */ responseMetadata: any[]; } ``` | 属性 | 类型 | 描述 | | -------------------- | --------- | --------------------------------------------------------------- | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | routerName | string | 路由名 | | url | string | 路由的去除路由前缀的部分,也是用户写在 @Get 等装饰器上的部分 | | requestMethod | string | get/post/delete/put/all 等 | | method | string | 实际调用的类上的方法名 | | description | string | 描述,路由装饰器上的参数 | | summary | string | 摘要,路由装饰器上的参数 | | handlerName | string | 等价于 controllerId.method | | funcHandlerName | string | 使用 @Func 写的 handler 名字 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | middleware | string\[] | 路由中间件字符串数组 | | controllerMiddleware | string\[] | 控制器中间件字符串数组 | | requestMetadata | any\[] | 请求参数的元数据,@Query/@Body 等元数据 | | responseMetadata | any\[] | 响应参数的元数据,@SetHeader/@ContentType 等元数据 | ## 路由优先级[​](#路由优先级 "路由优先级的直接链接") 以往我们需要关心路由的加载顺序,比如通配的 `/*` 比如在实际的 `/abc` 之后,否则会加载到错误的路由。在新版本中,我们对此种情况做了自动排序。 规则如下: * 1. 绝对路径规则优先级最高如 `/ab/cb/e` * 2. 星号只能出现最后且必须在/后面,如 `/ab/cb/**` * 3. 如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高 * 4. 有多个通配能匹配一个路径时,最长的规则匹配,如 `/ab/**` 和 `/ab/cd/**` 在匹配 `/ab/cd/f` 时命中 `/ab/cd/**` * 5. 如果 `/` 与 `/*` 都能匹配 / ,但 `/` 的优先级高于 `/*` 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如,排序完的优先级如下(高到低): ``` /api/invoke/abc /api/invoke/* /api/abc /api/* /abc /* ``` ## 当前匹配的路由[​](#当前匹配的路由 "当前匹配的路由的直接链接") 通过 `getMatchedRouterInfo` 方法,我们可以知道当前的路由,匹配到哪个路由信息(RouterInfo),从而进一步处理,这个逻辑在鉴权等场景很有用。 比如,在中间件中,我们可以在进入控制器之前提前判断。 ``` import { Middleware, Inject, httpError, MidwayWebRouterService } from '@midwayjs/core'; @Middleware() export class AuthMiddleware { @Inject() webRouterService: MidwayWebRouterService; resolve() { return async (ctx, next) => { // 查询当前路由是否在路由表中注册 const routeInfo = await this.webRouterService.getMatchedRouterInfo(ctx.path, ctx.method); if (routeInfo) { await next(); } else { throw new httpError.NotFoundError(); } } } } ``` ## 路由信息[​](#路由信息 "路由信息的直接链接") ### 获取扁平化路由列表[​](#获取扁平化路由列表 "获取扁平化路由列表的直接链接") 获取当前所有可注册到 HTTP 服务的路由列表(包括 @Func/@Controller,以及一切按照标准信息注册的自定义装饰器)。 会按照优先级从高到低自动排序。 定义: ``` async getFlattenRouterTable(): Promise ``` 获取路由表 API。 ``` const result = await this.webRouterService.getFlattenRouterTable(); ``` 输出示例: ``` [ { "prefix": "/", "routerName": "", "url": "/set_header", "requestMethod": "get", "method": "homeSet", "description": "", "summary": "", "handlerName": "apiController.homeSet", "funcHandlerName": "apiController.homeSet", "controllerId": "apiController", "middleware": [], "controllerMiddleware": [], "requestMetadata": [], "responseMetadata": [ { "type": "web:response_header", "setHeaders": { "ccc": "ddd" } }, { "type": "web:response_header", "setHeaders": { "bbb": "aaa" } } ], }, { "prefix": "/", "routerName": "", "url": "/ctx-body", "requestMethod": "get", "method": "getCtxBody", "description": "", "summary": "", "handlerName": "apiController.getCtxBody", "funcHandlerName": "apiController.getCtxBody", "controllerId": "apiController", "middleware": [], "controllerMiddleware": [], "requestMetadata": [], "responseMetadata": [], }, // ... ] ``` ### 获取 Router 信息列表[​](#获取-router-信息列表 "获取 Router 信息列表的直接链接") 在 Midway 中,每个 Controller 对应一个 Router 对象,每个 Router 都会有一个路由前缀(prefix),在此之中的所有路由都会按照上面的规则进行排序。 Router 本身也会按照 prefix 进行排序。 定义: ``` export interface RouterPriority { prefix: string; priority: number; middleware: any[]; routerOptions: any; controllerId: string; } async getRoutePriorityList(): Promise ``` Router 的数据相对简单。 | 属性 | 类型 | 描述 | | ------------- | --------- | ------------------------------------------------------------------------------ | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | priority | number | Router 的优先级,@Priority 装饰器填写的值,/ 根 Router 默认优先级最低,为 -999 | | middleware | string\[] | 控制器中间件字符串数组 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | routerOptions | any | @Controller 装饰器的 options | 获取路由表 API。 ``` const list = await collector.getRoutePriorityList(); ``` 输出示例: ``` [ { "prefix": "/case", "priority": 0, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "caseController" }, { "prefix": "/user", "priority": 0, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "userController" }, { "prefix": "/", "priority": -999, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "apiController" } ] ``` ### 获取带层级的路由[​](#获取带层级的路由 "获取带层级的路由的直接链接") 某些情况下,我们需要拿到带层级的路由,包括哪些路由在哪个控制器(Controller)下,这样能更好的创建路由。 Midway 也提供了获取带层级的路由表方法。层级内会按照优先级从高到低自动排序。 定义: ``` async getRouterTable(): Promise> ``` 获取层级路由表 API,返回的是个 Map,key 为控制器的路由前缀 prefix 字符串。未明确写明路由前缀的(比如函数或者其他场景),都将归为 / 路由前缀下。 ``` const result = await collector.getRouterTable(); ``` 输出示例: ``` Map(3) { '/' => [ { prefix: '/', routerName: '', url: '/set_header', requestMethod: 'get', method: 'homeSet', description: '', summary: '', handlerName: 'apiController.homeSet', funcHandlerName: 'apiController.homeSet', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [Array], }, { prefix: '/', routerName: '', url: '/ctx-body', requestMethod: 'get', method: 'getCtxBody', description: '', summary: '', handlerName: 'apiController.getCtxBody', funcHandlerName: 'apiController.getCtxBody', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [], }, // ... ] } ``` ### 获取所有函数信息[​](#获取所有函数信息 "获取所有函数信息的直接链接") 和 `getFlattenRouterTable` 相同,只是返回的内容多了函数部分的信息。 定义: ``` async getFunctionList(): Promise ``` 获取函数路由表 API。 ``` const result = await this.serverlessFunctionService.getFunctionList(); ``` ## 添加路由[​](#添加路由 "添加路由的直接链接") ### 动态添加 Web 控制器[​](#动态添加-web-控制器 "动态添加 Web 控制器的直接链接") 有些时候我们希望根据某些条件动态的添加一个控制器,就可以使用这个方法。 首先,我们需要有一个控制器类,但是不使用 `@Controller` 装饰器修饰。 ``` import { Get, Provide } from '@midwayjs/core'; // 注意这里未使用 @Controller 修饰 @Provide() export class DataController { @Get('/query_data') async getData() { return 'hello world'; } } ``` 我们可以通过 `addController` 方法动态添加它。 ``` // src/configuration.ts import { Configuration, Inject, MidwayWebRouterService } from '@midwayjs/core'; import { DataController } from './controller/data.controller'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { if (process.env.NODE_ENV === 'test') { this.webRouterService.addController(DataController, { prefix: '/test', routerOptions: { middleware: [ // ... ] } }); } // ... } } ``` `addController` 的方法,第一个参数为类本身,第二个参数和 `@Controller` 装饰器参数相同。 ### 动态添加 Web 路由函数[​](#动态添加-web-路由函数 "动态添加 Web 路由函数的直接链接") 在某些场景下,用户可以直接动态添加方法。 ``` // src/configuration.ts import { Configuration, Inject, MidwayWebRouterService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { // koa/egg 格式 this.webRouterService.addRouter(async (ctx) => { return 'hello world'; }, { url: '/api/user', requestMethod: 'GET', }); // ... // express 格式 this.webRouterService.addRouter(async (req, res) => { return 'hello world'; }, { url: '/api/user', requestMethod: 'GET', }); } } ``` `addRouter` 的方法,第一个参数为路由方法体,第二个参数为路由的元数据。 ### 动态添加 Serverless 函数[​](#动态添加-serverless-函数 "动态添加 Serverless 函数的直接链接") 和添加动态 Web 路由类似,使用内置的 `MidwayServerlessFunctionService` 服务来添加。 比如,添加一个 http 函数。 ``` // src/configuration.ts import { Configuration, Inject, MidwayServerlessFunctionService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { this.serverlessFunctionService.addServerlessFunction(async (ctx, event) => { return 'hello world'; }, { type: ServerlessTriggerType.HTTP, metadata: { method: 'get', path: '/api/hello' }, functionName: 'hello', handlerName: 'index.hello', }); } } ``` `metadata` 的信息和 @ServerlessTrigger 的参数相同。 --- # 部署到阿里云函数计算 阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。 阿里云 Serverless 包含许多产品,如函数计算 FC,轻量应用引擎 SAE 等,本文主要使用了其 **函数计算** 部分。 下面是常见的函数触发器的使用、测试和部署方法。 ## 部署类型[​](#部署类型 "部署类型的直接链接") 阿里云的函数计算部署类型比较多,根据运行的不同容器有以下几种。 | 名称 | 能力限制 | 描述 | 部署媒介 | | ------------------------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------- | --------------- | | 内置运行时 | 不支持流式请求和响应;不支持太大的请求和响应入参 | 只能部署函数接口,不需要自定义端口,构建出 zip 包给平台部署 | zip 包部署 | | 自定义运行时(Custom Runtime) | | 可以部署标准应用,启动 9000 端口,使用平台提供的系统镜像,构建出 zip 包给平台部署 | zip 包部署 | | 自定义容器(Custom Container) | | 可以部署标准应用,启动 9000 端口,自己控制所有环境依赖,构建出 Dockerfile 提供给平台部署 | Dockerfile 部署 | 在平台上分别对应创建函数时的三种方式。 ![](https://img.alicdn.com/imgextra/i1/O1CN01JrlhOw1EJBZmHklbq_!!6000000000330-2-tps-1207-585.png) ## 纯函数开发(内置运行时)[​](#纯函数开发内置运行时 "纯函数开发(内置运行时)的直接链接") 下面我们将以使用 **"内置运行时部署"** 纯函数作为示例。 ### 触发器代码[​](#触发器代码 "触发器代码的直接链接") * Event * HTTP * API 网关 * Timer * OSS * MNS 发布不包含触发器的函数,这是最简单的类型,可以直接通过 event 手动触发参数,也可以在平台绑定其他触发器。 通过直接在代码中的 `@ServerlessTrigger` 装饰器绑定事件触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.EVENT) async handleEvent(event: any) { return event; } } ``` 阿里云的 HTTP 触发器和其他平台的有所区别,是独立于 API 网关的另一套服务于 HTTP 场景的触发器。相比于 API 网关,该触发器更易于使用和配置。 通过直接在代码中的 `@ServerlessTrigger` 装饰器绑定 HTTP 触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` API 网关在阿里云函数体系中比较特殊,他类似于创建一个无触发器函数,通过平台网关的绑定到特定的路径上。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.API_GATEWAY, { path: '/api_gateway_aliyun', method: 'post', }) async handleAPIGatewayEvent(@Body() name) { return `hello ${name}`; } } ``` 定时任务触发器用于定时执行一个函数。 信息 温馨提醒,测试函数后请及时关闭触发器自动执行,避免超额扣费。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { TimerEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.TIMER) async handleTimerEvent(event: TimerEvent) { this.ctx.logger.info(event); return 'hello world'; } } ``` **事件结构** Timer 消息返回的结构如下,在 `TimerEvent` 类型中有描述。 ``` { triggerTime: new Date().toJSON(), triggerName: 'timer', payload: '', } ``` OSS 用于存储一些资源文件,是阿里云的资源存储产品。 当 OSS 中有文件创建,更新,对应的函数就会被触发而执行。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { OSSEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.OS) async handleOSSEvent(event: OSSEvent) { // xxx } } ``` **事件结构** OSS 消息返回的结构如下,在 `FC.OSSEvent` 类型中有描述。 ``` { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161e853" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.128.221" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] } ``` 信息 * 1、阿里云消息队列会对 Topic 和 Queue 产生一定的费用。 * 2、提供的默认消息队列格式为 JSON ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { MNSEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.MQ) async handleMNSEvent(event: MNSEvent) { // ... } } ``` **事件结构** MNS 消息返回的结构如下,在 `FC.MNSEvent` 类型中有描述。 ``` { "Context": "user custom info", "TopicOwner": "1186202104331798", "Message": "hello topic", "Subscriber": "1186202104331798", "PublishTime": 1550216302888, "SubscriptionName": "test-fc-subscibe", "MessageMD5": "BA4BA9B48AC81F0F9C66F6C909C39DBB", "TopicName": "test-topic", "MessageId": "2F5B3C281B283D4EAC694B7425288675" } ``` 信息 触发器的更多配置由于和平台相关,将写在 `s.yaml` 中,如定时任务的时间间隔等,更多细节请查看下面的部署段落。 ### 类型定义[​](#类型定义 "类型定义的直接链接") FC 的定义将由适配器导出,为了让 `ctx.originContext` 的定义保持正确,需要将其添加到 `src/interface.ts` 中。 ``` // src/interface.ts import type {} from '@midwayjs/fc-starter'; ``` 此外,还提供了各种 Event 类型的定义。 ``` // Event 类型 import type { OSSEvent, MNSEvent, SLSEvent, CDNEvent, TimerEvent, APIGatewayEvent, TableStoreEvent, } from '@midwayjs/fc-starter'; // InitializeContext 类型 import type { InitializeContext } from '@midwayjs/fc-starter'; ``` ### 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 触发器和 API Gateway 类型可以通过本地 `npm run dev` 和传统应用类似的开发方式进行本地开发,其他类型的触发器本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ### 本地测试[​](#本地测试 "本地测试的直接链接") 和传统应用测试类似,使用 `createFunctionApp` 方法创建函数 app, 使用 `close` 方法关闭。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: mockContext(), }); // ... await close(app); }); }); ``` `mockContext` 方法用来模拟一个 FC Context 数据结构,可以自定传递一个类似的结构或者修改部分数据。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: Object.assign(mockContext(), { function: { name: '***', handler: '***' } }), }); // ... await close(app); }); }); ``` 不同的触发器有着不同的测试方法,下面列出了一些常见的触发器。 * Event * HTTP * API 网关 * Timer * OSS * MNS 通过 `getServerlessInstance` 获取类实例,直接调用实例方法,传入参数进行测试。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleEvent('hello world')).toEqual('hello world'); // ... }); }); ``` 和应用类似相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; describe('test/hello_aliyun.test.ts', () => { it('should get result from http trigger', async () => { // ... const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); // ... }); }); ``` 和 HTTP 测试相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { createHttpRequest } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from http trigger', async () => { // ... const result = await createHttpRequest(app).post('api_gateway_aliyun').send({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `mockTimerEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockTimerEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from timer trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleTimerEvent(mockTimerEvent())).toEqual('hello world'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createOSSEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockOSSEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from oss trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleOSSEvent(mockOSSEvent())).toEqual('hello world'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createMNSEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockMNSEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from oss trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleMNSEvent(mockMNSEvent())).toEqual('hello world'); // ... }); }); ``` ## 纯函数部署(内置运行时)[​](#纯函数部署内置运行时 "纯函数部署(内置运行时)的直接链接") 以下将简述如何使用 Serverless Devs 部署到阿里云函数。 ### 1、确认启动器[​](#1确认启动器 "1、确认启动器的直接链接") 在项目根目录的 `f.yml` 的 `provider` 段落处确保 starter 为 `@midwayjs/fc-starter`。 ``` provider: name: aliyun starter: '@midwayjs/fc-starter' ``` ### 2、安装 Serverless Devs 工具[​](#2安装-serverless-devs-工具 "2、安装 Serverless Devs 工具的直接链接") aliyun 使用 [Serverless Devs 工具](https://www.serverless-devs.com/) 进行函数部署。 你可以将其安装到全局。 ``` $ npm install @serverless-devs/s -g ``` 参考 [密钥配置](https://docs.serverless-devs.com/serverless-devs/quick_start) 文档进行配置。 ### 3、编写一个 Serverless Devs 描述文件[​](#3编写一个--serverless-devs-描述文件 "3、编写一个 Serverless Devs 描述文件的直接链接") 在根目录创建一个 `s.yaml` ,添加以下内容。 ``` edition: 1.0.0 name: "midwayApp" # 项目名称 access: "default" # 秘钥别名 vars: service: name: fc-build-demo description: 'demo for fc-deploy component' services: project-0981cd9b07: component: devsapp/fc props: region: cn-hangzhou service: ${vars.service} function: name: hello # 函数名 handler: helloHttpService.handleHTTPEvent codeUri: '.' initializer: helloHttpService.initializer customDomains: - domainName: auto protocol: HTTP routeConfigs: - path: /* serviceName: ${vars.service.name} functionName: helloHttpService-handleHTTPEvent triggers: - name: http type: http config: methods: - GET authType: anonymous ``` 每加一个函数都需要调整 `s.yaml` 文件,为此Midway 提供了一个 `@midwayjs/serverless-yaml-generator` 工具用来将装饰器函数信息写入 `s.yaml`。 ``` { "scripts": { + "generate": "serverless-yaml-generator", }, "devDependencies": { + "@midwayjs/serverless-yaml-generator": "^1.0.0", }, } ``` 通过执行下面的命令,可以将现有函数信息填充到 `s.yaml` 中,并生成入口文件,方便排查问题。 ``` $ npm run generate ``` 工具将以函数名作为 key 在 `s.yaml` 中查找配置。 * 1、如果存在函数,则会覆盖特定字段,比如 handler,http 触发器的 methods * 2、如果不存在函数,则会添加一个新函数 * 3、工具不会写入 http 的路由方法,为了简化后续更新,可以提供一个 `/*` 路由(如示例) 我们推荐用户只在装饰器定义基础函数名,函数 handler,以及基础触发器信息(比如 http 触发器的 path 和 method),其余都写在 `yaml` 中。 `s.yaml` 的完整配置较为复杂,具体请参考 [描述文件规范](https://docs.serverless-devs.com/serverless-devs/yaml)。 ### 4、编写一个部署脚本[​](#4编写一个部署脚本 "4、编写一个部署脚本的直接链接") 由于部署有构建,拷贝等多个步骤,我们可以编写部署脚本统一这个过程。 比如在项目根目录新建一个 `deploy.sh` 文件,内容如下。 ``` #!/bin/bash set -e # 构建产物目录 export BUILD_DIST=$PWD/.serverless # 构建开始时间,单位毫秒 export BUILD_START_TIME=$(date +%s%3N) echo "Building Midway Serverless Application" # 打印当前目录 cwd echo "Current Working Directory: $PWD" # 打印结果目录 BUILD_DIST echo "Build Directory: $BUILD_DIST" # 安装当前项目依赖 npm i # 执行构建 ./node_modules/.bin/tsc || return 1 # 生成入口文件 ./node_modules/.bin/serverless-yaml-generator || return 1 # 如果 .serverless 文件夹存在,则删除后重新创建 if [ -d "$BUILD_DIST" ]; then rm -rf $BUILD_DIST fi mkdir $BUILD_DIST # 拷贝 dist、 *.json、*.yml 到 .serverless 目录 cp -r dist $BUILD_DIST cp *.yaml $BUILD_DIST 2>/dev/null || : cp *.json $BUILD_DIST 2>/dev/null || : # 移动入口文件到 .serverless 目录 mv *.js $BUILD_DIST 2>/dev/null || : # 进入 .serverless 目录 cd $BUILD_DIST # 安装线上依赖 npm install --production echo "Build success" # 在 .serverless 目录进行部署 s deploy ``` 可以将这个 `deploy.sh` 文件放到 `package.json` 的 `deploy` 指令中,后续部署执行 `npm run deploy` 即可。 ``` { "scripts": { "deploy": "sh deploy.sh" } } ``` 提示 * 1、 `deploy.sh` 只测试了 mac,其余平台可以自行调整 * 2、脚本内容可以根据业务逻辑自行调整,比如拷贝的文件等 ## 自定义运行时部署[​](#自定义运行时部署 "自定义运行时部署的直接链接") ### 1、创建项目[​](#1创建项目 "1、创建项目的直接链接") 自定义运行时可以使用标准项目来部署,由于需要提供 9000 端口,需要创建 Midway koa/express/express 项目。 初始化项目请参考 [创建第一个应用](/docs/quickstart.md)。 ### 2、调整端口[​](#2调整端口 "2、调整端口的直接链接") 为了避免影响本地开发,我们仅在入口 `bootstrap.js` 处增加端口。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ globalConfig: { koa: { port: 9000, } } }).run() ``` 不同的框架修改端口请参考: * [koa 修改端口](/docs/extensions/koa.md) * [Egg 修改端口](/docs/extensions/egg.md) * [Express 修改端口](/docs/extensions/express.md) ### 3、平台部署配置[​](#3平台部署配置 "3、平台部署配置的直接链接") * 1、选择运行环境,比如 `Node.js 18` * 2、选择代码上传方式,比如可以本地打 zip 包上传 * 3、启动命令指定 node bootstrap.js * 4、监听端口 9000 ![](https://img.alicdn.com/imgextra/i3/O1CN010JA2GU1lxNeqm81AR_!!6000000004885-2-tps-790-549.png) 配置完成之后,上传压缩包即可部署完成。 --- # 部署到 AWS Lambda AWS Lambda是Amazon Web Services (AWS)提供的无服务器计算服务。它允许您在无需预配或管理服务器的情况下运行代码。您可以为几乎任何类型的应用程序或后端服务运行代码,全部无需管理。 下面我们将介绍如何将 Midway 标准应用部署到 AWS Lambda。 ### 1、创建项目[​](#1创建项目 "1、创建项目的直接链接") 需要创建 Midway koa/express/express 项目。 初始化项目请参考 [创建第一个应用](/docs/quickstart.md),下面以 koa 应用为例。 ### 2、调整端口[​](#2调整端口 "2、调整端口的直接链接") 为了避免影响本地开发,我们仅在入口 `bootstrap.js` 处增加端口,比如 `8080`。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ globalConfig: { koa: { port: 8080, } } }).run() ``` 不同的框架修改端口请参考: * [koa 修改端口](/docs/extensions/koa.md) * [Egg 修改端口](/docs/extensions/egg.md) * [Express 修改端口](/docs/extensions/express.md) ### 3、安装和配置 AWS 工具[​](#3安装和配置-aws-工具 "3、安装和配置 AWS 工具的直��接链接") * [安装 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) * [配置AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) * [安装 AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) ### 4、编写 template.yaml[​](#4编写-templateyaml "4、编写 template.yaml的直接链接") ``` AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: EasySchoolBackendFunction: Type: AWS::Serverless::Function Properties: CodeUri: ./dist.zip Handler: dist/index/index.handler Runtime: nodejs14.x Timeout: 900 PackageType: Zip Events: ApiEvent: Type: Api Properties: Path: /{any+} Method: ANY ``` ### 4、构建和部署[​](#4构建和部署 "4、构建和部署的直接链接") ``` $ cd sam $ sam build # builds sam $ sam local start-api # start local api ``` --- # 函数上下文 ## Event 转换[​](#event-转换 "Event 转换的直接链接") Midway Serverless 针对不同平台的情况,进行了入参包裹,同时,在函数使用了 apigw(API 网关)和 http (阿里云)触发器的情况下,对入参(event)做了特殊处理,为了简化和统一写法,将 event 统一规则化成了类似 koa 写法的代码。 普通触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/core'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler(event) { return 'hello world'; } } ``` HTTP 、API 网关触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/core'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler() { // 下面两种写法相同 // this.ctx.body = 'hello world'; return 'hello world'; } } ``` ## Context[​](#context "Context的直接链接") 每次函数调用,都会创建一个全新的 ctx(函数上下文)。针对 ctx 上的属性或者方法,我们提供 ts 定义。 信息 在 Serverless v1 时代,我们的定义叫 FaaSContext,在 v2 我们将定义和应用做了统一,更为一致。 ### ctx.logger[​](#ctxlogger "ctx.logger的直接链接") * return `ILogger` 运行时传递下来的每次请求的日志对象,默认为 console。 ``` ctx.logger.info('hello'); ctx.logger.warn('hello'); ctx.logger.error('hello'); ``` ### ctx.env[​](#ctxenv "ctx.env的直接链接") * return `string` 当前启动的环境,即 NODE\_ENV 或者 MIDWAY\_SERVER\_ENV 的值,默认为 prod。 ``` ctx.env; // 默认 prod ``` ### ctx.requestContext[​](#ctxrequestcontext "ctx.requestContext的直接链接") * return `MidwayRequestContainer` midway faas 的 IoC 请求作用域容器,用于获取其他 IoC 容器中的对象实例。 ``` const userService = await ctx.requestContext.getAsync(UserService); ``` ## FaaSHTTPContext[​](#faashttpcontext "FaaSHTTPContext的直接链接") `Context` 定义继承于 `FaaSHTTPContext`,前者保留了后者,大部分场景下可以直接使用前者,后者是在 apigw(API 网关)和 http (阿里云)触发器下才有的能力。 对于普通用户,直接使用 `Context` 定义即可。 ``` import { Context } from '@midwayjs/faas'; @Inject() ctx: Context; ``` 在 ctx 对象中,我们提供了一些和编写传统 Koa Web 应用程序类似的 API。这样的好处是减少用户的认知成本,并且,在一定程度上,兼容原有传统代码,兼容社区 middleware 成为了可能。 我们提供了一些和传统类似的 API,支持常用的能力,**在不同的平台可能不一定完全相同**,我们会在特定 API 中指出。 ### ctx.request[​](#ctxrequest "ctx.request的直接链接") * return `FaaSHTTPRequest` FaaS 模拟的 HTTP Request 对象。 ### ctx.response[​](#ctxresponse "ctx.response的直接链接") * return `FaaSHTTPResponse` FaaS 模拟的 HTTP Response 对象。 ### ctx.params[​](#ctxparams "ctx.params的直接链接") 代理自 `request.pathParameters`,在 http 触发器(阿里云)和 API 网关触发器下可用。 ``` // /api/user/[id] /api/user/faas ctx.params.id; // faas ``` ### ctx.set[​](#ctxset "ctx.set的直接链接") 设置响应头,此方法代理自 `response.setHeader` 。 ``` ctx.set('X-FaaS-Duration', 2100); ``` ### ctx.status[​](#ctxstatus "ctx.status的直接链接") 设置返回状态码,此属性代理自 `response.statusCode` 。 ``` ctx.status = 404; ``` ### Request aliases[​](#request-aliases "Request aliases的直接链接") 以下列出的属性是从 [Request](#k6AZp) 对象代理过来 * `ctx.headers` * `ctx.method` * `ctx.url` * `ctx.path` * `ctx.ip` * `ctx.query` * `ctx.get()` ### Response aliases[​](#response-aliases "Response aliases的直接链接") 以下列出的属性是从 [Response](#kfTOD) 对象代理过来 * `ctx.body=` * `ctx.status=`alias to `response.statusCode` * `ctx.type=` * `ctx.set()`alias to `response.setHeader` ## FaaSHTTPRequest[​](#faashttprequest "FaaSHTTPRequest的直接链接") 此对象是通过将函数的 `event` 和 `context` 入参进行转换得来。 ### request.headers[​](#requestheaders "request.headers的直接链接") 包含所有请求头的对象,键值对存储。 ### request.ip[​](#requestip "request.ip的直接链接") 获取客户端请求 ip。 信息 在阿里云 FC 上,只有 HTTP 触发器能获取到值,api 网关暂时无法获取。 ### request.url[​](#requesturl "request.url的直接链接") 客户端请求完整 url。 ### request.path[​](#requestpath "request.path的直接链接") 客户端请求 path。 ### request.method[​](#requestmethod "request.method的直接链接") 请求的 method。 ### request.body[​](#requestbody "request.body的直接链接") POST 请求的 body,已经解析为 JSON。 ## FaaSHTTPResponse[​](#faashttpresponse "FaaSHTTPResponse的直接链接") 此对象是通过将函数的 `event` 和 `context` 入参进行转换得来。 ### response.setHeader[​](#responsesetheader "response.setHeader的直接链接") 设置响应头。 ### response.statusCode[​](#responsestatuscode "response.statusCode的直接链接") 设置返回状态码。 ### response.body[​](#responsebody "response.body的直接链接") 设置返回响应体内容, `string` 或者 `buffer`。 --- # 开发函数 ## 初始化代码[​](#初始化代码 "初始化代码的直接链接") 让我们来开发第一个纯 HTTP 函数,来尝试将它部署到云环境。 执行 `npm init midway`,选择 `faas` 脚手架。 ## 目录结构[​](#目录结构 "目录结构的直接链接") 以下就是一个函数的最精简的结构,核心会包括一个 `f.yml` 标准化函数文件,以及 TypeScript 的项目结构。 ``` . ├── f.yml # 标准化 spec 文件 ├── package.json # 项目依赖 ├── src │ └── function │ └── hello.ts ## 函数文件 └── tsconfig.json ``` 我们来简单了解一下文件内容。 * `f.yml` 函数定义文件 * `tsconfig.json` TypeScript 配置文件 * `src` 函数源码目录 * `src/function/hello.ts` 示例函数文件 我们将函数放在 `function`目录下,是为了更好的和其他类型的代码分开。 ## 函数文件[​](#函数文件 "函数文件的直接链接") 我们首先来看看函数文件,传统的函数是一个 `function` ,为了更符合 midway 体系,以及使用我们的依赖注入,这里将它变成了 Class。 通过 `@ServerlessTrigger` 装饰器,我们将方法标注为一个 HTTP 接口,并且标示 `path` 和 `method` 属性。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType, Query } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloHTTPService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` 除了触发器外,我们还可以使用 `@ServerlessFunction` 装饰器描述函数层面的元信息,比如函数名,并发度等等。 这样,当我们在一个函数上,使用多个触发器时,就可以这样设置。 ``` import { Provide, Inject, ServerlessFunction, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloServerlessService { @Inject() ctx: Context; // 一个函数多个触发器 @ServerlessFunction({ functionName: 'abcde', }) @ServerlessTrigger(ServerlessTriggerType.TIMER, { name: 'timer' }) async handleTimerEvent() { // TODO } } ``` 警告 注意,有些平台无法将不同类型的触发器放在同一个函数中,比如阿里云规定,HTTP 触发器和其他触发器不能同时在一个函数生效。 ## 函数定义文件[​](#函数定义文件 "函数定义文件的直接链接") `f.yml` 是框架识别函数信息的文件,内容如下。 ``` provider: name: aliyun # 发布的平台,这里是阿里云 starter: '@midwayjs/fc-starter' ``` 这里的 `@midwayjs/fc-starter` 就是适配 aliyun 函数的适配器。 ## 触发器装饰器参数[​](#触发器装饰器参数 "触发器装饰器参数的直接链接") `@ServerlessTrigger` 装饰器用于定义不同的触发器,它的参数为每个触发器信息,以及通用触发器参数。 比如触发器的名称修改为 abc。 ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { name: 'abc', // 触发器名称 }) ``` 如果只有一个触发器,可以将函数名信息写入到触发器上。 ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { functionName: 'hello' // 如果只有一个触发器,可以省略一个装饰器 name: 'abc', }) ``` ## 函数装饰器参数[​](#函数装饰器参数 "函数装饰器参数的直接链接") `@ServerlessFunction` 装饰器用于定义函数,如果有多个触发器,通过它可以统一修改函数名。 比如: ``` @ServerlessFunction({ functionName: 'abcde' // 函数名称 }) ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 函数本地开发和传统 Web 相同,输入以下命令。 ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 ,浏览器会打印出 `Hello midwayjs` 的信息。 非 HTTP 函数,无法直接触发,作为代替,可以编写测试函数执行。 --- # 默认错误行为 ## 错误值处理[​](#错误值处理 "错误值处理的直接链接") 为了保证安全性,Midway 针对 Serverless 场景下返回的错误做了一些特殊处理。 在函数业务抛出错误的情况下,框架侧会捕获所有的错误,并返回 “Internal Server Error” 的错误。 比如我们的函数返回一个错误: ``` @ServerlessTrigger(//...) async invoke() { throw new Error('abc'); } ``` 不管是 HTTP 还是非 HTTP 触发器,框架部分都有相应的处理。 在 **非线上环境**,比如 `NODE_ENV=local` 环境,框架会将整个错误通过网关透出。 比如(完整的错误堆栈): ``` 2021-07-02T05:57:08.553Z 19be4d99-c9cb-4c4c-aac2-9330d31b4408 [error] Error: abc at hello (/code/dist/function/index.js:17:15) at invokeHandler (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:174:56) at processTicksAndRejections (internal/process/task_queues.js:97:5) at (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:117:40) at cors (/code/node_modules/_@koa_cors@3.1.0@@koa/cors/index.js:98:16) at invokeHandlerWrapper (/code/node_modules/_@midwayjs_runtime-engine@2.11.1@@midwayjs/runtime-engine/dist/lightRuntime.js:18:28) { } ``` 在 线上环境,框架将直接返回 **“Internal Server Error”** ,但是日志中是完整的堆栈。 如图所示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1625205528496-96f7d2b8-d728-4f04-82f4-f2617e00720b.png) ## 调整错误返回[​](#调整错误返回 "调整错误返回的直接链接") 以上为默认行为,在特殊环境下,如果需要显示出错误,可以使用环境变量开启强制输出。 ``` process.env.SERVERLESS_OUTPUT_ERROR_STACK = 'true'; ``` --- # 介绍 ## Midway Serverless 能做什么[​](#midway-serverless-能做什么 "Midway Serverless 能做什么的直接链接") Midway Serverless 是用于构建 Node.js 云函数的 Serverless 框架。帮助您在云原生时代大幅降低维护成本,更专注于产品研发。 ## Midway Serverless 和 Midway 的关系[​](#midway-serverless-和-midway-的关系 "Midway Serverless 和 Midway 的关系的直接链接") Midway Serverless 是 Midway 产出的一套面向 Serverless 云平台的开发方案。其内容主要包括函数框架 `@midwayjs/faas`,以及一系列跟平台配套的工具链,启动器等。 在 Midway Serverless 2.0 之后,Midway Serverless 和 Midway 的能力复用,有着相同的 CLI 工具链,编译器,装饰器等等。 当前,Midway Serverless 主要面向的是 函数(FaaS)场景。 ## 函数(FaaS)能做什么[​](#函数faas能做什么 "函数(FaaS)能做什么的直接链接") 很多人对函数还不是很清楚或者不了解他能做什么。当前的函数,可以当做一个小容器,原来我们要写一个完整的应用来承载能力,现在只需要写中间的逻辑部分,以及考虑输入和输出的数据。 通过绑定平台的触发器,可以承载例如 HTTP,Socket 等流量。 通过平台提供的 BaaS SDK,可以对外调用数据库,Redis 等服务。 通过函数,能提供传统的 HTTP API 服务,结合现有的前端框架(react,vue 等)渲染出一个个美丽的页面,也可以做为一个独立的数据模块,等待被调用(触发),比如常见的文件上传变更,解压等等,也能作为定时任务的逻辑部分,到了指定的时间或者时间间隔被执行。 随着时间的更替,平台的迭代,函数的能力会越来越强,而用户的上手成本,服务器成本则会越来越低。 ## 函数不能做什么[​](#函数不能做什么 "函数不能做什么的直接链接") 函数的架构决定了,有些需求是无法支持的,另外,函数和应用在能力上还是有一定的区别。 函数不适用: * 执行时间超过函数配置下限制的(最好不超过 5s) * 有状态,在本地存储数据的 * 长链接,比如 ws 等 * 后台任务,有大数据执行的 * 依赖多进程通信的 * 大文件上传(比如网关限制的 2M 以上) * 自定义环境的,比如 nginx 配置,c++ 库(c++ addon 动态链接库等),python 版本依赖的 * 大量服务端缓存的 * 固定 ip 的情况 ## 术语描述[​](#术语描述 "术语描述的直接链接") ### 函数[​](#函数 "函数的直接链接") 逻辑意义上的一段代码片段,通过常见的入口文件包裹起来执行。函数是单一链路,并且无状态的,现在很多人认为,Serverless = FaaS + BaaS ,而 FaaS 则是无状态的函数,BaaS 解决带状态的服务。 ### 函数组[​](#函数组 "函数组的直接链接") 多个函数聚合到一起的逻辑分组名,对应原有的应用概念。 ### 触发器[​](#触发器 "触发器的直接链接") 触发器,也叫 Event(事件),Trigger 等,特指触发函数的方式。 与传统的开发理念不同,函数不需要自己启动一个服务去监听数据,而是通过绑定一个(或者多个)触发器,数据是通过类似事件触发的机制来调用到函数。 ### 函数运行时[​](#函数运行时 "函数运行时的直接链接") 英文叫 Runtime,具体指执行函数的环境,具体在各个平台可能是镜像,也可能是 Node.js 代码包,比如常见的社区运行时有 kubeless 等,该代码包会实现对接平台的各种接口,处理异常,转发日志等能力。 ### 发布平台[​](#发布平台 "发布平台的直接链接") 函数最后承载的平台,现在社区最常见的有阿里云 FC 、腾讯云 SCF,AWS 的 Lambda 等等。 ### Layer[​](#layer "Layer的直接链接") 由于运行时的代码比较简单,且需要保证稳定性无法经常性的更新,Layer 被设计出来扩展运行时的能力,并且可以精简本地的函数代码量(有一些平台限制了上传压缩包的大小)。 --- # Serverless 触发器 POST 情况差异 ## 阿里云 API 网关[​](#阿里云-api-网关 "阿里云 API 网关的直接链接") 阿里云 API 网关支持不同类型的的 POST 请求。 ### 入参透传的 POST[​](#入参透传的-post "入参透传的 POST的直接链接") 网关配置如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593175823751-f9b305fc-ddeb-4b04-ba13-481a616be260.png) 网关透传的 event 特征为有 `body` 字段以及 `isBase64Encoded` 为 true,解码比较容易,直接解 base64 即可。 信息 透传了之后,即为所有的结果交给函数处理。 #### 示例一 (text/html)[​](#示例一-texthtml "示例一 (text/html)的直接链接") 下面的 event,是一个最简单的透传示例,因为其中的 `content-type` 为 `text/html`,所以 body 传递过来 base64 解码的结果也同样是字符串。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "x-ca-dashboard-action": "DEBUG", "x-ca-dashboard-uid": "125087", "x-ca-stage": "RELEASE", "x-ca-dashboard-role": "USER", "user-agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "accept-encoding": "gzip,deflate", "content-md5": "Kry+hjKjc2lvIrwoJqdY9Q==", "content-type": "text/html; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // '{"c":"b"}' => string ``` #### 示例二(application/json)[​](#示例二applicationjson "示例二(application/json)的直接链接") 使用 `content-type` 为 `application/json` ,这样框架认为是一个 JSON,会自动被 JSON.parse。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "125087", "X-Ca-Stage": "RELEASE", "X-Ca-Dashboard-Role": "USER", "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "Accept-Encoding": "gzip,deflate", "Content-MD5": "Kry+hjKjc2lvIrwoJqdY9Q==", "Content-Type": "application/json; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` #### 示例三 (application/x-www-form-urlencoded)[​](#示例三-applicationx-www-form-urlencoded "示例三 (application/x-www-form-urlencoded)的直接链接") 使用 `content-type` 为 `application/x-www-form-urlencoded`,这个时候网关不会以 base64 格式透传,这也是前端原生表单的默认提交类型。 信息 在 API 网关侧测试,保持“入参透传”下,似乎没有效果,于是我换到了 Postman 进行测试。 Postman 模拟请求如下: ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593188653464-2a5659de-40ad-4611-ba86-f5754c7d4425.png) 函数拿到的 event 值如下。 ``` { "body": "{\"c\":\"b\"}", "headers": { "accept": "*/*", "cache-control": "no-cache", "user-agent": "PostmanRuntime/7.24.1", "postman-token": "feb51b11-9103-463a-92ff-73076d37b683", "accept-encoding": "gzip, deflate, br", "content-type": "application/x-www-form-urlencoded" }, "httpMethod": "POST", "isBase64Encoded": false, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` ### 入参映射的 POST[​](#入参映射的-post "入参映射的 POST的直接链接") 网关配置选择入参映射之后,body 数据类型有两种选择。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593186831907-7975c65c-aee5-4f96-9ae4-ffaeee66c7dd.png) 一旦选了映射,整个函数拿到的 Headers 中就 **没有了 content-type**。 这个时候,网关的返回 event 为 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "111111", "X-Ca-Dashboard-Role": "USER" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数由于默认没有拿到 header 头,只会对 base64 的结果做处理,结果为字符串。 ``` ctx.request.body; // '{"c":"b"}' => string ``` ## 阿里云 HTTP 触发器[​](#阿里云-http-触发器 "阿里云 HTTP 触发器的直接链接") 函数提供的 HTTP 触发器(和网关不同)。 ### 普通 POST(application/json)[​](#普通-postapplicationjson "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 字符串格式。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321679770-a7609684-ec5e-4f93-99f2-d346ed79c1fa.png) ``` ctx.request.body; // "bbb" => string ``` JSON 格式 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321730423-f9b2860f-7902-4f3a-81cf-bfbcfd4ee57f.png) ``` ctx.request.body; // {"b":"c"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded "表单(application/x-www-form-urlencoded)的直接链接") ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321823455-23ec3970-35a5-4746-8995-d9146eaa4ab0.png) ``` ctx.request.body; // {"b":"c"} => object ``` ### 文件上传(Binary)[​](#文件上传binary "文件上传(Binary)的直接链接") 暂未支持 ## 腾讯云网关[​](#腾讯云网关 "腾讯云网关的直接链接") 腾讯云提供单独网关。 ### 普通 POST(application/json)[​](#普通-postapplicationjson-1 "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 使用 Postman 请求。 字符串格式,正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323223487-c4e5f365-b500-4a2d-85e3-45bd4aba4653.png) ``` ctx.request.body; // "bbb" => string ``` JSON 格式,能正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323187488-e7b4e32e-4195-404d-b309-ba436c3f5f8e.png) ``` ctx.request.body; // {"c":"b"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded-1 "表单(application/x-www-form-urlencoded)的直接链接") 正常解析为 JSON。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323279728-983fd844-f37d-419b-90f3-f96d1ee8236d.png) ``` ctx.request.body; // {"c":"b"} => object ``` --- # 测试函数 ## HTTP 类的函数[​](#http-类的函数 "HTTP 类的函数的直接链接") 该方法适用于所有的类 HTTP 触发器的函数,包括 `HTTP` 和 `API_GATEWAY`。 使用和应用相同的测试方法来测试,针对 HTTP 函数,使用封装了 supertest 的 `createHttpRequest` 方法创建 HTTP 客户端。 唯一和应用不同的是,使用 `createFunctionApp` 方法创建函数应用(app)。 `createFunctionApp` 是 `createApp` 在函数场景下的定制方法。 HTTP 测试代码如下: ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/faas'; describe('test/hello_aliyun.test.ts', () => { it('should get result from api gateway trigger', async () => { const app: Application = await createFunctionApp(); const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); await close(app); }); }); ``` ## 普通触发器[​](#普通触发器 "普通触发器的直接链接") 除了类 HTTP 触发器之外,我们还有其他比如定时器、对象存储等函数触发器,这些触发器由于和网关关系密切,不能使用 HTTP 行为来测试,而是使用传统的方法调用来做。 通过 `createFunctionApp` 方法创建函数 app,通过 `getServerlessInstance` 方法获取类实例,然后通过实例的方法直接调用,传入参数进行测试。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/faas'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // 创建函数 app let app: Application = await createFunctionApp(); // 拿到服务类 const instance = await app.getServerlessInstance(HelloAliyunService); // 调用函数方法,传入参数 expect(await instance.handleEvent('hello world')).toEqual('hello world'); await close(app); }); }); ``` --- # 从 Serverless v2 迁移到 v3 基于 Midway 升级到 v3 的缘故,Serverless 体系也同步升级到了 v3 版本。 本文章介绍如何从 Serverless v2.0 迁移到 Serverless v3.0,和传统应用升级非常的类似。 警告 新的 Serverless 当前只支持阿里云函数。 ## 1、项目包版本的升级[​](#1项目包版本的升级 "1、项目包版本的升级的直接链接") 一些依赖包升级,包括: * midway 及组件版本升级到 3.x * CLI,Jest 等版本升级 * 移除了一些不再使用的依赖,比如 `@midwayjs/serverless-app` ``` "scripts": { "dev": "cross-env NODE_ENV=local midway-bin dev --ts", "test": "cross-env midway-bin test --ts", - "deploy": "cross-env UDEV_NODE_ENV=production midway-bin deploy", "lint": "mwts check", "lint:fix": "mwts fix" }, "dependencies": { - "@midwayjs/core": "^2.3.0", - "@midwayjs/decorator": "^2.3.0", - "@midwayjs/faas": "^2.0.0" + "@midwayjs/core": "^3.12.0", + "@midwayjs/faas": "^3.12.0", + "@midwayjs/fc-starter": "^3.12.0", + "@midwayjs/logger": "^2.0.0" }, "devDependencies": { - "@midwayjs/cli": "^1.2.45", - "@midwayjs/cli-plugin-faas": "^1.2.45", - "@midwayjs/fcli-plugin-fc": "^1.2.45", - "@midwayjs/mock": "^2.8.7", - "@midwayjs/serverless-app": "^2.8.7", - "@midwayjs/serverless-fc-trigger": "^2.10.3", - "@midwayjs/serverless-fc-starter": "^2.10.3", - "@types/jest": "^26.0.10", - "@types/node": "14", - "cross-env": "^6.0.0", - "jest": "^26.4.0", - "mwts": "^1.0.5", - "ts-jest": "^26.2.0", - "typescript": "~4.6.0" + "@midwayjs/mock": "^3.12.0", + "@types/jest": "29", + "@types/node": "16", + "cross-env": "^7.0.3", + "jest": "29", + "mwts": "^1.3.0", + "ts-jest": "29", + "ts-node": "^10.9.1", + "typescript": "~5.1.0" } ``` ## 2、入口主框架的变化[​](#2入口主框架的变化 "2、入口主框架的变化的直接链接") 显式声明 faas 作为主框架。 ``` // src/configuration import * as faas from '@midwayjs/faas'; @Configuration({ // ... imports: [ faas ], }) export class MainConfiguration { // ... } ``` ## 3、测试代码变化[​](#3测试代码变化 "3、测试代码变化的直接链接") 移除了 `@midwayjs/serverless-app` 的依赖。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; - import { Framework, Application } from '@midwayjs/serverless-app'; + import { Framework, Application } from '@midwayjs/faas'; ``` 移除了 `@midwayjs/serverless-fc-trigger` 和 `@midwayjs/serverless-fc-starter` 依赖,修改为 `@midwayjs/fc-starter`。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: Object.assign(mockContext(), { function: { name: '***', handler: '***' } }), }); // ... await close(app); }); }); ``` 一些 API 的替代,比如原有的 `createXXXEvent`,将变为 `mockXXXEvent`,原有的 `createInitializeContext` 将变为 `mockContext` 方法。 这些 API 将直接从 `@midwayjs/fc-starter` 中导出。 ## 5、部署方式的变化[​](#5部署方式的变化 "5、部署方式的变化的直接链接") 不再使用 `midway-bin deploy` 进行部署,将采用平台自己的 CLI 工具,Midway 只提供框架和本地开发能力。 更多的部署调整,请查询 [纯函数部署](/docs/serverless/aliyun_faas.md)。 --- # 服务和注入 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01LLV2Qd20Fbu1NWXVA_!!6000000006820-2-tps-2130-344.png) 提供这个抽象有以下几个好处: * 保持 Controller 中的逻辑更加简洁。 * 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。 * 将逻辑和展现分离,更容易编写测试用例。 ## 创建服务[​](#创建服务 "创建服务的直接链�接") 在 Midway 中,普通的服务就是一个 Class,比如我们之前创建了一个接受 user 请求的 Controller,我们来新增一个处理这些数据的服务。 对于服务的文件,我们一般会存放到 `src/service` 目录中。我们来添加一个 user 服务。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 内容为: ``` // src/service/user.ts import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async getUser(id: number) { return { id, name: 'Harry', age: 18, }; } } ``` 除了一个 `@Provide` 装饰器外,整个服务的结构和普通的 Class 一模一样,这样就行了。 之前我们还增加了一个 User 定义,这里也可以直接使用。 ``` import { Provide } from '@midwayjs/core'; import { User } from '../interface'; @Provide() export class UserService { async getUser(id: number): Promise { return { id, name: 'Harry', age: 18', }; } } ``` ## 使用服务[​](#使用服务 "使用服务的直接链接") 在 Controller 处,我们需要来调用这个服务。传统的代码写法,我们需要初始化这个 Class(new),然后将实例放在需要调用的地方。在 Midway 中,你**不需要这么做**,只需要编写我们提供的\*\* "依赖注入" \*\*的代码写法。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { UserService } from '../service/user'; @Controller('/api/user') export class APIController { @Inject() userService: UserService; @Get('/') async getUser(@Query('id') uid) { const user = await this.userService.getUser(uid); return {success: true, message: 'OK', data: user}; } } ``` 使用服务的过程分为几部分: * 1、使用 `@Provide` 装饰器暴露你的服务 * 2、在调用的代码处,使用 `@Inject` 装饰器注入你的服务 * 3、调用注入服务,执行对应的方法 Midway 的核心 “依赖注入” 容器会**自动关联**你的控制器(Controller) 和服务(Service),在运行过程中**会自动初始化**所有的代码,你**无需手动初始化**这些 Class。 ## 注入行为描述[​](#注入行为描述 "注入行为描述的直接链接") 看到这里,你会有一些疑惑,为什么服务(Service)上有一个 `@Provide` 装饰器,但是控制器(Controller) 上没有。 事实上,控制器(Controller) 上也有这个装饰器,只是在新版本中,Controller 包含了 Provide 的功能。如果你不确定什么时候可以隐藏,可以都写上。 你如果不写,默认等价于下面的代码。 ``` @Provide() @Controller('/api/user') export class APIController { ``` `@Provide` 装饰器的作用: * 1、这个 Class,被依赖注入容器托管,会自动被实例化(new) * 2、这个 Class,可以被其他在容器中的 Class 注入 而对应的 `@Inject` 装饰器,作用为: * 1、在依赖注入容器中,找到对应的属性名,并赋值为对应的实例化对象 信息 `@Inject` 的类中,必须有对应的 `@Provide` 才会生效。 `@Provide` 和 `@Inject` 装饰器是成对出现的,两者通过冒号后的类名进行关联。 ``` // service @Provide() export class UserService { //... } // controller @Provide() // <------ 由于有 Controller 包含了 Provide 的能力,这里展示的更加完整 @Controller('/api/user') export class APIController { @Inject() userService: UserService; // <------ 这里的类型是 Class,即会注入一个该类型的实例 //... } ``` 这样的组合之后会用到很多地方,**请务必记住这个用法**。 依赖注入还有更为复杂的情况,可以阅读 [依赖注入](/docs/3.0.0/container.md) 参考。 --- # 服务工厂 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 比如我们的 oss 组件,由于会创建多个 oss 对象,在编写的时候就需要留好多实例的接口。为了这种场景,midway 抽象了 `ServiceFactory` 类。 `ServiceFactory` 是个抽象类,每个需要实现的服务,都需要继承他。 我们以一个 http 客户端为例,需要准备一个创建 http 客户端实例的方法,其中包含几个部分: * 1、创建客户端实例的方法 * 2、客户端的配置 * 3、实例化服务类 ``` // 创建客户端的配置 const config = { baseUrl: '', timeout: 1000, }; // 创建客户端实例的方法 const httpClient = new HTTPClient(config); ``` ## 实现一个服务类[​](#实现一个服务类 "实现一个服务类的直接链接") 我们希望实现一个上述 HTTPClient 的服务工厂,用于在 midway 体系中创建多个 httpClient 对象。 服务工厂在 midway 中也是一个普通的导出类,作为服务的一员,比如我们也可以把他放到 `src/service/httpServiceFactory.ts` 中。 ### 1、实现创建实例接口[​](#1实现创建实例接口 "1、实现创建实例接口的直接链接") `ServiceFactory` 是个用于继承的抽象类,它包含一个泛型(创建的实例类型,比如下面就是创建出 HTTPClient 类型)。 我们只需要继承它,同时,一般服务工厂为单例。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { // ... } ``` 由于是抽象类,我们需要实现其中的两个方法。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { // 创建单个实例 protected createClient(config: any): any { return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `createClient` 方法用于传入一个创建服务配置(比如 httpClient 配置),返回一个具体的实例,就像示例中的那样。 `getName` 方法用于返回这个服务工厂的名字,方便框架识别和日志输出。 ### 2、增加配置和初始化方法[​](#2增加配置和初始化方法 "2、增加配置和初始化方法的直接链接") 我们需要注入一个配置,比如我们使用 `httpClient` 作为这个服务的配置。 ``` // config.default.ts export const httpClient = { // ... } ``` 然后注入到服务工厂中,同时,我们还需要在初始化时,调用创建多个实例的方法。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { @Config('httpClient') httpClientConfig; @Init() async init() { await this.initClients(this.httpClientConfig); } protected createClient(config: any): any { // 创建实例 return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `initClients` 方法是基类中实现的,它需要传递一个完整的用户配置,并循环调用 `createClient` 来创建对象,保存到内存中。 ### 3、实例化服务类[​](#3实例化服务类 "3、实例化服务类的直接链接") 为了方便用户使用,我们还需要提前将服务类创建,一般来说,只需要在组件或者项目的生命周期中实例化即可。 ``` import { Configuration } from '@midwayjs/core'; @Configuration({ imports: [ // ... ] }) export class ContainerConfiguration { async onReady(container) { // 实例化服务类 await container.getAsync(HTTPClientServiceFactory); } } ``` ## 获取实例[​](#获取实例 "获取实例的直接链接") `createClient` 方法只是定义了创建对象的方法,我们还需要定义配置的结构。 配置的结构分为几部分: * 1、默认配置,即所有对象都能复用的配置 * 2、单个实例需要的配置 * 3、多个实例需要的配置 我们来分别说明, **默认配置** 默认的配置,我们约定为 `default` 属性。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000 } } ``` ### 单个实例[​](#单个实例 "单个实例的直接链接") **单个配置** ``` // config.default.ts export const httpClient = { default: { timeout: 3000 }, client: { baseUrl: '' } } ``` `client` 用于单个实例结构的描述,创建对象时会和 `default` 做合并。使用 `get` 方法获取默认实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const httpClient = this.serviceFactory.get(); } } ``` ### 多个实例[​](#多个实例 "多个实例的直接链接") 使用 `clients` 来配置多个实例,每个 key 都是一个独立的实例配置。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000 }, clients: { aaa: { baseUrl: '' }, bbb: { baseUrl: '' } } } ``` 通过 key 来获取实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const aaaInstance = this.serviceFactory.get('aaa'); // ... const bbbInstance = this.serviceFactory.get('bbb'); // ... } } ``` ### 装饰器获取实例[​](#装饰器获取实例 "装饰器获取实例的直接链接") 从 v3.9.0 开始,ServiceFactory 添加了一个 `@InjectClient` 装饰器,方便在多客户端的的时候选择注入。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(HTTPClientServiceFactory, 'aaa') aaaInstance: HTTPClientServiceFactory; @InjectClient(HTTPClientServiceFactory, 'bbb') bbbInstance: HTTPClientServiceFactory; async invoke() { // this.aaaInstance.xxx // this.bbbInstance.xxx // ... } } ``` `@InjectClient` 装饰器用于快速注入 `ServiceFactory` 派生实现的多实例,所有扩展与 `ServiceFactory` 的类,都能使用。 装饰器包含两个参数,定义如下: ``` export function InjectClient( serviceFactoryClz: new (...args) => IServiceFactory, clientName?: string ) { // ... } ``` | 参数 | 描述 | | ----------------- | ------------------------------------------------------------------------- | | serviceFactoryClz | 必填,`ServiceFactory` 的派生类,装饰器会从中获取查找实例。 | | clientName | 可选,如果不填,默认会查找配置中的默认实例名 `defaultClientName` 配置项。 | ### 动态创建实例[​](#动态创建实例 "动态创建实例的直接链接") 也可以通过基类的 `createInstance` 方法动态获取实例。 警告 注意,这里使用的不是子类的 createClient,createClient 不包含和默认配置的逻辑。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { // 会合并 config.bucket3 和 config.default let customHttpClient = await this.serviceFactory.createInstance({ baseUrl: 'xxxxx' }, 'custom'); // 传了名字之后也可以从 factory 中获取 customHttpClient = this.serviceFactory.get('custom'); } } ``` `createInstance` 方法的第一个参数是配置,如果动态调用的时候,可以手动传参,第二个参数是一个字符串名称,如果传入了名称,创建完的实例将会保存到内存中,后续可以从服务工厂中再次获取。 ## 实例配置合并逻辑[​](#实例配置合并逻辑 "实例配置合并逻辑的直接链接") 在实际代码运行时,即使是单实例,配置一个 `client`,也会在内存中将配置变换为 `clients`。 比如下面的代码: ``` // config.default.ts export const httpClient = { client: { baseUrl: '' } } ``` 在内存中会变为: ``` // config.default.ts export const httpClient = { clients: { default: { baseUrl: '' } } } ``` 会多出一个名为 `default` 的默认实例,服务工厂会以 `clients` 的配置进行初始化。 ## 默认实例代理(可选)[​](#默认实例代理可选 "默认实例代理(可选)的直接链接") 如果用户每次使用时,都通过 `serviceFactory` 去获取,会非常的繁琐,对于最常用的默认实例,可以提供一个代理类,使其代理所有的目标实例方法。 ``` import { Provide, Scope, ScopeEnum, Init, ServiceFactory, MidwayCommonError, delegateTargetAllPrototypeMethod } from '@midwayjs/core'; // ... export class HTTPClientServiceFactory extends ServiceFactory { // ... } // 下面是默认代理类 @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientService implements HTTPClient { @Inject() private serviceFactory: HTTPClientServiceFactory; // 这个属性用于保存实际的实例 private instance: HTTPClient; @Init() async init() { // 在初始化阶段,从工厂拿到默认实例 this.instance = this.serviceFactory.get( this.serviceFactory.getDefaultClientName() || 'default' ); if (!this.instance) { throw new MidwayCommonError('http client default instance not found.'); } } } // 下面这段代码,用于默认实例类的 ts 定义正确被继承 // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface HTTPClientService extends HTTPClient { // empty } // 下面这段代码,用于默认实例类的实现可以被代理 delegateTargetAllPrototypeMethod(HTTPClientService, HTTPClient); ``` 通过上面的代码,我们就可以直接使用 `HTTPClientService` ,而无需从 `HTTPClientServiceFactory` 获取默认实例。 `delegateTargetAllPrototypeMethod` 是 Midway 提供的代理实例方法的工具方法。 此外,还有一些其他可用的工具方法,列举如下: * `delegateTargetAllPrototypeMethod` 用于代理目标所有的原型方法,包括原型链,不包括构造器和内部隐藏方法 * `delegateTargetPrototypeMethod` 用于代理目标所有的原型方法,不包括构造器和内部隐藏方法 * `delegateTargetMethod` 代理目标上指定的方法 ## 修改默认实例名[​](#修改默认实例名 "修改默认实例名的直接链接") 默认情况下,默认的实例名为 `default` ,默认的实例代理内部会根据该实例进行代理。 假如用户没有配置 `default` 实例,或者希望修改默认实例,用户通过配置修改。 ``` // config.default.ts export const httpClient = { clients: { default: { baseUrl: '' }, default2: { baseUrl: '' } }, defaultClientName: 'default2', } ``` 在默认的实例代理中,会通过 `this.serviceFactory.getDefaultClientName()` 来获取这个值。 ``` import { HTTPClientService } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() httpClientService: HTTPClientService; async invoke() { // this.httpClientService 中指向的是 default2 } } ``` ## 实例优先级[​](#实例优先级 "实例优先级的直接链接") 从 v3.14.0 开始,服务工厂的实例可以增加一个优先级属性,在不同的场景,会根据优先级做一些不同处理。 实例的优先级有 `L1`,`L2`, `L3`三个等级,分别对应高,中,低三个层级。 定义如下: ``` export const DEFAULT_PRIORITY = { L1: 'High', L2: 'Medium', L3: 'Low', }; ``` 通过配置,我们可以指定不同实例的优先级。 ``` // config.default.ts import { DEFAULT_PRIORITY } from '@midwayjs/core'; export default { httpClient: { clients: { default: { baseUrl: '' }, default2: { baseUrl: '' } }, clientPriority: { default: DEFAULT_PRIORITY.L1, default2: DEFAULT_PRIORITY.L2, } } } ``` 如果不做设置, 默认情况下优先级为中等,即 `DEFAULT_PRIORITY.L2`。 为了更好的判断优先级,`ServiceFactory` 基类中会增加一些方法。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientService implements HTTPClient { @Inject() private serviceFactory: HTTPClientServiceFactory; @Init() async init() { // 获取优先级 this.serviceFactory.getClientPriority('default'); // DEFAULT_PRIORITY.L2 // 判断优先级 this.serviceFactory.isHighPriority('default'); this.serviceFactory.isMediumPriority('default'); this.serviceFactory.isLowPriority('default'); } } ``` --- # 测试 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 所以,应用的 Controller、Service 等代码,都必须有对应的单元测试保证代码质量。 当然,框架和组件的每个功能改动和重构都需要有相应的单元测试,并且要求尽量做到修改的代码能被 100% 覆盖到。 当前社区的测试库主要是 `jest` 和 `mocha` ,本文以 `jest` 作为示例 。 ## 测试目录结构[​](#测试目录结构 "测试目录结构的直接链接") 我们约定 `test` 目录为存放所有测试脚本的目录,测试所使用到的 `fixtures` 和相关辅助脚本都应该放在此目录下。 测试脚本文件统一按 `${filename}.test.ts` 命名,必须以 `.test.ts` 作为文件后缀。 一个应用的测试目录示例: ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.controller.test.ts ├── package.json └── tsconfig.json ``` ## 测试运行工具[​](#测试运行工具 "测试运行工具的直接链接") Midway 默认提供 `midway-bin` 命令来运行测试脚本。在新版本中,Midway 默认将 mocha 替换成了 Jest,它的功能更为强大,集成度更高,这让我们**聚焦精力在编写测试代码**上,而不是纠结选择那些测试周边工具和模块。 只需要在 `package.json` 上配置好 `scripts.test` 即可。 * 直接使用 jest * 使用 @midwayjs/cli ``` { "scripts": { "test": "jest" } } ``` 然后就可以按标准的 `npm test` 来运行测试了,默认脚手架中,我们都已经提供了此命令,所以你可以开箱即用的运行测试。 ``` ➜ my_midway_app npm run test > my_midway_project@1.0.0 test /Users/harry/project/application/my_midway_app > jest Testing all *.test.ts... PASS test/controller/home.controller.test.ts PASS test/controller/api.controller.test.ts Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.26 s Ran all test suites matching /\/test\/[^.]*\.test\.ts$/i. ``` ``` { "scripts": { "test": "midway-bin test --ts" } } ``` 然后就可以按标准的 `npm test` 来运行测试了,默认脚手架中,我们都已经提供了此命令,所以你可以开箱即用的运行测试。 ``` ➜ my_midway_app npm run test > my_midway_project@1.0.0 test /Users/harry/project/application/my_midway_app > midway-bin test Testing all *.test.ts... PASS test/controller/home.controller.test.ts PASS test/controller/api.controller.test.ts Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.26 s Ran all test suites matching /\/test\/[^.]*\.test\.ts$/i. ``` ## 断言库[​](#断言库 "断言库的直接链接") jest 中自带了强大的 `expect` 断言库,可以直接在全局使用它。 比如常用的。 ``` expect(result.status).toBe(200); // 值是否等于某个值,引用相等 expect(result.status).not.toBe(200); expect(result).toEqual('hello'); // 简单匹配,对象属性相同也为 true expect(result).toStrictEqual('hello'); // 严格匹配 expect(['lime', 'apple']).toContain('lime'); // 判断是否在数组中 ``` 更多断言方法,请参考文档 ## 创建测试[​](#创建测试 "创建测试的直接链接") 不同的上层框架的测试方法不同,以最常用的 HTTP 服务举例,如果需要测试一个 HTTP 服务,一般来说,我们需要创建一个 HTTP 服务,然后用客户端请求它。 Midway 提供了一套基础的 `@midwayjs/mock` 工具集,可以帮助上层框架在这方面进行测试。同时也提供了方便的创建 Framework,App ,以及关闭的方法。 整个流程方法分为几个部分: * `createApp` 创建某个 Framework 的 app 对象 * `close` 关闭一个 Framework 或者一个 app 为保持测试简单,整个流程目前就透出这两个方法。 ``` // create app const app = await createApp(); ``` 这里传入的 `Framework` 是用来给 TypeScript 推导类型的。这样就可以返回主框架 app 实例了。 当 app 运行完成后,可以使用 `close` 方法关闭。 ``` import { createApp, close } from '@midwayjs/mock'; await close(app); ``` 事实上, `createApp` 方法中都是封装了 `@midwayjs/bootstrap` ,有兴趣的小伙伴可以阅读源码。 ## 测试 HTTP 服务[​](#测试-http-服务 "测试 HTTP 服务的直接链接") 除了创建 app 之外, `@midwayjs/mock` 还提供了简单的客户端方法,用于快速创建各种服务对应的测试行为。 比如,针对 HTTP,我们封装了 supertest,提供了 `createHttpRequest` 方法创建 HTTP 客户端。 ``` // 创建一个客户端请求 const result = await createHttpRequest(app).get('/'); // 测试返回结果 expect(result.text).toBe('Hello Midwayjs!'); ``` 推荐在一个测试文件中复用 app 实例。完整的测试示例如下。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/koa'; import * as assert from 'assert'; describe('test/controller/home.test.ts', () => { let app: Application; beforeAll(async () => { // 只创建一次 app,可以复用 app = await createApp(); }); afterAll(async () => { // close app await close(app); }); it('should GET /', async () => { // make request const result = await createHttpRequest(app) .get('/') .set('x-timeout', '5000'); // use expect by jest expect(result.status).toBe(200); expect(result.text).toBe('Hello Midwayjs!'); // or use assert assert.deepStrictEqual(result.status, 200); assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); }); it('should POST /', async () => { // make request const result = await createHttpRequest(app) .post('/') .send({id: '1'}); // use expect by jest expect(result.status).toBe(200); }); }); ``` **示例:** 创建 get 请求,传递 query 参数。 ``` const result = await createHttpRequest(app) .get('/set_header') .query({ name: 'harry' }); ``` 创建 post 请求,传递 body 参数。 ``` const result = await createHttpRequest(app) .post('/user/catchThrowWithValidate') .send({id: '1'}); ``` 创建 post 请求,传递 form body 参数。 ``` const result = await createHttpRequest(app) .post('/param/body') .type('form') .send({id: '1'}) ``` 传递 header 头。 ``` const result = await createHttpRequest(app) .get('/set_header') .set({ 'x-bbb': '123' }) .query({ name: 'harry' }); ``` 传递 cookie。 ``` const cookie = [ "koa.sess=eyJuYW1lIjoiaGFycnkiLCJfZXhwaXJlIjoxNjE0MTQ5OTQ5NDcyLCJfbWF4QWdlIjo4NjQwMDAwMH0=; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly", "koa.sess.sig=mMRQWascH-If2-BC7v8xfRbmiNo; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly" ] const result = await createHttpRequest(app) .get('/set_header') .set('Cookie', cookie) .query({ name: 'harry' }); ``` ## 测试服务[​](#测�试服务 "测试服务的直接链接") 在控制器之外,有时候我们需要对单个服务进行测试,我们可以从依赖注入容器中获取这个服务。 假设需要测试 `UserService` 。 ``` // src/service/user.ts import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async getUser() { // xxx } } ``` 那么在测试代码中这样写。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 class 获取实例(推荐) const userService = await app.getApplicationContext().getAsync(UserService); // 根据依赖注入 Id 获取实例 const userService = await app.getApplicationContext().getAsync('userService'); // 传入 class 忽略泛型也能正确推导 const userService = await app.getApplicationContext().getAsync(UserService); // close app await close(app); }); }); ``` 如果你的服务和请求相关联(ctx),可以使用请求作用域获取服务。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 Id 获取实例 const userService = await app.createAnonymousContext() .requestContext.getAsync('userService'); // 也能传入 class 获取实例 const userService = await app.createAnonymousContext() .requestContext.getAsync(UserService); // close app await close(app); }); }); ``` ## createApp 选项参数[​](#createapp-选项参数 "createApp 选项参数的直接链接") `createApp` 方法用于创建一个框架的 app 实例,通过传入泛型的框架类型,来使得我们推断出的 app 能够是该框架返回的 app。 比如: ``` import { Framework } from '@midwayjs/grpc'; // 这里的 app 能确保是 grpc 框架返回的 app const app = await createApp(); ``` `createApp` 方法其实是有参数的,它的方法签名如下。 ``` async createApp( appDir = process.cwd(), options: IConfigurationOptions = {} ) ``` 第一个参数为项目的绝对根目录路径,默认为 `process.cwd()` 。 第二个参数为 Bootstrap 的启动参数,比如一些全局行为的配置,具体可以参考 ts 定义。 ## close 选项参数[​](#close-选项参数 "close 选项参数的直接链接") `close` 方法用于关闭该 app 实例相关的框架。 ``` await close(app); ``` 其有一些参数。 ``` export declare function close( app: IMidwayApplication | IMidwayFramework, options?: { cleanLogsDir?: boolean; cleanTempDir?: boolean; sleep?: number; }): Promise; ``` 第一个参数是 app 或者 framework 的实例。 第二个参数是个对象,在执行关闭时可以执行一些行为: * 1、 `cleanLogsDir` 默认为 false,控制测试完成后删除日志 logs 目录(windows 除外) * 2、 `cleanTempDir` 默认为 false,清理一些临时目录(比如 egg 生成的 run 目录) * 3、 `sleep` 默认为 50,单位毫秒,关闭 app 后延迟的时间(防止日志没有成功写入) ## 使用 bootstrap 文件测试[​](#使用-bootstrap-文件测试 "使用 bootstrap 文件测试的直接链接") 一般情况下,你无需用到 `bootstrap.js` 来测试。如果你希望直接使用 `bootstrap.js` 入口文件直接测试,那么可以在测试的时候传递入口文件信息。 和 dev/test 启动不同的是,使用 `bootstrap.js` 启动是一个真实的服务,会同时运行多个框架,创建出多个框架的 app 实例。 `@midwayjs/mock` 提供了 `createBootstrap` 方法做启动文件类型的测试。我们可以将入口文件 `bootstrap.js` 作为启动参数传入,这样 `createBootstrap` 方法会通过入口文件来启动代码。 ``` it('should GET /', async () => { // create app const bootstrap = await createBootstrap(join(process.cwd(), 'bootstrap.js')); // 根据框架类型获取 app 实例 const app = bootstrap.getApp('koa'); // expect and test // close bootstrap await bootstrap.close(); }); ``` ## 运行单个测试[​](#运行单个测试 "运行单个测试的直接链接") 和 mocha 的 `only` 不同,jest 的 `only` 方法只针对单个文件生效。 * 直接使用 jest * 使用 @midwayjs/cli 执行单个文件。 ``` $ jest test/controller/api.ts ``` 如果你想运行文件中的特定测试,你可以使用 jest 的 `-t` 或 `--testNamePattern` 选项,后面跟上你想运行的测试的名称。例如: ``` $ jest -t "name of your test" ``` 这将只运行名称匹配的测试。 `midway-bin` 提供可以运行单个文件的能力。 ``` $ midway-bin test -f test/controller/api.ts ``` 这样可以指定运行某个文件的测试,再配合 `describe.only` 和 `it.only` ,这样可以只运行单个文件中的单个测试方法。 `midway-bin test --ts` 等价于直接使用 jest 的下面的命令。 ``` $ node --require=ts-node/register ./node_modules/.bin/jest ``` ## 自定义 Jest 文件内容[​](#自定义-jest-文件内容 "自定义 Jest 文件内容的直接链接") 一般情况下,Midway 工具链内置了 jest 配置,使得用户无需再添加该文件,但是有些特殊的场景下,比如使用 VSCode 或者 Idea 等编辑器,需要在可视化区域进行开发和测试时,可能会需要指定一个 `jest.config.js` 的场景,这种情况下,Midway 支持创建一个自定义的 jest 配置文件。 在项目根目录创建一个 `jest.config.js` 文件。 ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.test.ts ├── jest.config.js ├── package.json └── tsconfig.json ``` 内容如下,配置和标准的 jest 相同。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], }; ``` ## 常见设置[​](#常见设置 "常见设置的直接链接") 如果需要在单测前执行一些代码,可以增加 `jest.setup.js` ,增加配置如下。 ``` const path = require('path'); module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], setupFilesAfterEnv: ['/jest.setup.js'], // 预先读取 jest.setup.js }; ``` 警告 注意, `jest.setup.js` 只能使用 js 文件。 ### 示例一:测试代码时间较长的问题[​](#示例一测试代码时间较长的问题 "示例一:测试代码时间较长的问题的直接链接") 如果测试出现下面的错误,说明你的代码执行时间比较长(比如连接数据库,跑任务等),如果确定代码没有问题,就需要延长启动时间。 ``` Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout. ``` jest 默认时间为 **5000ms(5秒钟)**,我们可以将它调整到更多。 可以通过在 `package.json` 启动时修改。 * 直接使用 jest * 使用 @midwayjs/cli ``` { "scripts": { "test": "jest --testTimeout=30000" } } ``` ``` { "scripts": { "test": "midway-bin test --ts --testTimeout=30000" } } ``` 这里的 `testTimeout` 是 jest 的启动参数。 我们可以在 `jest.setup.js` 文件中写入下面的代码,对 jest 超时时间做调整。 ``` // jest.setup.js jest.setTimeout(30000); ``` ### 示例二:全局环境变量[​](#示例二全局环境变量 "示例二:全局环境变量的直接链接") 同理, `jest.setup.js` 也可以执行自定义的代码,比如设置全局环境变量。 ``` // jest.setup.js process.env.MIDWAY_TS_MODE = 'true'; ``` ### 示例三:程序无法正常退出的处理[​](#示例三程序无法正常退出的处理 "示例三:程序无法正常退出的处理的直接链接") 有时候,由于一些代码(定时器,监听等)在后台运行,导致单测跑完后会无法退出进程,对于这个情况,jest 提供了 `--forceExit` 参数。 * 直接使用 jest * 使用 @midwayjs/cli ``` $ jest --forceExit $ jest --coverage --forceExit ``` ``` $ midway-bin test --ts --forceExit $ midway-bin cov --ts --forceExit ``` 这里的 `testTimeout` 是 jest 的启动参数。 也可以在自定义文件中,增加属性。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], forceExit: true, }; ``` ### 示例四:并行改串行执行[​](#示例四并行改串行执行 "示例四:并行改串行执行的直接链接") jest 默认为每个测试文件并行处理,如果测试代码中有启动端口等场景,并行处理可能会导致端口冲突而报错,这个时候需要加 `--runInBand` 参数,注意,这个参数只能加载命令中。 * 直接使用 jest * 使用 @midwayjs/cli ``` $ jest --runInBand $ jest --coverage --runInBand ``` ``` $ midway-bin test --ts --runInBand $ midway-bin cov --ts --runInBand ``` ## 编辑器配置[​](#编辑器配置 "编辑器配置的直接链接") ### Jetbrain Webstorm/Idea 配置[​](#jetbrain-webstormidea-配置 "Jetbrain Webstorm/Idea 配置的直接链接") 在 Jetbrain 的编辑器使用,需要启用 "jest" 插件,由于使用了子进程的方式启动,我们依旧需要在启动时指定加载 `--require=ts-node/register` 。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01Wa6UaE1p0zU82gnpL_!!6000000005299-2-tps-1500-951.png) ### VSCode 配置[​](#vscode-配置 "VSCode 配置的直接链接") 先搜索插件,安装 Jest Runner。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01D6zTxi1GiwwrqhHVW_!!6000000000657-2-tps-1242-877.png) 打开配置,配置 jest 命令路径。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN017BK54o1n2FL7x8hI0_!!6000000005031-2-tps-1266-849.png) 在 jest command 处填入 `node --require=ts-node/register ./node_modules/.bin/jest` 。 或者是在工作区文件夹 .vscode 里面设置 settings.json。 ``` { "jest.pathToJest": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles", "jestrunner.jestCommand": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles" } ``` 由于 jest runner 插件的调试使用的是 VSCode 的调试,需要单独配置 VSCode 的 launch.json。 在文件夹 .vscode 里面设置 launch.json ``` { "version": "0.0.1", "configurations": [ { "name": "Debug Jest Tests", "type": "node", "request": "launch", "runtimeArgs": [ "--inspect-brk", "--require=ts-node/register", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "--detectOpenHandles" ], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] } ``` ## 关于 alias paths[​](#关于-alias-paths "关于 alias paths的直接链接") `mwtsc` 工具不支持 Alias Path 功能。 ## 关于 mock 数据[​](#关于-mock-数据 "关于 mock 数据的直接链接") 模拟数据是一个可以在开发和测试中都通用的能力,更多请查看 [模拟数据](/docs/3.0.0/mock.md)。 --- # Midway CLI 提示 由于 CLI 底层能力都来源于社区现有的模块功能,为了减少过渡封装带来的维护成本和理解成本,CLI 中的各项功能都将逐步变为社区现有的模块,同时 CLI 库将停止继续迭代。 为此后续的变化为 * 开发将从 `midway-bin dev` 变为 `mwtsc` * 编译将从 `midway-bin build` 变为 `tsc` * 测试将从 `midway-bin test` 变为 `mocha` 或者 `jest` * 覆盖率将从 `midway-bin cov` 变为 `jest --coverage` 或者其他类似指令 `@midwayjs/cli` 是新版本的 Midway 体系工具链,和 Serverless,以及原应用的工具链进行了整合。 ## 基础入口[​](#基础入口 "基础入口的直接链接") `@midwayjs/cli` 提供了两个入口命令。 `midway-bin` 和 `mw` 命令。 当 `@midwayjs/cli` 安装到全局时,一般使用 `mw` 命令,比如 `mw dev` 。当安装到项目中,做 cli 工具时,我们一般使用 `midway-bin` 命令,但是请记住,这两个命令是相同的。 ## dev 命令[​](#dev-命令 "dev 命令的直接链接") 以当前目录启动本地开发命令。 ``` $ mw dev --baseDir 应用目录,一般为 package.json 所在文件夹,默认为 process.cwd() --sourceDir ts代码目录,默认会自动分析 -p, --port dev侦听的端口,默认为 7001 --ts TS模式运行代码 --fast 极速模式 --framework 指定框架,默认会自动分析 -f, --entryFile 指定使用入口文件来启动 bootstrap.js --watchFile 更多的文件或文件夹修改侦听 --notWatch 代码变化时不自动重启 ``` ### **标准启动**[​](#标准启动 "标准启动的直接链接") ``` $ midway-bin dev --ts ``` ### **修改启动端口**[​](#修改启动端口 "修改启动端口的直接链接") 针对 HTTP 场景, `-p` 或者 `--port` 可以临时修改端口。 ``` $ midway-bin dev --ts --port=7002 ``` ### **修改启动路径**[​](#修改启动路径 "修改启动路径的直接链接") 指定应用根目录,一般为 package.json 所在文件夹,默认为 process.cwd() ``` $ midway-bin dev --ts --baseDir=./app ``` ### **修改ts源码路径**[​](#修改ts源码路径 "修改ts源码路径的直接链接") 指定ts代码目录,默认会自动分析 ``` $ midway-bin dev --ts --sourceDir=./app/src ``` ### **修改 tsconfig.json 的位置**[​](#修改-tsconfigjson-的位置 "修改-tsconfigjson-的位置的直接链接") 通过设置 [TS\_NODE\_PROJECT](https://github.com/TypeStrong/ts-node#project) 环境变量来指定tsconfig.json的位置。 ``` $ cross-env TS_NODE_PROJECT=./tsconfig.dev.json midway-bin dev -ts ``` ### **更快的启动方式**[​](#更快的启动方式 "更快的启动方式的直接链接") 默认的启动方式为 ts-node,在文件数量特别多的情况下会比较慢,可以切换为 swc 等新的编译方式。 ``` // 使用 ts-node 的快速dev模式 $ midway-bin dev --ts --fast // 使用 swc 的快速dev模式 $ midway-bin dev --ts --fast=swc ``` ### 监听文件变化[​](#监听文件变化 "监听文件变化的直接链接") `--watchFile` 用于指定更多的文件或文件夹修改侦听,默认侦听 `sourceDir` 目录中 `.ts`、`.yml`和 `.json`结尾的文件(可通过 --watchExt 参数指定更多扩展名),以及 `baseDir` 目录中的 `f.yml` 文件 ``` // 指定多个文件,使用英文逗号分隔 $ midway-bin dev --ts --watchFile=./a.txt,./b.txt // 指定多个文件夹和文件,使用英文逗号分隔 $ midway-bin dev --ts --watchFile=./test,./b.txt ``` * `--watchExt`:指定更多的侦听文件扩展名,默认为 `.ts`、`.yml`和 `.json` ``` // 指定多个文件扩展名,使用英文逗号分隔 $ midway-bin dev --ts --watchExt=.js,.html ``` ### 本地单步Debug调试[​](#本地单步debug调试 "本地单步Debug调试的直接链接") `--debug` 参数启动 debug 模式,可以通过 `chrome devtools` 进行单步代码调试: ![69456694-513D-4388-B52F-001562D4A520.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994136312-f1eda8ba-165d-4322-82b8-b21d3b9c6beb.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=177\&id=z4u1f\&margin=%5Bobject%20Object%5D\&name=69456694-513D-4388-B52F-001562D4A520.png\&originHeight=666\&originWidth=1538\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=276022\&status=done\&style=none\&taskId=ud161d835-1e96-4246-8061-c795e9a0ff1\&title=\&width=409) 您可以通过 `chrome://inspect/` 打开 `nodejs devtools` 进行断点调试: ![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995391144-a9ec0d4a-c6fb-4638-a292-615a3588d33d.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=236\&id=u4986bfa4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=1948\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=572568\&status=done\&style=none\&taskId=u07555349-8e09-42b2-bd94-f93160b0431\&title=\&width=488) ![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995418427-282d256a-de65-4eba-9a83-b474d3d74f9f.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=445\&id=u83271ad1\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1280\&originWidth=2280\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=710504\&status=done\&style=none\&taskId=uc2614db9-dea9-48d7-b87d-8cb608c8770\&title=\&width=792) 您也可以直接通过 chrome 浏览器打开命令行中输出的 `devtools` 协议的链接,给对应代码添加断点后调试: ![10016148-385E-46A4-8B3A-0A0110BECD18.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994137067-f663409a-483d-41f5-bc86-4798182edb38.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=135\&id=GooAh\&margin=%5Bobject%20Object%5D\&name=10016148-385E-46A4-8B3A-0A0110BECD18.png\&originHeight=950\&originWidth=2878\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=744085\&status=done\&style=none\&taskId=u892d9925-9206-4946-a1ed-cb6043c557d\&title=\&width=409) 如果您使用 `vscode` ,那么您可以使用 vscode 的 js debug terminal,在其中执行 dev 命令(无需添加 `--debug` 参数)启动就可以打断点调试了。![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1625237917317-8e7bf448-fded-4bc7-b743-6aade0ebcba2.png#clientId=u7c8a3183-c32b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=650\&id=u75e3aec7\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1300\&originWidth=2868\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=1140427\&status=done\&style=none\&taskId=ubcffa6c8-02eb-4256-ba7e-7ab3128c1ee\&title=\&width=1434) ## test 命令[​](#test-命令 "test 命令的直接链接") 以当前目录启动测试,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin test --ts -c, --cov 获取代码测试覆盖率 -f, --file 指定测试文件,例如 ./test/index.test.ts --ts TS模式运行单测 --forceExit jest forceExit --runInBand jest runInBand -w, --watch watch模式 --mocha 使用 mocha 进行单测 ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 信息 如果项目中使用了 TypeScript 的 path alias,请参考:[测试](/docs/3.0.0/testing.md#%E9%85%8D%E7%BD%AE-alias-paths) ### 使用 mocha 替代 jest[​](#使用-mocha-替代-jest "使用 mocha 替代 jest的直接链接") 有些同学对 mocha 情有独钟,希望使用 mocha 作为测试工具。 可以使用 mocha 模式进行测试。 ``` $ midway-bin test --ts --mocha ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 ### 配置 alias paths[​](#配置-alias-paths "配置 alias paths的直接链接") 当你在 `tsconfig.json` 中配置了 paths 之后,并且模块包导入使用了 paths ,则会存在 mocha 做单元测试会导致路径无法被解析,无法使用通过导入 `tsconfig-paths/register` 解决 ``` // src/configuration.ts import 'tsconfig-paths/register'; // ... ``` 需要添加 `tsconfig-paths` 并且在测试的时候引用进行处理 ``` $ npm install --save-dev tsconfig-paths ``` ``` $ midway-bin test --ts --mocha -r tsconfig-paths/register ``` 信息 注意,由于 mocha 没有自带断言工具,需要使用其他如 assert,chai 等工具进行断言。 ## cov 命令[​](#cov-命令 "cov 命令的直接链接") 以当前目录启动测试,并输出覆盖率信息,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin cov --ts ``` 当使用 mocha 进行单测覆盖率时,您需要安装以下额外依赖。 ``` $ npm i mocha @types/mocha nyc --save-dev ``` ## check 命令[​](#check-命令 "check 命令的直接链接") 自动分析代码中存在的问题,并给出修复建议。 ``` $ midway-bin check ``` 目前已提供 `32` 项问题的校验。 ## build 命令[​](#build-命令 "build 命令的直接链接") 使用 mwcc(tsc)进行 ts 代码编译,适用于标准项目,Serverless 项目请使用 package。 ``` $ midway-bin build -c -c, --clean 清理构建结果目录 --srcDir 源代码目录,默认 src --outDir 构建输出目录,默认为 tsconfig 中的 outDir 或 dist --tsConfig tsConfig json 字符串或文件位置 --buildCache 保留构建缓存 ``` ## deploy 命令[​](#deploy-命令 "deploy 命令的直接链接") 适用于 Serverless 项目发布到 Aliyun FC、Tencent SCF、Aws Lambda 等运行时。 执行 deploy 命令会自动执行 package。 ``` $ midway-bin deploy -y, --yes 发布的确认都是yes --resetConfig 重置发布配置,AK/AK/Region等 --serverlessDev 使用 Serverless Dev 进行aliyun fc函数发布,目前默认为 funcraft ...兼容package命令的所有参数 ``` #### 函数发布时域名配置[​](#函数发布时域名配置 "函数发布时域名配置的直接链接") 在 `f.yml` 中配置 `custom.customDomain` 为 `auto` ,则在发布时会配置一个临时的自动域名: ``` custom: customDomain: auto ``` 如果要取消自动的域名,将 `customDomain` 改为 `false`: ``` custom: customDomain: false ``` 如果有自定义域名,在 `customDomain` 中配置即可: ``` custom: customDomain: domainName: test.example.com ``` 如果自定义的域名,需要使用 https,那么在 云控制台 配置好 https 证书之后,需要将 customDomain 设置为 false,避免下次发布时重置成 http: ``` custom: customDomain: false ``` #### 每个路由都部署成了一个函数[​](#每个路由都部署成了一个函数 "每个路由都部署成了一个函数的直接链接") 可以使用高密度方案,合并成一个函数,f.yml 加如下配置 ``` aggregation: main: functionsPattern: - '*' ``` #### #### aliyun 发布 AK 错误问题[​](#aliyun-发布-ak-错误问题 "aliyun 发布 AK 错误问题的直接链接") 在第一次进行aliyun发布或使用 `--resetConfig`参数的时候都可以重置 ak。 不过要注意的是每次 ak 都会默认创建一个新的 `access` 分组,在修改配置时会自动生成分组名,如果要覆盖之前的 AK 需要手动输入,如图: ![image.png](https://cdn.nlark.com/yuque/0/2022/png/128621/1645609990378-8a7f92c0-bda4-46e0-93a6-4d6feb6ec66d.png#clientId=u9f50c864-5385-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=122\&id=u8a756167\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=122\&originWidth=693\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=17245\&status=done\&style=none\&taskId=u3b825703-abe6-4a2b-ae5f-86a88027cf8\&title=\&width=693) 发布时默认使用的分组为 `default`,如果您在修改配置时如上图使用了 `default-2`,那么需要在发布的时候通过 `--access`参数指定使用 `default-2`: ``` midway-bin deploy --access=default-2 ``` ## package 命令[​](#package-命令 "package 命令的直接链接") 适用于 Serverless 项目构建 ``` $ midway-bin package --npm npm client,默认为自动识别添加registry --sourceDir 源代码所在目录,默认会自动分析 --buildDir 构建结果目标目录 --sharedTargetDir 共享文件目标目录,默认为static,参考 --sharedDir 参数 --sharedDir 构建时会拷贝此目录到结果目录内的 $sharedTargetDir 目录 --skipZip 跳过zip打包 --skipBuild 跳过ts代码构建 --tsConfig tsConfig json 字符串或文件位置 --function 指定打包哪几个函数,多个使用英文 , 分隔 ``` #### 参数详解[​](#参数详解 "参数详解的直接链接") * `--function`:指定打包哪几个函数,多个函数使用英文 , 分隔 ``` // 打包 midway-bin package --function=a,b,c // 发布 midway-bin deploy --function=a,b,c ``` #### 函数构建打包时文件拷贝逻辑[​](#函数构建打包时文件拷贝逻辑 "函数构建打包时文件拷贝逻辑的直接链接") 默认拷贝的内容包含 `后端代码文件夹` (一般为 `src` 、faas前后端一体化一般为 `src/apis`)内的所有非 `.ts` 后缀的文件,以及 `项目根目录` 下的以 `.js`、`.json`、`.yml` 为扩展名的所有文件和 `config` 、`app` 文件夹内的所有文件。 如果要拷贝额外的文件,可以通过在 `f.yml` 文件中添加 `package`字段 中的 `include` 来指定,可以配置文件名,也可以通过 `fast-glob` [语法↗](https://github.com/mrmlnc/fast-glob#pattern-syntax) 匹配,使用示例如下: ``` # ...已省略其他属性的展示 package: include: # 通过 include 属性指定额外打包文件配置 - static # 项目根目录下的 static 文件夹 - a.json # 项目根目录下的 a.json 文件 - a/b/c.js # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - a/b/c.json # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - xxx/**/*.js # 项目根目录下的 xxx 目录下的所有 js 文件 ``` ## 实验性功能[​](#实验性功能 "实验性功能的直接链接") 在 `f.yml` 中通过 `experimentalFeatures` 配置开启实验性功能 ### 1. ignoreTsError[​](#1-ignoretserror "1. ignoreTsError的直接链接") 在构建时忽略ts error,不中断构建过程。 ``` experimentalFeatures: ignoreTsError: true ``` ### 2. removeUselessFiles[​](#2-removeuselessfiles "2. removeUselessFiles的直接链接") 在构建时移除大量无效文件,例如 `LICENSE`、`*.ts.map`、`**/test/` 等文件,可以有效减少构建包尺寸。 ``` experimentalFeatures: removeUselessFiles: true ``` ### 3. fastInstallNodeModules[​](#3-fastinstallnodemodules "3. fastInstallNodeModules的直接链接") 在构建时从当前的 devDependencies 中挑选出 production 依赖进行发布,可能会显著提升发布速度。 ``` experimentalFeatures: fastInstallNodeModules: true ``` ## CLI 扩展[​](#cli-扩展 "CLI 扩展的直接链接") ### 1. 生命周期扩展[​](#1-生命周期扩展 "1. 生命周期扩展的直接链接") 用户可以在 `package.json` 中添加 `midway-integration` 字段来根据各个命令的生命周期扩展 cli 的行为。 比如,在 package 命令 `installDevDep` 的后面添加自定义逻辑: ``` { "midway-integration": { "lifecycle": { "after:package:installDevDep": "npm run build" } } } ``` 其中 `lifecycle` 的格式为 `${ 'before' | 'after' | '' }:${ 命令 }:${ 命令生命周期 }` 。 package命令的声明周期列表: ``` 'cleanup', // 清理构建目录 'installDevDep', // 安装开发期依赖 'copyFile', // 拷贝文件: package.include 和 shared content 'compile', // 'emit', // 编译函数 'package:after:tscompile' 'analysisCode', // 分析代码 'copyStaticFile', // 拷贝src中的静态文件到dist目录,例如 html 等 'checkAggregation', // 检测高密度部署 'generateSpec', // 生成对应平台的描述文件,例如 serverless.yml 等 'generateEntry', // 生成对应平台的入口文件 'installLayer', // 安装layer 'installDep', // 安装依赖 'package', // 函数打包 'finalize', // 完成 ``` ### 2. 通过插件进行扩展[​](#2-通过插件进行扩展 "2. 通过插件进行扩展的直接链接") 用户可以自己编写 cli 插件,通过插件来实现更为复杂的 cli 的行为,也可以添加自定义命令。 目前支持两种插件: * npm 插件,插件是一个npm包 * local 插件,插件在本地位置 * 通过在 f.yml 文件中配置 `plugins` 字段使 cli 加载插件: ``` plugins: - npm::test-plugin-model - local::./test/plugin ``` plugin 配置格式为: `${ 'npm' | 'local' }:${ provider || '' }:${ pluginName || path }` 插件的代码参考: ``` // src/index.ts import { BasePlugin } from '@midwayjs/command-core'; export class TestLalalaPlugin extends BasePlugin { commands = { lalala: { usage: '自定义命令', lifecycleEvents: [ 'a', // 自定义生命周期 'b', ], // 暂无 options: { name: { usage: '参数 name, 例如: mw lalala --name=123', shortcut: 'n', // 参数缩写 }, }, }, }; hooks = { // 添加当前插件内的命令生命周期扩展 // lalala 命令的 a 生命周期 'lalala:a': async () => { // 输出 this.core.cli.log('lalala command hook'); // 获取用户输入的参数 this.core.cli.log(this.core.options); // f.yml 内容 this.core.cli.log(this.core.service); // 仅在 -V 参数下输出的内容 this.core.debug('lalala'); }, // 添加其他插件内的命令生命周期扩展 // 在 package 命令的 copyFile 生命周期 “之前” 执行 'before:package:copyFile': async () => { console.log('package command hook'); }, }; } ``` --- # 脚手架 Midway 编写了 `create-midway` 包,通过 npx 命令,可以方便的使用 `npm init midway` 命令创建脚手架。 ``` $ npm init midway@latest -y ``` 提示 如果不加 @latest 的 tag,可能不会更新到最新版本。 ## 通过 CLI 创建脚手架[​](#通过-cli-创建脚手架 "通过 CLI 创建脚手架的直接链接") ### 默认行为[​](#默认行为 "默认行为的直接链接") 不传递参数,可以列出当前最常用的模版列表。 比如执行 ``` $ npm init midway@latest -y ``` 则会输出 ``` ➜ ~ npm init midway ? Hello, traveller. Which template do you like? … ⊙ v3 ❯ koa-v3 - A web application boilerplate with midway v3(koa) egg-v3 - A web application boilerplate with midway v3(egg 2.0) faas-v3 - A serverless application boilerplate with midway v3(faas) component-v3 - A midway component boilerplate for v3 quick-start - A midway quickstart exmaple for v3 ⊙ v3-esm koa-v3-esm - A web application boilerplate with midway v3(koa) ⊙ v2 web - A web application boilerplate with midway and Egg.js koa - A web application boilerplate with midway and koa ``` 该模式下,会根据用户选择,按照指引创建模版。 ### 关于参数传递[​](#关于参数传递 "关于参数传递的直接链接") 由于 `npm init midway` 等价与 `npm exec create-midway`,根据不同的 npm 版本,[传递参数](https://docs.npmjs.com/cli/v10/commands/npm-exec) 的格式不同。 比如在最新的 npm 中,使用额外的 `--` 传递参数。 比如 ``` $ npm init midway -- -h ``` `-h` 参数可以显式所有的可用选项。 下面所有的参数示例,都将以这个模式展示。 ### 显式所有模版[​](#显式所有模版 "显式所有模版的直接链接") 非当前版本的模版,会默认隐藏,可以通过 `-a` 参数展示所有内置的模版。 ``` $ npm init midway -- -a ``` ### 指定模版名[​](#指定模版名 "指定模版名的直接链接") 每个模版都有一个模版名和模版描述,比如 `koa-v3 - A web application boilerplate with midway v3(koa)` 的模板名为 `koa-v3`。 可以通过 `--type` 参数指定模板名。 ``` $ npm init midway -- --type=koa-v3 ``` ### 指定模版包名[​](#指定模版包名 "指定模版包名的直接链接") 当自定义模版在 npm 上发布时,我们可以使用 `-t` 或者 `--template` 来指定包名。 ``` $ npm init midway -- -t=custom-template ``` 如果包还在本地开发,也可以指定一个相对路径或者绝对路径。 ``` $ npm init midway -- -t=./custom-template ``` ### 指定创建目标目录[​](#指定创建目标目录 "指定创建目标目录的直接链接") 通过 `--target` 参数可以指定创建的目录,必须和 `type` 或者 `template` 参数一同使用。 比如,下面的命令指定了 `koa-v3` 模版,将其生成到当前 abc 目录下,如果目录不存在,则会新建。 ``` $ npm init midway -- --type=koa-v3 --target=abc ``` 一般 `target` 可以省略,把路径放到最后一个参数即可。 ``` $ npm init midway -- --type=koa-v3 abc ``` ### 指定客户端[​](#指定客户端 "指定客户端的直接链接") 如果有私有客户端,可以使用 `--npm` 指定客户端。 ``` $ npm init midway -- --npm=tnpm ``` ### 指定源[​](#指定源 "指定源的直接链接") 如果有私有源,可以使用 `--registry` 指定私有源。 ``` $ npm init midway -- --registry=https://registry.npmmirror.com ``` ### 脚手架参数[​](#脚手架参数 "脚手架参数的直接链接") 如果脚手架中包含用户可传递的参数,也可以通过命令行传递。 ``` $ npm init midway -- --bbb=ccc ``` 如果参数名和工具的参数重复了,可以使用 `t_` 的参数,在工具传递给脚手架时,会自动处理。 ``` $ npm init midway -- --type=koa-v3 --t_type=ccc ``` ## 编写脚手架[​](#编写脚手架 "编写脚手架的直接链接") Midway 脚手架使用了自研的 light-generator 工具,具体的使用可以参考 。 也可以参考 Midway 自己的 [模版工程](https://github.com/midwayjs/midway-boilerplate/tree/master/v3)。 --- # egg:ts-helper 针对 midway 支持 Egg.js 的场景,重写了原 [egg-ts-helper](https://github.com/whxaxes/egg-ts-helper) 包,移除了原有的 TS,AST 分析等大依赖。 原来的包依赖的 ts v3 环境,依赖 egg 的目录结构,考虑非常多的可能性,在 midway 的场景中不会使用到。基于上述考虑 midway 将此包进行了重写,用最简单的方式提供 egg 定义。 [@midwayjs/egg-ts-helper](https://github.com/midwayjs/egg-ts-helper) 包提供 `ets` 全局命令。 ``` $ npm i @midwayjs/egg-ts-helper --save-dev $ ets ``` 一般我们会在开发命令里加入。 ``` "scripts": { "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", }, ``` 信息 此包是针对 midway 定制的,只能用于新版本 midway 及其配套代码。 最终会在项目根目录生成 `typings` 目录,其定义结构和文件如下: ``` . ├── ... └── typings ├── extend │ ├── request.d.ts │ ├── response.d.ts │ ├── application.d.ts │ └── context.d.ts ├── app │ └── index.d.ts └── config ├── index.d.ts └── plugin.d.ts ``` 警告 注意,该模块只是将 midway v2(Egg.js)的框架 + 插件定义聚合到一起,让当前的业务代码能够顺利的读取到框架和插件的定义,不支持生成业务代码本身的定义,也不支持在开发 egg 插件时生成定义。 --- # 规则检查工具 Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。`@midwayjs/luckyeye` 包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 > luckyeye,寓意为幸运眼,能快速发现和定位问题。 ## 使用[​](#使用 "使用的直接链接") 首先安装 `@midwayjs/luckyeye` 包。 ``` npm i @midwayjs/luckyeye --save-dev ``` 一般情况下,我们会将它加入到一个检查脚本中,比如: ``` "scripts": { // ...... "check": "luckyeye" }, ``` 接下去,我们需要配置“规则包”,比如 `midway_v2` 就是针对 midway v2 版本的规则检查包。 在 `package.json` 中加入下面的段落。 ``` "midway-luckyeye": { "packages": [ "midway_v2" ] }, ``` ## 执行[​](#执行 "执行的直接链接") 配置完后,可以执行上面添加的检查脚本。 ``` npm run check ``` **蓝色**代表输出的信息,用于排错,**绿色**代表检查项通过,**红色**代表检查项有问题,需要修改,**黄色**代表检查项可以做修改,但是可选。 执行效果如下。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1610983986151-79c54e7c-3ff0-4f94-98bc-359dda0fa694.png) ## 自定义规则包[​](#自定义规则包 "自定义规则包的直接链接") 请参考 的 README。 --- # Lint 和格式化 Midway 的框架和业务代码都是由 TypeScript 编写的,默认 Midway 提供了一套默认的 lint、编辑器以及格式化规则,用于更方便的进行开发和测试。 ## 代码风格库[​](#代码风格库 "代码风格库的直接链接") Midway 的代码风格库叫 [mwts](https://github.com/midwayjs/mwts),源自于 Google 的 [gts](https://github.com/google/gts)。mwts 是 Midway 的 TypeScript 样式指南,也是格式化程序,linter 和自动代码修复程序的配置。 信息 在 midway 项目中,我们会默认添加 mwts,下面的流程只是为了说明如何使用 mwts。 为了使用 mwts,我们需要把它添加到开发依赖中。 ``` "devDependencies": { "mwts": "^1.0.5", "typescript": "^4.0.0" }, ``` ## ESLint 配置[​](#eslint-配置 "ESLint 配置的直接链接") mwts 提供了一套默认的 ESLint 配置(TSLint 已经废弃,合并到了 ESLint 中)。 在项目根目录创建 `.eslintrc.json` 文件,内容如下(一般脚手架会自带): ``` { "extends": "./node_modules/mwts/", "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "interface.ts"], "env": { "jest": true } } ``` 上面是 midway 项目的默认配置,其他项目 `ignorePatterns` 和 `env` 可以自行根据 ESLint 自行调整。 整个 mwts 的默认规则请参考 [这里](https://github.com/midwayjs/mwts/blob/master/.eslintrc.json),如有需求,可以自行调整。 ## 执行代码检查和格式化[​](#执行代码检查和格式化 "执行代码检查和格式化的直接链接") 可以通过执行 `mwts check` 命令和 `mwts fix` 命令,来检查代码。比如在项目中增加脚本命令(一般脚手架会自带)。 ``` "scripts": { "lint": "mwts check", "lint:fix": "mwts fix", }, ``` ## Prettier 配置[​](#prettier-配置 "Prettier 配置的直接链接") mwts 提供了一套默认的 prettier 配置,创建一个 `.prettierrc.js` 文件,配置内容如下即可(一般脚手架自带)。 ``` module.exports = { ...require('mwts/.prettierrc.json'), }; ``` ## 配置保存自动格式化[​](#配置保存自动格式化 "配置保存自动格式化的直接链接") 我们以 VSCode 为例。 第一步,安装 Prettier 插件。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618042429530-177c3636-aefc-419d-8d3a-5258cad13631.png) 打开配置,搜索 “save”,找到右侧的 "Format On Save",勾选即可。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618042494782-71b6cc3c-18ae-4344-987b-ec82084f2dd8.png) 如果保存文件没有效果,一般是编辑器有多个格式化方式,可以右键进行默认选择。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125271116-845e8452-0f7b-46a9-a28a-388f2db9c5e3.png) 选择 “配置默认格式化程序”。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125381302-d3fe30c1-e56d-43f8-ada2-6e315f4ff2c4.png) 选择 Prettier 即可。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1618125423564-8e46b0f8-f422-4e3d-a805-3b0a1db037f8.png) --- # 开发工具 基于标准的 tsc 模块,midway 开发了一个简单的工具,用于本地开发和构建 ts 文件。 它的使用和标准 tsc 几乎一致。 ``` $ npx mwtsc ``` 等价于执行 `tsc` 命令。 ## 常用命令[​](#常用命令 "常用命令的直接链接") 由于 mwtsc 基于 tsc 进行开发,它可以使用所有 tsc 的命令。 比如 ``` # 监听模式 $ npx mwtsc --watch # 使用不同的 tsconfig 文件 $ npx mwtsc --project tsconfig.production.json ``` 更多的参数可以查询 [tsc cli 工具](https://www.typescriptlang.org/docs/handbook/compiler-options.html)。 下面介绍更多 midway 新增的参数。 ## 运行指令[​](#运行指令 "运行指令的直接链接") 为了使得 tsc 在代码开发期生效,midway 提供了一个 `run` 参数,用于在 tsc 编译成功后执行一个文件,这和 `tsc-watch` 模块类似。 比如 ``` $ mwtsc --watch --run @midwayjs/mock/app.js ``` 上述命令会执行下面的逻辑: * 1、编译代码,编译成功后执行 `@midwayjs/mock/app.js` 文件 * 2、如果修改代码,则会自动触发编译,杀掉上一次执行的文件之后,自动执行 `@midwayjs/mock/app.js` 文件 `run` 参数可以执行任意的 js 文件,midway 依靠这个参数本地开发。 比如 ``` $ npx mwtsc --watch --run ./bootstrap.js ``` 当然也可以配合其他参数一起使用。 ``` $ npx mwtsc --watch --project tsconfig.production.json --run ./bootstrap.js ``` 注意 `run` 命令必须放在最后,它之后的所有参数,都将传递给子进程。 ## 框架配置[​](#框架配置 "框架配置的直接链接") 可以在 Midway 项目中用 mwtsc 进行开发测试,比如: ``` { "scripts": { "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app", "build": "cross-env rm -rf dist && tsc" }, } ``` 这里的 `@midwayjs/mock/app` 指代的是 `@midwayjs/mock` 包中的 `app.js` 文件,这个文件用于本地开发时启动框架。针对 Serverless 环境,也有相应的启动文件。 ``` { "scripts": { "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/function", }, } ``` ## 常用能力[​](#常用能力 "常用能力的直接链接") ### 调整端口[​](#调整端口 "调整端口的直接链接") 可以通过参数 `--port` 动态修改启动的 http 端口,这个参数的优先级高于代码中的端口配置。 ``` $ npx mwtsc --watch --run @midwayjs/mock/app --port 7001 ``` ### 开启 https[​](#开启-https "开启 https的直接链接") 框架内置了一个 https 证书用来本地测试,可以通过参数 `--ssl` 启用。 ``` $ npx mwtsc --watch --run @midwayjs/mock/app --ssl ``` --- # sequelize-auto-midway forked from [sequelize/sequelize-auto](https://github.com/sequelize/sequelize-auto) 通过已存在的数据库生成用于 `Midway` 的 `Sequelize` 实体。 其他详细文档和用法请参考 [sequelize/sequelize-auto](https://github.com/sequelize/sequelize-auto) ## Installation[​](#installation "Installation的直接链接") ``` $ npm i sequelize-auto-midway ``` ## Usage[​](#usage "Usage的直接链接") ``` # 推荐 # 请替换配置信息 npx sequelize-auto-midway -h localhost -d yourDBname -u root -x yourPassword -p 13306 --dialect mysql -o ./models --noInitModels true --caseModel c --caseProp c --caseFile c --indentation 1 -a ./additional.json ``` additional.json ``` { "timestamps": true, "paranoid": true } ``` 自动生成的模板文件如下: ``` import { Column, DataType, Table, Model } from 'sequelize-typescript'; @Table({ tableName: 'task', timestamps: false, indexes: [ { name: 'PRIMARY', unique: true, using: 'BTREE', fields: [{ name: 'task_id' }], }, ], }) export class TaskEntity extends Model { @Column({ autoIncrement: true, type: DataType.INTEGER.UNSIGNED, allowNull: false, primaryKey: true, field: 'task_id', }) taskId: number; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务所属应用ID: 0-无所属', field: 'app_id', }) appId: number; @Column({ type: DataType.STRING(64), allowNull: false, comment: '任务名称', field: 'task_name', }) taskName: string; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务类别:1-cron,2-interval', }) type: number; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务状态:0-暂停中,1-启动中', }) status: number; @Column({ type: DataType.DATE, allowNull: true, comment: '任务开始时间', field: 'start_time', }) startTime: string; @Column({ type: DataType.DATE, allowNull: true, comment: '任务结束时间', field: 'end_time', }) endTime: string; @Column({ type: DataType.INTEGER, allowNull: false, defaultValue: -1, comment: '任务执行次数', }) limit: number; @Column({ type: DataType.STRING(128), allowNull: true, defaultValue: '', comment: '任务cron配置', }) cron: string; @Column({ type: DataType.INTEGER.UNSIGNED, allowNull: true, defaultValue: 0, comment: '任务执行间隔时间', }) every: number; @Column({ type: DataType.STRING(255), allowNull: true, comment: '参数', }) args: string; @Column({ type: DataType.STRING(255), allowNull: true, comment: '备注', }) remark: string; } ``` Use `npx sequelize-auto-midway --help` to see all available parameters with their descriptions. Some basic parameters below: ``` Usage: npx sequelize-auto-midway -h -d -p [port] -u -x [password] -e [engine] Options: --help Show help [boolean] --version Show version number [boolean] -h, --host IP/Hostname for the database. [string] -d, --database Database name. [string] -u, --user Username for database. [string] -x, --pass Password for database. If specified without providing a password, it will be requested interactively from the terminal. -p, --port Port number for database (not for sqlite). Ex: MySQL/MariaDB: 3306, Postgres: 5432, MSSQL: 1433 [number] -c, --config Path to JSON file for Sequelize-Auto options and Sequelize's constructor "options" flag object as defined here: https://sequelize.org/master/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor [string] -o, --output What directory to place the models. [string] -e, --dialect The dialect/engine that you're using: postgres, mysql, sqlite, mssql [string] -a, --additional Path to JSON file containing model options (for all tables). See the options: https://sequelize.org/master/class/lib/model.js~Model.html#static-method-init [string] --indentation Number of spaces to indent [number] -t, --tables Space-separated names of tables to import [array] -T, --skipTables Space-separated names of tables to skip [array] --caseModel, --cm Set case of model names: c|l|o|p|u c = camelCase l = lower_case o = original (default) p = PascalCase u = UPPER_CASE --caseProp, --cp Set case of property names: c|l|o|p|u --caseFile, --cf Set case of file names: c|l|o|p|u|k k = kebab-case --noAlias Avoid creating alias `as` property in relations [boolean] --noInitModels Prevent writing the init-models file [boolean] -n, --noWrite Prevent writing the models to disk [boolean] -s, --schema Database schema from which to retrieve tables[string] -v, --views Include database views in generated models [boolean] -l, --lang Language for Model output: es5|es6|esm|ts es5 = ES5 CJS modules (default) es6 = ES6 CJS modules esm = ES6 ESM modules ts = TypeScript [string] --useDefine Use `sequelize.define` instead of `init` for es6|esm|ts --singularize, --sg Singularize model and file names from plural table names ``` --- # typeorm:Model Generator 感谢社区用户 @youtiao66 提供此模块。 通过该工具,你可以快速创建 for Midway 的 TypeORM Model。 ## 使用[​](#使用 "使用的直接链接") 比如生成 mysql 的 model。 ``` # 推荐 # 请替换配置信息 $ npx mdl-gen-midway -h localhost -p 3306 -d yourdbname -u root -x yourpassword -e mysql --noConfig --case-property none ``` 完整参数: ``` Usage: npx mdl-gen-midway -h -d -p [port] -u -x [password] -e [engine] Options: --help Show help [boolean] --version Show version number [boolean] -h, --host IP address/Hostname for database server [default: "127.0.0.1"] -d, --database Database name(or path for sqlite) [required] -u, --user Username for database server -x, --pass Password for database server [default: ""] -p, --port Port number for database server -e, --engine Database engine [choices: "mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"] [default: "mssql"] -o, --output Where to place generated models [default: "./output"] -s, --schema Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3 --ssl [boolean] [default: false] --noConfig Doesn't create tsconfig.json and ormconfig.json [布尔] [默认值: false] --cp, --case-property Convert property names to specified case [可选值: "pascal", "camel", "snake", "none"] [默认值: "camel"] ``` --- # 版本检查工具 由于依赖安装版本的不确定性,Midway 提供了 `midway-version` 这一版本检查工具,可以快速检查版本之间的兼容性错误。 ## 检查兼容性[​](#检查兼容性 "检查兼容性的直接链接") 你可以使用下面的命令在项目根目录执行进行检查。 以下命令会检查 `node_modules` 中实际安装的版本,而非 `package.json` 中写的版本。 * npm * pnpm * yarn ``` $ npx midway-version@latest ``` ``` $ pnpx midway-version@latest ``` ``` $ yarn add midway-version@latest $ yarn midway-version ``` ## 升级到最新版本[​](#升级到最新版本 "升级到最新版本的直接链接") 你可以使用下面的命令在项目根目录执行进行升级。 `-u` 参数会检查 midway 所有模块,根据 `node_modules` 中实际安装的版本以及 `package.json` 中编写的版本,将其升级到 `最新` 版本。 如当前安装的组件版本为 `3.16.2`,最新版本为 `3.18.0` ,则会提示升级到 `3.18.0`。 在使用 `-u -w` 参数时: * 更新 `package.json` 的版本,保留前缀写法,比如 `^3.16.0` 会变为 `^3.18.0` * 将 `3.18.0` 版本写入到锁文件(如有) - npm - pnpm - yarn ``` $ npx midway-version@latest -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `package-lock.json` 文件(如有)。 ``` $ npx midway-version@latest -u -w ``` ``` $ pnpx midway-version@latest -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `pnpm-lock.yaml` 文件(如有)。 ``` $ pnpx midway-version@latest -u -w ``` ``` $ yarn add midway-version@latest $ yarn midway-version -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `yarn.lock` 文件(如有)。 ``` $ yarn midway-version -u -w ``` ## 升级到可兼容的最新版本[​](#升级到可兼容的最新版本 "升级到可兼容的最新版本的直接链接") `-m` 参数会检查 midway 所有模块,根据 `node_modules` 中实际安装的版本以及 `package.json` 中编写的版本,将其升级到 `最新的兼容` 版本。 如当前安装的组件版本为 `3.16.0`,最新版本为 `3.18.0` ,兼容版本为 `3.16.1` 和 `3.16.2`,则会提示升级到 `3.16.2`。 一般使用 `-m` 参数的场景为固化低版本,检查错误的组件版本,所以策略和 `-u` 有所不同。 在使用 `-m -w` 参数时: * 更新 `package.json` 的版本 * 如果有锁文件,将会保留前缀,比如 `^3.16.0` 会变为 `^3.16.2` * 如果没有锁文件,将会移除前缀,固定版本,比如 `^3.16.0` 会变为 `3.16.2` * 将 `3.16.2` 版本写入到锁文件(如有) - npm - pnpm - yarn ``` $ npx midway-version@latest -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `package-lock.json` 文件(如有)。 ``` $ npx midway-version@latest -m -w ``` ``` $ pnpx midway-version@latest -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `pnpm-lock.yaml` 文件(如有)。 ``` $ pnpx midway-version@latest -m -w ``` ``` $ yarn add midway-version@latest $ yarn midway-version -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `yarn.lock` 文件(如有)。 ``` $ yarn midway-version -m -w ``` --- # 2.x 升级指南 本篇将介绍从 midway v2 升级为 midway v3 的方式。 从 Midway v2 升级到 Midway v3,会有一些 Breaking Change。本篇文档会详细列出这些 Breaking 的地方,让用户可以提前知道变化,做出应对。 ## 自动升级工具[​](#自动升级工具 "自动升级工具的直接链接") **在升级前,请切出一个新的分支,避免升级失败导致无法恢复!!!** 拷贝以下脚本,在项目根目录执行: ``` $ npx --ignore-existing midway-upgrade ``` 提示 由于业务情况各异,请在脚本升级之后,再进行手动升级的核对。 ## 手动升级[​](#手动升级 "手动升级的直接链接") **midway v3 支持从 node v12 起。** ### 包版本更新[​](#包版本更新 "包版本更新的直接链接") 所有的组件包,核心包都将升级为 3.x 版本。 ``` { "dependencies": { "@midwayjs/bootstrap": "^3.0.0", "@midwayjs/core": "^3.0.0", "@midwayjs/decorator": "^3.0.0", "@midwayjs/koa": "^3.0.0", "@midwayjs/task": "^3.0.0", }, "devDependencies": { "@midwayjs/cli": "^1.2.90", "@midwayjs/luckyeye": "^1.0.0", "@midwayjs/mock": "^3.0.0", // ... } } ``` `@midwayjs/cli` 和 `@midwyajs/luckeye`, `@midwayjs/logger` 的版本除外。 ### Query/Body/Param/Header 装饰器变更[​](#querybodyparamheader-装饰器变更 "Query/Body/Param/Header 装饰器变更的直接链接") 主要是默认无参数下的行为。 旧 ``` async invoke(@Query() name) { // ctx.query.name } ``` 新 ``` async invoke(@Query() name) { // ctx.query } async invoke(@Query('name') name) { // ctx.query.name } ``` ### Validate/Rule 装饰器[​](#validaterule-装饰器 "Validate/Rule 装饰器的直接链接") 旧 ``` import { Validate, Rule, RuleType } from '@midwayjs/decorator'; ``` 新 ``` import { Validate, Rule, RuleType } from '@midwayjs/validate'; ``` 由于 validate 抽象成了组件,需要在代码中安装依赖并开启。 ``` // src/configuration import * as validate from '@midwayjs/validate'; @Configuration({ // ... imports: [ validate ], }) export class MainConfiguration { // ... } ``` ### task 组件配置 key 变更[​](#task-组件配置-key-变更 "task 组件配置 key 变更的直接链接") 旧 ``` export const taskConfig = {}; ``` 新 ``` export const task = {}; ``` ### 配置的绝对路径[​](#配置的绝对路径 "配置的绝对路径的直接链接") 不再支持相对路径 旧 ``` // src/configuration @Configuration({ // ... importConfigs: [ './config' // ok ] }) export class MainConfiguration { // ... } ``` 新 ``` // src/configuration import { join } from 'path'; @Configuration({ // ... importConfigs: [ - './config' // error + join(__dirname, './config') // ok ] }) export class MainConfiguration { // ... } ``` ### 使用默认框架/多框架[​](#使用默认框架多框架 "使用默认框架/多框架的直接链接") 旧,会在 bootstrap.js 中引入 ``` const WebFramework = require('@midwayjs/koa').Framework; const GRPCFramework = require('@midwayjs/grpc').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .load(config => { return new WebFramework().configure(config.cluster); }) .load(config => { return new GRPCFramemwork().configure(config.grpcServer); }) .run(); ``` 新版本 bootstrap.js 中不再需要单独实例化 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.run(); ``` 作为替代,以组件的形式引入 ``` // src/configuration import * as web from '@midwayjs/web'; import * as grpc from '@midwayjs/grpc'; @Configuration({ // ... imports: [ web, grpc, //... ], }) export class MainConfiguration { // ... } ``` 其他影响: * 1、测试中不再需要使用 createBootstrap 方法从 bootstrap.js 启动 * 2、原有入口 Framework 的配置现在可以放到 config.\*.ts 中,以框架名作为 key ### 删除了一批 IoC 容器 API[​](#删除了一批-ioc-容器-api "删除了一批 IoC 容器 API的直接链接") 移除 container 上的下列方法 * getConfigService(): IConfigService; * getEnvironmentService(): IEnvironmentService; * getInformationService(): IInformationService; * setInformationService(service: IInformationService): void; * getAspectService(): IAspectService; * getCurrentEnv(): string; 现在都有相应的框架内置服务来替代。 比如旧写法: ``` const environmentService = app.getApplicationContext().getEnvironmentService(); const env = environmentService.getCurrentEnvironment(); ``` 新写法 ``` const environmentService = app.getApplicationContext().get(MidwayEnvironmentService) const env = environmentService.getCurrentEnvironment(); ``` ## @midwayjs/web(egg)部分[​](#midwayjswebegg部分 "@midwayjs/web(egg)部分的直接链接") ### 启动端口[​](#启动端口 "启动端口的直接链接") 新版本框架启动会读取一个端口配置,如果未配,可能不会启动端口监听。 ``` // src/config/config.default export default { // ... egg: { port: 7001, }, } ``` ### 添加 egg-mock[​](#添加-egg-mock "添加 egg-mock的直接链接") 由于框架移除了 egg-mock 包,在新版本 `package.json` 需要手动引用。 ``` { "devDependencies": { "egg-mock": "^1.0.0", // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 新版本,统一使用 @midwayjs/logger,不管是不是启用 egg logger。 为了和 egg 日志不冲突,我们使用了新的 key,原有的 `midwayFeature` 字段不再使用。 旧 ``` export const logger = { level: 'warn', consoleLevel: 'info' } ``` 新 ``` export const midwayLogger = { default: { level: 'warn', consoleLevel: 'info' } } ``` Egg 的 `customLogger` 字段,针对无法修改的 egg 插件,我们做了兼容,对于业务代码,最好做修改。 ``` export const midwayLogger = { default: { level: 'warn', consoleLevel: 'info' }, clients: { // 自定义日志 customLoggerA: { // ... } } } ``` 其余的更具体配置,请参考 [日志章节 ](/docs/3.0.0/logger.md)中的自定义部分。 ### egg 插件[​](#egg-插件 "egg 插件的直接链接") 在 Midway3 中,为了文档和行为统一,我们关闭了大部分 egg 默认插件。 新版本默认插件如下: ``` module.exports = { onerror: true, security: true, static: false, development: false, watcher: false, multipart: false, logrotator: false, view: false, schedule: false, i18n: false, } ``` 请酌情开启(可能会和 midway 能力冲突)。 默认的 egg 日志切割插件(logrotator),由于日志不再支持 egg logger,我们在框架中直接关闭了(midway logger 自带了切割)。 ### 定时任务[​](#定时任务 "定时任务的直接链接") 如果希望使用老的 `@Schedule` 装饰器,需要额外安装 `midway-schedule` 包,并以 egg 插件的形式引入。 ``` // src/config/plugin.ts export default { schedule: true, schedulePlus: { enable: true, package: 'midway-schedule', } // ... } ``` ## 其他面对组件/框架开发者的调整[​](#其他面对组件框架开发者的调整 "其他面对组件/框架开发者的调整的直接链接") ### 组件中 registerObject 不再增加 namespace[​](#组件中-registerobject-不再增加-namespace "组件中 registerObject 不再增加 namespace的直接链接") 在组件开发时,不再增加 namespace 前缀。 旧,组件入口 ``` @Configuration({ namespace: 'A' // ... }) export class MainConfiguration { async onReady(container) { container.registerObject('aaa', 'bbb'); } } container.getAsync('A:aaa'); // => OK ``` 新组件入口 ``` @Configuration({ namespace: 'A' // ... }) export class MainConfiguration { async onReady(container) { container.registerObject('aaa', 'bbb'); } } container.getAsync('aaa'); // => OK ``` ### 自定义框架部分[​](#自定义框架部分 "自定义框架部分的直接链接") 自定义框架的变化比较大,框架组件化是这一版本的目标。有几个地方需要修改。 **1、在原框架上增加 @Framework 标识** 旧 ``` export class CustomKoaFramework extends BaseFramework { // ... } ``` 新 ``` import { Framework } from '@midwayjs/core'; @Framework() export class CustomKoaFramework extends BaseFramework { // ... } ``` **2、在入口处按组件规范导出 Configuration** 你可以在 configuration 中使用生命周期,和组件相同。`run` 方法将在新增的 `onServerReady` 这个生命周期显式调用执行。 ``` import { Configuration,Inject } from '@midwayjs/core'; import { MidwayKoaFramework } from './framework'; @Configuration({ namespace: 'koa', }) export class KoaConfiguration { @Inject() framework: MidwayKoaFramework; async onReady() {} async onServerReady() { // ... } } ``` **3、框架开发时** **需要注意的是,由于框架初始化在用户生命周期前,所以 applicationInit 的时候,不要通过 @Config 装饰器注入配置,而是调用 configService 去获取。** ``` import { Framework } from '@midwayjs/core'; @Framework() export class CustomKoaFramework extends BaseFramework { configure() { /** * 这里返回你的配置 * 返回的值会赋值到 this.configurationOptions,对接原来的用户显式入参 * */ return this.configService.getConfiguration('xxxxxxx'); } /** * 这个新增的方法,用来判断框架是否加载 * 有时候组件中包括 server 端(框架)和 client 端,就需要判断 * */ isEnable(): boolean { return this.configurationOptions.services?.length > 0; } // ... } ``` 这样在外面使用时也可以判断。 ``` import { Configuration,Inject } from '@midwayjs/core'; import { MidwayKoaFramework } from './framework'; @Configuration({ namespace: 'koa', }) export class KoaConfiguration { @Inject() framework: MidwayKoaFramework; async onReady() {} async onServerReady() { // 如果 isEnable 为 true,框架会默认调用 framework.run() // 如果一开始 enable 为 false,也可以延后去手动 run if (/* 延后执行 */) { await this.framework.run(); } } } ``` --- # 拦截器(AOP) 我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。 Midway 设计了一套通用的方法拦截器(切面),用于在不同场景中,统一编写逻辑。 拦截器和传统的 Web 中间件和装饰器都不同,是由 Midway 框架提供的能力,在执行顺序上,处于中间的位置,这个能力能对任意的 Class 方法做拦截。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DFfT1y1FC8xYeocrX_!!6000000000450-2-tps-823-133.png) ## 使用拦截器(切面)[​](#使用拦截器切面 "使用拦截器(切面)的直接链接") 拦截器一般会放在 `src/aspect` 目录。下面我们写一个对控制器(Controller)方法拦截的示例。创建一个 `src/aspect/report.ts` 文件。 ``` ➜ my_midway_app tree . ├── src │ │── aspect ## 拦截器目录 │ │ └── report.ts │ └── controller ## Web Controller 目录 │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return "Hello Midwayjs!"; } } ``` 内容如下: ``` import { Aspect, IMethodAspect, JoinPoint } from '@midwayjs/core'; import { HomeController } from '../controller/home'; @Aspect(HomeController) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('before home router run'); } } ``` 启动项目,运行后,在控制台会输出 `before home router run` 的字样。 你会发现,我们不需要去侵入控制器的代码,既没有在业务文件中加装饰器,也没有在主流程前后可见的加代码。 拦截器(切面)的能力非常强大,也非常可怕,我们一定要小心而正确的使用。 拦截器 **固定为单例**。 警告 在继承的情况下,拦截器不会对父类的方法生效。 ## 可切面的生命周期[​](#可切面的生命周期 "可切面的生命周期的直接链接") 方法拦截器可以对整个方法进行拦截,拦截的方式包括几个方面。 ``` export interface IMethodAspect { after?(joinPoint: JoinPoint, result: any, error: Error); afterReturn?(joinPoint: JoinPoint, result: any): any; afterThrow?(joinPoint: JoinPoint, error: Error): void; before?(joinPoint: JoinPoint): void; around?(joinPoint: JoinPoint): any; } ``` | 方法 | 描述 | | ----------- | ---------------------------- | | before | 方法调用前执行 | | around | 包裹方法的前后执行 | | afterReturn | 正确返回内容时执行 | | afterThrow | 抛出异常时执行 | | after | 最后执行(不管正确还是错误) | 简单理解如下; ``` try { // before // around or invokeMethod // afterReturn } catch(err){ // afterThrow } finally { // after } ``` | | 修改入参 | 调用原方法 | 获取返回值 | 修改返回值 | 获取错误 | 拦截并抛出错误 | | ----------- | -------- | ---------- | ---------- | ---------- | -------- | -------------- | | before | √ | √ | | | | | | around | √ | √ | √ | √ | √ | √ | | afterReturn | | | √ | √ | | | | afterThrow | | | | | √ | √ | | after | | | √ | | √ | | 我们常会在 `before` 的过程中修改入参、校验,以符合程序执行的逻辑,比如: ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home(data1, data2) { return data1 + data2; // 因为拦截了方法,这里的返回值是 3 } } // src/aspect/ @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log(point.args); // 这里因为对 Controller 方法做切面,原本的参数为 [ctx, next] point.args = [1, 2]; // 修改入参 } } ``` 这里的 `JoinPoint` 就是可以对方法做修改的参数,定义如下。 ``` export interface JoinPoint { methodName: string; target: any; args: any[]; proceed(...args: any[]): any; } ``` | 参数 | 描述 | | ---------- | ------------------------------------------ | | methodName | 拦截到的方法名 | | target | 方法调用时的实例 | | args | 原方法调用的参数 | | proceed | 原方法本身,只会在 before 和 around 中存在 | `around` 是比较全能的方法,它可以包裹整个方法调用流程。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async around(point: JoinPoint) { const result = await point.proceed(...point.args); // 执行原方法 return result + ' world'; } } ``` 最终 Controller 会返回 `hello world` 。 `afterReturn` 方法会多一个返回结果参数,如果只需要修改返回结果,可以直接使用它,上面的 `around` 例子用 `afterReturn` 改写会更简单。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { return 'hello'; } } // src/aspect/report.ts @Aspect(HomeController, 'home') // 这里只对 home 方法做拦截 export class ReportInfo implements IMethodAspect { async afterReturn(point: JoinPoint, result) { return result + ' world'; } } ``` `afterThrow` 用于拦截错误。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async afterThrow(point: JoinPoint, error) { if(/not found/.test(error.message)) { throw new Error('another error'); } else { console.error('got custom error'); } } } ``` `afterThrow` 能拦截错误,相应的,它不能在流程中返回结果,一般用来记录错误日志。 `after` 用来做最后的处理,不管是成功或者失败,都可以用它执行一些事情,比如记录所有成功或者失败的次数。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { throw new Error('custom error'); } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async after(point: JoinPoint, result, error) { if(error) { console.error(error); } else { console.log(result); } } } ``` ## 切面的异步问题[​](#切面的异步问题 "切面的异步问题的直接链接") 如果被拦截的方法是异步的,则原则上我们的 `before` 等方法应该都是异步的,反之,则都是同步的。 ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') async home() { // 这里是异步的,则下面的 before 是异步的 } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { } } ``` ``` // src/controller/home.ts @Controller('/') export class HomeController { @Get('/') home() { // 这里是同步的,则下面的 before 也是同步的 } } // src/aspect/report.ts @Aspect(HomeController, 'home') export class ReportInfo implements IMethodAspect { before(point: JoinPoint) { } } ``` ## 应用到多个 Class[​](#应用到多个-class "应用到多个 Class的直接链接") `@Aspect` 装饰器的参数可以是一个数组,我们可以提供多个 Class,这些 Class 的 \*\*所有方法 \*\*都将被拦截。比如,我们可以将上面的拦截器应用到多个 Controller,这样 \*\*每一个 Class 的每一个方法 \*\*都会被拦截。 ``` @Aspect([HomeController, APIController]) export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { } } ``` ## 特定方法匹配[​](#特定方法匹配 "特定方法匹配的直接链接") 一般情况下,我们只需要对某个 Class 特定的方法做拦截。我们提供了一些匹配方法的能力。 `@Aspect` 装饰的第二个参数则是一个通配方法的字符串。使用的规则为 [picomatch](https://github.com/micromatch/picomatch)。 假如我们的方法为: ``` // src/controller/home.ts import { Controller, Get } from "@midwayjs/core"; @Controller('/') export class HomeController { @Get('/1') async hello1() { return "Hello Midwayjs!"; } @Get('/2') async hello2() { return "Hello Midwayjs, too!"; } } ``` 那么,我们如下配置时,只会匹配到 `hello2` 这个方法。 ``` @Aspect([HomeController], '*2') export class ReportInfo implements IMethodAspect { async before(point: JoinPoint) { console.log('hello method with suffix 2'); } } ``` ## 切面执行顺序[​](#切面执行顺序 "切面执行顺序的直接链接") 如果多个拦截器(切面)同时针对一个方法做操作,可能会出现顺序错乱的问题,如果在两个文件中,这个顺序是随机的。 `@Aspect` 的第三个参数用于指定拦截器的优先级,默认为 0,数字越大,优先级越高,即先被注册到方法上,**先注册的方法会被后调用,**即洋葱模型**。** 以下面的代码作为示例。 `MyAspect2` 的优先级高于 `MyAspect1` ,所以会优先注册。示意图如下,整个拦截流程分为两部分,先是注册,后是执行。 **注册流程** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01d31RXA1cpHyjyPHCs_!!6000000003649-2-tps-924-497.png) **执行流程** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01RXmEtD26Thmkg8eX8_!!6000000007663-2-tps-769-311.png) 代码如下。 ``` @Aspect([HomeController]) export class MyAspect1 implements IMethodAspect { before(point: JoinPoint) { console.log('111'); } } @Aspect([HomeController], '*', 1) // 这里可以设置优先级 export class MyAspect2 implements IMethodAspect { before(point: JoinPoint) { console.log('222'); } } ``` 执行输出为 ``` 111 222 ``` ## 一些限制[​](#一些限制 "一些限制的直接链接") * 1、拦截器不会对父类生效 --- # 自执行代码 在初始化过程中,当我们的代码和主流程无关,却想执行的时候,一般会在启动 onReady 阶段来执行,随着的代码量越来越多,onReady 会变的臃肿。 比如,我们有一些需要提前执行的逻辑,一个用于监听 Redis 错误,一个用于初始化数据同步: ``` @Provide() @Scope(ScopeEnum.Singleton) export class RedisErrorListener { // ... } @Provide() @Scope(ScopeEnum.Singleton) export class DataSyncListener { // ... } ``` 一般,我们会在启动时通过 `getAsync` 方法来创建实例,使其执行。 ``` // configuration.ts //... @Configuration({ // ... }) export class MainConfiguration { async onReady(container) { await container.getAsync(RedisErrorListerner); await container.getAsync(DataSyncListerner); } } ``` 这样一旦代码多了,onReady 中会出现许多非必要流程的代码。 ## 自初始化[​](#自初始化 "自初始化的直接链接") 如果代码和主流程不耦合,属于独立的逻辑,比如上述的监听一些事件,初始化数据同步等,就可以使用 @Autoload 装饰器,使某个类可以自初始化。 比如: ``` import { Autoload, Scope, ScopeEnum } from '@midwayjs/core'; @Autoload() @Scope(ScopeEnum.Singleton) export class RedisErrorListener { @Init() async init() { const redis = new Redis(); redis.on('xxx', () => { // ... }); } } ``` 这样无需在 `onReady` 中使用 `getAsync` 方法即可自动初始化,并执行 init 方法。 --- # Awesome Midway 以下列举了与 Midwayjs 相关的优质社区项目 ## 微服务[​](#微服务 "微服务的直接链接") | 名称 | 作者 | 描述 | | ------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [@letscollab/midway-nacos](https://github.com/deskbtm-letscollab/midway-nacos) | Nawbc | midway nacos 组件 | | [midway-elasticsearch](https://github.com/ddzyan/midway-elasticsearch) | ddzyan | midway elasticsearch 组件 | | [midway-apollo](https://github.com/helloHT/midway-apollo) | helloHT | midway 携程异步动态配置 apollo 组件 | | [@mwcp/cache](https://github.com/waitingsong/midway-components/tree/main/packages/cache) | waitingsong | midway Cache 增强组件 支持 [`Cacheable`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheable-%E8%A3%85%E9%A5%B0%E5%99%A8), [`CacheEvict`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheevict-%E8%A3%85%E9%A5%B0%E5%99%A8), [`CachePut`](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#cacheput-%E8%A3%85%E9%A5%B0%E5%99%A8) 装饰器 并支持[传入泛型参数获得方法入参类型](https://github.com/waitingsong/midway-components/blob/main/packages/cache/README.zh-CN.md#%E4%BB%8E%E6%B3%9B%E5%9E%8B%E5%8F%82%E6%95%B0%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B) | | [@mwcp/kmore](https://github.com/waitingsong/kmore) | waitingsong | midway 数据库组件 基于 [Knex](https://knexjs.org/),通过 `Transactional` 装饰器支持声明式事务,支持自动分页、智能连表,集成 [OpenTelemetry](https://github.com/open-telemetry) 链路追踪 | | [@mwcp/otel](https://github.com/waitingsong/midway-components/tree/main/packages/otel) | waitingsong | midway [OpenTelemetry](https://github.com/open-telemetry) 增强组件,协议支持 HTTP 和 [gRPC (Unary)](https://github.com/midwayjs/midway/tree/main/packages/grpc) 支持 [`Trace`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#trace-%E8%A3%85%E9%A5%B0%E5%99%A8), [`TraceLog`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#tracelog-%E8%A3%85%E9%A5%B0%E5%99%A8), [`TraceInit`](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#traceinit-%E8%A3%85%E9%A5%B0%E5%99%A8) 装饰器 并支持[传入泛型参数获得方法入参类型](https://github.com/waitingsong/midway-components/blob/main/packages/otel/README.zh-CN.md#%E4%BB%8E%E6%B3%9B%E5%9E%8B%E5%8F%82%E6%95%B0%E8%87%AA%E5%8A%A8%E8%8E%B7%E5%8F%96%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B) | | [@mwcp/jwt](https://github.com/waitingsong/midway-components/tree/main/packages/jwt) | waitingsong | midway JWT 增强组件 支持 [`Public`](https://github.com/waitingsong/midway-components/blob/main/packages/jwt/README.md#public-decorator) 装饰器 | | [@mwcp/paradedb](https://github.com/waitingsong/paradedb/tree/main/packages/mwcp-paradedb) | waitingsong | midway [ParadeDb](https://pigsty.cc/zh/blog/pg/paradedb/) 组件。首个基于 Postgres 的 Elasticsearch 开源替代,采用 Rust 编写, 旨在提供快速的全文检索、语义检索和混合检索能力,适用于搜索场景 | | [@mwcp/pgmq](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js) | waitingsong | midway [pqmg-js](https://github.com/waitingsong/pgmq-js/tree/main/packages/pgmq-js) 组件 支持 [`Consumer`](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js#consumer-decorator), [`PgmqListener`](https://github.com/waitingsong/pgmq-js/tree/main/packages/mwcp-pgmq-js#consumer-decorator) 装饰器, 支持事务以及事务保护的类似 MQ `Exchange` 概念的路由。 [PGMQ](https://tembo-io.github.io/pgmq/) 是一个基于 [PG](https://pigsty.cc/zh/blog/pg/pg-eat-db-world/) 数据库扩展的轻量级消息队列,原生支持消息持久化和延迟消息,类似 `AWS SQS` 或 `RSMQ` | | [midway-throttler](https://github.com/larryzhuo/midway-throttler) | larryzhuo | midway throttler 限流组件 | ## 插件[​](#插件 "插件的直接链接") | 名称 | 作者 | 描述 | | ----------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [邮件组件](https://gitee.com/onlymry_admin/midwayjs_mailer) | MrDotYan | midway 邮箱组件,基于nodemailer和midwayjs,以服务的形式注入控制器使用[文档(国内)](https://gitee.com/onlymry_admin/midwayjs_mailer/blob/main/readme.md) [文档(国外)](https://github.com/MrDotYan/midwayjs_mailer/blob/main/readme.md) | ## swagger[​](#swagger "swagger的直接链接") | 名称 | 作者 | 描述 | | ---------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------ | | [midwayjs-knife4j2](https://github.com/fangbao-0418/midway/tree/master/packages/swagger) | Junyi | midway swagger 新皮肤 | | [midway-scalar](https://github.com/nobu121/midway-scalar) | nobu121 | midway scalar 组件,scalar是一个为 OpenAPI 标准构建的现代 API 平台 | ## 模板渲染[​](#模板渲染 "模板渲染的直接链接") | 名称 | 作者 | 描述 | | ----------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------- | | [yuntian001/midway-vite-view](https://github.com/yuntian001/midway-vite-view) | yuntian001 | midway vite 服务端渲染(ssr)/客户端渲染(client)组件 支持 vue3 react | ## 社区示例[​](#社区示例 "社区示例的直接链接") | 名称 | 作者 | 描述 | | --------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [midwayjs-crud](https://github.com/developeryvan/midwayjs-crud) | DeveloperYvan | 一个包含 prisma+casbin+nacos+crud 的示例 | | [midway-practice](https://github.com/ddzyan/midway-practice) | ddzyan | 一个包含 请求日志链路,统一响应体,统一异常处理,异常过滤器 + 三大主流 ORM 模型 (sequelize,typeORM,prisma) 的示例 | | [midway-boot](https://github.com/bestaone/midway-boot) | 码道功臣 | 一个比较完整的后端功能最佳实践,包含:增删改查及基类封装、数据库操作、缓存操作、用户安全认证及访问安全控制、JWT 访问凭证、分布式访问状态管理、密码加解密、统一返回结果封装、统一异常管理、Snowflake 主键生成、Swagger 集成及支持访问认证、环境变量的使用、Docker 镜像构建、Serverless 发布等 | | [midway-vue3-ssr](https://github.com/lqsong/midway-vue3-ssr) | LiQingSong | 基于 Midway、Vue 3 组装的 SSR 框架,简单、易学易用、方便扩展、集成 Midway 框架,您一直想要的 Vue SSR 框架。 | | [midway-learn](https://github.com/hbsjmsjwj/midway-learn.git) | hbsjmsjwj | 一个学习midway的demo,包含 midway3 + egg + 官方的组件&扩展(consul, jwt, typeorm, prometheus, swagger, mysql2,grpc,rabbitmq) | | [midway-admin](https://gitee.com/yncykj/midway-admin.git) | MrDotYan | 一套GeekerAdmin+Midwayjs构建的后台管理框架 | ## 学习资料[​](#学习资料 "学习资料的直接链接") | 名称 | 作者 | 描述 | | -------------- | -------- | ----------------------------------------- | | Midway开发实践 | 码道功臣 | | 提示 欢迎大家为社区贡献力量, 编辑此页添加你所喜爱的高质量 midway 项目/组件 --- # 内置服务 在 Midway 中,提供了众多的内置对象,方便用户使用。 在本章节,我们会介绍和框架相关联的的 Application,Context 对象,Midway 默认容器上的一些服务对象,这些对象在整个业务的开发中都会经常遇到。 以下是一些 Midway 依赖注入容器内置的服务,这些服务由依赖注入容器初始化,在业务中全局可用。 ## MidwayApplicationManager[​](#midwayapplicationmanager "MidwayApplicationManager的直接链接") Midway 内置的应用管理器,可以使用它获取到所有的 Application。 可以通过注入获取,比如对不同的 Application 添加同一个中间件。 ``` import { MidwayApplicationManager, onfiguration, Inject } from '@midwayjs/core' import { CustomMiddleware } from './middleware/custom.middleware'; @Configuration({ // ... }) export class MainConfiguration { @Inject() applicationManager: MidwayApplicationManager; async onReady() { this.applicationManager .getApplications(['koa', 'faas', 'express', 'egg']) .forEach(app => { app.useMiddleware(CustomMiddleware); }); } } ``` | API | 返回类型 | 描述 | | ------------------------------------- | --------------------- | ------------------------------------------------------ | | getFramework(namespace: string) | IMidwayFramework | 返回参数指定的 framework | | getApplication(namespace: string) | IMidwayApplication | 返回参数指定的 Application | | getApplications(namespace: string\[]) | IMidwayApplication\[] | 返回参数指定的多个 Application | | getWebLikeApplication() | IMidwayApplication\[] | 返回类似 Web 场景的 Application(express/koa/egg/faas) | ## MidwayInformationService[​](#midwayinformationservice "MidwayInformationService的直接链接") Midway 内置的信息服务,提供基础的项目数据。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayInformationService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() informationService: MidwayInformationService; @Get('/') async home() { // this.informationService.getAppDir(); } } ``` 一般用来返回用户相关的目录。 | API | 返回类型 | 描述 | | ------------ | -------- | ------------------------------------------------------- | | getAppDir() | String | 返回应用根目录 | | getBaseDir() | String | 返回应用代码目录,默认本地开发为 src,服务器运行为 dist | | getHome | String | 返回机器用户目录,指代 \~ 的地址。 | | getPkg | Object | 返回 package.json 的内容 | | getRoot | String | 在开发环境,返回 appDir,在其他环境,返回 Home 目录 | ## MidwayEnvironmentService[​](#midwayenvironmentservice "MidwayEnvironmentService的直接链接") Midway 内置的环境服务,提供环境设置和判断。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayEnvironmentService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() environmentService: MidwayEnvironmentService; @Get('/') async home() { // this.environmentService.getCurrentEnvironment(); } } ``` 一般用来获取当前的环境,API 如下: | API | 返回类型 | 描述 | | ------------------------ | -------- | ------------------ | | getCurrentEnvironment() | String | 返回应用当前环境 | | setCurrentEnvironment() | | 设置当前环境 | | isDevelopmentEnvironment | Boolean | 判断是否是开发环境 | ## MidwayConfigService[​](#midwayconfigservice "MidwayConfigService的直接链接") Midway 内置的多环境配置服务,提供配置的加载和获取,它也是 `@Config` 装饰器的数据源。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayConfigService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() configService: MidwayConfigService; @Get('/') async home() { // this.configService.getConfiguration(); } } ``` 一般用来获取当前的配置,API 如下: | API | 返回类型 | 描述 | | ------------------------------------------- | -------- | ------------------------ | | addObject(obj) | | 动态添加配置对象 | | getConfiguration('configKey', defaultValue) | Object | 返回当前合并好的配置对象 | | clearAllConfig() | | 清空所有配置 | ## MidwayLoggerService[​](#midwayloggerservice "MidwayLoggerService的直接链接") Midway 内置的日志服务,提供日志创建,获取等 API,它也是 `@Logger` 装饰器的数据源。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayLoggerService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() loggerService: MidwayLoggerService; @Get('/') async home() { // this.loggerService.getLogger('logger'); } } ``` 一般用来获取日志对象,API 如下: | API | 返回类型 | 描述 | | ---------------------------- | -------- | ------------------------------ | | createInstance(name, config) | ILogger | 动态创建一个 Logger 实例 | | getLogger(name) | ILogger | 根据日志名返回一个 Logger 实例 | ## MidwayFrameworkService[​](#midwayframeworkservice "MidwayFrameworkService的直接链接") Midway 内置的自定义框架服务,配合组件中自定义的 `@Framework` 标记的 Class,提供不同协议的对外服务。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayFrameworkService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() frameworkService: MidwayFrameworkService; @Get('/') async home() { // this.frameworkService.getMainFramework(); } } ``` 一般用来获取 Framework 对象,API 如下: | API | 返回类型 | 描述 | | --------------------------------- | ------------------ | ---------------------------------- | | getMainFramework() | IMidwayFramework | 返回主框架实例 | | getMainApp() | IMidwayApplication | 返回主框架中的 app 对象 | | getFramework(nameOrFrameworkType) | IMidwayFramework | 根据框架名或者框架类型返回框架实例 | ## MidwayMiddlewareService[​](#midwaymiddlewareservice "MidwayMiddlewareService的直接链接") Midway 内置的中间件处理服务,用于自建中间件的处理。 Midway 内置的自定义装饰器服务,用于实现框架层面的自定义装饰器,一般在自定义框架时使用。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayMiddlewareService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() middlewareService: MidwayMiddlewareService; @Get('/') async home() { // this.middlewareService.compose(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | -------------------------------- | ----------- | -------------------------------------------- | | compose(middlewares, app, name?) | IMiddleawre | 将多个中间件数组组合到一起返回一个新的中间件 | ## MidwayDecoratorService[​](#midwaydecoratorservice "MidwayDecoratorService的直接链接") Midway 内置的自定义装饰器服务,用于实现框架层面的自定义装饰器。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayDecoratorService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() decoratorService: MidwayDecoratorService; @Get('/') async home() { // this.decoratorService.registerPropertyHandler(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | ----------------------------------------------- | -------- | ---------------------- | | registerPropertyHandler(decoratorKey, handler) | | 添加一个属性装饰器实现 | | registerMethodHandler(decoratorKey, handler) | | 添加一个方法装饰器实现 | | registerParameterHandler(decoratorKey, handler) | | 添加一个参数装饰器实现 | 具体示例,请参考 **自定义装饰器** 部分。 ## MidwayAspectService[​](#midwayaspectservice "MidwayAspectService的直接链接") Midway 内置的拦截器服务,用于加载 `@Aspect` 相关的能力,自定义装饰器也使用了该服务。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayAspectService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() aspectService: MidwayAspectService; @Get('/') async home() { // this.aspectService.interceptPrototypeMethod(/** 省略 **/); } } ``` API 如下: | API | 返回类型 | 描述 | | ------------------------------------------------------------------------ | -------- | ---------------------------------------- | | addAspect(aspectInstance, aspectData) | | 添加一个拦截器实现 | | interceptPrototypeMethod(Clazz, methodName, aspectObject: IMethodAspect) | | 拦截原型上的方法,将拦截器的实现添加上去 | ## MidwayLifeCycleService[​](#midwaylifecycleservice "MidwayLifeCycleService的直接链接") Midway 内置的生命周期运行服务,用于运行 `configuration` 中的生命周期。 该服务均为内部方法,用户无法直接使用。 ## MidwayMockService[​](#midwaymockservice "MidwayMockService的直接链接") Midway 内置的数据模拟服务,用于在开发和单测时模拟数据。 可以通过注入获取。 ``` import { Inject, Controller, Get, MidwayMockService } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() mockService: MidwayMockService; @Get('/') async home() { // this.mockService.mockProperty(/** 省略 **/); } } ``` API 如下 | API | 返回类型 | 描述 | | ---------------------------------------------------- | -------- | ----------------------------------------------------------------- | | mockClassProperty(clzz, propertyName, value, group?) | | mock 一个 class 上的属性(方法),支持分组,默认分组为 `default` | | mockProperty(obj, key, value, group?) | | mock 一个普通对象上的属性(方法),支持分组,默认分组为 `default` | | mockContext(app, key, value, group?) | | mock 上下文对象上的属性,支持分组,默认分组为 `default` | | restore(group?) | | 恢复指定分组的 mock 数据,未指定则恢复所有 | | restoreAll() | | 清空所有 mock 数据 | ### mockClassProperty[​](#mockclassproperty "mockClassProperty的直接链接") 用于模拟类的某个属性或者方法。支持通过 `group` 参数指定分组。如果不传 `group` 参数,默认使用 `default` 分组。 ``` @Provide() export class UserService { data; async getUser() { return 'hello'; } } ``` 我们也可以在代码中模拟。 ``` import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @Provide() class TestMockService { @Inject() mockService: MidwayMockService; mock() { // 模拟属性,使用默认分组 this.mockService.mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); // 模拟属性,指定分组 this.mockService.mockClassProperty(UserService, 'data', { bbb: '1' }, 'group2'); } } ``` ### mockProperty[​](#mockproperty "mockProperty的直接链接") 使用 `mockProperty` 方法来模拟对象的属性。支持通过 `group` 参数指定分组。 ``` import { MidwayMockService, Provide, Inject } from '@midwayjs/core'; @Provide() class TestMockService { @Inject() mockService: MidwayMockService; mock() { const a = {}; // 默认分组 this.mockService.mockProperty(a, 'name', 'hello'); // 模拟属性,自定义分组 this.mockService.mockProperty(a, 'name', 'hello', 'group1'); // a['name'] => 'hello' // 模拟方法 this.mockService.mockProperty(a, 'getUser', async () => { return 'midway'; }, 'group2'); // await a.getUser() => 'midway' } } ``` ### mockContext[​](#mockcontext "mockContext的直接链接") 由于 Midway 的 Context 和 app 关联,所以在模拟的时候需要传入 app 实例。支持通过 `group` 参数指定分组。 使用 `mockContext` 方法来模拟上下文。 ``` import { MidwayMockService, Configuration, App } from '@midwayjs/core'; @Configuration(/**/) export class MainConfiguration { @Inject() mockService: MidwayMockService; @App() app; async onReady() { // 模拟上下文, 默认分组 this.mockService.mockContext(app, 'user', 'midway'); // 自定义分组 this.mockService.mockContext(app, 'user', 'midway', 'group1'); } } // ctx.user => midway ``` 如果你的数据比较复杂,或者带有逻辑,也可以使用回调形式。 ``` import { MidwayMockService, Configuration, App } from '@midwayjs/core'; @Configuration(/**/) export class MainConfiguration { @Inject() mockService: MidwayMockService; @App() app; async onReady() { // 模拟上下文 this.mockService.mockContext(app, (ctx) => { ctx.user = 'midway'; }, 'group2'); } } // ctx.user => midway ``` 注意,这个 mock 行为是在所有中间件之前执行。 ## MidwayWebRouterService[​](#midwaywebrouterservice "MidwayWebRouterService的直接链接") Midway 内置的路由表服务,用于应用路由和函数的创建。 可以通过注入获取。 ``` import { MidwayWebRouterService, Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { this.webRouterService.addRouter(async (ctx) => { return 'hello world'; }, { url: '/', requestMethod: 'GET', }); } } ``` API 如下 | API | 返回类型 | 描述 | | ------------------------------------------------- | ------------------------------------- | -------------------------------------- | | addController(controllerClz, controllerOption) | | 动态添加一个 Controller | | addRouter(routerFunction, routerInfoOption) | | 动态添加一个路由函数 | | getRouterTable() | Promise\> | 获取带层级的路由 | | getFlattenRouterTable() | Promise\ | 获取扁平化路由列表 | | getRoutePriorityList() | Promise\ | 获取路由前缀列表 | | getMatchedRouterInfo(url: string, method: string) | Promise\ | 根据访问的路径,返回当前匹配的路由信息 | 更多使用请参考 [Web 路由表](#router_table)。 ## MidwayServerlessFunctionService[​](#midwayserverlessfunctionservice "MidwayServerlessFunctionService的直接链接") Midway 内置的函数信息服务,继承与 `MidwayWebRouterService` ,方法几乎相同。 可以通过注入获取。 ``` import { MidwayServerlessFunctionService, Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { this.serverlessFunctionService.addServerlessFunction(async (ctx, event) => { return 'hello world'; }, { type: ServerlessTriggerType.HTTP, metadata: { method: 'get', path: '/api/hello' }, functionName: 'hello', handlerName: 'index.hello', }); } } ``` API 如下 | API | 返回类型 | 描述 | | ---------------------------------------------------------- | ----------------------- | ---------------- | | addServerlessFunction(fn, triggerOptions, functionOptions) | | 动态添加一个函数 | | getFunctionList() | Promise\ | 获取所有函数列表 | 更多使用请参考 [Web 路由表](#router_table)。 ## MidwayHealthService[​](#midwayhealthservice "MidwayHealthService的直接链接") Midway 内置的健康检查执行服务,用于外部扩展的健康检查能力。 完整的健康检查包含两个部分: * 1、健康检查的触发端,比如外部的定时请求,通常为一个 Http 接口 * 2、健康检查的执行端,一般在各个组件或者业务中,检查特定的项是否正常 `MidwayHealthService` 一般用于健康检查的触发端,下面描述的内容一般在触发端会实现。 可以通过注入获取后,执行健康检查任务。 ``` import { MidwayHealthService ,Configuration, Inject } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() healthService: MidwayHealthService; async onServerReady() { setInterval(() => { const results = await this.healthService.getStatus(); // console.log(results); // => // { // "status": false // "namespace": "redis", // "reason": "health check timeout", // "results": [ // { // "status": false // "reason": "health check timeout", // "namespace": "redis" // } // ] // } }, 1000); // ... } } ``` API 如下 | API | 返回类型 | 描述 | | -------------------------------- | ----------------------- | ---------------- | | getStatus() | Promise\ | 动态添加一个函数 | | setCheckTimeout(timeout: number) | void | 设置超时时间 | `getStatus` 方法用于外部调用轮询 `configuration` 中的 `onHealthCheck` 方法,返回一个符合 `HealthResults` 结构的数据。 `HealthResults` 包含几个字段,`status` 表示本次检查是否成功, 如果失败,`reason` 表示本次第一个失败组件的原因,`namespace` 代表第一个失败的组件名, `results` 则表示本次检查所有的返回项内容,返回项的结构和外部相同。 在执行过程时,如果 `onHealthCheck` 方法出现下列的情况,都会标记为失败。 * 1、未返回符合 `HealthResult` 结构的数据 * 2、未返回值 * 3、执行超时 * 4、抛出错误 * 5、返回符合 `HealthResult` 结构的代表错误的数据,比如 `{status: false}` 健康检查默认等待超时时间 1s。 可以使用全局的配置进行覆盖。 ``` // config.default export default { core: { healthCheckTimeout: 2000, } }; ``` 健康检查的执行端在业务或者组件的生命周期中实现,具体请查看 [生命周期](/docs/lifecycle.md#onhealthcheck)。 --- # 修改源码目录 在某些特殊场景下,可以修改源码所在的 `src` 目录。 一些限制: * 1、@midwayjs/web(egg)egg 由于目录固定,无法修改 * 2、只在纯 node 项目下测试通过(非一体化) ## 源码目录的修改[​](#源码目录的修改 "源码目录的修改的直接链接") 下面,我们以将 `src` 目录修改为 `server` 为例。 ### dev 开发[​](#dev-开发 "dev 开发的直接链接") `package.json` 中的 dev 命令需要增加源码目录,方便 dev 查找。 * 使用 mwtsc * 使用 @midwayjs/cli 默认可以识别 `tsconfig.json` 中的 `outDir` 字段,无需调整。 ``` "dev": "cross-env NODE_ENV=local midway-bin dev --sourceDir=./server --ts", ``` ### build 编译[​](#build-编译 "build 编译的直接链接") * 使用 mwtsc * 使用 @midwayjs/cli 默认可以识别 `tsconfig.json` 中的 `outDir` 字段,无需调整。 为了让 tsc 编译能找到源码目录,需要修改 `tsconfig.json` ,增加 `rootDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "rootDir": "server" }, } ``` 这样,开发和编译就都正常了。 ## 编译目录的修改[​](#编译目录的修改 "编译目录的修改的直接链接") 编译目录影响到部署,也可以修改。我们以将 `dist` 目录修改为 `build` 为例。 ### build 编译[​](#build-编译-1 "build 编译的直接链接") 修改 `tsconfig.json` 中的 `outDir` 字段。 ``` { "compileOnSave": true, "compilerOptions": { // ... "outDir": "build" }, "exclude": { "build", //... } } ``` 这样编译就正常了。 ### bootstrap 启动[​](#bootstrap-启动 "bootstrap 启动的直接链接") 编译目录修改之后,线上部署会找不到代码,所以如果走 `bootstrap.js` 启动,需要修改代码。 ``` // bootstrap.js const { join } = require('path'); const { Bootstrap } = require('@midwayjs/bootstrap'); //... // 需要用 configure 方法配置 baseDir Bootstrap .configure({ baseDir: join(__dirname, 'build'), }) .run(); ``` 对 `Bootstrap` 配置入口目录即可。 --- # 自定义组件 组件(Component)是一个可复用与多框架的模块包,一般用于几种场景: * 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等 * 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等 组件可以本地加载,也可以打包到一起发布成一个 npm 包。组件可以在 midway v3/Serverless 中使用。你可以将复用的业务代码,或者功能模块都放到组件中进行维护。几乎所有的 Midway 通用能力都可以在组件中使用,包括但不限于配置,生命周期,控制器,拦截器等。 设计组件的时候尽可能的面向所有的上层框架场景,所以我们尽可能只依赖 `@midwayjs/core` 。 从 v3 开始,框架(Framework)也变为组件的一部分,使用方式和组件保持统一。 ## 开发组件[​](#开发组件 "开发组件的直接链接") ### 脚手架[​](#脚手架 "脚手架的直接链接") 只需执行下面的脚本,模板列表中选择 `component-v4` 模板,即可快速生成示例组件。 ``` $ npm init midway@latest -y ``` 注意 [Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C)。 ### 组件目录[​](#组件目录 "组件目录的直接链接") 组件的结构和 midway 的推荐目录结构一样,组件的目录结构没有特别明确的规范,和应用或者函数保持一致即可。简单的理解,组件就是一个 “迷你应用"。 一个推荐的组件目录结构如下。 ``` . ├── package.json ├── src │ ├── index.ts // 入口导出文件 │ ├── configuration.ts // 组件行为配置 │ └── service // 逻辑代码 │ └── bookService.ts ├── test ├── index.d.ts // 组件扩展定义 └── tsconfig.json ``` 对于组件来说,唯一的规范是入口导出的 `Configuration` 属性,其必须是一个带有 `@Configuration` 装饰器的 Class。 一般来说,我们的代码为 TypeScript 标准目录结构,和 Midway 体系相同。 同时,又是一个普通的 Node.js 包,需要使用 `src/index.ts` 文件作为入口导出内容。 下面,我们以一个非常简单的示例来演示如何编写一个组件。 ### 组件生命周期[​](#组件生命周期 "组件生命周期的直接链接") 和应用相同,组件也使用 `src/configuration.ts` 作为入口启动文件(或者说,应用就是一个大组件)。 其中的代码和应用完全相同。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; @Configuration({ namespace: 'book' }) export class BookConfiguration { async onReady() { // ... } } ``` 唯一不同的是,你需要加一个 `namespace` 作为组件的命名空间。 每个组件的代码是一个独立的作用域,这样即使导出同名的类,也不会和其他组件冲突。 和整个 Midway 通用的 [生命周期扩展](/docs/lifecycle.md) 能力相同。 ### 组件逻辑代码[​](#组件逻辑代码 "组件逻辑代码的直接链接") 和应用相同,编写类导出即可,由依赖注入容器负责管理和加载。 ``` // src/service/book.service.ts import { Provide } from '@midwayjs/core'; @Provide() export class BookService { async getBookById() { return { data: 'hello world', } } } ``` 信息 一个组件不会依赖明确的上层框架,为了达到在不同场景复用的目的,只会依赖通用的 `@midwayjs/core`。 ### 组件配置[​](#组件配置 "组件配置的直接链接") 配置和应用相同,参考 [多环境配置](/docs/env_config.md)。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ namespace: 'book', importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class BookConfiguration { async onReady() { // ... } } ``` 在 v3 有一个重要的特性,组件在加载后,`MidwayConfig` 定义中就会包含该组件配置的定义。 为此,我们需要独立编写配置的定义。 在根目录下的 `index.d.ts` 中增加配置定义。 ``` // 由于修改了默认的类型导出位置,需要额外导出 dist 下的类型 export * from './dist/index'; // 标准的扩展声明 declare module '@midwayjs/core' { // 将配置合并到 MidwayConfig 中 interface MidwayConfig { book?: { // ... }; } } ``` 同时,组件的 `package.json` 也有对应的修改。 ``` { "name": "****", "main": "dist/index.js", "typings": "index.d.ts", // 这里的类型导出文件使用项目根目录的 // ... "files": [ "dist/**/*.js", "dist/**/*.d.ts", "index.d.ts" // 发布时需要额外带上这个文件 ], } ``` ### 组件约定[​](#组件约定 "组件约定的直接链接") 组件和应用本身略微有些不同,差异主要在以下几个方面。 * 1、组件的代码需要有一个入口,其必须是一个包含 `@Configuration` 装饰器或者 `defineConfiguration` 的文件,并且需要将其导出 * 2、所有 \*\*显式导出的代码 \*\*才会被依赖注入容器加载,简单来说,所有 **被装饰器装饰** 的类都需要导出,包括控制器,服务,中间件等等 比如: ``` // src/index.ts export { BookConfiguration as Configuration } from './configuration'; export * from './service/book.service'; ``` 信息 这样项目中只有 `service/book.service.ts` 这个文件才会被依赖注入容器扫描和加载。 以及在 `package.json` 中指定 main 路径。 ``` "main": "dist/index" ``` 这样组件就可以被上层场景依赖加载了。 ### 测试组件[​](#测试组件 "测试组件的直接链接") 测试单独某个服务,可以通过启动一个空的业务,指定当前组件来执行。 ``` import { createLightApp } from '@midwayjs/mock'; import * as custom from '../src'; describe('/test/index.test.ts', () => { it('test component', async () => { const app = await createLightApp('', { imports: [ custom ] }); const bookService = await app.getApplicationContext().getAsync(custom.BookService); expect(await bookService.getBookById()).toEqual('hello world'); }); }); ``` 如果组件是 Http 协议流程中的一部分,强依赖 context,必须依赖某个 Http 框架,那么,请使用一个完整的项目示例,使用 `createApp` 来测试。 ``` import { createApp, createHttpRequest } from '@midwayjs/mock'; import * as custom from '../src'; describe('/test/index.test.ts', () => { it('test component', async () => { // 在示例项目中,需要自行依赖 @midwayjs/koa 或其他对等框架 const app = await createApp(join(__dirname, 'fixtures/base-app'), { imports: [ custom ] }); const result = await createHttpRequest(app).get('/'); // ... }); }); ``` ### 依赖其他组件[​](#依赖其他组件 "依赖其他组件的直接链接") 如果组件依赖另一个组件中的类,和应用相同,需要在入口处声明,框架会按照模块顺序加载并处理重复的情况。 如果明确依赖某个组件中的类,那么必然是该组件的强依赖。 比如: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; @Configuration({ namespace: 'book', imports: [axios] }) export class BookConfiguration { async onReady() { // ... } } ``` 还有一种弱依赖的情况,无需显式声明,但是需要额外的判断。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration({ namespace: 'book', }) export class BookConfiguration { async onReady(container: IMidwayContainer) { // ... if (container.hasNamespace('axios')) { // 当 axios 组件被加载时才执行 } // ... } } ``` 增加依赖。 ``` // package.json { "dependencies": { "@midwayjs/axios": "xxxx" } } ``` 在根目录下的 `index.d.ts` 中增加显式导入依赖的组件定义。 ``` // 显式导入依赖的组件 import '@midwayjs/axios'; export * from './dist/index'; // ... ``` 提示 如果主应用不显式依赖 axios,代码执行是正常的,但是 typescript 的 axios 的定义不会被扫描到,导致编写配置时没有 axios 定义,上述代码可以解决这个问题。 ### 应用中开发组件[​](#应用中开发组件 "应用中开发组件的直接链接") 推荐使用 [lerna](https://github.com/lerna/lerna),以及开启 lerna 的 hoist 模式来编写组件。如果想在非 lerna 的场景场景下开发组件,请保证组件在 `src` 目录下,否则会出现加载失败的情况。 #### 使用 lerna[​](#使用-lerna "使用 lerna的直接链接") 使用 lerna 开发相对比较简单,具体的目录结构类似如下。 ``` . ├── src ├── packages/ │ ├── component-A │ │ └── package.json │ ├── component-B │ │ └── package.json │ ├── component-C │ │ └── package.json │ └── web │ └── package.json ├── lerna.json └── package.json ``` #### 非 lerna[​](#非-lerna "非 lerna的直接链接") 下面是一种常见的组件开发方式,示例结构为在应用代码开发时同时开发两个组件,当然,你也可以自定义你喜欢的目录结构。 ``` . ├── package.json ├── src // 源码目录 │ ├── components │ │ ├── book // book 组件代码 │ │ │ ├── src │ │ │ │ ├── service │ │ │ │ │ └── bookService.ts │ │ │ │ ├── configuration.ts │ │ │ │ └── index.ts │ │ │ └── package.json │ │ │ │ │ └── school │ │ ├── src │ │ │ ├── service // school 组件代码 │ │ │ │ └── schoolService.ts │ │ │ └── configuration.ts │ │ └── package.json │ │ │ ├── configuration.ts // 应用行为配置文件 │ └── controller // 应用路由目录 ├── test └── tsconfig.json ``` 组件行为配置。 ``` // src/components/book/src/bookConfiguration.ts import { Configuration } from '@midwayjs/core'; @Configuration() export class BookConfiguration {} ``` 为了让组件能导出,我们需要在组件的入口 `src/components/book/src/index.ts` 导出 `Configuration` 属性。 ``` // src/components/book/src/index.ts export { BookConfiguration as Configuration } from './bookConfiguration/src`; ``` 信息 注意,这里引用的地方是 "./xxxx/src",是因为一般我们 package.json 中的 main 字段指向了 dist/index,如果希望代码不修改,那么 main 字段要指向 src/index,且在发布时记得修改回 dist。 将组件引入的目录指向 src ,是为了能在保存是自动生效(重启)。 另外,在新版本可能会出现扫描冲突的问题。可以将 `configuration.ts` 中的依赖注入冲突检查功能关闭。 ### 使用组件[​](#使用组件 "使用组件的直接链接") 在任意的 midway 系列的应用中,可以通过同样的方式引入这个组件。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "midway-component-book": "*" } } ``` 然后,在应用(函数)中引入这个组件。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as book from 'midway-component-book'; @Configuration({ imports: [book], }) export class MainConfiguration {} ``` 至此,我们的准备工作就做完了,下面开始使用。 直接引入组件的类注入。 ``` import { Provide, Inject } from '@midwayjs/core'; import { BookService } from 'midway-component-book'; @Provide() export class Library { @Inject(); bookService: BookService; } ``` 其余如果组件有包含特定的能力,请参考组件本身的文档。 ### 组件发布[​](#组件发布 "组件发布的直接链接") 组件就是一个普通 Node.js 包,编译后发布到 npm 分发即可。 ``` ## 编译并发布对应的component $ npm run build && npm publish ``` ### 组件示例[​](#组件示例 "组件示例的直接链接") [这里](https://github.com/czy88840616/midway-test-component) 有一个组件示例。已经发布到 npm,可以尝试直接引入到项目中启动执行。 ## 开发框架(Framework)[​](#开发框架framework "开发框架(Framework)的直接链接") 在 v3 中,组件可以包含一个 Framework,来提供不同的服务,利用生命周期,我们可以扩展提供 gRPC,Http 等协议。 这里的 Framework 只是组件里的一个特殊业务逻辑文件。 比如: ``` . ├── package.json ├── src │ ├── index.ts // 入口导出文件 │ ├── configuration.ts // 组件行为配置 │ └── framework.ts // 框架代码 │ ├── test ├── index.d.ts // 组件扩展定义 └── tsconfig.json ``` ### 扩展现有 Framework[​](#��扩展现有-framework "扩展现有 Framework的直接链接") 上面提到,Framework 是组件的一部分,同时也遵循组件规范,是可以注入以及扩展的。 我们以扩展 `@midwayjs/koa` 举例。 首先创建一个自定义组件,和普通应用相同,由于需要扩展 `@midwayjs/koa` ,那么在组件中,我们需要依赖 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ namespace: 'myKoa', imports: [koa] }) export class MyKoaConfiguration { async onReady() { // ... } } ``` 随后,我们就可以注入 `@midwayjs/koa` 导出的 Framework,来做扩展了。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ namespace: 'myKoa', imports: [koa] }) export class MyKoaConfiguration { @Inject() framework: koa.Framework; async onReady() { // 添加中间件,koa 中的 app.useMiddleware 其实代理了 framework 上的方法 this.framework.useMiddleware(/* ... */); // 添加过滤器,koa 中的 app.useFilter 其实代理了 framework 上的方法 this.framework.useFilter(/* ... */); // koa 自身的扩展能力,比如扩展 context const app = this.framework.getApplication(); Object.defineProperty(app.context, 'user', { get() { // ... return 'xxx'; }, enumerable: true, }); // ... } async onServerReady() { const server = this.framework.getServer(); // server.xxxx } } ``` 这是一种基于现有 Framework 去扩展的一种方法。 * 如果组件中扩展了 context,那么请参考 [扩展上下文定义](/docs/context_definition.md) * 如果组件中扩展了配置,那么请参考 [组件配置](#%E7%BB%84%E4%BB%B6%E9%85%8D%E7%BD%AE) 等组件发布后,比如叫 `@midwayjs/my-koa`,业务可以直接使用你的组件,而无需引入 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; // 你自己的组件 import * as myKoa from '@midwayjs/my-koa'; @Configuration({ imports: [myKoa], }) export class MyConfiguration { async onReady() { // ... } } ``` 如果希望完全定义自己的组件,比如不同的协议,就需要完整自定义 Framework。 ### 编写 Framework[​](#编写-framework "编写 Framework的直接链接") 框架都遵循 `IMidwayFramewok` 的接口定义,以及如下约定。 * 每个框架有要自定义独立的启停流程 * 每个框架需要定义自己独立的 `Application` ,`Context` * 每个框架可以有自己独立的中间件能力 为了简化开发,Midway 提供了一个基础的 `BaseFramework` 类供继承。 ``` import { Framework, BaseFramework, IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core'; // 定义 Context export interface Context extends IMidwayContext { // ... } // 定义 Application export interface Application extends IMidwayApplication { // ... } // 框架的配置 export interface IMidwayCustomConfigurationOptions extends IConfigurationOptions { // ... } // 实现一个自定义框架,继承基础框架 @Framework() export class MidwayCustomFramework extends BaseFramework { // 处理初始化配置 configure() { // ... } // app 初始化 async applicationInitialize() { // ... } // 框架启动,比如 listen async run() { // ... } } ``` ### 自定义示例[​](#自定义示例 "自定义示例的直接链接") 接下去我们会以实现一个基础的 HTTP 服务框架作为示例。 ``` import { BaseFramework, IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core'; import * as http from 'http'; // 定义一些上层业务要使用的定义 export interface Context extends IMidwayContext {} export interface Application extends IMidwayApplication {} export interface IMidwayCustomConfigurationOptions extends IConfigurationOptions { port: number; } // 实现一个自定义框架,继承基础框架 export class MidwayCustomHTTPFramework extends BaseFramework { configure(): IMidwayCustomConfigurationOptions { return this.configService.getConfiguration('customKey'); } async applicationInitialize(options: Partial) { // 创建一个 app 实例 this.app = http.createServer((req, res) => { // 创建请求上下文,自带了 logger,请求作用域等 const ctx = this.app.createAnonymousContext(); // 从请求上下文拿到注入的服务 ctx.requestContext .getAsync('xxxx') .then((ins) => { // 调用服务 return ins.xxx(); }) .then(() => { // 请求结束 res.end(); }); }); // 给 app 绑定上 midway 框架需要的一些方法,比如 getConfig, getLogger 等。 this.defineApplicationProperties(); } async run() { // 启动的参数,这里只定义了启动的 HTTP 端口 if (this.configurationOptions.port) { new Promise((resolve) => { this.app.listen(this.configurationOptions.port, () => { resolve(); }); }); } } } ``` 我们定义了一个 `MidwayCustomHTTPFramework` 类,继承了 `BaseFramework` ,同时实现了 `applicationInitialize` 和 `run` 方法。 这样,一个最基础的框架就完成了。 最后,我们只要按照约定,将 Framework 导出即可。 ``` export { Application, Context, MidwayCustomHTTPFramework as Framework, IMidwayCustomConfigurationOptions, } from './custom'; ``` 上面是一个最简单的框架示例。事实上,Midway 所有的框架都是这么编写的。 --- # 依赖注入 Midway 中使用了非常多的依赖注入的特性,通过装饰器的轻量特性,让依赖注入变的优雅,从而让开发过程变的便捷有趣。 依赖注入是 Java Spring 体系中非常重要的核心,我们用简单的做法讲解这个能力。 我们举个例子,以下面的函数目录结构为例。 ``` . ├── package.json ├── src │ ├── controller # 控制器目录 │ │ └── user.controller.ts │ └── service # 服务目录 │ └── user.service.ts └── tsconfig.json ``` 在上面的示例中,提供了两个文件, `user.controller.ts` 和 `user.service.ts` 。 提示 下面的示例,为了展示完整的功能,我们会写完整的 `@Provide` 装饰器,而在实际使用中,如果有其他装饰器(比如 `@Controller` )的情况下, `@Provide` 可以被省略。 为了解释方便,我们将它合并到了一起,内容大致如下。 ``` import { Provide, Inject, Get } from '@midwayjs/core'; // user.controller.ts @Provide() // 实际可省略 @Controller() export class UserController { @Inject() userService: UserService; @Get('/') async get() { const user = await this.userService.getUser(); console.log(user); // world } } // user.service.ts @Provide() export class UserService { async getUser() { return 'world'; } } ``` 抛开所有装饰器,你可以看到这是标准的 Class 写法,没有其他多余的内容,这也是 Midway 体系的核心能力,依赖注入最迷人的地方。 `@Provide` 的作用是告诉 **依赖注入容器**,我需要被容器所加载。 `@Inject` 装饰器告诉容器,我需要将某个实例注入到属性上。 通过这两个装饰器的搭配,我们可以方便的在任意类中拿到实例对象,就像上面的 `this.userService` 。 **注意**:实际使用中,如果有其他装饰器(比如 `@Controller` )的情况下 `@Provide` 经常被省略。 ## 依赖注入原理[​](#依赖注入原理 "依赖注入原理的直接链接") 我们以下面的伪代码举例,在 Midway 体系启动阶段,会创建一个依赖注入容器(MidwayContainer),扫描所有用户代码(src)中的文件,将拥有 `@Provide` 装饰器的 Class,保存到容器中。 ``` /***** 下面为 Midway 内部代码 *****/ const container = new MidwayContainer(); container.bind(UserController); container.bind(UserService); ``` 这里的依赖注入容器类似于一个 Map。Map 的 key 是类对应的标识符(比如 **类名的驼峰形式字符串**),Value 则是 **类本身**。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01qRbFaS1dETlDbbrsl_!!6000000003704-2-tps-623-269.png) 在请求时,会动态实例化这些 Class,并且处理属性的赋值,比如下面的伪代码,很容易理解。 ``` /***** 下面为依赖注入容器伪代码 *****/ const userService = new UserService(); const userController = new UserController(); userController.userService = userService; ``` 经过这样,我们就能拿到完整的 `userController` 对象了,实际的代码会稍微不一样。 MidwayContainer 有 `getAsync` 方法,用来异步处理对象的初始化(很多依赖都是有异步初始化的需求),自动属性赋值,缓存,返回对象,将上面的流程合为同一个。 ``` /***** 下面为依赖注入容器内部代码 *****/ // 自动 new UserService(); // 自动 new UserController(); // 自动赋值 userController.userService = await container.getAsync(UserService); const userController = await container.getAsync(UserController); await userController.handler(); // output 'world' ``` 以上就是依赖注入的核心过程,创建实例。 信息 此外,这里还有一篇名为 [《这一次,教你从零开始写一个 IoC 容器》](https://mp.weixin.qq.com/s/g07BByYS6yD3QkLsA7zLYQ)的文章,欢迎扩展阅读。 ## 依赖注入作用域[​](#依赖注入作用域 "依赖注入作用域的直接链接") 默认的未指定或者未声明的情况下,所有的 `@Provide` 出来的 Class 的作用域都为 **请求作用域**。这意味着这些 Class ,会在 **每一次请求第一次调用时被实例化(new),请求结束后实例销毁。** 我们默认情况下的控制器(Controller)和服务(Service)都是这种作用域。 在 Midway 的依赖注入体系中,有三种作用域。 | 作用域 | 描述 | | --------- | --------------------------------------------------------------------------------------- | | Singleton | 单例,全局唯一(进程级别) | | Request | **默认**,请求作用域,生命周期绑定 **请求链路**,实例在请求链路上唯一,请求结束立即销毁 | | Prototype | 原型作用域,每次调用都会重复创建一个新的对象 | 不同的作用域有不同的作用,**单例** 可以用来做进程级别的数据缓存,或者数据库连接等只需要执行一次的工作,同时单例由于全局唯一,只初始化一次,所以调用的时候速度比较快。而 **请求作用域** 则是大部分需要获取请求参数和数据的服务的选择,**原型作用域** 使用比较少,在一些特殊的场景下也有它独特的作用。 ### 配置作用域[​](#配置作用域 "配置作用域的直接链接") 如果我们需要将一个对象定义为其他两种作用域,需要额外的配置。Midway 提供了 `@Scope` 装饰器来定义一个类的作用域。下面的代码就将我们的 user 服务变成了一个全局唯一的实例。 ``` // service import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class UserService { //... } ``` 信息 注意,所有的入口类,比如 Controller,均为请求作用域,不支持修改。大部分情况下,只需要调整 Service 即可。 ### 单例作用域[​](#单例作用域 "单例作用域的直接链接") 在显式配置后,某个类的作用域就可以变成单例作用域。 ``` // service import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class UserService { //... } ``` 后续不管获取这个类的实例多少次,在 **同一个进程下**,都是同一个实例。 比如基于上面的单例服务,下面两个注入的 `userService` 属性是同一个实例: ``` @Provide() export class A { @Inject() userService: UserService //... } @Provide() export class B { @Inject() userService: UserService //... } ``` 在 v3.10 版本之后,可以使用单例装饰器来简化原来的写法。 ``` import { Singleton } from '@midwayjs/core'; @Singleton() class UserService { // ... } ``` ### 请求作用域[​](#请求作用域 "请求作用域的直接链接") 默认情况下,代码中编写的类均为 **请求作用域**。 在每个协议入口框架会自动创建一个请求作用域下的依赖注入容器,所有创建的实例都会绑定当前协议的上下文。 比如: * http 请求进来的时候,会创建一个请求作用域,每个 Controller 都是在请求路由时动态创建 * 定时器触发,也相当于创建了请求作用域 ctx,我们可以通过@Inject()ctx可以拿到这个请求作用域。 信息 默认为请求作用域的目的是为了和请求上下文关联,显式传递 ctx 更为安全可靠,方便调试。 所以在请求作用域中,我们可以通过 `@Inject()` 来注入当前的 ctx 对象。 ``` import { Controller, Provide, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() // 实际可省略 @Controller('/user') export class UserController { @Inject() ctx: Context; //... } ``` 我们的 `@Inject` 装饰器也是在 **当前类的作用域** 下去寻找对象来注入的。比如,在 `Singleton` 作用域下,由于和请求不关联 ,默认没有 `ctx` 对象,所以注入 ctx 是不对的 。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() ctx; // undefined //... } ``` ### 作用域固化[​](#作用域固化 "作用域固化的直接链接") 当作用域被设置为单例(Singleton)之后,整个 Class 注入的对象在第一次实例化之后就已经被固定了,这意味着,单例中注入的内容不能是其他作用域。 我们来举个例子。 ``` // 这个类是默认的请求作用域(Request) @Provide() // 实际可省略 @Controller() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { async getUser() { // ... } } ``` 调用的情况如下。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01FN99rS1Xb1YydSFi0_!!6000000002941-2-tps-1110-388.png) 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 都会固定的那个。 我们再来举个例子演示单例中注入的服务是否还会保留原有作用域。 信息 这里的 `DBManager` 我们特地设置成请求作用域,来演示一下特殊场景。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01eAyxrC1xVEYzbNf9P_!!6000000006448-2-tps-1964-334.png) ``` // 这个类是默认的请求作用域(Request) @Provide() export class HomeController { @Inject() userService: UserService; } // 设置了单例,进程级别唯一 @Provide() @Scope(ScopeEnum.Singleton) export class UserService { @Inject() dbManager: DBManager; async getUser() { // ... } } // 未设置作用域,默认是请求作用域(这里用来验证单例链路下,后续的实例都被缓存的场景) @Provide() export class DBManager { } ``` 这种情况下,不论调用 `HomeController` 多少次,每次请求的 `HomeController` 实例是不同的,而 `UserService` 和 `DBManager` 都会固定的那个。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01UoLu1526stZQFhp1U_!!6000000007718-2-tps-1870-762.png) 简单的理解为,单例就像一个缓存,**其中依赖的所有对象都将被冻结,不再变化。** ### 作用域降级[​](#作用域降级 "作用域降级的直接链接") 上面提到,当单例作用域注入请求作用域对象时,请求作用域的对象实例将被固化,会保存一个固定的实例在单例的缓存中。 这个时候,请求作用域变为单例,出现 **作用域降级** 的情况。 在日常开发中,一不留神就会发生这种情况,比如中间件中调用服务。 ``` //下面这段是错误的示例 @Provide() export class UserService { @Inject() ctx: Context; async getUser() { const id = this.ctx.xxxx; // ctx not found, will throw error } } // 中间件是单例 @Middleware() export class ReportMiddleware implements IMiddleware { @Inject() userService: UserService; // 这里的用户服务是请求作用域 resolve() { return async(ctx, next) => { await this.userService.getUser(); // ... } } } ``` 这个时候,虽然 `UserService` 可以正常注入中间件,但是实际上是以 单例 的对象注入,而不是请求作用域的对象,会导致 `ctx` 为空的情况。 这个时候的内存对象图为: ![](https://img.alicdn.com/imgextra/i3/O1CN01SwATKb1zUtVUCaQGj_!!6000000006718-2-tps-1292-574.png) `UserService` 的实例变成了不同的对象,一个是单例调用的实例(单例,不含 ctx),一个是正常的请求作用域调用的实例(请求作用域,含 ctx)。 为了避免发生这种情况,默认在这类错误的注入时,框架会自动抛出名为 `MidwaySingletonInjectRequestError` 的错误,阻止程序执行。 如果用户了解其中的风险,明确需要在单例中调用请求作用域对象,可以通过作用域装饰器的参数来设置允许降级。 并在其中做好 `ctx` 的空对象判断。 ``` import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Request, { allowDowngrade: true }) export class UserService { @Inject() ctx: Context; async getUser() { if (ctx && ctx.xxxx) { // ... } // ... } } ``` 当然,如果只是误写,那可以使用动态的获取方式,使得作用域统一。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const userService = await ctx.requestContext.getAsync(UserService); // TODO userService.xxxx await next(); }; } } ``` ### 获取对象作用域[​](#获取对象作用域 "获取对象作用域的直接链接") 从 v3.12.0 版本开始,依赖注入容器增加了一个新的获取对象作用域的 API。 ``` import { Controller, Inject, ApplicationContext, Get, IMidwayContainer } from '@midwayjs/core'; import { UserService} from '../service/user.service'; @Singleton() export class UserSerivce { // ... } @Controller('/') export class HomeController { @Inject() userService: UserService; @ApplicationContext() applicationContext: IMidwayContainer; @Get('/') async home(): Promise { console.log(this.applicationContext.getInstanceScope(this)); // => Request console.log(this.applicationContext.getInstanceScope(this.userService)); // => Singleton // ... } } ``` `getInstanceScope` 方法的返回值为 `ScopeEnum` 值。 ## 注入规则[​](#注入规则 "注入规则的直接链接") Midway 支持多种方式的注入。 ### 基于类型的注入[​](#基于类型的注入 "基于类型的注入的直接链接") 导出一个 Class,注入的类型使用 Class,这是最简单的注入方式,大部分的业务和组件都是使用这样的方式。 标准的注入有两种形式,**属性注入** 以及 **构造器注入**。 * 属性注入 * 构造器注入 Midway 会自动使用 B 作为 b 这个属性的类型,在容器中实例化它。 ``` import { Provide, Inject } from '@midwayjs/core'; @Provide() // <------ 暴露一个 Class export class B { //... } @Provide() export class A { @Inject() b: B; // <------ 这里的属性使用 Class //... } ``` 在 `4.0.0` 版本中,我们恢复了构造器注入的特性,用户可以显式的在构造器中注入依赖。 ``` import { Provide, Inject } from '@midwayjs/core'; @Provide() export class B { //... } @Provide() export class A { private b: B; constructor(@Inject() b: B) { this.b = b; } } ``` Midway 会自动使用 B 作为 b 这个参数类型,在容器中实例化它。 在 TypeScript 中,你也可以使用简化的写法,带有访问修饰符的参数会自动创建对应的属性。 ``` @Provide() export class A { constructor(protected @Inject() b: B) {} } ``` 提示 仅有 `@Inject` 装饰器支持构造器注入。 ### 依赖注入标识符[​](#依赖注入标识符 "依赖注入标识符的直接链接") 不管哪种注入方式,Midway 都会自动创建一个唯一的 uuid 关联这个 Class,同时这个 uuid 我们称为 **依赖注入标识符**。 默认情况: * 1、 `@Provide` 会自动生成一个 uuid 作为 **依赖注入标识符** * 2、 `@Inject` 根据类型的 uuid 来查找 如果要获取这个 uuid,可以使用下面的 API。 ``` import { getProviderUUId } from '@midwayjs/core'; const uuid = getProviderUUId(B); // ... ``` 可以通过 `@Provide` 装饰器和 `@Inject` 装饰器的参数指定 **依赖注入标识符**,比如指定一个字符串。 ``` import { Provide, Inject } from '@midwayjs/core'; @Provide('bbbb') export class B { //... } @Provide() export class A { @Inject('bbbb') b: B; //... } ``` Midway 会将 `bbbb` 作为 B 这个 Class 的依赖注入标识符,在容器中实例化它。这种情况下,即使写了类型 B,依赖注入容器依旧会优先使用 `bbbb` 。 `@Provide` 和 `@Inject` 装饰器的参数是成对出现。 规则如下: * 1、如果装饰器包含参数,则以 **参数** 作为依赖注入标识符 * 2、如果没有参数,标注的 TS 类型为 Class,则将类 `@Provide` 的 key 作为 key,如果没有 key,默认取 uuid * 3、如果没有参数,标注的 TS 类型为非 Class,则将 **属性名** 作为 key ### 注入已有对象[​](#注入已有对象 "注入已有对象的直接链接") 有时候,应用已经有现有的实例,而不是类,比如引入了一个第三库,这个时候如果希望对象能够被其他 IoC 容器中的实例引用,也可以通过增加对象的方式进行处理。 我们拿常见的工具类库 lodash 来举例。 假如我们希望在不同的类中直接注入来使用,而不是通过 require 的方式。 你需要在业务调用前(一般在启动的生命周期中)通过 `registerObject` 方法添加这个对象。 在添加的时候需要给出一个 **依赖注入标识符**,方便其他类中注入。 ``` // src/configuration.ts import * as lodash from 'lodash'; import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration { async onReady(applicationContext: IMidwayContainer) { // 向依赖注入容器中添加一些全局对象 applicationContext.registerObject('lodash', lodash); } } ``` 这个时候就可以在任意的类中通过 `@Inject` 来使用了。 ``` @Provide() export class BaseService { @Inject('lodash') lodashTool; async getUser() { // this.lodashTool.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 }); } } ``` ### 内置的默认标识符[​](#内置的默认标识符 "内置的默认标识符的直接链接") Midway 会默认注入一些标识符,方便业务直接使用。 | **标识符** | **值类型** | **作用域** | **描述** | | ---------- | ---------- | ---------- | ------------------------------------------------------------------ | | baseDir | string | 全局 | 本地开发时为 src 目录,否则为 dist 目录 | | appDir | string | 全局 | 应用的根路径,一般为 process.cwd() | | ctx | object | 请求链路 | 对应框架的上下文类型,比如 Koa 和 EggJS 的 Context,Express 的 req | | logger | object | 请求链路 | 等价于 ctx.logger | | req | object | 请求链路 | Express 特有 | | res | object | 请求链路 | Express 特有 | | socket | object | 请求链路 | WebSocket 场景特有 | ``` @Provide() export class BaseService { @Inject() baseDir; @Inject() appDir; async getUser() { console.log(this.baseDir); console.log(this.appDir); } } ``` ## 循环依赖[​](#循环依赖 "循环依赖的直接链接") 如果项目较大,则可能会出现循环依赖的问题。 比如 A 依赖 B,B 依赖 C,C 依赖 A。 ``` @Provide() export class A { @Inject() b: B; } @Provide() export class B { @Inject() c: C; } @Provide() export class C { @Inject() a: A; } ``` 以上代码会报错,因为 A 依赖 B,B 依赖 C,C 依赖 A,形成了循环依赖。 ### 识别循环依赖[​](#识别循环依赖 "识别循环依赖的直接链接") 在 `4.0.0` 版本中,Midway 会自动识别循环依赖,并抛出错误。 你会看到类似下面的错误信息。 ``` Circular dependency detected: A -> B -> C -> A ``` ### 解决循环依赖[​](#解决循环依赖 "解决循环依赖的直接链接") 可以通过框架提供的 `@LazyInject` 装饰器来解决循环依赖的问题。 ``` import { LazyInject, Inject, Provide } from '@midwayjs/core'; @Provide() export class A { @Inject() b: B; } @Provide() export class B { @Inject() c: C; } @Provide() export class C { @LazyInject(() => A) a: A; } ``` 提示 仅在需要解决循环依赖的时候,才使用 `@LazyInject` 装饰器。 ## 获取依赖注入容器[​](#获取依赖注入容器 "获取依赖注入容器的直接链接") 在一般情况下,用户无需关心依赖注入容器,但是在一些特殊场景下,比如 * 需要动态调用服务的,比如 Web 的中间件场景,启动阶段需要调用服务的 * 封装框架或者其他三方 SDK 中需要动态获取服务的 简单来说,任意需要 **通过 API 动态获取服务** 的场景,都需要先拿到依赖注入容器。 ### 从 @ApplicationContext() 装饰器中获取[​](#从-applicationcontext-装饰器中获取 "从 @ApplicationContext() 装饰器中获取的直接链接") 在新版本中,Midway 提供了一个 @ApplicationContext() 的装饰器,用来获取依赖注入容器。 ``` import { ApplicationContext, IMidwayContainer } from '@midwayjs/core'; import { IMidwayContainer } from '@midwayjs/core'; @Provide() export class BootApp { @ApplicationContext() applicationContext: IMidwayContainer; // 这里也可以换成实际的框架的 app 定义 async invoke() { // this.applicationContext } } ``` ### 从 app 中获取[​](#从-app-中获取 "从 app 中获取的直接链接") Midway 将依赖注入容器挂载在两个地方,框架的 app 以及每次请求的上下文 Context,由于不同上层框架的情况不同,我们这里列举一下常见的示例。 对于不同的上层框架,我们统一提供了 `IMidwayApplication` 定义,所有的上层框架 app 都会实现这个接口,定义如下。 ``` export interface IMidwayApplication { getApplicationContext(): IMidwayContainer; //... } ``` 即通过 `app.getApplicationContext()` 方法,我们都能获取到依赖注入容器。 ``` const container = app.getApplicationContext(); ``` 配合 `@App` 装饰器,我们可以方便的在任意地方拿到当前运行的 app 实例。 ``` import { App, IMidwayApplication } from '@midwayjs/core'; @Provide() export class BootApp { @App() app: IMidwayApplication; // 这里也可以换成实际的框架的 app 定义 async invoke() { // 获取依赖注入容器 const applicationContext = this.app.getApplicationContext(); } } ``` 除了普通的依赖注入容器之外,Midway 还提供了一个 **请求链路的依赖注入容器** ,这个请求链路的依赖注入容器和全局的依赖注入容器关联,共享一个对象池。但是两者还是有所区别的。 请求链路的依赖注入容器,是为了获取特有的请求作用域的对象,这个容器中获取的对象,都是**和请求绑定**,关联了当前的上下文。这意味着,**如果 Class 代码和请求关联,必须要从这个请求链路的依赖注入容器中获取**。 请求链路的依赖注入容器,必须从请求上下文对象中获取,最常见的场景为 Web 中间件。 ``` @Middleware() export class ReportMiddleware { resolve() { return async(ctx, next) => { // ctx.requestContext 请求链路的依赖注入容器 await next(); } } } ``` Express 的请求链路依赖注入容器挂载在 req 对象上。 ``` @Middleware() export class ReportMiddleware { resolve() { return (req, res, next) => { // req.requestContext 请求链路的依赖注入容器 next(); } } } ``` ### 在 Configuration 中获取[​](#在-configuration-中获取 "在 Configuration 中获取的直接链接") 在代码的入口 `configuration` 文件的生命周期中,我们也会额外传递依赖注入容器参数,方便用户直接使用。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration { async onReady(applicationContext: IMidwayContainer) { // ... } } ``` ## 动态 API[​](#动态-api "动态 API的直接链接") ### 动态获取实例[​](#动态获取实例 "动态获取实例的直接链接") 拿到 **依赖注入容器** 或者 **请求链路的依赖** 注入容器之后,才可以通过容器的 API 获取到对象。 我们可以使用标准的依赖注入容器 API 来获取实例。 ``` // 全局容器,获取的是单例 const userSerivce = await applicationContext.getAsync(UserService); // 请求作用域容器,获取请求作用域实例 const userSerivce = await ctx.requestContext.getAsync(UserService); ``` 我们可以在任意能获取依赖注入容器的地方使用,比如中间件中。 ``` import { Middleware, ApplicationContext, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; import { UserService } from './service/user.service'; @Middleware() export class ReportMiddleware implements IMiddleware { @ApplicationContext() applicationContext: IMidwayContainer; resolve() { return async(ctx, next) => { // 指定泛型类型,比如某个接口 const userService1 = await this.applicationContext.getAsync(UserService); // 不写泛型,也能推导出正确的类型 const userService1 = await this.applicationContext.getAsync(UserService); // 下面的方法获取的服务和请求关联,可以注入上下文 const userService2 = await ctx.requestContext.getAsync(UserService); await next(); } } } ``` Express 的写法 ``` import { UserService, Middleware } from './service/user'; import { NextFunction, Context, Response } from '@midwayjs/express'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (req, res, next) => { const userService = await req.requestContext.getAsync(UserService); // ... next(); } } } ``` ### 传递构造器参数[​](#传递构造器参数 "传递构造器参数的直接链接") 在个别场景下,我们可以通过 `getAsync` 获取实例的时候,传递构造器的参数。普通装饰器模式无法做到,仅在 API 形式下可用。 ``` @Provide() class UserService { constructor(private readonly type) {} getUser() { // this.type => student } } // 全局容器,获取的是单例 const userSerivce = await applicationContext.getAsync(UserService, [ 'student', // 构造器参数,会 apply 到构造器中 ]); // 请求作用域容器,获取请求作用域实例 const userSerivce = await ctx.requestContext.getAsync(UserService, [ 'student' ]); ``` 注意,构造器不能使用注入形式传递实例,只能传递固定的值。 ### 动态函数注入[​](#动态函数注入 "动态函数注入的直接链接") 在某些场景下,我们需要函数作为某个逻辑动态执行,而依赖注入容器中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。 比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个工厂方法,并且在函数中拿到上下文,动态去生成实例。 下面是标准的工厂方法注入样例。 一般工厂方法用于返回相同接口的实现,比如我们有两个 `ICacheService` 接口的实现: ``` export interface ICacheService { getData(): any; } @Provide() export class LocalCacheService implements ICacheService { async getData {} } @Provide() export class RemoteCacheService implements ICacheService { async getData {} } ``` 然后可以定义一个动态服务(工厂),根据当前的用户配置返回不同的实现。 ``` // src/service/dynamicCacheService.ts import { providerWrapper, IMidwayContainer, MidwayConfigService } from '@midwayjs/core'; export async function dynamicCacheServiceHandler(container: IMidwayContainer) { // 从容器 API 获取全局配置 const config = container.get(MidwayConfigService).getConfiguration(); if (config['redis']['mode'] === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } } providerWrapper([ { id: 'dynamicCacheService', provider: dynamicCacheServiceHandler, scope: ScopeEnum.Request, // 设置为请求作用域,那么上面传入的容器就为请求作用域容器 // scope: ScopeEnum.Singleton, // 也可以设置为全局作用域,那么里面的调用的逻辑将被缓存 } ]); ``` 这样在业务中,可以直接来使用了。注意:在注入的时候,方法会**被调用后再注入**。 ``` @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('dynamicCacheServiceHandler') cacheService: ICacheService; @Get('/') async home() { const data = await this.cacheService.getData(); // ... } } ``` 通过 `providerWrapper` 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。 信息 注意,动态方法必须 export,才会被依赖注入扫描到,默认为请求作用域(获取的 Container 是请求作用域容器)。 由于我们能将动态方法绑定到依赖注入容器,那么也能将一个回调方法绑定进去,这样获取的方法是可以被执行的,我们可以根据业务的传参来决定返回的结果。 ``` import { providerWrapper, IMidwayContainer } from '@midwayjs/core'; export function cacheServiceHandler(container: IMidwayContainer) { return async (mode: string) => { if (mode === 'local') { return await container.getAsync('localCacheService'); } else { return await container.getAsync('remoteCacheService'); } }; } providerWrapper([ { id: 'cacheServiceHandler', provider: cacheServiceHandler, scope: ScopeEnum.Singleton, } ]); @Provide() @Controller('/') export class HomeController { @Inject() ctx: Context; @Inject('cacheServiceHandler') getCacheService; @Get('/') async home() { const data = await this.getCacheService('local'); // ... } } ``` ## 静态 API[​](#静态-api "静态 API的直接链接") 在有些工具类中,我们可以不需要创建 class 实例就能获取到全局的依赖注入容器(**在启动之后**)。 ``` import { getCurrentApplicationContext } from '@midwayjs/core'; export const getService = async (serviceName) => { return getCurrentApplicationContext().getAsync(serviceName); } ``` 获取主框架(**在启动之后**)。 ``` import { getCurrentMainFramework } from '@midwayjs/core'; export const framework = () => { return getCurrentMainFramework(); } ``` 获取主框架的 app 对象(**在启动之后**)。 ``` import { getCurrentMainApp } from '@midwayjs/core'; export const getGlobalConfig = () => { return getCurrentMainApp().getConfig(); } ``` ## 启动行为[​](#启动行为 "启动行为的直接链接") ### 自动扫描和绑定[​](#自动扫描和绑定 "自动扫描和绑定的直接链接") 上面提到,在容器初始化之后,我们会将现有的 class 注册绑定到容器中。 ``` const container = new MidwayContainer(); container.bind(UserController); container.bind(UserService); ``` 在 `4.0.0` 版本中,我们引入了 `detector` 的概念,用于扫描文件并进行绑定。 简单的来说,框架默认会递归扫描整个 `src` 目录下的 ts/js 文件,然后进行 require 操作,当文件导出的为 class,且显式或隐式包含 `@Provide()` 装饰器时,会执行 `container.bind` 逻辑。 下面的逻辑显式的声明了文件的加载行为,用户可以自定义文件探测器,来实现不同的文件加载行为。 ``` // src/configuration.ts import { Configuration, CommonjsFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonjsFileDetector(), }) export class MainConfiguration {} ``` ### 文件探测器[​](#文件探测器 "文件探测器的直接链接") 通过 `detector` 这个配置,我们可以自定义文件的加载行为。 框架提供了 `CommonJSFileDetector` 和 `ESModuleFileDetector` 两个文件加载器,分别用于加载 Commonjs 和 ESM 格式的文件。 * CommonJS * ESModule 如果你希望加载 Commonjs 格式的文件,那么可以这样配置: ``` // src/configuration.ts import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector(), }) export class MainConfiguration {} ``` 如果你希望加载 ESM 格式的文件,那么可以这样配置: ``` // src/configuration.ts import { Configuration, ESModuleFileDetector } from '@midwayjs/core'; @Configuration({ detector: new ESModuleFileDetector(), }) export class MainConfiguration {} ``` 默认情况下,会扫描 `src` 目录下的以下文件,并进行自动处理和绑定。 ``` export const DEFAULT_PATTERN = [ '**/**.tsx', '**/**.ts', '**/**.js', '**/**.mts', '**/**.mjs', '**/**.cts', '**/**.cjs', ]; ``` 同时忽略以下目录和文件: ``` export const DEFAULT_IGNORE_PATTERN = [ '**/logs/**', '**/run/**', '**/public/**', '**/app/view/**', '**/app/views/**', '**/app/extend/**', '**/node_modules/**', '**/**.test.ts', '**/**.test.js', '**/__test__/**', '**/**.d.ts', '**/**.d.mts', '**/**.d.cts' ]; ``` 在以上默认配置的基础上,我们可以通过一些配置来调整文件扫描行为。 如果我们希望扫描忽略某些目录或者类型,那么可以配置 `ignore` 来实现。 * CommonJS * ESModule ``` // src/configuration.ts import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector({ ignore: [ '**/logs/**', ], }), }) export class MainConfiguration {} ``` ``` // src/configuration.ts import { Configuration, ESModuleFileDetector } from '@midwayjs/core'; @Configuration({ detector: new ESModuleFileDetector({ ignore: [ '**/logs/**', ], }), }) export class MainConfiguration {} ``` 可以通过配置 `pattern` 增加扫描的文件后缀和格式。 * CommonJS * ESModule ``` // src/configuration.ts import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector({ pattern: [ '**/**.jsx' ], }), }) export class MainConfiguration {} ``` ``` // src/configuration.ts import { Configuration, ESModuleFileDetector } from '@midwayjs/core'; @Configuration({ detector: new ESModuleFileDetector({ pattern: [ '**/**.jsx' ], }), }) export class MainConfiguration {} ``` 通过配置 `conflictCheck` 来处理导出的类名检查,默认情况下,如果检测到导出相同的名字,会抛出错误。 可以通过配置 `conflictCheck` 来关闭这个检查。 * CommonJS * ESModule ``` // src/configuration.ts import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector({ conflictCheck: false, }), }) export class MainConfiguration {} ``` ``` // src/configuration.ts import { Configuration, ESModuleFileDetector } from '@midwayjs/core'; @Configuration({ detector: new ESModuleFileDetector({ conflictCheck: false, }), }) export class MainConfiguration {} ``` ## 对象生命周期[​](#对象生命周期 "对象生命周期的直接链接") 在依赖注入容器创建和销毁实例的时候,我们可以使用装饰器做一些自定义的操作。 ### 异步初始化[​](#异步初始化 "异步初始化的直接链接") 在某些情况下,我们需要一个实例在被其他依赖调用前需要初始化,如果这个初始化只是读取某个文件,那么可以写成同步方式,而如果这个初始化是从远端拿取数据或者连接某个服务,这个情况下,普通的同步代码就非常的难写。 Midway 提供了异步初始化的能力,通过 `@Init` 标签来管理初始化方法。 `@Init` 方法目前只能是一个。 ``` @Provide() export class BaseService { @Config('hello') config; @Init() async init() { await new Promise(resolve => { setTimeout(() => { this.config.c = 10; resolve(); }, 100); }); } } ``` 等价于 ``` const service = new BaseService(); await service.init(); ``` 信息 @Init 装饰器标记的方法,一定会以异步方式来调用。一般来说,异步初始化的服务较慢,请尽可能标注为单例(@Scope(ScopeEnum.Singleton))。 ### 异步销毁[​](#异步销毁 "异步销毁��的直接链接") Midway 提供了在对象销毁前执行方法的能力,通过 `@Destroy` 装饰器来管理方法。 `@Destroy` 方法目前只能是一个。 ``` @Provide() export class BaseService { @Config('hello') config; @Destroy() async stop() { // do something } } ``` ## 请求作用域中的上下文对象[​](#请求作用域中的上下文对象 "请求作用域中的上下文对�象的直接链接") 在请求作用域创建的对象,框架会在对象上挂载一个上下文对象,即使对象未显式声明 `@Inject() ctx` 也能获取当前上下文对象。 ``` import { REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; @Provide() export class UserManager { // ... } @Provide() export class UserService { // ... @Inject() userManager: UserManager; async invoke() { const ctx = this.userManager[REQUEST_OBJ_CTX_KEY]; // ... } } ``` 这个特性在 [拦截器](/docs/aspect.md) 或者 [自定义方法装饰器](/docs/custom_decorator.md) 中很有用。 ## 常见的使用错误[​](#常见的使用错误 "常见的使用错误的直接链接") ### 错误:构造器中获取注入属性[​](#错误构造器中获取注入属性 "错误:构造器中获取注入属性的直接链接") **请不要在构造器中** 获取注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('userManager') userManager; constructor() { console.log(this.userManager); // undefined } @Init() async initMethod() { console.log(this.userManager); // has value } } ``` ### 关于继承[​](#关于继承 "关于继承的直接链接") 为了避免属性错乱,请不要在基类上使用 `@Provide` 装饰器。 现阶段,Midway 支持属性装饰器的继承,不支持类和方法装饰器的继承(会有歧义)。 --- # 扩展上下文定义 由于 TS 的静态类型分析,我们并不推荐动态去挂载某些属性,动态的挂载会导致 TS 的类型处理非常困难。在某些特殊场景下,如果需要扩展上下文 ctx 属性,比如 Web 场景下中间件,我们可以往上附加一些方法或者属性。 ``` import { Middleware } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IWebMiddleware { resolve() { return async (ctx: Context, next) => { ctx.abc = '123'; await next(); } } } ``` 但是由于 TypeScript 模块定义的关系,我们无法往现有的模块上去附加定义,所以我们使用了一种新的方法来扩展。 ## 项目中扩展定义[​](#项目中扩展定义 "项目中扩展定义的直接链接") 你可以在 `src/interface.ts` 通过下面的代码,在项目中扩展 Midway 通用的 Context。 ``` // src/interface.ts import '@midwayjs/core'; // ... declare module '@midwayjs/core' { interface Context { abc: string; } } ``` 信息 注意,`declare module` 会替代原有的定义,所以请在之前使用 `import` 语法导入模块后再操作。 ## 组件中扩展定义[​](#组件中扩展定义 "组件中扩展定义的直接链接") 组件中略有不同,一般来说,组件可能是只能在特定的场景使用。 你可以在组件根目录的 `index.d.ts` 通过下面的代码,扩展 Midway 通用的 Context。 如果你希望对所有场景的 Context 做扩展。 ``` // index.d.ts // 下面这段可以对所有的 Context 做扩展 declare module '@midwayjs/core' { interface Context { abc: string; } } ``` 如果你只希望对特定场景的 Context 做扩展。 ``` // index.d.ts // 下面这段只 @midwayjs/koa 的 Context 做扩展 declare module '@midwayjs/koa/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/web 的 Context 做扩展 declare module '@midwayjs/web/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/faas 的 Context 做扩展 declare module '@midwayjs/faas/dist/interface' { interface Context { abc: string; } } // 下面这段只 @midwayjs/express 的 Context 做扩展 declare module '@midwayjs/express/dist/interface' { interface Context { abc: string; } } ``` 警告 * 1、组件中扩展和项目中略有不同(怀疑是 TS 的 bug)。 * 2、如果组件中使用了项目的扩展方式,那么其余组件的扩展提示会出现问题。 --- # 向 Midway 贡献 Midway 是一款开源框架,欢迎大家为社区贡献力量,本文介绍如何向 Midway 提交 issue,贡献代码,文档等。 ## 报告问题[​](#报告问题 "报告问题的直接链接") 如果你在开发过程中遇到了一些问题,你无法解决需要想开发者问询的,我们强烈建议: * 1、先在文档中查找相关的问题 * 2、如果查找后无法解决,可以提交一个 [Q\&A](https://github.com/midwayjs/midway/discussions/new/choose)。 在提交的内容时,请遵守下列规范。 * 1、在标题或内容中清楚地解释你的目的,中文或者英文均可。 * 2、在内容中描述以下内容 * 如果是个新需求,请详细描述需求内容,最好有伪代码实现 * 如果是一个 BUG,请提供复现步骤,错误日志,截图,相关配置,框架版本等可以让开发者快速定位问题的内容 * 如果可以,请尽可能提供一个最小可复现的代码仓库,方便调试 * 3、在您报告问题之前,请搜索相关问题。确保您不会打开重复的问题 开发者会在看到时进行标记问题,回复或者解决问题。 ## 修复代码问题[​](#修复代码问题 "修复代码问题的直接链接") 如果你发现框架有一些待修改的问题,可以通过 PR 来提交。 ### PR 流程[​](#pr-流程 "PR 流程的直接链接") 1、首先在 [midway github](https://github.com/midwayjs/midway) 右上角 fork 一个仓库,到自己的空间下。 2、git clone 该仓库到本地或者其他 IDE 环境,进行开发或者修复工作。 ``` # 创建新分支 $ git checkout -b branch-name # 安装依赖 $ npm i # 构建项目 $ npm run build # 开发并执行测试 $ npm test $ git add . # git add -u to delete files $ git commit -m "fix(role): role.use must xxx" $ git push origin branch-name ``` 3、创建一个 Pull Request,选择将自己的项目分支,合并到目标 midwayjs/midway 的 main 分支。 4、系统自动会创建 PR 到 midway 仓库下,在测试通过后,开发者会合并此 PR。 ### 提交规范[​](#提交规范 "提交规范的��直接链接") * 1、一般 PR 使用英文标题 * 2、提交前缀使用 `fix`,`chore`,`feat` ,`docs`字段,用于快速标示修复的类型。 ## 修复文档问题[​](#修复文档问题 "修复文档问题的直接链接") 和普通 PR 类似,如果是单篇文档,可以使用快速编辑的方式提交。 ### 单篇文档快速修复[​](#单篇文档快速修复 "单篇文档快速修复的直接链接") * 1、打开官网需要修复的文档,点击左下角 [Edit this page](#) 链接,会跳转到 Github 对应的文档 * 2、点击 “笔型” 按钮,进入编辑页面 * 3、编辑内容后,将提交的标题修改为 `docs: xxxx`,点击提交按钮创建 PR * 4、等待开发者合并 ### 多篇文档修复[​](#多篇文档修复 "多篇文档修复的直接链接") 和普通 PR 相同,clone 仓库,提交,注意,提交 PR 的标题为 `docs: xxx`。 --- # 路由和控制器 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责 **解析用户的输入,处理后返回相应的结果。** 如图所示,客户端通过 Http 协议请求服务端的控制器,控制器处理结束后响应客户端,这是一个最基础的 ”请求 - 响应“ 流程。 ![controller](https://img.alicdn.com/imgextra/i1/O1CN01dYitV22ADuagILnp3_!!6000000008170-2-tps-1600-634.png) 常见的有: * 在 [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) 接口中,控制器接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。 * 在 HTML 页面请求中,控制器根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。 * 在代理服务器中,控制器将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。 一般来说,控制器常用于对用户的请求参数做一些校验,转换,调用复杂的业务逻辑,拿到相应的业务结果后进行数据组装,然后返回。 在 Midway 中,控制器 **也承载了路由的能力**,每个控制器可以提供多个路由,不同的路由可以执行不同的操作。 在接下去的示例中,我们将演示如何在控制器中创建路由。 ## 路由[​](#路由 "路由的直接链接") 控制器文件一般来说在 `src/controller` 目录中,我们可以在其中创建控制器文件。Midway 使用 `@Controller()` 装饰器标注控制器,其中装饰器有一个可选参数,用于进行路由前缀(分组),这样这个控制器下面的所有路由都会带上这个前缀。 同时,Midway 提供了方法装饰器用于标注请求的类型。 比如,我们创建一个首页控制器,用于返回一个默认的 `/` 路由的页面。 ``` ➜ my_midway_app tree . ├── src │ └── controller │ └── home.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return "Hello Midwayjs!"; } } ``` `@Controller` 装饰器告诉框架,这是一个 Web 控制器类型的类,而 `@Get` 装饰器告诉框架,被修饰的 `home` 方法,将被暴露为 `/` 这个路由,可以由 `GET` 请求来访问。 整个方法返回了一个字符串,在浏览器中你会收到 `text/plain` 的响应类型,以及一个 `200` 的状态码。 提示 路由方法均为 async 方法。 ## 路由方法[​](#路由方法 "路由方法的直接链接") 上面的示例,我们已经创建了一个 **GET** 路由。一般情况下,我们会有其他的 HTTP Method,Midway 提供了更多的路由方法装饰器。 ``` // src/controller/home.ts import { Controller, Get, Post } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { return 'Hello Midwayjs!'; } @Post('/update') async updateData() { return 'This is a post method' } } ``` Midway 还提供了其他的装饰器, `@Get` 、 `@Post` 、 `@Put()` 、 `@Del()` 、 `@Patch()` 、 `@Options()` 、 `@Head()` 和 `@All()` ,表示各自的 HTTP 请求方法。 `@All` 装饰器比较特殊,表示能接受以上所有类型的 HTTP Method。 你可以将多个路由绑定到同一个方法上。 ``` @Get('/') @Get('/main') async home() { return 'Hello Midwayjs!'; } ``` ## 获取请求参数[​](#获取请求参数 "获取请求参数的直接链接") 接下去,我们将创建一个关于用户的 HTTP API,同样的,创建一个 `src/controller/user.ts` 文件,这次我们会增加一个路由前缀,以及增加更多的请求类型。 我们以用户类型举例,先增加一个用户类型,我们一般会将定义的内容放在 `src/interface.ts` 文件中。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` ``` // src/interface.ts export interface User { id: number; name: string; age: number; } ``` 再添加一个路由前缀以及对应的控制器。 ``` // src/controller/user.ts import { Controller } from "@midwayjs/core"; @Controller('/api/user') export class UserController { // xxxx } ``` 接下去,我们要针对不同的请求类型,调用不同的处理逻辑。除了请求类型之外,请求的数据一般都是动态的,会在 HTTP 的不同位置来传递,比如常见的 Query,Body 等。 ### 装饰器参数约定[​](#装饰器参数约定 "装饰器参数约定的直接链接") Midway 添加了常见的动态取值的装饰器,我们以 `@Query` 装饰器举例, `@Query` 装饰器会获取到 URL 中的 Query 参数部分,并将它赋值给函数入参。下面的示例,id 会从路由的 Query 参数上拿,如果 URL 为 `/?id=1` ,则 id 的值为 1,同时,这个路由将会返回 `User` 类型的对象。 ``` // src/controller/user.ts import { Controller, Get, Query } from "@midwayjs/core"; @Controller('/api/user') export class UserController { @Get('/') async getUser(@Query('id') id: string): Promise { // xxxx } } ``` `@Query` 装饰器的有参数,可以传入一个指定的字符串 key,获取对应的值,赋值给入参,如果不传入,则默认返回整个 Query 对象。 ``` // URL = /?id=1 async getUser(@Query('id') id: string) // id = 1 async getUser(@Query() queryData) // {"id": "1"} ``` Midway 提供了更多从 Query、Body 、Header 等位置获取值的装饰器,这些都是开箱即用,并且适配于不同的上层 Web 框架。 下面是这些装饰器,以及对应的等价框架取值方式。 | 装饰器 | Express 对应的方法 | Koa/EggJS 对应的方法 | | ----------------------- | -------------------------------- | ----------------------------------------- | | @Session(key?: string) | req.session / req.session\[key] | ctx.session / ctx.session\[key] | | @Param(key?: string) | req.params / req.params\[key] | ctx.params / ctx.params\[key] | | @Body(key?: string) | req.body / req.body\[key] | ctx.request.body / ctx.request.body\[key] | | @Query(key?: string) | req.query / req.query\[key] | ctx.query / ctx.query\[key] | | @Queries(key?: string) | 无 | 无 / ctx.queries\[key] | | @Headers(name?: string) | req.headers / req.headers\[name] | ctx.headers / ctx.headers\[name] | 警告 **注意** EggJS 和其他框架不同,`@Queries` 装饰器和 `@Query` **有所区别**。 Queries 会将相同的 key 聚合到一起,变为数组。当用户访问的接口参数为 `/?name=a&name=b` 时,@Queries 会返回 `{name: [a, b]}`,而 Query 只会返回 `{name: b}`。 ### Query[​](#query "Query的直接链接") 在 URL 中 `?` 后面的部分是一个 Query String,这一部分经常用于 GET 类型的请求中传递参数。例如 ``` GET /user?uid=1&sex=male ``` 就是用户传递过来的参数。 **示例:从装饰器获取** ``` // src/controller/user.ts import { Controller, Get, Query } from "@midwayjs/core"; @Controller('/user') export class UserController { @Get('/') async getUser(@Query('uid') uid: string): Promise { // xxxx } } ``` **示例:从 API 获取** ``` // src/controller/user.ts import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/') async getUser(): Promise { const query = this.ctx.query; // { // uid: '1', // sex: 'male', // } } } ``` 警告 **注意** EggJS 和其他框架不同,在 当 Query String 中的 key 重复时,`ctx.query` 只取 key 第一次出现时的值,后面再出现的都会被忽略。 比如 `GET /user?uid=1&uid=2` 通过 `ctx.query` 拿到的值是 `{ uid: '1' }`。 ### Body[​](#body "Body的直接链接") 虽然我们可以通过 URL 传递参数,但是还是有诸多限制: * [浏览器中会对 URL 的长度有所限制](http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers),如果需要传递的参数过多就会无法传递。 * 服务端经常会将访问的完整 URL 记录到日志文件中,有一些敏感数据通过 URL 传递会不安全。 在前面的 HTTP 请求报文示例中,我们看到在 header 之后还有一个 body 部分,我们通常会在这个部分传递 POST、PUT 和 DELETE 等方法的参数。一般请求中有 body 的时候,客户端(浏览器)会同时发送 `Content-Type` 告诉服务端这次请求的 body 是什么格式的。Web 开发中数据传递最常用的两类格式分别是 `JSON` 和 `Form`。 框架内置了 [bodyParser](https://github.com/koajs/bodyparser) 中间件来对这两类格式的请求 body 解析成 object 挂载到 `ctx.request.body` 上。HTTP 协议中并不建议在通过 GET、HEAD 方法访问时传递 body,所以我们无法在 GET、HEAD 方法中按照此方法获取到内容。 **示例:获取单个 body** ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/user') export class UserController { @Post('/') async updateUser(@Body('uid') uid: string): Promise { // id 等价于 ctx.request.body.uid } } ``` \*\*示例:获取整个 body \*\* ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/user') export class UserController { @Post('/') async updateUser(@Body() user: User): Promise { // user 等价于 ctx.request.body 整个 body 对象 // => output user // { // uid: '1', // name: 'harry', // } } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // POST /user/ HTTP/1.1 // Host: localhost:3000 // Content-Type: application/json; charset=UTF-8 // // {"uid": "1", "name": "harry"} import { Controller, Post, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Post('/') async getUser(): Promise { const body = this.ctx.request.body; // { // uid: '1', // name: 'harry', // } } } ``` **示例:获取 query 和 body 参数** 装饰器可以组合使用。 ``` @Post('/') async updateUser(@Body() user: User, @Query('pageIdx') pageIdx: number): Promise { // user 从 body 获取 // pageIdx 从 query 获取 } ``` 框架对 bodyParser 设置了一些默认参数,配置好之后拥有以下特性: * 当请求的 Content-Type 为 `application/json`,`application/json-patch+json`,`application/vnd.api+json` 和 `application/csp-report` 时,会按照 json 格式对请求 body 进行解析,并限制 body 最大长度为 `1mb`。 * 当请求的 Content-Type 为 `application/x-www-form-urlencoded` 时,会按照 form 格式对请求 body 进行解析,并限制 body 最大长度为 `1mb`。 * 如果解析成功,body 一定会是一个 Object(可能是一个数组)。 警告 常见错误: `ctx.request.body` 和 `ctx.body` 混淆,后者其实是 `ctx.response.body` 的简写。 ### Router Params[​](#router-params "Router Params的直接链接") 如果路由上使用 `:xxx` 的格式来声明路由,那么参数可以通过 `ctx.params` 获取到。 **示例:从装饰器获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Param } from '@midwayjs/core'; @Controller('/user') export class UserController { @Get('/:uid') async getUser(@Param('uid') uid: string): Promise { // xxxx } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/:uid') async getUser(): Promise { const params = this.ctx.params; // { // uid: '1', // } } } ``` ### Header[​](#header "Header的直接链接") 除了从 URL 和请求 body 上获取参数之外,还有许多参数是通过请求 header 传递的。框架提供了一些辅助属性和方法来获取。 * `ctx.headers`,`ctx.header`,`ctx.request.headers`,`ctx.request.header`:这几个方法是等价的,都是获取整个 header 对象。 * `ctx.get(name)`,`ctx.request.get(name)`:获取请求 header 中的一个字段的值,如果这个字段不存在,会返回空字符串。 * 我们建议用 `ctx.get(name)` 而不是 `ctx.headers['name']`,因为前者会自动处理大小写。 **示例:从装饰器获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Headers } from '@midwayjs/core'; @Controller('/user') export class UserController { @Get('/:uid') async getUser(@Headers('cache-control') cacheSetting: string): Promise { // no-cache // ... } } ``` **示例:从 API 获取** ``` // src/controller/user.ts // GET /user/1 import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/user') export class UserController { @Inject() ctx: Context; @Get('/:uid') async getUser(): Promise { const cacheSetting = this.ctx.get('cache-control'); // no-cache } } ``` ### Cookie[​](#cookie "Cookie的直接链接") HTTP 请求都是无状态的,但是我们的 Web 应用通常都需要知道发起请求的人是谁。为了解决这个问题,HTTP 协议设计了一个特殊的请求头:[Cookie](https://en.wikipedia.org/wiki/HTTP_cookie)。服务端可以通过响应头(set-cookie)将少量数据响应给客户端,浏览器会遵循协议将数据保存,并在下次请求同一个服务的时候带上(浏览器也会遵循协议,只在访问符合 Cookie 指定规则的网站时带上对应的 Cookie 来保证安全性)。 通过 `ctx.cookies`,我们可以在 Controller 中便捷、安全的设置和读取 Cookie。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // set cookie this.ctx.cookies.set('foo', 'bar', { encrypt: true }); // get cookie this.ctx.cookies.get('foo', { encrypt: true }); } } ``` Cookie 虽然在 HTTP 中只是一个头,但是通过 `foo=bar;foo1=bar1;` 的格式可以设置多个键值对。 Cookie 在 Web 应用中经常承担了传递客户端身份信息的作用,因此有许多安全相关的配置,不可忽视,[Cookie](/docs/cookie_session.md#%E9%BB%98%E8%AE%A4%E7%9A%84-cookies) 文档中详细介绍了 Cookie 的用法和安全相关的配置项,可以深入阅读了解。 ### Session[​](#session "Session的直接链接") 通过 Cookie,我们可以给每一个用户设置一个 Session,用来存储用户身份相关的信息,这份信息会加密后存储在 Cookie 中,实现跨请求的用户身份保持。 框架内置了 [Session](https://github.com/midwayjs/midway/tree/main/packages/session) 插件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 Session 上的内容 const userId = this.ctx.session.userId; const posts = await this.ctx.service.post.fetch(userId); // 修改 Session 的值 this.ctx.session.visited = ctx.session.visited ? (ctx.session.visited + 1) : 1; // ... } } ``` Session 的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为 `null`: ``` ctx.session = null; ``` 和 Cookie 一样,Session 也有许多安全等选项和功能,在使用之前也最好阅读 [Session](/docs/cookie_session.md#%E9%BB%98%E8%AE%A4%E7%9A%84-session) 文档深入了解。 ### 上传的文件[​](#上传的文件 "上传的文件的直接链接") 上传的文件一般使用 `multipart/form-data` 协议头,由 `@Files` 装饰器获取,由于上传功能由 upload 组件提供,具体可以参考 [upload 组件](/docs/extensions/upload.md)。 ### 其他的参数[​](#其他的参数 "其他的参数的直接链接") 还有一些比较常见的参数装饰器,以及它们的对应方法。 | 装饰器 | Express 对应的方法 | Koa/EggJS 对应的方法 | | ------------ | ------------------ | -------------------- | | @RequestPath | req.baseurl | ctx.path | | @RequestIP | req.ip | ctx.ip | **示例:获取 body 、path 和 ip** ``` @Post('/') async updateUser( @Body('id') id: string, @RequestPath() p: string, @RequestIP() ip: string): Promise { } ``` ### 自定义请求参数装饰器[​](#自定义请求参数装饰器 "自定义请求参数装饰器的直接链接") 你可以快速通过`createRequestParamDecorator` 创建自定义请求参数装饰器。 ``` import { createRequestParamDecorator } from '@midwayjs/core'; // 实现装饰器 export const Token = () => { return createRequestParamDecorator(ctx => { return ctx.headers.token; }); }; // 使用装饰器 export class UserController { async invoke(@Token() token: string) { console.log(token); } } ``` ## 请求参数类型转换[​](#请求参数类型转换 "请求参数类型转换的直接链接") 如果是简单类型,Midway 会自动将参数转换为用户声明的类型。 比如: 数字类型 ``` @Get('/') async getUser(@Query('id') id: number): Promise { console.log(typeof id) // number } ``` 布尔类型 * 当值为 0,"0", "false" 则转为 false,其余返回 Boolean(value) 的值 ``` @Get('/') async getUser(@Query('id') id: boolean): Promise { console.log(typeof id) // boolean } ``` 其他类型框架不会处理,如需转换请引入 [validation 组件](/docs/extensions/validation.md)。 ## 参数校验[​](#参数校验 "参数校验的直接链接") 参数校验功能由 [validation 组件](/docs/extensions/validation.md) 提供。 ## 设置 HTTP 响应[​](#设置-http-响应 "设置 HTTP 响应的直接链接") ### 设置返回值[​](#设置返回值 "设置返回值的直接链接") 绝大多数的数据都是通过 body 发送给请求方的,和请求中的 body 一样,在响应中发送的 body,也需要有配套的 Content-Type 告知客户端如何对数据进行解析。 * 作为一个 RESTful 的 API 接口 controller,我们通常会返回 Content-Type 为 `application/json` 格式的 body,内容是一个 JSON 字符串。 * 作为一个 html 页面的 controller,我们通常会返回 Content-Type 为 `text/html` 格式的 body,内容是 html 代码段。 在 Midway 中你可以简单的使用 `return` 来返回数据。 ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 返回字符串 return "Hello Midwayjs!"; // 返回 json return { a: 1, b: 2, }; // 返回 html return '

Hello

'; // 返回 stream return fs.createReadStream('./good.png'); } } ``` 也可以使用 koa 原生的 API。 ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') async home() { // 返回字符串 this.ctx.body = "Hello Midwayjs!"; // 返回 json this.ctx.body = { a: 1, b: 2, }; // 返回 html this.ctx.body = '

Hello

'; // 返回 stream this.ctx.body = fs.createReadStream('./good.png'); } } ``` 警告 注意:`ctx.body` 是 `ctx.response.body` 的简写,不要和 `ctx.request.body` 混淆了。 ### 设置状态码[​](#设置状态码 "设置状态码的直接链接") 默认情况下,响应的**状态码**总是**200**,我们可以通过在处理程序层添加 `@HttpCode` 装饰器或者通过 API 来轻松更改此行为。 当发送错误时,如 `4xx/5xx`,可以使用 [异常处理](/docs/error_filter.md) 抛出错误的方式实现。 **示例:使用装饰器** ``` import { Controller, Get, HttpCode } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @HttpCode(201) async home() { return "Hello Midwayjs!"; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.status = 201; // ... } } ``` 信息 状态码不能在响应流关闭后(response.end之后)修改。 ### 设置响应头[​](#设置响应头 "设置响应头的直接链接") Midway 提供 `@SetHeader` 装饰器或者通过 API 来简单的设置自定义响应头。 **示例:使用装饰器** ``` import { Controller, Get, SetHeader } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @SetHeader('x-bbb', '123') async home() { return "Hello Midwayjs!"; } } ``` 当有多个响应头需要修改的时候,你可以直接传入对象。 ``` import { Controller, Get, SetHeader } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @SetHeader({ 'x-bbb': '123', 'x-ccc': '234' }) async home() { return "Hello Midwayjs!"; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.set('x-bbb', '123'); // ... } } ``` 信息 响应头不能在响应流关闭后(response.end之后)修改。 ### 重定向[​](#重定向 "重定向的直接链接") 如果需要简单的将某个路由重定向到另一个路由,可以使用 `@Redirect` 装饰器。 `@Redirect` 装饰器的参数为一个跳转的 URL,以及一个可选的状态码,默认跳转的状态码为 `302` 。 此外,也可以通过 API 来跳转。 **示例:使用装饰器** ``` import { Controller, Get, Redirect } from '@midwayjs/core'; @Controller('/') export class LoginController { @Get('/login_check') async check() { // TODO } @Get('/login') @Redirect('/login_check') async login() { // TODO } @Get('/login_another') @Redirect('/login_check', 302) async loginAnother() { // TODO } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.redirect('/login_check'); // ... } } ``` 信息 重定向不能在响应流关闭后(response.end之后)修改。 ### 响应类型[​](#响应类型 "响应类型的直接链接") 虽然浏览器会自动根据内容判断最佳的响应内容,但是我们经常会碰到需要手动设置的情况。我们也提供了 `@ContentType` 装饰器用于设置响应类型。 此外,也可以通过 API 来设置。 **示例:使用装饰器** ``` import { Controller, Get, ContentType } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/') @ContentType('html') async login() { return 'hello world'; } } ``` **示例:使用 API** ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.type = 'html'; // ... } } ``` 信息 响应类型不能在响应流关闭后(response.end之后)修改。 ### 流式响应[​](#流式响应 "流式响应的直接链接") 如果希望以流式返回数据,可以使用 Node.js 原始的 response 对象上的 `write` 和 `end` 方法。 ``` import { Controller, Get, Inject, sleep } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.status = 200; this.ctx.set('Transfer-Encoding', 'chunked'); for (let i = 0; i < 100; i++) { await sleep(100); this.ctx.res.write('abc'.repeat(100)); } this.ctx.res.end(); } } ``` ### 高级响应处理[​](#高级响应处理 "高级响应处理的直接链接") 从 v3.17.0 开始,框架提供了一个新的的 `HttpServerResponse` 来处理返回数据,除了普通的数据之外,还提供了自定义状态模版,文件下载,SSE 等能力支持,具体请查看 [数据响应章节](/docs/data_response.md) ## 内部重定向[​](#内部重定向 "内部重定向的直接链接") 从 v3.12.0 开始,框架提供了一个内部重定向 API `ctx.forward(url)`,仅支持 koa/egg 类型。 和外部重定向不同的地方在于,内部重定向不会修改浏览器的 URL,只在程序内部流转。 ``` import { Controller, Get, Inject } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { return this.ctx.forward('/api'); } @Get('/api') async api() { return 'abc'; } } ``` 注意,内部重定向有一些规则: * 1、重定向会保留原始路由的所有参数,即透传整个 ctx * 2、重定向只能在相同的 http method 中进行 * 3、重定向不会再执行一遍 Web Middleware,不会执行守卫,但是会执行拦截器和参数装饰器 ## 全局路由前缀[​](#全局路由前缀 "全局路由前缀的直接链接") 需要在 `src/config/config.default` 配置中设置。 注意,不同组件在不同的关键字配置下: * koa * Egg.js * Express ``` // src/config/config.default.ts export default { koa: { globalPrefix: '/v1' } }; ``` ``` // src/config/config.default.ts export default { egg: { globalPrefix: '/v1' } }; ``` ``` // src/config/config.default.ts export default { express: { globalPrefix: '/v1' } }; ``` 配置后,所有的路由都会自动增加该前缀。 如有特殊路由不需要,可以使用装饰器参数忽略。 **示例:Controller 级别忽略** ``` // 该 Controller 下所有路由都将忽略全局前缀 @Controller('/api', {ignoreGlobalPrefix: true}) export class HomeController { // ... } ``` **示例:路由级别忽略** ``` @Controller('/') export class HomeController { // 该路由不会忽略 @Get('/', {}) async homeSet() { } // 该路由会忽略全局前缀 @Get('/bbc', {ignoreGlobalPrefix: true}) async homeSet2() { } } ``` ## 路由优先级[​](#路由优先级 "路由优先级的直接链接") midway 已经统一对路由做排序,通配的路径将自动降低优先级,在最后被加载。 规则如下: * 1、绝对路径规则优先级最高如 `/ab/cb/e` * 2、星号只能出现最后且必须在/后面,`如 /ab/cb/**` * 3、如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高,比如 `/abc/*` 和 `/abc/d`,那么请求 `/abc/d` 时,会匹配到后一个绝对的路由 * 4、有多个通配能匹配一个路径时,最长的规则匹配,如 `/ab/**` 和 `/ab/cd/**` 在匹配 `/ab/cd/f` 时命中 `/ab/cd/**` * 5、如果 `/` 与 `/*` 都能匹配 `/` ,但 `/` 的优先级高于 `/*` * 6、如果都为通配,但是其余权重都一样,比如 `/:page/page` 和 `/page/:page` ,那么两者权重等价,以编码加载顺序为准 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如: ``` @Controller('/api') export class APIController { @Get('/invoke/*') async invokeAll() { } @Get('/invoke/abc') async invokeABC() { } } ``` 这种情况下,会先注册 `/invoke/abc` ,保证优先级更高。 不同的 Controller 的优先级,我们会以长度进行排序, `/` 根 Controller 我们将会最后加载。 --- # Cookies 和 Session HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。 Cookie 主要用于以下三个方面: * 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息) * 个性化设置(如用户自定义设置、主题等) * 浏览器行为跟踪(如跟踪分析用户行为等) Cookie 在 Web 应用中经常承担标识请求方身份的功能,所以 Web 应用在 Cookie 的基础上封装了 Session 的概念,专门用做用户身份识别。 ## 适用范围[​](#适用范围 "适用范围的直接链接") * `@midwayjs/web` 下(即 egg)内置的是 egg 自带的 Cookie,未提供替换能力,不适用本文档 * `@midwayjs/express` 下(即 express)内置的是 express 自带的 Cookie 库,未提供替换能力,不适用本文档 ## 默认的 Cookies[​](#默认的-cookies "默认的 Cookies的直接链接") Midway 提供了 `@midwayjs/cookies` 模块来操作 Cookie。 同时在 `@midwayjs/koa` 中,默认提供了从上下文直接读取、写入 cookie 的方法 * `ctx.cookies.get(name, [options])` 读取上下文请求中的 cookie * `ctx.cookies.set(name, value, [options])` 在上下文中写入 cookie 示例如下: ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // set cookie this.ctx.cookies.set('foo', 'bar', { encrypt: true }); // get cookie this.ctx.cookies.get('foo', { encrypt: true }); } } ``` ## 设置 Cookie[​](#设置-cookie "设置 Cookie的直接链接") 使用 `ctx.cookies.set(key, value, options)` API 来设置 Cookie。 设置 Cookie 其实是通过在 HTTP 响应中设置 set-cookie 头完成的,每一个 set-cookie 都会让浏览器在 Cookie 中存一个键值对。在设置 Cookie 值的同时,协议还支持许多参数来配置这个 Cookie 的传输、存储和权限。 这些选项包括: | 选项 | 类型 | 描述 | 支持版本 | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | | path | String | 设置键值对生效的 URL 路径,默认设置在根路径上(`/`),也就是当前域名下的所有 URL 都可以访问这个 Cookie。 | | | domain | String | 设置键值对生效的域名,默认没有配置,可以配置成只在指定域名才能访问。 | | | expires | Date | 设置这个键值对的失效时间,如果设置了 maxAge,expires 将会被覆盖。如果 maxAge 和 expires 都没设置,Cookie 将会在浏览器的会话失效(一般是关闭浏览器时)的时候失效。 | | | maxAge | Number | 设置这个键值对在浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。如果设置了 maxAge,expires 将会被覆盖。 | | | secure | Boolean | 设置键值对 [只在 HTTPS 连接上传输](http://stackoverflow.com/questions/13729749/how-does-cookie-secure-flag-work),框架会帮我们判断当前是否在 HTTPS 连接上自动设置 secure 的值。 | | | httpOnly | Boolean | 设置键值对是否可以被 js 访问,默认为 true,不允许被 js 访问 | | | partitioned | Boolean | 设置独立分区状态([CHIPS](https://developers.google.com/privacy-sandbox/3pcd/chips))的 Cookie。注意,只有 `secure` 为 true 且 Chrome >=114 版本此配置才会生效 | @midwayjs/cookies >= 1.1.0 | | removeUnpartitioned | Boolean | 是否删除非独立分区状态的同名 cookie。注意,只有 `partitioned` 为 true 的时候此配置才会生效 | @midwayjs/cookies >= 1.2.0 | | priority | String | 设置 Cookie 的 [优先级](https://developer.chrome.com/blog/new-in-devtools-81?hl=zh-cn#cookiepriority),可选值为 `Low`、`Medium`、`High`,仅对 Chrome >= 81 版本有效 | @midwayjs/cookies >= 1.1.0 | 除了这些属性之外,框架另外扩展了 3 个参数: | 选项 | 类型 | 描述 | | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | overwrite | Boolean | 设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头。 | | signed | Boolean | 设置是否对 Cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true。 | | encrypt | Boolean | 设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false。 | 在设置 Cookie 时,我们需要考虑这个 Cookie 是否需要被前端获取,失效时间多久等等。 示例: ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { this.ctx.cookies.set('cid', 'hello world', { domain: 'localhost', // 写cookie所在的域名 path: '/index', // 写cookie所在的路径 maxAge: 10 * 60 * 1000, // cookie有效时长 expires: new Date('2017-02-15'), // cookie失效时间 httpOnly: false, // 是否只用于http请求中获取 overwrite: false, // 是否允许重写 }); ctx.body = 'cookie is ok'; } } ``` **默认的配置下,Cookie 是加签不加密的,浏览器可以看到明文,js 不能访问,不能被客户端(手工)篡改。** 如果想要 Cookie 在浏览器端可以被 js 访问并修改: ``` ctx.cookies.set(key, value, { httpOnly: false, signed: false, }); ``` 如果想要 Cookie 在浏览器端不能被修改,不能看到明文: ``` ctx.cookies.set(key, value, { httpOnly: true, // 默认就是 true encrypt: true, // 加密传输 }); ``` ## 获取 Cookie[​](#获取-cookie "获取 Cookie的直接链接") 使用 `ctx.cookies.get(key, options)` API 来获取 Cookie。 由于 HTTP 请求中的 Cookie 是在一个 header 中传输过来的,通过框架提供的这个方法可以快速的从整段 Cookie 中获取对应的键值对的值。上面在设置 Cookie 的时候,我们可以设置 `options.signed` 和 `options.encrypt` 来对 Cookie 进行签名或加密,因此对应的在获取 Cookie 的时候也要传相匹配的选项。 * 如果设置的时候指定为 signed,获取时未指定,则不会在获取时对取到的值做验签,导致可能被客户端篡改。 * 如果设置的时候指定为 encrypt,获取时未指定,则无法获取到真实的值,而是加密过后的密文。 如果要获取前端或者其他系统设置的 Cookie,需要指定参数 `signed` 为 `false`,避免对它做验签导致获取不到 Cookie 的值。 ``` ctx.cookies.get('frontend-cookie', { signed: false, }); ``` ## Cookie 秘钥[​](#cookie-秘钥 "Cookie 秘钥的直接链接") 由于我们在 Cookie 中需要用到加解密和验签,所以需要配置一个秘钥供加密使用。 默认脚手架会在配置文件 `src/config/config.default.ts` 中自动生成一个秘钥,也可以自己修改。 ``` // src/config/config.default export default { keys: ['key1','key2'], } ``` keys 默认是一个字符串,可以分隔配置多个 key。Cookie 在使用这个配置进行加解密时: * 加密和加签时只会使用第一个秘钥。 * 解密和验签时会遍历 keys 进行解密。 如果我们想要更新 Cookie 的秘钥,但是又不希望之前设置到用户浏览器上的 Cookie 失效,可以将新的秘钥配置到 keys 最前面,等过一段时间之后再删去不需要的秘钥即可。 ## 默认的 Session[​](#默认的-session "默认的 Session的直接链接") 默认的 `@midwayjs/koa` ,内置了 Session 组件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 ``` import { Inject, Controller, Get, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // 获取 Session 上的内容 const userId = this.ctx.session.userId; const posts = await this.ctx.service.post.fetch(userId); // 修改 Session 的值 this.ctx.session.visited = ctx.session.visited ? (ctx.session.visited + 1) : 1; // ... } } ``` Session 的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为 null: ``` ctx.session = null; ``` 需要 **特别注意** 的是:设置 session 属性时需要避免以下几种情况(会造成字段丢失,详见 [koa-session](https://github.com/koajs/session/blob/master/lib/session.js#L37-L47) 源码) * 不要以 `_` 开头 * 不能为 `isNew` ``` // ❌ 错误的用法 ctx.session._visited = 1; // --> 该字段会在下一次请求时丢失 ctx.session.isNew = 'HeHe'; // --> 为内部关键字, 不应该去更改 // ✔️ 正确的用法 ctx.session.visited = 1; // --> 此处没有问题 ``` Session 的实现是基于 Cookie 的,默认配置下,用户 Session 的内容加密后直接存储在 Cookie 中的一个字段中,用户每次请求我们网站的时候都会带上这个 Cookie,我们在服务端解密后使用。Session 的默认配置如下: ``` export default { session: { maxAge: 24 * 3600 * 1000, // 1天 key: 'MW_SESS', httpOnly: true, }, // ... } ``` 可以看到这些参数除了 `key` 都是 Cookie 的参数,`key` 代表了存储 Session 的 Cookie 键值对的 key 是什么。在默认的配置下,存放 Session 的 Cookie 将会加密存储、不可被前端 js 访问,这样可以保证用户的 Session 是安全的。 ## 函数下的 Session[​](#函数下的-session "函数下的 Session的直接链接") 在函数弹性容器的场景下,默认未内置 Session 模块,如果需要可以手动添加。 ``` { "dependencies": { "@midwayjs/session": "^4.0.0", // ... }, } ``` 在 configuration 中引入组件。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as faas from '@midwayjs/faas'; import * as session from '@midwayjs/session'; @Configuration({ imports: [ faas, session, // ... ] }) export class MainConfiguration { // ... } ``` ## Session 示例[​](#session-示例 "Session 示例的直接链接") ### 修改用户 Session 失效时间[​](#修改用户-session-失效时间 "修改用户 Session 失效时间的直接链接") 虽然在 Session 的配置中有一项是 maxAge,但是它只能全局设置 Session 的有效期,我们经常可以在一些网站的登陆页上看到有 **记住我** 的选项框,勾选之后可以让登陆用户的 Session 有效期更长。这种针对特定用户的 Session 有效时间设置我们可以通过 `ctx.session.maxAge=` 来实现。 ``` import { Inject, Controller, Post, Body, Provide, FORMAT } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { UserService } from './service/user.service'; @Controller('/') export class UserController { @Inject() ctx: Context; @Inject() userService: UserService; @Post('/') async login(@Body() data) { const { username, password, rememberMe } = data; const user = await this.userService.loginAndGetUser(username, password); // 设置 Session this.ctx.session.user = user; // 如果用户勾选了 `记住我`,设置 30 天的过期时间 if (rememberMe) { this.ctx.session.maxAge = FORMAT.MS.ONE_DAY * 30; } } } ``` ### 延长用户 Session 有效期[​](#延长用户-session-有效期 "延长用户 Session 有效期的直接链接") 默认情况下,当用户请求没有导致 Session 被修改时,框架都不会延长 Session 的有效期,但是在有些场景下,我们希望用户如果长时间都在访问我们的站点,则延长他们的 Session 有效期,不让用户退出登录态。框架提供了一个 `renew` 配置项用于实现此功能,它会在发现当用户 Session 的有效期仅剩下最大有效期一半的时候,重置 Session 的有效期。 ``` // src/config/config.default.ts export default { session: { renew: true, // ... }, // ... } ``` ### 调整 SameSite 配置以允许跨域访问[​](#调整-samesite-配置以允许跨域访问 "调整 SameSite 配置以允许跨域访问的直接链接") 默认情况下,框架不会设置 Session Cookie 的 SameSite 选项。从 Chrome 84 版本开始,SameSite 选项为空的 Cookie 默认将不会在跨域请求时发送,即默认按照 SameSite=Lax 处理。一般情况下,如果用户都是直接访问你的应用,这不会有问题。如果你的应用需要支持跨域访问,比如被其他应用 iframe 嵌入,或者允许配置 CORS 跨域请求,则需要调整 SameSite 选项,将其设置为更为宽松的 SameSite=None: ``` // src/config/config.default.ts export default { session: { sameSite: 'none', // 需要指定 Secure,否则 SameSite=None 无效 secure: true, // ... }, // ... } ``` 可以阅读 [SameSite Cookie 说明](https://web.dev/articles/samesite-cookies-explained?hl=zh-cn) 了解更多 SameSite 选项。 ## 自定义 Session Store[​](#自定义-session-store "自定义 Session Store的直接链接") 过多的将数据放在 Session 中并不太合理,大部分情况下,我们只需要在 Session 中存储一些 Id,来保证安全性。虽然我们觉得 Cookie 作为存储 Session 已经足够,但是在某些极端情况下,还是需要使用例如 Redis 来存储 Session 的情况。 不同的上层框架使用了不同的 Session 方案,下面列举了一些 Session 替换方案 * [@midwayjs/koa 方案](https://github.com/midwayjs/midway/tree/main/packages/session#custom-session-store) * [@midwayjs/express 方案](https://github.com/midwayjs/midway/tree/main/packages/express-session) * [@midwayjs/web(egg)方案](https://github.com/eggjs/egg-session) --- # 自定义数据响应 在大多数正常的逻辑中,返回数据只需要 `return` 相应的对象。 ``` ``` --- # 自定义装饰器 在新版本中,Midway 提供了由框架支持的自定义装饰器能力,它包括几个常用功能: * 定义可继承的属性装饰器 * 定义可包裹方法,做拦截的方法装饰器 * 定义修改参数的参数装饰器 我们考虑到了装饰器当前在标准中的阶段以及后续风险,Midway 提供的自定义装饰器方式及其配套能力由框架实现,以尽可能的规避后续规范变化带来的问题。 一般,我们推荐将自定义装饰器放到 `src/decorator` 目录中。 比如: ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── decorator ## 自定义装饰器 │ │ └── user.decorator.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` ## 装饰器 API[​](#装饰器-api "装饰器 API的直接链接") Midway 内部有一套标准的装饰器管理 API,用来将装饰器对接依赖注入容器,实现扫描和扩展,这些 API 方法我们都从 `@midwayjs/core` 包进行导出。 通过装饰器高级 API,我们可以自定义装饰器,并且将元数据附加其中,内部的各种装饰器都是通过该能力实现的。 信息 从 v4.0 版本开始,Midway 引入了两个新的静态类来管理装饰器和元数据: * `DecoratorManager` - 管理装饰器模块的注册和查询 * `MetadataManager` - 替代 reflect-metadata,提供完整的元数据管理功能 ### DecoratorManager[​](#decoratormanager "DecoratorManager的直接链接") `DecoratorManager` 是装饰器管理器,负责装饰器模块的注册、查询和自定义装饰器的创建。 **装饰器模块管理** * `DecoratorManager.saveModule` 用于保存某个类到某个装饰器 * `DecoratorManager.listModule` 获取所有绑定到某类型装饰器的 class * `DecoratorManager.resetModule` 重置指定装饰器的模块集合 * `DecoratorManager.clearAllModule` 清空所有模块 ``` import { DecoratorManager } from '@midwayjs/core'; // 示例:管理 API 接口类 const API_MODULE_KEY = 'api:modules'; // 保存 API 模块 @Controller('/user') class UserController {} DecoratorManager.saveModule(API_MODULE_KEY, UserController); // 获取所有 API 模块 const apiModules = DecoratorManager.listModule(API_MODULE_KEY); console.log(apiModules); // [UserController] // 通过过滤器查询 const userModules = DecoratorManager.listModule(API_MODULE_KEY, (module) => module.name.includes('User') ); ``` **Provider 管理工具** * `DecoratorManager.getProviderUUId` 获取 class provide 出来的 uuid,对应某个类,不会变 * `DecoratorManager.getProviderName` 获取 provide 时保存的 name,一般为类名小写 * `DecoratorManager.getProviderId` 获取 class 上 provide 出来的 id,一般为类名小写,也可能是自定义的 id * `DecoratorManager.isProvide` 判断某个类是否被 @Provide 修饰过 ``` import { DecoratorManager, Provide } from '@midwayjs/core'; @Provide('customUserService') class UserService {} // 检查是否为 Provider console.log(DecoratorManager.isProvide(UserService)); // true // 获取 Provider 信息 console.log(DecoratorManager.getProviderId(UserService)); // 'customUserService' console.log(DecoratorManager.getProviderName(UserService)); // 'userService' console.log(DecoratorManager.getProviderUUId(UserService)); // 唯一UUID字符串 // 保存自定义 Provider ID DecoratorManager.saveProviderId('myService', UserService); ``` **自定义装饰器创建工具** * `DecoratorManager.createCustomPropertyDecorator` 创建自定义属性装饰器 * `DecoratorManager.createCustomMethodDecorator` 创建自定义方法装饰器 * `DecoratorManager.createCustomParamDecorator` 创建自定义参数装饰器 ``` import { DecoratorManager } from '@midwayjs/core'; // 创建属性装饰器 const Cache = (key: string) => DecoratorManager.createCustomPropertyDecorator('cache', { key }); // 创建方法装饰器 const LogExecution = (level = 'info') => DecoratorManager.createCustomMethodDecorator('log', { level }); // 创建参数装饰器 const ValidateParam = (rules: any[]) => DecoratorManager.createCustomParamDecorator('validate', { rules }); // 使用装饰器 class UserService { @Cache('user-data') userData: any; @LogExecution('debug') async getUser(@ValidateParam(['required', 'string']) id: string) { // ... } } ``` ### MetadataManager[​](#metadatamanager "MetadataManager的直接链接") 提示 `MetadataManager` 是 v4.0 全新设计的元数据管理器,替代了 reflect-metadata,提供了更高效的缓存机制和原型链元数据继承支持。 **基础元数据操作** * `MetadataManager.defineMetadata` 定义元数据到 class 或属性(替换现有值) * `MetadataManager.attachMetadata` 附加元数据到 class 或属性(追加到数组) * `MetadataManager.getMetadata` 从 class 或属性获取元数据(支持原型链查找) * `MetadataManager.getOwnMetadata` 从 class 或属性获取自有元数据(不查找原型链) * `MetadataManager.hasMetadata` 检查 class 或属性是否存在元数据 * `MetadataManager.hasOwnMetadata` 检查 class 或属性是否存在自有元数据 * `MetadataManager.deleteMetadata` 删除 class 或属性的元数据 ``` import { MetadataManager } from '@midwayjs/core'; class UserService { name: string; email: string; } // 定义类级别元数据 MetadataManager.defineMetadata('entity', { tableName: 'users' }, UserService); // 定义属性级别元数据 MetadataManager.defineMetadata('column', { type: 'varchar', length: 100 }, UserService, 'name'); MetadataManager.defineMetadata('column', { type: 'varchar', unique: true }, UserService, 'email'); // 获取元数据 const entityMeta = MetadataManager.getMetadata('entity', UserService); console.log(entityMeta); // { tableName: 'users' } const nameMeta = MetadataManager.getMetadata('column', UserService, 'name'); console.log(nameMeta); // { type: 'varchar', length: 100 } // 检查元数据是否存在 console.log(MetadataManager.hasMetadata('entity', UserService)); // true // 附加元数据(追加到数组) MetadataManager.attachMetadata('validations', 'required', UserService, 'name'); MetadataManager.attachMetadata('validations', 'minLength:2', UserService, 'name'); const validations = MetadataManager.getMetadata('validations', UserService, 'name'); console.log(validations); // ['required', 'minLength:2'] ``` **元数据复制和批量操作** * `MetadataManager.copyMetadata` 复制元数据从源类到目标类(包含原型链) * `MetadataManager.copyOwnMetadata` 复制自有元数据从源类到目标类 * `MetadataManager.getMetadataKeys` 获取 class 或属性的所有元数据键(包含原型链) * `MetadataManager.getOwnMetadataKeys` 获取 class 或属性的自有元数据键 ``` // 元数据复制示例 class BaseEntity { id: number; createdAt: Date; } class UserEntity extends BaseEntity { name: string; } // 为基础实体设置元数据 MetadataManager.defineMetadata('table', { name: 'base_entities' }, BaseEntity); MetadataManager.defineMetadata('column', { primary: true }, BaseEntity, 'id'); // 复制元数据到新的类 class ProductEntity {} MetadataManager.copyMetadata(BaseEntity, ProductEntity); // 检查复制结果 console.log(MetadataManager.getMetadata('table', ProductEntity)); // { name: 'base_entities' } // 获取所有元数据键 const keys = MetadataManager.getMetadataKeys(UserEntity); console.log(keys); // 包含从 BaseEntity 继承的键 // 过滤复制特定元数据 MetadataManager.copyMetadata(BaseEntity, ProductEntity, { metadataFilter: (key) => key === 'column', // 只复制 column 元数据 overwrite: false // 不覆盖已存在的元数据 }); ``` **属性元数据查询** * `MetadataManager.getPropertiesWithMetadata` 获取包含指定元数据的所有属性(支持原型链) * `MetadataManager.getOwnPropertiesWithMetadata` 获取包含指定元数据的自有属性 ``` class UserModel { @Column({ type: 'varchar' }) name: string; @Column({ type: 'int' }) age: number; password: string; // 无装饰器 } // 假设 @Column 装饰器使用了 'column' 作为元数据键 // 获取所有包含列元数据的属性 const columnsWithMeta = MetadataManager.getPropertiesWithMetadata('column', UserModel); console.log(columnsWithMeta); // { // name: { type: 'varchar' }, // age: { type: 'int' } // } // 只获取自身定义的属性(不包括继承的) const ownColumns = MetadataManager.getOwnPropertiesWithMetadata('column', UserModel); ``` **类型反射工具** * `MetadataManager.getMethodParamTypes` 获取某个方法的参数类型 * `MetadataManager.getPropertyType` 获取某个属性的类型 * `MetadataManager.getMethodReturnTypes` 获取方法返回值类型 * `MetadataManager.transformTypeFromTSDesign` 将 TypeScript 设计时类型转换为标准类型描述 ``` class ApiService { userId: string; async getUserById(id: string, options?: any): Promise { // ... } } // 获取方法参数类型 const paramTypes = MetadataManager.getMethodParamTypes(ApiService, 'getUserById'); console.log(paramTypes); // [String, Object] // 获取方法返回类型 const returnType = MetadataManager.getMethodReturnTypes(ApiService, 'getUserById'); console.log(returnType); // Promise // 获取属性类型 const propertyType = MetadataManager.getPropertyType(ApiService, 'userId'); console.log(propertyType); // String // 转换类型描述 const typeDesc = MetadataManager.transformTypeFromTSDesign(String); console.log(typeDesc); // { name: 'string', isBaseType: true, originDesign: String } ``` ## 类装饰器[​](#类装饰器 "类装饰器的直接链接") 一般类装饰器都会和其他装饰器配合使用,用来标注某个类属于特定的一种场景,比如 `@Controller` 表示了类属于 Http 场景的入口。 我们举一个例子,定义一个类装饰器 @Model ,标识 class 是一个模型类,然后进一步操作。 首先创建一个装饰器文件,比如 `src/decorator/model.decorator.ts` 。 ``` import { Scope, ScopeEnum, MetadataManager, DecoratorManager, Provide } from '@midwayjs/core'; // 提供一个唯一 key export const MODEL_KEY = 'decorator:model'; export function Model(): ClassDecorator { return (target: any) => { // 将装饰的类,绑定到该装饰器,用于后续能获取到 class DecoratorManager.saveModule(MODEL_KEY, target); // 保存一些元数据信息,任意你希望存的东西 MetadataManager.defineMetadata( MODEL_KEY, { test: 'abc', }, target ); // 指定 IoC 容器创建实例的作用域,这里注册为请求作用域,这样能取到 ctx Scope(ScopeEnum.Request)(target); // 调用一下 Provide 装饰器,这样用户的 class 可以省略写 @Provide() 装饰器了 Provide()(target); }; } ``` 上面只是定义了这个装饰器,我们还要实现相应的功能,midway v2 开始有生命周期的概念,可以在 `configuration` 中的生命周期中执行。 ``` // src/configuration.ts import { DecoratorManager, Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { MODEL_KEY } from './decorator/model.decorator'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... // 可以获取到所有装饰了 @Model() 装饰器的 class const modules = DecoratorManager.listModule(MODEL_KEY); for (let mod of modules) { // 实现自定义能力 // 比如,拿元数据 MetadataManager.getMetadata(MODEL_KEY, mod) // 比如,提前初始化 app.applicationContext.getAsync(mod); } } } ``` 最后,我们要使用这个装饰器。 ``` import { Model } from '../decorator/model.decorator'; // Model 的作用是我们自己的逻辑能被执行(保存的元数据) @Model() export class UserModel { // ... } ``` ## 属性装饰器[​](#属性装饰器 "属性装饰器的直接链接") Midway 提供了 `DecoratorManager.createCustomPropertyDecorator` 方法,用于创建自定义属性装饰器,框架的 `@Logger` ,`@Config` 等装饰器都是这样创建而来的。 和 TypeScript 中定义的装饰器不同的是,Midway 提供的属性装饰器,可以在继承中使用。 我们举个例子,假如现在有一个内存缓存,我们的属性装饰器用于获取缓存数据,下面是一些准备工作。 ``` // 简单的缓存类 import { Configuration, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryStore extends Map { save(key, value) { this.set(key, value); } get(key) { return this.get(key); } } // src/configuration.ts // 入口实例化,并保存一些数据 import { Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() store: MemoryStore; async onReady() { // ... // 初始化一些数据 store.save('aaa', 1); store.save('bbb', 1); } } ``` 我们来实现一个简单的 `@MemoryCache()` 装饰器。属性装饰器的实现分为两部分: * 1、定义一个装饰器方法,一般只保存元数据 * 2、定义一个实现,在装饰器逻辑执行前即可 下面是定义装饰器方法的部分。 ``` // src/decorator/memoryCache.decorator.ts import { DecoratorManager } from '@midwayjs/core'; // 装饰器内部的唯一 id export const MEMORY_CACHE_KEY = 'decorator:memory_cache_key'; export function MemoryCache(key?: string): PropertyDecorator { return DecoratorManager.createCustomPropertyDecorator(MEMORY_CACHE_KEY, { key, }); } ``` 在装饰器的方法执行之前(一般在初始化的地方)去实现。实现装饰器,我们需要用到内置的 `MidwayDecoratorService` 服务。 ``` import { Configuration, Inject, Init, MidwayDecoratorService } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { MEMORY_CACHE_KEY, MemoryStore } from 'decorator/memoryCache.decorator'; @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() store: MemoryStore; @Inject() decoratorService: MidwayDecoratorService; @Init() async init() { // ... // 实现装饰器 this.decoratorService.registerPropertyHandler(MEMORY_CACHE_KEY, (propertyName, meta) => { return this.store.get(meta.key); }); } } ``` `registerPropertyHandler` 方法包含两个参数,第一个是之前装饰器定义的唯一 id,第二个是装饰器实现的回调方法。 `propertyName` 是装饰器装饰的方法名,meta 是装饰器的使用时的参数。 然后我们就能使用这个装饰器了。 ``` import { MemoryCache } from 'decorator/memoryCache.decorator'; // ... export class UserService { @MemoryCache('aaa') cacheValue; async invoke() { console.log(this.cacheValue); // => 1 } } ``` ## 方法装饰器[​](#方法装饰器 "方法装饰器的直接链接") Midway 提供了 `DecoratorManager.createCustomMethodDecorator` 方法,用于创建自定义方法装饰器。 和 TypeScript 中定义的装饰器不同的是,Midway 提供的方法装饰器,由拦截器统一实现,和其他拦截方式不冲突,并且更加简单。 我们以打印方法执行时间为例。 和属性装饰器相同,我们的定义与实现是分离的。 下面是定义装饰器方法的部分。 ``` // src/decorator/logging.decorator.ts import { DecoratorManager } from '@midwayjs/core'; // 装饰器内部的唯一 id export const LOGGING_KEY = 'decorator:logging_key'; export function LoggingTime(formatUnit = 'ms'): MethodDecorator { // 我们传递了一个可以修改展示格式的参数 return DecoratorManager.createCustomMethodDecorator(LOGGING_KEY, { formatUnit }); } ``` 实现的部分,同样需要使用框架内置的 `DecoratorService` 服务。 ``` //... function formatDuring(value, formatUnit: string) { // 这里返回时间格式化 if (formatUnit === 'ms') { return `${value} ms`; } else if (formatUnit === 'min') { // return xxx } } @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现方法装饰器 this.decoratorService.registerMethodHandler(LOGGING_KEY, (options) => { return { around: async (joinPoint: JoinPoint) => { // 拿到格式化参数 const format = options.metadata.formatUnit || 'ms'; // 记录开始时间 const startTime = Date.now(); // 执行原方法 const result = await joinPoint.proceed(...joinPoint.args); const during = formatDuring(Date.now() - startTime, format); // 打印执行时间 this.logger.info(`Method ${joinPoint.methodName} invoke during ${during}`); // 返回执行结果 return result; }, }; }); } } ``` `registerMethodHandler` 方法的第一个参数是装饰器定义的 id,第二个参数是回调的实现,参数为 options 对象,包含: | 参数 | 类型 | 描述 | | -------------------- | ------------- | ---------------------- | | options.target | new (...args) | 装饰器修饰所在的类 | | options.propertyName | string | 装饰器修饰所在的方法名 | | options.metadata | | 装饰器本身的参数 | 回调的实现,需要返回一个由拦截器处理的方法,key 为拦截器的 `before`,`around`,`afterReturn`,`afterThrow`,`after` 这几个可拦截的生命周期。 由于方法装饰器本身是拦截器实现的,所以具体的拦截方法可以查看 [拦截器](/docs/aspect.md) 部分。 使用装饰器如下: ``` // ... export class UserService { @LoggingTime() async getUser() { // ... } } // 执行时 // output => Method "getUser" invoke during 4ms ``` 警告 注意,被装饰的方法必须为 async 方法。 ## 无需实现的方法装饰器[​](#无需实现的方法装饰器 "无需实现的方法装饰器的直接链接") 默认情况下,自定义的方法装饰器必须有一个实现,否则运行期会报错。 在某些特殊情况,希望有一个无需实现的装饰器,比如只需要存储元数据而不做拦截。 可以在定义装饰器的时候,增加一个 impl 参数。 ``` // src/decorator/logging.decorator.ts import { DecoratorManager } from '@midwayjs/core'; // 装饰器内部的唯一 id export const LOGGING_KEY = 'decorator:logging_key'; export function LoggingTime(): MethodDecorator { // 最后一个参数告诉框架,无需指定实现 return DecoratorManager.createCustomMethodDecorator(LOGGING_KEY, {}, false); } ``` ## 参数装饰器[​](#参数装饰器 "参数装饰器的直接链接") Midway 提供了 `DecoratorManager.createCustomParamDecorator` 方法,用于创建自定义参数装饰器。 参数装饰器,一般用于修改参数值,提前预处理数据等,Midway 的 `@Query` 等请求系列的装饰器都基于其实现。 和其他装饰器相同,我们的定义与实现是分离的,我们以获取参数中的用户(ctx.user)来举例。 下面是定义装饰器方法的部分。 ``` // src/decorator/logging.decorator.ts import { DecoratorManager } from '@midwayjs/core'; // 装饰器内部的唯一 id export const USER_KEY = 'decorator:user_key'; export function User(): ParameterDecorator { return DecoratorManager.createCustomParamDecorator(USER_KEY, {}); } ``` 实现的部分,同样需要使用框架内置的 `DecoratorService` 服务。 ``` //... @Configuration({ imports: [koa], }) export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现参数装饰器 this.decoratorService.registerParameterHandler(USER_KEY, (options) => { // originArgs 是原始的方法入参 // 这里第一个参数是 ctx,所以取 ctx.user return options.originArgs[0]?.user ?? {}; }); } } ``` `registerParameterHandler` 方法的第一个参数是装饰器定义的 id,第二个参数是回调的实现,参数为 options 对象,包含: | 参数 | 类型 | 描述 | | ----------------------- | ------------- | ---------------------- | | options.target | new (...args) | 装饰器修饰所在的类 | | options.propertyName | string | 装饰器修饰所在的方法名 | | options.metadata | \| undefined | 装饰器本身的参数 | | options.originArgs | Array | 方法原始的参数 | | options.originParamType | | 方法原始的参数类型 | | options.parameterIndex | number | 装饰器修饰的参数索引 | 使用装饰器如下: ``` // ... export class UserController { @Inject() userService: UserService; @Inject() ctx: Context; async getUser() { return await this.getUser(ctx); } } export class UserService { async getUser(@User() user: string) { console.log(user); // => xxx } } ``` 提示 注意,为了方法调用的正确性,如果参数装饰器中报错,框架会使用原始的参数来调用方法,不会直接抛出异常。 你可以在开启 `NODE_DEBUG=midway:debug` 环境变量时找到这个错误。 警告 注意,被装饰的方法必须为 async 方法。 ## 方法装饰器获取上下文[​](#方法装饰器获取上下文 "方法装饰器获取上下文的直接链接") 在请求链路上,如果自定义了装饰器要获取上下文往往比较困难,如果代码没有显式的注入上下文,装饰器中获取会非常困难。 在 Midway 的依赖注入的请求作用域中,我们将上下文绑定到了每个实例上,从实例的特定属性 `REQUEST_OBJ_CTX_KEY` 上即可获取当前的上下文,从而进一步对请求做操作。 比如在我们自定义实现的方法装饰器中: ``` import { REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; //... export class MainConfiguration { @App() app: koa.Application; @Inject() decoratorService: MidwayDecoratorService; @Logger() logger; async onReady() { // ... // 实现方法装饰器 this.decoratorService.registerMethodHandler(LOGGING_KEY, (options) => { return { around: async (joinPoint: JoinPoint) => { // 装饰器所在的实例 const instance = joinPoint.target; const ctx = instance[REQUEST_OBJ_CTX_KEY]; // ctx.xxxx // ... }, }; }); } } ``` --- # 自定义错误 在 Node.js 中,每个异常都是内置的 Error 类型的实例。 通过扩展标准 Error,Midway 提供了内置的错误类型,额外增加了一些属性。 ``` export class MidwayError extends Error { // ... } ``` 现阶段,所有 Midway 框架提供的错误,都是该错误类抛出的实例。 MidwayError 包括几个属性: * name 错误的名字,比如 Error,TypeError 等,在自定义错误中,为自定义错误的类名 * message 错误的消息 * stack 错误的堆栈 * code 自定义错误码 * cause 错误的来源 我们可以通过简单的实例化并且抛出来使用,比如: ``` import { MidwayError } from '@midwayjs/core'; // ... async findAll() { throw new MidwayError('my custom error'); } ``` 也可以在业务中自定义一些错误。 常见的,我们会把异常统一定义到 error 目录中。 ``` ➜ my_midway_app tree . ├── src │ └── error │ ├── customA.error.ts │ └── customB.error.ts ├── test ├── package.json └── tsconfig.json ``` 如果业务有一些复用的异常,比如固定的错误 ``` // src/error/custom.error.ts import { MidwayError } from '@midwayjs/core'; export class CustomError extends MidwayError { constructor() { super('my custom error', 'CUSTOM_ERROR_CODE_10000'); } } ``` 然后在业务中抛出使用。 ``` import { CustomError } from './error/custom.error'; // ... async findAll() { throw new CustomError(); } ``` 上面的 `CUSTOM_ERROR_CODE_10000` 为错误的错误码,一般我们会为不同的错误分配不同的错误码和错误消息,以方便排查问题。 ## 自定义错误码[​](#自定义错误码 "自定义错误码的直接链接") 框架提供了一种通用的注册错误码的机制,错误码后期可以方便的排错,统计。 在业务的错误定义,以及组件错误定义的时候非常有用。 错误码一般是个枚举值,比如: ``` const CustomErrorEnum = { UNKNOWN: 10000, COMMON: 10001, PARAM_TYPE: 10002, // ... }; ``` 在编码中,我们会提供固定的错误码,并且希望在 SDK 或者组件中不冲突,这就需要框架来支持。 Midway 提供了 `registerErrorCode` 方法,用于向框架注册不重复的错误码,并且进行一定的格式化。 比如,在框架内部,我们有如下的定义: ``` import { registerErrorCode } from '@midwayjs/core'; export const FrameworkErrorEnum = registerErrorCode('midway', { UNKNOWN: 10000, COMMON: 10001, PARAM_TYPE: 10002, // ... } as const); ``` `registerErrorCode` 包含两个参数: * 错误分组,比如上面的 `midway` ,就是框架内置错误组名,在一个应用中,这个组名不应该重复 * 错误枚举对象,以错误名为 key,错误码为 value 方法会返回一个错误枚举值,枚举值会以错误名作为 key,错误分组加错误码作为 value。 比如: ``` FrameworkErrorEnum.UNKNOWN // => output: MIDWAY_10000 FrameworkErrorEnum.COMMON // => output: MIDWAY_10001 ``` 这样,当错误中出现 `MIDWAY_10000` 的错误码时,我们就知道是什么错误了,配合文档就可以沉淀所有的错误。 在错误定义时,直接使用这个错误码枚举即可。 ``` export class MidwayParameterError extends MidwayError { constructor(message?: string) { super(message ?? 'Parameter type not match', FrameworkErrorEnum.PARAM_TYPE); } } // user code async findAll(data) { if (!data.user) { throw new MidwayParameterError(); } // ... } // output // 2022-01-02 14:02:29,124 ERROR 14259 MidwayParameterError: Parameter type not match // at APIController.findAll (.... // at /Users/harry/project/midway-v3/packages/core/src/common/webGenerator.ts:38:57 // at processTicksAndRejections (node:internal/process/task_queues:96:5) { // code: 'MIDWAY_10002', // cause: undefined, // } ``` --- # 数据订阅 在某些场景下,我们希望订阅某个数据,并且在一段时间后更新它,这种类似订阅的方式,我们称之为 ”数据订阅“,常见的远程数据获取等,都可以应用这个模式。 Midway 提供了 `DataListener` 的抽象,用于方便的创建这种模式的代码。 ## 实现数据订阅[​](#实现数据订阅 "实现数据订阅的直接链接") 我们以一个简单的 **内存数据更新** 的需求为例。 数据订阅在 midway 中也是一个普通的类,比如我们也可以把他放到 `src/listener/memory.listner.ts` 中。 我们只需要继承内置的 `DataListener` 类,同时,一般数据订阅类为单例。 `DataListener` 包含一个泛型类型,需要声明该数据订阅返回的数据类型。 比如: ``` // src/listener/memory.listner.ts import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { DataListener } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryDataListener extends DataListener { // 初始化数据 initData() { return 'hello' + Date.now(); } // 更新数据 onData(setData) { setInterval(() => { setData('hello' + Date.now()); }, 1000); } } ``` `DataListener` 类有两个必须实现的方法: * `initData` 数据的初始化方法 * `onData` 数据订阅更新的方法 示例中,我们初始化了数据,同时实现了数据更新的方法,每隔 1 秒钟,我们会使用 `setData` 来更新内置的数据。 此外,大部分的数据订阅会使用到定时器,或者其他外部的 sdk,我们需要考虑好关闭和清理资源的情况。 代码中提供了 `destroyListener` 方法来处理。 比如上面的示例代码,我们需要关闭定时器。 ``` // src/listener/memory.listner.ts import { Provide, Scope, ScopeEnum, DataListener } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class MemoryDataListener extends DataListener { private intervalHandler; // 初始化数据 initData() { return 'hello' + Date.now(); } // 更新数据 onData(setData) { this.intervalHandler = setInterval(() => { setData('hello' + Date.now()); }, 1000); } // 清理资源 async destroyListener() { // 关闭定时器 clearInterval(this.intervalHandler); // 其他清理, close sdk 等等 } } ``` 上面的 `initData` 方法可以异步获取数据。 ``` // ... export class MemoryDataListener extends DataListener { async initData() { // ... } } ``` ## 使用数据订阅[​](#使用数据订阅 "使用数据订阅的直接链接") 我们可以在任意的代码中使用它,在业务中通过 `getData` 方法来获取当前的数据,不需要考虑数据变化的情况。 比如: ``` import { Provide, Inject } from '@midwayjs/core'; import { MemoryDataListener } from '../listener/memory.listner.ts'; @Provide() export class UserService { @Inject() memoryDataListener: MemoryDataListener; async getUserHelloData() { const helloData = this.memoryDataListener.getData(); // helloData => helloxxxxxxxx // ... } } ``` 数据订阅模式可以方便的将变化的数据隐藏在普通类中,而透出不变化的 API,使得标准的业务代码在逻辑和流程上都变的简洁。 --- # 数据响应 从 v3.17.0 开始,框架添加了 `ServerResponse` 和 `HttpServerResponse` 的实现。 通过这个功能,可以定制服务端的响应成功和失败时的通用格式,规范整个返回逻辑。 ## Http 通用响应[​](#http-通用响应 "Http 通用响应的直接链接") 在 koa 场景下,一般都会处理一些逻辑,最后返回一个结果。在此过程中,会出现返回成功和失败的情况。 最为常见实现会在 `ctx` 增加一些方法,包括数据后返回。 ``` import { Controller, Get, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { try { // ... return this.ctx.ok(/*...*/); } catch (err) { return this.ctx.fail(/*...*/); } } } ``` 也有人会在 Web 中间件中处理成功的返回,在错误过滤器中处理失败的返回。 为了解决这类代码难以统一维护的问题,框架提供了一套统一返回的方案。 我们以最为常见的返回 JSON 数据为例。 通过创建 `HttpServerResponse` 实例后,调用 `json()` 方法,链式返回数据。 ``` import { Controller, Get, Inject, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/success') async home() { return new HttpServerResponse(this.ctx).success().json({ // ... }); } @Get('/fail') async home2() { return new HttpServerResponse(this.ctx).fail().json({ // ... }); } } ``` 默认情况下,`HttpServerResponse` 在成功和失败的场景上会提供 JSON 的通用包裹结构。 比如在成功的场景下,接收到的数据如下。 ``` { success: 'true', data: //... } ``` 而在失败的场景下,接收到的数据如下。 ``` { success: 'false', message: //... } ``` 注意,`json()` 方法是数据设置的方法,必须在最后一个调用。 ### 常用的响应格式[​](#常用的响应格式 "常用的响应格式的直接链接") `HttpServerResponse` 需要传递一个当前请求的上下文对象 `ctx` 才能实例化。 ``` const serverResponse = new HttpServerResponse(this.ctx); ``` 之后以链式的形式进行调用。 ``` // json serverResponse.json({ a: 1, }); // text serverResponse.text('abcde'); // blob serverResponse.blob(Buffer.from('hello world')); ``` 除了设置数据的方法,还提供了一些其他的快捷方法可以组合使用。 ``` // status serverResponse.status(200).text('abcde'); // header serverResponse.header('Content-Type', 'text/html').text('
hello
'); // headers serverResponse.headers({ 'Content-Type': 'text/plain', 'Content-Length': '100' }).text('a'.repeat(100)); ``` ### 响应模版[​](#响应模版 "响应模版的直接链接") 针对不同的设置数据的方法,框架提供了不同模版以供用户自定义。 比如 `json()` 方法的模版如下。 ``` class ServerResponse { // ... static JSON_TPL = (data: Record, isSuccess: boolean): unknown => { if (isSuccess) { return { success: 'true', data, }; } else { return { success: 'false', message: data || 'fail', }; } }; } ``` 我们可以将全局的模版进行覆盖达到自定义的目的。 ``` HttpServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { // ... } else { // ... } }; ``` 也可以通过继承,自定义不同的响应模版,这样可以不影响全局的默认模板。 ``` class CustomServerResponse extends HttpServerResponse {} CustomServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { // ... } else { // ... } }; ``` 在使用时,创建实例即可。 ``` // ... @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { return new CustomServerResponse(this.ctx).success().json({ // ... }); } } ``` 此外,针对 `text` ,`blob` 方法的模版均可以覆盖。 ``` HttpServerResponse.TEXT_TPL = (data, isSuccess) => { /*...*/}; HttpServerResponse.BLOB_TPL = (data, isSuccess) => { /*...*/}; ``` ### 数据流式响应[​](#数据流式响应 "数据流式响应的直接链接") 使用内置的 `HttpServerResponse` 中的 `stream` 方法来处理流式数据返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const res = new HttpServerResponse(this.ctx).stream(); setTimeout(() => { for (let i = 0; i < 100; i++) { await sleep(100); res.send('abc'.repeat(100)); } res.end(); }, 1000); return res; } } ``` 通过 `STEAM_TPL` 可以修改数据的返回结构 ``` HttpServerResponse.STREAM_TPL = (data) => { /*...*/}; ``` 注意,这个模版只处理成功的数据。 ### 文件流式响应[​](#文件流式响应 "文件流式响应的直接链接") 从 v3.17.0 开始,可以通过 `HttpServerResponse` 简单处理文件下载。 传递一个文件路径即可,默认会使用 `application/octet-stream` 响应头返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const filePath = join(__dirname, '../../package.json'); return new HttpServerResponse(this.ctx).file(filePath); } } ``` 如需返回不同的类型,可以通过第二个参数指定类型。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const filePath = join(__dirname, '../../package.json'); return new HttpServerResponse(this.ctx).file(filePath, 'application/json'); } } ``` 通过 `FILE_TPL` 可以修改返回结构。 ``` HttpServerResponse.FILE_TPL = (data: Readable, isSuccess: boolean) => { /*...*/}; ``` ### SSE 响应[​](#sse-响应 "SSE 响应的直接链接") 从 v3.17.0 开始,框架提供了内置的 SSE (Server-Sent Events)支持。 SSE 的数据定义如下,你需要按下面的格式返回。 ``` export interface ServerSendEventMessage { data?: string | object; event?: string; id?: string; retry?: number; } ``` 通过 `HttpServerResponse` 定义一个返回实例。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { const res = new HttpServerResponse(this.ctx).sse(); // ... return res; } } ``` 可以通过 `send` 和 `sendEnd` 进行数据传递。 ``` const res = new HttpServerResponse(this.ctx).sse(); res.send({ data: 'abcde' }); res.sendEnd({ data: 'end' }); ``` 调用 `sendEnd` 后,请求将被关闭。 也可以通过 `sendError` 发送错误。 ``` const res = new HttpServerResponse(this.ctx).sse(); res.sendError(new Error('test error')); ``` 通过 `SSE_TPL` 可以修改返回结构。 ``` import { ServerSendEventMessage } from '@midwayjs/core'; HttpServerResponse.FILE_TPL = (data: ServerSendEventMessage) => { /*...*/}; ``` 注意,这个模版只处理成功的数据,不会处理 `sendError` 的情况,且返回也必须是 `ServerSendEventMessage` 格式。 ## 基础数据响应[​](#基础数据响应 "基础数据响应的直接链接") 除了 Http 场景之外,框架提供了基础的 `ServerResponse` 类,用于其他的场景。 `ServerResponse` 包含 `json`,`text`,`blob` 三种数据返回方法,以及 `success` 和 `fail` 这两个设置状态的方法。 行为和 `HttpServerResponse` 一致。 通过继承、覆盖等行为,可以非常简单的处理响应值。 比如我们对不同的用户做返回区分。 ``` // src/response/api.ts export class UserServerResponse extends HttpServerResponse {} UserServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { return { status: 200, ...data, }; } else { return { status: 500, message: 'limit exceed' }; } }; export class AdminServerResponse extends HttpServerResponse {} AdminServerResponse.JSON_TPL = (data, isSuccess) => { if (isSuccess) { return { status: 200, router: data.router, ...data }; } else { return { status: 500, message: 'interal error', ...data }; } }; ``` 使用返回。 ``` import { Controller, Get, Inject, sleep, HttpServerResponse } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { UserServerResponse, AdminServerResponse } from '../response/api'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // ... if (this.ctx.user === 'xxx') { return new AdminServerResponse(this.ctx).json({ router: '/', dbInfo: { // ... }, userInfo: { role: 'admin', }, status: 'ok', }); } return new UserServerResponse(this.ctx).json({ status: 'ok', }); } } ``` --- # 数据源管理 在使用数据库包过程中,我们经常会有多库连接和管理的需求,不同数据库的连接池管理,连接状态,以及使用的方式都有一定的差异。 虽然我们可以使用服务工厂来进行抽象,但是不管是语义,还是部分功能,和服务工厂还是略有不同,比如实体类的加载等能力,这都是数据源特有的。 为此,Midway 提供了 `DataSourceManager` 的抽象,方便数据源的管理。 我们以 `mysql2` 来举例,实现一个 `mysql2` 的连接池管理类。 下面是 `mysql2` 官方的示例,作为准备工作。 ``` // get the client const mysql = require('mysql2'); // create the connection to database const connection = mysql.createConnection({ host: 'localhost', user: 'root', database: 'test' }); // simple query connection.query( 'SELECT * FROM `table` WHERE `name` = "Page" AND `age` > 45', function(err, results, fields) { console.log(results); // results contains rows returned by server console.log(fields); // fields contains extra meta data about results, if available } ); ``` 和服务工厂类似,我们需要实现一些固定的方法。 * 1、创建数据源的方法 * 2、检查连接的方法 ## 实现数据源管理器[​](#实现数据源管理器 "实现数据源管理器的直接链接") 数据源管理器在 midway 中也是一个普通的导出类,比如我们也可以把他放到 `src/manager/mysqlDataSourceManager.ts` 中。 ### 1、实现创建数据源接口[​](#1实现创建数据源接口 "1、实现创建数据源接口的直接链接") 我们只需要继承内置的 `DataSourceManager` 类,就能实现一个数据源管理器。 `DataSourceManager` 包含一个泛型类型,需要声明该数据源的数据类型。 ``` import { Provide, Scope, ScopeEnum, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { // ... } ``` 由于是抽象类,我们需要实现其中的几个基本方法。 ``` import { Provide, Scope, ScopeEnum, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { // 创建单个实例 protected async createDataSource(config: any, dataSourceName: string): Promise { return mysql.createConnection(config); } getName(): string { return 'mysql'; } async checkConnected(dataSource: mysql.Connection): Promise { // 伪代码 return dataSource.status === 'connected'; } async destroyDataSource(dataSource: mysql.Connection): Promise { if (await this.checkConnected(dataSource)) { await dataSource.destroy(); } } } ``` ### 2、提供初始化配置[​](#2提供初始化配置 "2、提供初始化配置的直接链接") 我们可以利用 `@Init` 装饰器和 `@Config` 装饰器提供初始化配置。 ``` import { Provide, Scope, ScopeEnum, Init, Config, DataSourceManager } from '@midwayjs/core'; import * as mysql from 'mysql2'; @Provide() @Scope(ScopeEnum.Singleton) export class MySqlDataSourceManager extends DataSourceManager { @Config('mysql') mysqlConfig; @Init() async init() { await this.initDataSource(this.mysqlConfig, { concurrent: true }); } // ... } ``` 从 v4.0.0 开始,`initDataSource` 方法支持第二个参数,用于传递初始化选项。 可选的值有: * `baseDir`: 实体类扫描起始地址,可选,默认是 `src` 或者 `dist` * `entitiesConfigKey`: 实体类配置键,框架会从配置中的这个 key 获取实体类,可选,默认是 `entities` * `concurrent`: 是否并发初始化,可选,为了向前兼容,默认是 `false`。 在 `src/config/config.default` 中,我们可以提供多数据源的配置,来创建多个数据源。 比如: ``` // config.default.ts export const mysql = { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test' }, dataSource2: { host: 'localhost', user: 'root', database: 'test' }, dataSource3: { host: 'localhost', user: 'root', database: 'test' }, } // 其他配置 } ``` 数据源天然就是为了多个实例而设计的,和服务工厂不同,没有单个和多个的配置区别。 ### 3、实例化数据源管理器[​](#3实例化数据源管理器 "3、实例化数据源管理器的直接链接") 为了方便用户使用,我们还需要提前将数据源管理器创建,一般来说,只需要在组件或者项目的 `onReady` 生命周期中实例化,在 `onStop` 生命周期中销毁。 ``` import { Configuration } from '@midwayjs/core'; @Configuration({ imports: [ // ... ] }) export class ContainerConfiguration { private mysqlDataSourceManager: MySqlDataSourceManager; async onReady(container) { // 实例化数据源管理器 this.mysqlDataSourceManager = await container.getAsync(MySqlDataSourceManager); } async onStop() { // 销毁数据源管理器 if (this.mysqlDataSourceManager) { await this.mysqlDataSourceManager.stop(); } } } ``` ## 数据源配置[​](#数据源配置 "数据源配置的直接链接") 在 `src/config/config.default` 中,多个数据源配置格式和 [服务工厂](/docs/service_factory.md) 类似。 默认的配置,我们约定为 `default` 属性。 在创建数据源时,普通的数据源配置以及动态创建的数据源配置都会和 `default` 配置合并。 和服务工厂略有不同,数据源天然就是为了多个实例而设计的,没有单个配置的情况。 完整结构如下: ``` // config.default.ts export const mysql = { default: { // 默认数据源配置 } dataSource: { dataSource1: { entities: [], validateConnection: false, // 数据源配置 }, dataSource2: { // 数据源配置 }, dataSource3: { // 数据源配置 }, } // 其他配置 } ``` 提示 * `entities` 是框架提供的特有的配置,用于指定实体类。 * `validateConnection` 是框架提供的特有的配置,用于指定是否通过 `checkConnected` 方法验证连接。 ## 绑定实体类[​](#绑定实体类 "绑定实体类的直接链接") 数据源最重要的一环是实体类,每个数据源都可以拥有自己的实体类。比如 typeorm 等 orm 框架,都是基于此来设计的。 ### 显式关联实体类[​](#显式关联实体类 "显式关联实体类的直接链接") 实体类一般是和表结构相同的类。 比如: ``` // src/entity/user.entity.ts // 这里是伪代码,装饰器需要自行实现 @Entity() export class SimpleUser { @Column() name: string; } @Entity() export class User { @Column() name: string; @Column() age: number; } ``` 数据源管理器通过固定的配置,将这些实体类和数据源进行绑定。 ``` // config.default.ts import { User, SimpleUser } from '../entity/user.entity'; export default { mysql: { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test', entities: [User] }, dataSource2: { host: 'localhost', user: 'root', database: 'test', entities: [SimpleUser] }, // ... } } } ``` 每个数据源的 `entities` 配置,都可以添加各自的实体类。 ### 目录扫描关联实体[​](#目录扫描关联实体 "目录扫描关联实体的直接链接") 在某些情况下,我们也可以通过通配的路径来替代,比如: ``` // config.default.ts import { User, SimpleUser } from '../entity/user.entity'; export default { mysql: { dataSource: { dataSource1: { host: 'localhost', user: 'root', database: 'test', entities: [ User, SimpleUser, 'entity', // 特定目录(等价于目录通配) '**/abc/**', // 仅获取包含 abc 字符的目录下的文件 'abc/**/*.ts', // 特定目录 + 通配 'abc/*.entity.ts', // 匹配后缀 '**/*.entity.ts', // 通配加后缀匹配 '**/*.{j,t}s', // 后缀匹配 ] }, // ... // ... } } } ``` 警告 注意 * 1、填写目录字符串时,以 `initDataSource` 方法的第二个参数作为相对路径查找,默认为 `baseDir`(`src` 或者 `dist`) * 2、如果匹配后缀,`entities` 的路径注意包括 `js` 和 `ts` 后缀,否则编译后会找不到实体 * 3、字符串路径的写法不支持 [单文件构建部署](/docs/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2)(bundle模式) ## 获取数据源[​](#获取数据源 "获取数据源的直接链接") ### 根据实体获取数据源[​](#根据实体获取数据源 "根据实体获取数据源的直接链接") 一般我们的 API 都是在数据源对象上,比如 `connection.query`。 所以在很多时候,比如自定义装饰器,都需要一个从实体获取到数据源对象的方法。 ``` // 下面为伪代码 import { SimpleUser } from '../entity/user.entity'; class UserService { // 这里一般会注入一个实体类对应的 Model,包含增删改查方法 @InjectEntityModel(SimpleUser) userModel; } ``` 如果在实体类仅对应一个数据源的情况下,我们可以通过 `getDataSourceNameByModel` 来获取数据源。 ``` this.mysqlDataSourceManager.getDataSourceNameByModel(SimpleUser); // => dataSource1 ``` 多个的情况下,该方法获取的数据源不一定准确,会拿到最后设置的一个数据源。 这种时候一般需要用户手动指定数据源,比如: ``` // 下面为伪代码 import { SimpleUser } from '../entity/user.entity'; class UserService { @InjectEntityModel(SimpleUser, 'dataSource2') userModel; } ``` 也可以通过 `defaultDataSourceName` 配置显式指定默认的数据源。 ``` // config.default.ts export const mysql = { dataSource: { dataSource1: { // ... }, dataSource2: { // ... }, dataSource3: { // ... }, } defaultDataSourceName: 'dataSource2', } ``` ### 动态 API 获取数据源[​](#动态-api-获取数据源 "动态 API 获取数据源的直接链接") 通过注入数据源管理器,我们可以通过其上面的方法来拿到数据源。 ``` import { MySqlDataSourceManager } from './manager/mysqlDataSourceManager'; import { join } from 'path'; @Provide() export class UserService { @Inject() mysqlDataSourceManager: MySqlDataSourceManager; async invoke() { const dataSource = this.mysqlDataSourceManager.getDataSource('dataSource1'); // TODO } } ``` 此外,还有一些其他方法。 ``` // 数据源是否存在 this.mysqlDataSourceManager.hasDataSource('dataSource1'); // 获取所有的数据源名 this.mysqlDataSourceManager.getDataSourceNames(); // 数据源是否连接 this.mysqlDataSourceManager.isConnected('dataSource1') ``` ## 动态创建数据源[​](#动态创建数据源 "动态创建数据源的直接链接") 除了通过配置初始化数据源外,我们还可以在运行时动态创建数据源。这在需要根据不同条件创建数据源的场景下非常有用。 使用 `createInstance` 方法可以动态创建数据源: ``` import { Provide, Inject } from '@midwayjs/core'; import { MySqlDataSourceManager } from './manager/mysqlDataSourceManager'; @Provide() export class UserService { @Inject() mysqlDataSourceManager: MySqlDataSourceManager; async createNewDataSource() { // 创建新的数据源 const dataSource = await this.mysqlDataSourceManager.createInstance({ host: 'localhost', user: 'root', database: 'new_db', entities: ['entity/user.entity.ts'], validateConnection: true }, 'dynamicDB'); // 使用新创建的数据源 // ... } } ``` `createInstance` 方法接受两个参数: * `config`: 数据源配置 * `dataSourceName`: 数据源名称(可选) 提示 * 1、`dataSourceName` 是数据源的唯一标识,用于区分不同的数据源。 * 2、如果不提供 `dataSourceName`,则数据源管理器不会缓存该数据源,返回后需要用户自行管理其生命周期。 * 3、动态创建的数据源,会和 `default` 配置合并。 ## 类型定义[​](#类型定义 "类型定义的直接链接") 在使用数据源时,我们需要正确定义类型。Midway 提供了两个核心类型来帮助你定义数据源配置。 #### BaseDataSourceManagerConfigOption[​](#basedatasourcemanagerconfigoption "BaseDataSourceManagerConfigOption的直接链接") 用于定义基础数据源配置: ``` import { BaseDataSourceManagerConfigOption } from '@midwayjs/core'; // 定义你的数据源配置 interface MySQLOptions { host: string; port: number; username: string; password: string; database: string; } // 使用 BaseDataSourceManagerConfigOption 定义完整配置 // 第一个泛型参数是数据源配置 // 第二个泛型参数是实体配置的键名(默认为 'entities') type MySQLConfig = BaseDataSourceManagerConfigOption; ``` #### DataSourceManagerConfigOption[​](#datasourcemanagerconfigoption "DataSourceManagerConfigOption的直接链接") 在基础配置的基础上,增加了数据源管理相关的配置: ``` import { DataSourceManagerConfigOption } from '@midwayjs/core'; interface MySQLOptions { host: string; port: number; username: string; password: string; database: string; } // 使用 DataSourceManagerConfigOption 定义配置 declare module '@midwayjs/core' { interface MidwayConfig { mysql?: DataSourceManagerConfigOption; } } ``` #### 使用示例[​](#使用示例 "使用示例的直接链接") ``` // src/config/config.default.ts export default { mysql: { // 默认数据源配置 default: { host: 'localhost', port: 3306, username: 'root', password: '123456', database: 'test', entities: ['entity/**/*.entity.ts'], validateConnection: true }, // 多数据源配置 dataSource: { db1: { host: 'localhost', port: 3306, username: 'root', password: '123456', database: 'db1', entities: ['entity/db1/**/*.entity.ts'] } } } } ``` 提示 * `BaseDataSourceManagerConfigOption` 主要用于定义单个数据源的配置 * `DataSourceManagerConfigOption` 用于定义完整的数据源管理配置,包括多数据源支持 * 如果你的 ORM 使用不同的实体配置键名,可以通过第二个泛型参数指定,如: ``` // Sequelize 使用 models 而不是 entities type SequelizeConfig = DataSourceManagerConfigOption; ``` --- # 调试 本章节介绍如何在常用编辑器中调试 Midway 项目。 ## 在 VSCode 中调试[​](#在-vscode-中调试 "在 VSCode 中调试的直接链接") ### 方法一:使用 JavaScript Debug Teminal[​](#方法一使用-javascript-debug-teminal "方法一:使用 JavaScript Debug Teminal的直接链接") 在 VSCode 的终端下拉出,隐藏着一个 `JavaScript Debug Terminal` ,点击它,创建出来的终端将自带调试能力。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01HWzQEu1cQ6C7q9OYh_!!6000000003594-2-tps-1030-364.png) 输入任意的命令都将自动开启 Debug,比如输入 `npm run dev` 后。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01nnkbOQ1YN79M1svVV_!!6000000003046-2-tps-1500-570.png) ### 方法二:配置调试文件[​](#方法二配置调试文件 "方法二:配置调试文件的直接链接") 创建一个 vscode 的启动文件。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01WzgZwN23WVMLYP4Xs_!!6000000007263-2-tps-645-344.png) 随便选一个,会创建 `.vscode/launch.json` 文件, ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01pP7ntf1HRNMmTeGBT_!!6000000000754-2-tps-655-231.png) 将下面内容复制进去。 ``` { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [{ "name": "Midway Local", "type": "node", "request": "launch", "cwd": "${workspaceRoot}", "runtimeExecutable": "npm", "windows": { "runtimeExecutable": "npm.cmd" }, "runtimeArgs": [ "run", "dev" ], "env": { "NODE_ENV": "local" }, "console": "integratedTerminal", "protocol": "auto", "restart": true, "port": 7001, "autoAttachChildProcesses": true }] } ``` 启动断点即可。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01AGHSI51zZvrKgS9xx_!!6000000006729-2-tps-1470-1020.png) ## 在 WebStorm/Idea 中调试[​](#在-webstormidea-中调试 "在 WebStorm/Idea 中调试的直接链接") 开始配置 IDE。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01bmrjiW1frz9dLpdEZ_!!6000000004061-2-tps-1110-692.png) 配置 npm 命令。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01e4yJnU1QT3MOImlpR_!!6000000001976-2-tps-620-946.png) 选择你的 `package.json` 后,下拉选择 `Scrips` ,其中是你 `package.json` 中配置好的 `scripts` 中的命令,选择你要的命令,比如 `dev` 或者 `test` 等即可 。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01DBqmwD1rtbwqpuQZe_!!6000000005689-2-tps-1500-1017.png) 在代码上断点后执行调试即可。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01sGzfeH1iLPpzSIWSg_!!6000000004396-2-tps-1327-907.png) --- # 现有装饰器索引 Midway 提供了很多装饰器能力,这些装饰器分布在不同的包,也提供了不同的功能,本章节提供一个快速反查的列表。 ## @midwayjs/core[​](#midwayjscore "@midwayjs/core的直接链接") | 装饰器 | 修饰位置 | 描述 | | ------------------ | ------------ | ----------------------------------------- | | @Provide | Class | 暴露一个 class,让 IoC 容器能够获取元数据 | | @Inject | Property | 注入一个 IoC 容器中的对象 | | @Scope | Class | 指定作用域 | | @Init | Method | 标注对象初始化时自动执行的方法 | | @Destroy | Method | 标注对象销毁时执行的方法 | | @Async | Class | 【已废弃】表明为异步函数 | | @Autowire | Class | 【已废弃】标识类为自动注入属性 | | @Autoload | Class | 让类可以自加载执行 | | @Configuration | Class | 标识一个容器入口配置类 | | @Aspect | Class | 标识拦截器 | | @Validate | Method | 标识方法,需要被验证 | | @Rule | Property | 标识 DTO 的校验规则 | | @App | Property | 注入当前应用实例 | | @Config | Property | 获取配置 | | @Logger | Property | 获取日志实例 | | @Controller | Class | 标识为一个 Web 控制器 | | @Get | Method | 注册为一个 GET 类型的路由 | | @Post | Method | 注册为一个 POST 类型的路由 | | @Del | Method | 注册为一个 DELETE 类型的路由 | | @Put | Method | 注册为一个 PUT 类型的路由 | | @Patch | Method | 注册为一个 PATCH 类型的路由 | | @Options | Method | 注册为一个 OPTIONS 类型的路由 | | @Head | Method | 注册为一个 HEAD 类型的路由 | | @All | Method | 注册为一个全类型的路由 | | @Session | Parameter | 从参数获取 ctx.session | | @Body | Parameter | 从参数获取 ctx.request.body | | @Query | Parameter | 从参数获取 ctx.query | | @Param | Parameter | 从参数获取 ctx.param | | @Headers | Parameter | 从参数获取 ctx.headers | | @File | Parameter | 从参数获取第一个上传文件 | | @Files | Parameter | 从参数获取所有的上传文件 | | @Fields | Parameter | 从参数获取表单 Field(上传时) | | @Redirect | Method | 修改响应跳转 | | @HttpCode | Method | 修改响应状态码 | | @SetHeader | Method | 修改响应头 | | @ContentType | Method | 修改响应头中的 Content-Type 字段 | | @Schedule | Class | 标识为一个 egg 定时任务 | | @Plugin | Property | 获取 egg 插件 | | @Provider | Class | 暴露微服务提供者(生产者) | | @Consumer | Class | 暴露微服务调用者(消费者) | | @GrpcMethod | Method | 标识暴露的 gRPC 方法 | | @Func | Class/Method | 【已废弃】标识为一个函数入口 | | @Handler | Method | 【已废弃】配合标记函数 | | @ServerlessTrigger | Method | 标识一个函数触发器 | | @Task | Method | 定义一个分布式任务 | | @TaskLocal | Method | 定义一个本地任务 | | @Queue | Class | 定义一个自触发的任务 | ## @midwayjs/typeorm[​](#midwayjstypeorm "@midwayjs/typeorm的直接链接") | 装饰器 | 修饰位置 | 作用 | | --------------------- | -------- | ---------------- | | @EntityModel | Class | 定义一个实体对象 | | @InjectEntityModel | Property | 注入一个实体对象 | | @EventSubscriberModel | Class | 定义事件订阅 | ## @midwayjs/validate[​](#midwayjsvalidate "@midwayjs/validate的直接链接") | 装饰器 | 修饰位置 | 描述 | | --------- | -------- | ---------------------- | | @Rule | Property | 定义一个规则 | | @Validate | Method | 标识一个需要校验的方法 | ## @midwayjs/swagger[​](#midwayjsswagger "@midwayjs/swagger的直接链接") | 装饰器 | 修饰位置 | 描述 | | ----------------------- | ----------------- | ---- | | `@ApiBody` | Method | | | `@ApiExcludeEndpoint` | Method | | | `@ApiExcludeController` | Class | | | `@ApiHeader` | Class/Method | | | `@ApiHeaders` | Class/Method | | | `@ApiOperation` | Method | | | `@ApiProperty` | Property | | | `@ApiPropertyOptional` | Property | | | `@ApiResponseProperty` | Property | | | `@ApiQuery` | Method | | | `@ApiResponse` | Method | | | `@ApiTags` | Controller/Method | | | `@ApiExtension` | Method | | | `@ApiBasicAuth` | Controller | | | `@ApiBearerAuth` | Controller | | | `@ApiCookieAuth` | Controller | | | `@ApiOAuth2` | Controller | | | `@ApiSecurity` | Controller | | | `@ApiParam` | Method | | | `@ApiParam` | Method | | --- # 启动和部署 Midway 提供了一个轻量的启动器,用于启动你的应用。我们为应用提供了多种部署模式,你既可以将应用按照传统的样子,部署到任意的服务器上(比如自己购买的服务器),也可以将应用构建为一个 Serverless 应用,Midway 提供跨多云的部署方式。 ## 本地开发[​](#本地开发 "本地开发的直接链接") 这里列举的主要是本地使用 `dev` 命令开发的方式,有两种。 ### 快速启动单个服务[​](#快速启动单个服务 "快速启动单个服务的直接链接") 在本地研发时,Midway 在 `package.json` 中提供了一个 `dev` 命令启动框架,比如: * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "dev": "mwtsc --watch --run @midwayjs/mock/app.js", } } ``` 这是一个最精简的命令,他有如下特性: * 1、使用 `mwtsc` 工具构建代码,成功后通过 `@midwayjs/mock` 包中的 `app.js` 文件读取构建后的代码启动项目 * 2、使用内置的 API(@midwayjs/core 的 `initializeGlobalApplicationContext`)创建一个服务,不经过 `bootstrap.js` * 3、单进程运行 ``` { "script": { "dev": "midway-bin dev --ts" } } ``` 这是一个最精简的命令,他有如下特性: * 1、使用 `--ts` 指定 TypeScript(ts-node)环境启动 * 2、使用内置的 API(@midwayjs/core 的 `initializeGlobalApplicationContext`)创建一个服务,不经过 `bootstrap.js` * 3、单进程运行 在命令行运行下面的命令即可执行。 ``` $ npm run dev ``` ### 指定入口启动服务[​](#指定入口启动服务 "指定入口启动服务的直接链接") 由于本地的 dev 命令普通情况下和 `bootstrap.js` 启动文件初始化参数不同,有些用户担心本地开发和线上开发不一致,比如测试链路等。 这个时候我们可以直接传递一个入口文件给 `dev` 命令,直接使用入口文件启动服务。 * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "dev": "mwtsc --watch --run bootstrap.js", }, } ``` ``` { "script": { "dev": "midway-bin dev --ts --entryFile=bootstrap.js" } } ``` ## 部署到服务器[​](#部署到服务器 "部署到服务器的直接链接") ### 部署后和本地开发的区别[​](#部署后和本地开发的区别 "部署后和本地开发的区别的直接链接") 在部署后,有些地方和本地开发有所区别。 **1、node 环境的变化** 最大的不同是,服务器部署后,会直接使用 node 来启动项目。 * 如果使用了 `mwtsc` 开发项目,差距不是很大 * 如果使用了 `@midwayjs/cli`,将不会使用 `ts-node` 来启动项目,这意味着不再读取 `*.ts` 文件 **2、加载目录的变化** 服务器部署后,只会加载构建后的 `dist` 目录,而本地开发则是加载 `src` 目录。 | | 本地 | 服务器 | | ------- | ----------------------- | ------------------------ | | appDir | 项目根目录 | 项目根目录 | | baseDir | 项目根目录下的 src 目录 | 项目根目录下的 dist 目录 | **3、环境的变化** 服务器环境,一般使用 `NODE_ENV=production` ,很多库都会在这个环境下提供性能更好的方式,例如启用缓存,报错处理等。 **4、日志文件** 一般服务器环境,日志不会打印到项目的 logs 目录,而是其他不会受到项目更新影响的目录,比如 `home/admin/logs` ,这样固定的目录,也方便其他工具采集日志。 ### 部署的流程[​](#部署的流程 "部署的流程的直接链接") 整个部署分为几个部分,由于 Midway 是 TypeScript 编写,比传统 JavaScript 代码增加了一个构建的步骤,整个部署的过程如下。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01wSpCuM27pWGTDeDyK_!!6000000007846-2-tps-2212-242.png) 由于部署和平台、环境非常相关,下面我们都将以 Linux 来演示,其他平台可以视情况参考。 ### 编译代码和安装依赖[​](#编译代码和安装依赖 "编译代码和安装依赖的直接链接") 由于 Midway 项目是 TypeScript 编写,在部署前,我们先进行编译。在示例中,我们预先写好了构建脚本,执行 `npm run build` 即可,如果没有,在 `package.json` 中添加下面的 `build` 命令即可。 * 使用 mwtsc * 使用 @midwayjs/cli ``` { "scripts": { "build": "mwtsc --cleanOutDir", }, } ``` ``` { "scripts": { "build": "midway-bin build -c" }, } ``` 信息 虽然不是必须,但是推荐大家先执行测试和 lint。 一般来说,部署构建的环境和本地开发的环境是两套,我们推荐在一个干净的环境中构建你的应用。 下面的代码,是一个示例脚本,你可以保存为 `build.sh` 执行。 ``` ## 服务器构建(已经下载好代码) $ npm install # 安装开发期依赖 $ npm run build # 构建项目 $ npm prune --production # 移除开发依赖 ## 本地构建(已经安装好 dev 依赖) $ npm run build $ npm prune --production # 移除开发依赖 ``` 信息 一般安装依赖会指定 `NODE_ENV=production` 或 `npm install --production` ,在构建正式包的时候只安装 dependencies 的依赖。因为 devDependencies 中的模块过大而且在生产环境不会使用,安装后也可能遇到未知问题。 执行完构建后,会出现 Midway 构建产物 `dist` 目录。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── node_modules # Node.js 依赖包目录 ├── test ├── bootstrap.js # 部署启动文件 ├── package.json └── tsconfig.json ``` ### 构建时别名(alias path)的问题[​](#构建时别名alias-path的问题 "构建时别名(alias path)的问题的直接链接") 别名是前端工具带来的习惯,而非 Node.js 的标准能力,目前使用有两种可选的方式: * 1、使用 Node.js 自带的 [子路径导入方案](https://nodejs.org/dist/latest/docs/api/packages.html#subpath-imports) * 2、使用 [额外工具](/docs/faq/alias_path.md) 在编译时处理 ### 打包压缩[​](#打包压缩 "打包压缩的直接链接") 构建完成后,你可以简单的打包压缩,上传到待发布的环境。 警告 一般来说服务器运行必须包含的文件或者目录有 `package.json`,`bootstrap.js`,`dist`,`node_modules`。 ### 上传和解压[​](#上传和解压 "上传和解压的直接链接") 有很多种方式可以上传到服务器,比如常见的 `ssh/FTP/git` 等。也可以使用 [OSS](https://www.aliyun.com/product/oss) 等在线服务进行中转。 ### 启动项目[​](#启动项目 "启动项目的直接链接") Midway 构建出来的项目是单进程的,不管是采用 `fork` 模式还是 `cluster` 模式,单进程的代码总是很容易的兼容到不同的体系中,因此非常容易被社区现有的 pm2/forever 等工具所加载, 我们这里以 pm2 来演示如何部署。 项目一般都需要一个入口文件,比如,我们在根目录创建一个 `bootstrap.js` 作为我们的部署文件。 ``` ➜ my_midway_app tree . ├── src ├── dist # Midway 构建产物目录 ├── test ├── bootstrap.js # 部署启动文件 ├── package.json └── tsconfig.json ``` Midway 提供了一个简单方式以满足不同场景的启动方式,只需要安装我们提供的 `@midwayjs/bootstrap` 模块(默认已自带)。 ``` $ npm install @midwayjs/bootstrap --save ``` 然后在入口文件中写入代码,注意,这里的代码使用的是 `JavaScript` 。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.run(); ``` 虽然启动文件的代码很简单,但是我们依旧需要这个文件,在后续的链路追踪等场景中需要用到。 注意,这里不含 http 的启动端口,如果你需要,可以参考文档 修改。 * [修改 koa 端口](/docs/extensions/koa.md#%E4%BF%AE%E6%94%B9%E7%AB%AF%E5%8F%A3) 这个时候,你已经可以直接使用 `NODE_ENV=production node bootstrap.js` 来启动代码了,也可以使用 pm2 来执行启动。 我们一般推荐使用工具来启动 Node.js 项目,下面有一些文档可以进阶阅读。 * [pm2 使用文档](/docs/extensions/pm2.md) * [cfork 使用文档](/docs/extensions/cfork.md) ### 启动参数[​](#启动参数 "启动参数的直接链接") 在大多数情况下,不太需要在 Bootstrap 里配置参数,但是依旧有一些可配置的启动参数选项,通过 `configure` 方法传入。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ imports: [/*...*/] }) .run(); ``` | 属性 | 类型 | 描述 | | -------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | appDir | string | 可选,项目根目录,默认为 `process.cwd()` | | baseDir | string | 可选,项目代码目录,研发时为 `src`,部署时为 `dist` | | imports | Component\[] | 可选,显式的组件引用 | | moduleDetector | 'file' \| IFileDetector \| false | 可选,使用的模块加载方式,默认为 `file` ,使用依赖注入本地文件扫描方式,可以显式指定一个扫描器,也可以关闭扫描 | | logger | Boolean \| ILogger | 可选,bootstrap 中使用的 logger,默认为 consoleLogger | | ignore | string\[] | 可选,依赖注入容器扫描忽略的路径,moduleDetector 为 false 时无效 | | globalConfig | Array<{ \[environmentName: string]: Record\ }> \| Record\ | 可选,全局传入的配置,如果传入对象,则直接以对象形式合并到当前的配置中,如果希望传入不同环境的配置,那么,以数组形式传入,结构和 `importConfigs` 一致。 | **示例,传入全局配置(对象)** ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: { customKey: 'abc' } }) .run(); ``` **示例,传入分环境的配置** ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: [{ default: {/*...*/}, unittest: {/*...*/} }] }) .run(); ``` ## 使用 Docker 部署[​](#使用-docker-部署 "使用 Docker 部署的直接链接") ### 编写 Dockerfile,构建镜像[​](#编写-dockerfile构建镜像 "编写 Dockerfile,构建镜像的直接链接") 步骤一:在当前目录下新增Dockerfile ``` FROM node:18 WORKDIR /app ENV TZ="Asia/Shanghai" COPY . . # 如果各公司有自己的私有源,可以替换registry地址 RUN npm install --registry=https://registry.npm.taobao.org RUN npm run build # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "start"] ``` 步骤二: 新增 `.dockerignore` 文件(类似 git 的 ignore 文件),可以把 `.gitignore` 的内容拷贝到 `.dockerignore` 里面 步骤三:当使用 pm2 部署时,请将命令修改为 `pm2-runtime start` ,pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 步骤四:构建 docker 镜像 ``` $ docker build -t helloworld . ``` 步骤五:运行 docker 镜像 ``` $ docker run -itd -P helloworld ``` 运行效果如下: ![image.png](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882492099-49160b6a-601c-4f08-ba65-b95a1335aedf.png#height=33\&id=BtUCB\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=45\&originWidth=1024\&originalType=binary\&ratio=1\&size=33790\&status=done\&style=none\&width=746) 然后大写的 `-P` 由于给我们默认分配了一个端口,所以我们访问可以访问 `32791` 端口(这个 `-P` 是随机分配,我们也可以使用 `-p 7001:7001` 指定特定端口) ![image.png](https://cdn.nlark.com/yuque/0/2020/png/187105/1608882559686-031bcf0d-2185-42cd-a838-80f008777395.png#height=94\&id=dfag9\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=188\&originWidth=578\&originalType=binary\&ratio=1\&size=24488\&status=done\&style=none\&width=289) 后续:发布 docker 镜像 * 推送构建好的镜像到DockerHub,请参考[官方文档](https://docs.docker.com/get-started/04_sharing_app/) * 推送到自建的镜像仓库(以Harbor为例),请参考[Harbor文档](https://goharbor.io/docs/2.5.0/working-with-projects/working-with-images/pulling-pushing-images/) **优化** 我们看到前面我们打出来的镜像有1个多G,可优化的地方: * 1、我们可以采用更精简的 docker image 的基础镜像:例如 node:18-alpine, * 2、其中的源码最终也打在了镜像中,其实这块我们可以不需要。 我们可以同时结合 docker 的 multistage 功能来做一些优化,这个功能请注意要在 `Docker 17.05` 版本之后才能使用。 ``` FROM node:18 AS build WORKDIR /app COPY . . RUN npm install RUN npm run build FROM node:18-alpine WORKDIR /app COPY --from=build /app/dist ./dist # 把源代码复制过去, 以便报错能报对行 COPY --from=build /app/src ./src COPY --from=build /app/bootstrap.js ./ COPY --from=build /app/package.json ./ RUN apk add --no-cache tzdata ENV TZ="Asia/Shanghai" RUN npm install --production # 如果端口更换,这边可以更新一下 EXPOSE 7001 CMD ["npm", "run", "start"] ``` 当前示例的结果只有 `207MB`。相比原有的 `1.26G` 省了很多的空间。 ### 结合 Docker-Compose 运行[​](#结合-docker-compose-运行 "结合 Docker-Compose 运行的直接链接") 在 docker 部署的基础上,还可以结合 docker-compose 配置项目依赖的服务,实现快速部署整个项目。 下面以 midway 结合 redis 为例,使用 docker-compose 快速部署整个项目。 **步骤一:编写Dockerfile** 按照上文使用 Docker 部署的方式[编写Dockerfile](/docs/deployment.md#%E7%BC%96%E5%86%99-dockerfile%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F) **步骤二:编写docker-compose.yml** 新增 `docker-compose.yml` 文件,内容如下:(此处模拟我们的 midway 项目需要使用 redis) ``` # 项目的根目录,与Dockerfile文件同级 version: "3" services: web: build: . ports: - "7001:7001" links: - redis depends_on: - redis redis: image: redis ``` **步骤三:修改配置** 修改 redis 的配置文件,内容如下:( 配置redis,请参考 [redis组件](/docs/extensions/redis.md) ) ``` // src/config/config.default.ts export default { // ... redis: { client: { port: 6379, // redis容器的端口 host: "redis", // 这里与docker-compose.yml文件中的redis服务名称一致 password: "", //默认没有密码,请自行修改为redis容器配置的密码 db: 0, }, }, } ``` **步骤四:构建** 使用命令: ``` $ docker-compose build ``` **步骤五:运行** ``` $ docker-compose up -d ``` ![](https://cdn.nlark.com/yuque/0/2020/png/187105/1608884158660-02bd2d3c-08b4-4ecc-a4dd-a18d4b9d2c12.png) **后续** 更多关于 docker-compose ,请参考[官方文档](https://docs.docker.com/compose/) ## 单文件构建部署[​](#单�文件构建部署 "单文件构建部署的直接链接") 在某些场景,将项目构建为单文件,部署的文件可以更小,可以更容易的分发部署,在一些场景下特别的高效,如: * Serverless 场景,单文件可以更快的部署 * 私密场景,单文件可以更容易的做加密混淆 Midway 从 v3 开始支持将项目构建为单文件。 不支持的情况有: * egg 项目(@midwayjs/web) * 入口处 `importConfigs` 使用的路径形式引入配置的应用,组件 * 未显式依赖的包,或者包里有基于约定的文件 ### 前置依赖[​](#前置依赖 "前置依赖的直接链接") 单文件构建有一些前置依赖需要安装。 ``` ## 用于生成入口 $ npm i @midwayjs/bundle-helper --save-dev ## 用于构建单文件 ## 装到全局 $ npm i @vercel/ncc -g ## 或者装到项目(推荐) $ npm i @vercel/ncc --save-dev ``` ### 代码调整[​](#代码调整 "代码调整的直接链接") 有一些可能的调整,列举如下: #### 1、配置格式调整[​](#1配置格式调整 "1、配置格式调整的直接链接") 必须将项目引入的配置调整为 [对象模式](/docs/env_config.md)。 Midway 的官方组件都已经调整为该模式,如果有自己编写的组件,也请调整为该模式才能构建为单文件。 提示 Midway v2/v3 均支持配置以 "对象模式" 加载。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class MainConfiguration { } ``` #### 2、默认导出的情况[​](#2默认导出的情况 "2、默认导出的情况的直接链接") 由于 ncc 构建器的默认行为,请 **不要** 在依赖注入相关的代码中使用默认导出。 比如: ``` export default class UserSerivce { // ... } ``` 编译后会导致 `UserSerivce` 无法注入。 #### 3、数据源 entities 相关[​](#3数据源-entities-相关 "3、数据源 entities 相关的直接链接") 数据源依赖的扫描路径也是不支持的。 ``` export default { typeorm: { dataSource: { default: { // ... entities: [ '/abc', // 不支持 ] }, } } ``` 如果 entities 特别多,可以编写一个 js 文件,扫描出 entities 后,生成一个文件到目录下,在每次构建时执行。 ### 修改入口文件[​](#修改入口文件 "修改入口文件的直接链接") 修改入口 `bootstrap.js` 为下列代码。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ // 这里引用的是编译后的入口,本地开发不走这个文件 imports: require('./dist/index'), // 禁用依赖注入的目录扫描 moduleDetector: false, }).run() ``` ### 构建[​](#构建 "构建的直接链接") 单文件构建的编译需要几个步骤: * 1、将项目 ts 文件构建为 js * 2、使用额外编译器,将所有的 js 文件打包成一个文件 我们可以将上面的流程编写为下面的两条命令,放在 `package.json` 的 `scripts` 字段中。 ``` "scripts": { // ... "bundle": "bundle && npm run build && ncc build bootstrap.js -o build", "bundle_start": "NODE_ENV=production node ./build/index.js" }, ``` 包含三个部分 * `bundle` 是将所有的项目代码以组件的形式导出,并生成一个 `src/index.ts` 文件,该命令是 `@midwayjs/bundle-helper` 提供的 * `npm run build` 是基础的 ts 项目构建,将 `src/**/*.ts` 构建为 `dist/**/*.js` * `ncc build bootstrap.js -o build` 以 `bootstrap.js` 为入口构建为一个单文件,最终生成到 `build/index.js` 编写完成后,执行命令。 ``` $ npm run bundle ``` 提示 注意,构建过程中可能有错误,比如 ts 定义错误,入口生成语法不正确等情况,需要手动修复。 编译完成后,启动项目。 ``` $ npm run bundle_start ``` 如果启动访问没问题,那么你就可以拿着构建的 build 目录做分发了。 ## 二进制文件部署[​](#二进制文件部署 "二进制文件部署的直接链接") 将 Node.js 打包为一个单独的可执行文件,部署时直接拷贝执行即可,这种方式包含了 node 运行时,业务代码,有利于保护知识产权。 常见的将 Node.js 打包为可执行文件的工具有 `pkg`、`nexe`、`node-packer`、`enclose` 等,下面我们将以最为常见的 `pkg` 包作为示例。 ### 前置依赖[​](#前置依赖-1 "前置依赖的直接链接") 二进制文件部署有一些前置依赖需要安装。 ``` ## 用于生成入口 $ npm i @midwayjs/bundle-helper --save-dev ## 用于构建二进制文件 ## 装到全局 $ npm i pkg -g ## 或者装到项目(推荐) $ npm i pkg --save-dev ``` ### 代码调整[​](#代码调整-1 "代码调整的直接链接") 和 [单文件构建部署](/docs/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2) 的调整相同,请参考上面的文档。 ### 修改入口文件[​](#修改入口文件-1 "修改入口文件的直接链接") 和 [单文件构建部署](/docs/deployment.md#%E5%8D%95%E6%96%87%E4%BB%B6%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2) 的调整相同,请参考上面的文档。 ### 构建[​](#构建-1 "构建的直接链接") 首先需要对 pkg 进行配置,主要内容在 `package.json` 的 `bin` 和 `pkg` 字段下。 * `bin` 我们指定为入口文件,即 `bootstrap.js` * `pkg.scripts` 构建后的目录,使用了 glob 的语法包括了 `dist` 下的所有 js 文件 * `pkg.asserts` 如果有一些静态资源文件,可以在这里配置 * `pkg.targets` 构建的平台产物,是下列选项的组合(示例中我指定了 mac + node18): * **nodeRange** (node8), node10, node12, node14, node16 or latest * **platform** alpine, linux, linuxstatic, win, macos, (freebsd) * **arch** x64, arm64, (armv6, armv7) * `pkg.outputPath` 构建产物的地址,为了和 ts 输出分开,我们选择了 build 目录 `package.json` 参考示例: ``` { "name": "my-midway-project", // ... "devDependencies": { // ... "@midwayjs/bundle-helper": "^1.2.0", "pkg": "^5.8.1" }, "scripts": { // ... "pkg": "pkg . -d > build/pkg.log", "bundle": "bundle && npm run build" }, "bin": "./bootstrap.js", "pkg": { "scripts": "dist/**/*.js", "assets": [], "targets": [ "node18-macos-arm64" ], "outputPath": "build" }, // ... } ``` 更为细节的部分请参考 [pkg文档](https://github.com/vercel/pkg)。 提示 上面的实例中,pkg 命令的 `-d` 参数是为了输出调试信息到特定文件,可以自行删减。 二进制文件构建的编译需要几个步骤: * 1、生成 `src/index.ts` 入口文件,将项目 ts 文件构建为 js * 2、使用 pkg,生成特定平台的构建产物 我们可以执行命令。 ``` $ npm run bundle $ npm run pkg ``` 正确的话,我们可以在 `build` 目录下看到一个 `my-midway-project` 文件(我们的 `package.json` 的 `name` 字段),双击它即可执行。 ## 部署失败的问题[​](#部署失败的问题 "部署失败的问题的直接链接") 部署后由于和环境相关,情况更为复杂,如果部署到服务器之后碰到了问题,请查看 [服务器启动失败排查](/docs/ops/ecs_start_err.md) 。 --- # 多环境配置 配置是我们常用的功能,而且在不同的环境,经常会使用不同的配置信息。 本篇我们来介绍 Midway 如何加载不同环境的业务配置。 ## 配置文件[​](#配置文件 "配置文件的直接链接") 最为简单的就是使用框架提供的业务配置文件能力。 该能力可以在所有业务代码和组件中使用,贯穿整个 Midway 生命周期。 配置文件可以以两种格式导出,**对象形式** 和 **函数形式**。 提示 经过我们的实践,**对象形式** 会更加的简单友好,可以规避许多错误用法。 大部分文档中我们都将以此形式进行展示。 ### 配置文件目录[​](#配置文件目录 "配置文件目录的直接链接") 我们可以自定义一个目录,在其中放入配置文件。 比如 `src/config` 目录。 ``` ➜ my_midway_app tree . ├── src │ ├── config │ │ ├── config.default.ts │ │ ├── config.prod.ts │ │ ├── config.unittest.ts │ │ └── config.local.ts │ ├── interface.ts │ └── service ├── test ├── package.json └── tsconfig.json ``` 配置文件的名字有一些特定的约定。 `config.default.ts` 为默认的配置文件,所有环境都会加载这个配置文件。 其余的文件名,使用 `config.环境` 作为文件名,具体环境的概念请查看 [运行环境](/docs/environment.md)。 配置不是 **必选项**,请酌情添加自己需要的环境配置。 ### 对象形式[​](#对象形式 "对象形式的直接链接") 配置文件导出的格式为 object,比如: ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { keys: '1639994056460_8009', koa: { port: 7001, }, } as MidwayConfig; ``` ### 函数形式[​](#函数形式 "函数形式的直接链接") 配置文件为一个带有 `appInfo` 参数的函数。这个函数在框架初始化时会被自动执行,将返回值合并进完整的配置对象。 ``` // src/config/config.default.ts import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { keys: '1639994056460_8009', koa: { port: 7001, }, view: { root: path.join(appInfo.appDir, 'view'), }, }; } ``` 这个函数的参数为 `MidwayAppInfo` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | ### 配置文件定义[​](#配置文件定义 "配置文件定义的直接链接") Midway 提供了 `MidwayConfig` 作为统一的配置项定义,所有的组件都会将定义合并到此配置项定义中。每当一个组件被开启(在 `configuration.ts` 中被 `imports` ),`MidwayConfig` 就会自动包含该组件的配置定义。 为此,请尽可能使用文档推荐的格式,以达到最佳的使用效果。 每当启用一个新组件时,配置定义都会自动加入该组件的配置项,通过这个行为,也可以变相的检查是否启用了某个组件。 比如,我们启用了 view 组件的效果。 ![](https://img.alicdn.com/imgextra/i2/O1CN013sHGlA1o3uQ4Pg0nO_!!6000000005170-2-tps-1416-572.png) 提示 为什么不使用普通 key 导出形式而使用对象? 1、用户在不了解配置项的情况下,依旧需要查看文档了解每项含义,除了第一层有一定的提示作用外,后面的层级提示没有很明显的效率提升 2、key 导出的形式在过深的结构下展示没有优势 3、key 导出可能会出现重复,但是代码层面不会有警告或者报错,难以排查,这一点对象形式较为友好 ### 对象形式加载配置文件[​](#对象形式加载配置文件 "对象形式加载配置文件的直接链接") 框架提供了加载不同环境的配置文件的功能,需要在 `src/configuration.ts` 文件中开启。 配置加载有两种方式,**对象形式** 和 **指定目录形式** 加载。 从 Midway v3 开始,我们将以 **对象形式** 作为主推的配置加载形式。 在单文件构建、ESM 等场景下,只支持这种标准的模块加载方式来加载配置。 每个环境的配置文件 **必须显式指定添加**,后续框架会根据实际的环境进行合并。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as DefaultConfig from './config/config.default'; import * as LocalConfig from './config/config.local'; @Configuration({ importConfigs: [ { default: DefaultConfig, local: LocalConfig } ] }) export class MainConfiguration { } ``` `importConfigs` 中的数组中传递配置对象,每个对象的 key 为环境,值为环境对应的配置值,midway 在启动中会根据环境来加载对应的配置。 ### 指定目录、文件加载配置[​](#指定目录文件加载配置 "指定目录、文件加载配置的直接链接") 指定加载一个目录,目录里所有的 `config.*.ts` 都会被扫描加载。 ESM,单文件部署等方式不支持目录配置加载。 信息 `importConfigs` 这里只是指定需要加载的文件,实际运行时会**自动选择当前的环境**来找对应的文件后缀。 配置文件的规则为: * 1、可以指定一个目录,推荐传统的 `src/config` 目录,也可以指定一个文件 * 2、文件指定无需 ts 后缀 * 3、配置文件 **必须显式指定添加** **示例:指定目录** ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { } ``` **示例:指定特定文件** 手动指定一批文件时,这个时候如果文件不存在,则会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/config.default'), join(__dirname, './config/config.local'), join(__dirname, './config/custom.local') // 可以使用自定义的命名,只要中间部分带环境就行 ] }) export class MainConfiguration { } ``` 也可以使用项目外的配置,但是请使用绝对路径,以及 `*.js` 后缀。 比如目录结构如下(注意 `customConfig.default.js` 文件): ``` base-app ├── package.json ├── customConfig.default.js └── src ├── configuration.ts └── config └── config.default.ts ``` ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), join(__dirname, '../customConfig.default'), ] }) export class MainConfiguration { } ``` ### 配置加载顺序[​](#配置加载顺序 "配置加载顺序的直接链接") 配置存在优先级(应用代码 > 组件),相对于此运行环境的优先级会更高。 比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。 ``` -> 组件 config.default.ts -> 应用 config.default.ts -> 组件 config.prod.ts -> 应用 config.prod.ts ``` ### 配置合并规则[​](#配置合并规则 "配置合并规则的直接链接") 默认会加载 `**/config.defaut.ts` 的文件以及 `**/config.{环境}.ts` 文件。 比如,下面的代码在 `local` 环境会查找 `config.default.*` 和 `config.local.*` 文件,如果在其他环境,则只会查找 `config.default.*` 和 `config.{当前环境}.*` ,如果文件不存在,则不会加载,也不会报错。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { join } from 'path'; @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { } ``` 为了向前兼容,我们对某些特殊环境的配置读取做了一些处理。这里环境的值指的是根据 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 的值综合得出的 [结果](/docs/environment.md#AxjGQ)。 | **环境的值** | **读取的配置文件** | | ------------ | --------------------------------------------- | | prod | \*.default.ts + \*.prod.ts | | production | \*.default.ts + \*.production.ts + \*.prod.ts | | unittest | \*.default.ts + \*.unittest.ts | | test | \*.default.ts + \*.test.ts + \*.unittest.ts | 除了上述表格外,其余都是 `*.default.ts + *.{当前环境}.ts` 的值。 此外,配置的合并使用 [extend2](https://github.com/eggjs/extend2) 模块进行深度拷贝,[extend2](https://github.com/eggjs/extend2) fork 自 [extend](https://github.com/justmoon/node-extend),处理数组时会存在差异。 ``` const a = { arr: [ 1, 2 ], }; const b = { arr: [ 3 ], }; extend(true, a, b); // => { arr: [ 3 ] } ``` 根据上面的例子,框架直接覆盖数组而不是进行合并。 ## 获取配置[​](#获取配置 "获取配置的直接链接") Midway 会将配置都保存在内部的配置服务中,整个结构是一个对象,在 Midway 业务代码使用时,使用 `@Config` 装饰器注入。 ### 单个配置值[​](#单个配置值 "单个配置值的直接链接") 默认情况下,会根据装饰器的字符串参数值,从配置对象中获取。 ``` import { Config } from '@midwayjs/core'; export class IndexHandler { @Config('userService') userConfig; async handler() { console.log(this.userConfig); // { appname: 'test'} } } ``` ### 深层级别配置值[​](#深层级别配置值 "深层级别配置值的直接链接") 如果配置对象的值在对象的深处,那么可以用级联的方式获取。 比如数据源为: ``` { "userService": { "appname": { "test": { "data": "xxx" } } } } ``` 则可以写复杂的获取表达式来获取值,示例如下。 ``` import { Config } from '@midwayjs/core'; export class IndexHandler { @Config('userService.appname.test.data') data; async handler() { console.log(this.data); // xxx } } ``` ### 整个配置对象[​](#整个配置对象 "整个配置对象的直接链接") 从 v4.0.0 开始,使用 `@AllConfig()` 替换原来的 `@Config(ALL)`装饰器获取所有的配置。 ``` import { AllConfig } from '@midwayjs/core'; export class IndexHandler { @AllConfig() allConfig; async handler() { console.log(this.allConfig); // { userService: { appname: 'test'}} } } ``` ## 修改配置[​](#修改配置 "修改配置的直接链接") 在编码过程中,我们有一些可以动态修改配置的地方,用在不同的场景。 ### 生命周期中修改[​](#生命周期中修改 "生命周期中修改的直接链接") midway 新增了一个异步配置加载的生命周期,可以在配置加载后执行。 ``` // src/configuration.ts import { Configuration, IMidwayContainer } from '@midwayjs/core'; import { join } from 'path'; import { RemoteConfigService } from '../service/remote'; // 自定义的获取远端配置服务 @Configuration({ importConfigs: [ join(__dirname, './config/'), ] }) export class MainConfiguration { async onConfigLoad(container: IMidwayContainer) { // 这里你可以修改全局配置 const remoteConfigService = await container.getAsync(RemoteConfigService); const remoteConfig = await remoteConfigService.getData(); // 这里的返回值会和全局的 config 做合并 // const remoteConfig = { // typeorm: { // dataSource: { // default: { // type: "mysql", // host: "localhost", // port: 3306, // username: "root", // password: "123456", // database: "admin", // synchronize: false, // logging: false, // entities: "/**/**.entity.ts", // dateStrings: true // } // } // } // } return remoteConfig; } } ``` 警告 `onConfigLoad` 生命周期会在 egg 插件(若有)初始化之后执行,不能用于覆盖 egg 插件的配置。 ### 启动时修改[​](#启动时修改 "启动时修改的直接链接") 可以在启动代码之前,使用 Bootstrap 的 `configure` 方法添加配置。 `configure` 方法可以传递一个 `globalConfig` 的属性,可以在应用启动前传递一个全局配置。 如果传递数组,则可以区分环境。 ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: [ { default: { abc: '123' }, unittest: { abc: '321' } } ] }) .run(); // in unittest, app.getConfig('abc') => '321' ``` 如果传递对象,则直接覆盖。 ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .configure({ globalConfig: { abc: 'text' } }) .run(); // app.getConfig('abc') => 'text' ``` ### 使用 API 修改[​](#使用-api-修改 "使用 API 修改的直接链接") 其他场景的修改配置,可以使用 midway 提供的 [API](/docs/built_in_service.md#midwayconfigservice)。 ## 环境变量和配置[​](#环境变量和配置 "环境变量和配置的直接链接") 社区有一些库,比如 `dotenv` 可以加载 `.env` 文件注入到环境中,从而将一些秘钥放在环境中,在 Midway 中可以直接依赖它使用。 ``` $ npm i dotenv --save ``` 可以在项目根目录增加 `.env` 文件,比如下面的内容: ``` OSS_SECRET=12345 OSS_ACCESSKEY=54321 ``` 我们可以在入口中初始化,比如 `bootstrap.js` 或者 `configuration` 。 ``` import { Configuration } from '@midwayjs/core'; import * as dotenv from 'dotenv'; // load .env file in process.cwd dotenv.config(); @Configuration({ //... }) export class MainConfiguration { async onReady(container) { } } ``` 我们可以在环境配置中使用了。 ``` // src/config/config.default export const oss = { accessKey: process.env.OSS_ACCESSKEY, // 54321 secret: process.env.OSS_SECRET // 12345 } ``` ## 常见错误[​](#常见错误 "常见错误的直接链接") 配置未生效的可能性很多,排查思路如下: * 1、检查 configuration 文件中是否显式配置 `importConfigs` 相关的文件或者目录 * 2、检查应用启动的环境,是否和配置文件一致,比如 prod 的配置肯定不会在 local 出现 * 3、检查是否将普通导出和方法回调导出混用,比如下面的混用的情况 ### 1、在构造器(constructor)中获取 @Config 注入的值[​](#1在构造器constructor中获取-config-注入的值 "1、在构造器(constructor)中获取 @Config 注入的值的直接链接") \*\*请不要在构造器中 \*\*获取 `@Config()` 注入的属性,这会使得拿到的结果为 undefined。原因是装饰器注入的属性,都在实例创建后(new)才会赋值。这种情况下,请使用 `@Init` 装饰器。 ``` @Provide() export class UserService { @Config('redisConfig') redisConfig; constructor() { console.log(this.redisConfig); // undefined } @Init() async initMethod() { console.log(this.redisConfig); // has value } } ``` ### 2、回调和导出写法混用[​](#2回调和导出写法混用 "2、回调和导出写法混用的直接链接") **下面是错误用法。** ``` export default (appInfo) => { const config = {}; // xxx return config; }; export const keys = '12345'; ``` `export const` 定义的值会被忽略。 ### 3、export default 和 export const 混用[​](#3export-default-和-export-const-混用 "3、export default 和 export const 混用的直接链接") **下面是错误用法。** ``` export default { keys: '12345', } export const anotherKey = '54321'; ``` 位于后面的配置将会被忽略。 ### 4、export= 和其他混用[​](#4export-和其他混用 "4、export= 和其他混用的直接链接") `export=` 混用的情况,如果后面有其他配置,会忽略 `export=` 的值。 ``` export = { a: 1 } export const b = 2; ``` 编译后结果: ``` export const b = 2; ``` --- # 运行环境 Node.js 应用一般通过 `NODE_ENV` 来获取环境变量,来满足不同环境下的不同需求。比如在 `production` 环境下,开启缓存,优化性能,而在 `development` 环境下,会打开所有的日志开关,输出详细的错误信息等等。 ## 指定运行环境[​](#指定运行环境 "指定运行环境的直接链接") 由于在一些情况下 `NODE_ENV` 会被一些工具包拦截注入,所以在 Midway 体系下,我们会根据 `MIDWAY_SERVER_ENV` 优先获取环境,而 `NODE_ENV` 作为第二优先级获取。 我们可以通过启动时增加环境变量来指定。 ``` MIDWAY_SERVER_ENV=prod npm start // 第一优先级 NODE_ENV=local npm start // 第二优先级 ``` 在 windows 环境,我们需要使用 [cross-env](https://www.npmjs.com/package/cross-env) 模块以达到同样的效果。 ``` cross-env MIDWAY_SERVER_ENV=prod npm start // 第一优先级 cross-env NODE_ENV=local npm start // 第二优先级 ``` ## 代码中获取环境[​](#代码中获取环境 "代码中获取环境的直接链接") Midway 在 app 对象上提供了 `getEnv()` 方法获取环境,面对不同的上层框架,Midway 都做了相应的处理,保使得在不同场景下,都拥有 `getEnv()` 方法。。 ``` import { Application } from '@midwayjs/koa'; // process.env.MIDWAY_SERVER_ENV=prod @Provide() export class UserService { @App() app: Application; async invoke() { console.log(this.app.getEnv()); // prod } } ``` 如果 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 都没有赋值,那么默认情况下,方法的返回值为 `prod` 。 信息 注意,你不能直接通过 `NODE_ENV` 和 `MIDWAY_SERVER_ENV` 来获取环境,这两个值都有可能为空,且 Midway 不会反向设置它。如需获取环境,请通过 app.getEnv() 获取其他框架提供的 API 方法获取。 ## 常见的环境变量值[​](#常见的环境变量值 "常见的环境变量值的直接链接") 一般来说,每个公司都有一些自己的环境变量值,下面是一些常见的环境变量值以及他们对应的说明。 | 值 | 说明 | | --------------------- | ------------ | | local | 本地开发环境 | | dev/daily/development | 日常开发环境 | | pre/prepub | 预生产环境 | | prod/production | 生产环境 | | test/unittest | 单元测试环境 | | benchmark | 性能测试环境 | ## 依赖注入容器中获取环境[​](#依赖注入容器中获取环境 "依赖注入容器中获取环境的直接链接") 在依赖注入容器初始化的过程中,Midway 默认初始化了一个 `EnvironmentService` 服务用来解析环境,并在整个生命周期中,持续保持这个服务对象。 具体请查看 [环境服务](/docs/built_in_service.md#midwayenvironmentservice)。 --- # 框架错误码 以下是框架内置的错误,随着时间推移,我们会不断增加。 | 错误码 | 错误名 | 错误描述 | | ------------- | ------------------------------------- | ---------------------------- | | MIDWAY\_10000 | 占位使用 | 未知错误 | | MIDWAY\_10001 | MidwayCommonError | 未分类的错误 | | MIDWAY\_10002 | MidwayParameterError | 参数类型错误 | | MIDWAY\_10003 | MidwayDefinitionNotFoundError | 依赖注入定义未找到 | | MIDWAY\_10004 | MidwayFeatureNoLongerSupportedError | 功能不再支持 | | MIDWAY\_10005 | MidwayFeatureNotImplementedError | 功能未实现 | | MIDWAY\_10006 | MidwayConfigMissingError | 配置项丢失 | | MIDWAY\_10007 | MidwayResolverMissingError | 依赖注入属性 resovler 未找到 | | MIDWAY\_10008 | MidwayDuplicateRouteError | 路由重复 | | MIDWAY\_10009 | MidwayUseWrongMethodError | 使用了错误的方法 | | MIDWAY\_10010 | MidwaySingletonInjectRequestError | 作用域混乱 | | MIDWAY\_10011 | MidwayMissingImportComponentError | 组件未导入 | | MIDWAY\_10012 | MidwayUtilHttpClientTimeoutError | http client 调用超时 | | MIDWAY\_10013 | MidwayInconsistentVersionError | 使用了不正确的依赖版本 | | MIDWAY\_10014 | MidwayInvalidConfigError | 无效的配置 | | MIDWAY\_10015 | MidwayDuplicateClassNameError | 重复的类名 | | MIDWAY\_10016 | MidwayDuplicateControllerOptionsError | 重复的控制器参数 | | MIDWAY\_10017 | MidwayRetryExceededMaxTimesError | 重试次数超过最大限制 | | MIDWAY\_10018 | MidwayInvokeForbiddenError | 方法调用被禁止 | | MIDWAY\_10019 | MidwayCodeInvokeTimeoutError | 代码调用超时 | | MIDWAY\_10020 | MidwayMainFrameworkMissingError | 主框架缺失 | | MIDWAY\_10021 | MidwayInvalidConfigPropertyError | 无效的配置属性 | | MIDWAY\_10022 | MidwayEmptyValueError | 空值错误 | ## MIDWAY\_10001[​](#midway_10001 "MIDWAY_10001的直接链接") **问题描述** 最通用的框架错误,在不分类的情况下会抛出,一般会将错误的详细内容写入错误信息 **解决方案** 排错以错误信息为准。 ## MIDWAY\_10002[​](#midway_10002 "MIDWAY_10002的直接链接") **问题描述** 方法的参数传入错误,可能类型不对或者参数格式有误。 **解决方案** 参考方法定义或者文档传入参数。 ## MIDWAY\_10003[​](#midway_10003 "MIDWAY_10003的直接链接") **问题描述** 一般出现在启动或者动态从容器中获取某个类的时候,如果该类未在容器中注册,就会报出 `xxx is not valid in current context`错误。 **解决方案** 可能的情况,比如在业务代码或者组件使用中: ``` // ... export class UserService {} // ... @Controller() export class HomeController { @Inject() userService: UserService; } ``` 如果 `UserService` 没有写 `@Provide` 或者隐式含有 `@Provide` 的装饰器,就会出现上述错误。 一般的报错是类似下面这个样子。 ``` userService in class HomeController is not valid in current context ``` 那么,意味着 `HomeController` 中的 `userService` 属性未在容器中找到,你可以顺着这个线索往下排查。 ## MIDWAY\_10004[​](#midway_10004 "MIDWAY_10004的直接链接") **问题描述** 使用的废弃的功能。 **解决方案** 不使用该功能。 ## MIDWAY\_10005[​](#midway_10005 "MIDWAY_10005的直接链接") **问题描述** 使用的方法或者功能暂时未实现。 **解决方案** 不使用该功能。 ## MIDWAY\_10006[​](#midway_10006 "MIDWAY_10006的直接链接") **问题描述** 未提供需要的配置项。 **解决方案** 排查配置对应的环境,是否包含该配置,如果没有,在配置文件中增加该配置即可。 ## MIDWAY\_10007[​](#midway_10007 "MIDWAY_10007的直接链接") **问题描述** 未找到容器注入的解析类型,当前版本不会出现该错误。 **解决方案** 无。 ## MIDWAY\_10008[​](#midway_10008 "MIDWAY_10008的直接链接") **问题描述** 检查到重复的路由。 **解决方案** 移除重复的路由部分。 ## MIDWAY\_10009[​](#midway_10009 "MIDWAY_10009的直接链接") **问题描述** 使用了错误的方法。 **解决方案** 当你在同步的 get 方法中包含了一个异步调用,则会提示使用 `getAsync` 方法,修改即可。 ## MIDWAY\_10010[​](#midway_10010 "MIDWAY_10010的直接链接") **问题描述** 当在单例中注入了一个未显式声明的请求作用域实例则会出现此错误,错误原因为 [作用域降级](/docs/container.md#%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%99%8D%E7%BA%A7)。 比如下面的代码,就会抛出此错误: ``` // ... @Provide() export class UserService {} // ... @Provide() @Scope(ScopeEnum.Singleton) export class LoginService { @Inject() userService: UserService; } ``` 经常在 `configuration` 或者中间件文件中出现该问题。 该错误是为了规避作用域自动降级,缓存了实例数据带来的风险。 **解决方案** * 1、如果你是错误的在单例中注入了请求作用域实例,请修改请求作用域代码为单例 * 2、如果你希望在单例中注入请求作用域来使用,并且能够清楚的知道作用域降级带来的后果(被缓存),请显式在类上声明作用域选项(表示允许降级)。 ``` @Provide() @Scope(ScopeEnum.Request, { allowDowngrade: true }) export class UserService {} ``` ## MIDWAY\_10011[​](#midway_10011 "MIDWAY_10011的直接链接") **问题描述** 当组件未在 `configuration` 文件中 `imports`,就使用了组件中的类,就会出现此错误。 **解决方案** 显式在 `src/configuration` 中的 `imports` 部分中显式引入组件。 ## MIDWAY\_10012[​](#midway_10012 "MIDWAY_10012的直接链接") **问题描述** 内置的 Http Client 超时会抛出此错误。 **解决方案** 正常的超时错误,检查为何超时,做好错误处理即可。 ## MIDWAY\_10013[​](#midway_10013 "MIDWAY_10013的直接链接") **问题描述** 当安装的组件和框架版本不匹配会抛出此错误。 一般会出现在框架发布了新版本之后,当项目开启了 lock 文件,使用了老版本的框架版本,并且安装了一个新组件之后。 **解决方案** 删除 lock 文件,重新安装依赖。 ## MIDWAY\_10014[​](#midway_10014 "MIDWAY_10014的直接链接") **问题描述** 当配置文件中存在 `export default` 和 `export const` 两种导出方式后会抛出该错误。 **解决方案** 请勿两种导出方式混用。 ## MIDWAY\_10015[​](#midway_10015 "MIDWAY_10015的直接链接") **问题描述** 当启动开启了重复类名检查(conflictCheck),如果代码扫描时在依赖注入容器中发现相同的类名,则会抛出该错误。 ``` // src/configuration.ts @Configuration({ // ... conflictCheck: true, }) export class MainConfiguration { // ... } ``` **解决方案** 修改类名,或者关闭重复类名检查。 ## MIDWAY\_10016[​](#midway_10016 "MIDWAY_10016的直接链接") **问题描述** 当添加了不同的控制器,使用了相同的 `prefix`,并且添加了不同的 `options`,比如中间件,会抛出该错误。 **解决方案** 将相同 `prefix` 的控制器代码进行合并,或者移除所有的 `options`。 ## MIDWAY\_10017[​](#midway_10017 "MIDWAY_10017的直接链接") **问题描述** 当使用重试功能时,如果重试次数超过了设定的最大重试次数,会抛出该错误。 **解决方案** 检查重试逻辑,确认是否需要增加重试次数,或者优化被重试的方法以减少失败率。 ## MIDWAY\_10018[​](#midway_10018 "MIDWAY_10018的直接链接") **问题描述** 当尝试调用被标记为禁止调用的方法时,会抛出该错误。 **解决方案** 检查方法的调用权限设置,确认是否有权限调用该方法,或者使用其他替代方法。 ## MIDWAY\_10019[​](#midway_10019 "MIDWAY_10019的直接链接") **问题描述** 当代码执行时间超过设定的超时时间时,会抛出该错误。 **解决方案** 优化代码执行效率,或者适当增加超时时间设置。检查是否存在死循环或者耗时的同步操作。 ## MIDWAY\_10020[​](#midway_10020 "MIDWAY_10020的直接链接") **问题描述** 当系统无法找到主框架时,会抛出该错误。通常发生在框架配置不正确的情况下。 **解决方案** 检查框架配置,确保正确配置了主框架。检查 `configuration.ts` 文件中的框架导入和配置。 ## MIDWAY\_10021[​](#midway_10021 "MIDWAY_10021的�直接链接") **问题描述** 当配置属性的类型不符合预期时,会抛出该错误。 **解决方案** 检查配置文件中的属性类型,确保配置值符合预期的数据类型。参考文档中的配置说明进行修正。 ## MIDWAY\_10022[​](#midway_10022 "MIDWAY_10022的直接链接") **问题描述** 当遇到不允许的空值时,会抛出该错误。 **解决方案** 检查代码中的空值处理,确保在不允许空值的地方提供有效的值。添加必要的空值检查和默认值设置。 --- # 异常处理 Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。 异常处理器的执行位置处于中间件之后,所以它能拦截所有的中间件和业务抛出的错误。 ![err\_filter](https://img.alicdn.com/imgextra/i2/O1CN013pvSjT1nWvsLRE4vo_!!6000000005098-2-tps-2000-524.png) ## Http 异常[​](#http-异常 "Http 异常的直接链接") 在 Http 请求中,Midway 提供了通用的 `MidwayHttpError` 类型的异常,其继承于标准的 `MidwayError`。 ``` export class MidwayHttpError extends MidwayError { // ... } ``` 我们可以在请求的过程中抛出该错误,由于错误中包含状态码,Http 程序将会自动返回该状态码。 比如,下面的代码,抛出了包含 400 状态码的错误。 ``` import { MidwayHttpError } from '@midwayjs/core'; // ... async findAll() { throw new MidwayHttpError('my custom error', HttpStatus.BAD_REQUEST); } // got status: 400 ``` 但是一般我们很少这么做,大多数的业务的错误都是复用的,错误消息也基本是固定的,为了减少重复定义,我们可以自定义一些异常类型。 比如自定义一个状态码为 400 的 Http 异常,可以如下定义错误。 ``` // src/error/custom.error.ts import { HttpStatus } from '@midwayjs/core'; export class CustomHttpError extends MidwayHttpError { constructor() { super('my custom error', HttpStatus.BAD_REQUEST); } } ``` 然后在业务中抛出使用。 ``` import { CustomHttpError } from './error/custom.error'; // ... async findAll() { throw new CustomHttpError(); } ``` ## 异常处理器[​](#异常处理器 "异常处理器的直接链接") 内置的异常处理器用于标准的请求响应场景,它可以捕获所有请求中抛出的错误。 通过 `@Catch` 装饰器我们可以定义某一类异常的处理程序,我们可以轻松的捕获某一类型的错误,做出处理,也可以捕获全局的错误,返回统一的格式。 同时,框架也提供了一些默认的 Http 错误,放在 `httpError` 这个对象下。 比如捕获抛出的 `InternalServerErrorError` 错误。 我们可以将这一类异常处理器放在 `filter` 目录,比如 `src/filter/internal.filter.ts`。 ``` // src/filter/internal.filter.ts import { Catch, httpError, MidwayHttpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch(httpError.InternalServerErrorError) export class InternalServerErrorFilter { async catch(err: MidwayHttpError, ctx: Context) { // ... return 'got 500 error, ' + err.message; } } ``` `catch` 方法的参数为当前的错误,以及当前应用该异常处理器的上下文 `Context` 。我们可以简单的将响应的数据返回。 如果不写参数,那么会捕获所有的错误,不管是不是 HttpError,只在要请求中抛出的错误,都会被这里捕获。 ``` // src/filter/all.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class AllErrorFilter { async catch(err: Error, ctx: Context) { // ... } } ``` 定义的异常处理器只是一段普通的代码,我们还需要将它应用到我们某个框架的 app 中,比如 http 协议的 app。 我们可以在 `src/configuration.ts` 中将错误处理过滤器应用上,由于参数可以是数组,我们可以应用多个错误处理器。 ``` // src/configuration.ts import { Configuration, App, Catch } from '@midwayjs/core'; import { join } from 'path'; import * as koa from '@midwayjs/koa'; import { InternalServerErrorFilter } from './filter/internal.filter'; @Configuration({ imports: [ koa ], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useFilter([InternalServerErrorFilter]); } } ``` 信息 注意,某些非 Midway 的中间件或者框架内部设置的状态码,由于未使用错误抛出的形式,所以拦截不到,如果在业务中返回 400 以上的状态,请尽可能使用标准的抛出错误的形式,方便拦截器做处理。 ### 404 处理[​](#404-处理 "404 处理的直接链接") 框架内部,如果未匹配到路由,会抛出一个 `NotFoundError` 的异常。通过异常处理器,我们可以自定义其行为。 比如跳转到某个页面,或者返回特定的结果: ``` // src/filter/notfound.filter.ts import { Catch, httpError, MidwayHttpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch(httpError.NotFoundError) export class NotFoundFilter { async catch(err: MidwayHttpError, ctx: Context) { // 404 错误会到这里 ctx.redirect('/404.html'); // 或者直接返回一个内容 return { message: '404, ' + ctx.path } } } ``` ### 500 处理[​](#500-处理 "500 处理的直接链接") 当不传递装饰器参数时,将捕获所有的错误。 比如,捕获所有的错误,并返回特定的 JSON 结构,示例如下。 ``` // src/filter/default.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class DefaultErrorFilter { async catch(err: Error, ctx: Context) { // ... return { status: err.status ?? 500, message: err.message; } } } ``` 我们可以在 `src/configuration.ts` 中将错误处理过滤器应用上,由于参数可以是数组,我们可以应用多个错误处理器。 ``` import { Configuration, App, Catch } from '@midwayjs/core'; import { join } from 'path'; import * as koa from '@midwayjs/koa'; import { DefaultErrorFilter } from './filter/default.filter'; import { NotFoundFilter } from './filter/notfound.filter'; @Configuration({ imports: [ koa ], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useFilter([NotFoundFilter, DefaultErrorFilter]); } } ``` 使用异常处理器不需要考虑顺序,通用的错误处理器一定是最后被匹配,且一个 app 上有且只能有一个通用的错误处理器。 ## 派生异常处理[​](#派生异常处理 "派生异常处理的直接链接") 默认情况下,异常只会进行绝对匹配。 有时候我们需要去捕获所有的派生类,这个时候需要额外设置。 ``` import { Catch, MidwayError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; class CustomError extends MidwayError {} class CustomError2 extends MidwayError {} // 这里会捕获所有的子类 @Catch([MidwayError], { matchPrototype: true }) class TestFilter { catch(err, ctx) { // ... } } ``` 通过配置 `matchPrototype` 可以匹配所有的派生的类。 ## 异常日志[​](#异常日志 "异常日志的直接链接") Midway 内置了默认的异常处理行为。 如果 **没有匹配** 到异常处理器,都会被兜底的异常中间件拦截,记录。 反过来说,如果自定义了异常处理器,那么错误就会被当成正常的业务逻辑,请注意,这个时候底层抛出的异常就会作为业务正常的处理逻辑,而 **不会** 被日志记录。 你可以自行在异常处理器中打印日志。 ``` import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Catch() export class DefaultErrorFilter { async catch(err: Error, ctx: Context) { // ... ctx.logger.error(err); // ... return 'got 500 error, ' + err.message; } } ``` ## 内置的 Http 异常[​](#内置的-http-异常 "内置的 Http 异常的直接链接") 下面这些框架内置的 Http 异常,都可以从 `@midwayjs/core` 中找到并使用,每个异常都已经包含默认的错误消息和状态码。 * `BadRequestError` * `UnauthorizedError` * `NotFoundError` * `ForbiddenError` * `NotAcceptableError` * `RequestTimeoutError` * `ConflictError` * `GoneError` * `PayloadTooLargeError` * `UnsupportedMediaTypeError` * `UnprocessableEntityError` * `TooManyRequestsError` * `InternalServerErrorError` * `NotImplementedError` * `BadGatewayError` * `ServiceUnavailableError` * `GatewayTimeoutError` 比如: ``` import { httpError } from '@midwayjs/core'; // ... async findAll() { // something wrong throw new httpError.InternalServerErrorError(); } // got status: 500 ``` --- # ESModule 使用指南 在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。 两个模块系统之间的互操作带来了巨大的挑战,并具有许多功能差异。 自 Node.js v16 之后,ESM 的支持相对已经稳定,TypeScript 的一些配合功能也相继落地。 在此基础上,Midway 支持了 ESM 格式的文件加载,业务也可以使用这种全新的模块加载方式来构建自己的业务。 警告 在没有了解 ESM 前,不建议用户使用。 推荐阅读: * [TypeScript 官方 ESM 指南](https://www.typescriptlang.org/docs/handbook/esm-node.html) * [Node.js 官方 ESM 文档](https://nodejs.org/api/esm.html) ## 脚手架[​](#脚手架 "脚手架的直接链接") 由于改动较多,Midway 提供了全新的 ESM 格式的脚手架,如有 ESM 的需求,我们推荐用户重新创建后再来开发业务。 ``` $ npm init midway@latest -y ``` 在 v4 模板列表中选择 `koa-v4-esm`。 ## 和 CJS 项目的差异[​](#和-cjs-项目的差异 "和 CJS 项目的差异的直接链接") ### 1、package.json 的变化[​](#1packagejson-的变化 "1、package.json 的变化的直接链接") `package.json` 中的 type 必须设置为 `module`。 ``` { "name": "my-package", "type": "module", // ... "dependencies": { } } ``` ### 2、tsconfig.json 中的变化[​](#2tsconfigjson-中的变化 "2、tsconfig.json 中的变化的直接链接") `compilerOptions` 编译相关的选项需要设置为 `Node16` 或者 `NodeNext`。 ``` { "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "Node16", "esModuleInterop": true, // ... } } ``` ### 3、工具链的变化[​](#3工具链的变化 "3、工具链的变化的直接链接") 由于原有开发工具链仅支持 CJS 代码,且社区的部分模块并没有做好 ESM 的支持,Midway 在 ESM 模式下,使用新的工具链。 * 开发命令,使用 mwtsc (仅做了 tsc 必要的包裹) * 测试和覆盖率命令,使用 mocha + ts-node,同时测试代码和测试的配置都有所调整 * 构建命令,使用 tsc 一些不再支持的功能 * alias path,请用 Node.js 自带的 [子路径导出](https://nodejs.org/api/packages.html#subpath-exports) 代替 * 构建时非 js 文件的拷贝,将非代码文件放到 src 外部,或者在 build 时添加自定义命令 具体差异可以参考 Midway 官方脚手架仓库中的最新 ESM 模板:[midwayjs/midway-boilerplate](https://github.com/midwayjs/midway-boilerplate)。 ### 4、一些代码差异[​](#4一些代码差异 "4、一些代码差异的直接链接") 下面快速列出一些开发中 ESM 和 CJS 的差异。 1、ts 中,import 的文件必须指定后缀名,且后缀名为 js。 ``` import { helper } from "./foo.js"; // works in ESM & CJS ``` 2、你不能再使用 `module.exports` 或者 `exports.` 来导出。 ``` // ./foo.ts export function helper() { // ... } // ./bar.ts import { helper } from "./foo"; // only works in CJS ``` 3、你不能在代码中使用 `require` 只能使用 `import` 关键字。 4、你不能在代码中使用 `__dirname`,`__filename` 等和路径相关关键字 ``` // ESM solution import { dirname } from 'node:path' import { fileURLToPath } from 'node:url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(fileURLToPath(import.meta.url)) ``` 所有配置的部分,必须使用对象模式。 ``` import { Configuration } from '@midwayjs/core'; import DefaultConfig from './config/config.default.js'; import UnittestConfig from './config/config.unittest.js'; @Configuration({ importConfigs: [ { default: DefaultConfig, unittest: UnittestConfig, }, ], }) export class MainConfiguration { // ... } ``` --- # Alinode ## 准备工作[​](#准备工作 "准备工作的直接链接") 需要接入的应用是要部署在独立的服务获取云环境,可以接入互联网服务。 ## 创建服务[​](#创建服务 "创建服务的直接链接") **第一步** 登录阿里云,点击开通 [阿里云的 Node.js 性能平台](https://www.aliyun.com/product/nodejs) 的服务。 **第二步** 创建新应用,获取 APP ID 和 App Secret。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617267785895-dd0fb702-91c7-4b25-9c64-8a9358f2d254.png#align=left\&display=inline\&height=351\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=702\&originWidth=1548\&size=106487\&status=done\&style=none\&width=774) ## 安装监控依赖[​](#安装监控依赖 "安装监控依赖的直接链接") **第一步** 安装 Node.js 性能平台所需的组件 ``` # 安装版本管理工具 tnvm,安装过程出错参考:https://github.com/aliyun-node/tnvm $ wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash $ source ~/.bashrc # tnvm ls-remote alinode # 查看需要的版本 $ tnvm install alinode-v6.5.0 # 安装需要的版本 $ tnvm use alinode-v6.5.0 # 使用需要的版本 $ npm install @alicloud/agenthub -g # 安装 agenthub ``` 这里有三个部分 * 1、安装 tnvm(alinode 源) * 2、使用 tnvm 安装 alinode(替代默认的 node) * 3、安装 alinode 需要的数据采集器 安装完成后,可以检查一下,需要确保 `which node` 和 `which agenthub` 的路径中包括 `.tnvm` 即可。 ``` $ which node /root/.tnvm/versions/alinode/v3.11.4/bin/node $ which agenthub /root/.tnvm/versions/alinode/v3.11.4/bin/agenthub ``` 将 `创建新应用` 中获得的 `App ID` 和 `App Secret` 按如下所示保存为 `yourconfig.json`。比如放在项目根目录。 ``` { "appid": "****", "secret": "****", } ``` 启动插件: ``` agenthub start yourconfig.json ``` ## 启动 node 服务[​](#启动-node-服务 "启动 node 服务的直接链接") 在安装了服务器中,启动 Node 服务时,需要加入 ENABLE\_NODE\_LOG=YES 环境变量。 比如: ``` $ NODE_ENV=production ENABLE_NODE_LOG=YES node bootstrap.js ``` ## Docker 容器的方法[​](#docker-容器的方法 "Docker 容器的方法的直接链接") 关于 docker 容器的方法可以查看 [文档](https://help.aliyun.com/document_detail/66027.html?spm=a2c4g.11186623.6.580.261ba70feI6mWt)。 ## 其他[​](#其�他 "其他的直接链接") 更多内容可以查看阿里云 Node.js 性能平台的 [文档](https://help.aliyun.com/document_detail/60338.html?spm=a2c4g.11186623.6.548.599312e6IkGO9v)。 --- # HTTP 请求 ## 简单的 HTTP 请求[​](#简单的-http-请求 "简单的 HTTP 请求的直接链接") Midway 内置了一个简单的 HTTP 请求客户端,无需引入三方包即可使用。 默认 Get 请求,返回数据为 Buffer。 内置的 Http 客户端只提供最简单的能力,仅满足大部分的前端接口数据获取,如需复杂的功能,比如文件上传等,请使用其他的客户端,如 fetch,axios,got 等。 ### 简单方法形式[​](#简单方法形式 "简单方法形式的直接链接") ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/'); // Buffer.isBuffer(result.data) => true ``` Get 请求,带上 Query,返回类型为 JSON。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { data: { a: 1, b: 2 }, dataType: 'json', // 返回的数据格式 }); // typeof result.data => 'object' // result.data.url => /?a=1&b=2 ``` 可以指定类型 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'json', }); ``` 返回 text 格式。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'text', }); ``` POST 请求并返回 JSON。 ``` import { makeHttpRequest } from '@midwayjs/core'; const result = await makeHttpRequest('http://127.1:7001/', { method: 'POST', data: { a: 1, b: 2 }, dataType: 'json', contentType:'json', // 发送的 post 为 json }); // result.data ... ``` 警告 注意,请不要在请求中直接返回 result 对象,result 对象是标准的 httpResponse,在大部分场景下无法被直接序列化,会抛出对象循环的错误。 设置请求超时时间。 ``` import { makeHttpRequest } from '@midwayjs/core'; let err; // 超时会报错,注意 catch try { const result = await makeHttpRequest('http://127.1:7001/', { method: 'GET', dataType: 'text', timeout: 500, }); } catch (e) { err = e; } ``` ### 实例形式[​](#实例形式 "实例形式的直接链接") ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient(); const result = await httpclient.request('http://127.1:7001/'); // Buffer.isBuffer(result.data) => true ``` 和方法形式参数相同。 ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient(); const result = await httpclient.request('http://127.1:7001/', { method: 'POST', data: { a: 1, b: 2 }, dataType: 'json', contentType:'json', // 发送的 post 为 json }); // result.data ... ``` 示例形式,可以复用创建出的对象,并且每次请求,都可以带上一些固定的参数,比如 header。 ``` import { HttpClient } from '@midwayjs/core'; const httpclient = new HttpClient({ headers: { 'x-timeout': '5' }, method: 'POST', timeout: 2000 }); // 每次都会带上 headers const result = await httpclient.request('http://127.1:7001/'); ``` ## Axios 支持[​](#axios-支持 "Axios 支持的直接链接") Midway 包裹了 [axios](https://github.com/axios/axios) 包,使得在代码中可以简单的使用 axios 接口。 和 axios 的一些关系如下: * 接口完全一致 * 适配依赖注入写法,完整的类型定义 * 方便实例管理和配置统一 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/axios@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/axios": "^4.0.0", // ... }, } ``` ### 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path' @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 然后在业务代码中即可注入使用。 ### 使用默认 Axios 实例[​](#使用默认-axios-实例 "使用默认 Axios 实例的直接链接") 接口和 [axios](https://github.com/axios/axios) 一致。 ``` axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]]) axios.postForm(url[, data[, config]]) axios.putForm(url[, data[, config]]) axios.patchForm(url[, data[, config]]) ``` 使用示例: ``` import { HttpService } from '@midwayjs/axios'; @Provide() export class UserService { @Inject() httpService: HttpService; async invoke() { const url = 'https://midwayjs.org/resource/101010100.json'; const result = await this.httpService.get(url); // TODO result } } ``` ### 配置默认 Axios 实例[​](#配置默认-axios-实例 "配置默认 Axios 实例的直接链接") HttpService 实例等价于 `axios.create` ,所以可以有一些配置参数,这些参数了 axios 本身的参数相同,我们可以在 `src/config.default.ts` 中配置它。 比如: ``` export default { // ... axios: { default: { // 所有实例复用的配置 }, clients: { // 默认实例的配置 default: { baseURL: 'https://api.example.com', // `headers` are custom headers to be sent headers: { 'X-Requested-With': 'XMLHttpRequest' }, timeout: 1000, // default is `0` (no timeout) // `withCredentials` indicates whether or not cross-site Access-Control requests // should be made using credentials withCredentials: false, // default }, } } } ``` 更多的参数可以参考 [axios global config](https://github.com/axios/axios#config-defaults)。 ### 创建不同实例[​](#创建不同实例 "创建不同实例的直接链接") 和其他的服务多实例相同,配置不同的 key 即可。 ``` export default { // ... axios: { default: { // 所有实例复用的配置 }, clients: { default: { // 默认实例 }, customAxios: { // 自定义实例 } } } } ``` 使用方式如下: ``` import { HttpServiceFactory, HttpService } from '@midwayjs/axios'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(HttpServiceFactory, 'customAxios') customAxios: HttpService; async invoke() { const url = 'https://midwayjs.org/resource/101010100.json'; const result = await this.customAxios.get(url); // TODO result } } ``` ### 配置全局拦截器[​](#配置全局拦截器 "配置全局拦截器的直接链接") 如果使用的是默认的 Axios 实例,可以如下配置。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const httpService = await container.getAsync(axios.HttpService); httpService.interceptors.request.use( config => { // Do something before request is sent return config; }, error => { // Do something with request error return Promise.reject(error); } ); } } ``` 如果要给其他实例配置,可以参考下面的代码。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import * as axios from '@midwayjs/axios'; import { join } from 'path'; @Configuration({ imports: [ axios // 导入 axios 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const httpServiceFactory = await container.getAsync(axios.HttpServiceFactory); const customAxios = httpServiceFactory.get('customAxios'); customAxios.interceptors.request.use( config => { //... }, error => { //... } ); } } ``` ### 扩展 AxiosRequestConfig 类型[​](#扩展-axiosrequestconfig-类��型 "扩展 AxiosRequestConfig 类型的直接链接") 当前 Axios 库中 [issue](https://github.com/axios/axios/issues?q=is%3Aissue%20state%3Aopen%20AxiosRequestConfig) 有不少扩展 `AxiosRequestConfig` 类型的需求,但是 axios 本身并不支持扩展这个类型,其中的泛型仅限于设置 data 属性的类型。 Midway 中提供了 `AxiosRequestConfig` 的扩展,可以在组件层面增加新的属性。 ``` // interface.ts import '@midwayjs/axios'; declare module '@midwayjs/axios/dist/interface' { interface AxiosRequestConfig { retryDelay?: number; retry?: number; } } ``` ### 直接使用 Axios[​](#直接使用-axios "直接使用 Axios的直接链接") `@midayjs/axios`导出了原始的`axios`实例,在非应用环境中可以直接使用。 ``` import { Axios } from '@midwayjs/axios'; import { ReadStream, createWriteStream } from 'fs'; import { finished } from 'stream/promises'; async function download(url: string, filename: string) { const writer = await createWriteStream(filename); const res = Axios.get(url, { responseType: 'stream', }); res.data.pipe(writer); await finished(writer); return res; } ``` --- # 任务队列 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题。 示例如下: * 平滑处理峰值。可以在任意时间启动资源密集型任务,然后将这些任务添加到队列中,而不是同步执行。让任务进程以受控方式从队列中提取任务。也可以轻松添加新的队列消费者以扩展后端任务处理。 * 分解可能会阻塞 Node.js 事件循环的单一任务。比如用户请求需要像音频转码这样的 CPU 密集型工作,就可以将此任务委托给其他进程,从而释放面向用户的进程以保持响应。 * 提供跨各种服务的可靠通信渠道。例如,您可以在一个进程或服务中排队任务(作业),并在另一个进程或服务中使用它们。在任何流程或服务的作业生命周期中完成、错误或其他状态更改时,您都可以收到通知(通过监听状态事件)。当队列生产者或消费者失败时,它们的状态被保留,并且当节点重新启动时任务处理可以自动重新启动。 Midway 提供了 @midwayjs/bull 包作为 [Bull](https://github.com/OptimalBits/bull) 之上的抽象/包装器,[Bull](https://github.com/OptimalBits/bull) 是一种流行的、受良好支持的、高性能的基于 Node.js 的队列系统实现。该软件包可以轻松地将 Bull Queues 以友好的方式集成到您的应用程序中。 Bull 使用 Redis 来保存作业数据,在使用 Redis 时,Queue 架构是完全分布式,和平台无关。例如,您可以在一个(或多个)节点(进程)中运行一些 Queue 生产者、消费者,而在其他节点上的运行其他生产者和消费者。 本章介绍 @midwayjs/bull 包。我们还建议阅读 [Bull 文档](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md) 以了解更多背景和具体实施细节。 提示 * 1、从 v3.6.0 开始,原有任务调度 `@midwayjs/task` 模块废弃,如果查询历史文档,请参考 [这里](/docs/legacy/task.md)。 * 2、bull 是一个分布式任务管理系统,必须依赖 redis 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/bull@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull": "^4.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 bull 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { //... } ``` ## 一些概念[​](#一些概念 "一些概念的直接链接") Bull 将整个队列分为三个部分 * 1、Queue 队列,管理任务 * 2、Job,每个任务对象,可以对任务进行启停控制 * 3、Processor,任务处理,实际的逻辑执行部分 ## 基础配置[​](#基础配置 "基础配置的直接链接") bull 是一个分布式任务管理器,强依赖于 redis,在 `config.default.ts` 文件中配置。 ``` // src/config/config.default.ts export default { // ... bull: { // 默认的队列配置 defaultQueueOptions: { redis: `redis://127.0.0.1:32768`, } }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... bull: { defaultQueueOptions: { redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, } }, } ``` 所有的队列都会复用该配置。 ## 编写任务处理器[​](#编写任务处理器 "编写任务处理器的直接链接") 使用 `@Processor` 装饰器装饰一个类,用于快速定义一个任务处理器(这里我们不使用 Job,避免后续的歧义)。 `@Processor` 装饰器需要传递一个 Queue (队列)的名字,在框架启动时,如果没有名为 `test` 的队列,则会自动创建。 比如,我们在 `src/queue/test.queue.ts` 文件中编写如下代码。 ``` // src/queue/test.queue.ts import { Processor, IProcessor } from '@midwayjs/bull'; @Processor('test') export class TestProcessor implements IProcessor { async execute() { // ... } } ``` 在启动时,框架会自动查找并初始化上述处理器代码,同时自动创建一个名为 `test` 的 Queue。 ## 执行任务[​](#执行任务 "执行任务的直接链接") 当定义完 Processor 之后,由于并未指定 Processor 如何执行,我们还需要手动执行它。 通过获取对应的队列,我们可以很方便的来执行任务。 ### 手动执行任务[​](#手动执行任务 "手动执行任务的直接链接") 比如,我们可以在项目启动后执行。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; //... async onServerReady() { // 获取 Processor 相关的队列 const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue(); } } ``` ### 增加执行参数[​](#增加执行参�数 "增加执行参数的直接链接") 我们也可以在执行时,附加一些默认参数。 ``` @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { // params.aaa => 1 } } // invoke const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue({ aaa: 1, bbb: 2, }); ``` ### 任务状态和管理[​](#任务状态和管理 "任务状态和管理的直接链接") 执行 `addJobToQueue` 后,我们可以获取到一个 `Job` 对象。 ``` // invoke const testQueue = this.bullFramework.getQueue('test'); const job = await testQueue?.addJobToQueue(); ``` 通过这个 Job 对象,我们可以做进度管理。 ``` // 更新进度 await job.progress(60); // 获取进度 const progress = await job.process(); // => 60 ``` 获取任务状态。 ``` const state = await job.getState(); // state => 'delayed' 延迟状态 // state => 'completed' 完成状态 ``` 更多的 Job API,请查看 [文档](https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md)。 ### 延迟执行[​](#延迟执行 "延迟执行的直接链接") 执行任务时,也有一些额外的选项。 比如,延迟 1s 执行。 ``` const testQueue = this.bullFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue({}, { delay: 1000 }); ``` ### 中间件和错误处理[​](#中间件和错误处理 "中间件和错误处理的直接链接") Bull 组件包含可以独立启动的 Framework,有着自己的 App 对象和 Context 结构。 我们可以对 bull 的 App 配置独立的中间件和错误过滤器。 ``` @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @App('bull') bullApp: bull.Application; //... async onReady() { this.bullApp.useMiddleare( /*中间件*/); this.bullApp.useFilter( /*过滤器*/); } } ``` ### 上下文[​](#上下文 "上下文的直接链接") 任务处理器执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { jobId: JobId; job: Job, from: new (...args) => IProcessor; } ``` 我们可以直接从 ctx 中访问当前的 Job 对象。 ``` // src/queue/test.queue.ts import { Processor, IProcessor, Context } from '@midwayjs/bull'; @Processor('test') export class TestProcessor implements IProcessor { @Inject() ctx: Context; async execute() { // ctx.jobId => xxxx } } ``` ### 更多任务选项[​](#更多任务选项 "更多任务选项的直接链接") 除了上面的 delay 之外,还有更多的执行选项。 | 选项 | 类型 | 描述 | | ---------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | priority | number | 可选的优先级值。范围从 1(最高优先级)到 MAX\_INT(最低优先级)。请注意,使用优先级对性能有轻微影响,因此请谨慎使用。 | | delay | number | 等待可以处理此作业的时间量(毫秒)。请注意,为了获得准确的延迟,服务器和客户端都应该同步它们的时钟。 | | attempts | number | 在任务完成之前尝试尝试的总次数。 | | repeat | RepeatOpts | 根据 cron 规范的重复任务配置,更多可以查看 [RepeatOpts](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueadd),以及下面的重复任务介绍。 | | backoff | number \| BackoffOpts | 任务失败时自动重试的回退设置。请参阅 [BackoffOpts](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueadd)。 | | lifo | boolean | 如果为 true,则将任务添加到队列的右端而不是左端(默认为 false)。 | | timeout | number | 任务因超时错误而失败的毫秒数。 | | jobId | number \| string | 覆盖任务 id - 默认情况下,任务 id 是唯一整数,但您可以使用此设置覆盖它。如果您使用此选项,则由您来确保 jobId 是唯一的。如果您尝试添加一个 id 已经存在的任务,它将不会被添加。 | | removeOnComplete | boolean \| number | 如果为 true,则在成功完成后删除任务。如果设置数字,则为指定要保留的任务数量。默认行为是任务信息保留在已完成列表中。 | | removeOnFail | boolean \| number | 如果为 true,则在所有尝试后都失败时删除任务。如果设置数字,指定要保留的任务数量。默认行为是将任务信息保留在失败列表中。 | | stackTraceLimit | number | 限制将在堆栈跟踪中记录的堆栈跟踪行的数量。 | ## 重复执行的任务[​](#重复执行的任务 "重复执行的任务的直接链接") 除了手动执行的方式,我们也可以通过 `@Processor` 装饰器的参数,快速配置任务的重复执行。 ``` import { Processor, IProcessor } from '@midwayjs/bull'; import { FORMAT } from '@midwayjs/core'; @Processor('test', { repeat: { cron: FORMAT.CRONTAB.EVERY_PER_5_SECOND } }) export class TestProcessor implements IProcessor { @Inject() logger; async execute() { // ... } } ``` ## 常用 Cron 表达式[​](#常用-cron-表达式 "常用 Cron 表达式的直接链接") 关于 Cron 表达式,格式如下。 ``` * * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional) ``` 常见表达式: * 每隔5秒执行一次:`*/5 * * * * *` * 每隔1分钟执行一次:`0 */1 * * * *` * 每小时的20分执行一次:`0 20 * * * *` * 每天 0 点执行一次:`0 0 0 * * *` * 每天的两点35分执行一次:`0 35 2 * * *` 可以使用 [在线工具](https://cron.qqe2.com/) 执行确认下一次执行的时间。 Midway 在框架侧提供了一些常用的表达式,放在 `@midwayjs/core` 中供大家使用。 ``` import { FORMAT } from '@midwayjs/core'; // 每分钟执行的 cron 表达式 FORMAT.CRONTAB.EVERY_MINUTE ``` 内置的还有一些其他的表达式。 | 表达式 | 对应时间 | | --------------------------------- | --------------- | | CRONTAB.EVERY\_SECOND | 每秒钟 | | CRONTAB.EVERY\_MINUTE | 每分钟 | | CRONTAB.EVERY\_HOUR | 每小时整点 | | CRONTAB.EVERY\_DAY | 每天 0 点 | | CRONTAB.EVERY\_DAY\_ZERO\_FIFTEEN | 每天 0 点 15 分 | | CRONTAB.EVERY\_DAY\_ONE\_FIFTEEN | 每天 1 点 15 分 | | CRONTAB.EVERY\_PER\_5\_SECOND | 每隔 5 秒 | | CRONTAB.EVERY\_PER\_10\_SECOND | 每隔 10 秒 | | CRONTAB.EVERY\_PER\_30\_SECOND | 每隔 30 秒 | | CRONTAB.EVERY\_PER\_5\_MINUTE | 每隔 5 分钟 | | CRONTAB.EVERY\_PER\_10\_MINUTE | 每隔 10 分钟 | | CRONTAB.EVERY\_PER\_30\_MINUTE | 每隔 30 分钟 | ## 高级配置[​](#高级配置 "高级配置的直接链接") ### 清理之前的任务[​](#清理之前的任务 "清理之前的任务的直接链接") 在默认情况下,框架会自动清理前一次未调度的 **重复执行任务**,保持每一次的重复执行的任务队列为最新。如果在某些环境不需要清理,可以单独关闭。 比如你不需要清理重复: ``` // src/config/config.prod.ts export default { // ... bull: { clearRepeatJobWhenStart: false, }, } ``` 提示 如果不清理,如果前一次队列为 10s 执行,现在修改为 20s 执行,则两个定时都会存储在 Redis 中,导致代码重复执行。 在日常的开发中,如果不清理,很容易出现代码重复执行这个问题。但是在集群部署的场景,多台服务器轮流重启的情况下,可能会导致定时任务被意外清理,请评估开关的时机。 也可以在启动时手动清理所有任务。 ``` // src/configuration.ts import { Configuration, App, Inject } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { join } from 'path'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [koa, bull], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; @Inject() bullFramework: bull.Framework; async onReady() { // 在这个阶段,装饰器队列还未创建,使用 API 提前手动创建队列,装饰器会复用同名队列 const queue = this.bullFramework.createQueue('user'); // 通过队列手动执行清理 await queue.obliterate({ force: true }); } } ``` ### 清理任务历史记录[​](#清理任务历史记录 "清理任务历史记录的直接链接") 当开启 Redis 后,默认情况下,bull 会记录所有的成功和失败的任务 key,这可能会导致 redis 的 key 暴涨,我们可以配置成功或者失败后清理的选项。 默认情况下 * 成功时保留的任务记录为 3 条 * 失败保留的任务记录为 10 条 也可以通过参数进行配置。 比如在装饰器配置。 ``` import { FORMAT } from '@midwayjs/core'; import { IProcessor, Processor } from '@midwayjs/bull'; @Processor('user', { repeat: { cron: FORMAT.CRONTAB.EVERY_MINUTE, }, removeOnComplete: 3, // 成功后移除任务记录,最多保留最近 3 条记录 removeOnFail: 10, // 失败后移除任务记录 }) export class UserService implements IProcessor { execute(data: any) { // ... } } ``` 也可以在全局 config 中配置。 ``` // src/config/config.default.ts export default { // ... bull: { defaultQueueOptions: { // 默认的任务配置 defaultJobOptions: { // 保留 10 条记录 removeOnComplete: 10, }, }, }, } ``` ### Redis 集群[​](#redis-集群 "Redis 集群的直接链接") 可以使用 bull 提供的 `createClient` 方式来接入自定义的 redis 实例,这样你可以接入 Redis 集群。 比如: ``` // src/config/config.default import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, // 一定要是false retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null // 一定要是null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { bull: { defaultQueueOptions: { createClient: (type, opts) => { return redisClientInstance; }, // 这些任务存储的 key,都是相同开头,以便区分用户原有 redis 里面的配置 prefix: '{midway-bull}', }, } } ``` ## 队列管理[​](#队列管理 "队列管理的直接链接") 队列是廉价的,每个 Job 都会绑定一个队列,在一些情况下,我们也可以手动对队列进行管理操作。 ### 手动创建队列[​](#手动创建队列 "手动创建队列的直接链接") 除了使用 `@Processor` 简单定义队列,我们还可以使用 API 进行创建。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; @Configuration({ imports: [ // ... bull ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; async onReady() { const testQueue = this.bullFramework.createQueue('test', { redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, prefix: '{midway-bull}', }); // ... } } ``` 通过 `createQueue` 手动创建队列后,队列依旧会自动保存。如果在启动时 `@Processor` 使用了该队列名,则会自动使用已经创建好的队列。 比如: ``` // 会自动使用上面手动创建的同名队列 @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { } } ``` ### 获取队列[​](#获取队列 "获取队列的直接链接") 我们可以简单的根据队列名获取队列。 ``` const testQueue = bullFramework.getQueue('test'); ``` 也可以通过装饰器来获取。 ``` import { InjectQueue, BullQueue } from '@midwayjs/bull'; import { Provide } from '@midwayjs/core'; @Provide() export class UserService { @InjectQueue('test') testQueue: BullQueue; async invoke() { await this.testQueue.pause(); // ... } } ``` ### 队列常用操作[​](#队列常用操作 "队列常用操作的直接链接") 暂停队列。 ``` await testQueue.pause(); ``` 继续队列。 ``` await testQueue.resume(); ``` 队列事件。 ``` // Local events pass the job instance... testQueue.on('progress', function (job, progress) { console.log(`Job ${job.id} is ${progress * 100}% ready!`); }); testQueue.on('completed', function (job, result) { console.log(`Job ${job.id} completed! Result: ${result}`); job.remove(); }); ``` 完整队列 API 请参考 [这里](https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md)。 ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-bull.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { clients: { // ... bullLogger: { fileLogName: 'midway-bull.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { bull: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`; }, } } ``` ## 关于 Redis 版本[​](#关于-redis-版本 "关于 Redis 版本的直接链接") 请尽可能选择最新的版本( >=5 ),目前在低版本 redis 上有发现定时任务创建失败的问题。 ## Bull UI[​](#bull-ui "Bull UI的直接链接") 在分布式场景中,我们可以资利用 Bull UI 来简化管理。 和 bull 组件类似,需要独立安装和启用。 ``` $ npm i @midwayjs/bull-board@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull-board": "^4.0.0", // ... }, } ``` 将 bull-board 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bull, bullBoard, ] }) export class MainConfiguration { //... } ``` 默认的访问路径为:`http://127.1:7001/ui`。 效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01j4wEFb1UacPxA06gs_!!6000000002534-2-tps-1932-1136.png) 可以通过配置进行基础路径的修改。 ``` // src/config/config.prod.ts export default { // ... bullBoard: { basePath: '/ui', }, } ``` 此外,组件提供了 `BullBoardManager` ,可以添加动态创建的队列。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bull from '@midwayjs/bull'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bull, bullBoard ] }) export class MainConfiguration { @Inject() bullFramework: bull.Framework; @Inject() bullBoardManager: bullBoard.BullBoardManager; async onServerReady() { const testQueue = this.bullFramework.createQueue('test', { // ... }); this.bullBoardManager.addQueue(new bullBoard.BullAdapter(testQueue); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、EVALSHA 错误[​](#1evalsha-错误 "1、EVALSHA 错误的直接链接") ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01KfjCKT1yypmNPDkIL_!!6000000006648-2-tps-3540-102.png) 这个问题基本明确,问题会出现在 redis 的集群版本上。 原因是 redis 会对 key 做 hash 来确定存储的 slot,集群下这一步 @midwayjs/bull 的 key 命中了不同的 slot。 解决方案: task 里的 prefix 配置用 包括,强制 redis 只计算 里的hash,例如 `prefix: '{midway-task}'`。 ### 2、EVAL inside MULTI is not allowed 错误[​](#2eval-inside-multi-is-not-allowed-错误 "2、EVAL inside MULTI is not allowed 错误的直接链接") 表现为 `queue.createBulk()`、`job.moveToFailed()` 等任务队列 API 调用无效,并出现下面的错误。 ``` ReplyError: EXECABORT Transaction discarded because of previous errors. at parseError (/node_modules/redis-parser/lib/parser.js:179:12) at parseType (/node_modules/redis-parser/lib/parser.js:302:14) { command: { name: 'exec', args: [] }, previousErrors: [ ReplyError: ERR 'EVAL' inside MULTI is not allowed at parseError (/node_modules/redis-parser/lib/parser.js:179:12) at parseType (/node_modules/redis-parser/lib/parser.js:302:14) { command: [Object] } ] } ``` 提示 常出现于使用阿里云 Redis 服务。 由于这些 API 依赖的 Redis Lua 脚本中使用了 EVAL 或者 EVALSHA,阿里云 Redis 使用代理模式连接时,会对 Lua 脚本调用做额外限制,包括 [不允许在 MULTI 事务中执行 EVAL 命令](https://help.aliyun.com/zh/redis/support/usage-of-lua-scripts?#section-8f7-qgv-dlv),文档中还提到可以通过参数配置 script\_check\_enable 关闭这一校验,但是验证无效。 解决方案: * 1、在阿里云控制台操作开启直连地址,将服务切换到直连模式 * 2、客户端切换成集群模式,参考上述「Redis 集群」章节,切换配置方式 --- # 任务队列 队列是一种强大的设计模式,可帮助您应对常见的应用程序扩展和性能挑战。队列可以帮助您解决的一些问题: * 平滑处理峰值。可以在任意时间启动资源密集型任务,然后将这些任务添加到队列中,而不是同步执行。让任务进程以受控方式从队列中提取任务。也可以轻松添加新的队列消费者以扩展后端任务处理。 * 分解可能会阻塞 Node.js 事件循环的单一任务。比如用户请求需要像音频转码这样的 CPU 密集型工作,就可以将此任务委托给其他进程,从而释放面向用户的进程以保持响应。 * 提供跨各种服务的可靠通信渠道。例如,您可以在一个进程或服务中排队任务(作业),并在另一个进程或服务中使用它们。在任何流程或服务的作业生命周期中完成、错误或其他状态更改时,您都可以收到通知(通过监听状态事件)。当队列生产者或消费者失败时,它们的状态被保留,并且当节点重新启动时任务处理可以自动重新启动。 Midway 提供了 `@midwayjs/bullmq` 包作为 [BullMQ](https://github.com/taskforcesh/bullmq) 之上的抽象/包装器。BullMQ 是 Bull 的下一代实现,提供了更好的性能和更多的功能。该软件包可以轻松地将 BullMQ 以友好的方式集成到您的应用程序中。 BullMQ 使用 Redis 来保存作业数据,在使用 Redis 时,Queue 架构是完全分布式,和平台无关。例如,您可以在一个(或多个)节点(进程)中运行一些 Queue 生产者、消费者,而在其他节点上的运行其他生产者和消费者。 提示 BullMQ 是一个分布式任务管理系统,必须依赖 redis 警告 由于 BullMQ 是 Bull 的升级版,从 v3.20 开始,将由 BullMQ 替代 Bull 组件,如需使用 Bull 组件,请参考 [Bull 文档](/docs/extensions/bull.md) 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/bullmq@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bullmq": "^4.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 bullmq 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ // ... bullmq ] }) export class MainConfiguration { //... } ``` ## 一些概念[​](#一些概念 "一些概念的直接链接") BullMQ 将整个队列分为以下几个部分: * Queue:队列,管理任务 * Job:每个任务对象,可以对任务进行启停控制 * Worker:任务处理器,实际的逻辑执行部分 * QueueEvents:队列事件,用于监听任务状态变化 * FlowProducer:任务流生产者,用于创建任务依赖关系 ## 基础配置[​](#基础配置 "基础配置的直接链接") bullmq 是一个分布式任务管理器,强依赖于 redis,在 `config.default.ts` 文件中配置。 ``` // src/config/config.default.ts export default { // ... bullmq: { defaultConnection: { host: '127.0.0.1', port: 6379, }, // 可选,队列前缀 defaultPrefix: '{midway-bullmq}', }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... bullmq: { defaultConnection: { port: 6379, host: '127.0.0.1', password: 'foobared', } }, } ``` 所有的队列、任务处理器、队列事件、任务流都会复用该配置。 ## 编写任务处理器[​](#编写任务处理器 "编写任务处理器的直接链接") 使用 `@Processor` 装饰器装饰一个类,用于快速定义一个任务处理器。 `@Processor` 装饰器需要传递一个 Queue(队列)的名字,在框架启动时,如果没有名为 `test` 的队列,则会自动创建。 比如,我们在 `src/processor/test.processor.ts` 文件中编写如下代码。 ``` import { Processor, IProcessor } from '@midwayjs/bullmq'; @Processor('test') export class TestProcessor implements IProcessor { async execute(data: any) { // 处理任务逻辑 console.log('processing job:', data); } } ``` ## 执行任务[​](#执行任务 "执行任务的直接链接") 当定义完 Processor 之后,由于并未指定 Processor 如何执行,我们还需要手动执行它。 ### 手动执行任务[​](#手动执行任务 "手动执行任务的直接链接") ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ bullmq ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; async onServerReady() { // 获取 Processor 相关的队列 const testQueue = this.bullmqFramework.getQueue('test'); // 立即添加这个任务 await testQueue?.addJobToQueue(); } } ``` ### 增加执行参数[​](#增加执行参数 "增加执行参数的直接链接") 我们也可以在执行时,附加一些参数。 ``` @Processor('test') export class TestProcessor implements IProcessor { async execute(params) { // params.name => 'harry' } } // invoke const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({ aaa: 1, bbb: 2, }); ``` ### 任务状态和管理[​](#任务状态和管理 "任务状态和管理的直接链接") 执行 `addJobToQueue` 后,我们可以获取到一个 `Job` 对象。 ``` const testQueue = this.bullmqFramework.getQueue('test'); const job = await testQueue?.addJobToQueue(); // 更新进度 await job.updateProgress(60); // 获取进度 const progress = await job.progress; // => 60 // 获取任务状态 const state = await job.getState(); // state => 'delayed' 延迟状态 // state => 'completed' 完成状态 // state => 'failed' 失败状态 ``` ### 延迟执行[​](#延迟执行 "延迟执行的直接链接") 执行任务时,也有一些额外的选项。 比如,延迟 1s 执行。 ``` const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({}, { delay: 1000 }); ``` ### 任务重试[​](#任务重试 "任务重试的直接链接") BullMQ 支持任务失败重试机制。 ``` const testQueue = this.bullmqFramework.getQueue('test'); await testQueue?.addJobToQueue({}, { attempts: 3, // 最多重试 3 次 backoff: { // 重试策略 type: 'exponential', // 指数退避 delay: 1000 // 初始延迟 1 秒 } }); ``` ### 任务优先级[​](#任务优先级 "任务优先级的直接链接") 可以为任务设置优先级,优先级高的任务会优先执行。 ``` const testQueue = this.bullmqFramework.getQueue('test'); // priority 值越大优先级越高 await testQueue?.addJobToQueue({ priority: 1 }, { priority: 3 }); // 高优先级 await testQueue?.addJobToQueue({ priority: 2 }, { priority: 2 }); // 中优先级 await testQueue?.addJobToQueue({ priority: 3 }, { priority: 1 }); // 低优先级 ``` ### 中间件和错误处理[​](#中间件和错误处理 "中间件和错误处理的直接链接") BullMQ 组件包含可以独立启动的 Framework,有着自己的 App 对象和 Context 结构。 我们可以对 bullmq 的 App 配置独立的中间件和错误过滤器。 ``` @Configuration({ imports: [ bullmq ] }) export class MainConfiguration { @App('bullmq') bullmqApp: bullmq.Application; async onReady() { this.bullmqApp.useMiddleware(/*中间件*/); this.bullmqApp.useFilter(/*过滤器*/); } } ``` ### 上下文[​](#上下文 "上下文的直接链接") 任务处理器执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { jobId: string; job: Job; token?: string; from: new (...args) => IProcessor; } ``` 我们可以直接从 ctx 中访问当前的 Job 对象。 ``` import { Processor, IProcessor, Context } from '@midwayjs/bullmq'; @Processor('test') export class TestProcessor implements IProcessor { @Inject() ctx: Context; async execute(data: any) { // ctx.jobId => 当前任务ID // ctx.job => 当前任务对象 } } ``` ## 重复执行的任务[​](#重复执行的任务 "重复执行的任务的直接链接") 除了手动执行的方式,我们也可以通过 `@Processor` 装饰器的参数,快速配置任务的重复执行。 ``` import { Processor, IProcessor } from '@midwayjs/bullmq'; import { FORMAT } from '@midwayjs/core'; @Processor('test', { repeat: { pattern: FORMAT.CRONTAB.EVERY_PER_5_SECOND } }) export class TestProcessor implements IProcessor { async execute() { // 每 5 秒执行一次 } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 任务流(Flow Producer)[​](#任务流flow-producer "任务流(Flow Producer)的直接链接") BullMQ 支持创建任务依赖关系,形成任务流。 ``` const flowProducer = bullmqFramework.createFlowProducer({}, 'test-flow'); // 创建任务流 await flowProducer.add({ name: 'flow-test', queueName: 'flow-queue-1', data: { value: 1 }, children: [ { name: 'child-job', queueName: 'flow-queue-2', data: { value: 2 } } ] }); ``` ### 队列事件[​](#队列事件 "队列事件的直接链接") BullMQ 提供了丰富的事件系统,可以监听任务的各种状态变化。 ``` const eventQueue = bullmqFramework.createQueue('event-queue'); const queueEvents = eventQueue.createQueueEvents(); // 监听任务完成事件 queueEvents.on('completed', ({ jobId }) => { console.log(`Job ${jobId} completed!`); }); // 监听任务失败事件 queueEvents.on('failed', ({ jobId, failedReason }) => { console.log(`Job ${jobId} failed: ${failedReason}`); }); ``` ### 清理任务历史记录[​](#清理任务历史记录 "清理任务历史记录的直接链接") 当开启 Redis 后,默认情况下,bullmq 会记录所有的成功和失败的任务 key,这可能会导致 redis 的 key 暴涨,我们可以配置成功或者失败后清理的选项。 ``` // src/config/config.default.ts export default { bullmq: { defaultQueueOptions: { defaultJobOptions: { removeOnComplete: 3, // 成功后只保留最近 3 条记录 removeOnFail: 10, // 失败后只保留最近 10 条记录 } } } } ``` ### Redis 集群[​](#redis-集群 "Redis 集群的直接链接") bullmq 可以指定 connection 实例,你可以将自己创建的 Redis 实例配置到 `defaultConnection` 中,这样就可以接入 Redis 集群。 ``` // src/config/config.default.ts import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { bullmq: { defaultConnection: redisClientInstance, defaultPrefix: '{midway-bullmq}', } } ``` ### 获取任务处理器[​](#获取任务处理器 "获取任务处理器的直接链接") 通过内置的方法,我们可以获取到原始的任务处理器(Worker)。 可以启动任意多个 Worker 监听同一个队列,在这种情况下 BullMQ 会把队列中的任务轮流(round-robin)分配给这些 Worker。 当队列中有任务被添加时,BullMQ 会在这两个 Worker 之间自动分配任务。 我们可以通过方法 `getWorker` 获取到首个监听的 Worker 对象,也可以通过方法 `getWorkers` 获取到该队列监听的所有 Worker 对象。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; @Configuration({ imports: [ // ... bullmq, ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; async onServerReady() { const testWorker = this.bullmqFramework.getWorker('test'); const allWorkers = this.bullmqFramework.getWorkers('test'); } } ``` ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-bullmq.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { clients: { bullMQLogger: { fileLogName: 'midway-bullmq.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { bullmq: { contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`; }, } } ``` ## BullMQ 原始对象[​](#bullmq-原始对象 "BullMQ 原始对象的直接链接") 组件导出了 BullMQ 的原始对象,可以进行更多的操作。 ``` import { BullMQ } from '@midwayjs/bullmq'; ``` 你可以通过 `BullMQ` 对象,获取到 `Queue`、`Worker`、`FlowProducer` 等对象定义。 ## Bull UI[​](#bull-ui "Bull UI的直接链接") 在分布式场景中,我们可以资利用 Bull UI 来简化管理。 和 bull 组件类似,需要独立安装和启用。 ``` $ npm i @midwayjs/bull-board@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/bull-board": "^4.0.0", // ... }, } ``` 将 bull-board 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bullmq, bullBoard, ] }) export class MainConfiguration { //... } ``` 默认的访问路径为:`http://127.1:7001/ui`。 效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01j4wEFb1UacPxA06gs_!!6000000002534-2-tps-1932-1136.png) 可以通过配置进行基础路径的修改。 ``` // src/config/config.prod.ts export default { // ... bullBoard: { basePath: '/ui', }, } ``` 此外,组件提供了 `BullBoardManager` ,可以添加动态创建的队列。 ``` import { Configuration, Inject } from '@midwayjs/core'; import * as bullmq from '@midwayjs/bullmq'; import * as bullBoard from '@midwayjs/bull-board'; @Configuration({ imports: [ // ... bullmq, bullBoard ] }) export class MainConfiguration { @Inject() bullmqFramework: bullmq.Framework; @Inject() bullBoardManager: bullBoard.BullBoardManager; async onServerReady() { const testQueue = this.bullmqFramework.createQueue('test', { // ... }); this.bullBoardManager.addQueue(new bullBoard.BullMQAdapter(testQueue) as any); } } ``` 由于最新 bull-board 要求最低 Node.js 版本为 v20,所以 Midway v3 无法将 bull-board 升级;在 v5.23.0 版本下的 `bull-board` 存在类型定义问题,采用 `as any` 的方式绕过。 --- # 文件上传 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用上传组件,支持 `file` (服务器临时文件) 和 `stream` (流)两种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 提示 本模块自 3.17.0 起替换 upload 组件。 和 upload 组件的差异为: * 1、配置的 key 从 `upload` 调整为 `busboy` * 2、中间件不再默认加载,手动可配置到全局或者路由 * 3、入参定义类型调整为 `UploadStreamFileInfo` * 4、`fileSize` 的配置有调整 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/busboy@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/busboy": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; @Configuration({ imports: [ // ...other components busboy ], // ... }) export class MainConfiguration {} ``` ## 配置中间件[​](#配置中间件 "配置中间件的直接链接") 组件中提供了 `UploadMiddleware` 这个中间件,可以将其配置到全局或者特定路由,推荐配置到特定路由,提升性能。 **路由中间件** ``` import { Controller, Post } from '@midwayjs/core'; import { UploadMiddleware } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', { middleware: [UploadMiddleware] }) async upload(/*...*/) { // ... } } ``` **全局中间件** * @midwayjs/koa * @midwayjs/web * @midwayjs/express * @midwayjs/faas ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @App('koa') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/web'; @Configuration({ // ... }) export class MainConfiguration { @App('egg') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/express'; @Configuration({ // ... }) export class MainConfiguration { @App('express') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ``` // src/configuratin.ts import { Configuration } from '@midwayjs/core'; import * as busboy from '@midwayjs/busboy'; import { Application } from '@midwayjs/faas'; @Configuration({ // ... }) export class MainConfiguration { @App('faas') app: Application; async onReady() { this.app.useMiddleware(busboy.UploadMiddleware); } } ``` ## 配置[​](#配置 "配置的直接链接") 组件使用 `busboy` 作为配置的 key。 ### 上传模式[​](#上传模式 "上传模式的直接链接") 上传分为三种模式,文件模式,流式模式以及新增的异步迭代器模式。 代码中使用 `@Files()` 装饰器获取上传的文件, `@Fields` 装饰器获取其他上传表单字段。 * 文件模式 * 异步迭代器模式 * 流模式 `file` 为默认值,配置 mode 为 `file` 字符串。 ``` // src/config/config.default.ts export default { // ... busboy: { mode: 'file', }, } ``` 在代码中获取上传的文件,支持同时上传多个文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadFileInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload(@Files() files: Array, @Fields() fields: Record) { /* files = [ { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // 服务器临时文件地址 mimeType: 'application/pdf', // mime fieldName: 'file' // field name }, ] */ } } ``` 使用 file 模式时, 获取的 `data` 为上传的文件在服务器的 `临时文件地址`,后续可以再通过 `fs.createReadStream` 等方式来处理此文件内容,支持同时上传多个文件,多个文件会以数组的形式存放。 每个数组内的对象包含以下几个字段 ``` export interface UploadFileInfo { /** * 上传的文件名 */ filename: string; /** * 上传文件 mime 类型 */ mimeType: string; /** * 上传服务端保存的路径 */ data: string; /** * 上传的表单字段名 */ fieldName: string; } ``` 从 `v3.18.0` 提供,替代原有的 `stream` 模式,该模式支持多个文件流式上传。 配置 mode 为 `asyncIterator` 字符串。 ``` // src/config/config.default.ts export default { // ... busboy: { mode: 'asyncIterator', }, } ``` 在代码中获取上传的文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload( @Files() fileIterator: AsyncGenerator, @Fields() fieldIterator: AsyncGenerator ) { // ... } } ``` 在该模式下,`@Files` 和 `@File` 装饰器会提供同一个 `AsyncGenerator` ,而 `@Fields` 会也同样会提供一个 `AsyncGenerator`。 通过循环 `AsyncGenerator` ,可以针对每个上传文件的 `ReadStream` 做处理。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy'; import { tmpdir } from 'os'; import { createWriteStream } from 'fs'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload( @Files() fileIterator: AsyncGenerator, @Fields() fieldIterator: AsyncGenerator ) { for await (const file of fileIterator) { const { filename, data } = file; const p = join(tmpdir, filename); const stream = createWriteStream(p); data.pipe(stream); } for await (const { name, value } of fieldIterator) { // ... } // ... } } ``` 注意,如果一次上传中任意一个文件抛出了错误,本次上传流会直接关闭,所有未传输完成的文件都会异常。 异步迭代器中的上传对象包含以下几个字段。 ``` export interface UploadStreamFieldInfo { /** * 上传的文件名 */ filename: string; /** * 上传文件 mime 类型 */ mimeType: string; /** * 上传文件的文件流 */ data: Readable; /** * 上传的表单字段名 */ fieldName: string; } ``` 异步迭代器中的 `@Fields` 的对象略有不同,返回的数据会包含 `name` 和 `value` 字段。 ``` export interface UploadStreamFieldInfo { /** * 表单名 */ name: string; /** * 表单值 */ value: any; } ``` 警告 不再推荐使用。 配置 mode 为 `stream` 字符串。 使用 stream 模式时,通过 `@Files` 中获取的 `data` 为 `ReadStream`,后续可以再通过 `pipe` 等方式继续将数据流转至其他 `WriteStream` 或 `TransformStream`。 使用 stream 模式时,仅同时上传一个文件,即 `@Files` 数组中只有一个文件数据对象。 另外,stream 模式 `不会` 在服务器上产生临时文件,所以获取到上传的内容后无需手动清理临时文件缓存。 提示 faas 场景实现方式视平台而定,如果平台不支持流式请求/响应但是业务开启了 `mode: 'stream'`,将采用先读取到内存,再模拟流式传输来降级处理。 在代码中获取上传的文件,流式模式下仅支持单个文件。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadStreamFileInfo } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload', /*...*/) async upload(@Files() files: Array, @Fields() fields: Record { if (ctx.path === '/') { return [ '.jpg', '.jpeg', ]; } else { return [ '.jpg', ] }; }, // ... }, } ``` ### 上传文件 MIME 类型检查[​](#上传文件-mime-类型检查 "上传文件 MIME 类型检查的直接�链接") 部分`恶意用户`,会尝试将 `.php` 等 WebShell 修改扩展名为 `.jpg`,来绕过基于扩展名的白名单过滤规则,在某些服务器环境内,这个 jpg 文件依然会被作为 PHP 脚本来执行,造成安全风险。 组件提供了 `mimeTypeWhiteList` 配置参数 **【请注意,此参数无默认值设置,即默认不校验】**,您可以通过此配置设置允许的文件 MIME 格式,规则为由数组 `[扩展名, mime, [...moreMime]]` 组成的 `二级数组`,例如: ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/busboy'; export default { // ... busboy: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: { '.jpg': 'image/jpeg', // 也可以设置多个 MIME type,比如下面的允许 .jpeg 后缀的文件是 jpg 或者是 png 两种类型 '.jpeg': ['image/jpeg', 'image/png'], // 其他类型 '.gif': 'image/gif', '.bmp': 'image/bmp', '.wbmp': 'image/vnd.wap.wbmp', '.webp': 'image/webp', } }, } ``` 您也可以使用组件提供的 `DefaultUploadFileMimeType` 变量,作为默认的 MIME 校验规则,它提供了常用的 `.jpg`、`.png`、`.psd` 等文件扩展名的 MIME 数据: ``` // src/config/config.default.ts import { uploadWhiteList, DefaultUploadFileMimeType } from '@midwayjs/busboy'; export default { // ... busboy: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: DefaultUploadFileMimeType, }, } ``` 文件格式与对应的 MIME 映射,您可以通过 `https://mimetype.io/` 这个网站来查询,对于文件的 MIME 识别,我们使用的是 [file-type@16](https://www.npmjs.com/package/file-type) 这个 npm 包,请注意它支持的文件类型。 信息 MIME 类型校验规则仅适用于使用 文件上传模式 `mode=file`,同时设置此校验规则之后,由于需要读取文件内容进行匹配,所以会稍微影响上传性能。 但是,我们依然建议您在条件允许的情况下,设置 `mimeTypeWhiteList` 参数,这将提升您的应用程序安全性。 你可以传递一个函数,可以根据不同的条件动态返回 MIME 规则。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... busboy: { mimeTypeWhiteList: (ctx) => { if (ctx.path === '/') { return { '.jpg': 'image/jpeg', }; } else { return { '.jpeg': ['image/jpeg', 'image/png'], } }; } }, } ``` ### Busboy 上传限制[​](#busboy-上传限制 "Busboy 上传限制的直接链接") 默认情况下没有限制,可以通过配置修改,数字类型,单位为 byte。 ``` // src/config/config.default.ts export default { // ... busboy: { // ... limits: { fileSize: 1024 } }, } ``` 除此之外,还可以设置一些其他的 [限制](https://github.com/mscdex/busboy/tree/master?tab=readme-ov-file#exports)。 ### 临时文件与清理[​](#临时文件与清理 "临时文件与清理的直接链接") 如果你使用了 `file` 模式来获取上传的文件,那么上传的文件会存放在您于 `config` 文件中设置的 `upload` 组件配置中的 `tmpdir` 选项指向的文件夹内。 你可以通过在配置中使用 `cleanTimeout` 来控制自动的临时文件清理时间,默认值为 `5 * 60 * 1000`,即上传的文件于 `5 分钟` 后自动清理,设置为 `0` 则视为不开启自动清理功能。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/busboy'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... busboy: { mode: 'file', tmpdir: join(tmpdir(), 'midway-busboy-files'), cleanTimeout: 5 * 60 * 1000, }, } ``` 你也可以在代码中通过调用 `await ctx.cleanupRequestFiles()` 来主动清理当前请求上传的临时文件。 ### 设置不同路由的配置[​](#设置不同路由的配置 "设置不同路由的配置的直接链接") 通过中间件的不同实例,可以对不同的路由做不同的配置,这种场景下会和全局配置合并,仅能覆盖一小部分配置。 ``` import { Controller, Post, Files, Fields } from '@midwayjs/core'; import { UploadFileInfo, UploadMiddleware } from '@midwayjs/busboy'; @Controller('/') export class HomeController { @Post('/upload1', { middleware: [ createMiddleware(UploadMiddleware, {mode: 'file'}) ]}) async upload1(@Files() files Array) { // ... } @Post('/upload2', { middleware: [ createMiddleware(UploadMiddleware, {mode: 'stream'}) ]}) async upload2(@Files() files Array) { // ... } } ``` 当前可以传递的配置包括 `mode` 以及 `busboy` 自带的 [配置](https://github.com/mscdex/busboy/tree/master?tab=readme-ov-file#exports)。 ## 内置错误[​](#内置错误 "内置错误的直接链接") 以下的错误在不同上传模式下均会自动触发。 * `MultipartInvalidFilenameError` 无效文件名 * `MultipartInvalidFileTypeError` 无效文件类型 * `MultipartFileSizeLimitError` 文件大小超出限制 * `MultipartFileLimitError` 文件数量超出限制 * `MultipartPartsLimitError` 上传 parts 数量超出限制 * `MultipartFieldsLimitError` fields 数量超出限制 * `MultipartError` 其余的 busbuy 错误 ## 安全提示[​](#安全提示 "安全提示的直接链接") 1. 请注意是否开启 `扩展名白名单` (whiteList),如果扩展名白名单被设置为 `null`,则会有可能被攻击者所利用上传 `.php`、`.asp` 等WebShell。 2. 请注意是否设置 `match` 或 `ignore` 规则,否则普通的 `POST/PUT` 等接口会有可能被攻击者利用,造成服务器负荷加重和空间大量占用问题。 3. 请注意是否设置 `文件类型规则` (fileTypeWhiteList),否则可能会被攻击者伪造文件类型进行上传。 ## 前端文件上传示例[​](#前端文件上传示例 "前端文件上传示例的直接链接") ### 1. html form 的形式[​](#1-html-form-的形式 "1. html form 的形式的直接链接") ```
Name:
File:
``` ### 2. fetch FormData 方式[​](#2-fetch-formdata-方式 "2. fetch FormData 方式的直接链接") ``` const fileInput = document.querySelector('#your-file-input') ; const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData, }); ``` ## Postman 测试示例[​](#postman-测试示例 "Postman 测试示例的直接链接") ![](https://img.alicdn.com/imgextra/i4/O1CN01iv9ESW1uIShNiRjBF_!!6000000006014-2-tps-2086-1746.png) --- # 缓存 Midway Cache 是为了方便开发者进行缓存操作的组件,它有利于改善项目的性能。它为我们提供了一个数据中心以便进行高效的数据访问。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装[​](#安装 "安装的直接链接") 首先安装相关的组件模块。 ``` $ npm i @midwayjs/cache@4 cache-manager --save $ npm i @types/cache-manager --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cache": "^4.0.0", "cache-manager": "^3.4.1", // ... }, "devDependencies": { "@types/cache-manager": "^3.4.0", // ... } } ``` ## 使用 Cache[​](#使用-cache "使用 Cache的直接链接") Midway 为不同的 cache 存储提供了统一的 API。默认内置了一个基于内存数据存储的数据中心。如果想要使用别的数据中心,开发者也可以切换到例如 mongodb、fs 等模式。 首先,引入 Cache 组件,在 `configuration.ts` 中导入: ``` import { Configuration, App } from '@midwayjs/core'; import * as cache from '@midwayjs/cache'; import { join } from 'path' @Configuration({ imports: [ // ... cache // 导入 cache 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 然后在业务代码中即可注入使用。 ``` import { Inject, Provide } from '@midwayjs/core'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cacheManager: CacheManager; // 依赖注入 CacheManager } ``` 通过提供的 API 来设置,获取缓存数据。 ``` import { Inject, Provide } from '@midwayjs/core'; import { IUserOptions } from '../interface'; import { CacheManager } from '@midwayjs/cache'; @Provide() export class UserService { @Inject() cacheManager: CacheManager; async getUser(options: IUserOptions) { // 设置缓存内容 await this.cacheManager.set(`name`, 'stone-jin'); // 获取缓存内容 let result = await this.cacheManager.get(`name`); return result; } async getUser2(){ //获取缓存内容 let result = await this.cacheManager.get(`name`); return result; } async reset(){ await this.cacheManager.reset(); // 清空对应 store 的内容 } } ``` ### 设置缓存[​](#设置缓存 "设置缓存的直接链接") 我们通过 `await this.cache.set(key, value)` 方法进行设置,此处默认过期时间是10s。 你也可以手动设置 TTL(过期时间),如下: ``` await this.cacheManager.set(key, value, {ttl: 1000}); // ttl的单位为秒 ``` 如果你想要 Cache 不过期,则将 TTL 设置为 null 即可。 ``` await this.cacheManager.set(key, value, {ttl: null}); ``` 同时你也可以通过全局的 `config.default.ts` 中进行设置。 ``` export default { // ... cache: { store: 'memory', options: { max: 100, ttl: 10, // 修改默认的ttl配置 }, } } ``` ### 获取缓存[​](#获取缓存 "获取缓存的直接链接") ``` const value = await this.cacheManager.get(key); ``` 如果获取不到,则为 undefined。 ### 移除缓存[​](#移除缓存 "移除缓存的直接链接") 移除缓存,可以通过 del 方法。 ``` await this.cacheManager.del(key); ``` ### 清空整体store数据(此处是整体清除,需要重点⚠️)[​](#清空整体store数据此处是整体清除需要重点️ "清空整体store数据(此处是整体清除,需要重点⚠️)的直接链接") 比如用户设置了某个 redis 为 store,调用的话,包括非 cache 模块设置的也会清除。 ``` await this.cacheManager.reset(); // 这块需要注意 ``` ## 全局配置[​](#全局配置 "全局配置的直接链接") 当我们引用了这个 cache 组件后,我们能对其进行全局的配置。配置方法跟别的组件类似。 默认的配置: ``` export default { // ... cache: { store: 'memory', options: { max: 100, ttl: 10, }, } } ``` 例如用户可以修改默认的 TTL,也就是过期时间。 ## 其他Cache[​](#其他cache "其他Cache的直接链接") 用户也可以修改 store 方式,在 `config.default.ts` 中进行组件的配置: ``` import * as redisStore from 'cache-manager-ioredis'; export default { // ... cache: { store: redisStore, options: { host: 'localhost', // default value port: 6379, // default value password: '', db: 0, keyPrefix: 'cache:', ttl: 100 }, } } ``` 或者修改为 mongodb 的 cache。 危险 **再次注意⚠️:使用 redis 作为 cache 的时候,代码里面慎用 reset 方法,因为会把整个 redis 给 flushdb,简称数据清空。** ## 相关文档[​](#相关文档 "相关文档的直接链接") 由于 Midway Cache 是基于 cache-manager 封装,所以相关资料用户也可以查询:[cache-manger](https://www.npmjs.com/package/cache-manager)。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、set 和 get 无法得到相同值?[​](#1set-和-get-无法得到相同值 "1、set 和 get 无法得到相同值?的直接链接") 用户使用了 cache 模块,默认是内存式的,例如在本地用 dev 模式,由于是单进程的,那 set 和 ge t最终能达到相同的值。但是用户部署到服务器上面后,由于会有多 worker,相当于第一次请求,落在进程1上,然后第二次落在进程2上,这样获得到空了。 解决办法:参考 其他 Cache 的章节,配置 store 为分布式,例如 redis 的 store 等方式。 --- # 缓存 缓存是一个伟大而简单的技术,有助于提高你的应用程序的性能。本组件提供了缓存相关的能力,你可以将数据缓存到不同的数据源,也可以针对不同场景建立多级缓存,提高数据访问速度。 提示 Midway 提供基于 [cache-manager v5](https://github.com/node-cache-manager/node-cache-manager) 模块重新封装了缓存组件,原有的缓存模块基于 v3 开发不再迭代,如需查看老文档,请访问 [这里](/docs/extensions/cache.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装[​](#安装 "安装的直接链接") 首先安装相关的组件模块。 ``` $ npm i @midwayjs/cache-manager@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cache-manager": "^4.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as cacheManager from '@midwayjs/cache-manager'; import { join } from 'path' @Configuration({ imports: [ // ... cacheManager, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 使用缓存[​](#使用缓存 "使用缓存的直接链接") ### 1、配置缓存[​](#1配置缓存 "1、配置缓存的直接链接") 在使用前,你需要配置缓存所在的位置,比如内置的内存缓存,或者是引入 Redis 缓存,每个缓存对应了一个缓存的 Store。 下面的示例代码,配置了一个名为 `default` 的内存缓存。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', }, }, } } ``` 最常用的场景下,缓存会包含两个参数,配置 `max` 修改缓存的数量,配置 `ttl` 修改缓存的过期时间,单位毫秒。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', options: { max: 100, ttl: 10, }, }, }, } } ``` 提示 * `ttl` 的单位是毫秒 * `max` 代表缓存 key 的最大个数 * 不同的 Store 淘汰 key 的算法不同,内存缓存使用的淘汰算法是 LRU ### 2、使用缓存[​](#2使用缓存 "2、使用缓存的直接链接") 可以通过服务工厂的装饰器获取到实例,可以通过简单的 `get` 和 `set` 方法获取和保存缓存。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @InjectClient(CachingFactory, 'default') cache: MidwayCache; async invoke(name: string, value: string) { // 设置缓存 await this.cache.set(name, value); // 获取缓存 const data = await this.cache.get(name); // ... } } ``` 动态设置 `ttl` 过期时间。 ``` await this.cache.set('key', 'value', 1000); ``` 若要禁用缓存过期,可以将 `ttl` 配置属性设置为 0。 ``` await this.cache.set('key', 'value', 0); ``` 删除单个缓存。 ``` await this.cache.del('key'); ``` 清理整个缓存,可以使用 `reset` 方法。 ``` await this.cacheManager.reset(); ``` 危险 注意,清理整个缓存非常危险,如果使用了 Redis 作为缓存 store,将清空整个 Redis 数据。 除了装饰器之外,也可以通过 API 获取缓存实例。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Inject() cachingFactory: CachingFactory; async invoke() { const caching = await this.cachingFactory.get('default'); // ... } } ``` ### 3、配置多个缓存[​](#3配置多个缓存 "3、配置多个缓存的直接链接") 和其他组件一样,组件支持配置多个缓存实例。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', }, otherCaching: { store: 'memory', } }, } } ``` 可以注入不同的缓存实例。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; @Provide() export class UserService { @InjectClient(CachingFactory, 'default') cache: MidwayCache; @InjectClient(CachingFactory, 'otherCaching') customCaching: MidwayCache; } ``` ### 4、配置不同 Store[​](#4配置不同-store "4、配置不同 Store的直接链接") 组件基于 [cache-manager](https://github.com/node-cache-manager/node-cache-manager) 可以配置不同的缓存 Store,比如最常见的可以配置 Redis Store。 假如项目已经配置了一个 `Redis`,通过组件内置的 `createRedisStore` 方法,可以快速创建一个 Redis Store。 ``` import { createRedisStore } from '@midwayjs/cache-manager'; // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: createRedisStore('default'), options: { ttl: 10, } }, }, }, redis: { clients: { default: { port: 6379, host: '127.0.0.1', } } } } ``` `createRedisStore` 方法可以传递一个已经配置的 redis 实例名,可以和 redis 组件复用实例。 ### 5、配置三方 Store[​](#5配置三方-store "5、配置三方 Store的直接链接") 除了 Redis 之外,用户也可以自行选择 Cache-Manager 的 Store,列表可以参考 [这里](https://github.com/node-cache-manager/node-cache-manager?tab=readme-ov-file#store-engines)。 下面是一个配置 [node-cache-manager-ioredis-yet](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) 的例子。 ``` // src/config/config.default.ts import { redisStore } from 'cache-manager-ioredis-yet'; export default { cacheManager: { clients: { default: { store: redisStore, options: { port: 6379, host: 'localhost', ttl: 10, }, }, }, } } ``` ### 6、多级缓存[​](#6多级缓存 "6、多级缓存的直接链接") [cache-manager](https://github.com/node-cache-manager/node-cache-manager) 支持将多个缓存 Store 聚合到一起,实现多级缓存。 比如我可以创建一个多级缓存将多个缓存 Store 合并到一起。 ``` // src/config/config.default.ts import { createRedisStore } from '@midwayjs/cache-manager'; export default { cacheManager: { clients: { memoryCaching: { store: 'memory', }, redisCaching: { store: createRedisStore('default'), options: { ttl: 10, }, }, multiCaching: { store: ['memoryCaching', 'redisCaching'], options: { ttl: 100, }, }, }, }, redis: { clients: { default: { port: 6379, host: '127.0.0.1', }, }, }, }; ``` 这样 `multiCaching` 这个缓存实例就包含了两级缓存,缓存的优先级从上到下,在查找时,会先查找 `memoryCaching` ,如果内存缓存不存在 key,则继续查找 `redisCaching`。 ### 7、使用多级缓存[​](#7使用多级缓存 "7、使用多级缓存的直接链接") 和普通缓存类似,多级缓存除了 `set`、`get`、`del`方法外,还增加了 `mset` 、`mget`、`mdel` 方法。 ``` import { InjectClient, Provide } from '@midwayjs/core'; import { CachingFactory, MidwayMultiCache } from '@midwayjs/cache-manager'; const userId2 = 456; const key2 = 'user_' + userId; const ttl = 5; @Provide() export class UserService { @InjectClient(CachingFactory, 'multiCaching') multiCache: MidwayMultiCache; async invoke() { // 设置到所有级别的缓存 await this.multiCache.set('foo2', 'bar2', ttl); // 从最高优先级的缓存 Store 中获取 key console.log(await this.multiCache.get('foo2')); // >> "bar2" // 调用每一个 Store 的 del 方法进行删除 await this.multiCache.del('foo2'); // 在所有缓存中设置多个 key,可以多个键值对 await this.multiCache.mset( [ ['foo', 'bar'], ['foo2', 'bar2'], ], ttl ); // mget() 从最高优先级的缓存中获取值 // 如果第一个缓存 Store 中不包含所有的 key, // 继续在下一个缓存 Store 中查找没有找到的 key。 // 这是递归地完成的,直到: // - 所有的 key 都已经查找到值 // - 所有的缓存 Store 都被查找过 console.log(await this.multiCache.mget('key', 'key2')); // >> ['bar', 'bar2'] // 调用每一个 Store 的 mdel 方法进行删除 await this.multiCache.mdel('foo', 'foo2'); } } ``` ### 8、自动刷新[​](#8自动刷新 "8、自动刷新的直接链接") 不管是普通缓存还是多级缓存,都支持后台刷新功能,只需要配置 `refreshThreshold` 的时间,单位为毫秒。 ``` // src/config/config.default.ts export default { cacheManager: { clients: { default: { store: 'memory', options: { refreshThreshold: 3 * 1000, }, }, }, } } ``` 如果设置了 `refreshthreshold`,每次从缓存获取值之后,会检查 `ttl` 的值,如果剩余的 `ttl` 小于 `refreshthreshold` ,则系统将异步更新缓存,同时系统会返回旧值,直到 `ttl` 过期。 提示 * 在多级缓存的情况下,根据优先级顺序找到第一个包含 key 的 Store。 * 如果阈值较低且执行的函数比较慢,key 可能会过期,有可能会遇到并发更新的情况。 * 后台刷新机制目前只支持单个 key。 * 如果没有为 key 设置 `ttl`,则不会触发刷新机制。对于 redis,`ttl` 默认设置为-1。 ## 自动缓存[​](#自动缓存 "自动缓存的直接链接") ### 使用装饰器缓存方法[​](#使用装饰器缓存方法 "使用装饰器缓存方法的直接链接") 可以通过 `@Caching` 装饰器缓存方法的结果,比如缓存 http 响应或者服务调用的结果。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default') async getUser(name: string) { return name; } } ``` 当第一次调用 `getUser` 方法时,会正常执行逻辑,返回结果,装饰器会将结果缓存起来,第二次执行时,如果缓存未失效,则会从缓存中直接返回。 ### 指定缓存的 ttl[​](#指定缓存的-ttl "指定缓存的 ttl的直接链接") 也可以单独设置 `ttl` 。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default', 100) async getUser(name: string) { return name; } } ``` ### 手动指定缓存 key[​](#手动指定缓存-key "手动指定缓存 key的直接链接") 如果对自动生成的 key 不满意,可以手动指定缓存的 key。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; @Provide() export class UserService { @Caching('default', 'customKey', 100) async getUser(name: string) { return name; } } ``` ### 带逻辑的缓存[​](#带逻辑的缓存 "带逻辑的缓存的直接链接") 如果你希望根据一些特定逻辑进行缓存,比如特定参数,或者特定的 Header,可以传递一个工具函数进行逻辑判断。 ``` import { Provide } from '@midwayjs/core'; import { Caching } from '@midwayjs/cache-manager'; function cacheBy({methodArgs, ctx, target}) { if (methodArgs[0] === 'harry' || methodArgs[0] === 'mike') { return 'cache1'; } } @Provide() export class UserService { @Caching('default', cacheBy, 100) async getUser(name: string) { return 'hello ' + name; } } ``` 上面的示例中,`cacheBy` 方法自定义了缓存的逻辑,当方法入参值为 `harry` 或者 `mike` 时,将返回缓存的 `key` ,而其他参数时则跳过缓存。 这个时候执行的结果为: ``` await userService.getUser('harry')); // hello harry await userService.getUser('mike')); // hello harry await userService.getUser('lucy')); // hello lucy ``` `@Caching` 装饰器可以在第二个参数中传递一个方法,这个方法的入参 options 为: * `methodArgs` 当前调用方法的实际参数 * `ctx` 如果是请求作用域,则是当前调用的上下文对象,如果是单例,则该对象为空对象 * `target` 当前调用的实例 方法的返回值为字符串或者布尔值,当返回字符串时,表示以该 key 将方法的结果缓存,当返回 `undefined` 或者 `null` 时,表示跳过缓存。 通过这些参数判断,我们可以实现非常灵活的自定义缓存逻辑。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、多进程下内存缓存 set 和 get 无法得到相同值[​](#1多进程下内存缓存-set-和-get-无法得到相同值 "1、多进程下内存缓存 set 和 get 无法得到相同值的直接链接") 这是正常现象,每个进程的数据是独立的,仅保存在当前进程中。如需跨进程缓存,请使用 Redis 这类分布式缓存系统。 --- # 验证码 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用验证码组件,支持 `图片验证码`、`计算表达式` 等类型验证码。 您也可以通过此组件,来实现 `短信验证码`、`邮件验证码` 等验证能力,但是注意,本组件本身不含发送短信、邮件功能。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/captcha@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/captcha": "^4.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件。 ``` import * as captcha from '@midwayjs/captcha'; @Configuration({ imports: [ // ...other components captcha ], }) export class MainConfiguration {} ``` ## 调用服务[​](#调用服务 "调用服务的直接链接") ``` import { Controller, Inject } from '@midwayjs/core'; import { CaptchaService } from '@midwayjs/captcha'; @Controller('/') export class HomeController { @Inject() ctx; @Inject() captchaService: CaptchaService; // 示例:获取图像验证码 @Get('/get-image-captcha') async getImageCaptcha() { const { id, imageBase64 } = await this.captchaService.image({ width: 120, height: 40 }); return { id, // 验证码 id imageBase64, // 验证码 SVG 图片的 base64 数据,可以直接放入前端的 img 标签内 } } // 示例:获取计算表达式验证码 @Get('/get-formula-captcha') async getFormulaCaptcha() { const { id, imageBase64 } = await this.captchaService.formula({ noise: 1 }); return { id, // 验证码 id imageBase64, // 验证码 SVG 图片的 base64 数据,可以直接放入前端的 img 标签内 } } // 验证验证码是否正确 @Post('/check-captcha') async getCaptcha() { const { id, answer } = this.ctx.request.body; const passed: boolean = await this.captchaService.check(id, answer); if (passed) { return 'passed'; } return 'error'; } // 示例:短信验证码 @Post('/sms-code') async sendSMSCode() { // 验证验证码是否正确 const { id, text: code } = await this.captchaService.text({ size: 4 }); await sendSMS(18888888888, code); return { id } } // 示例:邮件验证码 @Post('/email-code') async sendEmailCode() { // 验证验证码是否正确 const { id, text: code } = await this.captchaService.text({ type: 'number'}); await sendEmail('admin@example.com', code); return { id } } // 示例:将任意文本内容塞入验证码中 @Get('/test-text') async testText() { // 存入内容,获取验证码id const id: string = await this.captchaService.set('123abc'); // 根据验证码id,校验内容是否正确 const passed: boolean = await this.captchaService.check(id, '123abc'); return { passed: passed === true, } } } ``` ## 可用配置[​](#可用配置 "可用配置的直接链接") ``` interface CaptchaOptions { default?: { // 默认配置 // 验证码字符长度,默认 4 个字符 size?: number; // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; // 图形验证码配置,图形中包含一些字符 }, image?: { // 验证码字符长度,默认 4 个字符 size?: number; // 图像验证码中的字符类型,默认为 'mixed' // - 'mixed' 表示 0-9、A-Z 和 a-z // - 'letter' 表示 A-Z 和 a-z // - 'number' 表示 0-9 type?: 'mixed', // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; }, // 计算公式验证码配置,例如返回的图像内容为 1+2,需要用户填入 3 formula?: { // 干扰线条的数量,默认 1 条 noise?: number; // 宽度,默认为 120 像素 width?: number; // 宽度,默认为 40 像素 height?: number; }, // 纯文本验证码配置,基于纯文本验证码可以实现短信验证码、邮件验证码 text?: { // 验证码字符长度,默认 4 个字符 size?: number; // 文本验证码中的字符类型,默认为 'mixed' // - 'mixed' 表示 0-9、A-Z 和 a-z // - 'letter' 表示 A-Z 和 a-z // - 'number' 表示 0-9 type?: 'mixed', }, // 验证码过期时间,默认为 1h expirationTime?: 3600, // 验证码存储的 key 前缀 idPrefix: 'midway:vc', } export const captcha: CaptchaOptions = { default: { // 默认配置 size: 4, noise: 1, width: 120, height: 40, }, image: { // 最终会合并 default 配置 type: 'mixed', }, formula: {}, // 最终会合并 default 配置 text: {}, // 最终会合并 default 配置 expirationTime: 3600, idPrefix: 'midway:vc', } ``` 更多配置请参考 [svg-captcha](https://github.com/produck/svg-captcha)。 ### 配置示例一[​](#配置示例一 "配置示例一的直接链接") 获取一个 包含 `5个纯英文字母` 的图像验证码,图像宽度 `200` 像素,高度 `50` 像素,并且包含 `3` 条干扰线。 因为图像验证码的配置 `image`, 会与 `default` 配置进行合并,所以可以只修改 `default` 配置: ``` export const captcha: CaptchaOptions = { default: { size: 5, noise: 3, width: 200, height: 50 }, image: { type: 'letter' } } ``` 当然,也可以 `不` 修改 `default` 配置,将宽度、高度等在 `image` 配置项中进行配置,取得 `同样`的效果: ``` export const captcha: CaptchaOptions = { image: { size: 5, noise: 3, width: 200, height: 50 type: 'letter' } } ``` ### 配置示例二[​](#配置示例二 "配置示例二的直接链接") 获取一个图像宽度 `100` 像素,高度 `60` 像素,并且包含 `2` 条干扰线的计算表达式验证码。 因为计算表达式验证码的配置 `formula` ,会与 `default` 配置合并,所以可以只修改 `default` 配置: ``` export const captcha: CaptchaOptions = { default: { noise: 2, width: 100, height: 60 }, } ``` 当然,也可以 `不` 修改 `default` 配置,将宽度、高度等在 `formula` 配置项中进行配置,取得 `同样`的效果: ``` export const captcha: CaptchaOptions = { formula: { noise: 2, width: 100, height: 60 } } ``` ## 组件依赖[​](#组件依赖 "组件依赖的直接链接") 验证码的内容存储基于 `@midwayjs/cache-manager` 组件,默认创建了一个名为 `captcha` 的缓存实例,将数据存储在 `memory` 中。 ``` export default { cacheManager: { clients: { captcha: { store: 'memory', }, }, }, }; ``` 如果要替换为 `redis` 或其他服务,请参照 `@midwayjs/cache-manager` 的 [文档](/docs/extensions/caching.md),对 cache 进行配置。 ## 效果[​](#效果 "效果的直接链接") **图片验证码** ![图片验证码](https://gw.alicdn.com/imgextra/i4/O1CN014cEzLH23vEniOgoyp_!!6000000007317-2-tps-120-40.png) **计算表达式** ![计算表达式](https://gw.alicdn.com/imgextra/i4/O1CN01u3Mj0q24lRx1md9pX_!!6000000007431-2-tps-120-40.png) ## 注意[​](#注意 "注意的直接链接") * 为了防止机器学习破解,使用的 `svg-captcha` 包为 [安全修复后](https://juejin.cn/post/6872656117839691789) 的版本。 --- # 角色鉴权 Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。 官网文档: ## Casbin 是什么[​](#casbin-是什么 "Casbin 是什么的直接链接") Casbin 可以: 1. 支持自定义请求的格式,默认的请求格式为`{subject, object, action}`。 2. 具有访问控制模型model和策略policy两个核心概念。 3. 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。 4. 支持内置的超级用户 例如:`root` 或 `administrator`。超级用户可以执行任何操作而无需显式的权限声明。 5. 支持多种内置的操作符,如 `keyMatch`,方便对路径式的资源进行管理,如 `/foo/bar` 可以映射到 `/foo*` Casbin 不能: 1. 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。 2. 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。 提示 注意: * 1、在 Midway v3.6.0 之后可用 * 2、Midway 只是封装了 Casbin 的 API 并提供简单的支持,策略规则编写请查看 [官方文档](https://casbin.org/) * 3、Casbin 不提供登录,只提供现有用户的鉴权,需要搭配 passport 等获取用户信息的组件来使用 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/casbin@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/casbin": "^4.0.0", // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path' @Configuration({ imports: [ // ... casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 准备模型和策略[​](#准备模型和策略 "准备模型和策略的直接链接") 使用 Casbin 前需要定义模型和策略,这两个文件的内容贯穿本文,建议先去官网了解相关内容。 我们以一个基础的模型为例,比如: ``` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ g2 = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act || r.sub == "root" ``` 将其保存在项目根目录的 `basic_model.conf` 文件中。 以及包含下面内容的策略文件。 ``` p, superuser, user, read:any p, manager, user_roles, read:any p, guest, user, read:own g, alice, superuser g, bob, guest g, tom, manager g2, users_list, user g2, user_roles, user g2, user_permissions, user g2, roles_list, role g2, role_permissions, role ``` 将其保存在项目根目录的 `basic_policy.csv` 文件中。 ## 配置模型和策略[​](#配置模型和策略 "配置模型和策略的直接链接") 这里我们的策略将以文件形式进行演示。 配置如下: ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; export default (appInfo: MidwayAppInfo) => { return { // ... casbin: { modelPath: join(appInfo.appDir, 'basic_model.conf'), policyAdapter: join(appInfo.appDir, 'basic_policy.csv'), } }; } ``` ## 装饰器鉴权[​](#装饰器鉴权 "装饰器鉴权的直接链接") 有多种形式来使用 Casbin,这里以装饰器作为示例。 ### 定义资源[​](#定义资源 "定义资源的直接链接") 首先定义资源,比如放在 `src/resource.ts` 文件中,对应策略文件中对应的资源。 ``` export enum Resource { USERS_LIST = 'users_list', USER_ROLES = 'user_roles', USER_PERMISSIONS = 'user_permissions', ROLES_LIST = 'roles_list', ROLE_PERMISSIONS = 'role_permission', } ``` ### 配置获取用户的方式[​](#配置获取用户的方式 "配置获取用户的方式的直接链接") 在使用装饰器鉴权时,我们需要配置一个获取用户的方式,比如在 passport 组件之后,我们会从 `ctx.user` 上获取用户名。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; export default (appInfo: MidwayAppInfo) => { return { // ... casbin: { modelPath: join(appInfo.appDir, 'basic_model.conf'), policyAdapter: join(appInfo.appDir, 'basic_policy.csv'), usernameFromContext: (ctx) => { return ctx.user; } } }; } ``` ### 增加守卫[​](#增加守卫 "增加守卫的直接链接") 装饰器鉴权依赖守卫,我们可以在全局或者某些路由上开启,全局守卫使用请参考守卫章节。 比如,我们只在下面的 `findAllUsers` 方法上开启鉴权,`AuthGuard` 是 `@midwayjs/casbin` 提供的守卫,可以直接使用。 ``` import { Controller, Get, UseGuard } from '@midwayjs/core'; import { AuthGuard } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @Get('/users') async findAllUsers() { // ... } } ``` ### 定义权限[​](#定义权限 "定义权限的直接链接") 使用 `UsePermission` 装饰器定义路由需要的权限。 ``` import { Controller, Get, UseGuard } from '@midwayjs/core'; import { AuthActionVerb, AuthGuard, AuthPossession, UsePermission } from '@midwayjs/casbin'; import { Resource } from './resouce'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @UsePermission({ action: AuthActionVerb.READ, resource: Resource.USER_ROLES, possession: AuthPossession.ANY }) @Get('/users') async findAllUsers() { // ... } } ``` 没有权限读取 `USER_ROLES` 的用户不能调用 findAllUsers 方法,在请求时会返回 403 状态码。 比如,上面的 `bob` 用户访问则会返回 403, 而 `tom` 用户访问则正常返回。 `UsePermission` 需要提供一个对象参数,包括 `action`、`resource`、`possession` 和一个可选的 `isOwn` 的对象。 * `action` 是一个 `AuthActionVerb` 枚举,包含读,写等操作 * `resource` 资源字符串 * `possession` 是一个 `AuthPossession` 枚举 * `isOwn` 是一个接受`Context`(守卫 `canActivate`的参数)作为唯一参数并返回布尔值的函数。 `AuthZGuard` 使用它来确定用户是否是资源的所有者。 如果未定义,将使用返回 `false` 的默认函数。 可以同时定义多个权限,但只有当所有权限都满足时,才能访问该路由。 比如: ``` @UsePermissions({ action: AuthActionVerb.READ, resource: 'USER_ADDRESS', possession: AuthPossession.ANY }, { action; AuthActionVerb.READ, resource: 'USER_ROLES, possession: AuthPossession.ANY }) ``` 只有当用户被授予读取 `USER_ADDRESS` 和 `USER_ROLES` 这两个权限时,才能访问该路由。 ## API 鉴权[​](#api-鉴权 "API 鉴权的直接链接") Casbin 本身提供了一些通用的 API 和权限相关的功能。 我们可以通过直接注入 `CasbinEnforcerService` 服务来使用。 比如,我们可以在守卫或者中间件中编码。 ``` import { CasbinEnforcerService } from '@midwayjs/casbin'; import { Guard, IGuard } from '@midwayjs/core'; @Guard() export class UserGuard extends IGuard { @Inject() casbinEnforcerService: CasbinEnforcerService; async canActivate(ctx, clz, methodName) { // 用户登录了,并且是特定的方法,则检查权限 if (ctx.user && methodName === 'findAllUsers') { return await this.casbinEnforcerService.enforce(ctx.user, 'USER_ROLES', 'read'); } // 未登录用户不允许访问 return false; } } ``` 在启用守卫后,效果和上面的装饰器相同。 此外,`CasbinEnforcerService` 还有更多的 API,比如重新加载策略。 ``` await this.casbinEnforcerService.loadPolicy(); ``` ## 分布式策略存储[​](#分布式策略存储 "分布式策略存储的直接链接") 在多台机器部署的场景下,需要将策略存储到外部。 当前已经实现的适配器有: * Redis * Typeorm ### Redis Adapter[​](#redis-adapter "Redis Adapter的直接链接") 需要依赖 `@midwayjs/casbin-redis-adapter` 包和 redis 组件。 ``` $ npm i @midwayjs/casbin-redis-adapter @midwayjs/redis --save ``` 启用 redis 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... redis, casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 配置 redis 连接和 casbin 适配器。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { createAdapter } from '@midwayjs/casbin-redis-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... redis: { clients: { // 为 casbin 定义了一个连接 'node-casbin-official': { host: '127.0.0.1', port: 6379, password: '', db: '0', } } }, casbin: { policyAdapter: createAdapter({ // 配置了上面的连接名 clientName: 'node-casbin-official' }), // ... }, }; } ``` ### TypeORM Adapter[​](#typeorm-adapter "TypeORM Adapter的直接链接") 需要依赖 `@midwayjs/casbin-typeorm-adapter` 包和 typeorm 组件。 ``` $ npm i @midwayjs/casbin-typeorm-adapter @midwayjs/typeorm --save ``` 启用 typeorm 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as typeorm from '@midwayjs/typeorm'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... typeorm, casbin, ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 配置适配器,下面以 sqlite 存储为例,mysql 的配置可以查看 typeorm 组件。 ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { CasbinRule, createAdapter } from '@midwayjs/casbin-typeorm-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... typeorm: { dataSource: { // 为 casbin 定义了一个连接 'node-casbin-official': { type: 'sqlite', synchronize: true, database: join(appInfo.appDir, 'casbin.sqlite'), // 注意这里显式引入了 Entity entities: [CasbinRule], } } }, casbin: { policyAdapter: createAdapter({ // 配置了上面的连接名 dataSourceName: 'node-casbin-official' }), // ... } }; } ``` ## 监视器[​](#监视器 "监视器的直接链接") 使用分布式消息系统,例如 [etcd](https://github.com/coreos/etcd) 来保持多个Casbin执行器实例之间的一致性。 因此,我们的用户可以同时使用多个Casbin 执行器来处理大量的权限检查请求。 Midway 当前只提供一种 Redis 更新策略,如有其他需求,可以给我们提交 issue。 ### Redis Watcher[​](#redis-watcher "Redis Watcher的直接链接") 需要依赖 `@midwayjs/casbin-redis-adapter` 包和 redis 组件。 ``` $ npm i @midwayjs/casbin-redis-adapter @midwayjs/redis --save ``` 启用 redis 组件。 ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import * as casbin from '@midwayjs/casbin'; import { join } from 'path'; @Configuration({ imports: [ // ... redis, casbin, ], // ... }) export class MainConfiguration { } ``` 使用示例: ``` import { MidwayAppInfo } from '@midwayjs/core'; import { join } from 'path'; import { createAdapter, createWatcher } from '@midwayjs/casbin-redis-adapter'; export default (appInfo: MidwayAppInfo) => { return { // ... redis: { clients: { 'node-casbin-official': { host: '127.0.0.1', port: 6379, db: '0', }, 'node-casbin-sub': { host: '127.0.0.1', port: 6379, db: '0', } } }, casbin: { // ... policyAdapter: createAdapter({ clientName: 'node-casbin-official' }), policyWatcher: createWatcher({ pubClientName: 'node-casbin-official', subClientName: 'node-casbin-sub', }) }, }; } ``` 注意,pub/sub 连接需要不同的客户端,上面代码定义了两个客户端。 pub 客户端可以和普通 Redis 客户端连接复用,而 sub 需要一个独立的客户端。 --- # cfork 很多同学没有听过 cfork,cfork 库是 egg-scripts 中用于启动主进程的库,是 egg 使用的基础库之一,他的功能是启动进程,并维持多个进程的保活。 文档在此: 由于 bootstrap.js 的特性,有时候不是很适合 pm2 来部署(比如集团内部,全局不安装,需要 API 启动)。 我们可以新增一个 `server.js` 用来做主进程的入口,将 `bootstrap.js` 作为每个子进程的启动入口。 ``` // server.js 'use strict'; const cfork = require('cfork'); const util = require('util'); const path = require('path'); const os = require('os'); // 获取 cpu 核数 const cpuNumbers = os.cpus().length; cfork({ exec: path.join(__dirname, './bootstrap.js'), count: cpuNumbers, }) .on('fork', (worker) => { console.warn('[%s] [worker:%d] new worker start', Date(), worker.process.pid); }) .on('disconnect', (worker) => { console.warn( '[%s] [master:%s] wroker:%s disconnect, exitedAfterDisconnect: %s, state: %s.', Date(), process.pid, worker.process.pid, worker.exitedAfterDisconnect, worker.state ); }) .on('exit', (worker, code, signal) => { const exitCode = worker.process.exitCode; const err = new Error( util.format( 'worker %s died (code: %s, signal: %s, exitedAfterDisconnect: %s, state: %s)', worker.process.pid, exitCode, signal, worker.exitedAfterDisconnect, worker.state ) ); err.name = 'WorkerDiedError'; console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack); }); ``` 最后启动 `node server.js` 即可。 --- # 代码染色 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的代码染色组件。 用于在 HTTP 场景展示调用链路耗时与各个方法的出入参,帮你更快地定位代码问题。 比如: * 代码执行缓慢 * 不知道是哪一个方法执行的慢:通过代码染色后,可以查看每一个 `方法的执行时长`。 * 代码执行错误 * 可能是方法没有调到:通过代码染色后,可以查看每一个 `方法的调用链`。 * 可能是方法调用参数出错:通过代码染色后,查看每一个`方法的入参和返回值` 使用效果: ![](https://gw.alicdn.com/imgextra/i1/O1CN017Zd6y628M2PvqJO7I_!!6000000007917-2-tps-2392-844.png) 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/code-dye@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/code-dye": "^4.0.0" // ... }, } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 将 code-dye 组件配置到代码中。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as codeDye from '@midwayjs/code-dye'; @Configuration({ imports: [ // ... { component: codeDye, enabledEnvironment: ['local'], // 只在本地启用 } ], }) export class MainConfiguration {} ``` 提示 * 可以在 `本地` 或 `研发` 环境开启本组件,便于开发时定位问题,但是 `不建议` 在线上启用,会对线上访问性能产生影响。 ## 配置染色[​](#配置染色 "配置染色的直接链接") 可以通过`matchQueryKey` 配置,控制当 `query` 参数包含`matchQueryKey` 配置对应的值的时候,进入染色链路,例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchQueryKey: 'codeDyeABC', } } ``` 当请求接口 `http://127.0.0.1:7001/test?codeDyeABC=html` 时,就会判断 `query` 中是否存在 `codeDyeABC` 参数来决定是否染色,并根据参数对应的值,来响应不同的染色结果。 也可以通过`matchHeaderKey` 配置,控制当 `headers` 参数包含 `matchHeaderKey` 配置对应的值的时候,进入染色链路,例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchHeaderKey: 'codeDyeHeader', } } ``` 当请求接口 `http://127.0.0.1:7001/test` 时,就会判断请求的 `headers` 中是否存在 `codeDyeHeader` 参数来决定是否染色,并根据参数对应的值,来响应不同的染色结果。 ## 染色报告[​](#染色报告 "染色报告的直接链接") 开启了代码染色后,链路染色的结果,可以通过开启染色的不同参数值来配置,目前支持以下三种: * `html`:`对` 当前请求的结果进行处理,将染色信息添加到结果中,响应为 `html`,可以在浏览器上查看,效果可以查看此文档上面的图片效果展示。 * `json`:`对` 当前请求的结果进行处理,将染色信息添加到结果中,响应为 `json` 结构化信息。 * `log`:`不对` 当前请求的结果进行处理,染色的信息将会输出到日志中,不影响请求。 例如,配置为: ``` // src/config/config.local.ts export default { codeDye: { matchQueryKey: 'codeDyeXXX', } } ``` 当请求接口 `http://127.0.0.1:7001/test?codeDyeXXX=html` 时,就会判断 `query` 中 `codeDyeXXX` 参数的值为 `html`,就将染色结果输出在当前请求的响应中,并且内容为 `html` 格式。 --- # 命令行 `@midwayjs/commander` 是一个基于 Midway IoC 容器的命令行组件,底层使用 [commander.js](https://github.com/tj/commander.js#readme) 做参数解析与 help 输出。你可以用 Midway 熟悉的依赖注入方式组织命令、选项解析与业务逻辑,并将命令拆分为多个 Class。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ❌ | | 可用于 Serverless | ❌ | | 可用于一体化 | ❌ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 commander 组件依赖。 ``` $ npm i @midwayjs/commander@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/commander": "^4.0.0" } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在入口配置中引入组件。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as commander from '@midwayjs/commander'; @Configuration({ imports: [commander], }) export class MainConfiguration {} ``` ## 编写命令[​](#编写命令 "编写命令的直接链接") 目录结构示例: ``` . ├── src │ ├── commands │ │ ├── hello.command.ts │ │ └── status.command.ts │ ├── configuration.ts │ └── ... ├── bootstrap.js └── package.json ``` 一个命令对应一个 Class,使用 `@Command()` 修饰,并实现 `CommandRunner` 接口的 `run()` 方法。 ``` // src/commands/hello.command.ts import { Inject, ILogger } from '@midwayjs/core'; import { Command, CommandRunner, Option } from '@midwayjs/commander'; @Command({ name: 'hello', description: 'hello command', arguments: '', aliases: ['hi'], }) export class HelloCommand implements CommandRunner { @Inject() logger: ILogger; @Option({ flags: '-f, --foo [foo]', description: 'foo option', defaultValue: 'bar', }) parseFoo(val: string) { return `${val}_parsed`; } async run(passedParams: string[], options?: Record) { const [name] = passedParams; this.logger?.info?.(`hello ${name}`, options); } } ``` ### `@Command()` 参数[​](#command-参数 "command-参数的直接链接") * `name`:命令名称(命令行调用与 `--help` 展示时使用) * `arguments`:命令位置参数声明(例如 ``、` [b]`) * `description`:命令描述,会展示在 `--help` 中 * `argsDescription`:位置参数描述对象,会展示在 `--help` 中 * `aliases`:命令别名数组 ### `@Option()` 参数[​](#option-参数 "option-参数的直接链接") * `flags`:选项声明(例如 `-f, --foo [foo]`、`-n, --num `) * `description`:选项描述,会展示在 `--help` 中 * `defaultValue`:默认值(不传该选项时生效) * `required`:是否必填(等价于 commander 的 `requiredOption`) `@Option()` 修饰的方法会作为 commander 的自定义 parser,用于把字符串参数转换为业务需要的类型(例如 number/boolean/自定义格式)。 ## 运行命令[​](#运行命令 "运行命令的直接链接") 该组件作为 Midway Framework 运行,在应用启动时会解析 `process.argv` 并执行匹配的命令。 如果你使用 `bootstrap.js` 作为入口,可以这样启动: ``` // bootstrap.js const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.run(); ``` 然后运行: ``` $ node bootstrap.js hello world --foo baz $ node bootstrap.js hi world ``` ## 上下文[​](#上下文 "上下文的直接链接") 每次命令执行都会创建请求上下文(request context),可以在命令类中注入 `Context` 获取运行时信息: ``` import { Command, CommandRunner, Context } from '@midwayjs/commander'; import { Inject } from '@midwayjs/core'; @Command({ name: 'info', arguments: '' }) export class InfoCommand implements CommandRunner { @Inject() ctx: Context; async run() { this.ctx.commandName; // 命令名 this.ctx.args; // 位置参数数组 this.ctx.options; // commander 解析后的选项 this.ctx.command; // commander 的 Command 实例 } } ``` ## 交互式提问(Enquirer)[​](#交互式提问enquirer "交互式提问(Enquirer)的直接链接") 组件内置了基于 [enquirer](https://github.com/enquirer/enquirer) 的交互式提问能力,适用于运行过程中补齐参数。你可以用 `@QuestionSet()` 组织问题集合,并在命令里通过 `EnquirerService` 触发。 如果希望既支持命令行传参又支持交互补齐,请把对应选项设为可选(否则 commander 会在缺参时直接报错)。 ``` import { Command, CommandRunner, QuestionSet, Question, ValidateFor, DefaultFor, WhenFor, EnquirerService, } from '@midwayjs/commander'; import { Inject } from '@midwayjs/core'; @QuestionSet() class ProfileQuestionSet { @Question({ type: 'input', name: 'age', message: 'Your age?' }) parseAge(value: string) { return Number.parseInt(value, 10); } @Question({ type: 'input', name: 'nickname', message: 'Nickname?' }) parseNickname(value: string) { return value; } @ValidateFor({ name: 'age' }) validateAge(value: string) { return value ? true : 'age required'; } @DefaultFor({ name: 'nickname' }) defaultNickname() { return 'neo'; } @WhenFor({ name: 'nickname' }) whenNickname(answers: Record) { return Boolean(answers.useNickname); } } @Command({ name: 'ask' }) export class AskCommand implements CommandRunner { @Inject() enquirerService: EnquirerService; async run(_passedParams: string[], options?: Record) { const answers = await this.enquirerService.prompt(ProfileQuestionSet, { useNickname: options?.useNickname, }); // use answers.age / answers.nickname } } ``` 说明: * `@Question()` 修饰的方法会作为 enquirer 的 `result`(用于转换用户输入)。 * `@DefaultFor()` 会映射到 enquirer 的 `initial`。 * `@WhenFor()` 支持根据已收集的答案决定是否提问。 * 可用的 `@*For()` 装饰器:`ValidateFor`、`ChoicesFor`、`MessageFor`、`DefaultFor`、`WhenFor`。 * `prompt()` 同时支持 `QuestionSet` 名称字符串或类引用,推荐使用类引用。 ## 错误处理[​](#错误处理 "错误处理的直接链接") 默认情况下,CLI 入口会捕获异常并输出日志后退出进程。你可以在配置里提供 `errorHandler` 来接管错误处理: ``` // src/config/config.default.ts export default { commander: { errorHandler: (err: Error) => { console.error(err); process.exit(1); }, }, }; ``` 如果你在命令里使用了 `@Catch()` 错误过滤器(Midway Filter),会先走过滤器逻辑,再进入这里的兜底处理。 ## 返回值与输出[​](#返回值与输出 "返回值与输出的直接链接") 默认情况下,命令执行完毕后,如果 `run()` 有返回值,框架会将返回值输出到标准输出(stdout),方便用作脚本管道或在测试中断言输出内容。 支持的返回值类型: * `string` / `Buffer`:直接写入 stdout * 普通对象:使用 `JSON.stringify` 后写入 stdout * `Readable`:会 pipe 到 stdout * `AsyncIterable`:会按迭代顺序逐段写入 stdout 下面是一个返回文本/JSON 的例子(使用 core 的 `ServerResponse` 语义来组织输出格式): ``` import { Command, CommandRunner, CliServerResponse } from '@midwayjs/commander'; @Command({ name: 'status' }) export class StatusCommand implements CommandRunner { async run() { return new CliServerResponse({} as any).success().json({ ok: true }); } } ``` 如果希望按 chunk 逐步输出,可以返回 `CliServerResponse().stream()`: ``` import { Command, CommandRunner, CliServerResponse } from '@midwayjs/commander'; @Command({ name: 'stream' }) export class StreamCommand implements CommandRunner { async run() { const response = new CliServerResponse({} as any); const stream = response.stream(); setImmediate(() => { stream.send('a'); stream.send({ b: 2 }); stream.end(); }); return stream; } } ``` ## 日志[​](#日志 "日志的直接链接") 组件默认会注册一个名为 `commanderLogger` 的 logger,默认写入 `midway-commander.log`。 你可以在命令类里通过 `@Logger('commanderLogger')` 注入使用,例如: ``` import { Logger, ILogger } from '@midwayjs/core'; import { Command, CommandRunner } from '@midwayjs/commander'; @Command({ name: 'hello', arguments: '' }) export class HelloCommand implements CommandRunner { @Logger('commanderLogger') logger: ILogger; async run(passedParams: string[]) { this.logger.info('hello %s', passedParams[0]); } } ``` 如果希望自定义日志文件名或级别,可以在应用配置中覆盖 `midwayLogger.clients.commanderLogger`: ``` // src/config/config.default.ts export default { midwayLogger: { clients: { commanderLogger: { fileLogName: 'my-commander.log', level: 'info', }, }, }, }; ``` ## 单元测试[​](#单元测试 "单元测试的直接链接") 命令行参数在测试环境中很容易被 Jest/Node 参数污染,推荐通过 framework 的 `runCommand()` 来执行命令,而不是直接 mock `process.argv`。 ``` import { createLightApp, close } from '@midwayjs/mock'; import { Framework } from '@midwayjs/commander'; import * as commander from '@midwayjs/commander'; describe('commander', () => { it('should run command', async () => { const app = await createLightApp({ imports: [commander], preloadModules: [HelloCommand], }); const framework = app.getFramework() as Framework; await framework.runCommand('hello', 'world', '--foo', 'bar'); await close(app); }); }); ``` --- # Consul consul 用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 本文基于最新组件实现,介绍 Consul 客户端的配置与使用,以及统一抽象的服务发现能力。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | 从 v4 开始 Consul 组件基于 Service Factory 进行了重构,API 有着非常大的变化,并提供了服务发现等抽象能力。 感谢 [boostbob](https://github.com/boostbob) 提供的组件。 效果如下图: ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01e5cFZx1I0draeZynr_!!6000000000831-2-tps-1500-471.png) ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01iLYF8r1HQ0B3b47Fh_!!6000000000751-2-tps-1500-895.png) ## 安装组件[​](#安装组件 "安装组件的直接链接") 首先安装 Consul 组件: ``` $ npm i @midwayjs/consul@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/consul": "^4.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") ``` import { Configuration } from '@midwayjs/core'; import * as consul from '@midwayjs/consul'; import { join } from 'path'; @Configuration({ imports: [consul], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration {} ``` ## 配置客户端[​](#配置客户端 "配置客户端的直接链接") 支持单客户端与多客户端,遵循 ServiceFactory 配置结构。 **单客户端** ``` // src/config/config.default.ts export default { consul: { client: { host: '127.0.0.1', port: '8500' } } } ``` **多客户端** ``` // src/config/config.default.ts export default { consul: { clients: { a: { host: '127.0.0.1', port: '8500' }, b: { host: '127.0.0.1', port: '8501' } }, defaultClientName: 'a' } } ``` **使用默认实例** `ConsulService` 作为默认实例代理,直接暴露原生 Consul 客户端方法。 ``` import { Provide, Inject } from '@midwayjs/core'; import { ConsulService } from '@midwayjs/consul'; @Provide() export class UserService { @Inject() consul: ConsulService; async register() { await this.consul.kv.set('name', 'juhai'); } } ``` **获取指定实例** 通过 `ConsulServiceFactory` 获取指定命名的客户端实例。 ``` import { Provide, Inject } from '@midwayjs/core'; import { ConsulServiceFactory } from '@midwayjs/consul'; @Provide() export class UserService { @Inject() consulFactory: ConsulServiceFactory; async invoke() { const consulA = this.consulFactory.get('a'); const consulB = this.consulFactory.get('b'); await consulA.agent.service.register({ name: 'svc-a', id: 'svc-a-1' }); await consulB.agent.service.register({ name: 'svc-b', id: 'svc-b-1' }); } } ``` ## 服务发现[​](#服务发现 "服务发现的直接链接") 从 v4 开始提供基于统一抽象的服务发现能力,Consul 将成为服务发现的客户端来使用。 服务发现包括 **注册服务** 和 **获取服务** 两部分。 ### 配置服务发现[​](#配置服务发现 "配置服务发现的直接链接") 你需要先配置一个客户端,如果配置了多个,可以使用 `serviceDiscoveryClient` 来指定。 通过 `serviceDiscovery` 来配置服务发现。 ``` // src/config/config.default.ts export default { consul: { clients: { default: { host: '127.0.0.1', port: '8500' }, }, serviceDiscovery: { // ... } } } ``` ### 注册服务发现[​](#注册服务发现 "注册服务发现的直接链接") 当服务启动后,你可以将当前的服务注册到 Consul 注册中心。 ``` import { Configuration, Inject } from '@midwayjs/core'; import { ConsulServiceDiscovery } from '@midwayjs/consul'; import { LoadBalancerType } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() consulDiscovery: ConsulServiceDiscovery; async onServerReady() { // 创建一个服务发现客户端 const client = this.consulDiscovery.createClient(); // 注册当前服务 await client.register({ id: client.defaultMeta.id, name: 'order', tags: ['test'], address: client.defaultMeta.host, port: 7001, meta: { version: '1.0.0' }, check: { name: 'TTL Health Check', timeout: '30s', ttl: '10s' } }); } } ``` `register` 方法需要传递一些基础的信息。 最重要的有 id,name,以及 address。 ``` interface RegisterOptions extends CommonOptions { name: string; id?: string; tags?: string[]; address?: string; taggedaddresses?: Record; meta?: Record; namespace?: string; port?: number; kind?: string; proxy?: any; connect?: RegisterConnect; check?: CheckOptions; checks?: CheckOptions[]; } ``` `client.defaultMeta` 提供了一些默认生成的数据,包括 id,serviceName, host。 ### 获取可用服务[​](#获取可用服务 "获取可用服务的直接链接") 你可以在任意需要的地方,动态获取到一个服务来调用。 ``` @Provide() export class OrderService { @Inject() consulDiscovery: ConsulServiceDiscovery; async getSerivce() { const instance = await this.consulDiscovery.getInstance({ service: 'order'}); // instance.name } } ``` 返回的 instance 类型为 `ConsulHealthItem`,结构如下。 ``` export interface ConsulHealthItem { Node: { ID: string; Node: string; Address: string; Datacenter: string; TaggedAddresses: Record; Meta: Record; CreateIndex: number; ModifyIndex: number; }; Service: { ID: string; Service: string; Tags: string[]; Address: string; TaggedAddresses: Record; Meta: Record; Port: number; Weights: Record; EnableTagOverride: boolean; Proxy: Record; Connect: Record; PeerName: string; CreateIndex: number; ModifyIndex: number; }; Checks: Array<{ Node: string; CheckID: string; Name: string; Status: 'passing' | 'warning' | 'critical'; Notes: string; Output: string; ServiceID: string; ServiceName: string; ServiceTags: string[]; Type: string; Interval: string; Timeout: string; ExposedPort: number; Definition: Record; CreateIndex: number; ModifyIndex: number; }>; } ``` ## 配置中心[​](#配置中心 "配置中心的直接链接") 同时 consul 也能作为一个服务配置的地方,如下代码: ``` import { Controller, Get, Inject } from '@midwayjs/core'; import { ConsulService } from '@midwayjs/consul'; @Controller('/') export class HomeController { @Inject() consul: ConsulService; @Get('/') async home() { await this.consul.kv.set('name', 'juhai'); const res = await this.consul.kv.get('name'); return res; } } ``` 我们调用 `kv.set` 方法,我们可以设置对应的配置,通过 `kv.get` 方法可以拿到对应的配置。 注意:在代码中,有同学出现,在每次请求中去 get 对应的配置,这时你的 QPS 多少对 Consul server 的压力。 所以在QPS比较大的情况,可以如下处理: ``` import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { ConsulService } from '@midwayjs/consul'; @Provide() @Scope(ScopeEnum.Singleton) export class ConfigService { @Inject() consul: ConsulService; config: any; @Init() async init() { setInterval(async () => { this.config = await this.consul.kv.get('name'); }, 5000); this.config = await this.consul.kv.get('name'); } async getConfig(){ return this.config; } } ``` 上面的代码,相当于定时去获取对应的配置,当每个请求进来的时候,获取 Scope 为 ScopeEnum.Singleton 服务的 `getConfig` 方法,这样每 5s 一次获取请求,就减少了对服务的压力。 Consul 界面上如下图: ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01V3P6uK1rIVs19JiWn_!!6000000005608-2-tps-1500-374.png) ![image.png](https://img.alicdn.com/imgextra/i2/O1CN014O2GyH1sMvIhmlbs4_!!6000000005753-2-tps-1500-667.png) 一共提供如下几种方法: * [get](https://www.npmjs.com/package/consul#kv-get),获取对应key的value * [keys](https://www.npmjs.com/package/consul#kv-keys),查询某个prefix的key的列表 * [set](https://www.npmjs.com/package/consul#kv-set),设置对应的key的值 * [del](https://www.npmjs.com/package/consul#kv-del),删除对应的key --- # 腾讯云对象存储(COS) 本文介绍了如何使用 midway 接入腾讯云 COS。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/cos@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cos": "^4.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as cos from '@midwayjs/cos'; import { join } from 'path' @Configuration({ imports: [ // ... cos // 导入 cos 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` // src/config/config.default export default { // ... cos: { client: { SecretId: '***********', SecretKey: '***********', }, }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default export default { // ... cos: { clients: { instance1: { SecretId: '***********', SecretKey: '***********', }, instance2: { SecretId: '***********', SecretKey: '***********', }, }, }, } ``` 更多参数可以查看 [cos-nodejs-sdk-v5](https://github.com/tencentyun/cos-nodejs-sdk-v5) 文档。 ## 使用 COS 服务[​](#使用-cos-服务 "使用 COS 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { COSService } from '@midwayjs/cos'; @Provide() export class UserService { @Inject() cosService: COSService; async invoke() { await this.cosService.sliceUploadFile({ Bucket: 'test-1250000000', Region: 'ap-guangzhou', Key: '1.zip', FilePath: './1.zip' }, } } ``` 可以使用 `COSServiceFactory` 获取不同的实例。 ``` import { COSServiceFactory } from '@midwayjs/cos'; import { join } from 'path'; @Provide() export class UserService { @Inject() cosServiceFactory: COSServiceFactory; async save() { const cos1 = await this.cosServiceFactory.get('instance1'); const cos2 = await this.cosServiceFactory.get('instance3'); //... } } ``` --- # 本地任务 和 bull 组件不同,cron 组件提供的是本地任务能力,即在每台机器的每个进程都会执行。如需不同机器或者不同进程之间只执行一次任务,请使用 [bull 组件](/docs/extensions/bull.md) 。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/cron@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/cron": "^4.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; @Configuration({ imports: [ // ... cron ] }) export class MainConfiguration { //... } ``` ## 编写任务处理类[​](#编写任务处理类 "编写任务处理类的直接链接") 使用 `@Job` 装饰器装饰一个类,用于快速定义一个任务处理器。 比如,在 `src/job` 目录中创建一个 `sync.job.ts`,用于某些数据同步任务,代码如下: ``` // src/job/sync.job.ts import { Job, IJob } from '@midwayjs/cron'; import { FORMAT } from '@midwayjs/core'; @Job({ cronTime: FORMAT.CRONTAB.EVERY_PER_30_MINUTE, start: true, }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } } ``` `@Job` 装饰器用于修饰一个任务类,在初始化时,框架会自动将其转变为一个任务。 任务类需要实现 `IJob` 接口,实现 `onTick` 方法,每当任务触发时,会自动调用 `onTick` 方法。 此外,还有一个可选的 `onComplete` 方法,用于在 `onTick` 完成后执行。 ``` @Job({ cronTime: FORMAT.CRONTAB.EVERY_PER_30_MINUTE, start: true, }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } async onComplete() { // 记录一些数据等等,用处不是很大 } } ``` `@Job` 装饰器的常用参数如下: | 参数 | 类型 | 描述 | | --------- | ------- | ---------------------- | | cronTime | string | crontab 表达式 | | start | boolean | 是否自动启动任务 | | runOnInit | boolean | 是否在初始化就执行一次 | 更多参数,请参考 [Cron](https://github.com/kelektiv/node-cron)。 ## 任务管理[​](#任务管理 "任务管理的直接链接") 除了定时执行任务,我们还通过框架提供的 API,对任务进行手动管理。 比如,下面的代码仅仅定义了一个任务,但是不会启动执行。 ``` @Job('syncJob', { cronTime: '*/2 * * * * *', // 每隔 2s 执行 }) export class DataSyncCheckerJob implements IJob { async onTick() { // ... } } ``` 我们定义了一个名为 `syncJob` 的任务,并且给它了一个默认的调度时间。 ### 获取任务对象[​](#获取任务对象 "获取任务对象的直接链接") 我们可以通过两种方式获取任务对象。 通过`@InjectJob` 用来注入某个任务,参数为类本身或者任务名。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @InjectJob(DataSyncCheckerJob) syncJob: CronJob; @InjectJob('syncJob') syncJob2: CronJob; async onServerReady() { // this.syncJob === this.syncJob2 } } ``` 通过 Framework API 获取。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @Inject() cronFramework: cron.Framework; async onServerReady() { const syncJob = this.cronFramework.getJob(DataSyncCheckerJob); const syncJob2 = this.cronFramework.getJob('syncJob'); // syncJob === syncJob2 } } ``` 警告 注意,任务对象都必须在 `onServerReady` 生命周期或者启动之后才能获取。 ### 启停任务[​](#启停�任务 "启停任务的直接链接") 我们可以在初始化或者某些程序执行完成之后,将这个任务启动。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as cron from '@midwayjs/cron'; import { InjectJob, CronJob } from '@midwayjs/cron'; import { DataSyncCheckerJob } from './job/sync.job'; @Configuration({ imports: [ cron ], }) export class ContainerConfiguration { @InjectJob(DataSyncCheckerJob) syncJob: CronJob; async onServerReady() { this.syncJob.start(); // ... this.syncJob.stop(); } } ``` ## 上下文[​](#上下文 "上下文的直接链接") 任务执行是在请求作用域中,其有着特殊的 Context 对象结构。 ``` export interface Context extends IMidwayContext { job: CronJob; } ``` 这里的 `CronJob` 类型来自于 [Cron](https://github.com/kelektiv/node-cron) 包。 ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-cron.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { // ... clients: { // ... cronLogger: { fileLogName: 'midway-cron.log', }, } } } ``` ## 全局配置[​](#全局配置 "全局配置的直接链接") 可以针对 Job 进行一些全局配置,会和每个 Job 的配置进行合并。 ``` export default { cron: { defaultCronJobOptions: { // ... } } } ``` 这里的 `defaultCronJobOptions` 配置项请参考 [CronJobParameters](https://github.com/kelektiv/node-cron/blob/main/lib/job.js#L51) --- # 跨域 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用跨域组件,支持 `cors` 、`jsonp` 多种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/cross-domain --save ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 中引入组件。 ``` import * as crossDomain from '@midwayjs/cross-domain'; @Configuration({ imports: [ // ...other components crossDomain ], }) export class MainConfiguration {} ``` ## 什么是跨域[​](#什么是跨域 "什么是跨域的直接链接") 假设有两个网站: * **A.com**:这是你的网站,你想要从这里访问一些资源。 * **B.com**:这是另一个网站,它拥有你想要访问的资源。 ### 场景设定[​](#场景设定 "场景设定的直接链接") 1. **A.com** 是你的主网站,你在这里运行一些 JavaScript 代码。 2. **B.com** 拥有一些 API 接口,你想要通过 A.com 的 JavaScript 代码来调用这些 API 接口。 由于同源策略,浏览器默认不允许 A.com 的 JavaScript 代码直接访问 B.com 的资源。这是因为浏览器出于安全考虑,防止恶意网站读取其他网站的敏感数据。你想要在 A.com 上运行的 JavaScript 代码中发起一个请求到 B.com 的 API 接口,这个请求会被视为跨域请求。 简单来说,从 A.com 访问 B.com 的接口,就是跨域。 此外,跨域还有一些条件: * 1、同源策略是浏览器安全机制的一部分,所以一般只有浏览器访问才有跨域问题 * 2、当浏览器发起跨域请求时,它会根据当前源自动添加一个 `Origin` 头部到请求中,服务端也会根据 `origin` 头判断来源,进而做处理 所以,当你发现跨域设置不生效时,请检查: * 1、是否真的是跨域请求 * 2、是否真的从浏览器发起 * 3、是否请求带有 `origin` 头 ## 什么是 CORS[​](#什么是-cors "什么是 CORS的直接链接") 在前端代码调用后端服务中经常会碰到下面的错误,这就最为常见的跨域 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 错误。 ``` Access to fetch at 'http://127.0.0.1:7002/' from origin 'http://127.0.0.1:7001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. ``` 出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,`XMLHttpRequest` 和 [Fetch API](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API) 遵循[同源策略](https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy)。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。 CORS 机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 [`XMLHttpRequest`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest) 或 [Fetch](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API))使用 CORS,以降低跨源 HTTP 请求所带来的风险。 ## 常见的 CORS 配置[​](#常见的-cors-配置 "常见的 CORS 配置�的直接链接") 下面列举几种跨域的解决方案,我们以 `fetch` 方法为例。 ### 未使用 `credentials`[​](#未使用-credentials "未使用-credentials的直接链接") 客户端。 ``` fetch(url); ``` 服务端配置。 ``` // src/config/config.default.ts export default { // ... cors: { origin: '*', }, } ``` ### 使用 `credentials`[​](#使用-credentials "使用-credentials的直接链接") 客户端。 ``` fetch(url, { credentials: "include", }); ``` 服务端配置 ``` // src/config/config.default.ts export default { // ... cors: { credentials: true, }, } ``` ### 限制 `origin` 来源[​](#限制-origin-来源 "限制-origin-来源的直接链接") 假如我们的网页地址为 `http://127.0.0.1:7001` 而接口为 `http://127.0.0.1:7002`。 客户端。 ``` fetch('http://127.0.0.1:7002/', { credentials: 'include' }) ``` 服务端配置,注意,由于启用了 `credentials`,这个时候 `origin` 字段不能为 `*`。 ``` // src/config/config.default.ts export default { // ... cors: { origin: 'http://127.0.0.1:7001', credentials: true, }, } ``` ## 更多 CORS 配置[​](#更多-cors-配置 "更多 CORS 配置的直接链接") 完整可用配置如下: ``` export const cors = { // 允许跨域的方法,【默认值】为 GET,HEAD,PUT,POST,DELETE,PATCH allowMethods: string |string[]; // 设置 Access-Control-Allow-Origin 的值,【默认值】会获取请求头上的 origin // 也可以配置为一个回调方法,传入的参数为 request,需要返回 origin 值 // 例如:http://test.midwayjs.org // 如果设置了 credentials,则 origin 不能设置为 * origin: string|Function; // 设置 Access-Control-Allow-Headers 的值,【默认值】会获取请求头上的 Access-Control-Request-Headers allowHeaders: string |string[]; // 设置 Access-Control-Expose-Headers 的值 exposeHeaders: string |string[]; // 设置 Access-Control-Allow-Credentials,【默认值】false // 也可以配置为一个回调方法,传入的参数为 request,返回值为 true 或 false credentials: boolean|Function; // 是否在执行报错的时候,把跨域的 header 信息写入到 error 对的 headers 属性中,【默认值】false keepHeadersOnError: boolean; // 设置 Access-Control-Max-Age maxAge: number; } ``` ## JSONP 配置[​](#jsonp-配置 "JSONP 配置的直接链接") 可以在 `src/config/config.default` 中进行 JSONP 配置。 ``` // src/config/config.default.ts export default { // ... jsonp: { callback: 'jsonp', limit: 512, }, } ``` --- # CRUD 本文档介绍如何在 Midway 中使用 `@midwayjs/crud`。 `@midwayjs/crud` 不是一个“只能自动生成接口”的脚手架,它本质上提供的是一套**面向资源的标准 CRUD 能力**: * 统一的增删改查 service 抽象 * 统一的分页 / 排序 / 过滤 / 搜索协议 * 可选的 REST 路由快捷生成 * 和现有 validation / swagger / web 路由体系的接入 如果你经常在不同模块里重复写下面这些代码: * `findAndCount` * `save` * `update` * `delete` * 手动解析 `page`、`limit`、`sort` * 为每个资源写一套几乎一样的 Controller 那这个组件就是用来把这些重复劳动收起来的。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 这个组件能做什么[​](#这个组件能做什么 "这个组件能做什么的直接链接") 先用一句话概括: **先提供一个可复用的 CRUD service,再按需把它暴露成 HTTP 接口。** 这意味着它支持两种使用方式: 1. 只把它当数据访问层能力来用
适合你的业务逻辑比较复杂,不想让组件替你生成接口。 2. 把它当接口快捷层来用
适合资源型接口很多,希望快速拿到统一的 REST API。 所以它解决的是“资源型接口的重复代码”问题,但**不会替代你的业务 service**。 复杂业务依然应该写在你自己的 service 里,例如: * 下单时要检查库存、优惠券、支付状态 * 创建用户时要同步多个系统 * 删除资源前要做权限和状态机校验 这些逻辑应该继续在你的业务 service 中完成,CRUD 组件只是提供一个稳定的资源操作基座。 ## 核心概念[​](#核心概念 "核心概念的直接链接") 在开始之前,先理解这三个层次。 ### 1. `CrudService`[​](#1-crudservicet "1-crudservicet的直接链接") 这是最核心的抽象,定义了统一的资源操作接口。 ``` list(query) findOne(id) create(data) update(id, data) delete(id) ``` 你可以把它理解成“一个标准化的资源仓储服务接口”。 ### 2. 数据库适配层[​](#2-数据库适配层 "2. 数据库适配层的直接链接") Midway CRUD 目前提供了 4 个官方适配基类: * `TypeOrmCrudService` * `MikroCrudService` * `SequelizeCrudService` * `MongooseCrudService` 它们都实现了相同的 CRUD 核心接口,但底层分别接不同的数据访问组件。 ### 3. HTTP 暴露层[​](#3-http-暴露层 "3. HTTP 暴露层的直接链接") 这是可选的。 如果你希望快速生成路由,可以使用: * 类式:`@Crud()` * 函数式:`defineCrudRoutes()` 这两种方式都只是把同一个 `CrudService` 暴露成 HTTP 接口,不会生成第二套独立逻辑。 ## 什么时候适合用[​](#什么时候适合用 "什么时候适合用的直接链接") 适合: * 大量资源型接口,结构相似 * 列表查询都需要统一分页、排序、过滤 * 想减少重复的 Repository / Model 调用代码 * 想让不同模块的 API 风格保持一致 不适合: * 主要是复杂工作流,不是标准资源接口 * 一个接口需要跨多个聚合、多个事务、多个外部系统 * 你希望所有查询语义都完全自由,不接受统一约束 如果一个模块的核心不是“资源管理”,而是“复杂业务流程”,那更适合直接写普通 Controller + Service,而不是强行套 CRUD。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 先安装 CRUD 组件本身: ``` $ npm i @midwayjs/crud@4 --save ``` 然后根据你使用的数据库组件安装对应依赖。 ``` # TypeORM $ npm i @midwayjs/typeorm@4 typeorm --save # MikroORM $ npm i @midwayjs/mikro@4 @mikro-orm/core --save # Sequelize $ npm i @midwayjs/sequelize@4 sequelize sequelize-typescript --save # Mongoose $ npm i @midwayjs/mongoose@4 mongoose --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/crud": "^4.0.0", "@midwayjs/typeorm": "^4.0.0", "@midwayjs/mikro": "^4.0.0", "@midwayjs/sequelize": "^4.0.0", "@midwayjs/mongoose": "^4.0.0", "typeorm": "^0.3.26", "@mikro-orm/core": "^6.4.5", "sequelize": "^6.37.5", "sequelize-typescript": "^2.1.6", "mongoose": "^8.9.5" } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件。 下面以 `koa + typeorm + crud` 为例: ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as typeorm from '@midwayjs/typeorm'; import * as crud from '@midwayjs/crud'; @Configuration({ imports: [ koa, typeorm, crud, ], }) export class MainConfiguration {} ``` 如果你使用其他数据库组件,只需要把对应组件加到 `imports` 中即可。 ## 入门:先从 service-only 开始[​](#入门先从-service-only-开始 "入门:先从 service-only 开始的直接链接") 对于新手来说,最容易理解的方式不是先生成路由,而是先把它当一个“可复用的数据服务”。 这也是推荐的理解顺序。 ### 为什么推荐先学 service-only[​](#为什么推荐先学-service-only "为什么推荐先学 service-only的直接链接") 因为这样你能先理解: * 组件真正提供的核心是什么 * 业务代码应该写在哪里 * 路由层只是一个可选外壳 如果一上来就只看 `@Crud()`,很容易误以为这只是一个自动生成接口的装饰器。 ### 最小 TypeORM 示例[​](#最小-typeorm-示例 "最小 TypeORM 示例的直接链接") 先定义一个资源 service: ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { TypeOrmCrudService } from '@midwayjs/crud/typeorm'; import { Repository } from 'typeorm'; import { UserEntity } from '../entity/user'; @Provide() export class UserCrudService extends TypeOrmCrudService { @InjectEntityModel(UserEntity) repo: Repository; } ``` 然后在业务 service 里直接组合它: ``` import { Provide, Inject } from '@midwayjs/core'; @Provide() export class UserService { @Inject() userCrudService: UserCrudService; async listUsers() { return this.userCrudService.list({ page: 1, limit: 20, sort: [], filters: [], }); } async createUser(input: CreateUserDTO) { return this.userCrudService.create(input); } } ``` 这时候: * 你已经获得统一的 CRUD 能力 * 但**不会自动生成任何 HTTP 路由** * 业务仍然由你自己的 `UserService` 负责组织 这也是最适合复杂业务场景的用法。 ## 其他数据库适配[​](#其他数据库适配 "其他数据库适配的直接链接") 如果你的项目不是 TypeORM,也可以使用其他官方适配。 ### MikroORM[​](#mikroorm "MikroORM的直接链接") ``` import { Provide } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/mikro'; import { MikroCrudService } from '@midwayjs/crud/mikro'; @Provide() export class UserCrudService extends MikroCrudService { @InjectRepository(UserEntity) repo; } ``` ### Sequelize[​](#sequelize "Sequelize的直接链接") ``` import { Provide } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import { SequelizeCrudService } from '@midwayjs/crud/sequelize'; import { Repository } from 'sequelize-typescript'; @Provide() export class UserCrudService extends SequelizeCrudService { @InjectRepository(UserModel) repo: Repository; } ``` ### Mongoose[​](#mongoose "Mongoose的直接链接") ``` import { Inject, Provide } from '@midwayjs/core'; import { MongooseDataSourceManager } from '@midwayjs/mongoose'; import { MongooseCrudService } from '@midwayjs/crud/mongoose'; @Provide() export class UserCrudService extends MongooseCrudService { @Inject() mongooseDataSourceManager: MongooseDataSourceManager; async onReady() { this.repo = this.mongooseDataSourceManager .getDataSource('default') .model('User'); } } ``` 这几个适配基类的对外用法保持一致,区别主要在于底层仓储注入方式和 ORM 行为。 ## 快速生成类式 REST 接口[​](#快速生成类式-rest-接口 "快速生成类式 REST 接口的直接链接") 当你已经有一个 `CrudService` 之后,如果希望快速生成标准资源型接口,可以使用 `@Crud()`。 ### 最小类式示例[​](#最小类式示例 "最小类式示例的直接链接") ``` import { Controller, Inject } from '@midwayjs/core'; import { Crud } from '@midwayjs/crud'; import { UserEntity } from '../entity/user'; import { UserCrudService } from '../service/user.crud'; @Controller('/users') @Crud({ model: UserEntity, service: UserCrudService, }) export class UserController { @Inject() crudService: UserCrudService; } ``` 默认会生成: * `GET /users` * `GET /users/:id` * `POST /users` * `PATCH /users/:id` * `DELETE /users/:id` ### 为什么还要 `@Inject() crudService`[​](#为什么还要-inject-crudservice "为什么还要-inject-crudservice的直接链接") 因为 `@Crud()` 只是声明“这个 Controller 是一个 CRUD 资源”,真正执行业务的是你绑定的 `crudService`。 也就是说: * `@Crud()` 负责生成默认路由 * `crudService` 负责真正执行 CRUD 逻辑 这是这个组件最重要的设计原则之一。 ### 业务逻辑写在哪里[​](#业务逻辑写在哪里 "业务逻辑写在哪里的直接链接") 不要把复杂业务逻辑塞到 `@Crud()` 里。 推荐做法是: * 资源级默认行为:写在 `UserCrudService` * 复杂业务编排:写在你自己的 `UserService` / Domain Service * 非标准动作:写成普通路由方法 例如: ``` @Controller('/users') @Crud({ model: UserEntity, service: UserCrudService, }) export class UserController { @Inject() crudService: UserCrudService; async create() { // 自定义事务、调用多个 service、做额外校验 } async resetPassword() { // 非标准资源动作 } } ``` 同名方法会优先使用你手写的实现,因此你可以只覆写部分默认行为。 ### 裁剪默认路由[​](#裁剪默认路由 "裁剪默认路由的直接链接") 如果你不想暴露所有默认路由,可以通过 `routes.only` 或 `routes.exclude` 控制。 ``` @Crud({ model: UserEntity, service: UserCrudService, routes: { only: ['list', 'detail', 'create'], }, }) ``` 这对于“只能查、不能删”或“只开放后台管理的一部分动作”的场景很有用。 ## 函数式路由模式[​](#函数式路由模式 "函数式路由模式的直接链接") 如果项目使用函数式 API,而不是类式 Controller,可以从 `@midwayjs/crud/functional` 导入 `defineCrudRoutes()`。 ### 最小示例[​](#最小示例 "最小示例的直接链接") ``` import { defineApi } from '@midwayjs/core/functional'; import { defineCrudRoutes } from '@midwayjs/crud/functional'; import { UserEntity } from '../entity/user'; import { UserCrudService } from '../service/user.crud'; const crudRoutes = defineCrudRoutes({ model: UserEntity, service: UserCrudService, }); export default defineApi('/users', api => ({ ...crudRoutes(api), })); ``` ### 和自定义动作一起使用[​](#和自定义动作一起使用 "和自定义动作一起使用的直接链接") 函数式模式最常见的用法,是把默认 CRUD 路由和自定义动作合并在同一个 `defineApi()` 里。 ``` export default defineApi('/users', api => ({ ...crudRoutes(api), resetPassword: api .post('/:id/reset-password') .handle(async ({ input, ctx }) => { return { ok: true }; }), })); ``` 这样可以让“标准资源动作”和“业务动作”共存在同一个资源路由下。 ## 查询协议[​](#查询协议 "查询协议的直接链接") 列表接口使用统一的查询协议,这是这个组件最重要的能力之一。 ### 支持的 query 参数[​](#支持的-query-参数 "支持的 query 参数的直接链接") * `page=` * `limit=` * `sort=:`,可重复传入 * `filter=||||`,可重复传入 * `search=` * `join=`,可重复传入 * `fields=` 例如: ``` GET /users?page=1&limit=20&sort=createdAt:DESC&filter=status||eq||active&search=harry&join=profile ``` ### 支持的过滤操作符[​](#支持的过滤操作符 "支持的过滤操作符的直接链接") 首阶段支持: * `eq` * `ne` * `gt` * `gte` * `lt` * `lte` * `in` * `like` ### 查询协议的约束[​](#查询协议的约束 "查询协议的约束的直接链接") 这些约束是有意设计出来的,用来保证资源接口的一致性: * `sort` 字段必须在 `sortable` 白名单里 * `filter` 字段必须在 `filterable` 白名单里 * `search` 只会作用于 `searchable` 白名单 * `join` 必须在 `join` 白名单里 * `join` 首阶段只支持一层关系名,不支持 `profile.company` 也就是说,这个组件不会让客户端随意拼接任意字段查询,而是让你在服务端声明资源允许暴露的查询能力。 ### 在 `@Crud()` 中声明查询能力[​](#在-crud-中声明查询能力 "在-crud-中声明查询能力的直接链接") ``` @Crud({ model: UserEntity, service: UserCrudService, query: { defaultLimit: 20, maxLimit: 100, sortable: ['id', 'createdAt'], filterable: ['status'], searchable: ['name', 'email'], join: ['profile'], }, }) ``` 这样配置后,查询行为就会按这个白名单执行。 ## 返回结构[​](#返�回结构 "返回结构的直接链接") 默认列表接口会返回统一的分页结构,而不是直接返回数组。 ``` type CrudPageResult = { data: T[]; meta: { page: number; limit: number; total: number; pageCount: number; hasNext: boolean; hasPrev: boolean; }; }; ``` 这能让前端和不同资源接口之间保持一致的分页消费方式。 其他默认返回规则: * `detail` 返回单个资源对象 * `create` 返回创建后的资源对象 * `update` 返回更新后的资源对象 * `delete` 默认返回 `204 No Content` ## DTO、Validation 与 Swagger[​](#dtovalidation-与-swagger "DTO、Validation 与 Swagger的直接链接") CRUD 路由会尽量复用现有 Midway 组件,而不是另起一套协议。 ### DTO 绑定[​](#dto-绑定 "DTO 绑定的直接链接") 你可以在 `@Crud()` 中声明: * `dto.create` * `dto.update` * `dto.replace` * `dto.query` 例如: ``` @Crud({ model: UserEntity, service: UserCrudService, dto: { create: CreateUserDTO, update: UpdateUserDTO, query: UserQueryDTO, }, }) ``` ### Validation[​](#validation "Validation的直接链接") 如果项目里启用了 `@midwayjs/validation` 或兼容的 validation service: * `dto.create` 会用于创建请求体校验 * `dto.update` 会用于更新请求体校验 * `dto.replace` 会用于替换请求体校验 * `dto.query` 会用于列表查询参数校验 如果没有安装 validation 组件,CRUD 本身不会强行报错,而是只跳过这一步自动校验。 ### Swagger[​](#swagger "Swagger的直接链接") 自动生成的 CRUD 路由会复用现有 Web 元数据链,所以 Swagger 组件可以识别到这些路由。 也就是说: * 默认路由会出现在 Swagger 文档里 * 基础的 path / query / body / response 元数据会被自动补齐 这意味着你不需要为每一个简单资源接口手动补一遍同样的 swagger 装饰器。 ## 软删除[​](#软删除 "软删除的直接链接") 默认删除行为是**硬删除**。 如果你希望某个资源使用软删除,需要显式开启: ``` @Crud({ model: UserEntity, service: UserCrudService, delete: { mode: 'soft', }, }) ``` 开启后: * `DELETE /:id` 会走软删除 * `list` / `detail` 默认排除已软删的数据 * 如果底层实体或仓储不支持软删除,会直接报错 ### 为什么不是默认软删除[​](#为什么不是默认软删除 "为什么不是默认软删除的直接链接") 因为软删除不是所有资源都适合: * 会影响唯一键约束 * 会影响查询逻辑 * 会影响索引设计 * 会影响后台数据管理 所以这里采用的是“显式开启”的策略,而不是默认偷偷帮你切换成软删。 ## 一个更完整的类式示例[​](#一个更完整的类式示��例 "一个更完整的类式示例的直接链接") 下面给一个稍完整一点的例子,把前面的内容串起来。 ``` import { Controller, Inject, Provide } from '@midwayjs/core'; import { Crud } from '@midwayjs/crud'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { TypeOrmCrudService } from '@midwayjs/crud/typeorm'; import { Repository } from 'typeorm'; @Provide() export class UserCrudService extends TypeOrmCrudService { @InjectEntityModel(UserEntity) repo: Repository; } @Controller('/users') @Crud({ model: UserEntity, service: UserCrudService, dto: { create: CreateUserDTO, update: UpdateUserDTO, query: UserQueryDTO, }, query: { defaultLimit: 20, maxLimit: 100, sortable: ['id', 'createdAt'], filterable: ['status'], searchable: ['name', 'email'], join: ['profile'], }, delete: { mode: 'soft', }, }) export class UserController { @Inject() crudService: UserCrudService; } ``` 这段代码的效果是: * 生成一个 `/users` 资源接口 * 自动获得标准 CRUD 路由 * 自动使用统一查询协议 * 自动按 DTO 做校验(如果启用了 validation) * 自动被 swagger 扫描 * 删除逻辑使用软删除 ## 二级导出[​](#二级导出 "二级导出的直接链接") 组件提供这些稳定入口: * `@midwayjs/crud` * `@midwayjs/crud/typeorm` * `@midwayjs/crud/mikro` * `@midwayjs/crud/sequelize` * `@midwayjs/crud/mongoose` * `@midwayjs/crud/functional` 建议这样理解: * 主入口:核心类型 + `@Crud()` * 数据库二级入口:各自的 CRUD service 适配 * `functional`:函数式路由适配 ## 最后的建议[​](#最后的建议 "最后的建议的直接链接") 如果你是第一次接触这个组件,建议按这个顺序使用: 1. 先学 `service-only`,把它当一个标准 CRUD service 2. 再用 `@Crud()` 快速展开简单资源接口 3. 最后再用函数式模式或高级查询配置 这样更容易理解它的边界,也更不容易把复杂业务错误地塞进自动 CRUD 层。 --- # EggJS Midway 可以使用 EggJS 作为上层 Web 框架,EggJS 提供了非常多常用的插件和 API,帮助用户快速构建企业级 Web 应用。本章节内容,主要介绍 EggJS 在 Midway 中如何使用自身的能力。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/web@4 egg --save $ npm i @midwayjs/egg-ts-helper --save-dev ``` 针对 EggJS 场景,这些包列举如下。 ``` "dependencies": { "@midwayjs/web": "^4.0.0", "@midwayjs/core": "^4.0.0", "egg": "^2.0.0", "egg-scripts": "^2.10.0" }, "devDependencies": { "@midwayjs/egg-ts-helper": "^1.0.1", }, ``` | @midwayjs/web | **必须**,Midway EggJS 适配层 | | ----------------------- | ------------------------------------------ | | @midwayjs/core | **必须**,Midway 核心包 | | egg | **必须**,EggJS 依赖包,提供定义等其他能力 | | egg-scripts | **可选**,EggJS 启动脚本 | | @midwayjs/egg-ts-helper | **可选**,EggJS 定义生成工具 | 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=egg-v3 my_project # npm v7 $ npm init midway -- --type=egg-v3 my_project ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as web from '@midwayjs/web'; import { join } from 'path'; @Configuration({ imports: [web], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: web.Application; async onReady() { // ... } } ``` ## 和默认 EggJS 的不同之处[​](#和默认-eggjs-的不同之处 "和默认 EggJS 的不同之处的直接链接") * 1、从 v3 开始,midway 提供了更多的组件,大部分 egg 内置插件默认禁用 * 2、baseDir 默认调整为 `src` 目录,服务器上为 `dist` 目录 * 3、禁用 egg-logger,全部替换为 @midwayjs/logger,不可切换 整个架构如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1614842824740-fc0c1432-3ace-4f77-b51f-15212984b168.png) ## 目录结构[​](#目录结构 "目录结构的直接链接") 除了 Midway 提供的目录结构外,EggJS 还有一些特殊的目录结构(不可变),整个结构如下。 ``` ➜ my_midway_app tree . ├── src | ├── app.ts ## EggJS 扩展 Worker 生命周期文件(可选) | ├── agent.ts ## EggJS 扩展 Agent 生命周期文件(可选) | ├── app ## EggJS 固定的根目录(可选) | │ ├── public ## EggJS 静态托管插件的默认目录(可配) | │ | └── reset.css | │ ├── view (可选) ## EggJS 模板渲染的默认目录(可配) | │ | └── home.tpl | │ └── extend (可选) ## EggJS 扩展目录(可配) | │ ├── helper.ts (可选) | │ ├── request.ts (可选) | │ ├── response.ts (可选) | │ ├── context.ts (可选) | │ ├── application.ts (可选) | │ └── agent.ts (可选) | │ | ├── config | | ├── plugin.ts | | ├── config.default.ts | | ├── config.prod.ts | | ├── config.test.ts (可选) | | ├── config.local.ts (可选) | | └── config.unittest.ts (可选) │ ├── controller ## Midway 控制器目录(推荐) │ ├── service ## Midway 服务目录(推荐) │ └── schedule ## Midway 定时器目录(推荐) │ ├── typings ## EggJS 定义生成目录 ├── test ├── package.json └── tsconfig.json ``` 以上是 EggJS 的目录结构全貌,其中包含了很多 EggJS 特有的目录,有一些在 Midway 体系中已经有相应的能力替代,可以直接替换。整个结构,基本上等价于将 EggJS 的目录结构移动到了 `src` 目录下。 由于 EggJS 是基于约定的框架,整个工程的目录结构是固定的,这里列举一些常用的约定目录。 | `src/app/public/**` | 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)。 | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `src/config/config.{env}.ts` | 用于编写配置文件,具体参见[配置](https://eggjs.org/zh-cn/basics/config.html)。 | | `src/config/plugin.js` | 用于配置需要加载的插件,具体参见[插件](https://eggjs.org/zh-cn/basics/plugin.html)。 | | `test/**` | 具体参见[单元测试](https://eggjs.org/zh-cn/core/unittest.html)。 | | `src/app.js` 和 `src/agent.js` | 用于自定义启动时的初始化工作,可选,具体参见[启动自定义](https://eggjs.org/zh-cn/basics/app-start.html)。关于`agent.js`的作用参见[Agent机制](https://eggjs.org/zh-cn/core/cluster-and-ipc.html#agent-%E6%9C%BA%E5%88%B6)。 | ## 配置定义[​](#配置定义 "配置定义的直接链接") Midway 在脚手架中提供了标准的 EggJS 的 TS 配置写法,MidwayConfig 中包括了 egg 中配置的定义和属性提示,结构如下。 ``` // src/config/config.default.ts import { MidwayConfig, MidwayAppInfo } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo) => { return { // use for cookie sign key, should change to your own and keep security keys: appInfo.name + '_xxxx', egg: { port: 7001, }, // security: { // csrf: false, // }, } as MidwayConfig; }; ``` 通过这样返回方法的形式,在运行期会被自动执行,合并进完整的配置对象。 这个函数的参数为 `MidwayAppConfig` 类型,值为以下内容。 | **appInfo** | **说明** | | ----------- | ---------------------------------------------------------------------- | | pkg | package.json | | name | 应用名,同 pkg.name | | baseDir | 应用代码的 src (本地开发)或者 dist (上线后)目录 | | appDir | 应用代码的目录 | | HOME | 用户目录,如 admin 账户为 /home/admin | | root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 | 信息 注意,这里的 `baseDir` 和 `appDir` 和 EggJS 应用有所区别。 ## 使用 Egg 插件[​](#使用-egg-插件 "使用 Egg 插件的直接链接") 插件是 EggJS 的特色之一,`@midwayjs/web` 也支持 EggJS 的插件体系,但是在有 Midway 组件的情况下,尽可能优先使用 Midway 组件。 插件一般通过 npm 模块的方式进行复用。 ``` $ npm i egg-mysql --save ``` 然后需要在应用或框架的 `src/config/plugin.js` 中声明开启。 如果有 `export default` ,请写在其中。 ``` import { EggPlugin } from 'egg'; export default { static: false, // default is true mysql: { enable: true, package: 'egg-mysql' } } as EggPlugin; ``` 如果没有 `export default` ,可以直接导出。 ``` // src/config/plugin.ts // 使用 mysql 插件 export const mysql = { enable: true, package: 'egg-mysql', }; ``` 在开启插件之后,我们就可以在业务代码中使用插件提供的功能了。一般来说,插件会将对象挂载到 EggJS 的 `app` 和 `ctx` 之上,然后直接使用。 ``` app.mysql.query(sql, values); // egg 提供的方法 ``` 在 Midway 中可以通过 `@App` 获取 `app` 对象,以及在请求作用域中通过 `@Inject() ctx` 获取 `ctx` 对象,所以我们可以通过注入来获取插件对象。 ``` import { Provide, Inject, Get } from '@midwayjs/core'; import { Application, Context } from '@midwayjs/web'; @Provide() export class HomeController { @App() app: Application; @Inject() ctx: Context; @Get('/') async home() { this.app.mysql.query(sql, values); // 调用 app 上的方法(如果有的话) this.ctx.mysql.query(sql, values); // 调用挂载在 ctx 上的方法(如果有的话) } } ``` 此外,还可以通过 `@Plugin` 装饰器来直接注入 `app` 挂载的插件,默认情况下,如果不传参数,将以属性名作为 key。 ``` import { Provide, Get, Plugin } from '@midwayjs/core'; @Provide() export class HomeController { @Plugin() mysql: any; @Get('/') async home() { this.mysql.query(sql, values); } } ``` 信息 `@Plugin() mysql` 等价于 `app.mysql` 。 `@Plugin` 的作用就是从 app 对象上拿对应属性名的插件,所以 `@Plugin() xxx` 就等于 `app['xxx']` 。 ## Web 中间件[​](#web-中间件 "Web 中间件的直接链接") 中间件样例如下: ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/web'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const startTime = Date.now(); await next(); console.log(Date.now() - startTime); }; } } ``` 警告 注意 1、如果要继续使用 EggJS 传统的函数式写法,必须将文件放在 `src/app/middleware` 下 2、egg 自带的内置中间件已经集成 应用中间件。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as egg from '@midwayjs/web'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [egg] // ... }) export class MainConfiguration { @App() app: egg.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 更多用法请参考 [Web 中间件](/docs/middleware.md) ## 中间件顺序[​](#中间件顺序 "中间件顺序的直接链接") 由于 egg 也有自己的中间件逻辑,在新版本中,我们将中间件加载顺序做了一定的处理,执行顺序如下: * 1、egg 框架中的中间件 * 2、egg 插件通过 config.coreMiddleware 添加的顺序 * 3、业务代码配置在 config.middleware 中配置的顺序 * 4、app.useMiddleware 添加的顺序 因为 midway 的中间件会后置加载,所以我们可以在 onReady 中进行自定义排序。 ## BodyParser[​](#bodyparser "BodyParser的直接链接") egg 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 和 `form` 类型。 如需 text 或者 xml,可以自行配置。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { formLimit: '1mb', jsonLimit: '1mb', textLimit: '1mb', xmlLimit: '1mb', }, } ``` 注意,使用 Postman 做 Post 请求时的类型选择: ![postman](https://img.alicdn.com/imgextra/i4/O1CN01QCdTsN1S347SuzZU5_!!6000000002190-2-tps-1017-690.png) ## 定时任务[​](#定时任务 "定时任务的直接链接") v3 开始请参考 [bull 组件](/docs/extensions/bull.md) 。 如需兼容之前的 [egg 定时任务](https://eggjs.org/zh-cn/basics/schedule.html) ,请照下列方法。 首先安装 `midway-schedule` 依赖。 ``` $ npm i midway-schedule --save ``` 添加到插件中即可。 ``` // src/config/plugin.ts export default { schedule: true, schedulePlus: { enable: true, package: 'midway-schedule', }, }; ``` 使用请参考上一版本文档。 ## 日志[​](#日志 "日志的直接链接") v3 开始无法使用 egg-logger,请参考 [日志](/docs/logger.md) 章节。 ## 异常处理[​](#异常处理 "异常处理的直接链接") EggJS 框架通过 [onerror](https://github.com/eggjs/egg-onerror) 插件提供了统一的错误处理机制,会作为 Midway 的兜底错误逻辑,和 [错误过滤器](/docs/error_filter.md) 不冲突。 对一个请求的所有处理方法(Middleware、Controller、Service)中抛出的任何异常都会被它捕获,并自动根据请求想要获取的类型返回不同类型的错误(基于 [Content Negotiation](https://tools.ietf.org/html/rfc7231#section-5.3.2))。 | 请求需求的格式 | 环境 | errorPageUrl 是否配置 | 返回内容 | | -------------- | ---------------- | --------------------- | ---------------------------------------------------- | | HTML & TEXT | local & unittest | - | onerror 自带的错误页面,展示详细的错误信息 | | HTML & TEXT | 其他 | 是 | 重定向到 errorPageUrl | | HTML & TEXT | 其他 | 否 | onerror 自带的没有错误信息的简单错误页(不推荐) | | JSON & JSONP | local & unittest | - | JSON 对象或对应的 JSONP 格式响应,带详细的错误信息 | | JSON & JSONP | 其他 | - | JSON 对象或对应的 JSONP 格式响应,不带详细的错误信息 | onerror 插件的配置中支持 errorPageUrl 属性,当配置了 errorPageUrl 时,一旦用户请求线上应用的 HTML 页面异常,就会重定向到这个地址。 在 `src/config/config.default.ts` 中 ``` // src/config/config.default.ts module.exports = { onerror: { // 线上页面发生异常时,重定向到这个页面上 errorPageUrl: '/50x.html', }, }; ``` ## 扩展 Application/Context/Request/Response[​](#扩展-applicationcontextrequestresponse "扩展 Application/Context/Request/Response的直接链接") ### 增加扩展逻辑[​](#增加扩展逻辑 "增加扩展逻辑的直接链接") 虽然 MidwayJS 并不希望直接将属性挂载到 koa 的 Context,App 上(会造成管理和定义的不确定性),但是 EggJS 的这项功能依旧可用。 文件位置如下。 ``` ➜ my_midway_app tree . ├── src │ ├── app │ │ └── extend │ │ ├── application.ts │ │ ├── context.ts │ │ ├── request.ts │ │ └── response.ts │ ├── config │ └── interface.ts ├── test ├── package.json └── tsconfig.json ``` 内容和原来的 EggJS 相同。 ``` // src/app/extend/context.ts export default { get hello() { return 'hello world'; }, }; ``` ### 增加扩展定义[​](#增加扩展定义 "增加扩展定义的直接链接") Context 请使用 Midway 的方式来扩展,请查看 [扩展上下文定义](/docs/context_definition.md)。 其余的部分,沿用 egg 的方式,请在 `src/interface.ts` 中扩展。 ``` // src/interface.ts declare module 'egg' { interface Request { // ... } interface Response { // ... } interface Application { // ... } } ``` 信息 业务自定义扩展的定义请 **不要放在根目录** `typings` 下,避免被 ts-helper 工具覆盖掉。 ## 使用 egg-scripts 部署[​](#使用-egg-scripts-部署 "使用 egg-scripts 部署的直接链接") 由于 EggJS 提供了默认的多进程部署工具 `egg-scripts` ,Midway 也继续支持这种方式,如果上层是 EggJS,推荐这种部署方式。 首先在依赖中,确保安装 `egg-scripts` 包。 ``` $ npm i egg-scripts --save ``` 添加 `npm scripts` 到 `package.json`: 在上面的代码构建之后,使用我们的 `start` 和 `stop` 命令即可完成启动和停止。 ``` "scripts": { "start": "egg-scripts start --daemon --title=********* --framework=@midwayjs/web", "stop": "egg-scripts stop --title=*********", } ``` 信息 `*********` 的地方是你的项目名。 > 注意:`egg-scripts` 对 Windows 系统的支持有限,参见 [#22](https://github.com/eggjs/egg-scripts/pull/22)。 #### **启动参数** ``` $ egg-scripts start --port=7001 --daemon --title=egg-server-showcase ``` Copy 如上示例,支持以下参数: * `--port=7001` 端口号,默认会读取环境变量 process.env.PORT,如未传递将使用框架内置端口 7001。 * `--daemon` 是否允许在后台模式,无需 nohup。若使用 Docker 建议直接前台运行。 * `--env=prod` 框架运行环境,默认会读取环境变量 process.env.EGG\_SERVER\_ENV, 如未传递将使用框架内置环境 prod。 * `--workers=2` 框架 worker 线程数,默认会创建和 CPU 核数相当的 app worker 数,可以充分的利用 CPU 资源。 * `--title=egg-server-showcase` 用于方便 ps 进程时 grep 用,默认为 `egg-server-\${appname}`。 * `--framework=yadan` 如果应用使用了[自定义框架](https://eggjs.org/zh-cn/advanced/framework.html),可以配置 package.json 的 egg.framework 或指定该参数。 * `--ignore-stderr` 忽略启动期的报错。 * `--https.key` 指定 HTTPS 所需密钥文件的完整路径。 * `--https.cert` 指定 HTTPS 所需证书文件的完整路径。 * 所有 [egg-cluster](https://github.com/eggjs/egg-cluster) 的 Options 都支持透传,如 --port 等。 更多参数可查看 [egg-scripts](https://github.com/eggjs/egg-scripts) 和 [egg-cluster](https://github.com/eggjs/egg-cluster) 文档。 信息 使用 egg-scripts 部署的日志会存放在 **用户目录** 下\*\*,\*\*比如 `/home/xxxx/logs` 。 ## 启动环境[​](#启动环境 "启动环境的直接链接") 原有 egg 使用 `EGG_SERVER_ENV` 中作为环境标志,在 Midway 中请使用 `MIDWAY_SERVER_ENV`。 ## State 类型定义[​](#state-类型定义 "State 类型定义的直接链接") 在 egg 底层的 koa 的 Context 中有一个特殊的 State 属性,通过和 Context 类似的方式可以扩展 State 定义。 ``` // src/interface.ts declare module '@midwayjs/web/dist/interface' { interface Context { abc: string; } interface State{ bbb: string; ccc: number; } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") ``` // src/config/config.default export default { // ... egg: { port: 7001, }, } ``` `@midwayjs/web` 所有参数如下: | 配置项 | 类型 | 描述 | | ----------------- | ------------------ | -------------------------------------- | | port | number | 必填,启动的端口 | | key | string | Buffer | | cert | string | Buffer | | ca | string | Buffer | | hostname | string | 监听的 hostname,默认 127.1 | | http2 | boolean | 可选,http2 支持,默认 false | | queryParseMode | simple\|extended | 默认为 extended | | queryParseOptions | `qs.IParseOptions` | 解析选项,当使用'simple'模式解析时可用 | 以上的属性,对本地和使用 `bootstrap.js` 部署的应用生效。 ### 修改端口[​](#修改端口 "修改端口的直接链接") 提示 注意,这个方式只会对本地研发,以及使用 bootstrap.js 文件部署的项目生效。 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 egg http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... egg: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... egg: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... egg: { key: join(__dirname, '../ssl/ssl.key'), cert: join(__dirname, '../ssl/ssl.pem'), }, } ``` ### favicon 设置[​](#favicon-设置 "favicon 设置的直接链接") 默认情况下,浏览器会发起一个 `favicon.ico` 的请求。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... siteFile: { '/favicon.ico': readFileSync(join(__dirname, 'favicon.png')), }, } ``` 如果开启了 `@midwayjs/static-file` 组件,那么会优先使用组件的静态文件托管。 ### 修改上下文日志[​](#修改上下文日志 "修改上下文日志的直接链接") 可以单独修改 egg 框架的上下文日志。 ``` export default { egg: { contextLoggerFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... }, }; ``` ### Query 数组解析[​](#query-数组解析 "Query 数组解析的直接链接") 默认情况下,`ctx.query` 会解析为忽略数组的情况,而 `ctx.queries` 会严格的将所有的字段都变成数组。 如果调整 `queryParseMode` ,则可以使 `ctx.query` 变为两者之间的结构(querystring 的结果)。 ``` // src/config/config.default export default { // ... egg: { // ... queryParseMode: 'simple', queryParseOptions: { arrayLimit: 100, }, }, } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、生成 ts 定义[​](#1生成-ts-定义 "1、生成 ts 定义的直接链接") Midway 提供了 `@midwayjs/egg-ts-hepler` 工具包,用于快速生成 EggJS 开发时所依赖的定义。 ``` $ npm install @midwayjs/egg-ts-helper --save-dev ``` 在 `package.json` 中加入对应的 `ets` 命令即可,一般来说,我们会在 dev 命令前加入,以保证代码的正确性。 ``` "scripts": { "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", }, ``` 信息 在第一次编写代码前,需要执行一次此命令才能有 ts 定义生成。 EggJS 生成的定义在 `typings` 目录中。 ``` ➜ my_midway_app tree . ├── src ## midway 项目源码 ├── typings ## EggJS 定义生成目录 ├── test ├── package.json └── tsconfig.json ``` ### 2、EggJS 中 Configuration 的特殊情况[​](#2eggjs-中-configuration-的特殊情况 "2、EggJS 中 Configuration 的特殊情况的直接链接") 在 EggJS 下, `configuration.ts` 中的生命周期**只会在 worker 下加载执行**。如果在 Agent 有类似的需求,请直接使用 EggJS 自身的 `agent.ts` 处理。 ### 3、异步初始化配置无法覆盖插件配置[​](#3异步初始化配置无法覆盖插件配置 "3、异步初始化配置无法覆盖插件配置的直接链接") `onConfigLoad` 生命周期会在 egg 插件(若有)初始化之后执行,所以不能用于覆盖 egg 插件所使用的配置。 ### 4、默认的 csrf 错误[​](#4默认的-csrf-错误 "4、默认的 csrf 错误的直接链接") 在 post 请求,特别是第一次时用户会发现一个 csrf 报错。原因是 egg 在框架中默认内置了安全插件 [egg-security](https://github.com/eggjs/egg-security), 默认开启了 csrf 校验。 我们可以在配置中关闭它,但是更好的是去[**了解它**](https://eggjs.org/zh-cn/core/security.html#%E5%AE%89%E5%85%A8%E5%A8%81%E8%83%81-csrf-%E7%9A%84%E9%98%B2%E8%8C%83)之后再做选择。 ``` export const security = { csrf: false, }; ``` ### 5、不存在定义的问题[​](#5不存在定义的问题 "5、不存在定义的问题的直接链接") 一些 egg 插件未提供 ts 定义,导致使用会出现未声明方法的情况,比如 egg-mysql。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01mv68zG1zN6nALff8n_!!6000000006701-2-tps-1478-876.png) 可以使用 any 绕过。 ``` await (this.app as any).mysql.query(sql); ``` 或者可以自行增加扩展定义。 ### 6、获取 Http Server[​](#6获取-http-server "6、获取 Http Server的直接链接") Eggjs 内部封装了原始的 HttpServer,需要通过事件获取。 ``` // src/configuration.ts import { Configuration, App } from '@midwayjs/core'; import { Application } from '@midwayjs/web'; @Configuration(/***/) export class MainConfiguration { @App('egg') app: Application; // ... async onServerReady() { this.app.once('server', (server) => { // ... }) } } ``` --- # ETCD etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中可以作为服务注册于发现,也可以作为 key-value 存储的中间件。 Midway 提供基于 [etcd3](https://github.com/microsoft/etcd3) 模块封装的组件,提供 etcd 的客户端调用能力。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/etcd@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/etcd": "^4.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as etcd from '@midwayjs/etcd'; import { join } from 'path' @Configuration({ imports: [ // ... etcd, ], // ... }) export class MainConfiguration { } ``` ## 配置默认客户端[​](#配置默认客户端 "配置默认客户端的直接链接") 大部分情况下,我们可以只使用默认客户端来完成功能。 ``` // src/config/config.default.ts export default { // ... etcd: { client: { host: [ '127.0.0.1:2379' ] }, }, } ``` ## 使用默认客户端[​](#使用默认客户端 "使用默认客户端的直接链接") 配置完成后,我们就可以在代码中使用了。 ``` import { Provide } from '@midwayjs/core'; import { ETCDService } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdService: ETCDService; async invoke() { await this.etcdService.put('foo').value('bar'); const fooValue = await this.etcdService.get('foo').string(); console.log('foo was:', fooValue); const allFValues = await this.etcdService.getAll().prefix('f').keys(); console.log('all our keys starting with "f":', allFValues); await this.etcdService.delete().all(); } } ``` 更多 API 请参考 ts 定义或者 [官网文档](https://microsoft.github.io/etcd3/classes/etcd3.html)。 ## 多实例配置[​](#多实例配置 "多实例配置的直接链接") ``` // src/config/config.default.ts export default { // ... etcd: { clients: { instance1: { { host: [ '127.0.0.1:2379' ] }, }, instance2: { { host: [ '127.0.0.1:2379' ] }, } } }, } ``` ## 多实例获取[​](#多实例获取 "多实例获取的直接链接") ``` import { Provide } from '@midwayjs/core'; import { ETCDServiceFactory } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdServiceFactory: ETCDServiceFactory; async invoke() { const instance1 = this.etcdServiceFactory.get('instance1'); // ... const instance2 = this.etcdServiceFactory.get('instance2'); // ... } } ``` ## 动态创建实例[​](#动态创建实例 "动态创建实例的直接链接") ``` import { Provide } from '@midwayjs/core'; import { ETCDServiceFactory } from '@midwayjs/etcd'; import { join } from 'path'; @Provide() export class UserService { @Inject() etcdServiceFactory: ETCDServiceFactory; async invoke() { const instance3 = await this.etcdServiceFactory.createInstance({ host: [ '127.0.0.1:2379' ] }, 'instance3'); // ... } } ``` ## 服务发现[​](#服务发现 "服务发现的直接链接") 从 v4 开始提供基于统一抽象的服务发现能力,虽然 ETCD 并不太适合作为服务发现的注册中心来使用,但是我们仍实现了 ETCD 作为服务发现的客户端能力。 服务发现包括 **注册服务** 和 **获取服务** 两部分。 ### 配置服务发现[​](#配置服务发现 "配置服务发现的直接链接") 你需要先配置一个客户端;若存在多个客户端,可通过 `serviceDiscoveryClient` 指定用于服务发现的客户端。 通过 `serviceDiscovery` 配置服务发现选项: ``` // src/config/config.default.ts export default { etcd: { clients: { default: { hosts: ['127.0.0.1:2379'] } }, serviceDiscovery: { namespace: 'services', ttl: 30, // 可选:loadBalancer: LoadBalancerType.ROUND_ROBIN } } } ``` 说明:`namespace` 为键空间前缀,实例键结构为 `namespace/serviceName/instanceId`;`ttl` 为实例过期时间(秒)。 ### 注册服务发现[​](#注册服务发现 "注册服务发现的直接链接") 服务启动后,将当前服务注册到 ETCD: ``` import { Configuration, Inject } from '@midwayjs/core'; import { EtcdServiceDiscovery } from '@midwayjs/etcd'; @Configuration({}) export class MainConfiguration { @Inject() etcdDiscovery: EtcdServiceDiscovery; async onServerReady() { // 创建服务发现客户端(可传入覆盖项) const client = this.etcdDiscovery.createClient(); // 注册当前服务并上线(写入键并绑定租约) await client.register({ id: client.defaultMeta.id, serviceName: 'order', ttl: 30, meta: { version: '1.0.0', host: client.defaultMeta.host, port: '7001' } }); } } ``` 说明:注册时会默认上线,无需显式调用 `online`。ETCD 通过 Lease 维持 TTL,定时续约保证存活;`offline` 删除键并撤销租约;`deregister` 注销并清理状态。重复调用 `register/online/offline/deregister` 具有幂等性。 ### 获取可用服务[​](#获取可用服务 "获取可用服务的直接链接") 在任意位置获取可用实例或按负载均衡选择一个实例: ``` @Provide() export class OrderService { @Inject() etcdDiscovery: EtcdServiceDiscovery; async getService() { const instances = await this.etcdDiscovery.getInstances('order'); const one = await this.etcdDiscovery.getInstance('order'); return { instances, one }; } } ``` 返回的实例为注册时写入的对象(`EtcdInstanceMetadata`),通常包含 `serviceName/id/ttl/meta/tags/status` 等字段。 --- # 事件 事件组件是基于 [eventemitter2](https://github.com/EventEmitter2/EventEmitter2) 实现的,提供了强大的事件处理能力。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/event-emitter@4 --save ``` 或者在 `package.json` 中增加依赖后,重新安装 ``` { "dependencies": { "@midwayjs/event-emitter": "^4.0.0" } } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 首先在 `configuration.ts` 中引入组件: ``` import { Configuration } from '@midwayjs/core'; import * as eventEmitter from '@midwayjs/event-emitter'; @Configuration({ imports: [ // ... eventEmitter ] }) export class MainConfiguration { } ``` ## 基础使用[​](#基础使用 "基础使用的直接链接") ### 定义事件监听器[​](#定义事件监听器 "定义事件监听器的直接链接") 警告 注意:`@OnEvent()` 装饰器只能用在单例(Singleton)类上。如果在非单例类上使用,事件监听器将无法正常工作。 使用 `@OnEvent()` 装饰器来定义事件监听器: ``` import { Provide, Singleton } from '@midwayjs/core'; import { OnEvent } from '@midwayjs/event-emitter'; @Provide() @Singleton() // 必须使用 @Singleton 装饰器 export class UserService { @OnEvent('user.created') async handleUserCreated(user: any) { console.log('新用户创建:', user); } } ``` ### 发送事件[​](#发送事件 "发送事件的直接链接") 通过注入 `EventEmitterService` 来发送事件: ``` import { Inject } from '@midwayjs/core'; import { EventEmitterService } from '@midwayjs/event-emitter'; @Provide() export class UserController { @Inject() eventEmitterService: EventEmitterService; async createUser() { const user = { id: 1, name: 'harry' }; // ... 创建用户逻辑 // 发送同步事件 this.eventEmitterService.emit('user.created', user); // 或者发送异步事件 await this.eventEmitterService.emitAsync('user.created', user); } } ``` ## 高级特性[​](#高级特性 "高级特性的直接链接") ### 事件监听器选项[​](#事件监听器选项 "事件监听器选项的直接链接") `@OnEvent()` 装饰器支持多个配置选项,每个选项都有其特定的用途: #### prependListener[​](#prependlistener "prependListener的直接链接") 用于控制监听器的执行顺序。设置为 `true` 时,会将监听器添加到监听器队列的开头,这样可以确保该监听器最先执行。 ``` @Provide() @Singleton() export class UserService { // 这个监听器会最先执行 @OnEvent('user.created', { prependListener: true }) async handleUserCreatedFirst(user: any) { console.log('第一个处理用户创建事件'); } // 这个监听器会在队列末尾执行 @OnEvent('user.created') async handleUserCreated(user: any) { console.log('后续处理用户创建事件'); } } ``` #### suppressErrors[​](#suppresserrors "suppressErrors的直接链接") 控制事件处理器中的错误处理行为: * 默认值为 `true`,表示错误会被捕获并忽略 * 设置为 `false` 时,错误会被抛出,可以在外层捕获 ``` @Provide() @Singleton() export class UserService { // 错误会被抛出 @OnEvent('user.created', { suppressErrors: false }) async handleWithError(user: any) { throw new Error('处理失败'); // 这个错误会被抛出 } // 错误会被忽略 @OnEvent('user.created', { suppressErrors: true }) async handleSuppressError(user: any) { throw new Error('处理失败'); // 这个错误会被忽略 } } // 在调用处可以捕获错误 @Provide() export class UserController { @Inject() eventEmitterService: EventEmitterService; async createUser() { try { await this.eventEmitterService.emitAsync('user.created', { id: 1 }); } catch (err) { // 可以捕获到 suppressErrors: false 的处理器抛出的错误 console.error('事件处理失败:', err); } } } ``` #### async[​](#async "async的直接链接") 控制事件处理器的执行方式: * 设置为 `true` 时,处理器会在单独的事件循环中异步执行 * 默认为 `false`,会按顺序同步执行 ``` @Provide() @Singleton() export class UserService { // 异步执行,不会阻塞其他处理器 @OnEvent('user.created', { async: true }) async handleAsync(user: any) { await someTimeConsumingTask(); console.log('异步处理完成'); } // 同步执行,会按顺序等待 @OnEvent('user.created') async handleSync(user: any) { console.log('同步处理'); } } ``` ### 通配符事件[​](#通配符事件 "通配符事件的直接链接") 通配符事件允许你使用模式匹配来监听一组相关的事件。需要在配置中启用 `wildcard: true`。 #### 配置启用[​](#配置启用 "配置启用的直接链接") ``` // config/config.default.ts export default { eventEmitter: { wildcard: true, // 启用通配符功能 } } ``` #### 使用示例[​](#使用示例 "使用示例的直接链接") ``` @Provide() @Singleton() export class UserService { // 监听所有用户相关事件 @OnEvent('user.*') async handleUserEvents(...args: any[]) { // 注意:通配符模式下,事件处理器直接接收发送事件时传入的参数 console.log('事件参数:', args); } // 监听多层级的事件 @OnEvent('user.*.detail') async handleUserDetailEvents(...args: any[]) { // 可以匹配 user.profile.detail, user.settings.detail 等 console.log('事件参数:', args); } } // 发送事件示例 @Provide() export class UserController { @Inject() eventEmitterService: EventEmitterService; async updateUser() { // 这些事件都会被上面的 user.* 处理器捕获 await this.eventEmitterService.emitAsync('user.created', { id: 1 }); await this.eventEmitterService.emitAsync('user.updated', { id: 1, name: 'new name' }); await this.eventEmitterService.emitAsync('user.profile.detail', { id: 1, profile: {} }); } } ``` 信息 注意:在使用通配符事件时,事件处理器的参数直接是事件发送时传入的参数。无法在处理器中获取具体触发的事件名称,所以建议在发送事件时将必要的信息包含在事件参数中。 ### 命名空间事件[​](#命名空间事件 "命名空间事件的直接链接") 命名空间事件提供了一种组织和分组事件的方式。通过 `delimiter` 配置分隔符。 #### 配置启用[​](#配置启用-1 "配置启用的直接链接") ``` // config/config.default.ts export default { eventEmitter: { delimiter: '.' // 设置命名空间分隔符 } } ``` #### 使用示例[​](#使用示例-1 "使用示例的直接链接") ``` @Provide() @Singleton() export class OrderService { // 监听订单命名空间下的创建事件 @OnEvent('order.created') async handleOrderCreated(order: any) { console.log('订单创建:', order); } // 如果需要使用通配符匹配,需要额外启用 wildcard: true @OnEvent('order.payment.*') async handleOrderPaymentEvents(...args: any[]) { // 可以匹配 order.payment.success, order.payment.failed 等 console.log('事件参数:', args); } } // 发送命名空间事件 @Provide() export class PaymentService { @Inject() eventEmitterService: EventEmitterService; async processPayment() { // 发送支付成功事件 await this.eventEmitterService.emitAsync('order.payment.success', { orderId: '123', amount: 100 }); } } ``` 信息 注意:命名空间的分隔符默认是 `.`,你可以通过 `delimiter` 配置修改。如果需要使用通配符(如 `*`)进行事件匹配,则需要额外启用 `wildcard: true` 配置。 ## 配置[​](#配置 "配置的直接链接") 在 `config.default.ts` 中可以配置 Event Emitter 的行为: ``` export default { // ... eventEmitter: { // 是否开启通配符事件 wildcard: true, // 命名空间分隔符 delimiter: '.', // 是否启用新监听器事件 newListener: false, // 是否启用移除监听器事件 removeListener: false, // 设置最大监听器数量 maxListeners: 10, // 是否启用详细的内存泄漏检测 verboseMemoryLeak: false, } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1. 事件处理顺序[​](#1-事件处理顺序 "1. 事件处理顺序的直接链接") * 默认情况下,事件处理器按照注册顺序执行 * 使用 `prependListener: true` 可以将处理器添加到队列开头 * 异步事件处理器(`emitAsync`)会按顺序等待每个处理器完成 ### 2. 错误处理[​](#2-错误处理 "2. 错误处理的直接链接") * 默认情况下,事件处理器中的错误会被抑制(`suppressErrors: true`) * 设置 `suppressErrors: false` 可以让错误抛出 * 使用 `emitAsync` 时,可以通过 try/catch 捕获错误 ### 3. 性能考虑[​](#3-性能考虑 "3. 性能考虑的直接链接") * 合理使用通配符事件,过多的通配符匹配可能影响性能 * 设置适当的 `maxListeners` 值,避免内存泄漏 * 及时移除不需要的事件监听器 --- # Express 本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/express@4 --save $ npm i @types/body-parser @types/express @types/express-session --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/express": "^4.0.0", // ... }, "devDependencies": { "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", "@types/express-session": "^1.17.4", // ... } } ``` 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=express-v3 my_project # npm v7 $ npm init midway -- --type=express-v3 my_project ``` 针对 Express,Midway 提供了 `@midwayjs/express` 包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。 信息 我们使用的 Express 版本为 `v4` 。 ## 目录结构[​](#目录结构 "目录结构的直接链接") ``` . ├── src │ ├── controller # controller接口的地方 │ ├── service # service逻辑处理的地方 | └── configuration.ts # 入口及生命周期配置、组件管理 ├── test ├── package.json └── tsconfig.json ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() {} } ``` ## 控制器(Controller)[​](#控制器controller "控制器(Controller)的直接链接") 整个请求控制器的写法和 Midway 适配其他框架的类似。为了和其他场景的框架写法一致,在请求的时候,Midway 将 Express 的 `req` 映射为 `ctx` 对象。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/express'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home(@Query() id) { console.log(id); // req.query.id === id return 'hello world'; // 简单返回,等价于 res.send('hello world'); } } ``` 你也可以额外注入 `req` 和 `res` 。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { Context, Response, NextFunction } from '@midwayjs/express'; @Controller('/') export class HomeController { @Inject() ctx: Context; // 即为 req @Inject() req: Context; @Inject() res: Response; @Get('/') async home(@Query() id) { // this.req.query.id === id } } ``` ## Web 中间件[​](#web-中间件 "Web 中间件的直接链接") Express 的中间件写法比较特殊,它的参数不同。 ``` import { Middleware } from '@midwayjs/core'; import { Context, Response, NextFunction } from '@midwayjs/express'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async ( req: Context, res: Response, next: NextFunction ) => { console.log('Request...'); next(); }; } } ``` 注意,这里我们导出了一个 `ReportMiddleware` 类,为了方便对接异步流程,`resolve` 返回可以是 async 函数。 Express 中的 next 方法,用于调用到下一个中间件,指的注意的是,Express 中间件并非洋葱模型,是单向调用。 ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 我们可以把上面编写的中间件应用到单个 Controller 上,也可以将中间件应用到单个路由上。 ``` import { Controller, Get, Provide } from '@midwayjs/core'; @Controller('/', { middleware: [ ReportMiddleware ]}) // controller 级别的中间件 export class HomeController { @Get('/', { middleware: [ ReportMiddleware ]}) // 路由级别的中间件 async home() { return 'hello world' } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 直接使用 Midway 提供的 `app.generateMiddleware` 方法,在入口处加载全局中间件。 ``` // src/configuration.ts import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { ReportMiddleware } from './middleware/report.middleware.ts' @Configuration({ imports: [express], }) export class MainConfiguration implements ILifeCycle { @App() app: express.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 除了加载 Class 形式的中间件外,也支持加载传统的 Express 中间件。 ``` // src/configuration.ts import { Configuration, ILifeCycle, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; @Configuration({ imports: [express], }) export class MainConfiguration implements ILifeCycle { @App() app: express.Application; async onReady() { this.app.useMiddleware((req, res, next) => { // xxx }); } } ``` 你可以通过注入 `app` 对象,来调用到所有 Express 上的方法。 ## 返回统一处理[​](#返回统一处理 "返回统一处理的直接链接") 由于 Express 中间件是单向调用,无法在返回时执行,为此我们额外设计了一个 `@Match` 装饰的过滤器,用于处理返回值的行为。 比如,我们可以定义针对全局返回的过滤器。 ``` // src/filter/globalMatch.filter.ts import { Match } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Match() export class GlobalMatchFilter { match(value, req, res) { // ... return { status: 200, data: { value }, }; } } ``` 也可以匹配特定的路由做返回。 ``` // src/filter/api.filter.ts import { Match } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Match((ctx: Context, res: Response) => { return ctx.path === '/api'; }) export class APIMatchFilter { match(value, req: Context, res: Response) { // ... return { data: { message: data: value, }, }; } } ``` 需要应用到 app 中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; import { APIMatchFilter } from './filter/api.filter'; import { GlobalMatchFilter } from 'filter/globalMatch.filter'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() { // ... this.app.useFilter([APIMatchFilter, GlobalMatchFilter]); } } ``` 注意,这类过滤器是按照添加的顺序来匹配执行。 ## 错误处理[​](#错误处理 "错误处理的直接链接") 和普通的项目相同,使用错误过滤器,但是参数略有不同。 ``` import { Catch } from '@midwayjs/core'; import { Context, Response } from '@midwayjs/express'; @Catch() export class GlobalError { catch(err: Error, req: Context, res: Response) { if (err) { return { status: err.status ?? 500, message: err.message, } } } } ``` 需要应用到 app 中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import { join } from 'path'; import { GlobalError } from './filter/global.filter'; @Configuration({ imports: [express], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: express.Application; async onReady() { this.app.useMiddleware((req, res, next) => { next(); }); this.app.useFilter([GlobalError]); } } ``` 注意,`@Match` 和 `@Catch` 都是过滤器,在内部会自动判断做区分执行。。 ## Cookie[​](#cookie "Cookie的直接链接") `@midwayjs/express` 自带 `cookie parser` 功能,使用的是 `cookie-parser` 模块。 针对 Cookie,统一使用 `keys` 作为秘钥。 ``` // src/config/config.default export default { keys: ['key1', 'key2'], } ``` 获取 Cookie。 ``` const cookieValue = req.cookies['cookie-key']; ``` 设置 Cookie。 ``` res.cookie( 'cookie-key', 'cookie-value', cookieOptions ); ``` ## Session[​](#session "Session的直接链接") `@midwayjs/express` 内置了 Session 组件,给我们提供了 `ctx.session` 来访问或者修改当前用户 Session 。 默认情况下为 `cookie-session` ,默认配置如下。 ``` // src/config/config.default export default { session: { name: 'MW_SESS', resave: true, saveUninitialized: true, cookie: { maxAge: 24 * 3600 * 1000, // ms httpOnly: true, // sameSite: null, }, } } ``` 我们可以通过简单的 API 来设置 session。 ``` @Controller('/') export class HomeController { @Inject() req; @Get('/') async get() { // set all this.req.session = req.query; // set value this.req.session.key = 'abc'; // get const key = this.req.session.key; // remove this.req.session = null; // set max age this.req.session.maxAge = Number(req.query.maxAge); // ... } } ``` ## BodyParser[​](#bodyparser "BodyParser的直接链接") `@midwayjs/express` 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 、`text`和 `urlencoded` 类型。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { json: { enable: true, limit: '1mb', strict: true, }, raw: { enable: false, limit: '1mb', }, text: { enable: true, limit: '1mb', }, urlencoded: { enable: true, extended: false, limit: '1mb', parameterLimit: 1000, }, }, } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/express` 的配置样例如下: ``` // src/config/config.default export default { // ... express: { port: 7001, }, } ``` 所有属性描述如下: | 属性 | 类型 | 描述 | | ------------ | ------------------------------------------ | ------------------------------------------------------- | | port | number | 可选,启动的端口 | | globalPrefix | string | 可选,全局的 http 前缀 | | keys | string\[] | 可选,Cookies 签名,如果上层未写 keys,也可以在这里设置 | | hostname | string | 可选,监听的 hostname,默认 127.1 | | key | string \| Buffer \| Array\ | 可选,Https key,服务端私钥 | | cert | string \| Buffer \| Array\ | 可选,Https cert,服务端证书 | | ca | string \| Buffer \| Array\ | 可选,Https ca | | http2 | boolean | 可选,http2 支持,默认 false | ### 修改端口[​](#修改端口 "修改端口的直接链接") 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 Express http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... express: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... express: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... express: { key: join(__dirname, '../ssl/ssl.key'), cert: join(__dirname, '../ssl/ssl.pem'), }, } ``` ### 修改上下文日志[​](#修改上下文日志 "修改上下文日志的直接链接") 可以单独修改 express 框架的上下文日志。 ``` export default { express: { contextLoggerFormat: info => { // 等价 req const req = info.ctx; const userId = req?.['session']?.['userId'] || '-'; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${userId} - ${Date.now() - req.startTime}ms ${req.method}] ${info.message}`; } // ... }, }; ``` --- # gRPC gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。 本篇内容演示了如何在 Midway 体系下,提供 gRPC 服务,以及调用 gRPC 服务的方法。 Midway 当前采用了最新的 gRPC 官方推荐的 [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) 进行开发,并提供了一些工具包,用于快速发布服务和调用服务。 我们使用的模块为 `@midwayjs/grpc` ,既可以独立发布服务,又可以接入其它框架调用 gRPC 服务。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | **调用服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | **其他** | 描述 | | | -------------------- | -- | | 可作为主框架独立使用 | ✅ | | 可独立添加中间件 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/grpc@4 --save $ npm i @midwayjs/grpc-helper --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/grpc": "^4.0.0", // ... }, "devDependencies": { "@midwayjs/grpc-helper": "^1.0.0", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 提示 不管是提供服务还是调用服务,都需要开启组件。 `@midwayjs/grpc` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as grpc from '@midwayjs/grpc'; @Configuration({ imports: [grpc], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as grpc from '@midwayjs/grpc'; @Configuration({ imports: [koa, grpc], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 大致的目录结构如下,`src/provider` 是提供 gRPC 服务的目录。 ``` . ├── package.json ├── proto ## proto 定义文件 │ └── helloworld.proto ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── provider ## gRPC 提供服务的文件 │ └── greeter.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 定义服务接口[​](#定义服务接口 "定义服务接口的直接链接") 在微服务中,定义一个服务需要特定的接口定义语言(IDL)来完成,在 gRPC中 默认使用 Protocol Buffers 作为序列化协议。 序列化协议独立于语言和平台,提供了多种语言的实现,Java,C++,Go 等等,每一种实现都包含了相应语言的编译器和库文件。所以 gRPC 是一个提供和调用都可以跨语言的服务框架。 一个gRPC服务的大体架构可以用官网上的一幅图表示。 ![](https://img.alicdn.com/imgextra/i3/O1CN01kpIyg51k8i5DtcGpZ_!!6000000004639-2-tps-621-445.png) Protocol Buffers 协议的文件,默认的后缀为 `.proto` 。.proto后缀的IDL文件,并通过其编译器生成特定语言的数据结构、服务端接口和客户端Stub代码。 信息 由于 proto 文件可以跨语言使用,为了方便共享,我们一般将 proto 文件放在 src 目录外侧,方便其他工具复制分发。 下面是一个基础的 `proto/helloworld.proto` 文件。 ``` syntax = "proto3"; package helloworld; service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } ``` proto3 表示的是第三版的 protobuf 协议,是 gRPC 目前推荐的版本,“语法简单,功能更全”。 我们可以用 `service` 格式,定义服务体,其中可以包含方法。同时,我们可以更加细致的通过 `message` 描述服务具体的请求参数和响应参数。 我们可以从 [Google 的官网文档](https://developers.google.com/protocol-buffers/docs/overview#simple) 中查看更多细节。 信息 大家会看到,这和 Java 中的 Class 非常相像,每个结构就相当于 Java 中的一个类。 ### 编写 proto 文件[​](#编写-proto-文件 "编写 proto 文件的直接链接") 现在我们再来看之前的服务,是不是就很好理解了。 ``` syntax = "proto3"; package helloworld; // 服务的定义 service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // 服务的请求参数 message HelloRequest { string name = 1; } // 服务的响应参数 message HelloReply { string message = 1; } ``` 我们定义了一个名为 `Greeter` 的服务,包含一个 `HelloRequest` 结构的请求体,以及返回 `HelloReply` 结构的响应体。 接下去,我们将对这个服务给大家做演示。 ### 生成代码定义[​](#生成代码定义 "生成代码定义的直接链接") 传统的 gRPC 框架,需要用户手动编写 proto 文件,以及生成 js 服务,最后再根据 js 生成的服务再编写实现,在 Midway 体系下,我们提供了一个 grpc-helper 工具包来加速这个过程。 如果没有安装,可以先安装。 ``` $ npm i @midwayjs/grpc-helper --save-dev ``` grpc-helper 工具的作用,是将用户提供的 proto 文件,生成对应可读的 ts interface 文件。 我们可以添加一个脚本,方便这个过程。 ``` { "scripts": { "generate": "tsproto --path proto --output src/domain" } } ``` 然后执行 `npm run generate` 。 上述命令执行后,会在代码的 `src/domain` 目录中生成 proto 文件对应的服务接口定义。 信息 不管是提供 gRPC 服务还是调用 gRPC 服务,都要先生成定义。 生成的代码如下,包含有一个命名空间(namespace),以及命名空间下的两个 TypeScript Interface, `Greeter` 用于编写服务端实现, `GreeterClient` 用于编写客户端实现。 ``` /** * This file is auto-generated by grpc-helper */ import * as grpc from '@midwayjs/grpc'; // 生成的命名空间 export namespace helloworld { // 服务端使用的定义 export interface Greeter { // Sends a greeting sayHello(data: HelloRequest): Promise; } // 客户端使用的定义 export interface GreeterClient { // Sends a greeting sayHello(options?: grpc.IClientOptions): grpc.IClientUnaryService; } // 请求体结构 export interface HelloRequest { name?: string; } // 响应体结构 export interface HelloReply { message?: string; } } ``` 信息 每当 proto 文件被修改时,就需要重新生成对应的服务定义,然后将对应的方法实现。 ## 提供 gRPC 服务(Provider)[​](#提供-grpc-服务provider "提供 gRPC 服务(Provider)的直接链接") ### 编写服务提供方(Provider)[​](#编写服务提供方provider "编写服务提供方(Provider)的直接链接") 在 `src/provider` 目录中,我们创建 `greeter.ts` ,内容如下 ``` import { MSProviderType, Provider, GrpcMethod, } from '@midwayjs/core'; import { helloworld } from '../domain/helloworld'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { return { message: 'Hello ' + request.name }; } } ``` 信息 注意,@Provider 装饰器和 @Provide 装饰器不同,前者用于提供服务,后者用于依赖注入容器扫描标识的类。 我们使用 `@Provider` 暴露出一个 RPC 服务, `@Provider` 的第一个参数为 RPC 服务类型,这个参数是个枚举,这里选择 GRPC 类型。 `@Provider` 的第二个参数为 RPC 服务的元数据,这里指代的是 gRPC 服务的元数据。这里需要写入 gRPC 的 package 字段,即 proto 文件中的 package 字段(这里的字段用于和 proto 文件加载后的字段做对应)。 对于普通的 gRPC 服务接口(UnaryCall),我们只需要使用 `@GrpcMethod()` 装饰器修饰即可。修饰的方法即为服务定义本身,入参为 proto 中定义好的入参,return 值即为定义好的响应体。 信息 注意,生成的 Interface 是为了更好的编写服务代码,规范结构,请务必按照定义编写。 ### 配置服务[​](#配置服务 "配置服务的直接链接") 配置内容如下。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpcServer: { services: [ { protoPath: join(appInfo.appDir, 'proto/hero.proto'), package: 'hero', }, { protoPath: join(appInfo.appDir, 'proto/helloworld.proto'), package: 'helloworld', } ], } }; } ``` services 字段是数组,意味着 Midway 项目可以同时发布多个 gRPC 服务。每个 service 的结构为: | 属性 | 类型 | 描述 | | --------- | ------ | -------------------------- | | protoPath | string | 必选,proto 文件的绝对路径 | | package | string | 必选,服务对应的 package | 除了 Service 配置之外,还有一些其他的配置。 | 属性 | 类型 | 描述 | | ------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- | | url | string | 可选,gRPC 服务地址,默认 6565 端口,比如 'localhost:6565' | | loaderOptions | Object | 可选,proto file loader 的 options | | credentials | ServerCredentials | 可选,grpc Server binding 时的 credentials 参数选项 | | serverOptions | ChannelOptions | 可选,grpc Server 的 [自定义 options](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js#supported-channel-options) | ### 提供安全证书[​](#提供安全证书 "提供安全证书的直接链接") 可以通过 `credentials` 参数传递安全证书。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; import { ServerCredentials } from '@midwayjs/grpc'; import { readFileSync } from 'fs'; import { join } from 'path'; const cert = readFileSync(join(__dirname, './cert/server.crt')); const pem = readFileSync(join(__dirname, './cert/server.pem')); const key = readFileSync(join(__dirname, './cert/server.key')); export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpcServer: { // ... credentials: ServerCredentials.createSsl(cert, [{ private_key: key, cert_chain: pem }]); } }; } ``` ### 编写单元测试[​](#编写单元测试 "编写单元测试的直接链接") `@midwayjs/grpc` 库提供了一个 `createGRPCConsumer` 方法,用于实时调用客户端,一般我们用这个方法做测试。 警告 这个方法每次调用会实时连接,不建议将该方法用在生产环境。 在测试中写法如下。 ``` import { createApp, close } from '@midwayjs/mock'; import { Framework, createGRPCConsumer } from '@midwayjs/grpc'; import { join } from 'path'; import { helloworld } from '../src/domain/helloworld'; describe('test/index.test.ts', () => { it('should create multiple grpc service in one server', async () => { const baseDir = join(__dirname, '../'); // 创建服务 const app = await createApp(); // 调用服务 const service = await createGRPCConsumer({ package: 'helloworld', protoPath: join(baseDir, 'proto', 'helloworld.proto'), url: 'localhost:6565' }); const result = await service.sayHello().sendMessage({ name: 'harry' }); expect(result.message).toEqual('Hello harry'); await close(app); }); }); ``` ## 调用 gRPC 服务(Consumer)[​](#调用-grpc-服务consumer "调用 gRPC 服务(Consumer)的直接链接") 我们编写一个 gRPC 服务来调用上面的暴露的服务。 信息 事实上,你可以在 Web 的 Controller,或者 Service 等其他地方来调用,这里只是做一个示例。 ### 调用配置[​](#调用配置 "调用配置的直接链接") 你需要在 `src/config/config.default.ts` 中增加你需要调用的目标服务以及它的 proto 文件信息。 比如,这里我们填写了上面暴露的服务本身,以及该服务的 proto,包名等信息(函数形式)。 ``` // src/config/config.default import { MidwayAppInfo, MidwayConfig } from '@midwayjs/core'; export default (appInfo: MidwayAppInfo): MidwayConfig => { return { // ... grpc: { services: [ { url: 'localhost:6565', protoPath: join(appInfo.appDir, 'proto/helloworld.proto'), package: 'helloworld', }, ], }, }; } ``` ### 代码调用[​](#代码调用 "代码调用的直接链接") 配置完后,我们就可以在代码里调用了。 `@midwayjs/grpc` 提供了 `clients` ,可以方便的获取到已配置的服务。我们只需要在需要注入的地方,注入这个对象即可。 比如: ``` import { Provide, Inject, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; } ``` 我们通过 `clients` 获取到对方服务的客户端实例,然后调用即可。 ``` import { Provide, Inject, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provide() export class UserService { @Inject() grpcClients: Clients; async invoke() { // 获取服务 const greeterService = this.grpcClients.getService( 'helloworld.Greeter' ); // 调用服务 const result = await greeterService.sayHello() .sendMessage({ name: 'harry' }); // 返回结果 return result; } } ``` 我们也可以利用 `@Init` 装饰器,将需要调用的服务缓存到属性上。这样可以在其他方法调用时复用。 示例如下。 ``` import { GrpcMethod, MSProviderType, Provider, Inject, Init, } from '@midwayjs/core'; import { helloworld, hero } from '../interface'; import { Clients } from '@midwayjs/grpc'; @Provider(MSProviderType.GRPC, { package: 'hero' }) export class HeroService implements hero.HeroService { // 注入客户端 @Inject() grpcClients: Clients; greeterService: helloworld.GreeterClient; @Init() async init() { // 赋值一个服务实例 this.greeterService = this.grpcClients.getService( 'helloworld.Greeter' ); } @GrpcMethod() async findOne(data) { // 调用服务 const result = await greeterService.sayHello() .sendMessage({ name: 'harry' }); // 返回结果 return result; } } ``` ## 流式服务[​](#流式服务 "流式服务的直接链接") gRPC 的流式服务用于减少连接,让服务端或者客户端不需要等待即可执行任务,从而提高执行效率。 gRPC 的流式服务分为三种,以服务端角度来说,为 * 服务端接收流(客户端推) * 服务端响应流(服务端推) * 双向流 下面我们将一一介绍。 ### 流式 proto 文件[​](#流式-proto-文件 "流式 proto 文件的直接链接") 流式的 proto 文件写法不同,需要在希望使用流式的地方将参数标记为 `stream` 。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; int32 num = 2; } message Num { int32 id = 1; int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } // 双向流 rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 该服务生成的接口定义为: ``` import { IClientDuplexStreamService, IClientReadableStreamService, IClientUnaryService, IClientWritableStreamService, IClientOptions, } from '@midwayjs/grpc'; export namespace math { export interface AddArgs { id?: number; num?: number; } export interface Num { id?: number; num?: number; } /** * server interface */ export interface Math { add(data: AddArgs): Promise; addMore(data: AddArgs): Promise; // 服务端推,客户端读 sumMany(data: AddArgs): Promise // 客户端端推,服务端读 addMany(num: AddArgs): Promise; } /** * client interface */ export interface MathClient { add(options?: IClientOptions): IClientUnaryService; addMore(options?: IClientOptions): IClientDuplexStreamService; // 服务端推,客户端读 sumMany(options?: IClientOptions): IClientReadableStreamService; // 客户端端推,服务端读 addMany(options?: IClientOptions): IClientWritableStreamService; } } ``` ### 服务端推送[​](#服务端推送 "服务端推送的直接链接") 客户端调用一次,服务端可以多次返回。通过 `@GrpcMethod()` 的参数来标识流式类型。 可用的类型为: * `GrpcStreamTypeEnum.WRITEABLE` 服务端输出流(单工) * `GrpcStreamTypeEnum.READABLE` 客户端输出流(单工),服务端接受多次 * `GrpcStreamTypeEnum.DUPLEX` 双工流 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.WRITEABLE }) async sumMany(args: math.AddArgs) { this.ctx.write({ num: 1 + args.num }); this.ctx.write({ num: 2 + args.num }); this.ctx.write({ num: 3 + args.num }); this.ctx.end(); } // ... } ``` 服务端使用 `ctx.write` 方法来返回数据,由于是服务端流,可以返回多次。 返回结束后,请使用 `ctx.end()` 方法关闭流。 客户端,调用一次,接受多次数据。 比如下面的累加逻辑。 Promise 写法,会等待服务端数据都返回再做处理。 ``` // 服务端推送 let total = 0; let result = await service.sumMany().sendMessage({ num: 1, }); result.forEach(data => { total += data.num; }); // total = 9; ``` 事件写法,实时处理。 ``` // 服务端推送 let call = service.sumMany().getCall(); call.on('data', data => { // do something }); call.sendMessage({ num: 1, }); ``` ### 客户端推送[​](#客户端推送 "客户端推送的直接链接") 客户端调用多次,服务端接收多次数据,返回一个结果。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.READABLE})` 的参数来标识流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { sumDataList: number[] = []; @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.READABLE, onEnd: 'sumEnd' }) async addMany(data: math.Num) { this.sumDataList.push(data); } async sumEnd(): Promise { const total = this.sumDataList.reduce((pre, cur) => { return { num: pre.num + cur.num, } }); return total; } // ... } ``` 客户端每次调用,都会触发一次 `addMany` 方法。 在客户端发送 `end` 事件之后,会调用 `@GrpcMethod` 装饰器上的 `onEnd` 参数指定的方法,该方法的返回值即为最后客户端拿到的值。 客户端示例如下: ``` // 客户端推送 const data = await service.addMany() .sendMessage({num: 1}) .sendMessage({num: 2}) .sendMessage({num: 3}) .end(); // data.num = 6 ``` ### 双向流[​](#双向流 "双向流的直接链接") 客户端可以调用多次,服务端也可以接收多次数据,返回多个结果,类似于传统的 TCP 通信。通过 `@GrpcMethod({type: GrpcStreamTypeEnum.DUPLEX})` 的参数来标识双工流式类型。 服务端示例如下: ``` import { GrpcMethod, GrpcStreamTypeEnum, Inject, MSProviderType, Provider } from '@midwayjs/core'; import { Context, Metadata } from '@midwayjs/grpc'; import { math } from '../interface'; /** */ @Provider(MSProviderType.GRPC, { package: 'math' }) export class Math implements math.Math { @Inject() ctx: Context; @GrpcMethod({type: GrpcStreamTypeEnum.DUPLEX, onEnd: 'duplexEnd' }) async addMore(message: math.AddArgs) { this.ctx.write({ id: message.id, num: message.num + 10, }); } async duplexEnd() { console.log('got client end message'); } // ... } ``` 服务端可以随时使用 `ctx.write` 返回数据,也可以使用 `ctx.end` 来关闭流。 客户端示例: 对于双工通信的客户端,由于无法保证调用、返回的顺序,我们需要使用监听的模式来消费结果。 ``` const clientStream = service.addMore().getCall(); let total = 0; let idx = 0; duplexCall.on('data', (data: math.Num) => { total += data.num; idx++; if (idx === 2) { duplexCall.end(); // total => 29 } }); duplexCall.write({ num: 3, }); duplexCall.write({ num: 6, }); ``` 如果希望保证调用顺序,我们也提供了保证顺序的双向流调用方法,但是需要在 proto 中定义一个固定的 id,来确保顺序。 比如我们的 Math.proto,对每个入参和出参,都增加了一个固定的 id,所以可以固定顺序。 ``` syntax = "proto3"; package math; message AddArgs { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } message Num { int32 id = 1; // 这里的 id 名字是固定的 int32 num = 2; } service Math { rpc Add (AddArgs) returns (Num) { } rpc AddMore (stream AddArgs) returns (stream Num) { } // 服务端往客户端推 rpc SumMany (AddArgs) returns (stream Num) { } // 客户端往服务端推 rpc AddMany (stream AddArgs) returns (Num) { } } ``` 固定顺序的客户端调用方式如下: ``` // 保证顺序的双向流 const t = service.addMore(); const result4 = await new Promise((resolve, reject) => { let total = 0; // 第一次调用和返回 t.sendMessage({ num: 2 }) .then(res => { expect(res.num).toEqual(12); total += res.num; }) .catch(err => console.error(err)); // 第二次调用和返回 t.sendMessage({ num: 5 }).then(res => { expect(res.num).toEqual(15); total += res.num; resolve(total); }) .catch(err => console.error(err)); t.end(); }); // result4 => 27 ``` 默认的 id 为 `id` ,如果服务端定义不同,需要修改,可以在客户端调用时传递。 ``` // 保证顺序的双向流 const t = service.addMore({ messageKey: 'uid' }); ``` ## 元数据(Metadata)[​](#元数据metadata "元数据(Metadata)的直接链接") gRPC 的元数据等价于 HTTP 的上下文。 服务端通过 `ctx.sendMetadata` 方法返回元数据,也可以通过 `ctx.metadata` 获取客户端传递的元数据。 ``` import { MSProviderType, Provider, GrpcMethod, } from '@midwayjs/core'; import { helloworld } from '../domain/helloworld'; import { Context, Metadata } from '@midwayjs/grpc'; /** * 实现 helloworld.Greeter 接口的服务 */ @Provider(MSProviderType.GRPC, { package: 'helloworld' }) export class Greeter implements helloworld.Greeter { @Inject() ctx: Context; @GrpcMethod() async sayHello(request: helloworld.HelloRequest) { // 客户端传递的元数据 console.log(this.ctx.metadata); // 创建元数据 const meta = new Metadata(); this.ctx.metadata.add('xxx', 'bbb'); this.ctx.sendMetadata(meta); return { message: 'Hello ' + request.name }; } } ``` 客户端通过方法的 options 参数传递元数据。 ``` import { Metadata } from '@midwayjs/grpc'; const meta = new Metadata(); meta.add('key', 'value'); const result = await service.sayHello({ metadata: meta, }).sendMessage({ name: 'harry' }); ``` 获取元数据相对麻烦一些。 普通一元调用(UnaryCall)获取元数据需要使用 `sendMessageWithCallback` 方法。 ``` const call = service.sayHello().sendMessageWithCallback({ name: 'zhangting' }, (err) => { if (err) { reject(err); } }); call.on('metadata', (meta) => { // output meta }); ``` 其他流式服务,可以通过 `getCall()` 方法获取原始客户端流对象,从而直接订阅。 ``` // 获取服务,注意,这里没有 await const call = service.addMany().getCall(); call.on('metadata', (meta) => { // output meta }); ``` ## 超时处理[​](#超时处理 "超时处理的直接链接") 我们可以在调用服务时传递参数,单位毫秒。 ``` const result = await service.sayHello({ timeout: 5000 }).sendMessage({ name: 'harry' }); ``` --- # HTTP 代理 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的 HTTP 请求代理组件,支持 GET、POST 等多种请求方法。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/http-proxy@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/http-proxy": "^4.0.0" // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件 ``` // ... import * as proxy from '@midwayjs/http-proxy'; @Configuration({ imports: [ // ...other components proxy, ], }) export class MainConfiguration {} ``` ## 配置[​](#配置 "配置的直接链接") 代理配置定义如下: ``` // 代理配置类型 export interface HttpProxyConfig { // 匹配要代理的 URL 正则表达式 match: RegExp; // 替换匹配到的链接的 host,将请求代理到此地址 host?: string; // 通过正则的表达式捕获组处理代理地址 target?: string; // 转发请求超时时间,默认为0不设置超时时间 proxyTimeout?: number; // 忽略代理请求转发的 header 中的字段 ignoreHeaders?: { [key: string]: boolean; }; } ``` 代理支持单个代理和多个代理。 单个代理配置 ``` // src/config/config.default.ts export default { httpProxy: { match: /\/tfs\//, host: 'https://gw.alicdn.com', }, }; ``` 多个代理配置 ``` // src/config/config.default.ts // 代理配置类型 export default { httpProxy: { default: { // 一些每个策略复用的值,会和底下的策略进行合并 }, strategy: { gw: { // https://gw.alicdn.com/tfs/TB1.1EzoBBh1e4jSZFhXXcC9VXa-48-48.png match: /\/tfs\//, host: 'https://gw.alicdn.com', }, g: { // https://g.alicdn.com/mtb/lib-mtop/2.6.1/mtop.js match: /\/bdimg\/(.*)$/, target: 'https://sm.bdimg.com/$1', }, httpBin: { // https://httpbin.org/ match: /\/httpbin\/(.*)$/, target: 'https://httpbin.org/$1', }, }, }, }; ``` ## 示例:使用 host 配置代理[​](#示例使用-host-配置代理 "示例:使用 host 配置代理的直接链接") ``` export default { httpProxy: { match: /\/tfs\//, host: 'https://gw.alicdn.com', }, }; ``` 当请求您的站点路径为: `https://yourdomain.com/tfs/test.png` 时,`match` 字段配置的正则表达式成功匹配,那么就将原始请求路径中的 `host` 部分 `https://yourdomain.com` 替换为配置的 `https://gw.alicdn.com`,从而发起代理请求到 `https://gw.alicdn.com/tfs/test.png`,并把响应结果返回给请求您站点的用户。 ## 示例:使用 target 配置代理[​](#示例使用-target-配置代理 "示例:使用 target 配置代理的直接链接") ``` export default { httpProxy: { match: /\/httpbin\/(.*)$/, target: 'https://httpbin.org/$1', }, }; ``` 当请求您的站点路径为: `https://yourdomain.com/httpbin/get?name=midway` 时,`match` 字段配置的正则表达式成功匹配,同时正则的捕获组中有结果 `['get?name=midway']` ,那么就将原始请求路径中的 `$1` 部分替换为捕获组中的第 1 个数据(index: 0)的 `get?name=midway`,从而发起代理请求到 `https://httpbin.org/get?name=midway`,并把响应结果返回给请求您站点的用户。 --- # 多语言 Midway 提供了多语言组件,让业务可以快速指定不同的语言,展示不同的文案,也可以在 HTTP 场景配合请求参数,请求头等方式来使用。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/i18n@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/i18n": "^4.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 i18n 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as i18n from '@midwayjs/i18n'; @Configuration({ imports: [ // ... i18n ] }) export class MainConfiguration { //... } ``` ## 使用[​](#使用 "使用的直接链接") 组件提供了 `MidwayI18nService` 服务,用于翻译多语言文本。 使用 `translate` 方法,传入不同的文本关键字和参数,返回不同语言的文本内容。 ``` @Controller('/') export class UserController { @Inject() i18nService: MidwayI18nService; @Get('/') async index(@Query('username') username: string) { return this.i18nService.translate('HELLO_MESSAGE', { args: { username }, }); } } ``` ## 配置多语言文案[​](#配置多语言文案 "配置多语言文案的直接链接") 你可以在配置文件中直接配置,但是大多数情况下,文案会很多,有时候甚至可能文案在远端服务上,这个时候直接配置就不太现实。 一般来说,我们会将文案单独放到某个文案配置目录中,比如 `src/locales` 。 以 `src/locale` 这个目录为例,我们举个例子,结构如下: ``` . ├── src │ ├── locales | │ ├── en_US.json | │ └── zh_CN.json │ └── controller │ └── home.controller.ts ├── package.json └── tsconfig.json ``` 这里我们建了两个多语言的文件,`en_US.json` 和 `zh_CN.json`,分别代表英文和中文。 文件内容分别如下: ``` // src/locales/en_US.json { "hello": "Hello {username}", "email": "email id", "login": "login account", "createdAt": "register date" } ``` ``` // src/locales/zh_CN.json { "hello": "你好 {username}", "email": "邮箱", "login": "帐号", "createdAt": "注册时间" } ``` 每行一个字符串对,是一个标准的 JSON 格式内容,也可以使用 js/ts 文件,花括号中是可替换的参数占位。 同时,需要在配置中加入这两个 JSON,其中 `default` 是语言的默认分组。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), }, zh_CN: { default: require('../locale/zh_CN'), } }, } } ``` 这样就可以使用了,使用输出如下。 ``` this.i18nService.translate('hello', { args: { username: 'harry', }, locale: 'en_US', }); // output: Hello harry. this.i18nService.translate('hello', { args: { username: 'harry', }, locale: 'zh_CN', }); // output: 你好 harry. ``` ## 多语言文案分组[​](#多语言文案分组 "多语言文案分组的直接链接") 在如下配置中,用户配置的多语言文案在 `default` 分组中。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), }, zh_CN: { default: require('../locale/zh_CN'), } }, } } ``` 这样做的好处是,在其他组件或者业务代码中,我们也可以使用不同的分组名,来添加其他的多语言文案。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { en_US: { default: require('../locale/en_US'), user: require('../locale/user_en_US'), }, zh_CN: { default: require('../locale/zh_CN'), user: require('../locale/user_zh_CN'), } }, } } ``` 在代码中,如果调用非默认分组,需要指定分组参数。 ``` this.i18nService.translate('user.hello', { args: { username: 'harry', }, group: 'user', // 指定其他分组 locale: 'en_US', }); ``` ## 多语言文案格式[​](#多语言文案格式 "多语言文案格式的直接链接") 多语言文本中可以添加参数,参数可以有 `对象` 和 `数组` 两种形式。 对象形式如下,使用花括号作为占位符。 ``` Hello {username} ``` 使用时,通过配置传递,按对象 key 覆盖变量。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: { username }, }); } ``` 数组形式如下,使用数字作为占位符。 ``` Hello {0} ``` 使用时,通过配置传递,格式是数组形式,按数组顺序覆盖数字变量。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: [username] }); } ``` ## 动态添加多语言文案[​](#动态添加多语言文案 "动态添加多语言文案的直接链接") 有时候,多语言文案可能放在远端,比如数据库等,我们可以通过 `addLocale` 方法进行动态添加。 比如,在配置加载后,代码使用前。 ``` // configuration.ts // ... @Configuration({ imports: [ koa, i18n ] }) export class MainConfiguration { @Inject() i18nService: MidwayI18nService; async onReady() { this.i18nService.addLocale('zh_TW', { hello: '你好,{username} 美麗的世界' }); } // ... } ``` 在代码中就可以使用。 ``` async index(@Query('username') username: string) { return this.i18nService.translate('hello', { args: [username], locale: 'zh_TW' }); } ``` ## 通过参数指定当前语言[​](#通过参数指定当前语言 "通过参数指定当前语言的直接链接") 一般情况下,默认语言为 `en_US`,用户的浏览器访问一般会自带 `Accept-Language` 头,所以会正确识别语言。比如用中文浏览器访问,就能正常显示中文。 除此之外,在 HTTP 场景下可以通过 URL Query,Cookie,Header 来指定语言。 优先级从上到下: * query: /?locale=en-US * cookie: locale=zh-TW * header: Accept-Language: zh-CN,zh;q=0.5 当传递了这些参数之后,多语言数据会自动保存到当前用户的 Cookie 中,下次请求会直接用该设定好的语言。 ## 手动设置语言[​](#手动设置语言 "手动设置语言的直接链接") 可以通过调用 `saveRequestLocale` 设置当前语言。 ``` async index() { // ... this.i18nService.saveRequestLocale('zh_CN'); } ``` 如果开启了 `writeCookie` 配置,设置后会保存到当前用户的 Cookie 中,下次请求会使用该设置。 ## 语言选择优先级[​](#语言选择优先级 "语言选择优先级的直接链接") 这些多种设置语言的方式,有着不同的优先级,如下优先级从高到低: * 1、`i18nService.translate` 方法显式指定的语言 * 2、通过其他装饰器设置的语言,比如 `@Validate` 装饰器的参数(本质是调用了`i18nService.translate` 方法) * 3、通过 `saveRequestLocale` API 直接设置的当前语言 * 4、通过浏览器 Query,Cookie,Header 设置的语言(本质是调用了 `saveRequestLocale`) * 5、i18n 组件配置中的默认语言 ## 关于语言大小写[​](#关于语言大小写 "关于语言大小写的直接链接") 在代码内部,我们会将所有的多语言,fallback 规则,写入的文本串,返回的 locale 结果,使用下面的规则替代 * 1、使用中划线代替下划线 * 2、使用小写代替大写 即所有的 `en_US` 都会变成 `en-us`,`zh_CN` 会变成 `zh-cn`。 这样做会安全的适配 URL 和 Cookie。 ## View 中使用[​](#view-中使用 "View 中使用的直接链接") 在 Web 类型的框架中,我们默认添加了 locals 变量支持,可以在模板引擎中使用。 假设我们使用的模板引擎是 [Nunjucks](/docs/extensions/render.md),可以直接引用到 `i18n` 方法。 多语言文案如下: ``` { "hello": "Hello {username}", } ``` 模板如下: ``` {{ i18n('hello', user) }} ``` 示例如下: ``` // ... @Controller('/') export class UserController { @Inject() ctx: Context; @Get('/') async index() { await this.ctx.render('index', { // 注意这里是整个对象传递给模板 user: { username: 'harry', } }); } } ``` i18n 方法定义如下: ``` function i18n(templateName: string, args: Record) { // ... } ``` 方法名可以通过配置修改。 ``` // src/config/config.default.ts export default { // ... i18n: { localsField: 'i18n', } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") 大部分情况下,你只需要在配置 `localeTable` 添加你自己的多语言翻译即可。 下面是完整的配置,你可以在配置定义中找到。 ``` // src/config/config.default.ts export default { // ... i18n: { // 默认语言 "en_US" defaultLocale: 'en_US', // 把你的翻译文本放到这里 localeTable: { en_US: { // group name default: { // hello: 'hello' } }, zh_CN: { // group name default: { // hello: '你好' } }, }, // 语言映射,可以用 * 号通配 fallbacks: { // 'en_*': 'en_US', // pt: 'pt-BR', }, // 是否将请求参数写入 cookie writeCookie: true, resolver: { // url query 参数,默认是 "locale" queryField: 'locale', cookieField: { // Cookie 里的 key,默认是 "locale" fieldName: 'locale', // Cookie 域名,默认为空,代表当前域名有效 cookieDomain: '', // Cookie 默认的过期时间,默认一年 cookieMaxAge: FORMAT.MS.ONE_YEAR, }, }, localsField: 'i18n', // 缺失翻译键的处理函数,默认返回原始键名 missingKeyHandler: (message, options) => message, } } ``` ### 回写 Cookie[​](#回写-cookie "回写 Cookie的直接链接") 默认情况下,多语言组件会将当前用户的语言回写到 Cookie 中,避免下次请求再进行查找以提高性能,我们可以通过配置关闭这个行为。 ``` // src/config/config.default.ts export default { // ... i18n: { writeCookie: false, } } ``` ### 请求解析配置[​](#请求解析配置 "请求解析配置的直接链接") HTTP 场景下,我们提供了通过参数指定当前语言的能力。 默认情况下,组件通过下面的字段来查找。 * query 的 `locale` 字段 * cookie 的 `locale` 字段 * header 的 `Accept-Language` 部分 我们可以通过配置修改查询的字段。 比如,修改 Query 的字段。 ``` // src/config/config.default.ts export default { // ... i18n: { resolver: { queryField: 'abc' }, } } ``` 我们就可以通过 `/?abc=en-US` 来请求修改语言。 如果不希望通过请求来设置语言,可以将整个 `resolver` 解析关闭,对 Cookie 的回写也将同时停止。 ``` // src/config/config.default.ts export default { // ... i18n: { resolver: false, } } ``` ### 缺失翻译键处理[​](#缺失翻译键处理 "缺失翻译键处理的直接链接") 当翻译键在所有语言文件中都找不到时,i18n 组件会调用 `missingKeyHandler` 函数来处理这种情况。 默认情况下,当找不到翻译时,会返回原始的键名: ``` // 默认的 missingKeyHandler missingKeyHandler: (message, options) => message ``` 例如: ``` // 假设 "unknown_key" 在任何语言文件中都不存在 this.i18nService.translate('unknown_key'); // 返回: "unknown_key" ``` 你可以自定义缺失键的处理方式,比如添加特殊标记、记录日志等: ``` // src/config/config.default.ts export default { i18n: { missingKeyHandler: (message, options) => { // 记录缺失的翻译键 console.warn(`Missing translation: ${message}`, options); // 根据不同的组返回不同的格式 const group = options?.group || 'default'; const locale = options?.locale || 'default'; return `[${group}:${locale}:${message}]`; } } } ``` ## 常用语言[​](#常用语言 "常用语言的直接链接") | 语言 | 语言包名 | | ---------------- | -------- | | 阿拉伯 | ar\_EG | | 亞美尼亞 | hy\_AM | | 保加利亚语 | bg\_BG | | 加泰罗尼亚语 | ca\_ES | | 捷克语 | cs\_CZ | | 丹麦语 | da\_DK | | 德语 | de\_DE | | 希腊语 | el\_GR | | 英语 | en\_GB | | 英语(美式) | en\_US | | 西班牙语 | es\_ES | | 爱沙尼亚语 | et\_EE | | 波斯语 | fa\_IR | | 芬兰语 | fi\_FI | | 法语(比利时) | fr\_BE | | 法语 | fr\_FR | | 希伯来语 | he\_IL | | 印地语 | hi\_IN | | 克罗地亚语 | hr\_HR | | 匈牙利 | hu\_HU | | 冰岛语 | is\_IS | | 印度尼西亚语 | id\_ID | | 意大利语 | it\_IT | | 日语 | ja\_JP | | 格鲁吉亚语 | ka\_GE | | 卡纳达语 | kn\_IN | | 韩语/朝鲜语 | ko\_KR | | 库尔德语 | ku\_IQ | | 拉脱维亚语 | lv\_LV | | 马来语 | ms\_MY | | 蒙古语 | mn\_MN | | 挪威 | nb\_NO | | 尼泊尔语 | ne\_NP | | 荷兰语(比利时) | nl\_BE | | 荷兰语 | nl\_NL | | 波兰语 | pl\_PL | | 葡萄牙语(巴西) | pt\_BR | | 葡萄牙语 | pt\_PT | | 斯洛伐克语 | sk\_SK | | 塞尔维亚 | sr\_RS | | 斯洛文尼亚 | sl\_SI | | 瑞典语 | sv\_SE | | 泰米尔语 | ta\_IN | | 泰语 | th\_TH | | 土耳其语 | tr\_TR | | 罗马尼亚语 | ro\_RO | | 俄罗斯语 | ru\_RU | | 乌克兰语 | uk\_UA | | 越南语 | vi\_VN | | 简体中文 | zh\_CN | | 繁体中文 | zh\_TW | ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、测试配置全局语言不生效[​](#1测试配置全局语言不生效 "1、测试配置全局语言不生效的直接链接") 一般场景下,你 **无需** 配置全局语言,因为浏览器访问会自动带上语言信息,比如中文浏览器自动返回中文,英文浏览器自动返回英文。 假如你明确希望测试全局设置的效果,请务必按下面操作: * 1、如果使用的是浏览器,请清空页面 cookie 再访问,因为 cookie 中会记录上一次用户的语言信息 * 2、如果使用的是 Postman 等工具,请不要带上 cookie 以及语言相关的 Header,Query 等字段 ### 2、测试返回的语言非预期[​](#2测试返回的语言非预期 "2、测试返回的语言非预期的直接链接") 请使用浏览器进行测试,不要使用 Postman。 由于 Postman 请求不会带有浏览器语言相关的 Header,所以服务端无法自动判断语言。 如果你一定要使用 Postman,请参考浏览器请求,加上 `Accept-Language` Header。 --- # 信息查看 Midway 提供了 info 组件,用于展示应用的基本信息,方便排查问题。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/info@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/info": "^4.0.0", // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 info 组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ // ... info ] }) export class MainConfiguration { //... } ``` 在有些情况下,为了不想让应用信息透出,我们指定在特殊环境下生效。 ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ koa, { component: info, enabledEnvironment: ['local'], // 只在本地启用 } ] }) export class MainConfiguration { //... } ``` ## 查看信息[​](#查看信息 "查看信息的直接链接") 在默认情况下,info 组件会为 Http 场景自动添加一个中间件,我们可以通过 `/_info` 来访问。 默认情况下,会展示系统,进程,以及配置等关键信息。 效果如下: ![info](https://img.alicdn.com/imgextra/i3/O1CN01TCkSvr28x8T7gtnCl_!!6000000007998-2-tps-797-1106.png) ## 修改访问路由[​](#修改访问路由 "修改访问路由的直接链接") 为了安全,我们可以调整访问的路由。 ``` // src/config/config.default.ts export default { // ... info: { infoPath: '/_my_info', } } ``` ## 隐藏信息[​](#隐藏信息 "隐藏信息的直接链接") 默认情况下,info 组件会隐藏秘钥等信息。我们可以配置增减隐藏的关键字,这个配置会对 **环境变量** 以及 **多环境配置** 生效。 关键字可以使用通配符,比如增加一些关键字。 ``` // src/config/config.default.ts import { DefaultHiddenKey } from '@midwayjs/info'; export default { // ... info: { hiddenKey: DefaultHiddenKey.concat(['*abc', '*def', '*bbb*']), } } ``` ## 调用 API[​](#调用-api "调用 API的直接链接") info 组件默认提供了 `InfoService` 用于在非 Http 或是自定义的场景来使用。 比如: ``` import { Provide } from '@midwayjs/core'; import { InfoService } from '@midwayjs/info'; @Provide() export class userService { @Inject() inforService: InfoService async getInfo() { // 应用信息,应用名等 this.inforService.projectInfo(); // 系统信息 this.inforService.systemInfo(); // 堆内存,cpu 等 this.inforService.resourceOccupationInfo(); // midway 框架的信息 this.inforService.softwareInfo(); // 当前使用的环境配置 this.inforService.midwayConfig(); // 依赖注入容器中的服务 this.inforService.midwayService(); // 系统时间,时区,启动时常 this.inforService.timeInfo(); // 环境变量 this.inforService.envInfo(); // 依赖信息 this.inforService.dependenciesInfo(); // 网络信息 this.inforService.networkInfo(); } } ``` --- # JWT `JSON Web Token` (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为`JSON`对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 Midway 提供了 jwt 组件,简单提供了一些 jwt 相关的 API,可以基于它做独立的鉴权和校验。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/jwt@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/jwt": "^4.0.0" // ... }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 将 jwt 组件配置到代码中。 ``` import { Configuration, IMidwayContainer } from '@midwayjs/core'; import { IMidwayContainer } from '@midwayjs/core'; import * as jwt from '@midwayjs/jwt'; @Configuration({ imports: [ // ... jwt, ], }) export class MainConfiguration { // ... } ``` ## 基础配置[​](#基础配置 "基础配置的直接链接") 然后在配置中设置,默认未加密。 ``` // src/config/config.default.ts export default { // ... jwt: { secret: 'xxxxxxxxxxxxxx', // fs.readFileSync('xxxxx.key') sign: { // signOptions expiresIn: '2d', // https://github.com/vercel/ms }, verify: { // verifyOptions }, decode: { // decodeOptions } }, }; ``` 更多配置请查看 ts 定义。 ## 常用 API[​](#常用-api "常用 API的直接链接") Midway 将 jwt 常用 API 提供为同步和异步两种形式。 ``` import { Provide, Inject } from '@midwayjs/core'; import { JwtService } from '@midwayjs/jwt'; @Provide() export class UserService { @Inject() jwtService: JwtService; async invoke() { // 同步 API this.jwtService.signSync(payload, secretOrPrivateKey, options); this.jwtService.verifySync(token, secretOrPublicKey, options); this.jwtService.decodeSync(token, options); // 异步 API await this.jwtService.sign(payload, secretOrPrivateKey, options); await this.jwtService.verify(token, secretOrPublicKey, options); await this.jwtService.decode(token, options); } } ``` 这些 API 都来自于 [node-jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) 基础库,如果不了解请阅读原版文档。 ## 中间件示例[​](#中间件示例 "中间件示例的直接链接") 一般,jwt 还会配合中间件来完成鉴权,下面是一个自定义 jwt 鉴权的中间件示例。 ``` // src/middleware/jwt.middleware import { Inject, Middleware, httpError } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/koa'; import { JwtService } from '@midwayjs/jwt'; @Middleware() export class JwtMiddleware { @Inject() jwtService: JwtService; public static getName(): string { return 'jwt'; } resolve() { return async (ctx: Context, next: NextFunction) => { // 判断下有没有校验信息 if (!ctx.headers['authorization']) { throw new httpError.UnauthorizedError(); } // 从 header 上获取校验信息 const parts = ctx.get('authorization').trim().split(' '); if (parts.length !== 2) { throw new httpError.UnauthorizedError(); } const [scheme, token] = parts; if (/^Bearer$/i.test(scheme)) { try { //jwt.verify方法验证token是否有效 await this.jwtService.verify(token, { complete: true, }); } catch (error) { //token过期 生成新的token const newToken = getToken(user); //将新token放入Authorization中返回给前端 ctx.set('Authorization', newToken); } await next(); } }; } // 配置忽略鉴权的路由地址 public match(ctx: Context): boolean { const ignore = ctx.path.indexOf('/api/admin/login') !== -1; return !ignore; } } ``` 然后在入口启用中间件即可。 ``` // src/configuration.ts import { Configuration, App, IMidwayContainer, IMidwayApplication} from '@midwayjs/core'; import * as jwt from '@midwayjs/jwt'; @Configuration({ imports: [ // ... jwt, ], }) export class MainConfiguration { @App() app: IMidwayApplication; async onReady(applicationContext: IMidwayContainer): Promise { // 添加中间件 this.app.useMiddleware([ // ... JwtMiddleware, ]); } } ``` ## 原始 JWT 对象[​](#原始-jwt-对象 "原始 JWT 对象的直接链接") 可以通过导出的 `Jwt` 对象引用到原始实例上的对象和方法。 ``` import { Jwt } from '@midwayjs/jwt'; // Jwt.TokenExpiredError ``` --- # Kafka 在复杂系统的架构中,事件流是很重要的一环,包括从事件源中(数据库、传感器、移动设备等)以事件流的方式去实时捕获数据,持久化事件流方便检索,并实时和回顾操作处理响应事件流。 应用于支付和金融交易、实施跟踪和监控汽车等行业信息流动、捕获分析物联网数据等等。 在 Midway中,我们提供了订阅 Kafka 的能力,专门来满足用户的这类需求。 相关信息: **订阅服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 基础概念[​](#基础概念 "基础概念的直接链接") 分布式流处理平台 * 发布订阅(流)信息 * 容错(故障转移)存储信息(流),存储事件流 * 在消息流发生的时候进行处理,处理事件流 理解 Producer(生产者) * 发布消息到一个主题或多个 topic (主题)。 理解 Consumer(主题消费者) * 订阅一个或者多个 topic,并处理产生的信息。 理解 Stream API * 充当一个流处理器,从 1 个或多个 topic 消费输入流,并生产一个输出流到1个或多个输出 topic,有效地将输入流转换到输出流。 理解 Broker * 已发布的消息保存在一组服务器中,称之为 Kafka 集群。集群中的每一个服务器都是一个代理(Broker)。 消费者可以订阅一个或多个主题(topic),并从Broker拉数据,从而消费这些已发布的消息。 ![image.png](https://kafka.apache.org/images/streams-and-tables-p1_p4.png) 提示 从 v3.19 开始,Kafka 组件做了一次重构,Kafka 组件的配置、使用方法和之前都有较大差异,原有使用方式兼容,但是文档不再保留。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 安装 `@midwayjs/kafka` 模块。 ``` $ npm i @midwayjs/kafka --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/kafka": "^4.0.0", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/kafka` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as kafka from '@midwayjs/kafka'; @Configuration({ imports: [ kafka ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as kafka from '@midwayjs/kafka'; @Configuration({ imports: [ koa, kafka ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 由于 Kafka 分为 **消费者(Consumer)** 和 **生产者(Producer)** 两部分,两个可以独立使用,我们将分别介绍。 ## 消费者(Consumer)[​](#消费者consumer "消费者(Consumer)的直接链接") ### 目录结构[​](#目录结构 "目录结构的直接链接") 我们一般把消费者放在 consumer 目录。比如 `src/consumer/user.consumer.ts` 。 ``` ➜ my_midway_app tree . ├── src │ ├── consumer │ │ └── user.consumer.ts │ ├── interface.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` ### 基础配置[​](#基础配置 "基础配置的直接链接") 通过 `consumer` 字段和 `@KafkaConsumer` 装饰器,我们可以配置多个消费者。 比如,下面的 `sub1` 和 `sub2` 就是两个不同的消费者。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { // ... }, sub2: { // ... }, } } } ``` 最简单的消费者配置需要几个字段,Kafka 的连接配置、消费者配置以及订阅配置。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { // ... }, consumerOptions: { // ... }, subscribeOptions: { // ... }, }, } } } ``` 比如: ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, consumerOptions: { groupId: 'groupId-test-1', }, subscribeOptions: { topics: ['topic-test-1'], } }, } } } ``` 完整可配置参数包括: * `connectionOptions`:Kafka 的连接配置,即 `new Kafka(consumerOptions)` 的参数 * `consumerOptions`:Kafka 的消费者配置,即 `kafka.consumer(consumerOptions)` 的参数 * `subscribeOptions`:Kafka 的订阅配置,即 `consumer.subscribe(subscribeOptions)` 的参数 * `consumerRunConfig`:消费者运行配置,即 `consumer.run(consumerRunConfig)` 的参数 这些参数的详细说明,可以参考 [KafkaJS Consumer](https://kafka.js.org/docs/consuming) 文档。 ### 复用 Kafka 实例[​](#复用-kafka-实例 "复用 Kafka 实例的直接链接") 如果如果需要复用 Kafka 实例,可以通过 `kafkaInstanceRef` 字段来指定。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, consumerOptions: { groupId: 'groupId-test-1', }, subscribeOptions: { topics: ['topic-test-1'], } }, sub2: { kafkaInstanceRef: 'sub1', consumerOptions: { groupId: 'groupId-test-2', }, subscribeOptions: { topics: ['topic-test-2'], } } } } } ``` 注意,上述的 `sub1` 和 `sub2` 是两个不同的消费者,但是它们共享同一个 Kafka 实例,且 `sub2` 的 `groupId` 需要和 `sub1` 不同。 用 Kafka SDK 写法类似如下: ``` const kafka = new Kafka({ clientId: 'my-app', brokers: ['localhost:9092'], }); const consumer1 = kafka.consumer({ groupId: 'groupId-test-1' }); const consumer2 = kafka.consumer({ groupId: 'groupId-test-2' }); ``` ### 消费者实现[​](#消费者实现 "消费者实现的直接链接") 我们可以在目录中提供一个标准的消费者实现,比如 `src/consumer/sub1.consumer.ts`。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachMessagePayload } from '@midwayjs/kafka'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { async eachMessage(payload: EachMessagePayload) { // ... } } ``` `sub1` 是消费者名称,使用的是配置中的 `sub1` 消费者。 也可以实现 `eachBatch` 方法,处理批量消息。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachBatchPayload } from '@midwayjs/kafka'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { async eachBatch(payload: EachBatchPayload) { // ... } } ``` ### 消息上下文[​](#消息上下文 "消息上下文的直接链接") 和其他消息订阅机制一样,消息本身通过 `Context` 字段来传递。 ``` // src/consumer/sub1.consumer.ts import { KafkaConsumer, IKafkaConsumer, EachMessagePayload, Context } from '@midwayjs/kafka'; import { Inject } from '@midwayjs/core'; @KafkaConsumer('sub1') class Sub1Consumer implements IKafkaConsumer { @Inject() ctx: Context; async eachMessage(payload: EachMessagePayload) { // ... } } ``` `Context` 字段包括几个属性: | 属性 | 类型 | 描述 | | ------------ | ------------------------------------ | ---------- | | ctx.payload | EachMessagePayload, EachBatchPayload | 消息内容 | | ctx.consumer | Consumer | 消费者实例 | 你可以通过 `ctx.consumer` 来调用 Kafka 的 API,比如 `ctx.consumer.commitOffsets` 来手动提交偏移量或者 `ctx.consumer.pause` 来暂停消费。 ## 生产者(Producer)[​](#生产者producer "生产者(Producer)的直接链接") ### 基础配置[​](#基础配置-1 "基础配置的直接链接") 服务生产者也需要创建实例,配置本身使用了 [服务工厂](/docs/service_factory.md) 的设计模式。 配置如下: ``` // src/config/config.default export default { kafka: { producer: { clients: { pub1: { // ... }, pub2: { // ... } } } } } ``` 每个 Producer 实例的配置,同样包括 `connectionOptions` 和 `producerOptions`。 ``` // src/config/config.default export default { kafka: { producer: { clients: { pub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, producerOptions: { // ... } } } } } } ``` 具体参数可以参考 [KafkaJS Producer](https://kafka.js.org/docs/producing) 文档。 此外,由于 Kafka Consumer 和 Producer 都可以从同一个 Kafka 实例创建,所以它们可以复用同一个 Kafka 实例。 Producer 后于 Consumer 创建,也同样可以使用 `kafkaInstanceRef` 字段来复用 Kafka 实例。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, } }, producer: { clients: { pub1: { kafkaInstanceRef: 'sub1', } } } } } ``` ### 使用 Producer[​](#使用-producer "使用 Producer的直接链接") Producer 不存在默认实例,由于使用了服务工厂的设计模式,所以可以通过 `@InjectClient()` 来注入。 ``` // src/service/user.service.ts import { Provide, InjectClient } from '@midwayjs/core'; import { KafkaProducerFactory, Producer } from '@midwayjs/kafka'; @Provide() export class UserService { @InjectClient(KafkaProducerFactory, 'pub1') producer: Producer; async invoke() { await this.producer.send({ topic: 'topic-test-1', messages: [{ key: 'message-key1', value: 'hello consumer 11 !' }], }); } } ``` ## Admin[​](#admin "Admin的直接链接") Kafka 的 Admin 功能,可以用来创建、删除、查看主题,查看配置和 ACL 等。 ### 基础配置[​](#基础配置-2 "基础配置的直接链接") 和 Producer 类似,Admin 也使用了服务工厂的设计模式。 ``` // src/config/config.default export default { kafka: { admin: { clients: { admin1: { // ... } } } } } ``` 同样的,Admin 也可以复用 Kafka 实例。 ``` // src/config/config.default export default { kafka: { consumer: { sub1: { connectionOptions: { clientId: 'my-app', brokers: ['localhost:9092'], }, } }, admin: { clients: { admin1: { kafkaInstanceRef: 'sub1', } } } } } ``` ### 使用 Admin[​](#使用-admin "使用 Admin的直接链接") Admin 不存在默认实例,由于使用了服务工厂的设计模式,所以可以通过 `@InjectClient()` 来注入。 ``` // src/service/admin.service.ts import { Provide, InjectClient } from '@midwayjs/core'; import { KafkaAdminFactory, Admin } from '@midwayjs/kafka'; @Provide() export class AdminService { @InjectClient(KafkaAdminFactory, 'admin1') admin: Admin; } ``` 更多的 Admin 使用方法,可以参考 [KafkaJS Admin](https://kafka.js.org/docs/admin) 文档。 ## 组件日志[​](#组件日志 "组件日志的直接链接") Kafka 组件默认使用 `kafkaLogger` 日志,默认会将 `ctx.logger` 记录在 `midway-kafka.log`。 你可以通过配置修改。 ``` // src/config/config.default export default { midwayLogger: { clients: { kafkaLogger: { fileLogName: 'midway-kafka.log', }, }, }, } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { kafka: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.message}`; }, } } ``` ## 获取 KafkaJS 模块[​](#获取-kafkajs-模块 "获取 KafkaJS 模块的直接链接") KafkaJS 模块,可以通过 `@midwayjs/kafka` 的 `KafkaJS` 字段来获取。 ``` import { KafkaJS } from '@midwayjs/kafka'; const { ConfigResourceTypes } = KafkaJS; // ... ``` ## 关于分区的警告[​](#关于分区的警告 "关于分区的警告的直接链接") 如果你使用的是 KafkaJS 的 v2.0.0 版本,你可能会看到如下的警告: ``` 2024-11-04 23:47:28.228 WARN 31729 KafkaJS v2.0.0 switched default partitioner. To retain the same partitioning behavior as in previous versions, create the producer with the option "createPartitioner: Partitioners.LegacyPartitioner". See the migration guide at https://kafka.js.org/docs/migration-guide-v2.0.0#producer-new-default-partitioner for details. Silence this warning by setting the environment variable "KAFKAJS_NO_PARTITIONER_WARNING=1" { timestamp: '2024-11-04T15:47:28.228Z', logger: 'kafkajs' } ``` 这个警告是由于 KafkaJS 的 v2.0.0 版本默认使用了新的分区器,如果接受新的分区器行为,但想要关闭这个警告消息,可以通过设置环境变量 `KAFKAJS_NO_PARTITIONER_WARNING=1` 来消除这个警告。 或者显示声明分区器。 ``` // src/config/config.default import { KafkaJS } from '@midwayjs/kafka'; const { Partitioners } = KafkaJS; export default { kafka: { producer: { clients: { pub1: { // ... producerOptions: { createPartitioner: Partitioners.DefaultPartitioner, // ... createPartitioner: Partitioners.LegacyPartitioner, }, }, }, }, } } ``` 建议你查看 KafkaJS v2.0.0 的 [迁移指南](https://kafka.js.org/docs/migration-guide-v2.0.0#producer-new-default-partitioner) 了解更多细节。 ## 参考文档[​](#参考文档 "参考文档的直接链接") * [KafkaJS](https://kafka.js.org/docs/introduction) * [apache kafka官网](https://kafka.apache.org/intro) --- # Koa Koa 是一个非常轻量易用的 Web 框架。本章节内容,主要介绍在 Midway 中如何使用 Koa 作为上层框架,并使用自身的能力。 Midway 默认的示例都是基于该包。 `@midwayjs/koa` 包默认使用 `koa@2` 以及集成了 `@koa/router` 作为路由基础能力,并默认内置了 `session` 和 `body-parser` 功能。 | 描述 | | | -------------- | -- | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/koa@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/koa": "^4.0.0", // ... }, } ``` 也可以直接使用脚手架创建示例。 ``` # npm v6 $ npm init midway --type=koa-v4 my_project # npm v7 $ npm init midway -- --type=koa-v4 my_project ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { join } from 'path'; @Configuration({ imports: [koa], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... } } ``` ## BodyParser[​](#bodyparser "BodyParser的直接链接") `@midwayjs/koa` 自带 `bodyParser` 功能,默认会解析 `Post` 请求,自动识别 `json` 和 `form` 类型。 如需 text 或者 xml,可以自行配置。 默认的大小限制为 `1mb`,可以单独对每项配置大小。 ``` // src/config/config.default export default { // ... bodyParser: { enableTypes: ['json', 'form', 'text', 'xml'], formLimit: '1mb', jsonLimit: '1mb', textLimit: '1mb', xmlLimit: '1mb', }, } ``` 注意,使用 Postman 做 Post 请求时的类型选择: ![postman](https://img.alicdn.com/imgextra/i4/O1CN01QCdTsN1S347SuzZU5_!!6000000002190-2-tps-1017-690.png) 关闭 bodyParser 中间件。 ``` // src/config/config.default export default { // ... bodyParser: { enable: false, // ... }, } ``` ## Cookie 和 Session[​](#cookie-和-session "Cookie 和 Session的直接链接") `@midwayjs/koa` 默认封装了 `cookies` 解析和 `Session` 的支持,可以查看 [Cookies 和 Session](/docs/cookie_session.md)。 ## 扩展 Context[​](#扩展-context "扩展 Context的直接链接") 在一些场景下,需要对 Context 做扩展。 如果希望挂在一些临时的请求相关的对象数据,可以使用 `ctx.setAttr(key, value)` API 来实现,比如组件里自用的数据。 如果实在有扩展 Context 的诉求,可以使用 koa 自带的 API。 比如,我们在 `configuration.ts` 中做扩展提供了一个 `render()` 方法。 ``` import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady(container) { Object.defineProperties(app.context, { render: { value: async function (...args) { // ... }, }, }); } } ``` 但是这样做无法直接让 Context 包含 Typescript 定义,需要额外增加定义,请参考 [扩展上下文定义](/docs/context_definition.md)。 ## 获取 Http Server[​](#获取-http-server "获取 Http Server的直接链接") 在一些特殊情况下,你需要获取到原始的 Http Server,我们可以在服务器启动后获取。 ``` import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ // ... }) export class MainConfiguration { @Inject() framework: koa.Framework; async onServerReady(container) { const server = this.framework.getServer(); // ... } } ``` ## State 类型定义[​](#state-类型定义 "State 类型定义的直接链接") 在 koa 的 Context 中有一个特殊的 State 属性,通过和 Context 类似的方式可以扩展 State 定义。 ``` // src/interface.ts declare module '@midwayjs/koa/dist/interface' { interface Context { abc: string; } interface State { bbb: string; ccc: number; } } ``` ## 获取端口[​](#获取端口 "获取端口的直接链接") 通过 framework 或者 app 上的 `getPort()` 方法可以获取端口。 ``` import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [ koa, // ... ] // ... }) export class MainConfiguration { @Inject() framework: koa.Framework; async onServerReady(container, mainApp: koa.Application) { const port = this.framework.getPort(); const port = this.mainApp.getPort(); // ... } } ``` ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/koa` 的配置样例如下: ``` // src/config/config.default export default { // ... koa: { port: 7001, }, } ``` 所有属性描述如下: | 属性 | 类型 | 描述 | | --------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | port | number | 可选,启动的端口 | | globalPrefix | string | 可选,全局的 http 前缀 | | keys | string\[] | 可选,Cookies 签名,如果上层未写 keys,也可以在这里设置 | | hostname | string | 可选,监听的 hostname,默认 127.1 | | key | string \| Buffer \| Array\Buffer\|Object> | 可选,Https key,服务端私钥 | | cert | string \| Buffer \| Array\ | 可选,Https cert,服务端证书 | | ca | string \| Buffer \| Array\ | 可选,Https ca | | http2 | boolean | 可选,http2 支持,默认 false | | proxy | boolean | 可选,是否开启代理,如果为 true 则对于 request 请求中的 ip 优先从 Header 字段中 X-Forwarded-For 获取,默认 false | | subdomainOffset | number | 可选,子域名的偏移量,默认 2 | | proxyIpHeader | string | 可选,获取代理 ip 的字段名,默认为 X-Forwarded-For | | maxIpsCount | number | 可选,获取的 ips 最大数量,默认为 0(全部返回) | | serverTimeout | number | 可选,服务端超时配置,默认为 2 \* 60 \* 1000(2 分钟),单位毫秒 | | serverOptions | Record\ | 可选,http Server [选项](https://nodejs.org/docs/latest/api/http.html#httpcreateserveroptions-requestlistener) | ### 修改端口[​](#修改端口 "修改端口的直接链接") 默认情况下,我们在 `config.default` 提供了 `7001` 的默认端口参数,修改它就可以修改 koa http 服务的默认端口。 比如我们修改为 `6001`: ``` // src/config/config.default export default { // ... koa: { port: 6001, }, } ``` 默认情况下,单测环境由于需要 supertest 来启动端口,我们的 port 配置为 `null`。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, } ``` 此外,也可以通过 `midway-bin dev --ts --port=6001` 的方式来临时修改端口,此方法会覆盖配置中的端口。 ### 全局前缀[​](#全局前缀 "全局前缀的直接链接") 此功能请参考 [全局前缀](/docs/controller.md#%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80)。 ### 反向代理配置[​](#反向代理配置 "反向代理配置的直接链接") 如果使用了 Nginx 等反向代理,请开启 `proxy` 配置。 ``` // src/config/config.default export default { // ... koa: { proxy: true, }, } ``` 默认使用 `X-Forwarded-For` Header,如果代理配置不同,请自行配置不同的 Header。 ``` // src/config/config.default export default { // ... koa: { proxy: true, proxyIpHeader: 'X-Forwarded-Host' }, } ``` ### Https 配置[​](#https-配置 "Https 配置的直接链接") 在大多数的情况,请尽可能使用外部代理的方式来完成 Https 的实现,比如 Nginx。 在一些特殊场景下,你可以通过配置 SSL 证书(TLS 证书)的方式,来直接开启 Https。 首先,你需要提前准备好证书文件,比如 `ssl.key` 和 `ssl.pem`,key 为服务端私钥,pem 为对应的证书。 然后配置即可。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... koa: { key: join(__dirname, '../ssl/ssl.key'), cert: join(__dirname, '../ssl/ssl.pem'), }, } ``` ### favicon 设置[​](#favicon-设置 "favicon 设置的直接链接") 默认情况下,浏览器会发起一个 `favicon.ico` 的请求。 框架提供了一个默认中间件,用来处理该请求,你可以指定一个 `favicon` 的 Buffer。 ``` // src/config/config.default import { readFileSync } from 'fs'; import { join } from 'path'; export default { // ... siteFile: { favicon: readFileSync(join(__dirname, '../static/fav.ico')), }, } ``` 如果开启了 `@midwayjs/static-file` 组件,那么会优先使用组件的静态文件托管。 关闭中间件。 ``` // src/config/config.default export default { // ... siteFile: { enable: false, // ... }, } ``` ### 修改上下文日志[​](#修改上下文日志 "修改上下文日志的直接链接") 可以单独修改 koa 框架的上下文日志。 ``` export default { koa: { contextLoggerFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... }, }; ``` ### Query 数组解析[​](#query-数组解析 "Query 数组解析的直接链接") 默认情况下,koa 使用 `querystring` 解析 query 参数,当碰到数组时,会将数组的数据拆开。 比如: ``` GET /query?a[0]=1&a[1]=2 ``` 拿到的结果是: ``` { "a[0]": 1, "a[1]": 2, } ``` 框架提供了一些参数来处理这种情况。 ``` // src/config/config.default export default { // ... koa: { queryParseMode: 'extended', // ... }, } ``` `queryParseMode` 参数可以选择 `extended`、 `strict`、`first` 三种值。 当 `queryParseMode` 有值时,会使用 `qs` 模块处理 query,效果同 `koa-qs` 模块。 当请求参数为 `/query?a=1&b=2&a=3&c[0]=1&c[1]=2'` 时。 默认效果(使用 `querystring`) ``` { "a": ["1", "3" ], "b": "2", "c[0]": "1", "c[1]": "2" } ``` `extended` 效果 ``` { "a": ["1", "3" ], "b": "2", "c": ["1", "2"] } ``` `strict` 效果 ``` { "a": ["1", "3" ], "b": ["2"], "c": ["1", "2"] } ``` `first` 效果 ``` { "a": "1", "b": "2", "c": "1" } ``` ### 超时配置[​](#超时配置 "超时配置的直接链接") RequestTiemout 和 ServerTimeout 是两种不同的超时情况。 * `serverTimeout`:用于设置服务器接收到请求后,等待客户端发送数据的超时时间。如果在该时间内客户端没有发送任何数据,则服务器将关闭连接。此超时适用于整个请求-响应周期,包括请求头、请求主体以及响应。 * `requestTimeout`:用于设置服务器等待客户端发送完整请求的超时时间。这个超时是针对请求头和请求主体的,服务器将在该时间内等待客户端发送完整的请求。如果在超时时间内没有收到完整的请求,则服务器将中止该请求。 默认情况下,`serverTimeout` 为 0,不会触发超时。 如有需求,可以通过配置修改,单位毫秒。 ``` // src/config/config.default export default { // ... koa: { serverTimeout: 100_000 }, } ``` 如果程序出现 `ERR_HTTP_REQUEST_TIMEOUT` 这个错误,说明是触发了 `requestTimeout`,默认为 `300_000` (五分钟),单位毫秒,可以通过以下配置修改。 ``` // src/config/config.default export default { // ... koa: { serverOptions: { requestTimeout: 600_000 } }, } ``` --- # MCP (Model Context Protocol) MCP (Model Context Protocol) 是由 Anthropic 开发的开放标准协议,用于将 AI 模型与外部数据源和工具安全连接。它允许 AI 应用程序与各种服务进行语义集成,为 AI 模型提供了获取实时信息、执行操作和访问资源的标准化方式。 ![MCP Architecture](https://mintcdn.com/mcp/4ZXF1PrDkEaJvXpn/images/mcp-simple-diagram.png?w=1650\&fit=max\&auto=format\&n=4ZXF1PrDkEaJvXpn\&q=85\&s=37d50a5429a8f662c1beb564b4df8e65) Midway 提供了对 MCP 的完整支持和封装,能够简单快速地创建 MCP 服务器。本章节演示了如何在 Midway 体系下,提供 MCP 服务的方法。 Midway 当前采用了最新的 [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) 进行开发,并提供了装饰器和框架集成,用于快速发布 MCP 服务。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | **传输类型支持** | 传输类型 | 描述 | 支持状态 | | ----------- | -------------------------------------- | -------- | | stdio | 标准输入输出传输,适用于 CLI 应用 | ✅ | | stream-http | HTTP 流传输,推荐的现代传输方式 | ✅ | | sse | 服务器发送事件传输(已弃用,向下兼容) | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 MCP 的依赖。 ``` $ npm i @midwayjs/mcp@4 --save $ npm i @modelcontextprotocol/sdk zod --save ``` 如果使用 `sse` 或 `stream-http` 传输类型,还需要安装 HTTP 框架组件(选择其中一个): ``` # Express 框架 $ npm i @midwayjs/express@4 --save # 或者 Koa 框架 $ npm i @midwayjs/koa@4 --save # 或者 Egg.js 框架 $ npm i @midwayjs/web@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/mcp": "^4.0.0", "@modelcontextprotocol/sdk": "^1.19.0", "zod": "^3.24.1", "@midwayjs/express": "^4.0.0" } } ``` 提示 如果使用 `sse` 或 `stream-http` 传输类型,您需要选择并安装一个 HTTP 框架: * `@midwayjs/express` - Express 框架 * `@midwayjs/koa` - Koa 框架 * `@midwayjs/web` - Egg.js 框架 如果只使用 `stdio` 传输类型,则不需要安装 HTTP 框架组件。 ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `src/configuration.ts` 中导入 MCP 组件: ``` import { Configuration } from '@midwayjs/core'; import * as mcp from '@midwayjs/mcp'; // 如果使用 sse/stream-http 传输类型,需要导入 HTTP 框架 import * as express from '@midwayjs/express'; @Configuration({ imports: [ express, // HTTP 框架(sse/stream-http 传输类型需要) mcp // 导入 MCP 组件 ], // ... }) export class MainConfiguration {} ``` 信息 **传输类型依赖说明**: * `stdio` 传输:只需要导入 `@midwayjs/mcp` * `sse` 或 `stream-http` 传输:需要同时导入 HTTP 框架组件(如 `@midwayjs/express`) ## 配置[​](#配置 "配置的直接链接") 在 `config.default.ts` 中配置 MCP 服务器信息: ``` export default { // 如果使用 sse/stream-http 传输类型,需要配置 HTTP 框架 express: { port: 3000, keys: ['mcp-secret-key'] }, // 或者如果使用 Koa // koa: { // port: 3000, // keys: ['mcp-secret-key'] // }, mcp: { serverInfo: { name: 'my-mcp-server', version: '1.0.0', }, // 传输类型:stdio | stream-http | sse(已弃用) transportType: 'stream-http', // 可选:自定义端点路径 endpoints: { streamHttp: '/mcp', // StreamHTTP 端点 sse: '/sse', // SSE 端点(向下兼容) messages: '/messages' // 消息端点 } } } ``` 注意 * 当使用 `sse` 或 `stream-http` 传输类型时,**必须配置 HTTP 框架的端口和密钥**: * 如果只使用 `stdio` 传输类型,则不需要 HTTP 框架配置 ### 传输类型说明[​](#传输类型说明 "传输类型说明的直接链接") MCP 支持多种传输类型: * **stdio**: 适用于命令行工具和脚本,通过标准输入输出通信 * **stream-http**: 推荐的 HTTP 传输方式,支持会话管理和并发请求 * **sse**: 传统的服务器发送事件传输(已弃用,但保持向下兼容) 提示 推荐使用 `stream-http` 传输类型,它提供了更好的性能和会话管理能力,同时兼容传统的 SSE 客户端。 ### 默认端点配置[​](#默认端点配置 "默认端点配置的直接链接") 当使用 `sse` 或 `stream-http` 传输类型时,Midway MCP 框架会自动配置以下默认端点: | 端点类型 | 默认路径 | 用途 | 支持的传输类型 | | ---------- | ----------- | ----------------------------- | --------------------------- | | StreamHTTP | `/mcp` | 主要的 MCP 通信端点,推荐使用 | stream-http | | SSE | `/sse` | 传统 SSE 客户端兼容端点 | sse, stream-http (向下兼容) | | Messages | `/messages` | 消息处理端点 | stream-http, sse | **自定义端点配置** 您可以通过 `endpoints` 配置项自定义这些端点路径: ``` export default { mcp: { serverInfo: { name: 'my-mcp-server', version: '1.0.0', }, transportType: 'stream-http', endpoints: { streamHttp: '/api/mcp', // 自定义 StreamHTTP 端点 sse: '/api/events', // 自定义 SSE 端点 messages: '/api/messages' // 自定义消息端点 } } } ``` **端点访问示例** 假设服务器运行在 `http://localhost:3000`,默认端点访问地址为: * StreamHTTP 客户端:`http://localhost:3000/mcp` * SSE 客户端:`http://localhost:3000/sse` * 消息端点:`http://localhost:3000/messages` 信息 **向下兼容说明**:当服务器配置为 `stream-http` 传输类型时,传统的 SSE 客户端仍然可以通过 `/sse` 端点正常连接和通信。 ### 日志配置[​](#日志配置 "日志配置的直接链接") MCP 组件默认志输出,可以通过 `mcpLogger` 进一步配置日志详情。 ``` // src/config/config.default.ts export default { midwayLogger: { mcpLogger: { // ... } }, } ``` ## 使用方式[​](#使用方式 "使用方式的直接链接") ### 工具(Tools)[​](#工具tools "工具(Tools)的直接链接") 使用 `@Tool` 装饰器创建 MCP 工具: ``` import { Tool, IMcpTool, ToolConfig } from '@midwayjs/mcp'; import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; const weatherConfig: ToolConfig<{ city: z.ZodString }> = { description: 'Get weather information for a city', inputSchema: { city: z.string().describe('The city name') } }; @Tool('get_weather', weatherConfig) export class WeatherTool implements IMcpTool { async execute(args: { city: string }): Promise { // 模拟获取天气数据 const weather = await this.getWeatherData(args.city); return { content: [ { type: 'text', text: `Weather in ${args.city}: ${weather.temperature}°C, ${weather.condition}` } ] }; } private async getWeatherData(city: string) { // 实际的天气 API 调用 return { temperature: 22, condition: 'Sunny' }; } } ``` ### 提示(Prompts)[​](#提示prompts "提示(Prompts)的直接链接") 使用 `@Prompt` 装饰器创建 MCP 提示: ``` import { Prompt, IMcpPrompt, PromptConfig } from '@midwayjs/mcp'; import { GetPromptResult } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; const promptConfig: PromptConfig<{ topic: z.ZodString; style: z.ZodOptional; }> = { description: 'Generate content on a specific topic', argsSchema: { topic: z.string().describe('The topic to write about'), style: z.string().optional().describe('Writing style (formal, casual, etc.)') } }; @Prompt('content_generator', promptConfig) export class ContentPrompt implements IMcpPrompt { async generate(args: { topic: string; style?: string }): Promise { const style = args.style || 'professional'; return { messages: [ { role: 'user', content: { type: 'text', text: `Write a ${style} article about: ${args.topic}` } } ] }; } } ``` ### 资源(Resources)[​](#资源resources "资源(Resources)的直接链接") 使用 `@Resource` 装饰器创建 MCP 资源: ``` import { Resource, IMcpResource, ResourceConfig } from '@midwayjs/mcp'; import { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js'; const resourceConfig: ResourceConfig = { description: 'Access user database information', uri: 'database://users/{id}', mimeType: 'application/json' }; @Resource('user_data', resourceConfig) export class UserResource implements IMcpResource { async handle(uri: URL): Promise { const userId = this.extractUserIdFromUri(uri); const userData = await this.getUserData(userId); return { contents: [ { uri: uri.toString(), mimeType: 'application/json', text: JSON.stringify(userData) } ] }; } private extractUserIdFromUri(uri: URL): string { const path = uri.pathname; return path.split('/').pop() || ''; } private async getUserData(userId: string) { // 实际的数据库查询 return { id: userId, name: 'John Doe', email: 'john@example.com' }; } } ``` ## 安全认证[​](#安全认证 "安全认证的直接链接") ### 内置的 JWT 助手[​](#内置的-jwt-助手 "内置的 JWT 助手的直接链接") Midway MCP 框架提供了内置的 JWT 认证助手,可以自动处理 JWT token 验证并将认证信息传递给 MCP 工具、提示和资源。 在配置中启用 JWT 认证助手: ``` // src/config/config.default.ts export default { // JWT 配置 jwt: { secret: 'your-jwt-secret-key', sign: { expiresIn: '1h' } }, mcp: { serverInfo: { name: 'my-mcp-server', version: '1.0.0', }, transportType: 'stream-http', // 启用内置 JWT 认证助手 enableJwtAuthHelper: true, } } ``` 认证助手是一个中间件,能将 jwt 的 payload 信息转化为 MCP SDK 中定义的 AuthInfo。 可以通过 `ctx.authInfo` 使用认证信息。 ``` import { Tool, IMcpTool, ToolConfig, Context } from '@midwayjs/mcp'; import { Inject } from '@midwayjs/core'; import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; @Tool('secure_operation', { description: 'A tool that requires authentication' }) export class SecureTool implements IMcpTool { @Inject() ctx: Context; async execute(args: any): Promise { const authInfo = this.ctx.authInfo; // ... } } ``` JWT payload 应包含以下标准字段: ``` { "aud": "client-id", // 客户端 ID,映射到 authInfo.clientId "scope": "mcp:read mcp:write", // 权限范围,映射到 authInfo.scopes "exp": 1234567890, // 过期时间,映射到 authInfo.expiresAt "resource": "https://api.example.com", // 资源 URL,映射到 authInfo.resource "sub": "user-123", // 用户 ID "iss": "https://auth.example.com", // 签发者 "extra": { // 其他自定义字段会放入 authInfo.extra "username": "testuser", "role": "admin" } } ``` ### 非标数据转换[​](#非标数据转换 "非标数据转换的直接链接") 如果传入的 jwt 结构为非标,需要在配置中自行提供转换函数。 ``` // src/config/config.default.ts import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; export default { // JWT 配置 jwt: { secret: 'your-jwt-secret-key', sign: { expiresIn: '1h' } }, mcp: { serverInfo: { name: 'my-mcp-server', version: '1.0.0', }, transportType: 'stream-http', // 启用内置 JWT 认证助手 enableJwtAuthHelper: true, // 自定义函数 jwtAuthCustomPayloadTransformer: (payload: any, token: string): AuthInfo => { return { // ...使用标准JWT字段映射AuthInfo token: token, clientId: payload.aud, // ... }; } } } ``` ### 更多认证[​](#更多认证 "更多认证的直接链接") 在其他的认证场景下,也可以使用 Midway 组件或者编写中间件完整。 比如你可以使用 `passport` 组件完成 OAuth 认证。 在认证完成后,按照 MCP SDK 规范,需将认证信息放到 `req.auth` 中。 如: ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import * as mcp from '@midwayjs/mcp'; import { MidwayMCPFramework } from '@midwayjs/mcp'; import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; @Configuration({ imports: [ express, // ... mcp ], importConfigs: ['./config'] }) export class MainConfiguration { @Inject() mcpFramework: MidwayMCPFramework; async onReady(container: IMidwayContainer, mainApp: IMidwayApplication) { const authMiddleware = async (req, res, next) => { // ... const userInfo = { user: 'zhangsan', role: 'admin' } // 必须要设置这个字段 req.auth = { token: req.headers.authorization, clientId: 'test-client-id', scopes: ['mcp:read', 'mcp:write'], resource: new URL('https://mcp.example.com/resources'), extra: userInfo, } as AuthInfo; // koa 就放到 ctx.req.auth 上 await next(); } // 注意这里的 mainApp 是 Express mainApp.getMiddleware().insertBefore(authMiddleware, 'mcpMiddleware'); } } ``` ## 完整示例[​](#完整示例 "完整示例的直接链接") 这里是一个完整的 MCP 服务器示例: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import * as mcp from '@midwayjs/mcp'; @Configuration({ imports: [ express, mcp ], importConfigs: ['./config'] }) export class MainConfiguration {} // src/config/config.default.ts export default { express: { port: 3000, }, mcp: { serverInfo: { name: 'example-mcp-server', version: '1.0.0', }, transportType: 'stream-http', } } // src/tools/calculator.ts import { Tool, IMcpTool, ToolConfig } from '@midwayjs/mcp'; import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; const calcConfig: ToolConfig<{ operation: z.ZodEnum<['add', 'subtract', 'multiply', 'divide']>; a: z.ZodNumber; b: z.ZodNumber; }> = { description: 'Perform basic mathematical operations', inputSchema: { operation: z.enum(['add', 'subtract', 'multiply', 'divide']), a: z.number(), b: z.number() } }; @Tool('calculator', calcConfig) export class CalculatorTool implements IMcpTool { async execute(args: { operation: 'add' | 'subtract' | 'multiply' | 'divide'; a: number; b: number; }): Promise { let result: number; switch (args.operation) { case 'add': result = args.a + args.b; break; case 'subtract': result = args.a - args.b; break; case 'multiply': result = args.a * args.b; break; case 'divide': if (args.b === 0) { throw new Error('Division by zero'); } result = args.a / args.b; break; } return { content: [ { type: 'text', text: `${args.a} ${args.operation} ${args.b} = ${result}` } ] }; } } ``` ## 动态调用 API[​](#动态调用-api "动态调用 API的直接链接") 您可以在运行时动态调用 MCP 服务器的原始 API 来注册工具、提示和资源: ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as express from '@midwayjs/express'; import * as mcp from '@midwayjs/mcp'; import { MidwayMCPFramework } from '@midwayjs/mcp'; import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; @Configuration({ imports: [ express, mcp ], importConfigs: ['./config'] }) export class MainConfiguration { @Inject() mcpFramework: MidwayMCPFramework; async onReady() { const server = this.mcpFramework.getServer(); // 动态注册工具 server.registerTool({ name: 'dynamic_tool', description: '动态注册的工具', inputSchema: { type: 'object', properties: { message: { type: 'string', description: '要处理的消息' } }, required: ['message'] } }, async (args): Promise => { return { content: [{ type: 'text', text: `动态处理: ${args.message}` }] }; }); // 动态注册提示 server.registerPrompt({ name: 'dynamic_prompt', description: '动态生成的提示', argsSchema: { type: 'object', properties: { topic: { type: 'string', description: '主题' } }, required: ['topic'] } }, async (args) => { return { messages: [{ role: 'user', content: { type: 'text', text: `请写一篇关于 ${args.topic} 的文章` } }] }; }); // 动态注册资源 server.registerResource({ uri: 'dynamic://config', name: '动态配置', description: '动态生成的配置资源', mimeType: 'application/json' }, async (uri) => { return { contents: [{ uri: uri.toString(), mimeType: 'application/json', text: JSON.stringify({ timestamp: new Date().toISOString(), config: 'dynamic data' }) }] }; }); } } ``` 提示 动态注册的 API 适用于需要在运行时根据业务逻辑动态添加 MCP 功能的场景。与装饰器方式相比,动态注册提供了更大的灵活性,但需要手动管理注册逻辑。 ## 客户端连接[​](#客户端连接 "客户端连接的直接链接") ### StreamHTTP 客户端[​](#streamhttp-客户端 "StreamHTTP 客户端的直接链接") ``` import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; // 创建客户端实例 const client = new Client({ name: 'my-mcp-client', version: '1.0.0' }); // 创建 StreamHTTP 传输 const transport = new StreamableHTTPClientTransport( new URL('http://localhost:3000/mcp'), { requestInit: { headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' } } } ); // 连接到服务器 await client.connect(transport); // 列出可用工具 const { tools } = await client.listTools(); console.log('Available tools:', tools); // 调用工具 const result = await client.callTool({ name: 'calculator', arguments: { operation: 'add', a: 5, b: 3 } }); console.log('Tool result:', result); // 使用完毕后关闭连接 await client.close(); ``` ### Stdio 客户端 (进程通信)[​](#stdio-客户端-进程通信 "Stdio 客户端 (进程通信)的直接链接") ``` import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; // 创建客户端实例 const client = new Client({ name: 'my-mcp-client', version: '1.0.0' }); // 创建 Stdio 传输,启动 MCP 服务器进程 const transport = new StdioClientTransport({ command: 'node', args: ['bootstrap.js'], env: { NODE_ENV: 'production', // 继承当前进程的环境变量 ...process.env }, // 可选:设置工作目录 cwd: '/path/to/mcp/server', // 可选:处理 stderr 输出 stderr: 'inherit' // 'pipe' | 'inherit' | 'ignore' }); // 连接到服务器(会自动启动子进程) await client.connect(transport); // 可选:监听 stderr 输出(当 stderr: 'pipe' 时) if (transport.stderr) { transport.stderr.on('data', (data) => { console.error('Server stderr:', data.toString()); }); } // 列出可用工具 const { tools } = await client.listTools(); console.log('Available tools:', tools); // 调用工具 const result = await client.callTool({ name: 'calculator', arguments: { operation: 'add', a: 5, b: 3 } }); console.log('Tool result:', result); // 使用完毕后关闭连接(会终止子进程) await client.close(); ``` 提示 **传输类型选择建议**: * **StreamHTTP**: 适用于网络服务、微服务架构、Web 应用集成 * **SSE**: 传统方式,主要用于向下兼容 * **Stdio**: 适用于命令行工具、本地脚本、桌面应用集成(如 Claude Desktop、Cursor、Trae 等 AI 编辑器) ### 与编辑器集成[​](#与编辑器集成 "与编辑器集成的直接链接") 在 Cursor/Trae/Claude Desktop 等编辑器的配置文件中添加您的 MCP 服务器: stdio 示例如下: ``` { "mcpServers": { "my-midway-mcp-server": { "command": "node", "args": ["bootstrap.js"], "env": { "NODE_ENV": "production" } } } } ``` stream-http 示例如下: ``` { "mcpServers": { "my-midway-mcp-server": { "url": "http://localhost:3000/mcp" } } } ``` ## 最佳实践[​](#最佳实践 "最佳实践的直接链接") ### 1. 类型安全[​](#1-类型安全 "1. 类型安全的直接链接") 使用 TypeScript 泛型确保类型安全: ``` import { Tool, ToolConfig } from '@midwayjs/mcp'; import { z } from 'zod'; // 定义清晰的输入类型 const userSchema = { userId: z.string().min(1), includeProfile: z.boolean().optional() } as const; const userToolConfig: ToolConfig = { description: 'Get user information', inputSchema: userSchema }; @Tool('get_user', userToolConfig) export class UserTool implements IMcpTool { // TypeScript 会自动推断 args 的类型 async execute(args: { userId: string; includeProfile?: boolean }) { // 实现逻辑 } } ``` ### 2. 错误处理[​](#2-错误处理 "2. 错误处理的直接链接") 正确处理错误并返回有意义的错误信息: ``` @Tool('risky_operation', config) export class RiskyTool implements IMcpTool { async execute(args: any): Promise { try { const result = await this.performRiskyOperation(args); return { content: [{ type: 'text', text: result }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error.message}` }], isError: true }; } } } ``` ### 3. 资源管理[​](#3-资源管理 "3. 资源管理的直接链接") 合理管理资源连接和清理: ``` @Resource('database_query', config) export class DatabaseResource implements IMcpResource { @Inject() databaseService: DatabaseService; async handle(uri: URL): Promise { const connection = await this.databaseService.getConnection(); try { const result = await connection.query(this.parseQuery(uri)); return { contents: [{ uri: uri.toString(), mimeType: 'application/json', text: JSON.stringify(result) }] }; } finally { await connection.close(); } } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Q: MCP 与传统 API 有什么区别?[​](#q-mcp-与传统-api-有什么区别 "Q: MCP 与传统 API 有什么区别?的直接链接") A: MCP 是专门为 AI 模型设计的协议,提供了语义化的接口描述、类型安全的参数验证和上下文感知的交互。与传统 REST API 相比,MCP 更适合 AI 模型理解和使用。 ### Q: 如何在生产环境中部署 MCP 服务?[​](#q-如何在生产环境中部署-mcp-服务 "Q: 如何在生产环境中部署 MCP 服务?的直接链接") A: 推荐使用 `stream-http` 传输类型,配合反向代理(如 Nginx)进行负载均衡。确保启用适当的安全措施和监控。 ### Q: 可以在一个应用中同时提供多种传输类型吗?[​](#q-可以在一个应用中同时提供多种传输类型吗 "Q: 可以在一个应用中同时提供多种传输类型吗?的直接链接") A: 当前版本每个应用实例只支持一种传输类型。如需支持多种传输类型,建议部署多个应用实例。 ### Q: 如何调试 MCP 服务?[​](#q-如何调试-mcp-服务 "Q: 如何调试 MCP 服务?的直接链接") A: 使用日志记录、MCP 客户端工具进行测试,或者使用官方提供的 [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) ## 相关链接[​](#相关链接 "相关链接的直接链接") * [MCP 官方文档](https://modelcontextprotocol.io/) * [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) * [Claude Desktop MCP 配置](https://docs.anthropic.com/claude/docs/mcp) --- # MikroORM 本章节介绍用户如何在 midway 中使用 MikroORM。 MikroORM 是基于数据映射器、工作单元和身份映射模式的 Node.js 的 TypeScript ORM。 MikroORM 的官网文档在 [这里](https://mikro-orm.io/docs)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 关于升级[​](#关于升级 "关于升级的直接链接") * 从 `v3.14.0` 版本的组件开始,支持 mikro v5/v6 版本,由于 mikro v5 到 v6 有较大的变化,如从 mikro 老版本升级请提前阅读 [Upgrading from v5 to v6](https://mikro-orm.io/docs/upgrading-v5-to-v6) * 组件示例已更新为 v6 版本 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 mikro 组件,提供接入 mikro-orm 的能力。 ``` $ npm i @midwayjs/mikro@4 @mikro-orm/core --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/mikro": "^4.0.0", "@mikro-orm/core": "^6.0.2", // ... }, "devDependencies": { // ... } } ``` 同时,还需要引入对应数据库的适配包。 比如: ``` { "dependencies": { // sqlite "@mikro-orm/sqlite": "^6.0.2", // mysql "@mikro-orm/mysql": "^6.0.2", }, "devDependencies": { // ... } } ``` 更多驱动程序请查看 [官方文档](https://mikro-orm.io/docs/usage-with-sql/)。 ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 mikro 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mikro from '@midwayjs/mikro'; import { join } from 'path'; @Configuration({ imports: [ // ... mikro // 加载 mikro 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ## 基础使用[​](#基础使用 "基础使用的直接链接") 和其他 orm 框架类似,都是分为几个步骤: * 1、定义 Entity * 2、配置数据源 * 3、获取 EntityModel 进行调用 下面的更多 Entity 代码请查看 [示例](https://github.com/midwayjs/midway/tree/main/packages/mikro/test/fixtures/base-fn-origin)。 ### 目录结构[​](#目录结构 "目录结构的直接链接") 一个基础的参考目录结构如下。 ``` MyProject ├── src │ ├── config │ │ └── config.default.ts │ ├── entity │ │ ├── book.entity.ts │ │ ├── index.ts │ │ └── base.ts │ ├── configuration.ts │ └── service ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` ### 定义 Entity[​](#定义-entity "定义 Entity的直接链接") 定义基础的 Entity。 ``` // src/entity/BaseEntity.ts import { PrimaryKey, Property } from '@mikro-orm/core'; export abstract class BaseEntity { @PrimaryKey() id!: number; @Property() createdAt: Date = new Date(); @Property({ onUpdate: () => new Date() }) updatedAt: Date = new Date(); } ``` 定义实际的 Entity,包含一对多,多对多等关系。 ``` // src/entity/book.entity.ts import { Cascade, Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core'; import { Author, BookTag, Publisher } from './index'; import { BaseEntity } from './base'; @Entity() export class Book extends BaseEntity { @Property() title: string; @ManyToOne(() => Author) author: Author; @ManyToOne(() => Publisher, { cascade: [Cascade.PERSIST, Cascade.REMOVE], nullable: true }) publisher?: Publisher; @ManyToMany(() => BookTag) tags = new Collection(this); @Property({ nullable: true }) metaObject?: object; @Property({ nullable: true }) metaArray?: any[]; @Property({ nullable: true }) metaArrayOfStrings?: string[]; constructor(title: string, author: Author) { super(); this.title = title; this.author = author; } } ``` ### 配置数据源[​](#配置数据源 "配置数据源的直接链接") mikro v5 和 v6 略有不同。 * mikro v6 * mikro v5 ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { join } from 'path'; import { SqliteDriver } from '@mikro-orm/sqlite'; export default (appInfo) => { return { mikro: { dataSource: { default: { dbName: join(__dirname, '../../test.sqlite'), driver: SqliteDriver, // 这里使用了 sqlite 做示例 allowGlobalContext: true, // 实体形式 entities: [Author, Book, BookTag, Publisher, BaseEntity], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], } } } } } ``` ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { join } from 'path'; export default (appInfo) => { return { mikro: { dataSource: { default: { dbName: join(__dirname, '../../test.sqlite'), type: 'sqlite', // 这里使用了 sqlite 做示例 allowGlobalContext: true, // 实体形式 entities: [Author, Book, BookTag, Publisher, BaseEntity], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], } } } } } ``` 提示 mikro 的 `entities` 字段配置已经经过框架处理,该字段配置请不要参考原始文档。 ### 增删查改[​](#增删查改 "增删查改的直接链接") 在业务代码中,可以使用 `InjectRepository` 注入 `Repository` 对象执行简单的查询操作。其它的增删改操作可以通过配合`EntityManger `的 `persist` 和 `flush` 接口来实现,使用 `InjectEntityManager` 可以直接注入 `EntityManager` 对象,也可以通过`repository.getEntityManager()`获取。 警告 * 1、从 5.7 版本开始,MikroORM 将原来 `Repository` 上 `persist` 和 `flush` 等接口标为*弃用*,并计划在 v6 版本中 [彻底移除](https://github.com/mikro-orm/mikro-orm/discussions/3989),建议直接调用`EntityManager`上的相关接口 * 2、v6 已经彻底 [弃用](https://mikro-orm.io/docs/upgrading-v5-to-v6#removed-methods-from-entityrepository) 上述接口 ``` // src/service/book.service.ts import { Book } from './entity/book.entity'; import { Provide } from '@midwayjs/core'; import { InjectEntityManager, InjectRepository } from '@midwayjs/mikro'; import { QueryOrder } from '@mikro-orm/core'; import { EntityManager, EntityRepository } from '@mikro-orm/mysql'; // 需要使用数据库驱动对应的类来执行操作 @Provide() export class BookService { @InjectRepository(Book) bookRepository: EntityRepository; @InjectEntityManager() em: EntityManager; async queryByRepo() { // 使用Repository查询 const books = await this.bookRepository.findAll({ populate: ['author'], orderBy: { title: QueryOrder.DESC }, limit: 20, }); return books; } async createBook() { const book = new Book({ title: 'b1', author: { name: 'a1', email: 'e1' } }); // 标记保存Book this.em.persist(book); // 执行所有变更 await this.em.flush(); return book; } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的数据源对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { MikroDataSourceManager } from '@midwayjs/mikro'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(MikroDataSourceManager); const orm = dataSourceManager.getDataSource('default'); const connection = orm.em.getConnection(); // ... } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/mikro'; import { MikroORM, IDatabaseDriver, Connection } from '@mikro-orm/core'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: MikroORM>; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: MikroORM>; async onReady(container: IMidwayContainer) { // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 可以通过配置将 midway 的 logger 添加到 mikro 中,用于记录 sql 等信息。 ``` // src/config/config.default.ts exporg default { midwayLogger: { clients: { mikroLogger: { // ... } } }, mikro: { dataSource: { default: { entities: [Author, Book, BookTag, Publisher, BaseEntity], // ... logger: 'mikroLogger', } }, } } ``` 默认情况下 mikro 自带颜色,也会将其写入文件,可以通过配置关闭。 ``` // src/config/config.default.ts exporg default { midwayLogger: { clients: { mikroLogger: { transports: { console: { autoColors: false, }, file: { fileLogName: 'mikro.log', }, }, } } }, mikro: { dataSource: { default: { entities: [Author, Book, BookTag, Publisher, BaseEntity], // ... logger: 'mikroLogger', colors: false, } }, } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Node 版本[​](#1node-版本 "1、Node 版本的直接链接") Mikro-orm 对 Node 版本有一些限制,必须为 `>=14.0.0` ,所以 `@midwayjs/mikro` 组件的使用规则也如此。 ### 2、Identity Map[​](#2identity-map "2、Identity Map的直接链接") Mikro-orm 内部查询有一个 [Identity Map](https://mikro-orm.io/docs/identity-map) 的概念,Midway 已经在所有的内置 Framework 的中间件内置加入了该功能,如果在非请求链路调用场景下使用,比如 `src/configuration` 中,可以开启 `allowGlobalContext` 选项。 ### 3、多库的支持[​](#3多库的支持 "3、多库的支持的直接链接") 和其他数据库一样,Midway 支持多数据源的配置。 ``` // src/config/config.default import { Author, BaseEntity, Book, BookTag, Publisher } from '../entity'; import { SqlHighlighter } from '@mikro-orm/sql-highlighter'; import { join } from 'path'; export default (appInfo) => { return { mikro: { dataSource: { custom1: { // ... }, custom2: { // ... } } } } } ``` 注意在使用时,需要传递来自哪个数据源。 ``` // ... @Provide() export class BookController { @InjectRepository(Book, 'custom1') bookRepository: EntityRepository; async findBookAndQuery() { // ... } } ``` --- # MongoDB 在这一章节中,我们选择 [Typegoose](https://github.com/typegoose/typegoose) 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 简单的来说,Typegoose 使用 TypeScript 编写 Mongoose 模型的 “包装器”,它的大部分能力还是由 [mongoose](https://www.npmjs.com/package/mongoose) 库来提供的。 也可以直接选择 [mongoose](https://www.npmjs.com/package/mongoose) 库来使用,我们会分别描述。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | 提示 * 1、当前模块从 v3.4.0 开始已经重构,历史写法兼容,如果查询历史文档,请参考 [这里](/docs/legacy/mongodb.md)。 * 2、如果代码中有读取配置,注意 `mongoose.clients` 可能会读不到,请使用 `mongoose.dataSource`。 ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 如果想使用新版本的用法,请参考下面的流程,将老代码进行修改,新老代码请勿混用。 升级方法: * 1、无需再使用 `EntityModel` 装饰器 * 3、在 `src/config.default` 的 `mongoose` 部分配置调整,参考下面的数据源配置部分 * 3.1 修改为数据源的形式 `mongoose.dataSource` * 3.2 将实体模型在数据源的 `entities` 字段中声明 ## Mongoose 版本依赖[​](#mongoose-版本依赖 "Mongoose 版本依赖的直接链接") mongoose 和你服务器使用的 MongoDB Server 的版本也有着一定的关系,如下,请务必注意。 * MongoDB Server 2.4.x: mongoose ^3.8 or 4.x * MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x * MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x * MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x * MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x * MongoDB Server 3.6.x: mongoose 5.x * MongoDB Server 4.0.x: mongoose ^5.2.0 * MongoDB Server 4.2.x: mongoose ^5.7.0 * MongoDB Server 4.4.x: mongoose ^5.10.0 * MongoDB Server 5.x: mongoose ^6.0.0 **mongoose 相关的依赖比较复杂,且对应不同的版本,现阶段,我们使用的主要是 mongoose v5 和 v6。** 信息 从 mongoose\@v5.11.0 开始,mongoose 官方支持了定义,所以不再需要安装 @types/mongoose 依赖包。 安装包依赖版本如下: **支持 MongoDB Server 6.x** ``` "dependencies": { "mongoose": "^7.0.0", "@typegoose/typegoose": "^10.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 5.x** ``` "dependencies": { "mongoose": "^6.0.7", "@typegoose/typegoose": "^9.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 4.4.x** 以下版本不需要安装额外定义包。 ``` "dependencies": { "mongoose": "^5.13.3", "@typegoose/typegoose": "^8.0.0", // 使用 typegoose 需要安装此依赖 }, ``` 以下版本需要安装额外定义包(不推荐)。 ``` "dependencies": { "mongodb": "3.6.3", // mongoose 内部写死了该版本 "mongoose": "~5.10.18", "@typegoose/typegoose": "^7.0.0", // 使用 typegoose 需要安装此依赖 }, "devDependencies": { "@types/mongodb": "3.6.3", // 只能使用此版本 "@types/mongoose": "~5.10.3", } ``` 其余的 MongoDB 安装模块类似,未测。 ## 使用 Typegoose[​](#使用-typegoose "使用 Typegoose的直接链接") ### 1、安装组件[​](#1安装组件 "1、安装组件的直接链接") 安装 Typegoose 组件,提供访问 MongoDB 的能力。 **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/typegoose@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/typegoose": "^4.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; @Configuration({ imports: [ typegoose // 加载 typegoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` 信息 在该组件中,midway 只是做了简单的配置规则化,并将其注入到初始化流程中。 ### 2、简单的目录结构[​](#2简单的目录结构 "2、简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── user.ts // 实体文件 │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ### 3、创建实体文件[​](#3创建实体文件 "3、创建实体文件的直接链接") 比如在 `src/entity/user.ts` 中。 ``` import { prop } from '@typegoose/typegoose'; export class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 等价于使用 mongoose 的下列代码 ``` const userSchema = new mongoose.Schema({ name: String, jobs: [{ type: String }] }); const User = mongoose.model('User', userSchema); ``` 信息 所以说,typegoose 只是简化了 model 的创建过程。 ### 4、配置连接信息[​](#4配置连接信息 "4、配置连接信息的直接链接") 在 `src/config/config.default.ts` 中加入连接的配置。 ``` import { User } from '../entity/user'; export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, // 关联实体 entities: [ User ] } } }, } ``` 如需以目录扫描形式关联,请参考 [数据源管理](/docs/data_source.md)。 ### 5、引用实体,调用数据库[​](#5引用实体调用数据库 "5、引用实体,调用数据库的直接链接") 示例代码如下: ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typegoose'; import { ReturnModelType } from '@typegoose/typegoose'; import { User } from '../entity/user'; @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; async getTest(){ // create data const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties // find data const user = await this.userModel.findById(id).exec(); console.log(user) } } ``` ### 6、多库的情况[​](#6多库的情况 "6、多库的情况的直接链接") 首先定义多个实体。 ``` class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } class User2 { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 将实体配置到多个数据源。 在 `src/config/config.default.ts` 中加入数据源的配置。 ``` import { User, User2 } from '../entity/user'; export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, entities: [ User ] }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' }, entities: [ User2 ] } } }, } ``` 定义实例时使用固定的连接,在扫描 dataSource 配置 Model 会自动关联 mongoose连接(`getModelForClass(Model, { existingConnection: conn })`)。 ``` @Provide() export class TestService{ @InjectEntityModel(User) userModel: ReturnModelType; @InjectEntityModel(User2) user2Model: ReturnModelType; async getTest(){ const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties const user = await this.userModel.findById(id).exec(); console.log(user) const { _id: id2 } = await this.user2Model.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User2); // an "as" assertion, to have types for all properties const user2 = await this.user2Model.findById(id2).exec(); console.log(user2) } } ``` ### 7、关于 schemaOptions[​](#7关于-schemaoptions "7、关于 schemaOptions的直接链接") Typegoose 预留了一个 `setGlobalOptions` 方法用来设置 [schemaOptions](https://typegoose.github.io/typegoose/docs/api/decorators/model-options#schemaoptions) 和一些其他全局性的 [配置](https://typegoose.github.io/typegoose/docs/api/decorators/model-options#options-1)。 我们可以在项目配置加载时设置它。 ``` // srcconfiguration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; import * as Typegoose from '@typegoose/typegoose'; @Configuration({ // ... }) export class MainConfiguration { async onConfigLoad() { Typegoose.setGlobalOptions({ schemaOptions: { // ... }, options: { allowMixed: Severity.ERROR } }); // ... } } ``` ## 直接使用 mongoose[​](#直接使用-mongoose "直接使用 mongoose的直接链接") mongoose 组件是 typegoose 的基础组件,有时候我们可以直接使用它。 ### 1、安装组件[​](#1安装组件-1 "1、安装组件的直接链接") **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/mongoose@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/mongoose": "^4.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` ### 2、开启组件[​](#2开启组件 "2、开启组件的直接链接") 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mongoose from '@midwayjs/mongoose'; @Configuration({ imports: [ mongoose // 加载 mongoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ### 2、配置[​](#2配置 "2、配置的直接链接") 和 typegoose 相同,或者说 typegoose 使用的就是 mongoose 的配置。 不管是单库还是多库,数据源配置都是类似的。 单库: ``` export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '**********' } } } }, } ``` 多库: ``` export default { // ... mongoose: { dataSource: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` ### 3、使用[​](#3使用 "3、使用的直接链接") 当我们希望获取到原始的连接对象时,可以直接使用封装好的 `MongooseConnectionService` 对象。 ``` import { Provide, Inject, Init } from '@midwayjs/core'; import { MongooseDataSourceManager } from '@midwayjs/mongoose'; import { Schema, Document } from 'mongoose'; interface User extends Document { name: string; email: string; avatar: string; } @Provide() export class TestService { @Inject() dataSourceManager: MongooseDataSourceManager; @Init() async init() { // get default connection this.conn = this.dataSourceManager.getDataSource('default'); } async invoke(){ const schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, avatar: String }); const UserModel = this.conn.model('User', schema); const doc = new UserModel({ name: 'Bill', email: 'bill@initech.com', avatar: 'https://i.imgur.com/dM7Thhn.png' }); await doc.save(); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、E002: You are using a NodeJS Version below 12.22.0[​](#1e002-you-are-using-a-nodejs-version-below-12220 "1、E002: You are using a NodeJS Version below 12.22.0的直接链接") 在新版本 @typegoose/typegoose (v8, v9) 中增加了 Node 版本的校验,如果你的 Node.js 版本低于 v12.22.0,就会出现这个提示。 普通情况下,请升级 Node.js 到这个版本以上即可解决。 在特殊场景下,比如 Serverless 无法修改 Node.js 版本且版本低于 v12.22 的情况下,由于 v12 版本子版本其实都可以,可以通过临时修改 process.version 绕过。 ``` // src/configuration.ts Object.defineProperty(process, 'version', { value: 'v12.22.0', writable: true, }); // other code export class MainConfiguration {} ``` --- # MQTT MQTT是用于物联网 (IoT) 的OASIS标准消息传递协议。它被设计为非常轻量级的发布/订阅消息传输,非常适合以较小的代码占用空间和最小的网络带宽连接远程设备。MQTT目前广泛应用于汽车、制造、电信、石油和天然气等行业。 相关信息: | 描述 | | | ----------------- | ------------ | | 可用于标准项目 | ✅ | | 可用于 Serverless | 可以发布消息 | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 版本要求[​](#版本要求 "版本要求的直接链接") 由于 [mqtt](https://github.com/mqttjs/MQTT.js) 库本身的要求,所需要的版本为 **Node.js >= 16** ## 前置依赖[​](#前置依赖 "前置依赖的直接链接") 由于 MQTT 需要 Broker 作为中转传输,你需要自行部署 MQTT Broker 服务,本文档不提供 MQTT 服务本身的部署指导。 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 mqtt 组件。 ``` $ npm i @midwayjs/mqtt@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/mqtt": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 中引入组件 ``` // ... import * as mqtt from '@midwayjs/mqtt'; @Configuration({ imports: [ // ...other components mqtt, ], }) export class MainConfiguration {} ``` 由于 MQTT 分为 **订阅者(subscriber)** 和 **发布者(publisher)** 两部分,两个可以独立使用,我们将分别介绍。 ## 订阅服务[​](#订阅服务 "订阅服务的直接链接") ### 基础配置[​](#基础配置 "基础配置的直接链接") 通过 `sub` 字段和 `@MqttSubscriber` 装饰器,我们可以配置多个订阅者。 比如,下面的 `sub1` 和 `sub2` 就是两个不同的订阅者。 ``` // src/config/config.default export default { mqtt: { sub: { sub1: { // ... }, sub2: { // ... } } } } ``` 最简单的订阅者配置需要几个字段,订阅的地址和订阅的 Topic。 ``` // src/config/config.default export default { mqtt: { sub: { sub1: { connectOptions: { host: 'test.mosquitto.org', port: 1883, }, subscribeOptions: { topicObject: 'test', }, }, sub2: { // ... } } } } ``` `sub1` 订阅者配置了 `connectOptions` 和 `subscribeOptions` ,分别代表连接配置和订阅配置。 ### 订阅实现[​](#订阅实现 "订阅实现的直接链接") 我们可以在目录中提供一个标准的订阅器实现,比如 `src/consumer/sub1.subscriber.ts`。 ``` // src/consumer/sub1.subscriber.ts import { ILogger, Inject } from '@midwayjs/core'; import { Context, IMqttSubscriber, MqttSubscriber } from '@midwayjs/mqtt'; @MqttSubscriber('sub1') export class Sub1Subscriber implements IMqttSubscriber { @Inject() ctx: Context; async subscribe() { // ... } } ``` `@MqttSubscriber` 装饰器声明了一个订阅类实现,它的参数为订阅者的名字,比如我们配置文件中的 `sub1`。 `IMqttSubscriber` 接口约定了一个 `subscribe` 方法,每当接收到新的消息时,这个方法就会被执行。 和其他消息订阅机制一样,消息本身通过 `Context` 字段来传递。 ``` // ... export class Sub1Subscriber implements IMqttSubscriber { @Inject() ctx: Context; async subscribe() { const payload = this.ctx.message.toString(); // ... } } ``` `Context` 字段包括几个 mqtt 属性。 | 属性 | 类型 | 描述 | | ----------- | ------------------------------ | ---------------- | | ctx.topic | string | 订阅 Topic | | ctx.message | Buffer | 消息内容 | | ctx.packet | IPublishPacket(来自 mqtt 库) | publish 的包信息 | ## 消息发布[​](#消息发布 "消息发布的直接链接") ### 基础配置[​](#基础配置-1 "基础配置的直接链接") 消息发布也需要创建实例,配置本身使用了 [服务工厂](/docs/service_factory.md) 的设计模式。 比如多实例配置如下: ``` // src/config/config.default export default { mqtt: { pub: { clients: { default: { host: 'test.mosquitto.org', port: 1883, }, pub2: { // ... } } } } } ``` 上面的配置创建了名为 `default` 和 `pub2` 的两个实例。 ### 使用发布者[​](#使用发布者 "使用发布者的直接链接") 如果实例名为 `default` ,则可以使用默认的消息发布类。 比如: ``` // src/service/user.service.ts import { Provide, Inject } from '@midwayjs/core'; import { DefaultMqttProducer } from '@midwayjs/mqtt'; @Provide() export class UserService { @Inject() producer: DefaultMqttProducer; async invoke() { // 同步发布消息 this.producer.publish('test', 'hello world'); // 异步发布 await this.producer.publishAsync('test', 'hello world'); // 增加配置 await this.producer.publishAsync('test', 'hello world', { qos: 2 }); } } ``` 也可以使用内置的工厂类 `MqttProducerFactory` 注入不同的实例。 ``` // src/service/user.service.ts import { Provide, Inject } from '@midwayjs/core'; import { MqttProducerFactory, DefaultMqttProducer } from '@midwayjs/mqtt'; @Provide() export class UserService { @InjectClient(MqttProducerFactory, 'pub2') producer: DefaultMqttProducer; async invoke() { // ... } } ``` ## 组件日志[​](#组件日志 "组件日志的直接链接") 组件有着自己的日志,默认会将 `ctx.logger` 记录在 `midway-mqtt.log` 中。 我们可以单独配置这个 logger 对象。 ``` export default { midwayLogger: { // ... mqttLogger: { fileLogName: 'midway-mqtt.log', }, } } ``` 这个日志的输出格式,我们也可以单独配置。 ``` export default { mqtt: { // ... contextLoggerFormat: info => { const { jobId, from } = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.message}`; }, } } ``` --- # 单次执行 `@midwayjs/one-shot` 是一个只提供 Framework 的一次性脚本执行组件,适合用 IoC 容器组织依赖,并在应用内触发一次性的任务逻辑。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ❌ | | 可用于 Serverless | ❌ | | 可用于一体化 | ❌ | | 包含独立主框架 | ✅ | | 包含独立日志 | ✅ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 one-shot 组件依赖。 ``` $ npm i @midwayjs/one-shot@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/one-shot": "^4.0.0" } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在入口配置中引入组件。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as oneShot from '@midwayjs/one-shot'; @Configuration({ imports: [oneShot], }) export class MainConfiguration {} ``` ## 在生命周期执行[​](#在生命周期执行 "在生命周期执行的直接链接") 该组件不要求编写额外 Runner,推荐在 `onServerReady` 生命周期里直接执行一次性脚本逻辑。 ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as oneShot from '@midwayjs/one-shot'; import { ScriptService } from './service/script'; @Configuration({ imports: [oneShot], }) export class MainConfiguration { @Inject() scriptService: ScriptService; async onServerReady() { await this.scriptService.runOnce(); } } ``` ## 需要请求作用域时[​](#需要请求作用域时 "需要请求作用域时的直接链接") 如果脚本逻辑需要依赖请求作用域(request scope),可以通过 framework 的 `runScript` 执行一个固定格式的 service 类,框架会为本次执行创建上下文并走中间件/过滤器链。 ``` // src/script/syncUser.ts import { Provide } from '@midwayjs/core'; import { OneShotRunner, Context } from '@midwayjs/one-shot'; @Provide() export class SyncUserScript implements OneShotRunner<{ id: number }, void> { async run(payload?: { id: number }, ctx?: Context) { // use payload / ctx void payload; void ctx; } } ``` ``` // src/configuration.ts import { Configuration, Inject } from '@midwayjs/core'; import * as oneShot from '@midwayjs/one-shot'; import { Framework } from '@midwayjs/one-shot'; import { SyncUserScript } from './script/syncUser'; @Configuration({ imports: [oneShot], }) export class MainConfiguration { @Inject() framework: Framework; async onServerReady() { await this.framework.runScript(SyncUserScript, { id: 42 }); } } ``` ## 日志[​](#日志 "日志的直接链接") 组件默认会注册一个名为 `oneShotLogger` 的 logger,默认写入 `midway-one-shot.log`。 你可以在脚本服务里通过 `@Logger('oneShotLogger')` 注入使用,例如: ``` import { Logger, ILogger } from '@midwayjs/core'; export class ScriptService { @Logger('oneShotLogger') logger: ILogger; async runOnce() { this.logger.info('run one-shot task'); } } ``` 如果希望自定义日志文件名或级别,可以在应用配置中覆盖 `midwayLogger.clients.oneShotLogger`: ``` // src/config/config.default.ts export default { midwayLogger: { clients: { oneShotLogger: { fileLogName: 'my-one-shot.log', level: 'info', }, }, }, }; ``` --- # TypeORM [TypeORM](https://github.com/typeorm/typeorm) 是 `node.js` 现有社区最成熟的对象关系映射器(`ORM` )。本文介绍如何在 Midway 中使用 TypeORM 。 提示 本模块是从 v3.4.0 开始为新版本,模块名有变化,历史写法部分兼容,如果查询历史文档,请参考 [这里](/docs/legacy/orm.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 旧模块为 `@midwayjs/orm` ,新模块为 `@midwayjs/typeorm`,区别如下: * 1、包名不同 * 2、在 `src/config.default` 的部分配置调整 * 2.1 配置文件中的 key 不同 (orm => typeorm) * 2.2修改为数据源的形式 `typeorm.dataSource` * 2.3 实体模型类或者实体模型类的路径,需要在数据源的 `entities` 字段中声明 * 2.4 Subscriber 需要在数据源的 `subscribers` 字段中声明 * 3、不再使用 `EntityModel` 装饰器,直接使用 typeorm 提供的能力 ## 安装组件[​](#安装组件 "安装组件的直接链接") 安装 typeorm 组件,提供数据库 ORM 能力。 ``` $ npm i @midwayjs/typeorm@4 typeorm --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/typeorm": "^4.0.0", "typeorm": "~0.3.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 orm 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as orm from '@midwayjs/typeorm'; import { join } from 'path'; @Configuration({ imports: [ // ... orm // 加载 typeorm 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 信息 * Oracle driver 比较特殊,需要查看 [文档](https://github.com/oracle/node-oracledb) * 不建议使用 typeorm 链接 mongodb,请使用 mongoose 组件 ## 简单的目录结构[​](#简单的目录结构 "简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── photo.entity.ts // 实体文件 │ │ └── photoMetadata.entity.ts │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ## 入门[​](#入门 "入门的直接链接") 下面,我们将以 mysql 举例。 ### 1、创建 Model[​](#1创建-model "1、创建 Model的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `photo` 举例。新建 entity 目录,在其中添加实体文件 `photo.entity.ts` ,一个简单的实体如下。 ``` // entity/photo.entity.ts export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 ### 2、定义实体模型[​](#2定义实体模型 "2、定义实体模型的直接链接") 我们使用 `Entity` 来定义一个实体模型类。 ``` // entity/photo.entity.ts import { Entity } from 'typeorm'; @Entity('photo') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 如果表名和当前的实体名不同,可以在参数中指定。 ``` // entity/photo.entity.ts import { Entity } from 'typeorm'; @Entity('photo_table_name') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 这些实体列也可以使用 [typeorm\_generator](/docs/tool/typeorm_generator.md) 工具生成。 ### 3、添加数据库列[​](#3添加数据库列 "3、添加数据库列的直接链接") 通过 typeorm 提供的 `@Column` 装饰器来修饰属性,每一个属性对应一个列。 ``` // entity/photo.entity.ts import { Entity, Column } from 'typeorm'; @Entity() export class Photo { @Column() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` 现在 `id` , `name` , `description` ,`filename` , `views` , `isPublished` 列将添加到 `photo` 表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 `@Column`装饰器中显式指定列类型来使用数据库支持的任何列类型。 我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。 数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 [官方文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/entities.md#%E5%88%97%E9%80%89%E9%A1%B9)。 ### 4、创建主键列[​](#4创建主键列 "4、创建主键列的直接链接") 每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 `@PrimaryColumn` 装饰器。 ``` // entity/photo.entity.ts import { Entity, Column, PrimaryColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 5、创建自增主键列[​](#5创建自增主键列 "5、创建自增主键列的直接链接") 现在,如果要设置自增的 id 列,需要将 `@PrimaryColumn` 装饰器更改为 `@PrimaryGeneratedColumn` 装饰器: ``` // entity/photo.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 6、列数据类型[​](#6列数据类型 "6、列数据类型的直接链接") 接下来,让我们调整数据类型。默认情况下,字符串映射到类似 `varchar(255)` 的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。 ``` // entity/photo.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Photo { @PrimaryGeneratedColumn() id: number; @Column({ length: 100 }) name: string; @Column('text') description: string; @Column() filename: string; @Column("double") views: number; @Column() isPublished: boolean; } ``` 示例,不同列名 ``` @Column({ length: 100, name: 'custom_name' }) name: string; ``` 此外还有有几种特殊的列类型可以使用: * `@CreateDateColumn` 是一个特殊列,自动为实体插入日期。 * `@UpdateDateColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。 * `@VersionColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。 * `@DeleteDateColumn` 是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。 比如: ``` @CreateDateColumn({ type: 'timestamp', }) createdDate: Date; ``` 列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](https://github.com/typeorm/typeorm/blob/master/docs/entities.md#column-types)。 提示 `CreateDateColumn` 和 `UpdateDateColumn` 是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。 ### 7、配置连接信息和实体模型[​](#7配置连接信息和实体模型 "7、配置连接信息和实体模型的直接链接") 请参考 [配置](/docs/env_config.md) 章节,增加配置文件。 然后在 `config.default.ts` 中配置数据库连接信息。 ``` // src/config/config.default.ts import { Photo } from '../entity/photo.entity'; export default { // ... typeorm: { dataSource: { default: { /** * 单数据库实例 */ type: 'mysql', host: '*******', port: 3306, username: '*******', password: '*******', database: undefined, synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true,注意会丢数据 logging: false, // 配置实体模型 entities: [Photo], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配 entities: [ 'entity', // 特定目录 '**/*.entity.{j,t}s', // 通配加后缀匹配 ] } } }, } ``` 提示 * 1. 如果使用的数据库已经有表结构同步的功能,比如云数据库,最好不要开启。如果一定要使用,synchronize 配置最好仅在开发阶段,或者第一次使用,避免造成一致性问题。 * 2. `entities` 字段配置已经经过框架处理,该字段配置请不要参考原始文档。 `type` 字段你可以使用其他的数据库类型,包括`mysql`, `mariadb`, `postgres`, `cockroachdb`, `sqlite`, `mssql`, `oracle`, `cordova`, `nativescript`, `react-native`, `expo`, or `mongodb` 比如 sqlite,需要以下信息。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { type: 'sqlite', database: path.join(__dirname, '../../test.sqlite'), synchronize: true, logging: true, // ... } } }, } ``` 信息 注意:synchronize 字段用于同步表结构。使用 `synchronize: true` 进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。 ### 8、使用 Model 插入数据库数据[​](#8使用-model-插入数据库数据 "8、使用 Model 插入数据库数据的直接链接") 在常见的 Midway 文件中,使用 `@InjectEntityModel` 装饰器注入我们配置好的 Model。我们所需要做的只是: * 1、创建实体对象 * 2、执行 `save()` ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // save async savePhoto() { // create a entity object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // save entity const photoResult = await this.photoModel.save(photo); // save success console.log('photo id = ', photoResult.id); } } ``` ### 9、查询数据[​](#9查询数据 "9、查询数据的直接链接") 更多的查询参数,请查询 [find文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/find-options.md)。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhotos() { // find All let allPhotos = await this.photoModel.find({}); console.log("All photos from the db: ", allPhotos); // find first let firstPhoto = await this.photoModel.findOne({ where: { id: 1 } }); console.log("First photo from the db: ", firstPhoto); // find one by name let meAndBearsPhoto = await this.photoModel.findOne({ where: { name: "Me and Bears" } }); console.log("Me and Bears photo from the db: ", meAndBearsPhoto); // find by views let allViewedPhotos = await this.photoModel.find({ where: { views: 1 } }); console.log("All viewed photos: ", allViewedPhotos); let allPublishedPhotos = await this.photoModel.find({ where: { isPublished: true } }); console.log("All published photos: ", allPublishedPhotos); // find and get count let [allPhotos, photosCount] = await this.photoModel.findAndCount({}); console.log("All photos: ", allPhotos); console.log("Photos count: ", photosCount); } } ``` ### 10、更新数据库[​](#10更新数据库 "10、更新数据库的直接链接") 现在,让我们从数据库中加载一个 Photo,对其进行更新并保存。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { let photoToUpdate = await this.photoModel.findOne({ where: { id: 1, }, }); photoToUpdate.name = "Me, my friends and polar bears"; await this.photoModel.save(photoToUpdate); } } ``` ### 11、删除数据[​](#11删除数据 "11、删除数据的直接链接") `remove` 用于删除给定的实体或实体数组。`delete` 用于按给定的 ID 或者条件删除。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from '../entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { /*...*/ const photo = await this.photoModel.findOne({ where: { id: 1, }, }); // 删除单个 await this.photoModel.remove(photo) // 删除多个 await this.photoModel.remove([photo1, photo2, photo3]); // 按 id 删除 await this.photoModel.delete(1); await this.photoModel.delete([1, 2, 3]); await this.photoModel.delete({ name: "Timber" }); } } ``` 现在,ID = 1的 Photo 将从数据库中删除。 此外还有软删除的方法。 ``` await this.photoModel.softDelete(1); // 使用 restore 方法恢复; await this.photoModel.restore(1); ``` ### 12、创建一对一关联[​](#12创建一对一关联 "12、创建一对一关联的直接链接") 让我们与另一个类创建一对一的关系。让我们在 `entity/photoMetadata.entity.ts` 中创建一个新类。这个类包含 photo 的其他元信息。 ``` import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo.entity'; @Entity() export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column("int") height: number; @Column("int") width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string; @OneToOne(type => Photo) @JoinColumn() photo: Photo; } ``` 在这里,我们使用一个名为 `@OneToOne` 的新装饰器。它允许我们在两个实体之间创建一对一的关系。`type => Photo`是一个函数,它返回我们要与其建立关系的实体的类。 由于语言的特殊性,我们被迫使用一个返回类的函数,而不是直接使用该类。我们也可以将其写为 `() => Photo` ,但是我们使用 `type => Photo`作为惯例来提高代码的可读性。类型变量本身不包含任何内容。 我们还添加了一个 `@JoinColumn`装饰器,它指示关系的这一侧将拥有该关系。关系可以是单向或双向的。关系只有一方可以拥有。关系的所有者端需要使用@JoinColumn装饰器。 如果您运行该应用程序,则会看到一个新生成的表,该表将包含一列,其中包含用于 Photo 关系的外键。 ``` +-------------+--------------+----------------------------+ | photo_metadata | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | height | int(11) | | | width | int(11) | | | comment | varchar(255) | | | compressed | boolean | | | orientation | varchar(255) | | | photoId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 接下去我们要在代码中关联他们。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { PhotoMetadata } from './entity/photoMetadata.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(PhotoMetadata) photoMetadataModel: Repository; async updatePhoto() { // create a photo let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create a photo metadata let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; metadata.photo = photo; // this way we connect them // first we should save a photo await this.photoModel.save(photo); // photo is saved. Now we need to save a photo metadata await this.photoMetadataModel.save(metadata); // done console.log("Metadata is saved, and relation between metadata and photo is created in the database too"); } } ``` ### 13、反向关系映射[​](#13反向关系映射 "13、反向关系映射的直接链接") 关系映射可以是单向或双向的。当在 PhotoMetadata 和 Photo之间的关系是单向的。关系的所有者是PhotoMetadata,而 Photo对 PhotoMetadata 是一无所知的。这使得从 Photo 端访问 PhotoMetadata 变得很复杂。若要解决此问题,我们添加一个反向的关系映射,使 PhotoMetadata 和 Photo之间变成双向关联。让我们修改我们的实体。 ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo'; @Entity() export class PhotoMetadata { /* ... other columns */ @OneToOne(type => Photo, photo => photo.metadata) @JoinColumn() photo: Photo; } ``` ``` import { Entity } from 'typeorm'; import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata.entity'; @Entity() export class Photo { /* ... other columns */ @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo) metadata: PhotoMetadata; } ``` `photo => photo.metadata` 是一个返回反向映射关系的函数。在这里,我们显式声明 Photo 类的 metadata 属性用于关联 PhotoMetadata。除了传递返回 photo 属性的函数外,您还可以直接将字符串传递给 `@OneToOne` 装饰器,例如 `“metadata”` 。但是我们使用了这种函数回调的方法来让我们的代码写法更简单。 请注意,只会在关系映射的一侧使用 `@JoinColumn` 装饰器。无论您放置此装饰器的哪一侧,都是关系的所有者。关系的拥有方在数据库中包含带有外键的列。 ### 14、加载对象及其依赖关系[​](#14加载对象及其依赖关系 "14、加载对象及其依赖关系的直接链接") 现在,让我们尝试在单个查询中一起加载出 Photo 和 PhotoMetadata。有两种方法可以执行此操作,使用 `find *` 方法或使用 `QueryBuilder` 功能。让我们首先使用 `find *` 方法。 `find *` 方法允许您使用 `FindOneOptions` / `FindManyOptions` 接口指定对象。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel.find({ relations: [ 'metadata' ] }); // typeorm@0.2.x } } ``` 在这里,photos 的值是一个数组,包含了整个数据库的查询结果,并且每个 photo 对象都包含其关联的 metadata 属性。在[此文档](https://github.com/typeorm/typeorm/blob/master/docs/find-options.md)中了解有关 `Find Options` 的更多信息。 使用 `Find Options` 很简单,但如果需要更复杂的查询,则应改用 `QueryBuilder` 。 `QueryBuilder` 允许以优雅的方式使用更复杂的查询。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel .createQueryBuilder('photo') .innerJoinAndSelect('photo.metadata', 'metadata') .getMany(); } } ``` `QueryBuilder`允许创建和执行几乎任何复杂的 SQL 查询。使用 `QueryBuilder` 时,请像创建 SQL 查询一样思考。在此示例中,“photo” 和 “metadata” 是应用于所选 photos 的别名。您可以使用别名来访问所选数据的列和属性。 ### 15、使用级联操作自动保存关联对象[​](#15使用级联操作自动保存关联对象 "15、使用级联操作自动保存关联对象的直接链接") 在我们希望在每次保存另一个对象时都自动保存关联的对象,这个时候可以在关系中设置级联。让我们稍微更改照片的 `@OneToOne` 装饰器。 ``` export class Photo { /// ... other columns @OneToOne(type => PhotoMetadata, metadata => metadata.photo, { cascade: true, }) metadata: PhotoMetadata; } ``` 使用 `cascade` 允许我们现在不再单独保存 Photo 和 PhotoMetadata,由于级联选项,元数据对象将被自动保存。 ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { PhotoMetadata } from './entity/photoMetadata.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { // create photo object let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create photo metadata object let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; photo.metadata = metadata; // this way we connect them // save a photo also save the metadata await this.photoModel.save(photo); // done console.log("Photo is saved, photo metadata is saved too"); } } ``` 注意,我们现在设置 Photo 的元数据,而不需要像之前那样设置元数据的 Photo 属性。这仅当您从 Photo 这边将 Photo 连接到 PhotoMetadata 时,级联功能才有效。如果在 PhotoMetadata 侧设置,则不会自动保存。 ### 16、创建多对一/一对多关联[​](#16创建多对一一对多关联 "16、创建多对一/一对多关联的直接链接") 让我们创建一个多对一/一对多关系。假设一张照片有一个作者,每个作者可以有很多照片。首先,让我们创建一个 Author 类: ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from 'typeorm'; import { Photo } from './entity/photo.entity'; @Entity() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below photos: Photo[]; } ``` `Author` 包含了一个反向关系。 `OneToMany` 和 `ManyToOne` 需要成对出现。 现在,将关系的所有者添加到 Photo 实体中: ``` import { Entity } from 'typeorm'; import { Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata.entity'; import { Author } from './author.entity'; @Entity() export class Photo { /* ... other columns */ @ManyToOne(type => Author, author => author.photos) author: Author; } ``` 在多对一/一对多关系中,所有者方始终是多对一。这意味着使用 `@ManyToOne` 的类将存储相关对象的 ID。 运行应用程序后,ORM 将创建 `author` 表: ``` +-------------+--------------+----------------------------+ | author | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | +-------------+--------------+----------------------------+ ``` 它还将修改 `photo` 表,添加新的 `author` 列并为其创建外键: ``` +-------------+--------------+----------------------------+ | photo | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | | description | varchar(255) | | | filename | varchar(255) | | | isPublished | boolean | | | authorId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` ### 17、创建多对多关联[​](#17创建多对多关联 "17、创建多对多关联的直接链接") 让我们创建一个多对一/多对多关系。假设一张照片可以在许多相册中,并且每个相册可以包含许多照片。让我们创建一个 `Album` 类。 ``` import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm'; @Entity() export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany(type => Photo, photo => photo.albums) @JoinTable() photos: Photo[]; } ``` `@JoinTable` 用来指明这是关系的所有者。 现在,将反向关联添加到 `Photo` 。 ``` export class Photo { /// ... other columns @ManyToMany(type => Album, album => album.photos) albums: Album[]; } ``` 运行应用程序后,ORM将创建一个 album\_photos\_photo\_albums 联结表: ``` +-------------+--------------+----------------------------+ | album_photos_photo_albums | +-------------+--------------+----------------------------+ | album_id | int(11) | PRIMARY KEY FOREIGN KEY | | photo_id | int(11) | PRIMARY KEY FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 现在,让我们将相册和照片插入数据库: ``` import { Provide, Inject } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Photo } from './entity/photo.entity'; import { Album } from './entity/album.entity'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(Album) albumModel: Repository async updatePhoto() { // create a few albums let album1 = new Album(); album1.name = "Bears"; await this.albumModel.save(album1); let album2 = new Album(); album2.name = "Me"; await this.albumModel.save(album2); // create a few photos let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.albums = [album1, album2]; await this.photoModel.save(photo); // now our photo is saved and albums are attached to it // now lets load them: const loadedPhoto = await this.photoModel.findOne(1, { relations: ["albums"] }); // typeorm@0.2.x } } ``` `loadedPhoto` 的值为: ``` { id: 1, name: "Me and Bears", description: "I am near polar bears", filename: "photo-with-bears.jpg", albums: [{ id: 1, name: "Bears" }, { id: 2, name: "Me" }] } ``` ### 18、使用 QueryBuilder[​](#18使用-querybuilder "18、使用 QueryBuilder的直接链接") 您可以使用QueryBuilder来构建几乎任何复杂的SQL查询。例如,您可以这样做: ``` let photos = await this.photoModel .createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it. .innerJoinAndSelect("photo.metadata", "metadata") .leftJoinAndSelect("photo.albums", "album") .where("photo.isPublished = true") .andWhere("(photo.name = :photoName OR photo.name = :bearName)") .orderBy("photo.id", "DESC") .skip(5) .take(10) .setParameters({ photoName: "My", bearName: "Mishka" }) .getMany(); ``` 该查询选择所有带有 “My” 或 “Mishka” 名称的已发布照片。它将从位置 5 开始返回结果(分页偏移),并且将仅选择 10 个结果(分页限制)。选择结果将按 ID 降序排列。该照片的相册将 left-Joined,元数据将自动关联。 您将在应用程序中大量使用查询生成器。在 [此处](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/select-query-builder.md) 了解有关QueryBuilder的更多信息。 ### 19、Event Subscriber[​](#19event-subscriber "19、Event Subscriber的直接链接") typeorm 提供了一个事件订阅机制,方便在做一些数据库操作时的日志输出,为此 midway 提供了一个 `EventSubscriberModel` 装饰器,用来标注事件订阅类,代码如下。 ``` import { EventSubscriberModel } from '@midwayjs/typeorm'; import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm'; @EventSubscriberModel() export class EverythingSubscriber implements EntitySubscriberInterface { /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { console.log(`BEFORE ENTITY INSERTED: `, event.entity); } /** * Called before entity insertion. */ beforeUpdate(event: UpdateEvent) { console.log(`BEFORE ENTITY UPDATED: `, event.entity); } /** * Called before entity insertion. */ beforeRemove(event: RemoveEvent) { console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity insertion. */ afterInsert(event: InsertEvent) { console.log(`AFTER ENTITY INSERTED: `, event.entity); } /** * Called after entity insertion. */ afterUpdate(event: UpdateEvent) { console.log(`AFTER ENTITY UPDATED: `, event.entity); } /** * Called after entity insertion. */ afterRemove(event: RemoveEvent) { console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity is loaded. */ afterLoad(entity: any) { console.log(`AFTER ENTITY LOADED: `, entity); } } ``` 这个订阅类提供了一些常用的接口,用来在数据库操作时执行一些事情。 同时,我们需要把订阅类加到配置中。 ``` // src/config/config.default.ts import { EverythingSubscriber } from '../event/subscriber'; export default { // ... typeorm: { dataSource: { default: { // ... entities: [Photo], // 传入订阅类 subscribers: [EverythingSubscriber] } } }, } ``` ## Repository API[​](#repository-api "Repository API的直接链接") 更多 API 请查看 [官网文档](https://github.com/typeorm/typeorm/blob/master/docs/repository-api.md)。 ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 多数据库支持[​](#多数据库支持 "多数据库支持的直接链接") 有时候,我们一个应用中会有多个数据库连接(Connection)的情况,这个时候会有多个配置。我们使用 DataSource 标准的 \*\*对象的形式 \*\*来定义配置。 比如下面定义了 `default` 和 `test` 两个数据库连接(Connection)。 ``` import { join } from 'path'; export default { typeorm: { dataSource: { default: { type: 'sqlite', database: join(__dirname, '../../default.sqlite'), // ... }, test: { type: 'mysql', host: '127.0.0.1', port: 3306, // ... } } } } ``` 在使用时,需要指定模型归属于哪个连接(Connection)。 ``` import { InjectEntityModel } from '@midwayjs/typeorm'; import { User } from './entity/user.entity'; export class XXX { @InjectEntityModel(User, 'test') testUserModel: Repository; //... } ``` ### 列值转换[​](#列值转��换 "列值转换的直接链接") 我们可以在实体定义中处理列值转换。 利用列装饰器的 `transformer` 参数,可以进行出入参的处理,比如对时间格式化。 ``` import { Entity, Column, CreateDateColumn, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'; import * as dayjs from 'dayjs'; const dateTransformer = { from: (value: Date | number) => { return dayjs(typeof value === 'number' ? value: value.getTime()).format('YYYY-MM-DD HH:mm:ss'); }, to: () => new Date(), }; @Entity() export class Photo { // ... @CreateDateColumn({ type: 'timestamp', transformer: dateTransformer, }) createdAt: Date; } ``` ### 指定默认数据源[​](#指定默认数据源 "指定默认数据源的直接链接") 在包含多个数据源时,可以指定默认的数据源。 ``` export default { // ... typeorm: { dataSource: { default1: { // ... }, default2: { // ... }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default1', }, }; ``` ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的 DataSource 对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(TypeORMDataSourceManager); const conn = dataSourceManager.getDataSource('default'); console.log(dataSourceManager.isConnected(conn)); } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/typeorm'; import { DataSource } from 'typeorm'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: DataSource; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: DataSource; async onReady(container: IMidwayContainer) { // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 数据源在未配置日志对象时,组件会自动创建一个 `typeormLogger`,用于保存执行的 SQL 信息,方便排查问题和 SQL 审核。 默认配置为: ``` export default { midwayLogger: { clients: { typeormLogger: { fileLogName: 'midway-typeorm.log', enableError: false, level: 'info', }, }, } } ``` 我们可以使用普通日志的配置方式进行调整,如果不希望生成日志,可以配置关闭。 ``` export default { // ... typeorm: { default: { // 所有数据源关闭 logging: false, }, dataSource: { default: { // 单个数据源关闭 logging: false, }, }, }, }; ``` ### 事务[​](#事务 "事务的直接链接") typeorm 的事务需要先获取到数据源,然后开启事务。 ``` import { Provide, Inject } from '@midwayjs/core'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; import { UserDTO } from '../entity/user'; @Provide() export class UserService { @Inject() dataSourceManager: TypeORMDataSourceManager; async updateUser(user: UserDTO) { // get dataSource const dataSource = this.dataSourceManager.getDataSource('default'); // start transaction await dataSource.transaction(async (transactionalEntityManager) => { // run code await transactionalEntityManager.save(UserDTO, user); }); } } ``` 更多的细节,可以参考 [文档](https://github.com/typeorm/typeorm/blob/master/docs/transactions.md)。 ### CLI[​](#cli "CLI的直接链接") TypeORM 默认提供了一个 CLI,用来创建 entity,migration 等,更多文档请查看 [这里](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/using-cli.md)。 由于 TypeORM 的默认配置和 Midway 不同,我们提供了一个简单的修改版本,用于适配 Midway 的数据源配置。 检查安装情况: ``` $ npx mwtypeorm -h ``` 常用的命令有 **创建空 Entity** 将会创建一个 `src/entity/User.ts` 文件。 ``` $ npx mwtypeorm entity:create src/entity/User ``` **创建 Migration** 将会根据现有数据源生成一个 `src/migration/******-photo.entity.ts` 文件。 比如配置如下: ``` export default { typeorm: { dataSource: { 'default': { // ... entities: [ '**/entity/*.entity{.ts,.js}' ], migrations: [ '**/migration/*.ts' ], }, }, } ``` 可以执行下面的命令,将修改后的 Entity 生成迁移文件。 ``` $ npx mwtypeorm migration:generate -d ./src/config/config.default.ts src/migration/photo ``` 警告 注意:上面的 entities 配置由于需要再 CLI 和 Midway 间复用,采用了两者都支持的扫描写法。 ### 关于表结构同步[​](#关于表结构同步 "关于表结构同步的直接链接") * 如果你已有表结构,想自动创建 Entity,使用 [生成器](https://www.npmjs.com/package/typeorm-model-generator) * 如果已经有 Entity 代码,想创建表结构请使用配置中的 `synchronize: true` ,注意可能会丢失数据 * 如果已经上线,但是又修改了表结构,可以使用 CLI 中的 `migration:generate` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Handshake inactivity timeout[​](#handshake-inactivity-timeout "Handshake inactivity timeout的直接链接") 一般是网络原因,如果本地出现,可以 ping 但是telnet不通,可以尝试执行如下命令: ``` $ sudo sysctl -w net.inet.tcp.sack=0 ``` ### 关于 mysql 时间列的时区展示[​](#关于-mysql-时间列的时区展示 "关于 mysql 时间列的时区展示的直接链接") 一般情况下,数据库中保存的是 UTC 时间,如果你希望返回当前时区的时间,可以使用下面的方式 **1、检查 mysql 数据库所在的环境** 比如下面默认的时区其实就是系统 UTC 时间,可以调整为 `+08:00`。 ``` mysql> show global variables like '%time_zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | UTC | | time_zone | SYSTEM | +------------------+--------+ 2 rows in set (0.05 sec) ``` **2、检查服务代码部署的环境** 尽量和数据库所在的环境一致,如果不一致,请在配置中设置 `timezone` (设置为和 mysql 一致)。 ``` export default { typeorm: { dataSource: { default: { type: 'mysql', // ... timezone: '+08:00', }, }, }, } ``` ### 时间列返回字符串[​](#时间列返回字符串 "时间列返回字符串的直接链接") 配置 dateStrings 可以使 mysql 返回时间按 DATETIME 格式返回,只对 mysql 生效。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { //... dateStrings: true, } } }, } ``` 如果使用了 `@CreateDateColumn` 和 `@UpdateDateColumn` ,可以调整实体返回类型。 ``` @UpdateDateColumn({ name: "gmt_modified", type: 'timestamp' }) gmtModified: string; @CreateDateColumn({ name: "gmt_create", type: 'timestamp', }) gmtCreate: string; ``` 效果如下: **配置前:** ``` gmtModified: 2021-12-13T03:49:43.000Z, gmtCreate: 2021-12-13T03:49:43.000Z ``` **配置后:** ``` gmtModified: '2021-12-13 11:49:43', gmtCreate: '2021-12-13 11:49:43' ``` ### 同时安装 mysql 和 mysql2[​](#同时安装-mysql-和-mysql2 "同时安装 mysql 和 mysql2的直接链接") 在 node\_modules 中同时有 mysql 和 mysql2 时,typeorm 会自动加载 mysql,而不是 mysql2。 这个时候如需使用 mysql2,请指定 driver。 ``` // src/config/config.default.ts export default { // ... typeorm: { dataSource: { default: { //... type: 'mysql', driver: require('mysql2'), } } }, } ``` ### Cannot read properties of undefined (reading 'getRepository')[​](#cannot-read-properties-of-undefined-reading-getrepository "Cannot read properties of undefined (reading 'getRepository')的直接链接") 一般是配置不正确,可以考虑两方面的配置: * 1、检查 `config.default.ts` 中的 `entities` 配置是否正确 * 2、检查 `configuration.ts` 文件,确认是否引入 orm --- # 阿里云对象存储(OSS) 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.999999999%,服务设计可用性不低于 99.99%。具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 `@midwayjs/oss` 组件就是在 midway 体系下用于对接 OSS 服务的 sdk。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 前置条件[​](#前置条件 "前置条件的直接链接") 使用 OSS 组件,你需要提前申请一个 OSS Bucket。Bucket 是 OSS 的存储库的概念,你的文件都将存储在这个库里。 * OSS 对象存储官网: * 什么是对象存储: ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/oss` 是主要的功能包。 ``` $ npm i @midwayjs/oss@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/oss": "^4.0.0", // ... }, } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as oss from '@midwayjs/oss'; import { join } from 'path' @Configuration({ imports: [ // ... oss // 导入 oss 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置 OSS[​](#配置-oss "配置 OSS的直接链接") OSS 组件需要配置后才能使用。需要填写 OSS 的 bucket、accessKeyId、accessKeySecret 等必要信息。 支持普通 oss 客户端和 oss 集群客户端,基于 [ali-oss](https://github.com/ali-sdk/ali-oss/) 这个包。 比如: **普通的 oss bucket 配置** ``` // src/config/config.default export default { // ... oss: { // normal oss bucket client: { accessKeyId: 'your access key', accessKeySecret: 'your access secret', bucket: 'your bucket name', endpoint: 'oss-cn-hongkong.aliyuncs.com', timeout: '60s', }, }, } ``` **集群(cluster) 模式的 oss bucket 配置,需要配置多个** ``` // src/config/config.default export default { // ... oss: { // need to config all bucket information under cluster client: { clusters: [{ endpoint: 'host1', accessKeyId: 'id1', accessKeySecret: 'secret1', }, { endpoint: 'host2', accessKeyId: 'id2', accessKeySecret: 'secret2', }], schedule: 'masterSlave', //default is `roundRobin` timeout: '60s', }, }, } ``` **STS 模式** ``` // src/config/config.default export default { // ... oss: { // if config.sts == true, oss will create STS client client: { sts: true, accessKeyId: 'your access key', accessKeySecret: 'your access secret', }, }, } ``` ## 使用组件[​](#使用组件 "使用组件的直接链接") 可以直接获取 `OSSService`,然后调用接口,比如,保存文件。 ``` import { OSSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossService: OSSService; async saveFile() { const localFile = join(__dirname, 'test.log'); const result = await this.ossService.put('/test/test.log', localFile); // => result.url } } ``` 如果配置的是 STS 模式,客户端可以使用 `OSSSTSService` 。 ``` import { OSSSTSService } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() stsService: OSSSTSService; async saveFile() { const roleArn = '******'; // 这里是阿里云角色的 arn const result = await this.stsService.assumeRole(roleArn); // result.credentials.AccessKeyId // result.credentials.AccessKeySecret; // result.credentials.SecurityToken; } } ``` 更多的 OSS 客户端 API,请查看 [OSS 文档](https://github.com/ali-sdk/ali-oss)。 ## 使用多个 OSS Bucket[​](#使用多个-oss-bucket "使用多个 OSS Bucket的直接链接") 有些应用需要访问多个 oss bucket,那么就需要配置 `oss.clients`。 ``` // src/config/config.default export default { // ... oss: { clients: { bucket1: { bucket: 'bucket1', // ... }, bucket2: { bucket: 'bucket2', // ... }, }, // client, clients,createInstance 方法共享的配置 default: { endpoint: '', accessKeyId: '', accessKeySecret: '', }, }, // other custom config bucket3: { bucket: 'bucket3', // ... }, } ``` 可以使用 `OSSServiceFactory` 获取不同的实例。 ``` import { OSSServiceFactory } from '@midwayjs/oss'; import { join } from 'path'; @Provide() export class UserService { @Inject() ossServiceFactory: OSSServiceFactory; @Config('bucket3') bucket3Config; async saveFile() { // 默认获取的类型是 OSSService const bucket1 = this.ossServiceFactory.get('bucket1'); const bucket2 = this.ossServiceFactory.get('bucket2'); // 如果是 STS,需要设置泛型联系 // const bucket1 = this.ossServiceFactory.get('bucket1'); // 会合并 config.bucket3 和 config.oss.default const bucket3 = await this.ossServiceFactory.createInstance(this.bucket3Config, 'bucket3'); // 传了名字之后也可以从 factory 中获取 bucket3 = this.ossServiceFactory.get('bucket3'); } } ``` --- # 身份验证 身份验证是大多数 Web 应用程序的重要组成部分。因此 Midway 封装了目前 Nodejs 中最流行的 Passport 库。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 从 v3.4.0 开始 Midway 自行维护 passport,将不再需要引入社区包和类型包。 ## 一些概念[​](#一些概念 "一些概念的直接链接") passport 是社区使用较多的身份验证库,通过称为策略的可扩展插件进行身份验证请求。 它本身包含几个部分: * 1、验证的策略,比如 jwt 验证,github 验证,oauth 验证等,passport 最为丰富的也是这块 * 2、执行策略之后,中间件的逻辑处理和配置,比如成功或者失败后的跳转,报错等 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 安装 `npm i @midwayjs/passport` 和相关策略依赖。 ``` ## 必选 $ npm i @midwayjs/passport@4 --save ## 可选 ## 下面安装本地策略 $ npm i passport-local --save $ npm i @types/passport-local --save-dev ## 下面安装 Github 策略 $ npm i passport-github --save ## 下面安装 Jwt 策略 $ npm i passport-jwt --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/passport": "^4.0.0", // 本地策略 "passport-local": "^1.0.0" // Jwt 策略 "passport-jwt": "^4.0.0", // Github 策略 "passport-github": "^1.1.0", // ... }, "devDependencies": { // 本地策略 "@types/passport-local": "^1.0.34", // Jwt 策略 "@types/passport-jwt": "^3.0.6", // Github 策略 "@types/passport-github": "^1.1.7", // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 首先启用组件。 ``` // src/configuration.ts import { join } from 'path'; import { ILifeCycle } from '@midwayjs/core'; import { Configuration } from '@midwayjs/core'; import * as passport from '@midwayjs/passport'; @Configuration({ imports: [ // ... passport, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle {} ``` ## 策略示例[​](#策略示例 "策略示例的直接链接") 这里我们以使用本地认证策略,和 Jwt 策略作为演示。 ### 示例:本地策略[​](#示例本地策略 "示例:本地策略的直接链接") 我们以 `passport-local` 来介绍 Passport 策略在 Midway 中如何使用, `passport-local` 的官方文档示例如下,通过 `passport.use` 加载一个策略,策略的验证逻辑是一个 `verify` 方法,包含 callback 参数,其余的策略的参数都在构造器中。 ``` passport.use( // 初始化一个策略 new LocalStrategy({ usernameField: 'username', passwordField: 'password', passReqToCallback: true, session: false }, function verify(username, password, done) { User.findOne({ username: username }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } if (!user.verifyPassword(password)) { return done(null, false); } return done(null, user); }); } ) ); ``` Midway 对此进行了改造,通过 `@CustomStrategy` 和 `PassportStrategy` 类继承一个 Passport 现有策略。 异步的 `validate` 方法代替原有的 `verify` 方法,`validate` 方法返回验证后的用户结果,方法的参数和原有对应的策略一致。 在 Midway 中编写的效果如下: ``` // src/strategy/local.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, IStrategyOptions } from 'passport-local'; import { Repository } from 'typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { UserEntity } from './user'; import * as bcrypt from 'bcrypt'; @CustomStrategy() export class LocalStrategy extends PassportStrategy(Strategy) { @InjectEntityModel(UserEntity) userModel: Repository; // 策略的验证 async validate(username, password) { const user = await this.userModel.findOneBy({ username }); if (!user) { throw new Error('用户不存在 ' + username); } if (!await bcrypt.compare(password, user.password)) { throw new Error('密码错误 ' + username); } return user; } // 当前策略的构造器参数 getStrategyOptions(): IStrategyOptions { return { usernameField: 'username', passwordField: 'password', passReqToCallback: true, session: false }; } } ``` 提示 注意:validate 方法是社区策略 verify 的 Promise 化替代方法,你无需在最后传递 callback 参数。 在 `passport-local` 的官方文档中,实现完策略后,需要作为中间件加载到业务中,比如: ``` app.post('/login/password', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })); ``` 提示 这里的 `local` 是 `passport-local` 内部的名字。 在 Midway 中,也需要将上述实现的 `LocalStrategy` 通过中间件加载。 自定义一个中间件继承 `PassportMiddleware` 扩展出的基础中间件,示例如下。 ``` // src/middleware/local.middleware.ts import { Middleware } from '@midwayjs/core'; import { PassportMiddleware, AuthenticateOptions } from '@midwayjs/passport'; import { LocalStrategy } from '../strategy/local.strategy'; @Middleware() export class LocalPassportMiddleware extends PassportMiddleware(LocalStrategy) { // 设置 AuthenticateOptions getAuthenticateOptions(): Promise | AuthenticateOptions { return { failureRedirect: '/login', }; } } ``` 将中间件加载到全局或者路由。 ``` // src/controller.ts import { Post, Inject, Controller } from '@midwayjs/core'; import { LocalPassportMiddleware } from '../middleware/local.middleware'; @Controller('/') export class LocalController { @Post('/passport/local', { middleware: [LocalPassportMiddleware] }) async localPassport() { console.log('local user: ', this.ctx.state.user); return this.ctx.state.user; } } ``` 使用 curl 模拟一次请求。 ``` curl -X POST http://localhost:7001/passport/local -d '{"username": "demo", "password": "1234"}' -H "Content-Type: application/json" 结果 {"username": "demo", "password": "1234"} ``` 警告 注意:如果将中间件放到全局,记得忽略需要登录的路由,否则请求会死循环。 ### 示例:Jwt 策略[​](#示例jwt-策略 "示例:Jwt 策略的直接链接") 首先需要 **额外安装** 依赖和策略: ``` $ npm i @midwayjs/jwt passport-jwt --save ``` 额外启用 jwt 组件。 ``` // configuration.ts import { join } from 'path'; import * as jwt from '@midwayjs/jwt'; import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as passport from '@midwayjs/passport'; @Configuration({ imports: [ // ... jwt, passport, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle {} ``` 然后在配置中设置,默认未加密,请不要把敏感信息存放在 payload 中。 ``` // src/config/config.default.ts export default { // ... jwt: { secret: 'xxxxxxxxxxxxxx', // fs.readFileSync('xxxxx.key') expiresIn: '2d', // https://github.com/vercel/ms }, }; ``` ``` // src/strategy/jwt.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; import { Config } from '@midwayjs/core'; @CustomStrategy() export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { @Config('jwt') jwtConfig; async validate(payload) { return payload; } getStrategyOptions(): any { return { secretOrKey: this.jwtConfig.secret, jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), }; } } ``` 提示 注意:validate 方法是社区策略 verify 的 Promise 化替代方法,你无需在最后传递 callback 参数。 ``` // src/middleware/jwt.middleware.ts import { Middleware } from '@midwayjs/core'; import { PassportMiddleware, AuthenticateOptions } from '@midwayjs/passport'; import { JwtStrategy } from '../strategy/jwt.strategy'; @Middleware() export class JwtPassportMiddleware extends PassportMiddleware(JwtStrategy) { getAuthenticateOptions(): Promise | AuthenticateOptions { return {}; } } ``` ``` import { Post, Inject, Controller } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { JwtService } from '@midwayjs/jwt'; import { JwtPassportMiddleware } from '../middleware/jwt.middleware'; @Controller('/') export class JwtController { @Inject() jwt: JwtService; @Inject() ctx: Context; @Post('/passport/jwt', { middleware: [JwtPassportMiddleware] }) async jwtPassport() { console.log('jwt user: ', this.ctx.state.user); return this.ctx.state.user; } @Post('/jwt') async genJwt() { return { t: await this.jwt.sign({ msg: 'Hello Midway' }), }; } } ``` 使用 curl 模拟请求 ``` curl -X POST http://127.0.0.1:7001/jwt 结果 {"t": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} curl http://127.0.0.1:7001/passport/jwt -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 结果 {"msg": "Hello Midway","iat": 1635468727,"exp": 1635468827} ``` ## 自定义其他策略[​](#自定义其他策略 "自定义其他策略的直接链接") `@midwayjs/passport` 支持自定义[其他策略](http://www.passportjs.org/packages/),这里以 Github OAuth 为例。 首先 `npm i passport-github`,之后编写如下代码: ``` // github-strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Strategy, StrategyOptions } from 'passport-github'; const GITHUB_CLIENT_ID = 'xxxxxx', GITHUB_CLIENT_SECRET = 'xxxxxxxx'; @CustomStrategy() export class GithubStrategy extends PassportStrategy(Strategy, 'github') { async validate(...payload) { return payload; } getStrategyOptions(): StrategyOptions { return { clientID: GITHUB_CLIENT_ID, clientSecret: GITHUB_CLIENT_SECRET, callbackURL: 'https://127.0.0.1:7001/auth/github/cb', }; } } ``` ``` // src/middleware/github.middleware.ts import { AuthenticateOptions, PassportMiddleware } from '@midwayjs/passport'; import { Middleware } from '@midwayjs/core'; import { GithubStrategy } from './githubStrategy'; @Middleware() export class GithubPassportMiddleware extends PassportMiddleware(GithubStrategy) { getAuthenticateOptions(): AuthenticateOptions | Promise { return {}; } } ``` ``` // src/controller/auth.controller.ts import { Controller, Get, Inject } from '@midwayjs/core'; import { GithubPassportMiddleware } from '../../middleware/github'; @Controller('/oauth') export class AuthController { @Inject() ctx; @Get('/github', { middleware: [GithubPassportMiddleware] }) async githubOAuth() {} @Get('/github/cb', { middleware: [GithubPassportMiddleware] }) async githubOAuthCallback() { return this.ctx.state.user; } } ``` ## 策略选项[​](#策略选项 "策略选项的直接链接") | 选项 | 类型 | 描述 | | ------------------- | ------- | ------------------------------------------------- | | failureRedirect | string | 失败跳转的 url | | session | boolean | 默认 true,开启后,会自动将用户信息设置到 session | | sessionUserProperty | string | 设置到 session 上的 key,默认 user | | userProperty | string | 设置到 ctx.state 或者 req 上的 key,默认 user | | successRedirect | string | 用户认证成功后跳转的地址 | ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Failed to serialize user into session[​](#1failed-to-serialize-user-into-session "1、Failed to serialize user into session的直接链接") 由于 passport 默认会尝试将 user 数据写入 session,如果无需将用户保存到 session,可以将 session 支持关闭。 ``` // src/config/config.default export default { // ... passport: { session: false, }, }; ``` 如果明确需要保存数据到 Session,则需要重写 `PassportStrategy`的 User 的序列化方法,请不要保存特别大的数据。 比如自己实现的本地策略。 ``` // src/strategy/local.strategy.ts import { CustomStrategy, PassportStrategy } from '@midwayjs/passport'; import { Repository } from 'typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { UserEntity } from './user'; import * as bcrypt from 'bcrypt'; @CustomStrategy() export class LocalStrategy extends PassportStrategy(Strategy) { // ... serializeUser(user, done) { // 可以只保存用户名 done(null, user.username); } deserializeUser(id, done) { // 这里不是异步方法,你可以从其他地方根据用户名,反查用户数据。 const user = getUserFromDataBase(id); done(null, user); } } ``` --- # 线程池 线程池组件 `@midwayjs/piscina` 基于 [Piscina](https://github.com/piscinajs/piscina) 提供在 Worker 线程池中执行任务的能力,适合 CPU 密集型计算,不会阻塞主线程。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装组件[​](#安装组件 "安装组件的直接链接") ``` $ npm i @midwayjs/piscina@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/piscina": "^4.0.0" } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 将组件配置到代码中。 ``` import { Configuration } from '@midwayjs/core'; import * as piscina from '@midwayjs/piscina'; @Configuration({ imports: [ piscina ], // ... }) export class MainConfiguration {} ``` ## 基础用法[​](#基础��用法 "基础用法的直接链接") 框架基于 [文档](/docs/service_factory.md) 提供了 `PiscinaService` 和 `PiscinaServiceFactory`。 你可以创建单个或者多个线程池对象来管理线程。 以下是 [Piscina](https://github.com/piscinajs/piscina) 的基础用法。 注入 `PiscinaService` 并调用 `run` 方法执行任务: ``` import { Inject, Provide } from '@midwayjs/core'; import * as piscina from '@midwayjs/piscina'; @Provide() export class UserService { @Inject() piscinaService: piscina.PiscinaService; async heavyTask() { // 调用 compute 函数 const result1 = await this.piscinaService.run({ handler: 'compute', payload: { value: 10 }, }); console.log(result1); // 20 // 调用 heavyComputation 函数 const result2 = await this.piscinaService.run({ handler: 'heavyComputation', payload: { data: [1, 2, 3, 4, 5] }, }); console.log(result2); // 15 } } ``` ## 使用 Midway 容器[​](#使用-midway-容器 "使用 Midway 容器的直接链接") 如果需要在 Worker 中使用 Midway 的依赖注入功能,我们需要在线程中单独在启动一个 Midway 环境。 ### 1. 创建线程中的环境[​](#1-创建线程中的环境 "1. 创建线程中的环境的直接链接") 你可以在主项目中单独创建一个目录用来保存线程代码,**必须** 使用 `defineConfiguration` 方法来创建入口。 目录结构如下: ``` ➜ base-app git:(feat/support_background_task) ✗ tree . ├── package.json └── src ├── configuration.ts ## 主项目入口 └── worker ## worker 目录 ├── index.ts └── task.ts ``` 我们可以在 Worker 目录中创建一个新 Midway 入口配置: ``` // src/worker/index.ts import { defineConfiguration } from '@midwayjs/core/functional'; import { CommonJSFileDetector } from '@midwayjs/core'; import * as piscina from '@midwayjs/piscina'; export default defineConfiguration({ namespace: 'worker', detector: new CommonJSFileDetector(), imports: [piscina], // 导入 Piscina }); ``` ### 2. 编写任务类[​](#2-编写任务类 "2. 编写任务类的直接链接") 和 Midway 其他组件类似,使用 `@PiscinaTask` 装饰器定义任务: ``` // src/worker/task.ts import { PiscinaTask, IPiscinaTask } from '@midwayjs/piscina'; @PiscinaTask('calculate') export class CalculateTask implements IPiscinaTask { async execute(payload: { a: number; b: number; operation: string }) { if (payload.operation === 'add') { return payload.a + payload.b; } else if (payload.operation === 'multiply') { return payload.a * payload.b; } throw new Error('Unknown operation'); } } @PiscinaTask('square') export class SquareTask implements IPiscinaTask { async execute(payload: { value: number }) { return payload.value * payload.value; } } ``` `@PiscinaTask` 装饰器的参数为一个字符串,代表堆外暴露的 handler 名称。 ### 3. 配置主应用[​](#3-配置主应用 "3. 配置主应用的直接链接") 在主应用配置中指定 Worker 目录: ``` // src/config/config.default.ts import { join } from 'path'; export default { piscina: { client: { // 指定 worker 入口文件 workerFile: join(__dirname, '../worker/index'), }, }, }; ``` 主应用需要忽略 Worker 目录,避免冲突: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import { CommonJSFileDetector } from '@midwayjs/core'; import * as piscina from '@midwayjs/piscina'; @Configuration({ imports: [piscina], detector: new CommonJSFileDetector({ ignore: ['**/worker/**'], // 忽略 worker 目录 }), }) export class MainConfiguration {} ``` ### 4. 执行容器任务[​](#4-执行容器任务 "4. 执行容器任务的直接链接") 使用 `runInContainer` 方法执行 Worker 容器中的任务: ``` @Provide() export class UserService { @Inject() piscinaService: piscina.PiscinaService; async heavyTask() { // 执行 calculate 任务 - 乘法 const result1 = await this.piscinaService.runInContainer('calculate', { a: 5, b: 6, operation: 'multiply', }); console.log(result1); // 30 // 执行 calculate 任务 - 加法 const result2 = await this.piscinaService.runInContainer('calculate', { a: 10, b: 20, operation: 'add', }); console.log(result2); // 30 // 执行 square 任务 const result3 = await this.piscinaService.runInContainer('square', { value: 7, }); console.log(result3); // 49 } } ``` ## 取消任务[​](#取消任务 "取消任务的直接链接") 使用 `AbortController` 可以取消正在运行的任务: ``` @Provide() export class UserService { @Inject() piscinaService: piscina.PiscinaService; async cancelableTask() { const abortController = new AbortController(); // 3 秒后取消任务 setTimeout(() => { abortController.abort(); }, 3000); try { const result = await this.piscinaService.run( { handler: 'longRunning', payload: { duration: 10000 }, // 10 秒的任务 }, { signal: abortController.signal, // 传递 AbortSignal } ); } catch (error) { console.error('任务被取消:', error); } } } ``` ## 多个 Worker Pool[​](#多个-worker-pool "多个 Worker Pool的直接链接") 可以配置多个 Worker Pool,每个 Pool 执行不同的任务: ``` // src/config/config.default.ts export default { piscina: { clients: { // 计算任务池 compute: { workerFile: join(__dirname, '../worker/compute.worker'), maxThreads: 4, }, // 图像处理任务池 image: { workerFile: join(__dirname, '../worker/image.worker'), maxThreads: 2, }, }, }, }; ``` 使用不同的 Pool: ``` @Provide() export class UserService { @Inject() piscinaServiceFactory: piscina.PiscinaServiceFactory; async useDifferentPools() { // 使用计算池 const computePool = this.piscinaServiceFactory.get('compute'); const result1 = await computePool.run({ handler: 'compute', payload: { value: 10 }, }); // 使用图像处理池 const imagePool = this.piscinaServiceFactory.get('image'); const result2 = await imagePool.run({ handler: 'process', payload: { imagePath: '/path/to/image.jpg' }, }); } } ``` ## 配置选项[​](#配置选项 "配置选项的直接链接") ### 常用配置[​](#常用配置 "常用配置的直接链接") [Piscina](https://github.com/piscinajs/piscina) 有非常丰富的线程配置。 ``` export default { piscina: { client: { workerFile: join(__dirname, '../worker/index'), minThreads: 1, // 最小线程数 maxThreads: 4, // 最大线程数 idleTimeout: 60000, // 空闲超时(毫秒) maxQueue: 'auto', // 最大队列长度 concurrentTasksPerWorker: 1, // 每个 Worker 的并发任务数 }, }, }; ``` ### 多 Pool 配置[​](#多-pool-配置 "多 Pool 配置的直接链接") ``` export default { piscina: { clients: { default: { workerFile: join(__dirname, '../worker/default.worker'), }, heavy: { workerFile: join(__dirname, '../worker/heavy.worker'), maxThreads: 8, idleTimeout: 30000, }, }, }, }; ``` ## Worker 文件路径说明[​](#worker-文件路径说明 "Worker 文件路径说明的直接链接") * 支持 `.ts` 和 `.js` 文件,框架会自动查找 * 建议使用不带扩展名的路径,框架按 `.js -> .ts -> .mjs -> .cjs` 顺序查找 * 生产环境编译后会自动找到对应的 `.js` 文件 ``` // 推荐:不带扩展名 workerFile: join(__dirname, '../worker/compute.worker') // 也可以:显式指定扩展名 workerFile: join(__dirname, '../worker/compute.worker.js') workerFile: join(__dirname, '../worker/compute.worker.ts') ``` ## API 参考[​](#api-参考 "API 参考的直接链接") ### PiscinaService[​](#piscinaservice "PiscinaService的直接链接") #### run(task, options?)[​](#runtask-options "run(task, options?)的直接链接") 执行普通 Worker 任务。 ``` await piscinaService.run( { handler: 'functionName', // Worker 文件中导出的函数名 payload: { /* 数据 */ }, // 传递给函数的参数 }, { signal: abortController.signal, // 可选:AbortSignal transferList: [], // 可选:可转移对象列表 } ); ``` #### runInContainer(handler, payload?, options?)[​](#runincontainerhandler-payload-options "runInContainer(handler, payload?, options?)的直接链接") 执行 Worker 容器中的 `@PiscinaTask` 任务。 ``` await piscinaService.runInContainer( 'taskName', // @PiscinaTask 装饰器的参数 { /* 数据 */ }, // 传递给 execute 方法的参数 { signal: abortController.signal, // 可选:AbortSignal } ); ``` ## 最佳实践[​](#最佳实践 "最佳实践的直接链接") ### 适用场景[​](#适用场景 "适用场景的直接链接") * CPU 密集型计算(数据处理、加密解密、图像处理) * 耗时较长的同步操作 * 需要避免阻塞主线程的场景 * 需要并行处理大量任务的场景 ### 选择合适的模式[​](#选择合适的模式 "选择合适的模式的直接链接") **普通 Worker 模式**: * 适合简单的纯函数计算 * 不需要依赖注入 * 性能开销更小 **Midway 容器模式**: * 需要使用依赖注入 * 需要在 Worker 中使用其他服务 * 适合复杂的业务逻辑 ### 注意事项[​](#注意事项 "注意事项的直接链接") 1. **数据传递**:传递给 Worker 的数据会被序列化,不支持函数、类实例等不可序列化对象 2. **线程数配置**:根据 CPU 核心数合理配置 `maxThreads`,避免过多线程导致上下文切换开销 3. **内存管理**:Worker 线程有独立的内存空间,注意避免内存泄漏 4. **错误处理**:Worker 中的错误会被捕获并传递回主线程,需要适当处理 5. **路径问题**:Worker 文件路径建议使用绝对路径(如 `join(__dirname, '../worker/xxx')`) ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 如何传递大量数据?[​](#如何传递大量�数据 "如何传递大量数据?的直接链接") 对于大型数据(如 ArrayBuffer、Buffer),使用 `transferList` 避免数据复制: ``` const buffer = new ArrayBuffer(1024 * 1024); await piscinaService.run( { handler: 'process', payload: buffer }, { transferList: [buffer] } ); ``` --- # pm2 [PM2](https://github.com/Unitech/pm2) 是带有内置负载平衡器的 Node.js 应用程序的生产过程管理器。可以利用它来简化很多 Node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 ## 安装[​](#安装 "安装的直接链接") 我们一般会把 pm2 安装到全局。 ``` $ npm install pm2 -g # 命令行安装 pm2 ``` ## 常用命令[​](#常用命令 "常用命令的直接链接") ``` $ pm2 start # 启动一个服务 $ pm2 list # 列出当前的服务 $ pm2 stop # 停止某个服务 $ pm2 restart # 重启某个服务 $ pm2 delete # 删除某个服务 $ pm2 logs # 查看服务的输出日志 ``` 比如, `pm2 list`,就会以表格显示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616560437389-b193a0d0-b463-49f1-a347-8dec20e7504d.png) pm2 的服务都有一个数组 id,你可以用 id 快速操作它。 比如: ``` $ pm2 stop 1 # 停止编号为 1 的服务 $ pm2 delete 1 # 删除编号为 1 的服务 ``` 使用 `--name` 参数添加一个应用名。 ``` $ pm2 start ./bootstrap.js --name test_app ``` 然后你可以用这个应用名来操作启停。 ``` $ pm2 stop test_app $ pm2 restart test_app ``` ## 启动应用[​](#启动应用 "启动应用的直接链接") Midway 应用一般使用 `npm run start` 做线上部署。其对应的命令为 `NODE_ENV=production node bootstrap.js`。 信息 部署前需要执行编译 npm run build 对应的 pm2 命令为 ``` $ NODE_ENV=production pm2 start ./bootstrap.js --name midway_app -i 4 ``` * \--name 用于指定应用名 * -i 用于指定启动的实例数(进程),会使用 cluster 模式启动 效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1616562075255-088155ee-7c4f-4eae-b5c5-db826f78b519.png) ## Docker 容器启动[​](#docker-容器启动 "Docker 容器启动的直接链接") 在 Docker 容器中,后台启动的代码都会被退出,达不到预期效果。pm2 使用另一个命令来支持容器启动。 请将命令修改为 pm2-runtime start 。 ``` $ NODE_ENV=production pm2-runtime start ./bootstrap.js --name midway_app -i 4 ``` 具体的 pm2 行为请参考 [pm2 容器部署说明](https://www.npmjs.com/package/pm2#container-support)。 --- # 进程 Agent midway 封装了 `@midwayjs/process-agent` 用来解决 node 场景中,多进程部分场景数据进程间数据不一致,或者无法指定 master 进程执行某个方法。 举例: * 如果使用 pm2、cluster、多进程进行部署方式,使用内存的 cache,那这个 cache 在自己的进程内。 * prometheus,获取 `/metrics` 的时候,需要把所有进程的数据收集上来,而不是某个进程的 * 健康检查,如果有4个进程,如果有一个进程不正常了,健康检查应该检查失败。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装方法[​](#安装方法 "安装方法的直接链接") 使用方法: ``` $ npm install @midwayjs/process-agent@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/process-agent": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") `configuration.ts` 使用方法: ``` import * as processAgent from '@midwayjs/process-agent'; @Configuration({ imports: [ // ... processAgent ], }) export class MainConfiguration { } ``` ## 使用方法[​](#使用方法 "使用方法的直接链接") 业务代码 UserService: ``` import { Provide, Inject } from '@midwayjs/core'; import { TestService } from './test'; @Provide() export class UserService { @Inject() testService: TestService; async getUser() { let result = await this.testService.setData(1); return result; } } ``` 然后调用 testService 的时候,希望只在主进程执行: ``` import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { RunInPrimary } from '@midwayjs/process-agent'; @Provide() @Scope(ScopeEnum.Singleton) export class TestService { data: any = 0; @RunInPrimary() async setData(b){ this.data = b; return this.data; } @RunInPrimary() async getData(){ return this.data; } } ``` 注意,执行返回的数据只限于可序列化的数据,比如普通 JSON,不支持包含方法等无法序列化的数据。 ## 效果描述[​](#效果描述 "效果描述的直接链接") 假设采用pm2 或者 egg-script 等多进程方式启动,假设这是个请求 首先: * 1、设置 setData * 2、然后获取 getData 如果没有 RunInPrimary 这个装饰器,那请求可能落在进程2,或者进程3,那可能没有获取更新的data。 所以 RunInPrimary 能确保这个函数执行能落到主进程去。 ## 功能征集[​](#功能征集 "功能征集的直接链接") 如果有其他类似相关功能,觉得可以放在这个包里面的,欢迎在评论区,或者 [issue](https://github.com/midwayjs/midway/issues) 里面帮忙提一下,我们会跟大家一起讨论和实现。 --- # Prometheus Prometheus(普罗米修斯)是一个最初在 SoundCloud 上构建的监控系统。 自 2012 年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus 于 2016 年加入云原生云计算基金会(CNCF),成为继 Kubernetes 之后的第二个托管项目。 Grafana 是一个开源的度量分析与可视化套件。纯 Javascript 开发的前端工具,通过访问库(如 InfluxDB),展示自定义报表、显示图表等。Grafana 支持许多不同的数据源。每个数据源都有一个特定的查询编辑器,该编辑器定制的特性和功能是公开的特定数据来源。而 Prometheus 正好是其支持的数据源之一。 本篇介绍了 Midway 如何接入 Grafana + Prometheus。 接入效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617259935548-a2df4339-3229-4391-bd3d-4ba8e6979d4d.png) ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 首先安装 Midway 提供的指标监控组件: ``` $ npm install @midwayjs/prometheus@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/prometheus": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `configuration.ts` 中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as prometheus from '@midwayjs/prometheus'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [ // ... prometheus ], importConfigs: [join(__dirname, 'config')], }) export class MainConfiguration {} ``` 启动我们的应用,此时访问的时候多了一个 `${host}:${port}/metrics` 。 信息 Prometheus 基于 HTTP 获取监控数据,请包含 web/koa/express 其中任一组件。 访问接口,返回如下,里面的内容是当前的指标。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260048533-4f725824-9471-40c9-be8b-6dcbf27d9cca.png) ## 其他配置[​](#其他配置 "其他配置的直接链接") 指标组件也提供了相关的配置,方便开发者进行配置。 可以在 `config.default.ts` 中,修改 prometheus 的配置。 ``` // src/config/config.default export default { // ... prometheus: { labels: { APP_NAME: 'demo_project', }, }, } ``` 更多的配置,我们可以查看定义进行配置。 通过配置,我们例如可以归类哪些 node 是同一个应用,因为我们部署的时候,node 程序是分布式的。例如上面我们加了 APP\_NAME,用来区分不同的应用,这样在监控指标中,我们可以区分不同的应用。 ## 数据采集[​](#数据采集 "数据采集的直接链接") 我们前面在 Midway 中引入的组件主要是在 Node 中加了指标模块。接下来我们需要让 Prometheus 来采集我们的指标数据。 如果开发者所在部门已经有 Prometheus+grafana 了,则只需将应用的指标地址上报给 PE 或者通过接口上报即可。此处我们假设大家没有 Prometheus+grafana,然后按照下面描述进行操作。 ## 搭建 Prometheus[​](#搭建-prometheus "搭建 Prometheus的直接链接") 此处我们通过 docker-compose 来搭建 Prometheus, docker-compose.yml 文件如下: ``` version: '2.2' services: tapi: logging: driver: 'json-file' options: max-size: '50m' image: prom/prometheus restart: always volumes: - ./prometheus_data:/prometheus_data:rw - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./targets.json:/etc/prometheus/targets.json command: - '--storage.tsdb.path=/prometheus_data' - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention=10d' - '--web.enable-lifecycle' ports: - '9090:9090' ``` `prometheus.yml` 文件如下: ``` global: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. scrape_configs: - job_name: 'node' file_sd_configs: - refresh_interval: 1m files: - '/etc/prometheus/targets.json' - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] ``` 然后采集的 `targets.json` 如下:下面文件里面 `${ip}` 替换为 Node.js 应用所在服务器的 ip 地址。 ``` [ { "targets": ["${ip}:7001"], "labels": { "env": "prod", "job": "api" } } ] ``` 然后我们启动 `docker-compose.yml` 文件, ``` $ docker-compose up ``` 至此,Prometheus 已经会去拉取我们 Node 应用程序的指标数据了。 如果想要更新 target 怎么做: 修改了这个 targets.json 文件后,通过 prometheus 的 reload 方法进行热加载。 方法如下: ``` $ curl -X POST http://${prometheus的ip}:9090/-/reload ``` 然后我们可以查看 prometheus 的页面也可以确认是否生效,界面地址: ``` http://${prometheus的ip}:9090/classic/targets ``` 接下来就是如何展示这些采集到的数据了。 ## 数据展示[​](#数据展示 "数据展示的直接链接") 我们可以借助 Grafana 来展示我们的数据。 此处我们简单通过 Docker 来搭建一下 Grafana: ``` $ docker run -d --name=grafana -p 3000:3000 grafana/grafana ``` 也可以将 grafana 和 prometheus 放在一起使用 docker-compose 统一管理。 将 grafana 添加到 `docker-compose.yml`, 示例如下: ``` version: '2.2' services: tapi: logging: driver: 'json-file' options: max-size: '50m' image: prom/prometheus restart: always volumes: - ./prometheus_data:/prometheus_data:rw # prometheus Data mapping directory - ./prometheus.yml:/etc/prometheus/prometheus.yml # prometheus Configuration mapping file - ./targets.json:/etc/prometheus/targets.json command: - '--storage.tsdb.path=/prometheus_data' - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention=10d' - '--web.enable-lifecycle' ports: - '9090:9090' grafana: image: grafana/grafana container_name: "grafana0" ports: - "3000:3000" restart: always volumes: - "./grafana_data:/var/lib/grafana" # grafana data mapping directory - "./grafana_log:/var/log/grafana" # grafana log mapping directory ``` 重启 `docker-compose.yml` 文件 ``` docker-compose restart ``` ![](https://cdn.nlark.com/yuque/0/2022/png/525744/1667300763153-5ee476a7-00ff-4899-92ba-5985995b4862.png) 完成以上任意一种, 然后我们访问 127.0.0.1:3000,默认账号密码:admin:admin。 访问后效果如下: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260561047-c2643a69-6258-491b-937d-9bfc4558252f.png) 然后我们让 Grafana 接入我们的 Prometheus 数据源: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1617260581029-1e2e06a8-3054-4ad8-96b5-d50ab9bb1612.png) 然后我们点击 Grafana 添加图表: ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725466020-28793a78-c03b-48fa-bf16-0c9c8ecc1a94.png) 这边 ID 选择 14403,然后点击 load,然后点击下一步,然后点击 import 后,就能看到我们刚刚接入的效果了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725497338-a32a8982-d51f-4e74-b511-dc10a7c66d80.png) ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1620725514630-4f654f10-ef3a-41f7-b403-02832d3ef7d8.png) 这样开发者可以运维自己的 Node 程序了,例如,是否最近引入了一个 NPM 包导致了什么内存泄漏的情况,是否最近有应用重启的情况了。 当然还能支持其他的自定义操作。 ## Socket-io 场景[​](#socket-io-场景 "Socket-io 场景的直接链接") 使用方法: ``` $ npm install @midwayjs/prometheus-socket-io@4 --save ``` 使用方法: ``` import { Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as prometheus from '@midwayjs/prometheus'; import * as prometheusSocketIo from '@midwayjs/prometheus-socket-io'; @Configuration({ imports: [prometheus, prometheusSocketIo], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration {} ``` 然后在/metrics 这边就能看到 socket-io 的数据了。 ![](https://cdn.nlark.com/yuque/0/2021/png/187105/1631090438583-d925c13c-371a-4037-9f53-edaa34580aab.png) 一共新增 8 个指标。 后续会提供 Grafana 的模版 ID 给大家使用。 ## 功能介绍[​](#功能介绍 "功能介绍的直接链接") * 根据 appName 进行分类 * 查看不同 path 的 qps 情况 * 查看不同 status 的分布情况 * 查询不同 path 的 rt 情况 * 进程的 CPU 使用情况 * 进程的内存使用情况 * 堆栈情况 * Event Loop * 等 --- # RabbitMQ 在复杂系统的架构中,会有负责处理消息队列的微服务,如下图:服务A负责产生消息给消息队列,而服务B则负责消费消息队列中的任务。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01SYMbCz1moVSVLl7S2_!!6000000005001-2-tps-646-251.png) 在Midway中,我们提供了订阅rabbitMQ的能力,专门来满足用户的这类需求。 相关信息: **订阅服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ❌ | ## 基础概念[​](#基础概念 "基础概念的直接链接") RabbitMQ 的概念较为复杂,其基于高级消息队列协议即 Advanced Message Queuing Protocol(AMQP),如果第一次接触请阅读一下相关的参考文档。 AMQP 有一些概念,Queue、Exchange 和 Binding 构成了 AMQP 协议的核心,包括: * Producer:消息生产者,即投递消息的程序。 * Broker:消息队列服务器实体。 * Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。 * Binding:绑定,它的作用就是把 Exchange 和 Queue 按照路由规则绑定起来。 * Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 * Consumer:消息消费者,即接受消息的程序。 简单的理解,消息通过 Publisher 发布到 Exchange(交换机),Consumer 通过订阅 Queue 来接受消息,Exchange 和 Queue 通过路由做连接。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01fLrucw1FVNbCx4NqG_!!6000000000492-2-tps-700-328.png) ## 消费者(Consumer)使用方法[​](#消费者consumer使用方法 "消费者(Consumer)使用��方法的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") Midway 提供了订阅 rabbitMQ 的能力,并能够独立部署和使用。安装 `@midwayjs/rabbitmq` 模块及其定义。 ``` $ npm i @midwayjs/rabbitmq@4 --save $ npm i amqplib --save $ npm i @types/amqplib --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/rabbitmq": "^4.0.0", "amqplib": "^0.10.1", // ... }, "devDependencies": { "@types/amqplib": "^0.8.2", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/rabbmitmq` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as rabbitmq from '@midwayjs/rabbitmq'; @Configuration({ imports: [ rabbitmq ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as rabbitmq from '@midwayjs/rabbitmq'; @Configuration({ imports: [ koa, rabbitmq ], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ### 目录结构[​](#目录结构 "目录结构的直接链接") 我们一般把能力分为生产者和消费者,而订阅正是消费者的能力。 我们一般把消费者放在 consumer 目录。比如 `src/consumer/userConsumer.ts` 。 ``` ➜ my_midway_app tree . ├── src │ ├── consumer │ │ └── user.consumer.ts │ ├── interface.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` 代码示例如下。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @Inject() ctx: Context; @RabbitMQListener('tasks') async gotData(msg: ConsumeMessage) { this.ctx.channel.ack(msg); } } ``` `@Consumer` 装饰器,提供消费者标识,并且它的参数,指定了某种消费框架的类型,比如,我们这里指定了 `MSListenerType.RABBITMQ` 这个类型,指的就是 rabbitMQ 类型。 标识了 `@Consumer` 的类,对方法使用 `@RabbitMQListener` 装饰器后,可以绑定一个 RabbitMQ 的队列(Queue)。 方法的参数为接收到的消息,类型为 `ConsumeMessage` 。如果返回值需要确认,则需要对服务端进行 `ack` 操作,明确接收到的数据。 如果需要订阅多个队列,可以使用多个方法,也可以使用多个文件。 ### RabbitMQ 消息上下文[​](#rabbitmq-消息上下文 "RabbitMQ 消息上下文的直接链接") 订阅 `RabbitMQ` 数据的上下文,和 Web 同样的,其中包含一个 `requestContext` ,和每次接收消息的数据绑定。 从 ctx 上可以取到 `channel` ,整个 ctx 的定义为: ``` export type Context = { channel: amqp.Channel; requestContext: IMidwayContainer; }; ``` 可以从框架获取定义 ``` import { Context } from '@midwayjs/rabbitmq'; ``` ### 配置消费者[​](#配置消费者 "配置消费者的直接链接") 我们需要在配置中指定 rabbitmq 的地址。 ``` // src/config/config.default import { MidwayConfig } from '@midwayjs/core'; export default { // ... rabbitmq: { url: 'amqp://localhost' } } as MidwayConfig; ``` 更多配置: | 属性 | 描述 | | ------------- | -------------------------------- | | url | rabbitMQ 的连接信息 | | socketOptions | amqplib.connect 的第二个参数 | | reconnectTime | 队列断连后的重试时间,默认 10 秒 | ### Fanout Exchange[​](#fanout-exchange "Fanout Exchange的直接链接") Fanout 是一种特定的交换机,如果满足匹配(binding),就往 Exchange 所绑定的 Queue 发送消息。Fanout Exchange 会忽略 RoutingKey 的设置,直接将 Message 广播到所有绑定的 Queue 中。 即所有订阅该交换机的 Queue 都会收到消息。 比如,下面我们添加了两个 Queue,订阅了相同的交换机。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/core'; import { Context, Application } from '@midwayjs/rabbitmq'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('abc', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, } }) async gotData(msg: ConsumeMessage) { this.logger.info('test output1 =>', msg.content.toString('utf8')); // TODO } @RabbitMQListener('bcd', { exchange: 'logs', exchangeOptions: { type: 'fanout', durable: false, }, exclusive: true, consumeOptions: { noAck: true, } }) async gotData2(msg: ConsumeMessage) { this.logger.info('test output2 =>', msg.content.toString('utf8')); // TODO } } ``` 订阅的 abc 和 bcd 队列,绑定了相同的交换机 logs,最终的结果是,两个方法都会被调用。 ### Direct Exchange[​](#direct-exchange "Direct Exchange的直接链接") Direct Exchange 是 RabbitMQ 默认的 Exchange,完全根据 RoutingKey 来路由消息。设置 Exchange 和 Queue 的 Binding 时需指定 RoutingKey(一般为 Queue Name),发消息时也指定一样的 RoutingKey,消息就会被路由到对应的Queue。 下面的示例代码,我们不填写 Queue Name,只添加一个 routingKey,交换机类型为 direct。 ``` import { Consumer, MSListenerType, RabbitMQListener, Inject, App } from '@midwayjs/core'; import { Context, Application } from '../../../../../src'; import { ConsumeMessage } from 'amqplib'; @Consumer(MSListenerType.RABBITMQ) export class UserConsumer { @App() app: Application; @Inject() ctx: Context; @Inject() logger; @RabbitMQListener('', { exchange: 'direct_logs', exchangeOptions: { type: 'direct', durable: false, }, routingKey: 'direct_key', exclusive: true, consumeOptions: { noAck: true, } }) async gotData(msg: ConsumeMessage) { // TODO } } ``` direct 类型的消息,会根据 routerKey 做定向过滤,所以只有特定订阅能收到消息。 ### 装饰器参数[​](#装饰器参数 "装饰器参数的直接链接") `@RabbitMQListener` 装饰器的第一个参数为 queueName,代表需要监听的队列。 第二个参数是一个对象,包含队列,交换机等参数,详细定义如下: ``` export interface RabbitMQListenerOptions { exchange?: string; /** * queue options */ exclusive?: boolean; durable?: boolean; autoDelete?: boolean; messageTtl?: number; expires?: number; deadLetterExchange?: string; deadLetterRoutingKey?: string; maxLength?: number; maxPriority?: number; pattern?: string; /** * prefetch */ prefetch?: number; /** * router */ routingKey?: string; /** * exchange options */ exchangeOptions?: { type?: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string; durable?: boolean; internal?: boolean; autoDelete?: boolean; alternateExchange?: string; arguments?: any; }; /** * consumeOptions */ consumeOptions?: { consumerTag?: string; noLocal?: boolean; noAck?: boolean; exclusive?: boolean; priority?: number; arguments?: any; }; } ``` ### 本地测试[​](#本地测试 "本地测试的直接链接") Midway 提供了一个简单的测试方法用于测试订阅某个数据。 `@midwayjs/mock` 工具提供了一个 `createRabbitMQProducer` 的方法,用于创建一个生产者,通过它,你可以创建一个队列(Queue),以及向这个队列发消息。 然后,我们启动一个 app,就可以自动监听到这个队列中的数据,并执行后续逻辑。 ``` import { createRabbitMQProducer, close, creatApp } from '@midwayjs/mock'; describe('/test/index.test.ts', () => { it('should test create message and get from app', async () => { // create a queue and channel const channel = await createRabbitMQProducer('tasks', { isConfirmChannel: true, mock: false, url: 'amqp://localhost', }); // send data to queue channel.sendToQueue('tasks', Buffer.from('something to do')) // create app and got data const app = await creatApp(); // wait a moment await close(app); }); }); ``` **示例一** 创建一个 fanout exchange。 ``` const manager = await createRabbitMQProducer('tasks-fanout', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'logs'; // Write a message const msg = "Hello World!"; // 声明交换机 manager.assertExchange(ex, 'fanout', { durable: false }) // 'fanout' will broadcast all messages to all the queues it knows // 启动服务 const app = await creatApp('base-app-fanout', { url: 'amqp://localhost', reconnectTime: 2000 }); // 发送到交换机,由于不持久化,需要等订阅服务起来之后再发 manager.sendToExchange(ex, '', Buffer.from(msg)) // 等一段时间 await sleep(5000); // 校验结果 // 关闭 producer await manager.close(); // 关闭 app await close(app); ``` **示例二** 创建一个 direct exchange。 ``` /** * direct 类型的消息,根据 routerKey 做定向过滤 */ const manager = await createRabbitMQProducer('tasks-direct', { isConfirmChannel: false, mock: false, url: 'amqp://localhost', }); // Name of the exchange const ex = 'direct_logs'; // Write a message const msg = "Hello World!"; // 声明交换机 manager.assertExchange(ex, 'direct', { durable: false }) // 'fanout' will broadcast all messages to all the queues it knows const app = await creatApp('base-app-direct', { url: 'amqp://localhost', reconnectTime: 2000 }); // 这里指定 routerKey,发送到交换机 manager.sendToExchange(ex, 'direct_key', Buffer.from(msg)) // 校验结果 await manager.close(); await close(app); ``` ## 生产者(Producer)使用方法[​](#生产者producer使用方法 "生产者(Producer)使用方法的直接链接") 生产者(Producer)也就是第一节中的消息产生者,简单的来说就是会创建一个客户端,将消息发送到 RabbitMQ 服务。 注意:当前 Midway 并没有使用组件来支持消息发送,这里展示的示例只是使用纯 SDK 在 Midway 中的写法。 ### 安装依赖[​](#安装依赖-1 "安装依赖的直接链接") ``` $ npm i amqplib amqp-connection-manager --save $ npm i @types/amqplib --save-dev ``` ### 调用服务发送消息[​](#调用服务发送消息 "调用服务发送消息的直接链接") 比如,我们在 service 文件下,新增一个 `rabbitmq.ts` 文件。 ``` import { Provide, Scope, ScopeEnum, Init, Autoload, Destroy } from '@midwayjs/core'; import * as amqp from 'amqp-connection-manager' @Autoload() @Provide() @Scope(ScopeEnum.Singleton) // Singleton 单例,全局唯一(进程级别) export class RabbitmqService { private connection: amqp.AmqpConnectionManager; private channelWrapper; @Init() async connect() { // 创建连接,你可以把配置放在 Config 中,然后注入进来 this.connection = await amqp.connect('amqp://localhost'); // 创建 channel this.channelWrapper = this.connection.createChannel({ json: true, setup: function(channel) { return Promise.all([ // 绑定队列 channel.assertQueue("tasks", { durable: true }), ]); } }); } // 发送消息 public async sendToQueue(queueName: string, data: any) { return this.channelWrapper.sendToQueue(queueName, data); } @Destroy() async close() { await this.channelWrapper.close(); await this.connection.close(); } } ``` 大概就是创建了一个用来封装消息通信的 service,同时他是全局唯一的 Singleton 单例。由于增加了 `@AutoLoad` 装饰器,可以自执行初始化。 这样基础的调用服务就抽象好了,我们只需要在用到的地方,调用 `sendToQueue` 方法即可。 比如: ``` @Provide() export class UserService { @Inject() rabbitmqService: RabbitmqService; async invoke() { // TODO // 发送消息 await this.rabbitmqService.sendToQueue('tasks', {hello: 'world'}); } } ``` ## 参考文档[​](#参考文档 "参考文档的直接链接") * [理解 RabbitMQ Exchange](https://zhuanlan.zhihu.com/p/37198933) * [RabbitMQ for Node.js in 30 steps](https://github.com/Gurenax/node-rabbitmq) --- # Redis 这里介绍如何快速在 Midway 中使用 Redis。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/redis` 是主要的功能包。 ``` $ npm i @midwayjs/redis@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/redis": "^4.0.0", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `src/configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as redis from '@midwayjs/redis'; import { join } from 'path'; @Configuration({ imports: [ // ... redis // 导入 redis 组件 ], importConfigs: [ join(__dirname, 'config') ], }) export class MainConfiguration { } ``` ## 配置 Redis[​](#配置-redis "配置 Redis的直接链接") **单客户端配置** ``` // src/config/config.default.ts export default { // ... redis: { client: { port: 6379, // Redis port host: "127.0.0.1", // Redis host password: "auth", db: 0, }, }, } ``` **Sentinel 配置** ``` // src/config/config.default.ts export default { // ... redis: { client: { sentinels: [{ // Sentinel instances port: 26379, // Sentinel port host: '127.0.0.1', // Sentinel host }], name: 'mymaster', // Master name password: 'auth', db: 0 }, }, } ``` **Cluster 模式配置,需要配置多个** ``` // src/config/config.default.ts export default { // ... redis: { // Cluster Redis client: { cluster: true, nodes: [{ host: 'host', port: 'port', },{ host: 'host', port: 'port', }], redisOptions: { family: '', password: 'xxxx', db: 'xxx' } } }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default.ts export default { // ... redis: { // Multi Redis clients: { instance1: { host: 'host', port: 'port', password: 'password', db: 'db', }, instance2: { host: 'host', port: 'port', password: 'password', db: 'db', }, }, }, } ``` 更多参数可以查看 [ioredis 文档](https://github.com/luin/ioredis/blob/master/API.md#new_Redis_new)。 ## 使用 Redis 服务[​](#使用-redis-服务 "使用 Redis 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { RedisService } from '@midwayjs/redis'; @Provide() export class UserService { @Inject() redisService: RedisService; async invoke() { // 简单设置 await this.redisService.set('foo', 'bar'); // 设置过期时间,单位秒 await this.redisService.set('foo', 'bar', 'EX', 10); // 获取数据 const result = await this.redisService.get('foo'); // result => bar } } ``` 可以使用 `RedisServiceFactory` 获取不同的实例。 ``` import { RedisServiceFactory } from '@midwayjs/redis'; import { join } from 'path'; @Provide() export class UserService { @Inject() redisServiceFactory: RedisServiceFactory; async save() { const redis1 = this.redisServiceFactory.get('instance1'); const redis2 = this.redisServiceFactory.get('instance3'); //... } } ``` 也可以通过装饰器获取。 ``` import { RedisServiceFactory, RedisService } from '@midwayjs/redis'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(RedisServiceFactory, 'instance1') redis1: RedisService; @InjectClient(RedisServiceFactory, 'instance3') redis2: RedisService; async save() { //... } } ``` ## 服务发现[​](#服务发现 "服务发现的直接链接") 提供基于统一抽象的服务发现能力,虽然 Redis 一般不作为服务发现的注册中心,但是其拥有 pub/sub 能力可以变相提供功能,我们仍实现了 Redis 将作为服务发现的客户端能力。 服务发现包括 **注册服务** 和 **获取服务** 两部分。 ### 配置服务发现[​](#配置服务发现 "配置服务发现的直接链接") 你需要先配置一个客户端;若存在多个客户端,可通过 `serviceDiscoveryClient` 指定用于服务发现的客户端。 通过 `serviceDiscovery` 配置服务发现选项: ``` // src/config/config.default.ts export default { redis: { clients: { default: { host: '127.0.0.1', port: 6379 } }, serviceDiscovery: { prefix: 'services:', ttl: 30, scanCount: 100 } } } ``` ### 注册服务发现[​](#注册服务发现 "注册服务发现的直接链接") 服务启动后,将当前服务注册到 Redis: ``` import { Configuration, Inject } from '@midwayjs/core'; import { RedisServiceDiscovery } from '@midwayjs/redis'; @Configuration({}) export class MainConfiguration { @Inject() redisDiscovery: RedisServiceDiscovery; async onServerReady() { const client = this.redisDiscovery.createClient(); await client.register({ serviceName: 'order', id: client.defaultMeta.id, host: client.defaultMeta.host, port: 7001, ttl: 30, meta: { version: '1.0.0' } }); // 注册默认上线,无需显式 online } } ``` 说明:上线时写入实例键并设置 TTL,客户端会定时刷新 TTL 保持存活;下线删除实例键并清理刷新;注销发布变更消息以便 Listener 全量刷新。 ### 获取可用服务[​](#获取可用服务 "获取可用服务的直接链接") 在任意位置获取可用实例或按负载均衡选择一个实例: ``` @Provide() export class OrderService { @Inject() redisDiscovery: RedisServiceDiscovery; async getService() { const instances = await this.redisDiscovery.getInstances('order'); const one = await this.redisDiscovery.getInstance('order'); return { instances, one }; } } ``` 返回的实例为注册时写入的对象,通常包含 `serviceName/id/host/port/ttl/meta/tags/status` 等字段。 --- # 模板渲染 本组件用于在 midway 体系使用服务端渲染 ejs,nunjucks 模板。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ❌ | ## 使用 ejs[​](#使用-ejs "使用 ejs的直接链接") ### 安装依赖[​](#安装依赖 "安装依赖的直接链接") 选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-ejs@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/view-ejs": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ### 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as view from '@midwayjs/view-ejs'; import { join } from 'path' @Configuration({ imports: [ view // 导入 ejs 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ### 配置[​](#配置 "配置的直接链接") 配置后缀,映射到指定的引擎。 ``` // src/config/config.default.ts export default { // ... view: { mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` ### 使用[​](#使用 "使用的直接链接") 注意,默认的 view 目录为 `${appDir}/view` ,在其中创建一个 `hello.ejs` 文件。 目录结构如下: ``` ➜ my_midway_app tree . ├── src │ └── controller ## Controller 目录 │ └── home.ts ├── view ## 模板目录 │ └── hello.ejs ├── test ├── package.json └── tsconfig.json ``` 我们在模板里写一些 ejs 格式的内容,比如: ``` // view/hello.ejs hello <%= data %> ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await this.ctx.render('hello.ejs', { data: 'world', }); } } ``` ### 配置后缀[​](#配置后缀 "配置后缀的直接链接") 默认后缀为 `.html` ,为了改成习惯的 `.ejs` 后缀,我们可以加一个 `defaultExtension` 配置。 ``` // src/config/config.default.ts export default { // ... view: { defaultExtension: '.ejs', mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` 这样我们在渲染时不需要增加后缀。 ``` @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await this.ctx.render('hello', { data: 'world', }); } } ``` ### 默认渲染引擎[​](#默认渲染引擎 "默认渲染引擎的直接链接") 我们可以通过 `defaultViewEngine` 来设置默认的渲染引擎。 其作用是,当遇到的模板后缀,比如 `.html` 未在配置的 `mapping` 字段中找到时,使用该 `defaultViewEngine` 字段指定的引擎来渲染。 ``` // src/config/config.default.ts export default { // ... view: { defaultViewEngine: 'ejs', mapping: { '.ejs': 'ejs', }, }, // ejs config ejs: {} } ``` 这样,如果模板是 `.html` 后缀,由于 `mapping` 中未指定,依旧会使用 `ejs` 来渲染。 ### 配置多个模板目录[​](#配置多个模板目录 "配置多个模板目录的直接链接") 如果我们需要将代码封装为组件提供,就需要支持不同的模板目录。 默认的模板目录在 `${appDir}/view`。我们可以在 `rootDir` 字段增加其他的目录。 ``` // src/config/config.default.ts // 修改默认 view 组件的 default 目录 export default { // ... view: { rootDir: { default: path.join(__dirname, './view'), } }, } // 其他组件需要增加目录的配置 export default { // ... // view 组件的配置 view: { rootDir: { anotherRoot: path.join(__dirname, './view'), } }, } ``` 通过对象合并的机制,使得所有的 `rootDir` 都能合并到一起,组件内部会获取 values 做匹配。 ## 使用 Nunjucks[​](#使用-nunjucks "使用 Nunjucks的直接链接") 和 ejs 类似,引入对应组件即可。 1、选择对应的模板安装依赖。 ``` $ npm i @midwayjs/view-nunjucks@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/view-nunjucks": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` 2、引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path' @Configuration({ imports: [ view // 导入 nunjucks 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` 3、增加 nunjucks 的配置,比如默认使用 nunjucks。 ``` export default { // ... view: { defaultViewEngine: 'nunjucks', mapping: { '.nj': 'nunjucks', }, }, } ``` 4、在 view 目录增加模板 ``` // view/test.nj hi, {{ user }} ``` 在 Controller 中渲染。 ``` import { Inject, Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async render(){ await ctx.render('test.nj', { user: 'midway' }); } } ``` 访问后会输出 `hi, midway` 。 如果有自定义 filter 的需求,可以在入口处增加,比如下面增加了一个名为 `hello` 的 filter。 ``` import { App, Configuration, Inject } from '@midwayjs/core'; import * as view from '@midwayjs/view-nunjucks'; import { join } from 'path' @Configuration({ imports: [view], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { @App() app; @Inject() env: view.NunjucksEnvironment; async onReady(){ this.env.addFilter('hello', (str) => { return 'hi, ' + str; }); } } ``` 在模板里可以使用 ``` {{ name | hello }} ``` 然后渲染 ``` // controller // ... await ctx.render('test.nj', { name: 'midway' }); ``` 也会输出 `hi, midway` 。 ## 自定义模板引擎[​](#自定义模板引擎 "自定义模板引擎的直接链接") 默认我们只提供了 ejs 和 nunjucks 的模板引擎,你也可以编写自己的模板引擎代码。 ### 实现模板引擎[​](#实现模板引擎 "实现模板引擎的直接链接") 首先需要创建一个请求作用域的模板引擎类,它将在每个请求执行时初始化。你需需要实现其中的 `render` 和 `renderString` 方法。如果你的模板引擎不支持某个方法,可以抛出异常。 ``` // lib/view.ts import { Provide, Config } from '@midwayjs/core'; import { IViewEngine } from '@midwayjs/view'; @Provide() export class MyView implements IViewEngine { @Config('xxxx') viewConfig; async render(name: string, locals?: Record, options?: RenderOptions) { return myengine.render(name, locals, options); } async renderString(tpl: string, locals?: Record, options?: RenderOptions) { throw new Error('not implement'); } }; ``` 这两个方法接受类似的三个参数,`renderString` 第一个参数需要传入待解析的模板内容本身,而 `render` 方法会解析模板文件。 `render(name, locals, viewOptions)` * name: 从 `root`(默认是 `/view` ) 相对的 path * locals: 模板需要的数据 * viewOptions: 每次渲染的模板参数,可覆盖的配置,可以在配置文件中重写,其中包含几个参数: * root: 模板的绝对路径 * name: 调用 render 方法的原始 name 值 * locals: 调用 render 方法的原始 locals 值 `renderString(tpl, locals, viewOptions)` * tpl: 模板名 * locals: 和 `render` 一样 * viewOptions: 和 `render` 一样 ### 注册模板引擎[​](#注册模板引擎 "注册模板引擎的直接链接") 在实现自定义的模板引擎后,我们需要在启动入口注册它。 通过引入 `ViewManager` ,我们可以使用 `use` 方法注册自定义模板引擎。 ``` // src/configuration.ts import { Configuration, Inject, Provide } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as view from '@midwayjs/view'; import { MyView } from './lib/my'; @Configuration({ imports: [koa, view], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { @Inject() viewManager: view.ViewManager; async onReady(){ this.viewManager.use('ejs', MyView); } } ``` ## 注意事项[​](#注意事项 "注意事项的直接链接") 如需在 egg(@midwayjs/web) 场景下使用,请在 `plugin.ts` 中关闭 view 和其相关插件。 ``` import { EggPlugin } from 'egg'; export default { // ... view: false, } as EggPlugin; ``` 否则会出现下面类似的错误。 ``` TypeError: Cannot set property view of # which has only a getter ``` --- # 安全 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用安全组件,支持 `csrf` 、`xss` 等多种安全策略。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ## 安装使用[​](#安装使用 "安装使用的直接链接") 1、安装依赖 ``` $ npm i @midwayjs/security --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/security": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` 2、在 configuration 中引入组件 ``` import * as security from '@midwayjs/security'; @Configuration({ imports: [ // ...other components security ], }) export class MainConfiguration {} ``` *** ## 防范常见的安全威胁[​](#防范常见的安全威胁 "防范常见的安全威胁的直接链接") ### 一、CSRF[​](#一csrf "一、CSRF的直接链接") CSRF(Cross-site request forgery 跨站请求伪造),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。 #### 1. 令牌同步模式[​](#1-令牌同步模式 "1. 令牌同步模式的直接链接") 通过响应页面时将 token 渲染到页面上,在开启 `csrf` 配置后,通过 `ctx.csrf` 可以获取到 `csrf token`,可以再返回页面 html 时同步输出 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { return `
title:
`; } } ``` 传递 CSRF token 的字段(上述示例中的 `_csrf`)可以在配置中改变,请查看下述 `配置 -> csrf`。 #### 2. Cookies 模式[​](#2-cookies-模式 "2. Cookies 模式的直接链接") 在 CSRF 默认配置下,token 会被设置在 Cookie 中,可以再前端页面中通过 JS 从 Cookies 中获取,然后再 ajax/fetch 等请求中添加到 `header`、`query` 或 `body` 中。 ``` const csrftoken = Cookies.get('csrfToken'); fetch('/api/post', { method: 'POST', headers: { 'x-csrf-token': csrftoken }, ... }); ``` 默认配置下,框架会将 `CSRF token` 存在 `Cookie` 中,以方便前端 JS 发起请求时获取到。但是所有的子域名都可以设置 Cookie,因此当我们的应用处于无法保证所有的子域名都受控的情况下,存放在 `Cookie` 中可能有被 `CSRF` 攻击的风险。框架提供了一个配置项 `useSession`,可以将 token 存放到 Session 中。 当 `CSRF token` 存储在 `Cookie` 中时,一旦在同一个浏览器上发生用户切换,新登陆的用户将会依旧使用旧的 token(之前用户使用的),这会带来一定的安全风险,因此在每次用户登陆的时候都必须调用 `ctx.rotateCsrfSecret()` 刷新 `CSRF token`,例如: ``` @Controller('/') export class HomeController { @Inject() ctx; @Inject() userService; @Get('/login') async login(@Body('username') username: string, @Body('password') password: string) { const user = await userService.login({ username, password }); this.ctx.session = { user }; this.ctx.rotateCsrfSecret(); return { success: true }; } } ``` ### 二、XSS[​](#二xss "二、XSS的直接链接") `XSS`(cross-site scripting 跨站脚本攻击)攻击是最常见的 Web 攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。 `XSS` 攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。 #### 1. 反射型的 XSS 攻击[​](#1-反射型的-xss-攻击 "1. 反射型的 XSS 攻击的直接链接") 主要是由于服务端接收到客户端的不安全输入,在客户端触发代码执行从而发起 `Web` 攻击。 例如:在某搜索网站搜索时,搜索结果会显示搜索的关键词。搜索关键词填入 ``, 点击搜索后,若页面程序没有对关键词进行处理,这段代码就会直接在页面上执行,弹出 alert。 框架提供了 `ctx.security.escape()` 方法对字符串进行 XSS 过滤。 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { const str = ``; const escapedStr = this.ctx.security.escape(str); // <script>alert("xss") </script> return escapedStr; } } ``` 另外当网站输出的内容是作为 js 脚本的。这个时候需要使用 `ctx.security.js()` 来进行过滤。 还有一种情况,有时候我们需要在 `js` 中输出 `json` ,若未做转义,易被利用为 `XSS` 漏洞。框架提供了 `ctx.security.json(变量)` 来提供 json encode,防止 XSS 攻击。 ``` @Controller('/') export class HomeController { @Inject() ctx; @Get('/home') async home() { return ``; } } ``` #### 2. 存储型的 XSS 攻击[​](#2-存储型的-xss-攻击 "2. 存储型的 XSS 攻击的直接链接") 通过提交带有恶意脚本的内容存储在服务器上,当其他人看到这些内容时发起 Web 攻击,比如一些网站的评论框中,用户恶意将一些代码作为评论内容,若没有过滤,其他用户看到这个评论时恶意代码就会执行。 框架提供了 `ctx.security.html()` 来进行过滤。 #### 3. 其他 XSS 的防范方式[​](#3-其他-xss-的防范方式 "3. 其他 XSS 的防范方式的直接链接") 浏览器自身具有一定针对各种攻击的防范能力,他们一般是通过开启 Web 安全头生效的。框架内置了一些常见的 Web 安全头的支持。 **CSP** `Content Security Policy`,简称 `CSP`,主要是用来定义页面可以加载哪些资源,减少 `XSS` 的发生。 默认关闭(可通过 `csp: {enable: true}` 配置开启),开启后可以有效的防止 `XSS` 攻击的发生。要配置 `CSP` , 需要对 `CSP` 的 `policy` 策略有了解,具体细节可以参考 [阿里聚安全 - CSP是什么?](https://www.zhihu.com/question/21979782/answer/122682029) **X-Download-Options:noopen** 默认开启(可通过 `noopen: {enable: false}` 配置关闭),禁用 IE 下下载框 Open 按钮,防止 IE 下下载文件默认被打开 XSS。 **X-Content-Type-Options:nosniff** 禁用 IE8 自动嗅探 mime 功能,默认关闭(可通过 `nosniff: {enable: true}` 配置开启),例如 text/plain 却当成 text/html 渲染,特别当本站点 serve 的内容未必可信的时候。 **X-XSS-Protection** IE 提供的一些 XSS 检测与防范,默认开启(可通过 `xssProtection: {enable: false}` 配置关闭) close 默认值 false,即设置为 1; mode=block *** ## 配置[​](#配置 "配置的直接链接") 默认配置如下: ``` // src/config/config.default export default { // ... // 默认配置 security: { csrf: { enable: true, type: 'ctoken', useSession: false, cookieName: 'csrfToken', sessionName: 'csrfToken', headerName: 'x-csrf-token', bodyName: '_csrf', queryName: '_csrf', refererWhiteList: [], }, xframe: { enable: true, value: 'SAMEORIGIN', }, csp: { enable: false, }, hsts: { enable: false, maxAge: 365 * 24 * 3600, includeSubdomains: false, }, noopen: { enable: false, }, nosniff: { enable: false, }, xssProtection: { enable: true, value: '1; mode=block', }, }, } ``` ### csrf[​](#csrf "csrf的直接链接") | 配置项 | 类型 | 作用描述 | 默认值 | | ---------------- | ------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------------------- | | enable | boolean | 是否开启 | true | | type | 'all' / 'any' / 'ctoken' / 'referer' | csrf 校验类型,all/any 等于 ctoken + referer | 'ctoken' 从query/header/body 中获取 csrf token;;'referer' 则可以通过 refererWhiteList 配置白名单 | | useSession | boolean | csrf token 是否存放在 session 中 | false,默认存放在 cookies 中 | | cookieName | string | token 在 cookie 中存放的 字段 | 'csrfToken' | | sessionName | string | token 在 session 中存放的 字段 | 'csrfToken' | | headerName | string | token 在 header 中存放的 字段 | 'x-csrf-token' | | bodyName | string | token 在 body 中存放的 字段 | '\_csrf' | | queryName | string | token 在 query 中存放的 字段 | '\_csrf' | | refererWhiteList | Array\ | 允许的来源白名单 | \[] | #### 配置 refererWhiteList 不生效?[​](#配置-refererwhitelist-不生效 "配置 refererWhiteList 不生效?的直接链接") * 原因一:refererWhiteList 中需要配置 referer 的 host 部分,例如 referer 为 `https://midway-demo.com:1234/docs`,则 refererWhiteList 中需要配置 `midway-demo.com:1234`。 * 原因二:refererWhiteList 仅在 csrf 配置中 type 为 `referer` 的情况下生效,默认 type 为 `ctoken`,需要修改为 `referer`。 * 原因三:发送的http请求中的 referer 字段不是一个标准的 url 地址(例如没有加上请求协议等),参考 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer) 文档 ### xframe[​](#xframe "xframe的直接链接") xframe 用来配置 `X-Frame-Options` 响应头,用来给浏览器指示允许一个页面可否在 `frame`, `iframe`, `embed` 或者 `object` 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免 `clickjacking` 攻击。 `X-Frame-Options` 有三个可能的值: * X-Frame-Options: deny:页面不允许在 frame 中展示 * X-Frame-Options: sameorigin:该页面可以在相同域名页面的 frame 中展示 * X-Frame-Options: allow-from [https://example.com/:该页面可以在指定来源的](https://example.com/%EF%BC%9A%E8%AF%A5%E9%A1%B5%E9%9D%A2%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%9D%A5%E6%BA%90%E7%9A%84) frame 中展示 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | ------------------ | ------------ | | enable | boolean | 是否开启 | true | | value | string | X-Frame-Options 值 | 'SAMEORIGIN' | ### hsts[​](#hsts "hsts的直接链接") `HTTP Strict Transport Security`(通常简称为 `HSTS` )是一个安全功能,它告诉浏览器只能通过 `HTTPS` 访问当前资源,而不是 `HTTP`。 | 配置项 | 类型 | 作用描述 | 默认值 | | ----------------- | ------- | ------------------------------------------------------------------------------- | ------------------------ | | enable | boolean | 是否开启 | false | | maxAge | number | 在浏览器收到这个请求后的多少 `秒` 时间内凡是访问这个域名下的请求都使用HTTPS请求 | `365 * 24 * 3600` 即一年 | | includeSubdomains | boolean | 此规则是否适用于该网站的所有子域名 | false | ### csp[​](#csp "csp的直接链接") HTTP 响应头 `Content-Security-Policy` 允许站点管理者控制指定的页面加载哪些资源。这将帮助防止跨站脚本攻击(XSS)。 | 配置项 | 类型 | 作用描述 | 默认值 | | ---------- | --------------------------------------------------------- | ---------------- | ------ | | enable | boolean | 是否开启 | false | | policy | Object\ | 策略列表 | | | reportOnly | boolean | 是否开启 | false | | supportIE | boolean | 是否支持IE浏览器 | false | 详细的 `policy` 配置可以参考: [Content Security Policy (CSP) 是什么?阿里聚安全](https://www.zhihu.com/question/21979782/answer/122682029) ### noopen[​](#noopen "noopen的直接链接") 用于指定 `IE 8` 以上版本的用户不打开文件而直接保存文件。在下载对话框中不显式“打开”选项。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | -------- | ------ | | enable | boolean | 是否开启 | false | ### nosniff[​](#nosniff "nosniff的直接链接") 开启后,如果从 `script` 或 `stylesheet` 读入的文件的 `MIME` 类型与指定 `MIME` 类型不匹配,不允许读取该文件。用于防止 `XSS` 等跨站脚本攻击。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | -------- | ------ | | enable | boolean | 是否开启 | false | ### xssProtection[​](#xssprotection "xssProtection的直接链接") 用于启用浏览器的XSS过滤功能,以防止 `XSS` 跨站脚本攻击。 `X-XSS-Protection` 响应头是 `IE`,`Chrome` 和 `Safari` 的一个特性,当检测到跨站脚本攻击 (XSS (en-US))时,浏览器将停止加载页面。若网站设置了良好的 `Content-Security-Policy` 来禁用内联 JavaScript ('unsafe-inline'),现代浏览器不太需要这些保护, 但其仍然可以为尚不支持 `CSP` 的旧版浏览器的用户提供保护。 `X-XSS-Protection` 可以配置下述四个值 * `0`: 禁止XSS过滤。 * `1`:启用XSS过滤(通常浏览器是默认的)。 如果检测到跨站脚本攻击,浏览器将清除页面(删除不安全的部分)。 * `1;mode=block`:启用XSS过滤。 如果检测到攻击,浏览器将不会清除页面,而是阻止页面加载。 * `1; report=`: Chromium only,启用XSS过滤。 如果检测到跨站脚本攻击,浏览器将清除页面并使用CSP report-uri (en-US)指令的功能发送违规报告。 | 配置项 | 类型 | 作用描述 | 默认值 | | ------ | ------- | --------------------- | --------------- | | enable | boolean | 是否开启 | false | | value | string | X-XSS-Protection 配置 | `1; mode=block` | --- # Sequelize 本文档介绍如何在 Midway 中使用 Sequelize。 提示 当前模块从 v3.4.0 开始已经重构,历史写法兼容,如果查询历史文档,请参考 [这里](/docs/legacy/sequelize.md)。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 和老写法的区别[​](#和老写法的区别 "和老写法的区别的直接链接") 如果想使用新版本的用法,请参考下面的流程,将老代码进行修改,新老代码不能混用。 升级方法: * 1、请在业务依赖中显式添加 `sequelize` 和 `sequelize-typescript` * 2、不再使用 `BaseTable` 装饰器,而直接使用 `sequelize-typescript` 包导出的 `Table` 装饰器 * 3、在 `src/config.default` 的 `sequelize` 部分配置调整,参考下面的数据源配置部分 * 3.1 修改为数据源的形式 `sequelize.dataSource` * 3.2 将实体模型在数据源的 `entities` 字段中声明 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/sequelize@4 sequelize sequelize-typescript --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/sequelize": "^4.0.0", "sequelize": "^6.21.3", "sequelize-typescript": "^2.1.0" // ... }, "devDependencies": { // ... } } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 下面的文档,我们将以 `mysql2` 作为示例。 ### Directory structure[​](#directory-structure "Directory structure的直接链接") 一个基础的参考目录结构如下。 ``` MyProject ├── src │ ├── config │ │ └── config.default.ts │ ├── entity │ │ └── person.entity.ts │ ├── configuration.ts │ └── service ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 在 `src/configuration.ts` 文件中启用组件。 ``` import { Configuration, ILifeCycle } from '@midwayjs/core'; import { join } from 'path'; import * as sequelize from '@midwayjs/sequelize'; @Configuration({ imports: [ // ... sequelize, ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle { // ... } ``` ## 模型定义[​](#模型定义 "模型定义的直接链接") ### 1、创建 Model(Entity)[​](#1创建-modelentity "1、创建 Model(Entity)的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 Sequelize 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `person` 举例。新建 entity 目录,在其中添加实体文件 `person.entity.ts` ,一个简单的实体如下。 ``` // src/entity/person.entity.ts import { Table, Model, Column, HasMany } from 'sequelize-typescript'; @Table export class Hobby extends Model { @Column name: string; } @Table export class Person extends Model { @Column name: string; @Column birthday: Date; @HasMany(() => Hobby) hobbies: Hobby[]; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 `@Table` 装饰器可以在不传递任何参数的情况下使用,更多参数请查看 [定义选项](https://sequelize.org/v5/manual/models-definition.html#configuration) 。 ``` @Table({ timestamps: true, ... }) export class Person extends Model {} ``` ### 2、主键[​](#2主键 "2、主键的直接链接") 主键 (id) 将从基类 Model 继承。 一般来说主键是 Integer 类型并且是自增的。 主键设置有两种方法,设置 `@Column({primaryKey: true})` 或者 `@PrimaryKey`。 比如: ``` import { Table, Model, PrimaryKey } from 'sequelize-typescript'; @Table export class Person extends Model { @PrimaryKey name: string; } ``` ### 3、时间列[​](#3时间列 "3、时间列的直接链接") 主要指代的是 `@CreatedAt`, `@UpdatedAt`, `@DeletedAt` 单个装饰器标注的列。 比如: ``` import { Table, Model, CreatedAt, UpdatedAt, DeletedAt } from 'sequelize-typescript'; @Table export class Person extends Model { @CreatedAt creationDate: Date; @UpdatedAt updatedOn: Date; @DeletedAt deletionDate: Date; } ``` | 装饰器 | 描述 | | ------------ | ----------------------------------------------------------------------- | | `@CreatedAt` | 会设置 `timestamps=true` 和 `createdAt='creationDate'` | | `@UpdatedAt` | 会设置 `timestamps=true` 和 `updatedAt='updatedOn'` | | `@DeletedAt` | 会设置 `timestamps=true`, `paranoid=true` 和 `deletedAt='deletionDate'` | ### 4、普通列[​](#4普通列 "4、普通列的直接链接") @Column 装饰器用于标注普通列,可以在不传递任何参数的情况下使用。 但是因此需要能够自动推断 js 类型(详见[类型推断](https://github.com/sequelize/sequelize-typescript#type-inference))。 ``` import { Table, Model, Column } from 'sequelize-typescript'; @Table export class Person extends Model { @Column name: string; } ``` 或者指定列类型。 ``` import { Table, Column, DataType } from 'sequelize-typescript'; @Table export class Person extends Model { @Column(DataType.TEXT) name: string; } ``` 更多类型描述,请参考 [这里](https://sequelize.org/v5/manual/models-definition.html#configuration)。 比如: ``` import { Table, Model, Column, DataType } from 'sequelize-typescript' @Table export class Person extends Model { @Column({ type: DataType.FLOAT, comment: 'Some value', ... }) value: number; } ``` | 装饰器 | 描述 | | ------------------------------------ | ------------------------------------------------------------------------------------------------- | | `@Column` | 使用推导的 [dataType](https://sequelize.org/v5/manual/models-definition.html#data-types) 作为类型 | | `@Column(dataType: DataType)` | 显式设置 [dataType](https://sequelize.org/v5/manual/models-definition.html#data-types) | | `@Column(options: AttributeOptions)` | 设置 [attribute options](https://sequelize.org/v5/manual/models-definition.html#configuration) | ## 数据源配置[​](#数据源配置 "数据源配置的直接链接") 新版本我们启用了 [数据源机制](/docs/data_source.md),在 `src/config.default.ts` 中配置: ``` // src/config/config.default.ts import { Person } from '../entity/person.entity'; export default { // ... sequelize: { dataSource: { // 第一个数据源,数据源的名字可以完全自定义 default: { database: 'test4', username: 'root', password: '123456', host: '127.0.0.1', port: 3306, encrypt: false, dialect: 'mysql', define: { charset: 'utf8' }, timezone: '+08:00', // 本地的时候,可以通过 sync: true 直接 createTable sync: false, // 实体形式 entities: [Person], // 支持如下的扫描形式,为了兼容我们可以同时进行.js和.ts匹配️ entities: [ 'entity', // 指定目录 '**/entity/*.entity.{j,t}s', // 通配加后缀匹配 ], }, // 第二个数据源 default2: { // ... }, }, }, }; ``` ## 模型关联[​](#模型关联 "模型关联的直接链接") 可以通过 `HasMany` 、`@HasOne` 、`@BelongsTo`、`@BelongsToMany` 和 `@ForeignKey` 装饰器在模型中直接描述关系。 提示 你不需要在数据库中创建外键也可以使用这个功能。 ### 一对多[​](#一对多 "一对多的直接链接") ``` import { Table, Model, Column, ForeignKey, BelongsTo, HasMany } from 'sequelize-typescript'; @Table export class Player extends Model { @Column name: string; @Column num: number; @ForeignKey(() => Team) @Column teamId: number; @BelongsTo(() => Team) team: Team; } @Table export class Team extends Model { @Column name: string; @HasMany(() => Player) players: Player[]; } ``` `sequelize-typescript` 会在内部进行关联,会自动查询出相关的依赖。 比如通过 `find` 查询。 ``` const team = await Team.findOne({ include: [Player] }); team.players.forEach((player) => { console.log(`Player ${player.name}`); }); ``` ### 多对多[​](#多对多 "多�对多的直接链接") ``` import { Table, Model, Column, ForeignKey, BelongsToMany } from 'sequelize-typescript'; @Table export class Book extends Model { @BelongsToMany(() => Author, () => BookAuthor) authors: Author[]; } @Table export class Author extends Model { @BelongsToMany(() => Book, () => BookAuthor) books: Book[]; } @Table export class BookAuthor extends Model { @ForeignKey(() => Book) @Column bookId: number; @ForeignKey(() => Author) @Column authorId: number; } ``` 上面的类型,在某些场景下是不安全的,比如上面的 `BookAuthor`,`Author` 的 `books` 的类型,可能会丢失某些属性,需要手动设置。 ``` @BelongsToMany(() => Book, () => BookAuthor) books: Array; ``` ### 一对一[​](#一对一 "一对一的直接链接") 对于一对一,使用 `@HasOne(...)`(关系的外键存在于另一个模型上)和 `@BelongsTo(...)`(关系的外键存在于此模型上)。 比如: ``` import { Table, Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { User } from './user.entity'; @Table export class Photo extends Model { @ForeignKey(() => User) @Column({ comment: '用户Id', }) userId: number; @BelongsTo(() => User) user: User; @Column({ comment: '名字', }) name: string; } @Table export class User extends Model { @Column name: string; } ``` ### 模型循环依赖[​](#模型循环依赖 "模型循环依赖的直接链接") 如果你使用了 `@BelongsTo` 装饰器,很容易触发一个模型循环依赖的错误,比如: ``` ReferenceError: Cannot access 'Photo' before initialization ``` 你可以将类型使用 `ReturnType` 包裹起来。 ``` import { Table, Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { User } from './user.entity'; @Table export class Photo extends Model { // ... @BelongsTo(() => User) user: ReturnType<() => User>; } ``` ## 静态操作方法[​](#静态操作方法 "静态操作方法的直接链接") 如果是单个数据源,可以使用下面的静态方法。 ### 保存[​](#保存 "保存的直接链接") 在需要调用的地方,使用实体模型来操作。 ``` import { Provide } from '@midwayjs/core'; import { Person } from '../entity/person.entity'; @Provide() export class PersonService { async createPerson() { const person = new Person({ name: 'bob', age: 99 }); await person.save(); } } ``` ### 查找和更新[​](#查找和更新 "查找和更新的直接链接") ``` import { Provide } from '@midwayjs/core'; import { Person } from '../entity/person.entity'; @Provide() export class PersonService { async updatePerson() { const person = await Person.findOne(); // 更新 person.age = 100; await person.save(); await Person.update( { name: 'bobby', }, { where: { id: 1 }, } ); } } ``` ## Repository 模式[​](#repository-模式 "Repository 模式的直接链接") Repository 模式可以将查找、创建等静态操作从模型定义中分离出来。它还支持与多个 sequelize 实例(多数据源)一起使用。 ### 启动 Repository 模式[​](#启动-repository-模式 "启动 Repository 模式的直接链接") 和数据源配置相同,只是多了一个属性。 ``` // src/config/config.default.ts import { Person } from '../entity/person.entity'; export default { // ... sequelize: { dataSource: { default: { // ... entities: [Person], // 多了这一个 repositoryMode: true, }, }, sync: false, }, }; ``` 如果是多个数据源,务必在每个数据源都开启该属性,开启后,原有的静态操作方法不再可用。 你需要使用 `Repository` 的操作方式。 ### 使用 Repository 模式[​](#使用-repository-模式 "使用 Repository 模式的直接链接") 基本 API 和静态操作相同,Midway 对其进行了一些简单包裹,使用 `InjectRepository` 装饰器可以在服务中注入 `Repository`。 ``` import { Controller, Get } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import { Photo } from '../entity/photo.entity'; import { User } from '../entity/user.entity'; import { Op } from 'sequelize'; import { Repository } from 'sequelize-typescript'; @Controller('/') export class HomeController { @InjectRepository(User) userRepository: Repository; @InjectRepository(Photo) photoRepository: Repository; @Get('/') async home() { // 查询 let result = await this.photoRepository.findAll(); console.log(result); // 新增 await this.photoRepository.create({ name: '123', }); // 删除 await this.photoRepository.destroy({ where: { name: '123', }, }); // 联合查询 // SELECT * FROM photo WHERE name = "23" OR name = "34"; let result = await this.photoRepository.findAll({ where: { [Op.or]: [{ name: '23' }, { name: '34' }], }, }); // => result // 连表查询 let result = await this.userRepository.findAll({ include: [Photo] }); // => result } } ``` 关于 OP 的更多用法: ### 多库的支持[​](#多库的支持 "多库的支持的直接链接") 在 Repository 模式下,我们可以在 `InjectRepository` 参数中指定特定的数据源。 ``` import { Controller } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import { Photo } from '../entity/photo.entity'; import { User } from '../entity/user.entity'; import { Repository } from 'sequelize-typescript'; @Controller('/') export class HomeController { // 指定某个数据源 @InjectRepository(User, 'default') userRepository: Repository; // ... } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 数据源同步配置[​](#数据源同步配置 "数据源同步配置的直接链接") sequelize 在同步数据源时可以添加 sync 的参数。 ``` export default { // ... sequelize: { dataSource: { default: { sync: true, syncOptions: { force: false, alter: true, }, }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default', }, }; ``` ### 指定默认数据源[​](#指定默认数据源 "指定默认数据源的直接链接") 在包含多个数据源时,可以指定默认的数据源。 ``` export default { // ... sequelize: { dataSource: { default1: { // ... }, default2: { // ... }, }, // 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: 'default1', }, }; ``` ### 获取数据源[​](#获取数据源 "获取数据源的直接链接") 数据源即创建出的 sequelize 对象,我们可以通过注入内置的数据源管理器来获取。 ``` import { Configuration } from '@midwayjs/core'; import { SequelizeDataSourceManager } from '@midwayjs/sequelize'; @Configuration({ // ... }) export class MainConfiguration { async onReady(container: IMidwayContainer) { const dataSourceManager = await container.getAsync(SequelizeDataSourceManager); const conn = dataSourceManager.getDataSource('default'); await conn.authenticate(); } } ``` 从 v3.8.0 开始,也可以通过装饰器注入。 ``` import { Configuration } from '@midwayjs/core'; import { InjectDataSource } from '@midwayjs/sequelize'; import { Sequelize } from 'sequelize-typescript'; @Configuration({ // ... }) export class MainConfiguration { // 注入默认数据源 @InjectDataSource() defaultDataSource: Sequelize; // 注入自定义数据源 @InjectDataSource('default1') customDataSource: Sequelize; async onReady(container: IMidwayContainer) { // ... } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、Dialect needs to be explicitly supplied as of v4.0.0[​](#1dialect-needs-to-be-explicitly-supplied-as-of-v400 "1、Dialect needs to be explicitly supplied as of v4.0.0的直接链接") 原因为配置中数据源没有指定 `dialect` 字段,确认数据源的结构,格式以及配置合并的结果。 ### 2、生成实体列[​](#2生成实体列 "2、生成实体列的直接链接") 请参考社区提供的模块,如 [sequelize-typescript-generator](https://github.com/spinlud/sequelize-typescript-generator) ### 3、Raw Query[​](#3raw-query "3、Raw Query的直接链接") 如果遇到比较复杂的,可以使用 [raw query 方法](https://sequelize.org/v5/manual/raw-queries.html) ### 4、TS2612 错误[​](#4ts2612-错误 "4、TS2612 错误的直接链接") 如果你的模型列报了 TS2612 错误,比如: ``` src/entity/AesTenantConfigInfo.ts:29:6 - error TS2612: Property 'id' will overwrite the base property in 'Model'. If this is intentional, add an initializer. Otherwise, add a 'declare' modifier or remove the redundant declaration. 29 id?: number; ~~ ``` 可以将其赋一个空值。 ``` import { Table, Column } from 'sequelize-typescript'; @Table export class User extends Model { @Column({ primaryKey: true, autoIncrement: true, type: DataType.BIGINT, }) id?: number = undefined; } ``` ## 其他[​](#其他 "其他的直接链接") * 上面的文档,翻译自 sequelize-typescript,更多 API ,请参考 [英文文档](/docs/extensions/\(https://github.com/sequelize/sequelize-typescrip\)) * 一些 [案例](https://github.com/ddzyan/midway-practice) --- # SocketIO Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01YTye6U22gICvarVur_!!6000000007149-2-tps-1204-352.png) Midway 提供了对 Socket.io 的支持和封装,能够简单的创建一个 Socket.io 服务。本篇内容演示了如何在 Midway 体系下,提供 Socket.io 服务的方法。 Midway 当前采用了最新的 [Socket.io (v4.0.0)](https://socket.io/docs/v4) 进行开发。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ✅ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 Socket.io 的依赖。 ``` $ npm i @midwayjs/socketio@4 --save ## 客户端可选 $ npm i @types/socket.io-client socket.io-client --save-dev ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/socket.io": "^4.0.0", // 客户端可选 "socket.io-client": "^4.4.1", // ... }, "devDependencies": { // 客户端可选 "@types/socket.io-client": "^1.4.36", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/socket.io` 可以作为独立主框架使用。 ``` import { Configuration } from '@midwayjs/core'; import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [socketio], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [koa, socketio], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 下面是 Socket.io 项目的基础目录结构,和传统应用类似,我们创建了 `socket` 目录,用户存放 Soscket.io 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## socket.io 服务的文件 │ └── hello.controller.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## Socket.io 工作原理[​](#socketio-工作原理 "Socket.io 工作原理的直接链接") Socket.io 服务器和 Socket.io 客户端(浏览器,Node.js 或另一种编程语言)之间的双向通道通过 [WebSocket连接](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) 建立起来,在不可用时,将使用 HTTP 长轮询作为备用手段。 Socket.io 代码是基于 Engine.io 库搭建起来的,是属于 Engine.io 的上层实现。Engine.io 负责整个服务端和客户端连接的部分,包括连接检查,传输方式等等。而 Socket.io 负责上层的重连,封包缓冲,广播等等特性。 Socket.io(Engine.io)实现了两种 Transports(传输方式)。 第一种是 HTTP 长轮询。HTTP Get 请求用于 long-running(长连接),Post 请求用于 short-running(短连接)。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01xhdZHA1XTEpUue7CQ_!!6000000002924-2-tps-1778-1068.png) 第二种是 WebSocket 协议,直接基于 [WebSocket Connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 实现。它在服务器和客户端之间提供了双向且低延迟的通信通道。 在默认的情况下,Socket.io 会先采用 HTTP 长轮询进行连接,并发送一个类似下面结构的数据。 ``` { "sid": "FSDjX-WRwSA4zTZMALqx", // 连接的 session id "upgrades": ["websocket"], // 可升级的协议 "pingInterval": 25000, // 心跳时间间隔 "pingTimeout": 20000 // 心跳超时时间 } ``` 当当前的服务满足升级到 WebSocket 协议的要求时,会自动升级到 WebSocket 协议,如下图。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01QHZi9x1mz2ZLecco3_!!6000000005024-2-tps-585-216.png) * 1、第一次握手,传输 sid 等结构 * 2、使用 HTTP 长轮询发送数据 * 3、使用 HTTP 长轮询返回数据 * 4、升级协议,使用 WebSocket 协议发送数据 * 5、当协议升级后,关闭之前的长轮询 之后就开始正常的 WebSocket 通信了。 ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController` 装饰器定义 Socket 服务。 ``` @WSController('/') export class HelloController { // ... } ``` `@WSController` 的入参,指代了每个 Socket 的 Namespace(非 path)。如果不提供 Namespace,每个 Socket.io 会自动创建一个 `/` 的 Namespace,并且将客户端连接都归到其中。 信息 这里的 namespace 支持字符串和正则。 当 Namespace 有客户端连接时,会触发 `connection` 事件,我们在代码中可以使用 `@OnWSConnection()` 装饰器来修饰一个方法,当每个客户端第一次连接到该 Namespace 时,将自动调用该方法。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod() { console.log('on client connect', this.ctx.id); } } ``` 信息 这里的 ctx 等价于 socket 实例。 ## 消息和响应[​](#消息和响应 "消息和响应的直接链接") Socket.io 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()` 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, Provide, OnWSMessage, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') async gotMessage(data) { console.log('on data got', this.ctx.id, data); } } ``` 注意,由于 Socket.io 在一个事件中可以传递多个数据,这里的参数可以是多个。 ``` @OnWSMessage('myEvent') async gotMessage(data1, data2, data3) { // ... } ``` 当获取到数据之后,通过业务逻辑处理数据,然后将结果返回给客户端,返回的时候,我们也是通过另一个事件发送给客户端。 通过 `@WSEmit` 装饰器来将方法的返回值返回给客户端。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/socketio'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { return 'hello world'; // 这里将 hello world 字符串返回给客户端 } } ``` 上面的代码,我们的方法返回值 hello world,将自动发送给客户端监听的 `myEventResult` 事件。 ## Socket 中间件[​](#socket-中间件 "Socket 中间件的直接链接") Socket 中的中间件的写法和 [Web 中间件 ](/docs/middleware.md)相似,但是加载的时机略有不同。 由于 Socket 有连接和接收消息两个阶段,所以中间件以此分为几类。 * 全局 Connection 中间件,会对所有 namespace 下的 connection 生效 * 全局 Message 中间件,会对所有 namespace 下的 message 生效 * Controller 中间件,会对单个 namespace 下的 connection 和 message 生效 * Connection 中间件,会对单个 namespace 下的 connection 生效 * Message 中间件,会对单个 namespace 下的 message 生效 ### 中间件写法[​](#中间件写法 "中间件写法的直接链接") 注意,中间件必须通过 `return` 返回结果。 ``` // src/middleware/socket.middleware.ts import { Middleware } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/socketio'; @Middleware() export class SocketMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... return await next(); } } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 和 Web 中间件类似,通过 `socket.io` 的 app 实例,注册中间件。 ``` import * as socketio from '@midwayjs/socketio'; @Configuration({ imports: [ socketio ], // ... }) export class MainConfiguration { @App('socketIO') app: Application; async onReady() { // 可以注册全局 connection 中间件 this.app.useConnectionMiddleware(SocketMiddleware); // 也可以注册全局 Message 中间件 this.app.useMiddleware(SocketMiddleware); } } ``` ### Namespace 中的中间件[​](#namespace-中的中间件 "Namespace 中的中间件的直接链接") 通过装饰器,注册不同阶段的中间件。 比如 Namespace 级别的中间件,会对单个 namespace 下的 connection 和 message 生效。 ``` // ... // Namespace 级别的中间件 @WSController('/api', { middleware: [SocketMiddleware]}) export class APIController { } ``` Connection 中间件,在连接时生效。 ``` // ... @WSController('/api') export class APIController { // Connection 触发时的中间件 @OnWSConnection({ middleware: [SocketMiddleware] }) init() { // ... } } ``` Message 中间件,接收到特定消息时生效。 ``` // ... @WSController('/api') export class APIController { // Message 触发时的中间件 @OnWSMessage('my', { middleware: [SocketMiddleware] }) @WSEmit('ok') async gotMyMessage() { // ... } } ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") 由于 socket.io 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway 框架一起启动)。 当作为独立框架启动时,需要指定端口。 ``` // src/config/config.default export default { // ... socketIO: { port: 3000, }, } ``` 当作为副框架启动时(比如和 http ,由于 http 在单测时未指定端口(使用 supertest 自动生成),无法很好的测试,可以仅在测试环境显式指定一个端口。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, socketIO: { port: 3000, }, } ``` 提示 * 1、这里的端口仅为 WebSocket 服务在测试时启动的端口 * 2、koa 中的端口为 null,即意味着在测试环境下,不配置端口,不会启动 http 服务 和其他 Midway 测试方法一样,我们使用 `createApp` 启动项目。 ``` import { createApp, close } from '@midwayjs/mock' // 这里使用的 Framework 定义,以主框架为准 import { Framework } from '@midwayjs/koa'; describe('/test/index.test.ts', () => { it('should create app and test socket.io', async () => { const app = await createApp(); //... await close(app); }); }); ``` 你可以直接使用 `socket.io-client` 来测试。也可以使用 Midway 提供的基于 `socket.io-client` 模块封装的测试客户端。 假如我们的服务端处理逻辑如下(返回客户端传递的数据相加的结果): ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 测试代码如下: ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 拿到结果返回 const data = await new Promise(resolve => { client.on('myEventResult', resolve); // 发送事件 client.send('myEvent', 1, 2, 3); }); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 如果多个客户端,也可以使用更简单的写法,使用 node 自带的 `events` 模块的 `once` 方法来优化,就会变成下面的代码。 ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 用事件的 promise 写法监听 const gotEvent = once(client, 'myEventResult'); // 发送事件 client.send('myEvent', 1, 2, 3); // 等待返回 const [data] = await gotEvent; // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 等待回执(ack)的消息[​](#等待回执ack的消息 "等待回执(ack)的消息的直接链接") Socket.io 支持一种直接返回消息的写法。当客户端传递消息的时候,如果最后一个参数为一个 function(callback),则服务端可以拿到这个 callback,将数据直接返回给客户端,不需要创建一个新的消息。 我们的服务代码不需要变化, `@midwayjs/socketio` 内部会判断最后一个参数,自动返回给客户端。 比如,服务端代码: ``` @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage(data1, data2, data3) { return { name: 'harry', result: data1 + data2 + data3, }; } ``` 客户端测试代码: ``` import { createApp, close } from '@midwayjs/mock' import { Framework } from '@midwayjs/koa'; import { createSocketIOClient } from '@midwayjs/mock'; import { once } from 'events'; describe('/test/index.test.ts', () => { it('should test create socket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个对应的客户端 const client = await createSocketIOClient({ port: 3000, }); // 发送事件,这里使用了 await 的写法 const data = await client.sendWithAck('myEvent', 1, 2, 3); // 判断结果 expect(data).toEqual({ name: 'harry', result: 6, }); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); }); ``` ## 常见的消息和广播[​](#常见的消息和广播 "常见的消息和广播的直接链接") 以下面的代码示例举例: ``` import { Context, Application } from '@midwayjs/socketio'; import { WSController, OnWSMessage, WSEmit, App, Inject } from '@midwayjs/core'; @WSController('/') export class HelloSocketController { @Inject() ctx: Context; @App('socketIO') app: Application; @OnWSMessage('myEvent') @WSEmit('myEventResult') async gotMessage() { // TODO } } ``` 发送给客户端(也可以用装饰器形式直接 return)。 ``` this.ctx.emit("hello", "can you hear me?", 1, 2, "abc"); ``` 发送给的所有除发件人以外的所有客户端。 ``` this.ctx.broadcast.emit("broadcast", "hello friends!"); ``` 发送给所有在 `game` 房间的客户端(除了发送者)。 ``` this.ctx.to("game").emit("nice game", "let's play a game"); ``` 发送给所有的 `game1` 和 `game2` 房间的客户端(除了发送者)。 ``` this.ctx.to("game1").to("game2").emit("nice game", "let's play a game (too)"); ``` 发送给所有 `game` 房间的客户端,包括发送者。 ``` this.app.in("game").emit("big-announcement", "the game will start soon"); ``` 给 `myNamespace` 命名空间的客户端广播,包括发送者。 ``` // 从 app 发送 this.app.of("myNamespace").emit("bigger-announcement", "the tournament will start soon"); // 从 ctx 发送 this.ctx.nsp.emit("bigger-announcement", "the tournament will start soon"); ``` 发送到特定的 namespace 和 room,包括发送者。 ``` // 从 app 发送 this.app.of("myNamespace").to("room").emit("event", "message"); // 从 ctx 发送 this.ctx.nsp.emit("bigger-announcement", "the tournament will start soon"); ``` 发送给所有连接到当前节点上的客户端(多个节点的时候,就是多进程) ``` this.app.local.emit("hi", "my lovely babies"); ``` ## Application(io 对象)[​](#applicationio-对象 "Application(io 对象)的直接链接") 传统的 Socket.io 服务端创建代码如下: ``` const io = require("socket.io")(3000); io.on("connection", socket => { // ... }); ``` 在 `@midwayjs/socketio` 框架中,Application 实例即为该 io 实例,类型和能力保持一致。即通过 `@App` 装饰器注入的 app 实例,即为 io 对象。 我们可以通过该对象做一些全局的事情。 比如获取所有的 socket 实例。 ``` // 返回所有的 socket 实例 const sockets = await app.fetchSockets(); // 返回所有的在 room1 的 socket 实例 const sockets = await app.in("room1").fetchSockets(); // 返回特定 socketId 的实例 const sockets = await app.in(theSocketId).fetchSockets(); ``` 多框架下,主框架一般为 Web 框架,我们可以通过指定 key 获取 Socket.io 的 app。 ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Controller, App } from '@midwayjs/core'; @Controller() export class UserController { @App('socketIO') socketApp: SocketApplication; } ``` 这样我们可以通过 `@midwayjs/socketio` 的 app 对象(等价于 io),调用现有的 socket 连接。 比如,HTTP 请求调用进来对特定 namespace 下的所有客户端广播: ``` import { Application as SocketApplication } from '@midwayjs/socketio'; import { Provide, Controller, App, Get } from '@midwayjs/core'; @Controller() export class UserController { @App('socketIO') socketApp: SocketApplication; @Get() async invoke() { // 对 / 下的连接做广播 this.socketApp.of('/').emit('hi', 'everyone'); } } ``` 更多的 io API,请参考 [Socket.io Server instance 文档](https://socket.io/docs/v4/server-instance/)。 ## Socket 部署[​](#socket-部署 "Socket 部署的直接链接") ### Socket 服务端口[​](#socket-服务端口 "Socket 服务端口的直接链接") `@midwayjs/socketio` 的配置样例如下: ``` // src/config/config.default export default { // ... socketIO: { port: 7001, }, } ``` 当 `@midwayjs/socketio` 和其他 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` 同时启用时,可以复用http 端口。 ``` // src/config/config.default export default { // ... koa: { port: 7001, }, socketIO: { // 这里不配置即可 }, } ``` ### Nginx 配置[​](#nginx-配置 "Nginx 配置的直接链接") 一般来说,我们的 Node.js 服务前都会有 Nginx 等类似的反向代理服务,这里以 Nginx 的配置为例。 ``` http { server { listen 80; server_name example.com; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://localhost:7001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } } ``` ## 配置[​](#配置 "配置的直接链接") ### 可用配置[​](#可用配置 "可用配置的直接链接") | 属性 | 类型 | 描述 | | -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | port | number | 可选,如果传递了该端口,socket.io 内部会创建一个该端口的 HTTP 服务,并将 socket 服务 attach 在其之上。如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | path | string | 可选,服务端 path | | adapter | object | 分布式处理的适配器,比如可以配置 redis-adapter | | connectTimeout | number | 客户端超时时间,单位 ms,默认值 *45000* | 更多的启动选项,请参考 [Socket.io 文档](https://socket.io/docs/v4/server-api/#new-Server-httpServer-options)。 ## 适配器[​](#适配器 "适配器的直接链接") 适配器是用于 Socket.io 在分布式部署时,在多台机器,多个进程能够进行通信的一层适配层,当前 socket.io 官方提供的适配器有几种: * 1、cluster-adapter 用于在单台机器,多进程之间适配 * 2、redis-adapter 用于在多台机器,多个进程之间适配 在分布式场景下,我们一般使用 redis-adapater 来实现功能。 ### 配置 redis 适配器[​](#配置-redis-适配器 "配置 redis 适配器的直接链接") `@midwayjs/socketio` 提供了一个适配器(adapter)的入口配置,只需要初始化适配器实例,传入即可。 提示 Socket.io 官方已经更新了原有的适配器包名,现在的包名为 `@socket.io/redis-adapter`(原来叫 `socket.io-redis`),配置有更新,迁移参考请查看 [官方文档](https://github.com/socketio/socket.io-redis-adapter#migrating-from-socketio-redis)。 安装如下: ``` $ npm i @socket.io/redis-adapter --save ``` 新版本配置的示例如下,更多的配置可以参考 [官方文档](https://github.com/socketio/socket.io-redis-adapter): ``` // src/config/config.default import { createAdapter } from '@socket.io/redis-adapter'; import Redis from 'ioredis'; // github 文档创建 redis 实例 const pubClient = new Redis(/* redis 配置 */); const subClient = pubClient.duplicate(); export default { // ... socketIO: { adapter: createAdapter(pubClient, subClient) }, } ``` 通过使用 `@socket.io/redis-adapter` 适配器运行 Socket.io,可以在不同的进程或服务器中运行多个 Socket.io 实例,这些实例都可以相互广播和发送事件。 此外,还有一些 Adapter 上的特殊 API,具体可以查看 [文档](https://github.com/socketio/socket.io-redis-adapter#api)。 ## 粘性会话[​](#粘性会话 "粘性会话的直接链接") 由于 Node.js 经常在启动时使用多进程(cluster)模式,如果同一个会话(sid)无法多次访问到同一个进程上,socket.io 就会报错。 解决办法有两种。 ### 使用 WebSocket 协议[​](#使用-websocket-协议 "使用 WebSocket 协议的直接链接") 最简单的方法,只启用 WebSocket 协议(禁用长轮询),这样就可以规避上述问题。 你需要在服务端和客户端同时配置。 ``` // 服务端 export default { // ... socketIO: { // ... transports: ['websocket'], }, } // 客户端 const socket = io("http://127.0.0.1:7001", { transports: ['websocket'] }); ``` ### 调整进程模型[​](#调整进程模型 "调整进程模型的直接链接") 这是相对复杂的方法,但是在 pm2 部署的场景下,既要支持粘性会话又要启用轮询支持,这是唯一的解法。 第一步,禁用配置中启动的端口,比如: ``` // src/config/config.default export default { koa: { // port: 7001, }, socketIO: { // ... }, }; ``` 如果开发需要,可以在 `config.local` 中加上端口,或者直接在 `package.json` 的 scripts 中加上端口。 ``` "scripts": { "dev": "cross-env NODE_ENV=local midway-bin dev --ts --port=7001", }, ``` 第二步,调整你的 `bootstrap.js` 文件内容,使其变为下面的代码。 ``` const { Bootstrap, ClusterManager, setupStickyMaster } = require('@midwayjs/bootstrap'); const http = require('http'); // 创建一个进程管理器,处理子进程 const clusterManager = new ClusterManager({ exec: __filename, count: 4, sticky: true, // 开启粘性会话支持 }); if (clusterManager.isPrimary()) { // 主进程启动一个 http server 做监听 const httpServer = http.createServer(); setupStickyMaster(httpServer); // 启动子进程 clusterManager.start().then(() => { // 监听端口 httpServer.listen(7001); console.log('main process is ok'); }); clusterManager.onStop(async () => { // 停止时关闭 http server await httpServer.close(); }); } else { // 子进程逻辑 Bootstrap .run() .then(() => { console.log('child is ready'); }); } ``` 在 pm2 启动时,无需指定 `-i` 参数来启动 worker,直接 `pm2 --name=xxx ./bootstrap.js` 使其只启动一个进程。 ## 常见 API[​](#常见-api "常见 API的直接链接") ### 获取连接数[​](#获取连接数 "获取连接数的直接链接") ``` const count = app.engine.clientsCount; // 获取所有的连接数 const count = app.of('/').sockets.size; // 获取单个 namespace 里的连接数 ``` ### 修改 sid 生成[​](#修改-sid-生成 "修改 sid 生成的直接链接") ``` const uuid = require("uuid"); app.engine.generateId = (req) => { return uuid.v4(); // must be unique across all Socket.IO servers } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 服务端/客户端没连上,没响应[​](#服务端客户端没连上没响应 "服务端/客户端没连上,没响应的直接链接") 1、端口服务端和客户端一致 ``` export default { koa: { port: 7001, // 这里的端口 } } // 或者 export default { socketIO: { port: 7001, // 这里的端口 } } ``` 和下面的端口要一致。 ``` // socket.io client const socket = io('************:7001', { //... }); // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ port: 7001 }); ``` 2、服务端的 path 和客户端的 path 要保持一致。path 指的是启动参数的部分。 ``` // config.default export default { socketIO: { path: '/testPath' // 这里是服务端 path } } ``` 和下面的 path 要一致 ``` // socket.io client const socket = io('************:7001', { path: '/testPath' // 这里是客户端的 path }); // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ path: '/testPath' }); ``` 3、服务端的 namespace 和客户端的 namespace 要保持一致。 ``` // server @WSController('/test') // 这里是服务端的 namespace export class HelloController { } // socket.io client const io = require("socket.io-client") io('*****:3000/test', {}); // 这里是客户端的 namespace // midway 的 socket.io 测试客户端 const client = await createSocketIOClient({ namespace: '/test', }); ``` ### 配置 CORS[​](#配置-cors "配置 CORS的直接链接") 如果出现跨域错误,需要在启动的时候配置 cors 信息。 ``` // config.default export default { socketIO: { cors: { origin: "http://localhost:8080", methods: ["GET", "POST"] } } } ``` 具体参数可以参考 [Socket.io Handling CORS](https://socket.io/docs/v4/handling-cors/)。 --- # 静态文件托管 midway 提供了基于 [koa-static-cache](https://github.com/koajs/static-cache) 模块的静态资源托管组件。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ❌ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/static-file@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/static-file": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as staticFile from '@midwayjs/static-file'; import { join } from 'path' @Configuration({ imports: [ koa, staticFile ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 使用[​](#使用 "使用的直接链�接") 默认情况下,会托管项目根目录下的 `public` 目录中的内容。 比如: ``` ➜ my_midway_app tree . ├── src ├── public | ├── index.html │ └── hello.js │ ├── test ├── package.json └── tsconfig.json ``` 我们可以直接使用路径访问 `GET /public/index.html` 并获取相应的结果。 ## 配置[​](#配置 "配置的直接链接") ### 修改默认行为[​](#修改默认行为 "修改默认行为的直接链接") 资源的托管使用的是 `dirs` 字段,其中有一个 `default` 属性,我们可以修改它。 ``` // {app_root}/src/config/config.default.ts export default { // ... staticFile: { dirs: { default: { prefix: '/', dir: 'xxx', }, } }, } ``` `dirs` 中的对象值,会和 `staticFile` 下的值合并后,传入 `koa-static-cache` 中间件中。 ### 增加新的目录[​](#增加新的目录 "增加新的目录的直接链接") 可以对 dirs 做修改,增加一个新的目录。key 不重复即可,value 会和默认的配置合并。 ``` // {app_root}/src/config/config.default.ts export default { // ... staticFile: { dirs: { default: { prefix: '/', dir: 'xxx', }, another: { prefix: '/', dir: 'xxx', }, } // ... }, } ``` ### 可用配置[​](#可用配置 "可用配置的直接链接") 支持所有的 [koa-static-cache](https://github.com/koajs/static-cache) 配置,默认配置如下: | 属性名 | 默认值 | 描述 | | ------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | dirs | {"default": {prefix: "/public", "dir": "xxxx"}} | 托管的目录,为了支持多个目录,是个对象。
除了 default 之外,其他的 key 可以随意添加,dirs 中的对象值会和外部默认值做合并 | | dynamic | true | 动态加载文件,而不是在初始化读取后做缓存 | | preload | false | 是否在初始化缓存 | | maxAge | prod 为 31536000,其他为 0 | 缓存的最大时间 | | buffer | prod 为 true,其余为 false | 使用 buffer 字符返回 | 更多配置,请参考 [koa-static-cache](https://github.com/koajs/static-cache) 。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、函数下路由未生效[​](#1函数下路由未生效 "1、函数下路由未生效的直接链接") 函数路由需要显式配置才能生效,一般来说,会添加一个通配的路由用于静态文件,如 `/*`,或者 `/public/*`。 ``` import { Provide, ServerlessTrigger, ServerlessTriggerType, } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloHTTPService { @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/public/*', method: 'get', }) async handleStaticFile() { // 这个函数可以没有方法体,只是为了让网关注册一个额外的路由 } } ``` ### 2、默认 index.html[​](#2默认-indexhtml "2、默认 index.html的直接链接") 由于 [koa-static-cache](https://github.com/koajs/static-cache) 不支持默认 `index.html` 的配置,可以通过它的 alias 功能来解决。 可以配置把 `/` 指向到 `/index.html` 即可,不支持通配和正则。 ``` export default { // ... staticFile: { dirs: { default: { prefix: '/', alias: { '/': '/index.html', }, }, }, // ... }, } ``` ### 3、egg(@midwayjs/web)下不生效的情况[​](#3eggmidwayjsweb下不生效的情况 "3、egg(@midwayjs/web)下不生效的情况的直接链接") 由于 egg 自带了静态托管插件,如果开启了 static 插件,会和此组件冲突。 如需使用本组件,请务必关闭 egg 插件。 ``` // src/config/plugin.ts import { EggPlugin } from 'egg'; export default { // ... static: false, } as EggPlugin; ``` ### 4、Internal Server Error, real status: 500[​](#4internal-server-error-real-status-500 "4、Internal Server Error, real status: 500的直接链接") 如果使用staticFile配置的静态目录不存在,则服务可能会抛出500错误,请确保您配置的静态目录已被正确创建。 --- # Swagger 基于最新的 [OpenAPI 3.0.3](https://swagger.io/specification/) 实现了新版的 Swagger 组件。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ❌ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm install @midwayjs/swagger@4 --save $ npm install swagger-ui-dist --save-dev ``` 如果想要在服务器上输出 Swagger API 页面,则需要将 `swagger-ui-dist` 安装到依赖中。 ``` $ npm install swagger-ui-dist --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/swagger": "^4.0.0", // 如果你希望在服务器上使用 "swagger-ui-dist": "^4.2.1", // ... }, "devDependencies": { // 如果你不希望在服务器上使用 "swagger-ui-dist": "^4.2.1", // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `configuration.ts` 中增加组件。 ``` import { Configuration } from '@midwayjs/core'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [ // ... swagger ] }) export class MainConfiguration { } ``` 可以配置启用的环境,比如下面的代码指的是 **只在 local 环境下启用**。 ``` import { Configuration } from '@midwayjs/core'; import * as swagger from '@midwayjs/swagger'; @Configuration({ imports: [ // ... { component: swagger, enabledEnvironment: ['local'] } ] }) export class MainConfiguration { } ``` 然后启动项目,访问地址: * UI: * JSON: 路径可以通过 `swaggerPath` 参数配置。 ## 数据类型[​](#数据类型 "数据类型的直接链接") ### 自动类型提取[​](#自动类型提取 "自动类型提取的直接链接") Swagger 组件会识别各个 `@Controller` 中每个路由方法的 `@Body()`、`@Query()`、`@Param()` 装饰器,提取路由方法参数和类型。 比如下面的代码: ``` @Get('/') async home( @Query('uid') uid: number, @Query('tid') tid: string, @Query('isBoolean') isBoolean: boolean, ) { // ... } ``` 基础的布尔,字符串,数字类型展示效果如下: ![](https://img.alicdn.com/imgextra/i2/O1CN01KGk0B325xe6cV5HCo_!!6000000007593-2-tps-1110-854.png) ### 类型和 Schema[​](#类型和-schema "类型和 Schema的直接链接") 我们常在参数使用对象,并使用定义好的类作为类型,这个时候 swagger 组件也能自动识别,同时也能和普通的类型进行组合识别。 比如下面的代码: ``` @Post('/:id', { summary: 'test'}) async create(@Body() createCatDto: CreateCatDto, @Param('id') id: number) { // ... } ``` `CreateCatDto` 类型的定义如下,我们使用 `ApiProperty` 将其中的每个属性都进行了定义。 ``` import { ApiProperty } from "@midwayjs/swagger"; export class CreateCatDto { @ApiProperty({ example: 'Kitty', description: 'The name of the Catname'}) name: string; @ApiProperty({ example: '1', description: 'The name of the Catage'}) age: number; @ApiProperty({ example: 'bbbb', description: 'The name of the Catbreed'}) breed: string; } ``` 效果如下,组件会自动提取其中的两个参数: ![swagger1](https://img.alicdn.com/imgextra/i2/O1CN01qpyb7k1uheVEFq8CI_!!6000000006069-2-tps-1220-1046.png) 同时,由于在类中定义了每个属性的 example,会自动填入示例值。 在 Swagger 中,每个类型都会有一个 `Schema` 来描述,我们已经定义了一个 `CreateCatDto` 的 Schema,看起来就像是下面的样子。 注意,我们会重复用到这些 Schema。 ![swagger2](https://img.alicdn.com/imgextra/i2/O1CN01iZYONb1tAqW35GM3C_!!6000000005862-2-tps-1050-694.png) ### 基础类型[​](#基础类型 "基础类型的直接链接") 通过给 `@ApiProperty(...)` 装饰器中设置 type,我们可以定义常见的类型。 大多数情况下,基础类型无需显式声明 `type` ,可自动识别。 **字符串** ``` @ApiProperty({ type: 'string', // ... }) name: string; ``` **布尔类型** ``` @ApiProperty({ type: 'boolean', example: 'true', // ... }) isPure: boolean; ``` **数字类型** ``` @ApiProperty({ type: 'number', example: '1', description: 'The name of the Catage' }) age: number; ``` 此外,也可以使用 format 字段来定义更为精确的长度。 ``` @ApiProperty({ type: 'integer', format: 'int32', example: '1', description: 'The name of the Catage' }) age: number; ``` ### 数组类型[​](#数组类型 "数组类型的直接链接") 如果是数组类型,我们可以配置 type 字段来定义,同时通过 `items` 的 `type` 来指定类型。 ``` @ApiProperty({ type: 'array', items: { type: 'string', }, example: ['1'], description: 'The name of the Catage' }) breeds: string[]; ``` ### 枚举类型[​](#枚举类型 "枚举类型的直接链接") 如果是枚举类型,可以通过配置 enmu 字段来定义。 ``` enum HelloWorld { One = 'One', Two = 'Two', Three = 'Three', } @ApiProperty({ enum: ['One', 'Two', 'Three'], description: 'The name of the Catage' }) hello: HelloWorld; ``` 如果该字段在最顶层,展示效果如下: ![swagger3](https://img.alicdn.com/imgextra/i1/O1CN015M37MU1KgtdNfqsgp_!!6000000001194-0-tps-1406-426.jpg) ### 复杂对象类型[​](#复杂��对象类型 "复杂对象类型的直接链接") 如果某个属性的类型是个现有的复杂类型,我们可以使用 `type` 来指定这个复杂的类型。 ``` export class Cat { /** * The name of the Catcomment * @example Kitty */ @ApiProperty({ example: 'Kitty', description: 'The name of the Cat'}) name: string; @ApiProperty({ example: 1, description: 'The age of the Cat' }) age: number; @ApiProperty({ example: '2022-12-12 11:11:11', description: 'The age of the CatDSate' }) agedata?: Date; @ApiProperty({ example: 'Maine Coon', description: 'The breed of the Cat', }) breed: string; } export class CreateCatDto { // ... @ApiProperty({ type: Cat, // 这里无需指定 example }) related: Cat; } ``` 效果如下: ![](https://img.alicdn.com/imgextra/i3/O1CN01KADwTb1rkS4gJExuP_!!6000000005669-2-tps-1376-1070.png) ### 复杂对象数组类型[​](#复杂对象数组类型 "复杂对象数组类型的直接链接") 如果某个属性的类型是个复杂的数组类型,写法略有不同。 首先`type` 必须声明为 `array`,除了设置`type`,我们还可以使用 `getSchemaPath` 方法额外导入一个不同的类型(上面的复杂对象也可以使用它设置$ref)。 此外,如果 `Cat` 类型没有在其他属性的 `type` 字段中声明过,需要使用 `@ApiExtraModel` 装饰器额外声明引入外部类型。 ``` import { ApiProperty, getSchemaPath, ApiExtraModel } from '@midwayjs/swagger'; class Cat { // ... } @ApiExtraModel(Cat) export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { $ref: getSchemaPath(Cat), } }) relatedList: Cat[]; } ``` 效果如下: ![](https://img.alicdn.com/imgextra/i1/O1CN01h4sQJ41dP0uq4fgi7_!!6000000003727-2-tps-1332-666.png) ### 循环依赖[​](#循环依赖 "循环依赖的直接链接") 当类之间具有循环依赖关系时,请使用惰性函数提供类型信息。 比如 `type` 字段的循环。 ``` class Photo { // ... @ApiProperty({ type: () => Album }) album: Album; } class Album { // ... @ApiProperty({ type: () => Photo }) photo: Photo; } ``` `getSchemaPath` 也可以使用。 ``` export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { $ref: () => getSchemaPath(Cat) } }) relatedList: Cat[]; } ``` ## 请求定义[​](#请求定义 "请求定义的直接链接") [OpenAPI](https://swagger.io/specification/) 定义的 paths 就是各个路由路径,且每个路由路径都有 HTTP 方法的定义,比如 GET、POST、DELETE、PUT 等。 ### Query 定义[​](#query-定义 "Query 定义的直接链接") 使用 `@ApiQuery` 来定义 Query 数据。 基础使用,会自动识别 `@Query` 装饰器。 ``` @Get('/get_user') async getUser(@Query('name') name: string) { return 'hello'; } ``` 如果 `@Query` 以对象形式,可以有两种方式: 1. 使用 `@ApiProperty` 显式定义文档字段(传统方式) 2. 使用 `@midwayjs/validation` DTO(`@Rule`)自动推导字段(默认开启) 自动推导开启时(`swagger.useValidationSchema = true`,默认值),对象 Query 会按 DTO 字段展开为多个 query 参数。 当前推导能力基于 `@midwayjs/validation` 的 validator adapter,支持 joi、zod、class-validator。 ``` export class UserDTO { @ApiProperty() name: string; } @Get('/get_user') @ApiQuery({ name: 'query' }) async getUser(@Query() dto: UserDTO) { // ... } ``` ### Body 定义[​](#body-定义 "Body 定义的直接链接") 使用 `@ApiBody` 来定义 Body 数据。 `@Body` 对象类型同样支持两种方式: 1. `@ApiProperty` 显式定义文档字段 2. `@midwayjs/validation` DTO 自动推导字段 当两者同时存在时,采用 **merge 策略**: * `@ApiProperty` 显式字段优先 * validation 推导只补齐缺失信息(例如 `required`、基础 `type` 等) ``` export class UserDTO { @ApiProperty() name: string; } @Post('/update_user') async upateUser(@Body() dto: UserDTO) { // ... } ``` 如需其他细节,请使用 `@ApiBody` 增强。 注意,Swagger 规定,`Body` 定义只能存在一个,如果配置了 `@ApiBody` ,则类型提取的数据会自动被覆盖。 比如下面示例中,`Body` 的类型会被替换为 `Cat`。 ``` @ApiBody({ type: Cat }) async upateUser(@Body() dto: UserDTO) { // ... } ``` ### 文件上传定义[​](#文件上传定义 "文件上传定义的直接链接") 文件上传是 Post 请求中较为特殊的一类场景。 可以通过在 DTO 中定义属性来实现多个文件以及 `Fields` 的类型。 ``` import { ApiProperty, BodyContentType } from "@midwayjs/swagger"; export class CreateCatDto { // ... @ApiProperty({ type: 'array', items: { type: 'string', format: 'binary', } }) files: any; } // ... @Post('/test1') @ApiBody({ contentType: BodyContentType.Multipart, schema: { type: CreateCatDto, } }) async upload1(@Files() files, @Fields() fields) { // ... } ``` Swagger UI 中展示: ![swagger6](https://img.alicdn.com/imgextra/i3/O1CN01w9dZxe1YQJv3uOycZ_!!6000000003053-0-tps-1524-1118.jpg) 如果不需要多个文件,使用 schema 定义即可。 ``` export class CreateCatDto { // ... @ApiProperty({ type: 'string', format: 'binary', }) file: any; } ``` Swagger UI 中展示: ![swagger4](https://img.alicdn.com/imgextra/i3/O1CN01KlDHNt24mMglN1fyH_!!6000000007433-0-tps-1598-434.jpg) ### 请求 Header[​](#请求-header "请求 Header的直接链接") 通过 `@ApiHeader({...})` 装饰器来定义 Header 参数。 ``` @ApiHeader({ name: 'x-test-one', description: 'this is test one' }) @ApiTags(['hello']) @Controller('/hello') export class HelloController {} ``` ![](https://img.alicdn.com/imgextra/i1/O1CN01n8Xgn729GphI6XzXk_!!6000000008041-2-tps-1234-584.png) ### 请求 Response[​](#请求-response "请求 Response的直接链接") 可以使用 `@ApiResponse({...})` 来自定义请求 Response。 ``` @Get('/:id') @ApiResponse({ status: 200, description: 'The found record', type: Cat, }) findOne(@Param('id') id: string, @Query('test') test: any): Cat { return this.catsService.findOne(+id); } ``` 还提供了其他不需要设置 status 的装饰器: * `@ApiOkResponse()` * `@ApiCreatedResponse()` * `@ApiAcceptedResponse()` * `@ApiNoContentResponse()` * `@ApiMovedPermanentlyResponse()` * `@ApiBadRequestResponse()` * `@ApiUnauthorizedResponse()` * `@ApiNotFoundResponse()` * `@ApiForbiddenResponse()` * `@ApiMethodNotAllowedResponse()` * `@ApiNotAcceptableResponse()` * `@ApiRequestTimeoutResponse()` * `@ApiConflictResponse()` * `@ApiTooManyRequestsResponse()` * `@ApiGoneResponse()` * `@ApiPayloadTooLargeResponse()` * `@ApiUnsupportedMediaTypeResponse()` * `@ApiUnprocessableEntityResponse()` * `@ApiInternalServerErrorResponse()` * `@ApiNotImplementedResponse()` * `@ApiBadGatewayResponse()` * `@ApiServiceUnavailableResponse()` * `@ApiGatewayTimeoutResponse()` * `@ApiDefaultResponse()` HTTP 请求返回的数据模型定义也可以通过指定 type。对于模型字段,推荐优先使用 `@ApiProperty`;如果模型同时带有 `@midwayjs/validation` 的 DTO 规则,则会按上述 merge 规则补齐缺失信息。 ``` import { ApiProperty } from '@midwayjs/swagger'; export class Cat { @ApiProperty({ example: 'Kitty', description: 'The name of the Cat'}) name: string; @ApiProperty({ example: 1, description: 'The age of the Cat' }) age: number; @ApiProperty({ example: 'Maine Coon', description: 'The breed of the Cat', }) breed: string; } ``` Swagger 还支持带前缀 `x-` 的扩展字段,可以使用 `@ApiExtension(x-..., {...})` 装饰器。 ``` @ApiExtension('x-hello', { hello: 'world' }) ``` 当不希望通过 type 来定义 model 类型时,我们可以通过在 Controller 中或者 Model Class 中加入 `@ApiExtraModel` 来增加额外的 `schema` 类型描述。 ``` @ApiExtraModel(TestExtraModel) @Controller() class HelloController { @Post('/:id', { summary: 'test'}) @ApiResponse({ status: 200, content: { 'application/json': { schema: { properties: { data: { '$ref': getSchemaPath(TestExtraModel)} } } } } }) async create(@Body() createCatDto: CreateCatDto, @Param('id') id: number): Promise { return this.catsService.create(createCatDto); } } // or @ApiExtraModel(TestExtraModel) class TestModel { @ApiProperty({ item: { $ref: getSchemaPath(TestExtraModel) }, description: 'The name of the Catage' }) one: TestExtraModel; } ``` ### 泛型返回数据[​](#泛型返回数据 "泛型返回数据的直接链接") Swagger 本身不支持泛型数据,泛型作为 Typescript 的一种类型,会在构建期抹掉,在运行时无法读取。 我们可以用一些取巧的方式来定义。 比如,我们需要将返回值增加一些通用的包裹结构。 ``` { code: 200, message: 'xxx', data: any } ``` 为此,我们可以编写一个方法,入参是返回的 data,返回一个包裹的类。 ``` import { Type } from '@midwayjs/swagger'; type Res = { code: number; message: string; data: T; } export function SuccessWrapper(ResourceCls: Type): Type> { class Successed { @ApiProperty({ description: '状态码' }) code: number; @ApiProperty({ description: '消息' }) message: string; @ApiProperty({ type: ResourceCls, }) data: T; } return Successed; } ``` 我们可以基于这个方法,来实现我们自己的返回类。 ``` class ViewCat extends SuccessWrapper(Cat) {} ``` 在使用的时候,可以直接指定这个类即可。 ``` @Get('/:id') @ApiResponse({ status: 200, description: 'The found record', type: ViewCat, }) async findOne(@Param('id') id: string, @Query('test') test: any): ViewCat { // ... } ``` ### 更多的定义示例[​](#更多的定义示例 "更多的定义示例的直接链接") Swagger 中还有更多的写法,框架都进行了支持,更多用法可以查看我们的 [测试用例](https://github.com/midwayjs/midway/blob/main/packages/swagger/test/parser.test.ts)。 ## 授权验证[​](#授权验证 "授权验证的直接链接") 组件可以通过添加授权验证配置来设置验证方式,我们支持配置 `basic`、`bearer`、`cookie`、`oauth2`、`apikey`、`custom`。 可以使用 `auth` 字段定义验证类型。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'basic', }, }, } ``` 支持数组,配置多个验证类型。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: [ { name: 'basicAuth1', authType: 'basic', }, { name: 'basicAuth2', authType: 'basic', } ], }, } ``` ### basic[​](#basic "basic的直接链接") 启用 basic 验证 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BasicAuth', authType: 'basic', description: 'Basic Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 basic | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiBasicAuth() // 默认使用 'basic' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiBasicAuth()` 装饰器有默认值 `'basic'`。如果配置文件中的 `name` 字段不是 `'basic'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'BasicAuth' 时 @ApiBasicAuth('BasicAuth') @Controller('/hello') export class HelloController {} ``` ### bearer[​](#bearer "bearer的直接链接") 启用 bearer 验证(bearerFormat 为 JWT) ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BearerAuth', authType: 'bearer', description: 'Bearer Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 bearer | | bearerFormat | 可选,bearer 类型默认为 JWT | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiBearerAuth() // 默认使用 'bearer' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiBearerAuth()` 装饰器有默认值 `'bearer'`。如果配置文件中的 `name` 字段不是 `'bearer'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'BearerAuth' 时 @ApiBearerAuth('BearerAuth') @Controller('/hello') export class HelloController {} ``` ### oauth2[​](#oauth2 "oauth2的直接链接") OAuth2 是 OpenAPI 里最复杂但最强大的认证类型,所有授权交互流程都能被描述清楚,swagger-ui 全自动支持。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'testOAuth2', authType: 'oauth2', flows: { implicit: { authorizationUrl: 'http://example.org/api/oauth/dialog', scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' } }, authorizationCode: { authorizationUrl: 'https://example.com/api/oauth/dialog', tokenUrl: 'https://example.com/api/oauth/token', scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' } }, }, }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | name | 必选,你的 API Key 的字段名 | | authType | 固定为 oauth2 | | flows | 必选,四种授权模式 | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | flows 是其中最复杂的字段配置,包括不同的参数,目前主要使用 **authorizationCode** 和 **clientCredentials**。 | **Flow 类型** | **简介** | **适用场景** | **当前状态** | | --------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------ | | **authorizationCode** | 标准授权码模式。用户通过授权服务器跳转登录,拿到授权码后再换取 access token。支持前端+后端安全配合。 | Web 应用、移动端应用(如 Google 登录、GitHub OAuth)。现代主流通用模式。 | ✅ 推荐使用(最安全、最通用) | | **clientCredentials** | 客户端凭证模式。没有用户参与,直接用 client\_id 和 client\_secret 拿 token,机器与机器之间认证。 | 微服务、后台服务、系统集成、API 网关 | ✅ 推荐使用(服务器到服务器通信首选) | | **password** | 密码模式。直接用用户名和密码换取 token,跳过授权服务器跳转。 | 内部系统、测试、历史遗留系统。风险高,暴露用户密码。 | ❌ 已废弃(RFC 6749 明确不推荐新系统使用) | | **implicit** | 隐式模式。前端单页应用直接在浏览器获取 token,不经后端,早期为避免前端暴露 client\_secret 设计。 | 早期 SPA、浏览器端应用。现已被 authorizationCode + PKCE 替代。 | ❌ 已废弃(OAuth 2.1 标准已移除) | 上述四种 Flow 类型可用的参数如下: | **参数** | **描述** | authorizationCode | clientCredentials | password | implicit | | ---------------- | ------------------------ | ----------------- | ----------------- | -------- | -------- | | authorizationUrl | 用户授权页面跳转地址 | ✅ 必须 | ❌ 无 | ❌ 无 | ✅ 必须 | | tokenUrl | 获取 access token 的地址 | ✅ 必须 | ✅ 必须 | ✅ 必须 | ❌ 无 | | refreshUrl | 刷新 access token 的地址 | ⚪ 可选 | ⚪ 可选 | ⚪ 可选 | ⚪ 可选 | | scopes | 授权范围,权限粒度控制 | ✅ 必须 | ✅ 必须 | ✅ 必须 | ✅ 必须 | 在控制器层面生效。 ``` @ApiOAuth2(['read:pets']) // 必须指定权限范围,默认使用 'oauth2' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiOAuth2()` 装饰器有默认值 `'oauth2'`。如果配置文件中的 `name` 字段不是 `'oauth2'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'testOAuth2' 时 @ApiOAuth2(['read:pets'], 'testOAuth2') @Controller('/hello') export class HelloController {} ``` ### cookie[​](#cookie "cookie的直接链接") 启用 cookie 验证,底层会转换为 apikey。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'cookie', securityName: 'testforcookie', cookieName: 'connect.sid', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------- | | securityName | 可选,验证字段的 key,可以自行修改 | | authType | 固定为 cookie | | cookieName | cookie 中的 key | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiCookieAuth() // 默认使用 'cookie' 作为名称 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiCookieAuth()` 装饰器有默认值 `'cookie'`。如果配置文件中的 `name` 字段不是 `'cookie'`,需要在装饰器中显式指定相同的名称: ``` // 配置文件中 name 为 'testforcookie' 时 @ApiCookieAuth('testforcookie') @Controller('/hello') export class HelloController {} ``` ### apikey[​](#apikey "apikey的直接链接") apiKey 是 OpenAPI 里最灵活的认证模式。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'x-api-key', authType: 'apikey', in: 'header', description: 'ApiKey Auth', }, }, } ``` 字段描述 | **字段** | **说明** | | ----------------------- | ------------------------------------------------------------------------- | | name | 必选,你的 API Key 的字段名(header 里的名字 / query 参数名 / cookie 名) | | authType | 固定为 apikey,注意是小写 | | in | API Key 放在请求的哪个位置,可选值:header / query / cookie | | description | 可选,仅文档用途(swagger-ui 展示用) | | addSecurityRequirements | 可选,是否全局启用 | 在控制器层面生效。 ``` @ApiSecurity('api_key') // 必须指定名称,无默认值 @Controller('/hello') export class HelloController {} ``` **注意**:`@ApiSecurity()` 装饰器必须指定名称参数,与配置文件中的 `name` 字段保持一致。 ### custom 验证[​](#custom-验证 "custom 验证的直接链接") 自定义验证方式,需要自己设计参数配置 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { authType: 'custom', name: 'mycustom' // ... }, }, } ``` 在控制器层面生效。 ``` @ApiSecurity('mycustom') @Controller('/hello') export class HelloController {} ``` ### 全局开启验证[​](#全局开启验证 "全局开启验证的直接链接") 一般情况下仅对特定的路由开启验证,如需全局开启,可以在某个验证方式上添加 `addSecurityRequirements` 属性。 ``` // src/config/config.default.ts export default { // ... swagger: { auth: { name: 'BasicAuth', authType: 'basic', description: 'Basic Auth', addSecurityRequirements: true, }, }, } ``` ### 忽略验证[​](#忽略验证 "忽略验证的直接链接") 可以使用 `@ApiExcludeSecurity` 来忽略设置,支持类和方法。 ``` @Controller('/api') @ApiSecurity('api_key') class APIController { @Post('/update_user') async updateUser() { // ... } @Get('/get_user') @ApiExcludeSecurity() async getUser() { // ... } } ``` ## 更多配置[​](#更多配置 "更多配置的直接链接") ### 路由标签[​](#路由标签 "路由标签的直接链接") Swagger 可以对每个路由添加标签,进行分组。 标签添加有两种形式。 * 添加到控制器 * @ApiTags 和 @ApiOperation 默认情况下,框架会根据 Controller 的路径来生成标签,比如下面的代码,会生成一个 `hello` 的标签,这个标签会应用到这个控制器所有的路由上。 ``` @Controller('/hello') export class HelloController {} ``` 如果需要自定义标签,可以通过 `@ApiTags([...])` 来自定义 Controller 标签。 ``` @ApiTags(['hello']) @Controller('/hello') export class HelloController {} ``` 从 `v3.17.3` 开始,可以通过配置 `isGenerateTagForController` 来控制是否自动生成 Controller 标签。 ``` // src/config/config.default.ts export default { swagger: { isGenerateTagForController: false } } ``` 可以将 `@ApiTags` 标签直接加在路由方法上。 ``` // ... export class HomeController { @ApiTags(['bbb']) @Get('/') async home(): Promise { // ... } } ``` 也可以通过 `@ApiOperation` 来添加标签。 ``` // ... export class HomeController { @ApiOperation({ tags: ['bbb'] }) @Get('/') async home(): Promise { // ... } } ``` `@ApiTags` 的优先级比 `@ApiOperation` 更高,如果两者同时存在,`@ApiTags` 会覆盖 `@ApiOperation`。 同理,路由上的 `@ApiTags` 也会覆盖控制器上的 `@ApiTags`。 可以通过配置给 Tag 添加描述。 ``` // src/config/config.default.ts export default { swagger: { tags: [ { name: 'api', description: 'API Document' }, { name: 'hello', description: 'Other Router' }, ] } } ``` ### 忽略路由[​](#忽略路由 "忽略路由的直接链接") 配置 `@ApiExcludeController` 可以忽略整个 Controller 的路由。 ``` @ApiExcludeController() @Controller('/hello') export class HelloController {} ``` 配置 `@ApiExcludeEndpoint` 可以忽略单个路由。 ``` @Controller('/hello') export class HelloController { @ApiExcludeEndpoint() @Get() async getUser() { // ... } } ``` 如果需要满足更加动态的场景,可以通过配置路由过滤器来批量过滤。 ``` // src/config/config.default.ts import { RouterOption } from '@midwayjs/core'; export default { // ... swagger: { routerFilter: (url: string, options: RouterOption) => { return url === '/hello/getUser'; } }, } ``` `routerFilter` 用来传入一个过滤函数,包含 `url` 和 `routerOptions` 两个参数。`routerOptions` 中包含了路由基础信息。 每当匹配到一个路由时,会自动执行 `routerFilter` 方法,当 `routerFilter` 返回 true 时,代表这个路由将会被过滤。 ### 完整参数配置[​](#完整参数配置 "完整参数配置的直接链接") Swagger 组件提供了和 [OpenAPI](https://swagger.io/specification/) 一致的参数配置能力,可以通过自定义配置来实现。 配置项如下: ``` /** * see https://swagger.io/specification/ */ export interface SwaggerOptions { /** * 默认值: My Project * https://swagger.io/specification/#info-object title 字段 */ title?: string; /** * 默认值: This is a swagger-ui for midwayjs project * https://swagger.io/specification/#info-object description 字段 */ description?: string; /** * 默认值: 1.0.0 * https://swagger.io/specification/#info-object version 字段 */ version?: string; /** * https://swagger.io/specification/#info-object contact 字段 */ contact?: ContactObject; /** * https://swagger.io/specification/#info-object license 字段 */ license?: LicenseObject; /** * https://swagger.io/specification/#info-object termsOfService 字段 */ termsOfService?: string; /** * https://swagger.io/specification/#openapi-object externalDocs 字段 */ externalDocs?: ExternalDocumentationObject; /** * https://swagger.io/specification/#openapi-object servers 字段 */ servers?: Array; /** * https://swagger.io/specification/#openapi-object tags 字段 */ tags?: Array; /** * 可以参考 https://swagger.io/specification/#security-scheme-object */ auth?: AuthOptions | AuthOptions[]; /** * 默认值: /swagger-ui * 访问 swagger ui 的路径 */ swaggerPath?: string; /** * 对路由 tag 进行 ascii 排序 * 可以使用 1-xxx、2-xxx、3-xxx 来定义 tag */ tagSortable?: boolean; /** * UI 展示中需要用到的配置 * 可以参考 https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#display */ displayOptions?: { deepLinking?: boolean; displayOperationId?: boolean; defaultModelsExpandDepth?: number; defaultModelExpandDepth?: number; defaultModelRendering?: 'example' | 'model'; displayRequestDuration?: boolean; docExpansion?: 'list' | 'full' | 'none'; filter?: boolean | string; maxDisplayedTags?: number; showExtensions?: boolean; showCommonExtensions?: boolean; useUnsafeMarkdown?: boolean; tryItOutEnabled?: boolean; }; documentOptions?: { /** * 自定义 operationIdFactory,用于生成 operationId * @default () => controllerKey_webRouter.methodKey */ operationIdFactory?: ( controllerKey: string, webRouter: RouterOption ) => string; }; /** * 默认值: true * 是否复用 @midwayjs/validation DTO 元数据推导 Schema */ useValidationSchema?: boolean; } /** * 继承自 https://swagger.io/specification/#security-scheme-object */ export interface AuthOptions extends Omit { /** * 验权类型 * basic => http basic 验证 * bearer => http jwt 验证 * cookie => cookie 方式验证 * oauth2 => 使用 oauth2 * apikey => apiKey * custom => 自定义方式 */ authType: AuthType; /** * https://swagger.io/specification/#security-scheme-object type 字段 */ type?: SecuritySchemeType; /** * authType = cookie 时可以修改,通过 ApiCookie 装饰器关联的名称 */ securityName?: string; /** * authType = cookie 时可以修改,cookie 的名称 */ cookieName?: string; } ``` ## 装饰器列表[​](#装饰器列表 "装饰器列表的直接链接") 组件所有装饰器参考了 [@nestjs/swagger](https://github.com/nestjs/swagger) 的设计,都带 `Api` 前缀。这里列出全部装饰器: | 装饰器 | 支持模式 | | ----------------------- | ----------------- | | `@ApiBody` | Method | | `@ApiExcludeEndpoint` | Method | | `@ApiExcludeController` | Controller | | `@ApiHeader` | Controller/Method | | `@ApiHeaders` | Controller/Method | | `@ApiOperation` | Method | | `@ApiProperty` | Model Property | | `@ApiPropertyOptional` | Model Property | | `@ApiResponseProperty` | Model Property | | `@ApiQuery` | Method | | `@ApiResponse` | Method | | `@ApiTags` | Controller/Method | | `@ApiExtension` | Method | | `@ApiBasicAuth` | Controller/Method | | `@ApiBearerAuth` | Controller/Method | | `@ApiCookieAuth` | Controller/Method | | `@ApiOAuth2` | Controller/Method | | `@ApiSecurity` | Controller/Method | | `@ApiExcludeSecurity` | Controller/Method | | `@ApiParam` | Method | | `@ApiExtraModel` | Controller | ## UI 渲染[​](#ui-渲染 "UI 渲染的直接链接") ### 从 Swagger-ui-dist 渲染[​](#从-swagger-ui-dist-渲染 "从 Swagger-ui-dist 渲染的直接链接") 默认情况下,如果安装了 `swagger-ui-dist` 包,组件会默认会调用 `renderSwaggerUIDist` 渲染 swagger ui,如果需要传递 swagger-ui 的 options,可以 通过 `swaggerUIRenderOptions` 选项。 ``` // src/config/config.default.ts import { renderSwaggerUIDist } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderSwaggerUIDist, swaggerUIRenderOptions: { // ... } }, } ``` 如果希望调整 UI 的配置,可以使用自定义文件的方式替换默认的 `swagger-initializer.js`。 ``` // src/config/config.default.ts import { AppInfo } from '@midwayjs/core'; import { renderSwaggerUIDist } from '@midwayjs/swagger'; import { join } from 'path'; export default (appInfo: AppInfo) { return { // ... swagger: { swaggerUIRender: renderSwaggerUIDist, swaggerUIRenderOptions: { customInitializer: join(appInfo.appDir, 'resource/swagger-initializer.js'), } }, } } ``` 自定义的 `swagger-initializer.js` 内容大致如下: ``` window.onload = function() { window.ui = SwaggerUIBundle({ url: "/index.json", dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout", persistAuthorization: true, }); }; ``` 其中的 url 指向当前的 swagger json,可以自行修改,完整的 `swagger-ui` 配置请参考 [这里](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md)。 ### 从 unpkg 等 CDN 地址渲染[​](#从-unpkg-等-cdn-地址渲染 "从 unpkg 等 CDN 地址渲染的直接链接") 如果未安装 `swagger-ui-dist` 包,会自动使用 `renderSwaggerUIRemote` 方法进行渲染,默认由 `unpkg.com` 提供 cdn 资源。 ``` // src/config/config.default.ts import { renderSwaggerUIRemote } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderSwaggerUIRemote, swaggerUIRenderOptions: { // ... } }, } ``` ### 仅提供 Swagger JSON[​](#仅提供-swagger-json "仅提供 Swagger JSON的直接链接") 如果仅希望提供 Swagger JSON,可以配置 `renderJSON` 仅渲染 JSON ,无需引入 `swagger-ui-dist` 包。 ``` // src/config/config.default.ts import { renderJSON } from '@midwayjs/swagger'; export default { // ... swagger: { swaggerUIRender: renderJSON, }, } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### `@Get` 等路由注解中的 `summary` 或者 `description` 不生效[​](#get-等路由注解中的-summary-或者-description-不生效 "get-等路由注解中的-summary-或者-description-不生效的直接链接") 当存在 `@ApiOperation` 时候,将优先使用 `@ApiOperation` 中的 `summary` 或者 `description`,所以在 `@ApiOperation` 与 `@Get` 等路由注解中,只需要写一个即可。 --- # TableStore 本文介绍了如何使用 midway 接入阿里云 TableStore。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/tablestore@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/tablestore": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入组件,在 `configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as tablestore from '@midwayjs/tablestore'; import { join } from 'path' @Configuration({ imports: [ tablestore // 导入 tablestore 组件 ], importConfigs: [ join(__dirname, 'config') ] }) export class MainConfiguration { } ``` ## 配置[​](#配置 "配置的直接链接") 比如: **单客户端配置** ``` // src/config/config.default export default { // ... tableStore: { client: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, }, } ``` **多个客户端配置,需要配置多个** ``` // src/config/config.default export default { // ... tableStore: { clients: { db1: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, db2: { accessKeyId: '', secretAccessKey: '', stsToken: '', /*When you use the STS authorization, you need to fill in. ref:https://help.aliyun.com/document_detail/27364.html*/ endpoint: '', instancename: '' }, }, }, } ``` 更多参数可以查看 [aliyun tablestore sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk) 文档。 ## 使用 TableStore 服务[​](#使用-tablestore-服务 "使用 TableStore 服务的直接链接") 我们可以在任意的代码中注入使用。 ``` import { Provide, Controller, Inject, Get } from '@midwayjs/core'; import { TableStoreService } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async invoke() { await this.tableStoreService.putRow(params); } } ``` 可以使用 `TableStoreServiceFactory` 获取不同的实例。 ``` import { TableStoreServiceFactory } from '@midwayjs/tablestore'; import { join } from 'path'; @Provide() export class UserService { @Inject() tableStoreServiceFactory: TableStoreServiceFactory; async save() { const db1 = await this.tableStoreServiceFactory.get('db1'); const db2 = await this.tableStoreServiceFactory.get('db2'); //... } } ``` 示例:getRow ``` import { join } from 'path'; import { TableStoreService, Long, CompositeCondition, SingleColumnCondition, LogicalOperator, ComparatorType } from '@midwayjs/tablestore'; @Provide() export class UserService { @Inject() tableStoreService: TableStoreService; async getInfo() { const data = await tableStoreService.getRow({ tableName: "sampleTable", primaryKey: [{ 'gid': Long.fromNumber(20013) }, { 'uid': Long.fromNumber(20013) }], columnFilter: condition }); // TODO } } ``` 如示例所示,原有的 tablestore 包中导出的类型,应该都已经被 @midwayjs/tablestore 代理和接管,更多具体方法参数可以查看 [示例](https://github.com/midwayjs/midway/tree/2.x/packages/tablestore/test/sample)。 --- # 标签组件 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用标签组件。 ### 使用场景[​](#使用场景 "使用场景的直接链接") 标签是一种抽象化的服务端常用系统化能力,可用于多种用途,如: * 组织管理资源 * 实现分类系统(面向内容、人群等) * 资源管理系统 * 图片添加各种颜色标签、物体和场景标签,通过标签筛选图片 * 视频等素材标签 * 访问控制 * 权限系统(管理员、编辑、游客) * 状态系统(编辑中、已发布等) 基于标签系统提供的增删改查,以及通过标签,对绑定了标签的 `实体` 进行增删改查,能够很方便的实现更多高级的业务逻辑。 标签系统就是为了这种业务场景,让服务端基于标签能力,实现更高效、便捷的业务开发。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | ✅ | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | ### 如何使用?[​](#如何使用 "如何使用?的直接链接") 1. 安装依赖 ``` $ npm i @midwayjs/tags --save ``` 2. 在 configuration 中引入组件 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as tags from '@midwayjs/tags'; @Configuration({ imports: [ // ... tags ], }) export class MainConfiguration {} ``` 3. 添加配置 ``` // src/config/config.local.ts export default { tags: { clients: { 'tagGroup1': { // 使用 本机内存 作为数据存储 dialectType: 'memory', }, }, } } ``` 4. 在代码中调用 ``` // src/testTags.ts import { Provide, Inject, InjectClient } from '@midwayjs/core'; import { TagServiceFactory, TagClient } from '@midwayjs/tags'; @Provide() export class TestTagsService { @Inject() tags: TagServiceFactory; // 相当于 this.tags.get('tagGroup1') @InjectClient(TagServiceFactory, 'tagGroup1') tagClient: TagClient; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/tags/list', method: 'get'}) async listTags() { // 也可以直接使用 this.tagClient const tagClient: TagClient = this.tags.get('tagGroup1'); // add new tag const tagInfo = await tagClient.new({ name: 'test-tag-name', desc: 'tag desc', }); /* tagInfo = { success: true, id: 1, } */ // list top 20 tags const tags = await tagClient.list({ count: true }); /* tags: { list: [ { id: 1, name: 'test-tag-name', desc: 'tag desc' } ], total: 1 } */ return tags; } } ``` ### 方法[​](#方法 "方法的直接链接") #### 新增标签 new[​](#新增标签-new "新增标签 new的直接链接") ``` new(tagDefine: { // 标签名,在同一个 group 里面不能重复 name: string; // 标签描述 desc?: string; }): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 删除标签 remove[​](#删除标签-remove "删除标签 remove的直接链接") 删除标签也会删除和这个标签绑定的实体关系 ``` remove(tagIdOrName: number | string): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 更新标签 update[​](#更新标签-update "更新标签 update的直接链接") 更细一个标签的基础信息 ``` update(tagIdOrName: number | string, params: Partial< { name: string; desc?: string; }>): Promise<{ success: boolean; message: string; // 标签id id?: number; }>; ``` #### 列举标签 list[​](#列举标签-list "列举标签 list的直接链接") 搜索标签,支持分页 ``` list(listOptions?: { // 搜索的标签,支持传入标签 id 和标签名 tags?: Array; // 检索的时候标签是采用交集还是并集,取值为 and 和 or type?: MATCH_TYPE; count?: boolean; pageSize?: number; page?: number; }): Promise<{ // 标签列表 list: { id: number; name: string; desc: string; createAt: number; updateAt: number; }[]; // 标签总数 total?: number; }>; ``` #### 绑定实体 bind[​](#绑定实体-bind "绑定实体 bind的直接链接") 绑定实体的意思就是将其他的任何东西绑定到一个标签上,这里的实体可以是一张图片、也可以是一个文件,实体的id由用户自己控制 ``` bind(bindOptions: { // 标签列表 tags: Array; // 不存在标签的话自动创建标签,并绑定,默认为false autoCreateTag?: boolean; // 实体id objectId: number, }): Promise<{ success: boolean; message: string; }> ``` #### 解绑实体 unbind[​](#解绑实体-unbind "解绑实体 unbind的直接链接") ``` unbind(unbindOptions: { // 解绑的多个标签,标签id或者是标签 name tags: Array, // 实体id objectId: number, }): Promise<{ success: boolean; message: string; }> ``` #### 根据标签列举实体 listObjects[​](#根据标签列举实体-listobjects "根据标签列举实体 listObjects的直接链接") ``` listObjects(listOptions?: { // 标签id或者是标签 name tags?: Array; count?: boolean; // 检索的时候标签是采用交集还是并集,取值为 and 和 or type?: MATCH_TYPE; pageSize?: number; page?: number; }): Promise<{ // 实体的 id 列表 list: number[]; // 实体总数 total?: number; }>; ``` #### 根据实体获取标签 listObjectTags[​](#根据实体获取标签-listobjecttags "根据实体获取标签 listObjectTags的直接链接") ``` listObjectTags(listOptions?: { // 实体id objectId: number; count?: boolean; pageSize?: number; page?: number; }): Promise<{ list: { // 标签列表 name: string; desc?: string; id: number; createAt: number; updateAt: number; }[]; // 标签总数 total?: number; }>; ``` ### 配置[​](#配置 "配置的直接链接") Tags 支持内存存储(默认)和 mysql 数据库存储两种方式,下面是一个配置的示例: ``` // src/config/config.local.ts export default { tags: { clients: { 'tagGroup1': { // 使用 本机内存 作为数据存储 dialectType: 'memory', }, 'tagGroup2': { // 使用 mysql 作为数据存储 dialectType: 'mysql', // 自动同步表结构 sync: true, // mysql 连接实例 instance: mysqlConnection.promise(), }, }, } } ``` #### 内存存储配置[​](#内存存储配置 "内存存储配置的直接链接") | 配置 | 值类型 | 默认值 | 配置描述 | | ----------- | --------------- | ------ | ------------------------------- | | dialectType | string `memory` | - | 配置为 `memory`,则启用内存存储 | #### Mysql 存储配置[​](#mysql-存储配�置 "Mysql 存储配置的直接链接") 如果要使用 Mysql 数据库作为数据存储,那么需要将 Mysql 的 `数据库连接对象` 传入 tags 的配置中。 | 配置 | 值类型 | 默认值 | 配置描述 | | -------------- | ----------------------------------------------------------- | ------- | ---------------------------------------------------------------------- | | dialectType | string `mysql` | - | 配置为 `mysql`,则启用 Mysql 存储 | | sync | boolean | `false` | 自动同步 Tags 的表结构,Tags组件会创建两张数据表,详见下方的数据表信息 | | instance | `{ query: (sql: string, placeholder?: any[])}: Promise<[]>` | - | Mysql 连接的示例,需要提供一个 query 方法,可以查看下面的示例 | | tablePrefix | string | - | 数据表前缀 | | tableSeparator | string | `_` | 数据表的拼接分隔符 | 下面是使用 `mysql2` 这个 npm 包进行数据库连接的示例: ``` // src/config/config.local.ts const mysql = require('mysql2'); export default () => { const connection = mysql.createConnection({ host: 'db4free.net', user: 'tag***', password: 'tag***', database: 'tag***', charset: 'utf8', }); return { tags: { clients: { 'tagGroup': { dialectType: 'mysql', sync: true, instance: { // 包含 query 的mysql连接实例 query: (...args) => { return connection.promise().query(...args); } }, }, }, } } } ``` 你也可以考虑在 `configuration.ts` 中的 `onConfigLoad` 生命周期中进行数据库连接,这样的好处是在关闭时,可以关闭数据库连接: ``` // src/configuration.ts import { Config, Configuration } from '@midwayjs/core'; import { join } from 'path'; import * as tags from '@midwayjs/tags'; import { ITagMysqlDialectOption } from '@midwayjs/tags'; const mysql = require('mysql2'); @Configuration({ imports: [ tags ], }) export class MainConfiguration { connection; @Config() tags; async onConfigLoad(container) { // 创建 mysql 连接 this.connection = mysql.createConnection({ host: 'db4free.net', user: 'tag***', password: 'tag***', database: 'tag***', charset: 'utf8', }); let dialect: ITagMysqlDialectOption = { dialectType: 'mysql', sync: true, instance: { query: (...args) => { return this.connection.promise().query(...args); } } }; return { tags: dialect } } async onStop() { // 关闭 mysql 连接 this.connection.close(); } } ``` ##### 数据表信息[​](#数据表信息 "数据表信息的直接链接") Tags 组件需要两种数据表来存储数据,分别是 `tag` 和 `relationship`,这两张表在数据库中真实的表名,是通过配置中的 `表名前缀`、`表名分隔符` 和 `客户端名/分组名` 进行拼接的,例如: ``` const clientName = 'local-test'; const { tablePrefix = 'a', tableSeparator = '_' } = tagOptions; const tagTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}tag`; // tagTableName: a_local-test_tag const relationshipTableName = `${tablePrefix}${tableSeparator}${clientName}${tableSeparator}relationship` // relationshipTableName: a_local-test-relationship ``` 当你在配置中启用 `sync` 的自动表结构同步时,如果没有这两张表,就会根据下述的表结构创建对应的数据表: `tag` 表结构: ``` CREATE TABLE `tag` ( `id` BIGINT unsigned NOT NULL AUTO_INCREMENT, `group` varchar(32) NULL, `name` varchar(32) NULL, `descri` varchar(128) NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, `update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) ``` `relationship` 表结构: ``` CREATE TABLE `relationship` ( `id` BIGINT unsigned NOT NULL AUTO_INCREMENT, `tid` BIGINT unsigned NOT NULL, `oid` BIGINT unsigned NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, `update_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) ``` --- # 租户 这里介绍如何快速在 Midway 中使用租户组件。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 租户定义[​](#租户定义 "租户定义的直接链接") 租户管理是中后台业务开发过程中经常需要的功能。 在开发中,不同的用户需要保存在不同的数据源、命名空间或是区域中,这些不同的数据区域我们统称为 “租户”。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") `@midwayjs/tenant` 是主要的功能包。 ``` $ npm i @midwayjs/tenant@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/tenant": "^4.0.0", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 首先,引入 组件,在 `src/configuration.ts` 中导入: ``` import { Configuration } from '@midwayjs/core'; import * as tenant from '@midwayjs/tenant'; @Configuration({ imports: [ // ... tenant, ], }) export class MainConfiguration { } ``` ## 租户信息存取[​](#租户信息存取 "租户信息存取的直接链接") 不同的租户数据相互隔离,一般来说,每个用户数据都会关联相关的租户信息,在用户认证拿到用户信息之后,获取其对应的租户数据,以便后续数据读写使用。 在 Midway 中,可以将租户数据保存在请求对象 ctx 中,后续的所有请求作用域对象可以使用。但是租户信息仅仅在请求链路中使用是不够的,需要在不同的作用域都生效,这就需要新的架构来支持。 组件提供了一个 `TenantManager` 来管理租户信息。 你需要在每个请求链路中保存租户信息,之后才能获取。 租户信息的格式可以按需求定义。 比如: ``` interface TenantInfo { id: string; name: string; } ``` 比如,在中间件中保存。 ``` import { TenantManager } from '@midwayjs/tenant'; import { Middleware, Inject } from '@midwayjs/core'; @Middleware() class TenantMiddleware { @Inject() tenantManager: TenantManager; resolve() { return async(ctx, next) => { // 请求链路中设置租户信息 await this.tenantManager.setCurrentTenant({ id: '123', name: '我的租户' }); } } } ``` 在后续的单例服务中获取。 ``` import { TenantManager } from '@midwayjs/tenant'; import { Inject, Singleton } from '@midwayjs/core'; import { TenantInfo } from '../interface'; @Singleton() class TenantService { @Inject() tenantManager: TenantManager; async getTenantInfo() { const tenantInfo = await this.tenantManager.getCurrentTenant(); if (tenantInfo) { console.log(tenantInfo.name); // output => 我的租户 } } } ``` 提示 * 1、租户信息一定会关联请求,如有需求,你可以在不同的 Framework 中都加入中间件 * 2、每个请求保存的租户信息是隔离的 * 3、不管是单例还是请求作用域,你都仅能获取到当前请求对应的租户数据 --- # 文件上传 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用上传组件,支持 `file` (服务器临时文件) 和 `stream` (流)两种模式。 相关信息: | web 支持情况 | | | ----------------- | -- | | @midwayjs/koa | ✅ | | @midwayjs/faas | 💬 | | @midwayjs/web | ✅ | | @midwayjs/express | ✅ | 警告 💬 部分函数计算平台不支持流式请求响应,请参考对应平台能力。 ## 安装依赖[​](#安装依赖 "安装依�赖的直接链接") ``` $ npm i @midwayjs/upload@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/upload": "^4.0.0", // ... }, "devDependencies": { // ... } } ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") ``` import { Configuration } from '@midwayjs/core'; import * as upload from '@midwayjs/upload'; @Configuration({ imports: [ // ...other components upload ], // ... }) export class MainConfiguration {} ``` 3、在代码中获取上传的文件 ``` import { Controller, Inject, Post, Files, Fields } from '@midwayjs/core'; @Controller('/') export class HomeController { @Inject() ctx; @Post('/upload') async upload(@Files() files, @Fields() fields) { /* files = [ { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // mode 为 file 时为服务器临时文件地址 fieldname: 'test1', // 表单 field 名 mimeType: 'application/pdf', // mime }, { filename: 'test.pdf', // 文件原名 data: ReadStream, // mode 为 stream 时为服务器临时文件地址 fieldname: 'test2', // 表单 field 名 mimeType: 'application/pdf', // mime }, // ...file 下支持同时上传多个文件 ] */ return { files, fields } } } ``` 警告 如果同时开启了 swagger 组件,请务必添加上传参数的类型(装饰器对应的类型,以及 @ApiBody 中的 type),否则会报错,更多请参考 swagger 的文件上传章节。 ## 配置[​](#配置 "配置的直接链接") ### 默认配置[​](#默认配置 "默认配置的直接链接") 默认配置如下,一般情况下无需修改。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { // mode: UploadMode, 默认为file,即上传到服务器临时目录,可以配置为 stream mode: 'file', // fileSize: string, 最大上传文件大小,默认为 10mb fileSize: '10mb', // whitelist: string[],文件扩展名白名单 whitelist: uploadWhiteList.filter(ext => ext !== '.pdf'), // tmpdir: string,上传的文件临时存储路径 tmpdir: join(tmpdir(), 'midway-upload-files'), // cleanTimeout: number,上传的文件在临时目录中多久之后自动删除,默认为 5 分钟 cleanTimeout: 5 * 60 * 1000, // base64: boolean,设置原始body是否是base64格式,默认为false,一般用于腾讯云的兼容 base64: false, // 仅在匹配路径到 /api/upload 的时候去解析 body 中的文件信息 match: /\/api\/upload/, }, } ``` ### 上传模式 - file[​](#上传模式---file "上传模式 - file的直接链接") `file` 为默认值,也是框架的推荐值。 配置 upload 的 mode 为 `file` 字符串,或使用 `@midwayjs/upload` 包导出的 `UploadMode.File` 来配置。 使用 file 模式时,通过 `this.ctx.files` 中获取的 `data` 为上传的文件在服务器的 `临时文件地址`,后续可以再通过 `fs.createReadStream` 等方式来获取到此文件内容。 使用 file 模式时,支持同时上传多个文件,多个文件会以数组的形式存放在 `this.ctx.files` 中。 警告 当采取 `file` 模式时,由于上传组件会在接收到请求时,会根据请求的 `method` 和 `headers` 中的部分标志性内容进行匹配,如果认为是一个文件上传请求,就会对请求进行解析,将其中的文件 `写入` 到服务器的临时缓存目录,您可以通过本组件的 `match` 或 `ignore` 配置来设置允许解析文件的路径。 配置 `match` 或 `ignore`后,则可以保证您的普通 post 等请求接口,不会被用户非法用作上传,可以 `避免` 服务器缓存被充满的风险。 您可以查看下面的 `配置 允许(match) 或 忽略(ignore)的上传路径` 章节,来进行配置。 ### 上传模式 - stream[​](#上传模式---stream "上传模式 - stream的直接链接") 配置 upload 的 mode 为 `stream` 字符串,或使用 `@midwayjs/upload` 包导出的 `UploadMode.Stream` 来配置。 使用 stream 模式时,通过 `this.ctx.files` 中获取的 `data` 为 `ReadStream`,后续可以再通过 `pipe` 等方式继续将数据流转至其他 `WriteStream` 或 `TransformStream`。 使用 stream 模式时,仅同时上传一个文件,即 `this.ctx.files` 数组中只有一个文件数据对象。 另外,stream 模式 `不会` 在服务器上产生临时文件,所以获取到上传的内容后无需手动清理临时文件缓存。 提示 faas 场景实现方式视平台而定,如果平台不支持流式请求/响应但是业务开启了 `mode: 'stream'`,将采用先读取到内存,再模拟流式传输来降级处理。 ### 上传白名单[​](#上传白名单 "上传白名单的直接链接") 通过 `whitelist` 属性,配置允许上传的文件后缀名,配置 `null` 则不校验后缀名。 警告 如果配置为 `null`,则不对上传文件后缀名进行校验,如果采取文件上传模式 (mode=file),则会有可能被攻击者所利用,上传 `.php`、`.asp` 等后缀的 WebShell 实现攻击行为。 当然,由于 `@midwayjs/upload` 组件会对上传后的临时文件采取 `重新随机生成` 文件名写入,只要开发者 `不将` 上传后的临时文件地址返回给用户,那么即使用户上传了一些不被预期的文件,那也无需过多担心会被利用。 如果上传的文件后缀不匹配,会响应 `400` error,默认值如下: ``` '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.wbmp', '.webp', '.tif', '.psd', '.svg', '.js', '.jsx', '.json', '.css', '.less', '.html', '.htm', '.xml', '.pdf', '.zip', '.gz', '.tgz', '.gzip', '.mp3', '.mp4', '.avi', ``` 可以通过 `@midwayjs/upload` 包中导出的 `uploadWhiteList` 获取到默认的后缀名白名单。 另外,midway 上传组件,为了避免部分 `恶意用户`,通过某些技术手段来`伪造`一些可以被截断的扩展名,所以会对获取到的扩展名的二进制数据进行过滤,仅支持 `0x2e`(即英文点 `.`)、`0x30-0x39`(即数字 `0-9`)、`0x61-0x7a`(即小写字母 `a-z`) 范围内的字符作为扩展名,其他字符将会被自动忽略。 从 v3.14.0 开始,你可以传递一个函数,可以根据不同的条件动态返回白名单。 ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { whitelist: (ctx) => { if (ctx.path === '/') { return [ '.jpg', '.jpeg', ]; } else { return [ '.jpg', ] }; }, // ... }, } ``` ### MIME 类型检查[​](#mime-类型检查 "MIME 类型检查的直接链接") 部分`恶意用户`,会尝试将 `.php` 等 WebShell 修改扩展名为 `.jpg`,来绕过基于扩展名的白名单过滤规则,在某些服务器环境内,这个 jpg 文件依然会被作为 PHP 脚本来执行,造成安全风险。 因此,`@midwayjs/upload` 组件提供了 `mimeTypeWhiteList` 配置参数 **【请注意,此参数无默认值设置,即默认不校验】**,您可以通过此配置设置允许的文件 MIME 格式,规则为由数组 `[扩展名, mime, [...moreMime]]` 组成的 `二级数组`,例如: ``` // src/config/config.default.ts import { uploadWhiteList } from '@midwayjs/upload'; export default { // ... upload: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: { '.jpg': 'image/jpeg', // 也可以设置多个 MIME type,比如下面的允许 .jpeg 后缀的文件是 jpg 或者是 png 两种类型 '.jpeg': ['image/jpeg', 'image/png'], // 其他类型 '.gif': 'image/gif', '.bmp': 'image/bmp', '.wbmp': 'image/vnd.wap.wbmp', '.webp': 'image/webp', } }, } ``` 您也可以使用 `@midwayjs/upload` 组件提供的 `DefaultUploadFileMimeType` 变量,作为默认的 MIME 校验规则,它提供了常用的 `.jpg`、`.png`、`.psd` 等文件扩展名的 MIME 数据: ``` // src/config/config.default.ts import { uploadWhiteList, DefaultUploadFileMimeType } from '@midwayjs/upload'; export default { // ... upload: { // ... // 扩展名白名单 whitelist: uploadWhiteList, // 仅允许下面这些文件类型可以上传 mimeTypeWhiteList: DefaultUploadFileMimeType, }, } ``` 文件格式与对应的 MIME 映射,您可以通过 `https://mimetype.io/` 这个网站来查询,对于文件的 MIME 识别,我们使用的是 [file-type@16](https://www.npmjs.com/package/file-type) 这个 npm 包,请注意它支持的文件类型。 信息 MIME 类型校验规则仅适用于使用 文件上传模式 `mode=file`,同时设置此校验规则之后,由于需要读取文件内容进行匹配,所以会稍微影响上传性能。 但是,我们依然建议您在条件允许的情况下,设置 `mimeTypeWhiteList` 参数,这将提升您的应用程序安全性。 从 v3.14.0 开始,你可以传递一个函数,可以根据不同的条件动态返回 MIME 规则。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { mimeTypeWhiteList: (ctx) => { if (ctx.path === '/') { return { '.jpg': 'image/jpeg', }; } else { return { '.jpeg': ['image/jpeg', 'image/png'], } }; } }, } ``` ### 配置 match 或 ignore[​](#配置-match-或-ignore "配置 match 或 ignore的直接链接") 当开启了 upload 组件后,当请求的 `method` 为 `POST/PUT/DELETE/PATCH` 之一时,如果判断请求的 `headers['content-type']` 中包含 `multipart/form-data` 及 `boundary` 时,将会 `**自动进入**` 上传文件解析逻辑。 这会造成:如果用户可能手动分析了网站的请求信息,手动调用任一一个 `post` 等类型的接口,将一个文件进行上传,就会触发 `upload` 组件的解析逻辑,在临时目录创建临时的已上传文件缓存,对网站服务器产生不必要的`负荷`,严重时可能会`影响`服务器正常业务逻辑处理。 所以,您可以在配置中添加 `match` 或 `ignore` 配置,来设置哪些 api 路径是允许进行上传的。 ### 同名 Field[​](#同名-field "同名 Field的直接链接") 从 v3.16.6 开始,组件支持同名 Field。 ``` // src/config/config.default.ts import { tmpdir } from 'os'; import { join } from 'path'; export default { // ... upload: { allowFieldsDuplication: true }, } ``` 开启 `allowFieldsDuplication` 之后,同名的 Field 会被合并为数组。 ``` import { Controller, Inject, Post, Files, Fields } from '@midwayjs/core'; @Controller('/') export class HomeController { @Post('/upload') async upload(@Files() files, @Fields() fields) { /* fields = { name: ['name1', 'name2'], otherName: 'nameOther' // ... } */ } } ``` ## 临时文件与清理[​](#临时文件与清理 "临时文件与清理的直接链接") 如果你使用了 `file` 模式来获取上传的文件,那么上传的文件会存放在您于 `config` 文件中设置的 `upload` 组件配置中的 `tmpdir` 选项指向的文件夹内。 你可以通过在配置中使用 `cleanTimeout` 来控制自动的临时文件清理时间,默认值为 `5 * 60 * 1000`,即上传的文件于 `5 分钟` 后自动清理,设置为 `0` 则视为不开启自动清理功能。 你也可以在代码中通过调用 `await ctx.cleanupRequestFiles()` 来主动清理当前请求上传的临时文件。 ## 安全提示[​](#安全提示 "安全提示的直接链接") 1. 请注意是否开启 `扩展名白名单` (whiteList),如果扩展名白名单被设置为 `null`,则会有可能被攻击者所利用上传 `.php`、`.asp` 等WebShell。 2. 请注意是否设置 `match` 或 `ignore` 规则,否则普通的 `POST/PUT` 等接口会有可能被攻击者利用,造成服务器负荷加重和空间大量占用问题。 3. 请注意是否设置 `文件类型规则` (fileTypeWhiteList),否则可能会被攻击者伪造文件类型进行上传。 ## 前端文件上传示例[​](#前端文件上传示例 "前端文件上传示例的直接链接") ### 1. html form 的形式[​](#1-html-form-的形式 "1. html form 的形式的直接链接") ```
Name:
File:
``` ### 2. fetch FormData 方式[​](#2-fetch-formdata-方式 "2. fetch FormData 方式的直接链接") ``` const fileInput = document.querySelector('#your-file-input') ; const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData, }); ``` ## Postman 测试示例[​](#postman-测试示例 "Postman 测试示例的直接链接") ![](https://img.alicdn.com/imgextra/i4/O1CN01iv9ESW1uIShNiRjBF_!!6000000006014-2-tps-2086-1746.png) --- # 参数校验 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型,这个能力来源于 [joi](https://joi.dev/api/) 。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 背景[​](#背景 "背景的直接链接") 最常用参数校验的地方是 控制器(Controller),同时你也可以在任意的 Class 中使用这个能力。 我们以控制器(Controller)中使用为例,还是那个 user。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ └── user.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 普通情况下,我们从 `body` 上拿到所有 Post 结果,并进行一些校验。 ``` // src/interface.ts export interface User { id: number; firstName: string; lastName: string; age: number; } // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: User) { if (!user.id || typeof user.id !== 'number') { throw new Error('id error'); } if (user.age <= 30) { throw new Error('age not match'); } // xxx } } ``` 如果每个方法都需要这么校验,会非常的繁琐。 针对这种情况,Midway 提供了 Validate 组件。 配合 `@Validate` 和 `@Rule` 装饰器,用来 **快速定义校验的规则**,帮助用户 **减少这些重复的代码**。 注意,从 v3 开始,`@Rule` 和 `@Validate` 装饰器从 `@midwayjs/validate` 中导出。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") ``` $ npm i @midwayjs/validate@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/validate": "^4.0.0" // ... }, "devDependencies": { // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `configuration.ts` 中增加组件。 ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as validate from '@midwayjs/validate'; import { join } from 'path'; @Configuration({ imports: [koa, validate], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... } } ``` ## 定义检查规则[​](#定义检查规则 "定义检查规则的直接链接") 按照上面的逻辑,我们需要 **重新定义一个新的 Class**,因为装饰器只能装饰在实际的 Class 上,而不是 interface。 为了方便后续处理,我们将 user 放到一个 `src/dto` 目录中。 > Data Transfer Object(数据传输对象)DTO 是一组需要跨进程或网络边界传输的聚合数据的简单容器。它不应该包含业务逻辑,并将其行为限制为诸如内部一致性检查和基本验证之类的活动。 ``` // src/dto/user.ts import { Rule, RuleType } from '@midwayjs/validate'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } ``` 由于这个类属于一个 `PlainObject` ,也不需要被依赖注入管理,我们不需要提供 `@Provide` 装饰器。 这个 User Class 提供了三个属性和他们对应的校验规则。 * `id` 一个必填的数字类型 * `firstName` 一个必填的字符串类型 * `lastName` 一个可选的最长为 10 的字符串类型 * `age` 一个最大不超过 60 的数字 `@Rule` 装饰器用于 **修饰需要被校验的属性**,它的参数为 `RuleType` 对象提供的校验规则的链式方法。 信息 这里的 `RuleType` 即为 joi 对象本身。 [joi](https://joi.dev/api/) 提供了非常多的校验类型,还可以对对象和数组中的字段做校验,还有例如字符串常用的 `RuleType.string().email()` ,以及 `RuleType.string().pattern(/xxxx/)` 正则校验等,具体可以查询 [joi](https://joi.dev/api/) 的 API 文档。 ## 校验参数[​](#校验参数 "校验参数的直接链接") 定义完类型之后,就可以直接在业务代码中使用了。 ``` // src/controller/home.ts import { Controller, Get, Provide, Body } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO) { // user.id } } ``` 所有的校验代码都通通不见了,业务变的更纯粹了,当然,记得要把原来的 user interface 换成 Class。 一旦校验失败,浏览器或者控制台就会报出类似的错误。 ``` ValidationError: "id" is required ``` 同时,由于定义了 `id` 的类型,在拿到字符串的情况下,会自动将 id 变为数字。 ``` async updateUser(@Body() user: UserDTO ) { // typeof user.id === 'number' } ``` 如果需要对方法级别单独配置信息,可以使用 `@Validate` 装饰器,比如单独配置错误状态。 ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; import { Validate } from '@midwayjs/validate'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') @Validate({ errorStatus: 422, }) async updateUser(@Body() user: UserDTO) { // user.id } } ``` 一般情况下,使用全局默认配置即可。 ## 通用场景校验[​](#通用场景校验 "通用场景校验的直接链接") 如果参数不是 DTO,可以使用 `@Valid` 装饰器进行校验,`@Valid` 装饰器可以直接传递一个 Joi 规则。 ``` // src/controller/home.ts import { Controller, Get, Query } from '@midwayjs/core'; import { Valid, RuleType } from '@midwayjs/validate'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Get('/') async getUser(@Valid(RuleType.number().required()) @Query('id') id: number) { // ... } } ``` 在非 Web 场景下,没有 `@Body` 等 Web 类装饰器的情况下,也可以使用 `@Valid` 装饰器来进行校验,如果不传参数,也会复用 DTO 规则。 比如在服务中: ``` import { Valid } from '@midwayjs/validate'; import { Provide } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Provide() export class UserService { async updateUser(@Valid() user: UserDTO) { // ... } } ``` 如果参数不是 DTO,不存在规则,也可以通过参数传递一个 Joi 格式的校验规则。 ``` import { Valid, RuleType } from '@midwayjs/validate'; import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async updateUser(@Valid(RuleType.number().required()) userAge: number) { // ... } } ``` ## 校验管道[​](#校验管道 "校验管道的直接链接") 如果你的参数是基础类型,比如 `number`, `string`, `boolean`,则可以使用组件提供的管道进行校验。 默认的 Web 参数装饰器都可以在第二个参数传入管道。 比如: ``` import { ParseIntPipe } from '@midwayjs/validate'; import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number) { // ... } } ``` `ParseIntPipe` 管道可以将字符串,数字数据转换为数字,这样从请求参数获取到的 `age` 字段则会通过管道的校验并转换为数字格式。 可以使用 的内置管道有: * `ParseIntPipe` * `ParseFloatPipe` * `ParseBoolPipe` * `DefaultValuePipe` `ParseIntPipe` 用于将参数转为整形数字。 ``` import { ParseIntPipe } from '@midwayjs/validate'; // ... async update(@Body('age', [ParseIntPipe]) age: number) { return age; } update({ age: '12'} ); => 12 update({ age: '12.2'} ); => Error update({ age: 'abc'} ); => Error ``` `ParseFloatPipe` 用于将参数转为浮点型数字数字。 ``` import { ParseFloatPipe } from '@midwayjs/validate'; // ... async update(@Body('size', [ParseFloatPipe]) size: number) { return size; } update({ size: '12.2'} ); => 12.2 update({ size: '12'} ); => 12 ``` `ParseBoolPipe` 用于将参数转为布尔值。 ``` import { ParseBoolPipe } from '@midwayjs/validate'; // ... async update(@Body('isMale', [ParseBoolPipe]) isMale: boolean) { return isMale; } update({ isMale: 'true'} ); => true update({ isMale: '0'} ); => Error ``` `DefaultValuePipe` 用于设定默认值。 ``` import { DefaultValuePipe } from '@midwayjs/validate'; // ... async update(@Body('nickName', [new DefaultValuePipe('anonymous')]) nickName: string) { return nickName; } update({ nickName: undefined} ); => 'anonymous' ``` ## 自定义校验管道[​](#自定义校验管道 "自定义校验管道的直接链接") 如果默认的管道不满足需求,可以通过继承,快速实现一个自定义校验管道,组件已经提供了一个 `ParsePipe` 类用于快速编写。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validate'; @Pipe() export class ParseCustomDataPipe extends ParsePipe { getSchema(): RuleType.AnySchema { // ... } } ``` `getSchema` 方法用于返回一个符合 `Joi` 格式的校验规则。 比如 `ParseIntPipe` 的代码如下,管道执行时会自动获取这个 schema 进行校验,并在校验成功后将值返回。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validate'; @Pipe() export class ParseIntPipe extends ParsePipe { getSchema() { return RuleType.number().integer().required(); } } ``` ## 校验规则[​](#校验规则 "校验规则的直接链接") ### 常见的校验写法[​](#常见的校验写法 "常见的校验写法的直接链接") ``` RuleType.number().required(); // 数字,必填 RuleType.string().empty(''); // 字符串非必填 RuleType.number().max(10).min(1); // 数字,最大值和最小值 RuleType.number().greater(10).less(50); // 数字,大于 10,小于 50 RuleType.string().max(10).min(5); // 字符串,长度最大 10,最小 5 RuleType.string().length(20); // 字符串,长度 20 RuleType.string().pattern(/^[abc]+$/); // 字符串,匹配正则格式 RuleType.object().length(5); // 对象,key 数量等于 5 RuleType.array().items(RuleType.string()); // 数组,每个元素是字符串 RuleType.array().max(10); // 数组,最大长度为 10 RuleType.array().min(10); // 数组,最小长度为 10 RuleType.array().length(10); // 数组,长度为 10 RuleType.string().allow(''); // 非必填字段传入空字符串 export enum DeviceType { iOS = 'ios', Android = 'android', } RuleType.string().valid(...Object.values(DeviceType)) // 根据枚举值校验 ``` ### 级联校验[​](#级联校验 "级联校验的直接链接") Midway 支持每个校验的 Class 中的属性依旧是一个对象。 我们给 `UserDTO` 增加一个属性 `school` ,并且赋予一个 `SchoolDTO` 类型。 ``` import { Rule, RuleType, getSchema } from '@midwayjs/validate'; export class SchoolDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.string()) address: string; } export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; // 复杂对象 @Rule(getSchema(SchoolDTO).required()) school: SchoolDTO; // 对象数组 @Rule(RuleType.array().items(getSchema(SchoolDTO)).required()) schoolList: SchoolDTO[]; } ``` 这个时候, `@Rule` 装饰器的参数可以为需要校验的这个类型本身。 ### 继承校验[​](#继承校验 "继承校验的直接链接") Midway 支持校验继承方式,满足开发者抽离通用的对象属性的时候做参数校验。 例如我们下面 `CommonUserDTO` 抽离接口的通用的一些属性,然后 `UserDTO` 作为特殊接口需要的特定参数。 ``` import { Rule, RuleType } from '@midwayjs/validate'; export class CommonUserDTO { @Rule(RuleType.string().required()) token: string; @Rule(RuleType.string()) workId: string; } export class UserDTO extends CommonUserDTO { @Rule(RuleType.string().required()) name: string; } ``` 老版本需要在子类上面加,新版本不需要啦~ 信息 如果属性名相同,则取当前属性的规则进行校验,不会和父类合并。 ### 多类型校验[​](#多类型校验 "多类型校验的直接链接") 从 v3.4.5 开始,Midway 支持某个属性的不同类型的校验。 例如某个类型,既可以是可以普通类型,又可以是一个复杂类型。 ``` import { Rule, RuleType, getSchema } from '@midwayjs/validate'; export class SchoolDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.string()) address: string; } export class UserDTO { @Rule(RuleType.string().required()) name: string; @Rule(RuleType.alternatives([RuleType.string(), getSchema(SchoolDTO)]).required()) school: string | SchoolDTO; } ``` 我们可以使用 `getSchema` 方法,从某个 DTO 拿到当前的 joi schema,从而进行复杂的逻辑处理。 ### 从原有 DTO 创建新 DTO[​](#从原有-dto-创建新-dto "从原有 DTO 创建新 DTO的直接链接") 有时候,我们会希望从某个 DTO 中获取一部分属性,变成一个新的 DTO 类。 Midway 提供了 `PickDto` 和 `OmitDto` 两个方法根据现有的的 DTO 类型创建新的 DTO。 `PickDto` 用于从现有的 DTO 中获取一些属性,变成新的 DTO,而 `OmitDto` 用于将其中某些属性剔除,比如: ``` // src/dto/user.ts import { Rule, RuleType, PickDto } from '@midwayjs/validate'; export class UserDTO { @Rule(RuleType.number().required()) id: number; @Rule(RuleType.string().required()) firstName: string; @Rule(RuleType.string().max(10)) lastName: string; @Rule(RuleType.number().max(60)) age: number; } // 继承出一个新的 DTO export class SimpleUserDTO extends PickDto(UserDTO, ['firstName', 'lastName']) {} // const simpleUser = new SimpleUserDTO(); // 只包含了 firstName 和 lastName 属性 // simpleUser.firstName = xxx export class NewUserDTO extends OmitDto(UserDTO, ['age']) {} // const newUser = new NewUserDTO(); // newUser.age 定义和属性都不存在 // 使用 async login(@Body() user: NewUserDTO) { // ... } ``` ### 复用校验规则[​](#复用校验规则 "复用校验规则的直接链接") 如果很多字段都是字符串必填,或者类似需求,写 `RuleType.string().required()` 有点长,可以将重复的部分赋值为新的规则对象,进行复用。 ``` // 自己在一个文件中定义一下你们部门的规范或常用的 const requiredString = RuleType.string().required(); export class UserDTO { @Rule(requiredString) // 这样就不用写上面这么长的了 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; } // 自己在一个文件中定义一下你们部门的规范或常用的 const maxString = (length) => RuleType.string().max(length); export class UserDTO { @Rule(requiredString) // 同上 name: string; @Rule(requiredString) // 同上 nickName: string; @Rule(requiredString) // 同上 description: string; @Rule(maxString(50)) // 这样通过换个参数即可 info: string; @Rule(maxString(50).required()) // 这样也行 info2: string; } ``` ## 多语言[​](#多语言 "多语言的直接链接") 在 Validate 中,同时依赖了 [i18n](/docs/extensions/i18n.md) 组件来实现校验消息的国际化。 默认情况下,提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,所以在请求失败时,会返回当前浏览器访问所指定的语言。 ### 通过装饰器指定语言[​](#通过装饰器指定语言 "通过装饰器指定语言的直接链接") 默认情况下,会跟着 i18n 组件的 `defaultLocale` 以及浏览器访问语言的情况来返回消息,不过,我们可以在装饰器中指定当前翻译的语言,比如: ``` @Controller('/user') export class UserController { @Post('/') @Validate({ locale: 'en_US', }) async getUser(@Body() bodyData: UserDTO) { // ... } } ``` ### 通过参数指定语言[​](#通过参数指定语言 "通过参数指定语言的直接链接") 除了装饰器指定,我们也可以使用标准的 i18n 通过参数指定语言的方式。 比如 Query 参数。 ``` Get /user/get_user?locale=zh_CN ``` 更多的参数用法请参考 [i18n](/docs/extensions/i18n.md) 组件。 ### 其他语言的翻译[​](#其他语言的翻译 "其他语言的翻译的直接链接") 默认情况下,Midway 提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,如果还需要额外的翻译,可以配置在 i18n 中。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { // 增加翻译 zh_TW: { validate: require('../../locales/zh_TW.json'), }, }, }; ``` 如果可以的话,我们希望你将翻译提交给 Midway 官方,让大家都能使用。 ## 自定义错误文本[​](#自定义错误文本 "自定义错误文本的直接链接") ### 指定单个规则的文本[​](#指定单个规则的文本 "指定单个规则的文本的直接链接") 如果只想定义某个 DTO 中某个规则的错误消息,可以简单指定。 ``` export class UserDTO { @Rule(RuleType.number().required().error(new Error('my custom message'))) id: number; } ``` 这个 `id` 属性上的所有规则,只要有验证失败的,都会返回你的自定义消息。 ### 全局指定部分文本[​](#全局指定部分文本 "全局指定部分文本的直接链接") 通过配置 i18n 组件的 `validate` 多语言文本表,你可以选择性的替换大部分的校验文本,所有的规则都会应用该文本。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { zh_CN: { validate: { 'string.max': 'hello world', }, }, }, }, }; ``` 这里的 `validate` 是 `@midwayjs/validate` 组件在 i18n 组件中配置的语言表关键字。 由于 [默认的语言表](https://github.com/midwayjs/midway/tree/main/packages/validate/locales) 也是对象形式,我们可以很方便的找到其中的字段,进行替换。 由于这些文本区分语言,所以需要谨慎处理,比如,替换不同的语言。 ``` // src/config/config.default.ts export default { // ... i18n: { // 把你的翻译文本放到这里 localeTable: { zh_CN: { validate: { 'string.max': '字符超长', }, }, en_US: { validate: { 'string.max': 'string is too long', }, }, }, }, }; ``` ### 完全自定义错误文本[​](#完全自定义错误文本 "完全自定义错误文本的直接链接") 如果希望完全自定义错误文本,可以通过替换内置的语言翻译文本来解决。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { localeTable: { // 替换中文翻译 zh_CN: { validate: require('../../locales/custom.json'), }, }, }, }; ``` ## 默认配置[​](#默认配置 "默认配置的直接链接") 我们可以对 validate 组件做一些配置。 | 配置项 | 类型 | 描述 | | ----------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | errorStatus | number | 当校验出错时,返回的 Http 状态码,在 http 场景生效,默认 422 | | locale | string | 校验出错文本的默认语言,当前有 `en_US` 和 `zh_CN` 两种,默认为 `en_US`,会根据 i18n 组件的规则切换 | | validationOptions | joi 的 ValidationOptions 选项 | 常用的有 allowUnknown,stripUnknown 等选项,如果配置,那么全局的校验都允许出现没有定义的字段,更多的请查看 joi 的 [ValidationOptions 选项](https://joi.dev/api/?v=17.6.0#anyvalidatevalue-options)。 | ## 独立的校验服务[​](#独立的校验服务 "独立的校验服务的直接链接") 组件底层提供了单例的 `ValidateService` 校验服务类,如有必要,可以在中间件或者独立的服务中使用。事实上,所有的校验装饰器,最终都会走到这个方法。 `ValidateService` 提供了一个 `validate` 方法,用于校验 DTO。 我们以上面定义的 `UserDTO` 为例。 ``` import { ValidateService } from '@midwayjs/validate'; export class UserService { @Inject() validateService: ValidateService; async inovke() { // ... const result = this.validateService.validate(UserDTO, { name: 'harry', nickName: 'harry', }); // 失败返回 result.error // 成功返回 result.value } } ``` `validate` 方法返回的 result 包含 `error` 和 `value` 两个属性。失败会返回 `MidwayValidationError` 错误,成功会返回格式化好的 DTO 对象。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、允许未定义的字段[​](#1允许未定义的字段 "1、允许未定义的字段的直接链接") 由于部分用户在参数校验的时候,希望允许出现没有定义的字段,可以在全局配置,以及装饰器上分别设置,前者对全局生效,后者对单个校验生效。 ``` // src/config/config.default.ts export default { // ... validate: { validationOptions: { allowUnknown: true, // 全局生效 }, }, }; ``` 或者在装饰器上。 ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate({ validationOptions: { allowUnknown: true, }, }) async updateUser(@Body() user: UserDTO) { // user.id } } ``` ### 2、剔除参数中的未定义属性[​](#2剔除参数中的未定义属性 "2、剔除参数中的未定义属性的直接链接") 也同样是 validationOptions 的属性,可以直接剔除传入的参数中的某些属性。 ``` // src/config/config.default.ts export default { // ... validate: { validationOptions: { stripUnknown: true, // 全局生效 }, }, }; ``` 或者在装饰器上。 ``` @Controller('/api/user') export class HomeController { @Post('/') @Validate({ validationOptions: { stripUnknown: true, }, }) async updateUser(@Body() user: UserDTO) {} } ``` ### 3、处理校验错误[​](#3处理校验错误 "3、处理校验错误的直接链接") 上面提到,Midway 会在校验失败时抛出 `MidwayValidationError` 错误,我们可以在 [异常处理器](/docs/error_filter.md) 中处理。 比如: ``` // src/filter/validate.filter import { Catch } from '@midwayjs/core'; import { MidwayValidationError } from '@midwayjs/validate'; import { Context } from '@midwayjs/koa'; @Catch(MidwayValidationError) export class ValidateErrorFilter { async catch(err: MidwayValidationError, ctx: Context) { // ... return { status: 422, message: '校验参数错误,' + err.message, }; } } ``` ### 4、临时禁用全局校验[​](#4临时禁用全局校验 "4、临时禁用全局校验的直接链接") 开启组件后,只要参数使用了 DTO,就会自动被校验,如果某个参数临时无需验证,可以使用下面的写法。 ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: Partial) {} } ``` --- # 参数校验 我们经常要在方法调用时执行一些类型检查,参数转换的操作,Midway 提供了一种简单的能力来快速检查参数的类型。 提示 从 `v4.0.0` 起,`@midwayjs/validation` 作为 `@midwayjs/validate` 的升级替代方案推出,两者是不同的包。 `@midwayjs/validation` 提供更上层的校验抽象,支持 joi/zod/class-validator,并预留自定义校验器扩展;`@midwayjs/validate` 仅基于 joi,仍可用但不再新增功能,建议逐步迁移。 新版本提供了更灵活的验证器扩展机制,支持多种验证器(如 Joi、Zod 等)的无缝切换,并提供了更好的类型支持和性能优化。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 背景[​](#背景 "背景的直接链接") 最常用参数校验的地方是控制器(Controller),同时你也可以在任意的 Class 中使用这个能力。 我们以控制器(Controller)中使用为例。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ └── user.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 普通情况下,我们从 `body` 上拿到所有 Post 结果,并进行一些校验。 ``` // src/interface.ts export interface User { id: number; firstName: string; lastName: string; age: number; } // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: User) { if (!user.id || typeof user.id !== 'number') { throw new Error('id error'); } if (user.age <= 30) { throw new Error('age not match'); } // xxx } } ``` 如果每个方法都需要这么校验,会非常的繁琐。 针对这种情况,Midway 提供了 Validation 组件。配合 `@Validate` 和 `@Rule` 装饰器,用来 **快速定义校验的规则**,帮助用户 **减少这些重复的代码**。 下面的通用能力将以 [joi](https://joi.dev/api/) 来举例。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 你需要安装 validation 组件以及对应验证器。 ``` ## 安装 validation 组件 $ npm i @midwayjs/validation@4 --save ## 选择一个或多个验证器 $ npm i @midwayjs/validation-joi@4 --save ## 基础库 $ npm i joi --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/validation": "^4.0.0", "@midwayjs/validation-joi": "^4.0.0", "joi": "^17.13.3", // ... }, "devDependencies": { // ... } } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") 在 `configuration.ts` 中增加组件: ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as validation from '@midwayjs/validation'; import { join } from 'path'; @Configuration({ imports: [ koa, validation, // ... 其他组件 ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... } } ``` 在配置文件中设置验证器: ``` // src/config/config.default.ts import joi from '@midwayjs/validation-joi'; export default { // ... validation: { // 配置验证器 validators: { joi, }, // 设置默认验证器 defaultValidator: 'joi' } } ``` ## 校验规则[​](#校验规则 "校验规则的直接链接") 通过 `@Rule` 装饰器,可以传递校验规则。 ``` import { Rule } from '@midwayjs/validation'; import * as Joi from 'joi'; export class UserDTO { @Rule(Joi.number().required()) id: number; @Rule(Joi.string().required()) firstName: string; @Rule(Joi.string().max(10)) lastName: string; @Rule(Joi.number().max(60)) age: number; } ``` ## 校验参数[​](#校验参数 "校验参数的直接链接") 定义完类型之后,就可以直接在业务代码中使用了,框架将自动帮你校验和转换 DTO。 ``` // src/controller/home.ts import { Controller, Get, Provide, Body } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO) { // user.id } } ``` 所有的校验代码都通通不见了,业务变的更纯粹了,当然,记得要把原来的 user interface 换成 Class。 一旦校验失败,浏览器或者控制台就会报出类似的错误。 ``` ValidationError: "id" is required ``` 同时,由于定义了 `id` 的类型,在拿到字符串的情况下,会自动将 id 变为数字。 ``` async updateUser(@Body() user: UserDTO ) { // typeof user.id === 'number' } ``` 如果需要对方法级别单独配置信息,可以使用 `@Validate` 装饰器,比如单独配置错误状态。 ``` // src/controller/home.ts import { Controller, Get, Provide } from '@midwayjs/core'; import { Validate } from '@midwayjs/validation'; import { UserDTO } from './dto/user'; @Controller('/api/user') export class HomeController { @Post('/') @Validate({ errorStatus: 422, }) async updateUser(@Body() user: UserDTO) { // user.id } } ``` 提示 `@Validate` 装饰器可以传递多个配置项,比如 `errorStatus`,`locale` 等。 | 配置项 | 类型 | 描述 | | ------------------ | ------- | ------------------------------------------------------------------ | | errorStatus | number | 当校验出错时,返回的 Http 状态码,在 http 场景生效,默认 422 | | locale | string | 校验出错文本的默认语言,默认为 `en_US`,会根据 i18n 组件的规则切换 | | throwValidateError | boolean | 是否抛出校验错误,默认 `true`,如果设置为 `false`,则返回校验结果 | | defaultValidator | string | 设置默认使用的验证器 | ## 校验结果[​](#校验结果 "校验结果的直接链接") 校验结果是一个对象,包含了校验的状态,校验的错误,校验的值等信息。Midway 对不同的验证器的返回值做了封装,统一了返回值的格式。 整体结构如下: ``` interface ValidateResult { /** * 校验是否成功 */ status: boolean; /** * 校验错误,如果有多个错误,会返回第一个错误 */ error?: any; /** * 校验的所有错误 */ errors?: any[]; /** * 校验错误信息,如果有多个错误,会返回第一个错误的信息 */ message?: string; /** * 校验的所有错误信息 */ messages?: string[]; /** * 校验额外信息 */ extra?: any; } ``` 提示 不同的验证器返回都已经处理成相同的结构。 ## 通用场景校验[​](#通用场景校验 "通用场景校验的直接链接") 如果参数不是 DTO,可以使用 `@Valid` 装饰器进行校验,`@Valid` 装饰器可以直接传递一个验证规则。 使用 Joi: ``` import { Controller, Get, Query } from '@midwayjs/core'; import { Valid } from '@midwayjs/validation'; import * as Joi from 'joi'; @Controller('/api/user') export class HomeController { @Get('/') async getUser(@Valid(Joi.number().required()) @Query('id') id: number) { // ... } } ``` 使用 Zod: ``` import { Controller, Get, Query } from '@midwayjs/core'; import { Valid } from '@midwayjs/validation'; import { z } from 'zod'; @Controller('/api/user') export class HomeController { @Get('/') async getUser(@Valid(z.number().min(1)) @Query('id') id: number) { // ... } } ``` 在非 Web 场景下,没有 `@Body` 等 Web 类装饰器的情况下,也可以使用 `@Valid` 装饰器来进行校验。 ``` import { Valid } from '@midwayjs/validation'; import { Provide } from '@midwayjs/core'; import { UserDTO } from './dto/user'; @Provide() export class UserService { async updateUser(@Valid() user: UserDTO) { // ... } } ``` ## 校验管道[​](#校验管道 "校验管道的直接链接") 如果你的参数是基础类型,比如 `number`, `string`, `boolean`,则可以使用组件提供的管道进行校验。 默认的 Web 参数装饰器都可以在第二个参数传入管道。 比如: ``` import { ParseIntPipe } from '@midwayjs/validation'; import { Controller, Post, Body } from '@midwayjs/core'; @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number) { // ... } } ``` `ParseIntPipe` 管道可以将字符串,数字数据转换为数字,这样从请求参数获取到的 `age` 字段则会通过管道的校验并转换为数字格式。 可以使用 的内置管道有: * `ParseIntPipe` * `ParseFloatPipe` * `ParseBoolPipe` * `DefaultValuePipe` `ParseIntPipe` 用于将参数转为整形数字。 ``` import { ParseIntPipe } from '@midwayjs/validation'; // ... async update(@Body('age', [ParseIntPipe]) age: number) { return age; } update({ age: '12'} ); => 12 update({ age: '12.2'} ); => Error update({ age: 'abc'} ); => Error ``` `ParseFloatPipe` 用于将参数转为浮点型数字数字。 ``` import { ParseFloatPipe } from '@midwayjs/validation'; // ... async update(@Body('size', [ParseFloatPipe]) size: number) { return size; } update({ size: '12.2'} ); => 12.2 update({ size: '12'} ); => 12 ``` `ParseBoolPipe` 用于将参数转为布尔值。 ``` import { ParseBoolPipe } from '@midwayjs/validation'; // ... async update(@Body('isMale', [ParseBoolPipe]) isMale: boolean) { return isMale; } update({ isMale: 'true'} ); => true update({ isMale: '0'} ); => Error ``` `DefaultValuePipe` 用于设定默认值。 ``` import { DefaultValuePipe } from '@midwayjs/validation'; // ... async update(@Body('nickName', [new DefaultValuePipe('anonymous')]) nickName: string) { return nickName; } update({ nickName: undefined} ); => 'anonymous' ``` ## 自定义校验管道[​](#自定义校验管道 "自定义校验管道的直接链接") 如果默认的管道不满足需求,可以通过继承,快速实现一个自定义校验管道,组件已经提供了一个 `ParsePipe` 类用于快速编写。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validation'; @Pipe() export class ParseCustomDataPipe extends ParsePipe { getSchema() { // ... } } ``` `getSchema` 方法用于返回一个校验规则。 比如 `ParseIntPipe` 的代码如下,管道执行时会自动获取这个 schema 进行校验,并在校验成功后将值返回。 我们依旧拿 `joi` 来举例。 ``` import { Pipe } from '@midwayjs/core'; import { ParsePipe, RuleType } from '@midwayjs/validation'; import * as Joi from 'joi'; @Pipe() export class ParseIntPipe extends ParsePipe { getSchema() { return Joi.number().integer().required(); } } ``` ## 校验规则[​](#校验规则-1 "校验规则的直接链接") 提示 * 新版本中已经移除了 `RuleType` 的使用,可以直接使用对应的验证器写法。 * `@Rule` 装饰器可以传递不同类型的验证器的规则。 * 在 `@Rule` 装饰器中,使用 `getSchema` 方法,需要使用箭头函数。 ### 常见的 joi 校验写法[​](#常见的-joi-校验写法 "常见的 joi 校验写法的直接链接") ``` import * as Joi from 'joi'; Joi.number().required(); // 数字,必填 Joi.string().empty(''); // 字符串非必填 Joi.number().max(10).min(1); // 数字,最大值和最小值 Joi.number().greater(10).less(50); // 数字,大于 10,小于 50 Joi.string().max(10).min(5); // 字符串,长度最大 10,最小 5 Joi.string().length(20); // 字符串,长度 20 Joi.string().pattern(/^[abc]+$/); // 字符串,匹配正则格式 Joi.object().length(5); // 对象,key 数量等于 5 Joi.array().items(Joi.string()); // 数组,每个元素是字符串 Joi.array().max(10); // 数组,最大长度为 10 Joi.array().min(10); // 数组,最小长度为 10 Joi.array().length(10); // 数组,长度为 10 Joi.string().allow(''); // 非必填字段传入空字符串 export enum DeviceType { iOS = 'ios', Android = 'android', } Joi.string().valid(...Object.values(DeviceType)) // 根据枚举值校验 ``` ### 级联校验[​](#级联校验 "级联校验的直接链接") Midway 支持每个校验的 Class 中的属性依旧是一个对象。 我们给 `UserDTO` 增加一个属性 `school` ,并且赋予一个 `SchoolDTO` 类型。 ``` import { Rule, getSchema } from '@midwayjs/validation'; import * as Joi from 'joi'; export class SchoolDTO { @Rule(Joi.string().required()) name: string; @Rule(Joi.string()) address: string; } export class UserDTO { @Rule(Joi.number().required()) id: number; @Rule(Joi.string().required()) firstName: string; @Rule(Joi.string().max(10)) lastName: string; // 复杂对象 // 这里执行的时候 validator 还未注册,所以需要使用箭头函数 @Rule(() => getSchema(SchoolDTO).required()) school: SchoolDTO; // 对象数组 @Rule(() => Joi.array().items(getSchema(SchoolDTO)).required()) schoolList: SchoolDTO[]; } ``` 这个时候, `@Rule` 装饰器的参数可以为需要校验的这个类型本身。 ### 继承校验[​](#继承校验 "继承校验的直接链接") Midway 支持校验继承方式,满足开发者抽离通用的对象属性的时候做参数校验。 例如我们下面 `CommonUserDTO` 抽离接口的通用的一些属性,然后 `UserDTO` 作为特殊接口需要的特定参数。 ``` import { Rule } from '@midwayjs/validation'; export class CommonUserDTO { @Rule(Joi.string().required()) token: string; @Rule(Joi.string()) workId: string; } export class UserDTO extends CommonUserDTO { @Rule(Joi.string().required()) name: string; } ``` 老版本需要在子类上面加,新版本不需要啦~ 信息 如果属性名相同,则取当前属性的规则进行校验,不会和父类合并。 ### 多类型校验[​](#多类型校验 "多类型校验的直接链接") 从 v3.4.5 开始,Midway 支持某个属性的不同类型的校验。 例如某个类型,既可以是可以普通类型,又可以是一个复杂类型。 ``` import { Rule, getSchema } from '@midwayjs/validation'; import * as Joi from 'joi'; export class SchoolDTO { @Rule(Joi.string().required()) name: string; @Rule(Joi.string()) address: string; } export class UserDTO { @Rule(Joi.string().required()) name: string; @Rule(() => Joi.alternatives([Joi.string(), getSchema(SchoolDTO)]).required()) school: string | SchoolDTO; } ``` 我们可以使用 `getSchema` 方法,从某个 DTO 拿到当前的 schema,从而进行复杂的逻辑处理。 ### 从原有 DTO 创建新 DTO[​](#从原有-dto-创建新-dto "从原有 DTO 创建新 DTO的直接链接") 有时候,我们会希望从某个 DTO 中获取一部分属性,变成一个新的 DTO 类。 Midway 提供了 `PickDto` 和 `OmitDto` 两个方法根据现有的的 DTO 类型创建新的 DTO。 `PickDto` 用于从现有的 DTO 中获取一些属性,变成新的 DTO,而 `OmitDto` 用于将其中某些属性剔除,比如: ``` // src/dto/user.ts import { Rule, PickDto } from '@midwayjs/validation'; export class UserDTO { @Rule(Joi.number().required()) id: number; @Rule(Joi.string().required()) firstName: string; @Rule(Joi.string().max(10)) lastName: string; @Rule(Joi.number().max(60)) age: number; } // 继承出一个新的 DTO export class SimpleUserDTO extends PickDto(UserDTO, ['firstName', 'lastName']) {} // const simpleUser = new SimpleUserDTO(); // 只包含了 firstName 和 lastName 属性 // simpleUser.firstName = xxx export class NewUserDTO extends OmitDto(UserDTO, ['age']) {} // const newUser = new NewUserDTO(); // newUser.age 定义和属性都不存在 // 使用 async login(@Body() user: NewUserDTO) { // ... } ``` ## 多语言[​](#多语言 "多语言的直接链接") 默认情况下,提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,所以在请求失败时,会返回当前浏览器访问所指定的语言。 ### 通过装饰器指定语言[​](#通过装饰器指定语言 "通过装饰器指定语言的直接链接") 默认情况下,会跟着 i18n 组件的 `defaultLocale` 以及浏览器访问语言的情况来返回消息,不过,我们可以在装饰器中指定当前翻译的语言,比如: ``` @Controller('/user') export class UserController { @Post('/') @Validate({ locale: 'en_US', }) async getUser(@Body() bodyData: UserDTO) { // ... } } ``` ### 通过参数指定语言[​](#通过参数指定语言 "通过参数指定语言的直接链接") 除了装饰器指定,我们也可以使用标准的 i18n 通过参数指定语言的方式。 比如 Query 参数。 ``` Get /user/get_user?locale=zh_CN ``` 更多的参数用法请参考 [i18n](/docs/extensions/i18n.md) 组件。 ### 其他语言的翻译[​](#其他语言的翻译 "其他语言的翻译的直接链接") 默认情况下,Midway 提供了 `en_US` 和 `zh_CN` 两种校验的翻译文本,如果还需要额外的翻译,可以配置在 i18n 中。 比如: ``` // src/config/config.default.ts export default { // ... i18n: { // 增加翻译 zh_TW: { validate: require('../../locales/zh_TW.json'), }, }, }; ``` ## 自定义错误文本[​](#自定义错误文本 "自定义错误文本的直接链接") 如果只想定义某个 DTO 中某个规则的错误消息,可以简单指定。 ``` export class UserDTO { @Rule(RuleType.number().required().error(new Error('my custom message'))) id: number; } ``` ## ## 默认配置[​](#默认配置 "默认配置的直接链接") 在 `src/config/config.default.ts` 中,我们可以对 validation 组件做一些配置。 | 配置项 | 类型 | 描述 | | ---------------- | ------------------------- | --------------------------------------------------------------------- | | errorStatus | number | 当校验出错时,返回的 Http 状态码,在 http 场景生效,默认 422 | | locale | string | 校验出错文本的默认语言,默认为 `en_US`,会根据 i18n 组件的规则切换 | | validators | Record\ | 配置要使用的验证器 | | defaultValidator | string | 设置默认使用的验证器,如果未设置,则使用用户 `require` 的第一个验证器 | ## 高级[​](#高级 "高级的直接链接") ### 独立的校验服务[​](#独立的校验服务 "独立的校验服务的直接链接") 组件底层提供了单例的 `ValidationService` 校验服务类,如有必要,可以在中间件或者独立的服务中使用。 ``` import { ValidationService } from '@midwayjs/validation'; export class UserService { @Inject() validateService: ValidationService; async invoke() { // ... const result = this.validateService.validate(UserDTO, { name: 'harry', nickName: 'harry', }, { throwValidateError: false, }); if (result.status) { // 成功 } else { // 失败 } } } ``` ### 使用 `zod` 验证器[​](#使用-zod-验证器 "使用-zod-验证器的直接链接") Midway 同时支持 Zod v3 和 Zod v4 两个版本,你可以根据项目需求选择: * `@midwayjs/validation-zod` - 支持 Zod v3 (3.x) * `@midwayjs/validation-zod4` - 支持 Zod v4 (4.x) - Zod v3 - Zod v4 如果你选择使用 Zod v3 验证器,需要先安装相关依赖包: ``` $ npm i @midwayjs/validation@4 @midwayjs/validation-zod@4 zod@3 --save ``` 在配置文件中设置验证器: ``` // src/config/config.default.ts import zod from '@midwayjs/validation-zod'; export default { // ... validation: { // 配置验证器 validators: { 'zod': zod, }, // 设置默认验证器 defaultValidator: 'zod' } } ``` 然后就可以使用 Zod 的验证规则: ``` import { Rule } from '@midwayjs/validation'; import { z } from 'zod'; export class UserDTO { @Rule(z.number().min(1)) id: number; @Rule(z.string().min(1)) firstName: string; @Rule(z.string().max(10)) lastName: string; @Rule(z.number().max(60)) age: number; } ``` Zod 验证器使用了 `zod-i18n-map` 提供的翻译,支持更多的语言,包括: * 简体中文 (zh-CN) * 繁体中文 (zh-TW) * 英语 (en) * 日语 (ja) * 韩语 (ko) * 俄语 (ru) 等多种语言。 如有需要,可以参考 [zod-i18n-map](https://github.com/g-plane/zod-i18n-map) 的文档,添加更多的语言支持。 ``` // src/config/config.default.ts export default { // ... i18n: { localeTable: { zh_TW: { zod: require('zod-i18n-map/locales/zh-TW/zod.json'), }, }, } } ``` 如果你选择使用 Zod v4 验证器,需要先安装相关依赖包: ``` $ npm i @midwayjs/validation@4 @midwayjs/validation-zod4@4 zod@4 --save ``` 在配置文件中设置验证器: ``` // src/config/config.default.ts import zod from '@midwayjs/validation-zod4'; export default { // ... validation: { // 配置验证器 validators: { 'zod': zod, }, // 设置默认验证器 defaultValidator: 'zod' } } ``` 可以直接使用 Zod 的验证规则: ``` import { Rule } from '@midwayjs/validation'; import { z } from 'zod'; export class UserDTO { @Rule(z.number().min(1)) id: number; @Rule(z.string().min(1)) firstName: string; @Rule(z.string().max(10)) lastName: string; @Rule(z.number().max(60)) age: number; } ``` Zod v4 验证器使用了 `@semihbou/zod-i18n-map` 提供的翻译,支持更多的语言,包括: * 简体中文 (zh-CN) * 繁体中文 (zh-TW) * 英语 (en) * 日语 (ja) * 韩语 (ko) * 俄语 (ru) 等多种语言。 如有需要,可以参考 [@semihbou/zod-i18n-map](https://github.com/VC-Semih/zod-i18n) 的文档,添加更多的语言支持。 ``` // src/config/config.default.ts export default { // ... i18n: { localeTable: { zh_TW: { zod: require('@semihbou/zod-i18n-map/locales/zh-TW/zod.json'), }, }, } } ``` ### 使用 `class-validator` 验证器[​](#使用-class-validator-验证器 "使用-class-validator-验证器的直接链接") 你需要先安装 `class-validator` 和相关依赖包: ``` $ npm i @midwayjs/validation@4 @midwayjs/validation-class-validator@4 class-validator class-transformer --save ``` 在配置文件中设置验证器: ``` // src/config/config.default.ts import classValidator from '@midwayjs/validation-class-validator'; export default { // ... validation: { validators: { 'class-validator': classValidator, }, defaultValidator: 'class-validator' } } ``` 然后就可以使用 `class-validator` 的验证规则: ``` import { Rule } from '@midwayjs/validation'; import { IsString, IsNumber } from 'class-validator'; export class UserDTO { @Rule(IsString()) name: string; @Rule(IsNumber()) age: number; } ``` 默认针对 `class-validator` 的验证规则,Midway 提供了 `zh_CN` 和 `en_US` 两种翻译文本。 如果需要更多的语言支持,可以参考 [class-validator-multi-lang](https://github.com/EndyKaufman/class-validator-multi-lang/tree/i18n) 提供的翻译文本。 比如,我们想支持俄语 (ru) 的翻译,可以将对应的翻译文件拷贝出来放在 `/locales/ru.json` 文件中。 配置如下。 ``` // src/config/config.default.ts export default { // ... i18n: { // 配置验证器 localeTable: { ru_RU: { classValidator: require('../../locales/ru.json'), }, }, } } ``` ### 混用验证器[​](#混用验证器 "混用验证器的直接链接") 你可以在同一个项目中配置了多个验证器。 ``` // src/config/config.default.ts import joi from '@midwayjs/validation-joi'; import zod from '@midwayjs/validation-zod'; export default { // ... validation: { // 配置验证器 validators: { 'joi': joi, 'zod': zod, }, // 设置默认验证器 defaultValidator: 'joi' } } ``` `@Rule` 装饰器的参数可以使用不同的校验规则。 ``` import { Rule } from '@midwayjs/validation'; import * as Joi from 'joi'; import { z } from 'zod'; export class UserDTO { @Rule(Joi.number().required()) id: number; @Rule(Joi.string().required()) name: string; } export class AnotherUserDTO { @Rule(z.number()) id: number; @Rule(z.string().min(1)) name: string; } ``` 提示 你不能在同一个类中使用不同的验证器。 可以通过 `defaultValidator` 手动选择指定哪种验证器生效。 ``` @Controller('/user') export class UserController { @Post('/') @Validate({ defaultValidator: 'zod', }) async getUser(@Body() bodyData: AnotherUserDTO) { // ... } } ``` 在 `ValidationService` 中也可以使用。 ``` import { ValidationService } from '@midwayjs/validation'; export class UserService { @Inject() validateService: ValidationService; async invoke() { // ... const result = this.validateService.validate(UserDTO, { name: 'harry', nickName: 'harry', }, { defaultValidator: 'zod' }); } } ``` ### 自定义验证器[​](#自定义验证器 "自定义验证器的直接链接") 除了使用内置的 Joi 和 Zod 验证器,你还可以实现自己的验证器。验证器需要实现 `IValidationService` 接口: ``` import { IMidwayContainer } from '@midwayjs/core'; import { IValidationService, ValidateResult, ValidationExtendOptions } from '@midwayjs/validation'; class CustomValidator implements IValidationService { // 初始化验证器 async init(container: IMidwayContainer): Promise { // 在这里进行初始化操作 } // 使用 schema 进行验证 validateWithSchema( schema: any, value: any, options: ValidationExtendOptions, validatorOptions: any ): ValidateResult { const res = {} as ValidateResult; try { // 实现你的验证逻辑 res.status = true; res.value = value; // 可以在这里对值进行转换 } catch (error) { res.status = false; res.error = error; res.message = error.message; } return res; } // 获取 schema getSchema(ClzType: any): any { // 实现获取 schema 的逻辑 } // 获取基础类型的 schema getIntSchema(): any { // 返回整数类型的 schema } getBoolSchema(): any { // 返回布尔类型的 schema } getFloatSchema(): any { // 返回浮点数类型的 schema } getStringSchema(): any { // 返回字符串类型的 schema } } // 导出验证器工厂函数 export default async (container: IMidwayContainer) => { return new CustomValidator(); }; ``` 然后在配置中使用你的自定义验证器: ``` // src/config/config.default.ts import customValidator from './custom.validator'; export default { validation: { validators: { custom: customValidator, // 注册自定义验证器 }, defaultValidator: 'custom' // 设置为默认验证器 } }; ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1. Joi 中允许未定义的字段[​](#1-joi-中允许未定义的字段 "1. Joi 中允许未定义的字段的直接链接") 对于 Joi 验证器,可以通过以下配置允许未定义的字段: ``` // src/config/config.default.ts export default { // ... joi: { allowUnknown: true, } }; ``` ### 2. 处理校验错误[​](#2-处理校验错误 "2. 处理校验错误的直接链接") 上面提到,Midway 会在校验失败时抛出 `MidwayValidationError` 错误,我们可以在 [异常处理器](/docs/error_filter.md) 中处理。 ``` // src/filter/validate.filter import { Catch } from '@midwayjs/core'; import { MidwayValidationError } from '@midwayjs/validation'; import { Context } from '@midwayjs/koa'; @Catch(MidwayValidationError) export class ValidateErrorFilter { async catch(err: MidwayValidationError, ctx: Context) { return { status: 422, message: '校验参数错误,' + err.message, }; } } ``` ### 3. 多语言未生效[​](#3-多语言未生效 "3. 多语言未生效的直接链接") 请使用浏览器,不要直接使用 Postman 来测试。 --- # WebSocket [ws](https://www.npmjs.com/package/ws) 模块是 Node 端的一个 WebSocket 协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接. 这种可以持续连接的特性使得 WebSocket 特别适合用于适合用于游戏或者聊天室等使用场景。 Midway 提供了对 [ws](https://www.npmjs.com/package/ws) 模块的支持和封装,能够简单的创建一个 WebSocket 服务。 相关信息: **提供服务** | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | | 包含独立主框架 | ❌ | | 包含独立日志 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在现有项目中安装 WebSocket 的依赖。 ``` $ npm i @midwayjs/ws@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/ws": "^4.0.0", // ... }, } ``` ## 开启组件[​](#开启组件 "开启组件的直接链接") `@midwayjs/ws` 可以作为独立主框架使用。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [ws], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` 也可以附加在其他的主框架下,比如 `@midwayjs/koa` 。 ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws], // ... }) export class MainConfiguration { async onReady() { // ... } } ``` ## 目录结构[​](#目录结构 "目录结构的直接链接") 下面是 WebSocket 项目的基础目录结构,和传统应用类似,我们创建了 `socket` 目录,用户存放 WebSocket 业务的服务代码。 ``` . ├── package.json ├── src │ ├── configuration.ts ## 入口配置文件 │ ├── interface.ts │ └── socket ## ws 服务的文件 │ └── hello.controller.ts ├── test ├── bootstrap.js ## 服务启动入口 └── tsconfig.json ``` ## 提供 Socket 服务[​](#提供-socket-服务 "提供 Socket 服务的直接链接") Midway 通过 `@WSController` 装饰器定义 WebSocket 服务。 ``` import { WSController } from '@midwayjs/core'; @WSController() export class HelloSocketController { // ... } ``` 当有客户端连接时,会触发 `connection` 事件,我们在代码中可以使用 `@OnWSConnection()` 装饰器来修饰一个方法,当每个客户端第一次连接服务时,将自动调用该方法。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; import * as http from 'http'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod(socket: Context, request: http.IncomingMessage) { console.log(`namespace / got a connection ${this.ctx.readyState}`); } } ``` 信息 这里的 ctx 等价于 WebSocket 实例。 ## 消息和响应[​](#消息和响应 "消息和响应的直接链接") WebSocket 是通过事件的监听方式来获取数据。Midway 提供了 `@OnWSMessage()` 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。 ``` import { WSController, OnWSMessage, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') async gotMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } } ``` 我们可以通过 `@WSBroadCast` 装饰器将消息发送到所有连接的客户端上。 ``` import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') @WSBroadCast() async gotMyMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } @OnWSDisConnection() async disconnect(id: number) { console.log('disconnect ' + id); } } ``` 通过 `@OnWSDisConnection` 装饰器,在客户端断连时,做一些额外处理。 ## WebSocket Server 实例[​](#websocket-server-实例 "WebSocket Server 实例的直接链接") 该组件提供的 App 即为 WebSocket Server 实例本身,我们可以如下获取。 ``` import { Controller, App } from '@midwayjs/core'; import { Application } from '@midwayjs/ws'; @Controller() export class HomeController { @App('webSocket') wsApp: Application; } ``` 比如,我们可以在其他 Controller 或者 Service 中广播消息。 ``` import { Controller, App } from '@midwayjs/core'; import { Application } from '@midwayjs/ws'; @Controller() export class HomeController { @App('webSocket') wsApp: Application; async invoke() { this.wsApp.clients.forEach(ws => { // ws.send('something'); }); } } ``` ## 心跳检查[​](#心跳检查 "心跳检查的直接链接") 有时服务器和客户端之间的连接可能会中断,服务器和客户端都不知道连接的断开情况。 可以通过启用 `enableServerHeartbeatCheck` 配置心跳检查主动断开请求。 ``` // src/config/config.default export default { // ... webSocket: { enableServerHeartbeatCheck: true, }, } ``` 默认检查时间为 `30*1000` 毫秒,可以通过 `serverHeartbeatInterval` 进行修改,配置单位为毫秒。 ``` // src/config/config.default export default { // ... webSocket: { serverHeartbeatInterval: 30000, }, } ``` 这一配置每隔一段时间会自动发送 `ping` 包,客户端若没有在下一个时间间隔返回消息,则会被自动 `terminate` 。 客户端如果希望知道服务端的状态,可以通过监听 `ping` 消息来实现。 ``` import WebSocket from 'ws'; function heartbeat() { clearTimeout(this.pingTimeout); // 每次接收 ping 之后,延迟等待,如果下一次未拿到服务端 ping 消息,则认为出现问题 this.pingTimeout = setTimeout(() => { // 重连或者中止 }, 30000 + 1000); } const client = new WebSocket('wss://websocket-echo.com/'); // ... client.on('ping', heartbeat); ``` ## 鉴权[​](#鉴权 "鉴权的直接链接") 在 WebSocket 连接建立之前,您可能需要对客户端进行身份验证。从 v3.20.9 开始 Midway 提供了 `onWebSocketUpgrade` 方法来在 WebSocket 握手前进行鉴权。 ### 设置鉴权处理器[​](#设置鉴权处理器 "设置鉴权处理器的直接链接") 您可以在应用启动时设置鉴权处理器: ``` import { Configuration, Inject } from '@midwayjs/core'; import { Framework } from '@midwayjs/ws'; @Configuration() export class WSConfiguration { @Inject() wsFramework: Framework; async onReady() { // 设置升级前鉴权处理器 this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { // 从 URL 参数中获取 token const url = new URL(request.url, `http://${request.headers.host}`); const token = url.searchParams.get('token'); // 验证 token if (token === 'valid-token') { return true; // 允许连接 } return false; // 拒绝连接 }); } } ``` ### 鉴权处理器参数[​](#鉴权处理器参数 "鉴权处理器参数的直接链接") 鉴权处理器接收三个参数: * `request`: HTTP 请求对象 (`http.IncomingMessage`) * `socket`: 原始 socket 对象 * `head`: WebSocket 握手的头部数据 (`Buffer`) 处理器需要返回一个 `Promise`: * `true`: 允许 WebSocket 连接 * `false`: 拒绝 WebSocket 连接 ### 获取鉴权信息[​](#获取鉴权信息 "获取鉴权信息的直接链接") 您可以从多个来源获取鉴权信息: **URL 参数** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const url = new URL(request.url, `http://${request.headers.host}`); const token = url.searchParams.get('token'); const userId = url.searchParams.get('userId'); // 验证逻辑 return await this.validateToken(token, userId); }); ``` **请求头** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const authorization = request.headers.authorization; if (!authorization) { return false; } const token = authorization.replace('Bearer ', ''); return await this.validateToken(token); }); ``` **Cookie** ``` this.wsFramework.onWebSocketUpgrade(async (request, socket, head) => { const cookie = request.headers.cookie; if (!cookie) { return false; } // 解析 cookie 获取 session 信息 const sessionId = this.parseCookie(cookie).sessionId; return await this.validateSession(sessionId); }); ``` ## 本地测试[​](#本地测试 "本地测试的直接链接") ### 配置测试端口[​](#配置测试端口 "配置测试端口的直接链接") 由于 ws 框架可以独立启动(依附于默认的 http 服务,也可以和其他 midway 框架一起启动)。 当作为独立框架启动时,需要指定端口。 ``` // src/config/config.default export default { // ... webSocket: { port: 3000, }, } ``` 当作为副框架启动时(比如和 http ,由于 http 在单测时未指定端口(使用 supertest 自动生成),无法很好的测试,可以仅在测试环境显式指定一个端口。 ``` // src/config/config.unittest export default { // ... koa: { port: null, }, webSocket: { port: 3000, }, } ``` 提示 * 1、这里的端口仅为 WebSocket 服务在测试时启动的端口 * 2、koa 中的端口为 null,即意味着在测试环境下,不配置端口,不会启动 http 服务 ### 测试代码[​](#测试代码 "测试代码的直接链接") 和其他 Midway 测试方法一样,我们使用 `createApp` 启动项目。 ``` import { createApp, close } from '@midwayjs/mock' // 这里使用的 Framework 定义,以主框架为准 import { Framework } from '@midwayjs/koa'; describe('/test/index.test.ts', () => { it('should create app and test webSocket', async () => { const app = await createApp(); //... await close(app); }); }); ``` ### 测试客户端[​](#测试客户端 "测试客户端的直接链接") 你可以直接使用 `ws` 来测试。也可以使用 Midway 提供的基于 `ws` 模块封装的测试客户端。 比如: ``` import { createApp, close, createWebSocketClient } from '@midwayjs/mock'; import { sleep } from '@midwayjs/core'; // ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); const result = await new Promise(resolve => { client.on('message', (data) => { // xxxx resolve(data); }); // 发送事件 client.send(1); }); // 判断结果 expect(JSON.parse(result)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); ``` 使用 node 自带的 `events` 模块的 `once` 方法来优化,就会变成下面的代码。 ``` import { sleep } from '@midwayjs/core'; import { once } from 'events'; import { createApp, close, createWebSocketClient } from '@midwayjs/mock'; // ... 省略 describe it('should test create websocket app', async () => { // 创建一个服务 const app = await createApp(process.cwd()); // 创建一个客户端 const client = await createWebSocketClient(`ws://localhost:3000`); // 发送事件 client.send(1); // 用事件的 promise 写法监听 let gotEvent = once(client, 'message'); // 等待返回 let [data] = await gotEvent; // 判断结果 expect(JSON.parse(data)).toEqual({ name: 'harry', result: 6, }); await sleep(1000); // 关闭客户端 await client.close(); // 关闭服务端 await close(app); }); ``` 两种写法效果相同,按自己理解的写就行。 ## 配置[​](#配置 "配置的直接链接") ## 默认配置[​](#默认配置 "默认配置的直接链接") `@midwayjs/ws` 的配置样例如下: ``` // src/config/config.default export default { // ... webSocket: { port: 7001, }, } ``` 当 `@midwayjs/ws` 和其他 `@midwayjs/web` , `@midwayjs/koa` , `@midwayjs/express` 同时启用时,可以复用端口。 ``` // src/config/config.default export default { // ... koa: { port: 7001, } webSocket: { // 这里不配置即可 }, } ``` | 属性 | 类型 | 描述 | | ------ | ---------- | -------------------------------------------------------------------------------------------------------------------------- | | port | number | 可选,如果传递了该端口,ws 内部会创建一个该端口的 HTTP 服务。如果希望和 midway 其他的 web 框架配合使用,请不要传递该参数。 | | server | httpServer | 可选,当传递 port 时,可以指定一个已经存在的 webServer | 更多的启动选项,请参考 [ws 文档](https://github.com/websockets/ws)。 --- # 关于 Alias Path 我们并不建议使用 Alias Path, Node 和 TS 原生不支持这个功能,即使有,现在也是通过各种 Hack 手段来实现(从 v18 开始,Node.js 已经有 exports 的方案,但是类型还未支持,可以等后续)。 如果你一定想要使用,请往下看。 ## 本地开发的支持(dev 阶段)[​](#本地开发的支持dev-阶段 "本地开发的支持(dev 阶段)的直接链接") tsc 将 ts 编译成 js 的时候,并不会去转换 import 的模块路径,因此当你在 `tsconfig.json` 中配置了 paths 之后,如果你在 ts 中使用 paths 并 import 了对应模块,编译成 js 的时候就有大概率出现模块找不到的情况。 解决办法是,要么不用 paths ,要么使用 paths 的时候只用来 import 一些声明而非具体值,再要么就可以使用 [tsconfig-paths](https://github.com/dividab/tsconfig-paths) 来 hook 掉 node 中的模块路径解析逻辑,从而支持 `tsconfig.json` 中的 paths。 ``` $ npm i tsconfig-paths --save-dev ``` 使用 tsconfig-paths 可以在 `src/configuration.ts` 中引入。 ``` // src/configuration.ts import 'tsconfig-paths/register'; // ... ``` 信息 上述的方法只会对 dev 阶段( ts-node)生效。 ## 测试的支持(jest test)[​](#测试的支持jest-test "测试的支持(jest test)的直接链接") 在测试中,由于 Jest 的环境比较特殊,需要对 alias 再做一次处理,可以利用 Jest 的配置文件中的 `moduleNameMapper` 功能来替换加载到的模块,变相实现 alias 的功能。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], moduleNameMapper: { '^@/(.*)$': '/src/$1' } }; ``` 注意,这里使用的 alias 前缀是 @符号,如果是其他的 alias 名,请自行修改。 ## 运行时的支持[​](#运行时的支持 "运行时的支持的直接链接") `tsconfig-paths` 是在 ts 运行后在内存中替换路径,编译后依旧会输出带 @符号的路径,使得部署后找不到文件,社区有一些库会在 ts 编译做一些替换支持。 比如: * ## 其他[​](#其他 "其他的直接链接") 老版本 CLI 中预埋了一个 mwcc 编译器,基于固定 TS 版本在构建器替换 Alias 内容,但是由于依赖 TS 私有 API 导致无法升级 TS 版本,无法享受到新版本的功能。 我们从 CLI 2.0 版本开始,移除了这个编译器。 --- # 常见框架问题 ## 多个 @midwayjs/core 警告[​](#多个-midwayjscore-警告 "多个 @midwayjs/core 警告的直接链接") `@midwayjs/core` 包一般来说,npm 会让相同的依赖在 node\_modules 存在一份实例,其余的模块都会通过软链(link)链接到 node\_modules/@midwayjs/core。 我们会用到下面的命令,`npm ls` 会列出项目底下某个包的依赖树。 ``` $ npm ls @midwayjs/core ``` 比如下图所示。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01Td86gC1tQsKjRB8XU_!!6000000005897-2-tps-541-183.png) 灰色的 `deduped` 指的就是该包是被 npm 软链到同一个模块,是正常的。 我们再来看下有问题的示例。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01gsnexD1i6lA7kM48q_!!6000000004364-2-tps-1010-308.png) 这是一个 lerna 项目,最下面的 demo-docs 中的 decorator 包,后面没有 **deduped** 标示,说明这个包是独立存在的,是错误的。 根据这个思路,我们可以逐步排查为什么会出现这种情况。 比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装。 我们可以按照下面的思路逐步排查: * 1、包含不同版本的 decorator 包(比如,package-lock 锁包,或者依赖写死版本) * 2、未正确使用 lerna 的 hoist 模式(比如上图,可能是在单个模块中使用的 npm install,而不是使用 lerna 安装) ## xxx is not valid in current context[​](#xxx-is-not-valid-in-current-context "xxx is not valid in current context的直接链接") 这个是当依赖注入容器中某个属性所关联的类在依赖注入容器中找不到爆出的。这个错误展示的可能会递归,比较深。 比如: ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01sTvqNX1NiDcoiyS2a_!!6000000001603-2-tps-1053-141.png) 错误核心就是第一个属性,在某个类中找不到。 比如上图的核心就是 `packageBuildInfoHsfService` 这个注入的类找不到。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01BBe4gu1KHhqnT0S75_!!6000000001139-2-tps-765-166.png) 这个时候,就需要去对应的类中去看,是否是 provide 出来的名字被自定义了。 常见的问题有: * 1、Provide 装饰器导出的名字不对,无法和属性对应 * 2、Provide 为空的话,大概率是大小写没写对 * 3、注入是组件的话,可能是漏了组件名 简单的解法:`@Inject` 装饰器不加参数,属性的定义写明确的类,这样 midway 可以自动找到对应的类并注入(不适用于多态的情况)。 ``` @Inject() service: PackageBuildInfoHsfService; ``` ## TypeError: (0 ,decorator\_1.Framework) is not a function[​](#typeerror-0-decorator_1framework-is-not-a-function "TypeError: (0 ,decorator_1.Framework) is not a function的直接链接") 原因为使用了错误的版本,比如低版本的框架,使用了高版本的组件(2.x 的框架使用了 3.x 的组件)。 ![](https://img.alicdn.com/imgextra/i3/O1CN01G7gzCj1EkCpW1gaJl_!!6000000000389-2-tps-1461-491.png) 解法:确认自己的框架大版本(@midwayjs/core 的版本即为框架版本),选择对应的文档,对应的组件使用。 --- # 常见 git 问题 ## 文件名大小写问题[​](#文件名大小写问题 "文件名大小写问题的直接链接") 由于 git 默认对大小写不敏感,如果文件名从小写变成了大写之后,无法发现文件有变化导致没有提交到仓库。 更可怕的是 mac 也是大小写不敏感,经常出现到本地可以运行,到服务器就执行错误的情况。 为此,我们最好把 git 的默认大小写关闭。 下面的命令。 ``` $ git config core.ignorecase false ## 对当前项目生效 $ git config --global --add core.ignorecase false ## 对全局生效 ``` ## windows 下换行问题[​](#windows-下换行问题 "windows 下换行问题的直接链接") 在 Windows 上创建或者克隆代码,开发或者提交时,可能出现如下错误: ``` Delete `␍`eslint(prettier/prettier) ``` 原因如下: 由于历史原因,windows下和linux下的文本文件的换行符不一致。 * Windows在换行的时候,同时使用了回车符 CR(carriage-return character) 和换行符 LF(linefeed character) * 而Mac和Linux系统,仅仅使用了换行符 LF * 老版本的Mac系统使用的是回车符 CR | Windows | Linux/Mac | Old Mac(pre-OSX | | ------- | --------- | --------------- | | CRLF | LF | CR | | '\n\r' | '\n' | '\r' | 因此,文本文件在不同系统下创建和使用时就会出现不兼容的问题。 解决方案如下: 设置全局 git 文本换行 ``` $ git config --global core.autocrlf false ``` 注意:git 全局配置之后,你需要重新拉取代码。 如您使用的是vscode编辑器,解决方案如下: 在编辑器右下角将`CRLF`手动更改为`LF` 此方法仅可修改当前文件的换行符,使用vscode新建文件换行符还为`CRLF`,可在`settings.json`中增加以下配置 ``` "files.eol": "\n", ``` 参考: * [Delete `␍`eslint(prettier/prettier) 错误的解决方案](https://juejin.cn/post/6844904069304156168) * [配置 Git 处理行结束符](https://docs.github.com/cn/github/getting-started-with-github/configuring-git-to-handle-line-endings) --- # 常见 npm 问题 ## 1、不希望生成 package-lock.json[​](#1不希望生成-package-lockjson "1、不希望生成 package-lock.json的直接链接") 在某些时候,锁版本不是特别好用,反而会出现不少奇怪的问题,我们会禁用 npm 的生成 `package-lock.json` 文件的功能。 可以输入下面的命令。 ``` $ npm config set package-lock false ``` ## 2、Maximum call stack size exceeded 报错[​](#2maximum-call-stack-size-exceeded-报错 "2、Maximum call stack size exceeded 报错的直接链接") 一般在 npm install 之后,再 npm install 某个包导致的。 解法: * 1、删除 node\_modules * 2、删除 package-lock.json * 3、重新 npm install 如果还有问题,可以尝试使用 node v14/npm6 重试。 ## 3、Python/Canvas 报错[​](#3pythoncanvas-报错 "3、Python/Canvas 报错的直接链接") 出现在使用 node v15/npm7 安装 jest 模块。 比如: ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01fctCcQ2191p8aMfDd_!!6000000006941-2-tps-1623-295.png) 解决方案:npm i 时添加 `--legacy-peer-deps` 参数。 原因:测试框架 Jest 依赖 jsdom,npm7 会自动安装其 peerDependencies 中依赖的 canvas 包, 而 canvas 的安装编译需要有python3环境。 --- # 常见 TS 问题 TS 有很多编译静态检查,比如类型不一致,对象未定义等,默认情况下是最佳的,希望用户合理考虑编码风格和习惯,谨慎开关配置,享受 TS 静态检查带来的好处。 ## 依赖包定义错误[​](#依赖包定义错误 "依赖包定义错误的直接链接") 如果依赖包和项目本身的 TS 版本不一致,在编译时会出现错误。 可以在 `tsconfig.json` 关闭依赖包的检查。 ``` { "compilerOptions": { "skipLibCheck": true }, } ``` ## TS2564 初始化未赋值错误[​](#ts2564-初始化未赋值错误 "TS2564 初始化未赋值错误的直接链接") 错误如下: ``` error TS2564: Property 'name' has no initializer and is not definitely assigned in the constructor. ``` 原因为开启了 TS 的初始化属性检查,如果没有初始化赋值就会报错。 处理方法: 第一种:移除 tsconfig.json 的检查规则 ``` { "strictPropertyInitialization": false // 或者移除 } ``` 第二种:属性加感叹号 ``` export class HomeController { @Inject() userService!: UserService; } ``` ## TS6133 对象声明未使用错误[​](#ts6133-对象声明未使用错误 "TS6133 对象声明未使用错误的直接链接") 错误如下: ``` error TS6133: 'app' is declared but its value is never read. ``` 原因为开启了 TS 的对象未使用检查,如果声明了但是没有使用就会报错。 处理方法: 第一种:移除未定义的变量 第二种:移除 tsconfig.json 的检查规则 ``` { "compilerOptions": { "noUnusedLocals": false }, } ``` ## tsconfig 中定义 typings 不生效[​](#tsconfig-中定义-typings-不生效 "tsconfig 中定义 typings 不生效的直接链接") 在 tsconfig.json 中,如果定义了 typeRoots,且定义了 include,如果 include 中不包含 typeRoot 中的内容,则会在 dev/build 时报错。 此为 ts/ts-node 的问题,issue 见 [#782](https://github.com/TypeStrong/ts-node/issues/782) [#22217](https://github.com/microsoft/TypeScript/issues/22217) 比如: ``` "typeRoots": [ "./node_modules/@types", "./typings" ], "include": [ "src", "typings" ], "exclude": [ "dist", "node_modules" ], ``` 上述,如果 include 中不写 typings,则会在 dev/build 时找不到定义而报错。 --- # 函数式 API 本页用于快速查询 `@midwayjs/core/functional` 当前可用的函数式 API。 ## 配置与路由[​](#配置与路由 "配置与路由的直接链接") 最小目录示例: ``` src ├── server │ ├── index.ts # defineConfiguration 入口 │ └── api │ └── user.api.ts # defineApi 声明文件 └── web └── api └── client.ts ``` ### `defineConfiguration`[​](#defineconfiguration "defineconfiguration的直接链接") * 作用:定义 Midway 函数式配置入口(替代 class `@Configuration`) * 等同于原 class 写法:`@Configuration(...)` class 示例: ``` // src/server/index.ts import { defineConfiguration } from '@midwayjs/core/functional'; import * as koa from '@midwayjs/koa'; export default defineConfiguration({ imports: [koa], }); ``` ### `defineApi`[​](#defineapi "defineapi的直接链接") * 作用:定义函数式 API 契约与路由(method/path/input/output/handle) * 等同于原 class 写法:`@Controller(...)` + `@Get/@Post/...` + 方法实现 示例: ``` // src/server/api/user.api.ts import { defineApi } from '@midwayjs/core/functional'; import { z } from 'zod'; export const userApi = defineApi('/users', api => ({ getUser: api .get('/:id') .input({ params: z.object({ id: z.string() }), }) .handle(async ({ input }) => { return { id: input.params.id, name: 'harry' }; }), })); ``` * 说明:`input(...)` 不只做校验,也会把类型传到 `handle(...)` ## Hooks[​](#hooks "Hooks的直接链接") ### `useContext`[​](#usecontext "usecontext的直接链接") * 作用:获取当前请求上下文 * 等同于原 class 写法:方法参数里直接使用 `@Context()`(或 `ctx` 入参) 示例: ``` // src/server/api/trace.api.ts import { defineApi, useContext } from '@midwayjs/core/functional'; export const traceApi = defineApi('/trace', api => ({ getTrace: api.get('/').handle(async () => { const ctx = useContext(); return { traceId: ctx?.headers?.['x-trace-id'] }; }), })); ``` ### `useLogger`[​](#uselogger "uselogger的直接链接") * 作用:获取当前上下文日志对象(或主应用 logger) * 等同于原 class 写法:`@Logger()` 注入或使用 `ctx.logger` 示例: ``` // src/server/api/log.api.ts import { defineApi, useLogger } from '@midwayjs/core/functional'; export const logApi = defineApi('/log', api => ({ ping: api.get('/ping').handle(async () => { const logger = useLogger(); logger.info('hello functional'); return 'ok'; }), })); ``` ### `usePlugin`[​](#useplugin "useplugin的直接链接") * 作用:从上下文或应用对象中获取插件能力 * 等同于原 class 写法:在 class 中通过 `ctx.app.xxx` / `this.app.xxx` 访问插件 * 说明:仅在 Egg 场景下使用,函数式常规场景不可用 示例: ``` // src/server/api/plugin.api.ts import { defineApi, usePlugin } from '@midwayjs/core/functional'; export const pluginApi = defineApi('/plugin', api => ({ info: api.get('/').handle(async () => { const cache = usePlugin('cache'); return { hasCache: !!cache }; }), })); ``` ### `useInject`[​](#useinject "useinject的直接链接") * 作用:异步获取 IoC 实例 * 等同于原 class 写法:`@Inject()` 属性注入后调用 示例: ``` // src/server/api/user.api.ts import { defineApi, useInject } from '@midwayjs/core/functional'; import { z } from 'zod'; import { UserService } from '../service/user.service'; export const userApi = defineApi('/users', api => ({ getUser: api .get('/:id') .input({ params: z.object({ id: z.string() }), }) .handle(async ({ input }) => { const userService = await useInject(UserService); return userService.find(input.params.id); }), })); ``` ### `useInjectSync`[​](#useinjectsync "useinjectsync的直接链接") * 作用:同步获取 IoC 实例 * 等同于原 class 写法:`@Inject()` 注入已就绪实例并同步使用 示例: ``` // src/server/api/sync.api.ts import { defineApi, useInjectSync } from '@midwayjs/core/functional'; import { UserService } from '../service/user.service'; export const syncApi = defineApi('/sync', api => ({ get: api.get('/').handle(async () => { const userService = useInjectSync(UserService); return userService.findSync?.('u-1'); }), })); ``` ### `useConfig`[​](#useconfig "useconfig的直接链接") * 作用:读取配置 * 等同于原 class 写法:`@Config()` 注入配置 示例: ``` // src/server/api/config.api.ts import { defineApi, useConfig } from '@midwayjs/core/functional'; export const configApi = defineApi('/config', api => ({ get: api.get('/').handle(async () => { const redisConfig = useConfig('redis'); return { redisConfig }; }), })); ``` ### `useApp`[​](#useapp "useapp的直接链接") * 作用:按名称获取应用实例 * 等同于原 class 写法:在框架类/上下文里按 appName 取应用实例 示例: ``` // src/server/api/app.api.ts import { defineApi, useApp } from '@midwayjs/core/functional'; export const appApi = defineApi('/app', api => ({ info: api.get('/').handle(async () => { const koaApp = useApp('koa'); return { appName: koaApp?.getFrameworkName?.() }; }), })); ``` ### `useMainApp`[​](#usemainapp "usemainapp的直接链接") * 作用:获取主应用实例 * 等同于原 class 写法:在 class 场景中直接拿主应用对象(app) 示例: ``` // src/server/api/main.api.ts import { defineApi, useMainApp } from '@midwayjs/core/functional'; export const mainApi = defineApi('/main', api => ({ info: api.get('/').handle(async () => { const app = useMainApp(); return { hasApp: !!app }; }), })); ``` ### `useInjectClient`[​](#useinjectclient "useinjectclient的直接链接") * 作用:从 `IServiceFactory` 获取客户端实例 * 等同于原 class 写法:注入 `IServiceFactory` 后调用 `get(...)` 示例: ``` // src/server/api/client.api.ts import { defineApi, useInjectClient } from '@midwayjs/core/functional'; import { HttpServiceFactory } from './httpServiceFactory'; // 示例类型 export const clientApi = defineApi('/client', api => ({ get: api.get('/').handle(async () => { const client = await useInjectClient(HttpServiceFactory, 'default'); return client.request?.('/ping'); }), })); ``` ### `useInjectDataSource`[​](#useinjectdatasource "useinjectdatasource的直接链接") * 作用:从 `IDataSourceManager` 获取数据源实例 * 等同于原 class 写法:注入 `IDataSourceManager` 后调用 `getDataSource(...)` 示例: ``` // src/server/api/db.api.ts import { defineApi, useInjectDataSource } from '@midwayjs/core/functional'; import { OrmDataSourceManager } from './ormDataSourceManager'; // 示例类型 export const dbApi = defineApi('/db', api => ({ get: api.get('/').handle(async () => { const db = await useInjectDataSource(OrmDataSourceManager, 'default'); return { connected: !!db }; }), })); ``` --- # 构建部署 Functional 一体化项目的实践建议是:开发一体化,部署分离化。 ## 推荐脚本[​](#推荐脚本 "推荐脚本的直接链接") ``` { "scripts": { "dev": "vite", "build:server": "tsc -p tsconfig.server.json", "build:web": "vite build", "build": "npm run build:server && npm run build:web" } } ``` ## 产物说明[​](#产物说明 "产物说明的直接链接") * `dist/server`:给 Node 运行 * `dist/web`:静态资源(Nginx/CDN) ## 常见部署方式[​](#常见部署方式 "常见部署方式的直接链接") 1. 启动服务端:`node dist/server/bootstrap.js` 2. 将 `dist/web` 托管到静态服务 3. 前端请求通过同域或反向代理转到服务端 API ## SSR / SSG 场景[​](#ssr--ssg-场景 "SSR / SSG 场景的直接链接") * 沿用前端框架官方流程 * Midway Functional 负责 API 契约和服务逻辑 * `basePath` 建议区分浏览器和服务端运行时配置 ``` basePath: { browser: '/api', server: 'http://127.0.0.1:7001/api', } ``` --- # 前端集成 这一节给出一条可直接落地的路线:把 React/Vue 项目和函数式 Midway 接起来。 ## 1. 安装依赖[​](#1-安装依赖 "1. 安装依赖的直接链接") 如果你已经是前端项目,只需补 Midway 相关依赖。 React: ``` $ npm i @midwayjs/core @midwayjs/web-bridge @midwayjs/mock @midwayjs/react zod ``` Vue: ``` $ npm i @midwayjs/core @midwayjs/web-bridge @midwayjs/mock @midwayjs/vue zod ``` ## 2. 准备目录[​](#2-准备目录 "2. 准备目录的直接链接") ``` . ├── package.json # 项目脚本与依赖 ├── vite.config.ts # Vite 配置(含 devPlugin/apiPlugin) ├── src │ ├── main.tsx / main.ts # React/Vue 入口 │ ├── web │ │ ├── app.tsx / app.vue # 前端根组件 │ │ └── api │ │ └── client.ts # 前端 API 客户端 │ └── server │ ├── index.ts # Midway 服务端入口(也可命名为 configuration.ts) │ └── api │ └── user.api.ts # 服务端 API 定义 └── tsconfig.json # TypeScript 配置 ``` ## 3. 定义服务端 API[​](#3-定义服务端-api "3. 定义服务端 API的直接链接") ``` // src/server/api/user.api.ts import { defineApi } from '@midwayjs/core/functional'; import { z } from 'zod'; export const userApi = defineApi('/users', api => ({ getUser: api .get('/:id') .input({ params: z.object({ id: z.string() }), }) .output( z.object({ id: z.string(), name: z.string(), }) ) .handle(async ({ input }) => { return { id: input.params.id, name: 'harry', }; }), })); ``` 这里有两个效果: 1. `input(...)` 会在运行时校验 `params/query/body/headers` 2. schema 的类型会继续传给 `handle(...)`,所以上面可以直接写 `input.params.id` ## 4. 创建前端 client[​](#4-创建前端-client "4. 创建前端 client的直接链接") React: ``` // src/web/api/client.ts import { createClient } from '@midwayjs/react'; import { userApi } from '../../server/api/user.api'; export const api = createClient( { user: userApi }, { basePath: '/api' } ); ``` Vue: ``` // src/web/api/client.ts import { createClient } from '@midwayjs/vue'; import { userApi } from '../../server/api/user.api'; export const api = createClient( { user: userApi }, { basePath: '/api' } ); ``` ## 5. 在页面里调用[​](#5-在页面里调用 "5. 在页面里调用的直接链接") React: ``` import { useEffect, useState } from 'react'; import { api } from './api/client'; export function UserPage() { const [name, setName] = useState(''); useEffect(() => { api.user.getUser({ params: { id: 'u-1' } }).then(user => { setName(user.name); }); }, []); return
{name}
; } ``` Vue: ``` // setup() const user = await api.user.getUser({ params: { id: 'u-1' }, }); ``` ## 6. 配置 Vite 桥接[​](#6-配置-vite-桥接 "6. 配置 Vite 桥接的直接链接") ``` import { defineConfig } from 'vite'; import { devPlugin } from '@midwayjs/mock/vite'; import { apiPlugin } from '@midwayjs/web-bridge/vite'; export default defineConfig({ plugins: [ devPlugin({ appDir: process.cwd(), baseDir: 'src/server', basePath: '/api', }), apiPlugin({ root: process.cwd(), apiDir: 'src/server/api', target: 'both', }), ], }); ``` * React 项目再加 `@vitejs/plugin-react` * Vue 项目再加 `@vitejs/plugin-vue` ## 7. 函数式中间件[​](#7-�函数式中间件 "7. 函数式中间件的直接链接") 路由级: ``` api.get('/:id').meta({ middleware: [authMw] }).handle(async () => ({})); ``` 模块级: ``` defineApi('/users', api => ({ getUser: api.get('/:id').handle(async () => ({})), }), { middleware: [authMw], }); ``` ## 8. 启动与验证[​](#8-启动与验证 "8. 启动与验证的直接链接") 1. `$ npm run dev` 2. 打开页面触发 API 调用 3. 在浏览器网络面板确认请求命中 `/api/*` ## 9. Rspack 场景(可选)[​](#9-rspack-场景可选 "9. Rspack 场景(可选)的直接链接") ``` createApiRspackRule({ root: process.cwd(), apiDir: 'src/server/api', }); ``` ## 10. 自定义目录说明[​](#10-自定义目录说明 "10. 自定义目录说明的直接链接") `src/web/api` 只是推荐目录,不是强制。你可以改成 `src/client/api` 等。 只要保证以下两处同步: 1. 前端 `client.ts` 的真实路径与导入路径 2. 构建插件 `apiDir` 指向正确的服务端 API 定义目录 --- # 函数式基础 这一章回答三个核心问题: 1. 函数式能力从哪里导出 2. 现有框架函数和 class 写法是什么关系 3. 为什么会演进出 `defineApi` ## 导出约定[​](#导出约定 "导出约定的直接链接") 函数式写法统一通过 `@midwayjs/core/functional` 及其子路径导出。 这里重点关注三类能力: * 配置入口:`defineConfiguration` * API 定义:`defineApi` * Hooks:`useContext`、`useInject`、`useConfig`、`useLogger`(以及同类 `use*` 能力) 示例: ``` import { defineConfiguration, defineApi, useInject, useContext, } from '@midwayjs/core/functional'; ``` ## 和 Class 写法的关系[​](#和-class-写法的关系 "和 Class 写法的关系的直接链接") 函数式不是替代 class,而是同一套框架能力的另一种表达方式。 | Class 写法 | 函数式写法 | 作用 | | ----------------------------- | ------------------------------------------------------- | ---------------------------------------------------- | | `@Configuration` class | `defineConfiguration(...)` | 定义应用入口配置、组件导入、运行时参数 | | `@Controller` + `@Get/@Post` | `defineApi(...)` + `api.get/api.post` | 声明路由、输入输出契约,并把 schema 类型传给 handler | | `@Inject()` | `useInject(...)` | 获取服务实例(IoC 注入) | | `@Config()` / `ctx.logger` 等 | `useConfig(...)` / `useLogger(...)` / `useContext(...)` | 读取配置、日志与上下文能力 | ## 框架函数对比示例[​](#框架函数对比示例 "框架函数对比示例的直接链接") ### 配置入口对比[​](#配置入口对比 "配置入口对比的直接链接") Class: ``` import { Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa], }) export class MainConfiguration {} ``` Functional: ``` import { defineConfiguration } from '@midwayjs/core/functional'; import * as koa from '@midwayjs/koa'; export default defineConfiguration({ imports: [koa], }); ``` ## 演进说明:为什么有 `defineApi`[​](#演进说明为�什么有-defineapi "演进说明为什么有-defineapi的直接链接") 当前函数式能力的重点是“和前端协同开发更顺滑”,所以引入了 `defineApi`: * 把服务端 API 契约直接暴露给前端 * 前端可直接使用类型化 client 调用 * 减少手写 `method/path` 和联调偏差 * `input/output` 既做运行时校验,也提供 handler 内的类型提示 ### `defineApi` 与 class 路由对比[​](#defineapi-与-class-路由对比 "defineapi-与-class-路由对比的直接链接") | 对比项 | Class 路由 | `defineApi` | | ------------ | ----------------------------- | -------------------------------------------------------- | | 组织方式 | Controller class + 方法 | 函数式对象声明 | | 前端复用契约 | 通常需额外抽取 | 天然可复用 `src/server/api/*.api.ts` | | 校验方式 | decorator + pipeline | `input/output` | | 中间件绑定 | controller / method decorator | `controllerOptions.middleware` / `.meta({ middleware })` | ### 同一个项目如何选[​](#同一个项目如何选 "同一个项目如何选的直接链接") * 需要和前端同仓协作:优先 `defineApi` * 纯后端 API:`@Controller` 和 `defineApi` 都可 * 存量系统:可按模块渐进迁移,不需要一次替换 --- # 概览 这套文档的目标只有一个:让你尽快把前后端联调跑起来。 如果你是第一次接触 Functional,建议按下面顺序阅读: 1. [函数式基础](/docs/functional/fundamentals.md) 2. [函数式 API](/docs/functional/api-reference.md) 3. [前端集成](/docs/functional/frontend-integration.md) 4. [参数校验](/docs/functional/validation.md) 5. [测试](/docs/functional/testing.md) 6. [构建部署](/docs/functional/build-deploy.md) ## 你会得到什么[​](#你会得到什么 "你会得到什么的直接链接") * 后端定义一次 API(method/path/参数) * 前端直接调用 `api.user.getUser(...)` * 调用参数和返回值都有类型提示 * 减少手写请求路径和联调沟通成本 ## 和现有写法的关系[​](#和现有写法的关系 "和现有写法的关系的直接链接") Functional 不是替代 Class Controller,两者可以无冲突共存。 选型建议: * 如果要和前端在同一仓库协同开发,优先使用 `defineApi`。 * 如果只是提供 API 服务,`@Controller` 和 `defineApi` 都可以,按团队习惯选择。 ## 整体流程[​](#整体流程 "整体流程的直接链接") 1. 在 `src/server/api` 定义接口(`defineApi`)。 2. 在前端通过 `createClient` 复用这份定义。 3. 页面里直接调用 `api.xxx.yyy()`。 4. 请求仍然发到服务端执行,不会在浏览器里执行后端代码。 ## 推荐目录(默认)[​](#推荐目录默认 "推荐目录(默认)的直接链接") ``` src ├── server │ └── api │ └── user.api.ts # 用户 API 定义(defineApi) └── web └── api └── client.ts # 前端 API 客户端创建 ``` 详细目录约束见:[一体化目录与边界](/docs/functional/workspace.md) ## 下一步[​](#下一步 "下一步的直接链接") * 想先了解概念:看 [函数式基础](/docs/functional/fundamentals.md) * 想查 API 清单:看 [函数式 API](/docs/functional/api-reference.md) * 想先做前端联调:看 [前端集成](/docs/functional/frontend-integration.md) * 想看参数校验:看 [参数校验](/docs/functional/validation.md) * 想先补测试:看 [测试](/docs/functional/testing.md) * 想准备上线:看 [构建与部署](/docs/functional/build-deploy.md) --- # 迁移指南 迁移建议是“渐进式”,不要一次改完。 ## 推荐迁移顺序[​](#推荐迁移顺序 "推荐迁移顺序的直接链接") 1. 保留现有 Service 层 2. 新接口先用 `defineApi` 3. 旧接口按模块逐步迁移 4. 关键接口补齐 `input/output` 5. 稳定后再删除旧 controller ## 共存策略[​](#共存策略 "共存策略的直接链接") 同一个项目里,`@Controller` 和 `defineApi` 可以直接共存,不需要强制分层或隔离。 按场景选择即可: * 需要和前端协同开发:优先 `defineApi` * 纯后端 API 提供:两种写法都可用 Midway 会按 `method + fullPath` 做冲突检测。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 前端可以直接执行后端 handler 吗?[​](#前端可以直接执行后端-handler-吗 "前端可以直接执行后端 handler 吗?的直接链接") 不能。前端只复用契约和类型,真实逻辑仍在服务端执行。 ### 必须用 `src/server`、`src/web` 吗?[​](#必须用-srcserversrcweb-吗 "必须用-srcserversrcweb-吗的直接链接") 不是,目录可以自定义。文档里的结构是推荐默认值。 ### 要一次性给所有接口补 schema 吗?[​](#要一次性给所有接口补-schema-吗 "要一次性给所有接口补 schema 吗?的直接链接") 不用。先覆盖高风险接口,再逐步补齐即可。 --- # React 集成 本节按“能跑起来”为目标,给出最小接入步骤。 ## 安装[​](#安装 "安装的直接链接") ``` $ npm i @midwayjs/react @midwayjs/web-bridge @midwayjs/mock ``` ``` { "dependencies": { "@midwayjs/react": "^4.0.0", "@midwayjs/web-bridge": "^4.0.0", "@midwayjs/mock": "^4.0.0" } } ``` ## 1. 创建客户端[​](#1-创建客户端 "1. 创建客户端的直接链接") ``` // src/web/api/client.ts import { createClient } from '@midwayjs/web-bridge'; import { userApi } from '../../server/api/user.api'; export const api = createClient( { user: userApi }, { basePath: '/api' } ); ``` ## 2. 在页面里调用[​](#2-在页面里调用 "2. 在页面里调用的直接链接") ``` import { useEffect, useState } from 'react'; import { api } from './api/client'; export function UserPage() { const [name, setName] = useState(''); useEffect(() => { api.user.getUser({ params: { id: 'u-1' } }).then(user => { setName(user.name); }); }, []); return
{name}
; } ``` ## 3. 配置 Vite 插件(推荐)[​](#3-配置-vite-插件推荐 "3. 配置 Vite 插件(推荐)的直接链接") ``` import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { devPlugin } from '@midwayjs/mock/vite'; import { apiPlugin } from '@midwayjs/web-bridge/vite'; export default defineConfig({ plugins: [ devPlugin({ appDir: process.cwd(), baseDir: 'src/server', basePath: '/api', }), react(), apiPlugin({ root: process.cwd(), apiDir: 'src/server/api', target: 'both', }), ], }); ``` 这两个插件的作用: * `devPlugin`:开发时把后端服务带起来 * `apiPlugin`:让 `server/api` 导入在浏览器端可运行 ## 4. 如果你用 Rspack[​](#4-如果你用-rspack "4. 如果你用 Rspack的直接链接") ``` import { defineConfig } from '@rspack/cli'; import { createApiRspackRule } from '@midwayjs/web-bridge/rspack'; export default defineConfig({ module: { rules: [ createApiRspackRule({ root: process.cwd(), apiDir: 'src/server/api', }), ], }, devServer: { proxy: [{ context: ['/api'], target: 'http://127.0.0.1:7001' }], }, }); ``` ## 示例仓库[​](#示例仓库 "示例仓库的直接链接") * `samples/react-functional-api` * `samples/react-functional-api-axios` * `samples/react-functional-api-rspack` --- # 测试 建议把 Functional API 的测试分成三层:契约层、服务端层、前端调用层。 ## 1. 契约层测试(快)[​](#1-契约层测试快 "1. 契约层测试(快)的直接链接") 目标:验证 `input/output` 与 handler 行为是否符合预期。 你可以直接测试 API 调用返回,重点覆盖: * 正常输入 * 非法输入(应该失败) * 边界输入(空值、极值) ## 2. 服务端集成测试(主力)[​](#2-服务端集成测试主力 "2. 服务端集成测试(主力)的直接链接") 目标:验证真实 HTTP 路由是否可用(含中间件、prefix、状态码)。 常见做法: * 用 `@midwayjs/mock` 启动测试 app * 用请求工具打 `/api/...` 路由 * 断言状态码、响应体、header 示例(简化): ``` import { close, createApp, createHttpRequest } from '@midwayjs/mock'; describe('functional api', () => { let app; beforeAll(async () => { app = await createApp(); }); afterAll(async () => { await close(app); }); it('GET /api/users/:id should work', async () => { const result = await createHttpRequest(app).get('/api/users/u-1'); expect(result.status).toBe(200); expect(result.body.id).toBe('u-1'); }); }); ``` ## 3. 前端调用层测试(按需)[​](#3-前端调用层测试按需 "3. 前端调用层测试(按需)的直接链接") 目标:验证页面调用 typed client 时的行为(成功、失败、loading)。 建议: * 单元测试里 mock client 返回值 * E2E 再验证一条真实链路 ## 推荐测试优先级[​](#推荐测试优先级 "推荐测试优先级的直接链接") 1. 先补服务端集成测试(收益最高) 2. 再补关键契约层测试(参数和返回) 3. 最后补前端调用层测试(交互体验) ## 覆盖点清单[​](#覆盖点清单 "覆盖点清单的直接链接") * 参数校验失败是否按预期报错 * 中间件是否生效(例如鉴权) * `globalPrefix` / version 路由是否正确 * 响应结构是否符合 `output(...)` --- # 参数校验 这一节说明 Functional API 里的参数校验方式,以及它和 class + decorator + pipeline 的关系。 ## 结论先说[​](#结论先说 "结论先说的直接链接") * Class 写法通常用参数装饰器 + pipe 机制做校验。 * Functional 写法用 `input(...)` / `output(...)` 做校验。 * 两者都能保证运行时安全,只是声明方式不同。 * Functional 场景下,`input(...)` 的 schema 类型还会继续传给 `handle(...)`。 ## Functional 的校验入口[​](#functional-的校验入口 "Functional 的校验入口的直接链接") 在 `defineApi` 里: * `input(...)`:校验请求输入(`params/query/body/headers`) * `output(...)`:校验响应输出 示例: ``` import { defineApi } from '@midwayjs/core/functional'; import { z } from 'zod'; export const userApi = defineApi('/users', api => ({ getUser: api .get('/:id') .input({ params: z.object({ id: z.string().min(1), }), query: z.object({ verbose: z.string().optional(), }), }) .output( z.object({ id: z.string(), name: z.string(), }) ) .handle(async ({ input }) => { return { id: input.params.id, name: 'harry', }; }), })); ``` 上面这段代码里: * `params.id` 在请求进入业务逻辑前会先做运行时校验 * `handle(...)` 里的 `input.params.id` 会直接拿到 `string` 类型提示 ## 失败时会发生什么[​](#失败时会发生什么 "失败时会发生什么的直接链接") * `input(...)` 校验失败:请求会在进入业务逻辑前失败。 * `output(...)` 校验失败:handler 返回后、响应前失败。 这样可以避免不合法数据进入服务层,也能避免错误响应结构流出。 ## 支持什么 schema[​](#支持什么-schema "支持什么 schema的直接链接") Functional 内部会调用 schema 的解析接口(如 `safeParse/safeParseAsync/parse/parseAsync`),因此像 zod 这类 schema 库可以直接使用。 ## 常见实践建议[​](#常见实践建议 "常见实践建��议的直接链接") 1. 先给核心接口加 `input(...)`,特别是写操作接口。 2. 再补 `output(...)`,保证前后端返回结构稳定。 3. 把业务校验(如权限、业务规则)留在 service 层,不要全堆在 schema。 --- # Vue 集成 这篇和 React 一样,先保证你能快速接通调用链路。 ## 1. 创建客户端[​](#1-创建客户端 "1. 创建客户端的直接链接") ``` // src/web/api/client.ts import { createClient } from '@midwayjs/vue'; import { userApi } from '../../server/api/user.api'; export const api = createClient( { user: userApi }, { basePath: '/api' } ); ``` ## 2. 在组件中调用[​](#2-在组件中调用 "2. 在组件中调用的直接链接") ``` // Vue setup() const user = await api.user.getUser({ params: { id: 'u-1' }, }); ``` ## 3. 推荐目录[​](#3-推荐目录 "3. 推荐目录的直接链接") ``` src ├── server │ └── api │ └── user.api.ts # 用户 API 定义(defineApi) └── web ├── app.vue # 前端应用根组件 └── api └── client.ts # 前端 API 客户端创建 ``` ## 4. 开发时你需要知道的事[​](#4-开发时你需要知道的事 "4. 开发时你需要知道的事的直接链接") * server 负责 API 定义与运行时逻辑 * web 直接复用 `src/server/api` 契约 * 构建阶段由桥接层处理浏览器可运行转换 ## 示例[​](#示例 "示例的直接链接") * `samples/vue-functional-api` --- # 目录与编辑 这一页解决两个常见问题: * 代码应该放在哪里? * 前端到底可以引用什么? ## 推荐目录[​](#推荐目录 "推荐目录的直接链接") ``` src ├── server │ ├── index.ts # Midway 服务端入口(也可命名为 configuration.ts) │ └── api │ └── user.api.ts # 用户 API 定义(defineApi) └── web ├── main.tsx # 前端启动入口 ├── app.tsx # 前端应用根组件 └── api └── client.ts # 前端 API 客户端创建 ``` 默认约定: * `serverDir`: `src/server` * `webDir`: `src/web` * `apiDir`: `src/server/api` 可改,不是强制。 ## 前端可引用 / 不可引用[​](#前端可引用--不可引用 "前端可引用 / 不可引用的直接链接") 前端可引用: * `src/server/api` 导出的 API 定义 * 类型和 schema 前端不要引用: * Node-only 模块(`fs` / `path` / `net`) * 服务端运行时代码 * handler 内部实现细节 ## 为什么这样划分[​](#为什么这样划分 "为什么这样划分的直接链接") 因为 `src/server/api/*.api.ts` 既是服务端路由契约,也是前端类型来源。 统一这一层后,可以减少重复定义和联调偏差。 ## 开发和发布[​](#开发和发布 "开发和发布的直接链接") 开发期:建议一个 `npm run dev` 入口。
发布期:仍然前后端分离产物和部署。 ## `web/api` 目录如何自定义[​](#webapi-目录如何自定义 "webapi-目录如何自定义的直接链接") `src/web/api` 只是推荐目录,不是强制。你可以改成: * `src/client/api` * `src/web/sdk` * 或任意团队习惯目录 重点是保持两件事一致: 1. 你的前端 client 文件导入路径 2. 构建插件里的 `apiDir`(服务端 API 定义目录) Vite 示例(把服务端 API 目录改为 `src/contracts/api`): ``` apiPlugin({ root: process.cwd(), apiDir: 'src/contracts/api', target: 'both', }); ``` Rspack 示例: ``` createApiRspackRule({ root: process.cwd(), apiDir: 'src/contracts/api', }); ``` 如果你同时改了 server 根目录,也要同步调整 `devPlugin` 的 `baseDir`。 --- # 守卫 从 v3.6.0 开始,Midway 提供守卫能力。 守卫会根据运行时出现的某些条件(例如权限,角色,访问控制列表等)来确定给定的请求是否由路由处理程序处理。 普通的应用程序中,一般会在中间件中处理这些逻辑,但是中间件的逻辑过于通用,同时也无法很优雅的去和路由方法进行结合,为此我们在中间件之后,进入路由方法之前设计了守卫,可以方便的进行方法鉴权等处理。 下面的代码,我们将以 `@midwayjs/koa` 举例。 ## 编写守卫[​](#编写守卫 "编写守卫的直接链接") 一般情况下,我们会在 `src/guard` 文件夹中编写守卫。 创建一个 `src/guard/auth.guard.ts` ,用于验证路由是否能被用户访问。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── guard │ │ └── auth.guard.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` Midway 使用 `@Guard` 装饰器标识守卫,示例代码如下。 ``` import { IMiddleware, Guard, IGuard } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // ... } } ``` `canActivate` 方法用于在请求中验证是否可以访问后续的方法,当返回 true 时,后续的方法会被执行,当 `canActivate` 返回 false 时,会抛出 403 错误码。 ## 使用守卫[​](#使用守卫 "使用守卫的直接链接") 守卫可以被应用到不同的框架上,在 http 下,可以应用到全局,Controller 和方法上,在其他的 Framework 实现中,仅能在方法上使用。 ### 路由守卫[​](#路由守卫 "路由守卫的直接链接") 在写完守卫之后,我们需要把它应用到各个控制器路由之上。 使用 `UseGuard` 装饰器,我们可以应用到类和方法上。 ``` import { Controller } from '@midwayjs/core'; import { AuthGuard } from '../guard/auth.guard'; @UseGuard(AuthGuard) @Controller('/') export class HomeController { } ``` 在方法上应用守卫。 ``` import { Controller, Get } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; import { AuthGuard } from '../guard/auth.guard'; @Controller('/') export class HomeController { @UseGuard(AuthGuard) @Get('/', { middleware: [ ReportMiddleware ]}) async home() { } } ``` 也可以传入数组。 ``` @UseGuard([AuthGuard, Auth2Guard]) ``` ### 全局守卫[​](#全局守卫 "全局守卫的直接链接") 我们需要在应用启动前,加入当前框架的守卫列表中,`useGuard` 方法,可以把守卫加入到守卫列表中。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { AuthGuard } from './guard/auth.guard'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useGuard(AuthGuard); } } ``` 同理可以添加多个守卫。 ``` async onReady() { this.app.useGuard([AuthGuard, Auth2Guard]); } ``` ## 自定义错误[​](#自定义错误 "自定义错误的直接链接") 默认情况下,守卫的 `canActivate` 方法当返回 false 时,框架会抛出 403 错误(`ForbiddenError`)。 你也可以在守卫中自行决定需要抛出的错误。 ``` import { IMiddleware, Guard, IGuard, httpError } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // ... if (methodName ==='xxx') { throw new httpError.ForbiddenError(); } return true; } } ``` 提示 注意全局错误处理器也会拦截守卫抛出的错误。 ## 和中间件的区别[​](#和中间件的区别 "和中间件的区别的直接链接") 守卫会在全局中间件 **之后**,路由方法业务逻辑 **之前** 执行。 中间件一般编写通用的处理逻辑,比如登录,用户识别,安全校验等,而守卫由于在路由内部,更适合做基于路由的权限控制。 中间件中虽然有路由信息,但是无法明确得知具体进入的是哪个实际的路由控制器(除非额外查询匹配),而守卫已经进入了路由方法,在性能方面有比较大的优势。 ## 基于角色的鉴权示例[​](#基于角色的鉴权示例 "基于角色的鉴权示例的直接链接") 一般情况下,我们会把方法访问和角色关联起来,下面我们来简单实现一个基于用户角色的访问控制。 首先,我们定义一个 `@Role` 装饰器,用于设定方法的访问权限。 ``` // src/decorator/role.decorator.ts import { savePropertyMetadata } from '@midwayjs/core'; export const ROLE_META_KEY = 'role:name' export function Role(roleName: string | string[]): MethodDecorator { return (target, propertyKey, descriptor) => { roleName = [].concat(roleName); // 只保存元数据 savePropertyMetadata(ROLE_META_KEY, roleName, target, propertyKey); }; } ``` 编写一个守卫,用于角色鉴权。 ``` // src/guard/auth.guard.ts import { Guard, IGuard, getPropertyMetadata } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { ROLE_META_KEY } from '../decorator/role.decorator'; @Guard() export class AuthGuard implements IGuard { async canActivate(context: Context, supplierClz, methodName: string): Promise { // 从类元数据上获取角色信息 const roleNameList = getPropertyMetadata(ROLE_META_KEY, supplierClz, methodName); if (roleNameList && roleNameList.length && context.user.role) { // 假设中间件已经拿到了用户角色信息,保存到了 context.user.role 中 // 直接判断是否包含该角色 return roleNameList.includes(context.user.role); } return false; } } ``` 在路由上使用该守卫。 ``` import { Controller, Get, UseGuard } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; import { AuthGuard } from '../guard/auth.guard'; import { Role } from '../decorator/role.decorator'; @UseGuard(AuthGuard) @Controller('/user') export class HomeController { // 只允许 admin 访问 @Role(['admin']) @Get('/getUserRoles') async getUserRoles() { // ... } } ``` 只有当 `ctx.user.role` 返回了 `admin` 的时候,才会被允许访问 `/getUserRoles` 路由。 --- # 接口开发 ## 路由[​](#路由 "路由的直接链接") 在 Midway Hooks 中,你可以通过 `@midwayjs/hooks` 提供的 `Api()` 函数来快速创建接口。 Hello World 示例: /src/hello.ts ``` import { Api, Get, } from '@midwayjs/hooks'; export default Api( Get(), // Http Path: /api/hello, async () => { return 'Hello World!'; } ); ``` 一个 API 接口由以下部分组成: * `Api()`:定义接口函数 * `Get(path?: string)`:指定 Http 触发器,指定请求方法为 GET,可选参数 `path` 为接口路径,不指定路径的情况下会根据`函数名 + 文件名`生成路径,默认带有 `/api` 前缀 * `Handler: async (...args: any[]) => { ... }`:用户逻辑,处理请求并返回结果 你也可以指定路径,例子如下。 /src/hello.ts ``` import { Api, Get, } from '@midwayjs/hooks'; export default Api( Get('/hello'), // Http Path: /hello, async () => { return 'Hello World!'; } ); ``` ## 请求上下文(Context / Request / Response)[​](#请求上下文context--request--response "请求上下文(Context / Request / Response)的直接链接") 你可以通过 `@midwayjs/hooks` 提供的 `useContext` 来获取请求上下文对象。 以使用 [Koa](https://koajs.com/) 框架为例,那么 `useContext` 将返回 Koa 的 [Context](https://koajs.com/#context) 对象。 基础示例: 1. 获取请求 Method 和 Path ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); return { method: ctx.method, path: ctx.path, }; }); ``` 2. 设置返回的 Header ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.set('X-Powered-By', 'Midway'); return 'Hello World!'; }); ``` 同时我们也可以通过 `SetHeader()` 来设置 Header。 ## Http 触发器[​](#http-触发器 "Http 触发器的直接链接") | 触发器 | 注释 | | ------------------------ | --------------------------- | | `All(path?: string)` | 接受所有 Http Method 的请求 | | `Get(path?: string)` | 接受 GET 请求 | | `Post(path?: string)` | 接受 POST 请求 | | `Put(path?: string)` | 接受 PUT 请求 | | `Delete(path?: string)` | 接受 DELETE 请求 | | `Patch(path?: string)` | 接受 PATCH 请求 | | `Head(path?: string)` | 接受 HEAD 请求 | | `Options(path?: string)` | 接受 OPTIONS 请求 | ## 请求 Request[​](#请求-request "请求 Request的直接链接") ### 传递参数 Data[​](#传递参数-data "传递参数 Data的直接链接") 在 Midway Hooks 中,接口的入参就是声明函数的参数。 基础示例如下: ``` import { Api, Post, } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 你可以用两种方式来调用接口。 1. 全栈项目:基于零 Api,导入接口并调用 2. 手动调用:使用 fetch 在 Http 下,`Handler(...args: any[])` 的入参,可以在手动请求时通过设置 Http Body 的 args 参数来传递参数。 * 全栈应用(零 Api) * 手动调用 ``` import say from './api'; const response = await say('Midway'); console.log(response); // Hello Midway! ``` ``` fetch('/api/say', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ args: ['Midway'], }), }) .then((res) => res.text()) .then((res) => console.log(res)); // Hello Midway! ``` ### 查询参数 Query[​](#查询参数-query "查询参数 Query的直接链接") 查询参数可以实现在 URL 上传递参数的方式,使用该功能时,必须通过 `Query` 声明类型。 如果希望接口路径是 `/articles?page=0&limit=10`,可以这样写。 ``` import { Api, Get, Query, useContext, } from '@midwayjs/hooks'; export default Api( Get(), Query<{ page: string; limit: string; }>(), async () => { const ctx = useContext(); return { page: ctx.query.page, limit: ctx.query.limit, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getArticles from './api'; const response = await getArticles({ query: { page: '0', limit: '10' }, }); console.log(response); // { page: '0', limit: '10' } ``` ``` fetch('/api/articles?page=0&limit=10') .then((res) => res.json()) .then((res) => console.log(res)); // { page: '0', limit: '10' } ``` ### 路径参数 Params[​](#路径参数-params "路径参数 Params的直接链接") 路径参数可以实现动态路径和从路径中获取参数的功能。使用该功能时,必须手动设置路径,并通过 `Params` 声明类型。 如果希望接口路径是 `/article/100`,并获取 id 为 `100` 的值,可以这样写: ``` import { Api, Get, Params, useContext, } from '@midwayjs/hooks'; export default Api( Get('/article/:id'), Params<{ id: string }>(), async () => { const ctx = useContext(); return { article: ctx.params.id, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getArticle from './api/article'; const response = await getArticle({ params: { id: '100' }, }); console.log(response); // { article: '100' } ``` ``` fetch('/article/100') .then((res) => res.json()) .then((res) => console.log(res)); // { article: '100' } ``` ### 请求头 Headers[​](#请求头-headers "请求头 Headers的直接链接") 请求头可以实现通过 Http Headers 传递参数的功能,使用该功能时,必须通过 `Headers` 声明类型。 如果希望请求 `/auth`,并在 `Request Headers` 中 传递 token,可以这样写: ``` import { Api, Get, Headers, useContext, } from '@midwayjs/hooks'; export default Api( Get('/auth'), Headers<{ token: string }>(), async () => { const ctx = useContext(); return { token: ctx.headers.token, }; } ); ``` 前端调用 * 全栈应用 * 手动调用 ``` import getAuth from './api/auth'; const response = await getAuth({ headers: { token: '123456' }, }); console.log(response); // { token: '123456' } ``` ``` fetch('/auth', { headers: { token: '123456', }, }) .then((res) => res.json()) .then((res) => console.log(res)); // { token: '123456' } ``` ## 响应 Response[​](#响应-response "响应 Response的直接链接") ### 状态码 HttpCode[​](#状态码-httpcode "状态码 HttpCode的直接链接") 支持 `HttpCode(status: number)` * SetHeader * 手动设置 ``` import { Api, Get, HttpCode, } from '@midwayjs/hooks'; export default Api( Get(), HttpCode(201), async () => { return 'Hello World!'; } ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.status = 201; return 'Hello World!'; }); ``` ### 响应头 SetHeader[​](#响应头-setheader "响应头 SetHeader的直接链接") 支持 `SetHeader(key: string, value: string)` * SetHeader * 手动设置 ``` import { Api, Get, SetHeader, } from '@midwayjs/hooks'; export default Api( Get(), SetHeader('X-Powered-By', 'Midway'), async () => { return 'Hello World!'; } ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api(Get(), async () => { const ctx = useContext(); ctx.set('X-Powered-By', 'Midway'); return 'Hello World!'; }); ``` ### 重定向 Redirect[​](#重定向-redirect "重定向 Redirect的直接链接") 支持: `Redirect(url: string, code?: number = 302)` * Redirect * 手动设置 ``` import { Api, Get, Redirect, } from '@midwayjs/hooks'; export default Api( Get('/demo'), Redirect('/hello'), async () => {} ); ``` ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; export default Api( Get('/demo'), async () => { const ctx = useContext(); ctx.redirect('/hello'); } ); ``` ### 返回值类型 ContentType[​](#返回值类型-contenttype "返回值类型 ContentType的直接链接") 支持: `ContentType(type: string)`。 * ContentType * 手动设置 ``` import { Api, Get, ContentType, } from '@midwayjs/hooks'; export default Api( Get(), ContentType('text/html'), async () => { return '

Hello World!

'; } ); ``` ``` import { Api, Get, ContentType, } from '@midwayjs/hooks'; export default Api( Get(), ContentType('text/html'), async () => { return '

Hello World!

'; } ); ``` --- # Hooks Midway Hooks 可以通过使用 `Hooks` 函数来获取运行时上下文。 ## 语法[​](#语法 "语法的直接链接") Hooks 需要在 Api 接口中使用。 有效的例子: ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); console.log(ctx.method); // ... }); ``` 无效例子: ``` import { useContext } from '@midwayjs/hooks'; const ctx = useContext(); // will throw error ``` ## 支持的 Hooks[​](#支持的-hooks "支持的 Hooks的直接链接") ### useContext[​](#usecontext "useContext的直接链接") `useContext()` 函数将返回本次请求相关的上下文,返回的 `Context` 与底层使用的框架决定。 以使用 [Koa](https://koajs.com/) 框架为例,那么 `useContext` 将返回 Koa 的 [Context](https://koajs.com/#context) 对象。 以获取请求 Method 和 Path 为例。 ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; export default Api(Get(), async () => { const ctx = useContext(); return { method: ctx.method, path: ctx.path, }; }); ``` 你可以通过泛型来标注当前上下文的类型。 ``` // Koa import { Context } from '@midwayjs/koa'; const ctx = useContext(); // FaaS import { Context } from '@midwayjs/faas'; const ctx = useContext(); ``` ## 创建可复用的 Hooks[​](#创建可复用的-hooks "创建可复用的 Hooks的直接链接") 你可以创建可复用的 Hooks,以便在多个接口中使用。 ``` import { Api, Get, useContext, } from '@midwayjs/hooks'; import { Context } from '@midwayjs/koa'; function useIp() { const ctx = useContext(); return ctx.ip; } export default Api(Get(), async () => { const ip = useIp(); return { ip, }; }); ``` 一体化调用: ``` import getIp from './api'; const { ip } = await getIp(); console.log(ip); // 127.0.0.1 ``` --- # 前端请求客户端 在 Midway Hooks 的全栈应用中,我们使用 `@midwayjs/rpc` 作为默认的请求客户端。所有生成的接口都会通过 `@midwayjs/rpc` 来调用服务端。 ## 配置[​](#配置 "配置的直接链接") `@midwayjs/rpc` 提供了 `setupHttpClient` 方法来配置请求客户端(📢 `setupHttpClient` 应放置于前端代码的入口处。)。 支持的配置项如下: ``` type SetupOptions = { baseURL?: string; withCredentials?: boolean; fetcher?: Fetcher; middleware?: Middleware[]; }; type Fetcher = ( req: HttpRequestOptions, options: SetupOptions ) => Promise; type Middleware = ( ctx: Context, next: () => Promise ) => void; type Context = { req: HttpRequestOptions; res: any; }; type HttpRequestOptions = { url: string; method: HttpMethod; data?: { args: any[]; }; // query & headers query?: Record; headers?: Record; }; ``` ### baseURL: string[​](#baseurl-string "baseURL: string的直接链接") 设置请求的基础 URL,默认为 `/`。 ``` import { setupHttpClient } from '@midwayjs/rpc'; setupHttpClient({ baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:7001' : 'https://api.example.com', }); ``` ### withCredentials: boolean[​](#withcredentials-boolean "withCredentials: boolean的直接链接") 默认为 `false`。具体可参考:[MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials) ``` import { setupHttpClient } from '@midwayjs/rpc'; setupHttpClient({ withCredentials: true, }); ``` ### fetcher: Fetcher[​](#fetcher-fetcher "fetcher: Fetcher的直接链接") `@midwayjs/rpc` 默认使用 [redaxios](https://github.com/developit/redaxios) 作为请求客户端,一个遵循 axios api 的 mini 客户端。 通过设置 `fetcher`,可以替换默认的请求客户端。此处以使用 `axios` 作为默认的请求客户端为例。 ``` import axios from 'axios'; import { setupHttpClient } from '@midwayjs/rpc'; import type { Fetcher } from '@midwayjs/rpc'; const fetcher: Fetcher = async ( req, options ) => { const response = await axios({ method: req.method, url: req.url, data: req.data, params: req.query, headers: req.headers, baseURL: options.baseURL, withCredentials: options.withCredentials, }); return response.data; }; setupHttpClient({ fetcher }); ``` ### middleware: Middleware\[][​](#middleware-middleware "middleware: Middleware\[]的直接链接") 在 `@midwayjs/rpc` 中,我们可以设置中间件来用于打印参数,返回值处理错误等。 以打印当前请求的地址与返回值为例: ``` import { setupHttpClient } from '@midwayjs/rpc'; import type { Middleware } from '@midwayjs/rpc'; const logger: Middleware = async ( ctx, next ) => { console.log(`<-- ${ctx.req.url}`); await next(); console.log( `--> ${ctx.req.url} ${ctx.res}` ); }; setupHttpClient({ middleware: [logger], }); ``` 你也可以用于统一处理错误: 使用默认 `fetcher` 的情况下,`err` 类型参考:[Axios Response Schema](https://axios-http.com/docs/res_schema)。 ``` import { setupHttpClient } from '@midwayjs/rpc'; import type { Middleware } from '@midwayjs/rpc'; const ErrorHandler: Middleware = async ( ctx, next ) => { try { await next(); } catch (err) { switch (err.status) { case 401: location.href = '/login'; break; case 500: alert('Internal Server Error'); break; default: alert( `Unknown Error, status: ${err.status}` ); break; } } }; setupHttpClient({ middleware: [ErrorHandler], }); ``` --- # 使用 Midway 组件 Midway 提供了一系列的组件,包含 Cache / Http / Redis 等。 而在 Midway Hooks 中,我们可以直接使用 Midway 组件,来快速实现功能。 ## 引入组件[​](#引入组件 "引入组件的直接链接") Midway Hooks 在 `configuration.ts` 中使用 `createConfiguration()` 来配置项目,其 Api 与 `@midwayjs/decorator` 提供的 `@Configuration()` 一致。 以 `@midwayjs/cache` 组件为例: ``` import { createConfiguration, hooks, } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; import { join } from 'path'; import * as cache from '@midwayjs/cache'; export default createConfiguration({ imports: [cache, Koa, Hooks()], importConfigs: [ join(__dirname, 'config'), ], }); ``` 你可以通过 `imports` 来导入组件,`importConfigs` 来导入配置文件。 ## 使用组件[​](#使用组件 "使用组件的直接链接") 在 `@midwayjs/cache` 中,提供了 `CacheManager` 类来操作缓存。 在 Midway Hooks 中,你可以通过 `@midwayjs/hooks` 提供的 `useInject(class)` 来在运行时获取类的实例。 ``` import { Api, Get, useInject, } from '@midwayjs/hooks'; import { CacheManager } from '@midwayjs/cache'; export default Api(Get(), async () => { const cache = await useInject( CacheManager ); await cache.set('name', 'Midway'); const result = await cache.get( `name` ); return `Hello ${result}!`; }); ``` 这里的 `useInject(CacheManager)` 与 `@Inject() cache: CacheManager` 的功能是一致的。 --- # 项目配置 我们通过项目根目录下的 `midway.config.ts` 来配置项目,具体的配置项如下。 > 如果是纯接口项目,因为需要在生成环境读取配置,因此请使用 JavaScript,配置文件名: `midway.config.js` ## source: string[​](#source-string "source: string的直接链接") 配置后端根目录,纯服务接口下默认为 `./src`,全栈应用下默认为 `./src/api`。 ## routes: RouteConfig\[][​](#routes-routeconfig "routes: RouteConfig\[]的直接链接") 启用文件系统路由并配置,默认为 `undefined`。具体格式参考 [简易模式 & 文件系统路由](/docs/hooks/file-route.md)。 ## dev.ignorePattern: IgnorePattern[​](#devignorepattern-ignorepattern "dev.ignorePattern: IgnorePattern的直接链接") 配置全栈应用下,本地开发的哪些请求应该忽略,不进入服务端处理。 ## build.outDir: string[​](#buildoutdir-string "build.outDir: string的直接链接") 配置全栈应用的输出目录,默认为 `./dist`。 ## vite: ViteConfig[​](#vite-viteconfig "vite: ViteConfig的直接链接") 仅 `import { defineConfig } from '@midwayjs/hooks-kit'` 时可用。 配置全栈应用下 Vite 的配置,具体配置项参考 [Vite](https://vitejs.dev/config/)。 例子: ``` import react from '@vitejs/plugin-react'; import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ vite: { plugins: [react()], }, }); ``` --- # 跨域 CORS 在 Midway Hooks 中,可以通过 [@koa/cors](https://github.com/koajs/cors) 来配置跨域功能。 ## 使用方法[​](#使用方法 "使用方法的直接链接") 安装 `@koa/cors` 依赖。 ``` npm install @koa/cors ``` 在 `configuration.ts` 启用 `@koa/cors` 中间件。 ``` import { createConfiguration, hooks, } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; import cors from '@koa/cors'; export default createConfiguration({ imports: [ Koa, hooks({ middleware: [ cors({ origin: '*' }), ], }), ], }); ``` 支持的[配置项](https://github.com/koajs/cors#corsoptions)如下: ``` /** * CORS middleware * * @param {Object} [options] * - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header * - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH' * - {String|Array} exposeHeaders `Access-Control-Expose-Headers` * - {String|Array} allowHeaders `Access-Control-Allow-Headers` * - {String|Number} maxAge `Access-Control-Max-Age` in seconds * - {Boolean|Function(ctx)} credentials `Access-Control-Allow-Credentials`, default is false. * - {Boolean} keepHeadersOnError Add set headers to `err.header` if an error is thrown * @return {Function} cors middleware * @api public */ ``` --- # 调试 得益于编辑器的支持,我们可以快速的在本地调试应用。 ## VSCode[​](#vscode "VSCode的直接链接") ### JavaScript Debug Terminal[​](#javascript-debug-terminal "JavaScript Debug Terminal的直接链接") 在 VSCode 中创建 JavaScript Debug Terminal。 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789601759-d2634846-49f7-4487-be6f-0dc9e5f80082.png#clientId=u3a1b2f6d-ebe0-4\&from=paste\&height=192\&id=p5BOe\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=192\&originWidth=375\&originalType=binary\&size=31856\&status=done\&style=none\&taskId=u7286159b-9369-4d17-8a6a-c43a6f52556\&width=375) 在命令行中运行命令(如 `npm start`),将自动启用调试模式。 ### Debug Scripts[​](#debug-scripts "Debug Scripts的直接链接") 打开 `package.json`,查看 `scripts` 上方的 `debug` 按钮 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789617835-64b2099a-6b94-41c4-81fa-4f0bb0763ebb.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=225\&id=u459844f5\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=225\&originWidth=565\&originalType=binary\&size=26636\&status=done\&style=none\&taskId=u3838b111-c93e-41e0-81ce-01c1bdd6ad4\&width=565) 选择 `start` 命令,既可正常的启动调试模式 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789623261-57851b50-421e-45fa-9dd9-95ac7d48776e.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=170\&id=ue315d401\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=170\&originWidth=427\&originalType=binary\&size=19905\&status=done\&style=none\&taskId=u8b079aa2-8376-4014-b48b-ed27ef66da6\&width=427) ## Jetbrains (WebStorm/IDEA...)[​](#jetbrains-webstormidea "Jetbrains (WebStorm/IDEA...)的直接链接") 打开 `package.json`,选择你要执行的 `scripts` ,并点击 `debug` 按钮,即可启动本地调试。 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/98602/1622789628840-eb403a2a-a864-4fd6-8f57-3f576c9b3417.png#clientId=u7ee4f0d0-4c66-4\&from=paste\&height=176\&id=uc2a06ce8\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=176\&originWidth=548\&originalType=binary\&size=28656\&status=done\&style=none\&taskId=ucb4c5c34-6e56-47c9-a724-4ed700dce9d\&width=548) --- # 部署 Midway Hooks 支持 Api Server 与一体化两种模式。 ## Api Server 部署[​](#api-server-部署 "Api Server 部署的直接链接") Api Server 部署可以参考:[启动和部署](/docs/deployment.md)。 如果使用单文件部署,可以参考示例:[hooks-api-bundle-starter](https://github.com/midwayjs/hooks/blob/main/examples/api-bundle/readme.md) ## 一体化部署[​](#一体化部署 "一体化部署的直接链接") 一体化的构建产物中包含前后端,根据部署的难易程度,可以分为以下几类。 * 前后端部署在同一服务器上,由后端托管 HTML & 静态资源 & 提供接口 * 静态资源部署至 CDN,后端托管 HTML & 提供接口 * 静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口 接下来我将介绍三种部署模式如何落地,优势及存在的问题。 ### 前后端部署在同一服务器上[​](#前后端部署在同一服务器上 "前后端部署在同一服务器上的直接链接") 这是全栈套件默认的部署模式。 优势:最简单,将打包后的产物直接上传至服务器,启动后即可提供服务 劣势: * 后端服务需要处理 & 发送文件 * 静态资源不在 CDN,不同地域的访问速度不稳定 整体部署架构如图所示: ![](https://img.alicdn.com/imgextra/i1/O1CN01GYtN9n1T2tbEXWOwf_!!6000000002325-2-tps-2064-648.png) ### 静态资源部署至 CDN,后端托管 HTML & 提供接口[​](#静态资源部署至-cdn后端托管-html--提供接口 "静态资源部署至 CDN,后端托管 HTML & 提供接口的直接链接") 这也是当前前端主流的部署模式。 优势: * 静态资源由 CDN 托管,保证用户访问速度 * 后端托管 HTML,确保返回的 HTML 文件是最新的 劣势: * 后端仍需要托管 HTML,仍需要处理 & 发送文件,且如果服务宕机则页面无法访问 整体访问架构如图所示: ![](https://img.alicdn.com/imgextra/i4/O1CN01ue3LJg1HeernvfxgQ_!!6000000000783-55-tps-267-367.svg) #### 指定静态资源公共域名[​](#指定静态资源公共域名 "指定静态资源公共域名的直接链接") 在全栈套件项目中使用时,可以通过设置 `midway.config.ts` 中 `vite.base` 选项,来指定静态资源的公共域名。 ``` import react from '@vitejs/plugin-react'; import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ vite: { plugins: [react()], base: 'https://cdn.example.com', }, }); ``` 此时访问页面时,静态资源会指向 CDN 的地址。 #### 部署静态文件[​](#部署静态文件 "部署静态文件的直接链接") 全栈套件项目中,默认的构建目录为 dist,其中 `dist/_clients` 为前端静态资源目录。 如下所示: ``` dist ├── _client │   ├── assets │   │   ├── index.85bb4f15.js │   │   ├── index.b779b14d.css │   │   └── vendor.346bc0da.js │   ├── index.html │   ├── logo.png │   └── manifest.json ├── _serve │   └── index.js ├── book.js ├── configuration.js ├── date.js ├── midway.config.js └── star.js ``` 你需要自行将 `_client` 目录下的文件上传至 CDN,而在部署后端时,仍然保留 `_client/index.html` 文件,以供后端托管使用。 ### 静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口[​](#静态资源部署至-cdnhtml-由单独的服务托管cdn--nginx--etc后端仅提供接口 "静态资源部署至 CDN,HTML 由单独的服务托管(CDN / Nginx / etc.),后端仅提供接口的直接链接") 这也是前端目前主流的部署模式。 优势: * 后端仅提供 API 接口,不需要处理 & 发送文件 * 静态资源由 CDN 托管,保证用户访问速度 * HTML 由单独服务托管,保证访问是页面是最新版本,后端服务宕机不影响页面展示 * 架构可拓展,可增加更多节点应对意外情况,如在后端前置增加网关节点,在后端服务宕机时切换至备用服务等 劣势: * 复杂,对 CI / CD 流水线及基建要求高 整体访问架构如图所示 ![](https://img.alicdn.com/imgextra/i1/O1CN01i78JiC1yinvfLq84b_!!6000000006613-55-tps-323-367.svg) 部署工作流如下: ![](https://img.alicdn.com/imgextra/i2/O1CN018oAQf71h1QxHtRHYY_!!6000000004217-2-tps-1728-1680.png) #### 全栈套件部署指南[​](#全栈套件部署指南 "全栈套件部署指南的直接链接") 需要默认禁用全栈套件的 index.html 托管能力,此时全栈套件在构建时不会生成 `index.html` 的托管函数,仅提供 Api 服务。 ``` import { defineConfig } from '@midwayjs/hooks-kit'; export default defineConfig({ static: false, }); ``` 在你的 CI / CD 工作流中,需要针对以下文件做单独处理。 * index.html:部署至单独的托管服务,如 Nginx / CDN 等,该服务只负责静态页面渲染 * 静态资源:部署至 CDN,如 Aliyun OSS 等,该服务可以提供静态资源的 CDN 加速 * Api 服务:部署至你的服务器中 最终的域名可能如下: * index.html: * 静态资源: * Api 服务: 或者 [https://example.com/api(需要设置反向代理)](https://example.com/api%EF%BC%88%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%EF%BC%89) --- # 简易模式 & 文件系统路由 ## 简易模式[​](#简易模式 "简易模式的直接链接") 在 Midway Hooks 中,我们提供了一个简易模式,可以使用纯函数来快速创建接口。 📢 注意: * 简易模式需启用文件路由系统,需要在 `midway.config.js` 中启用 `routes` 配置。 * 纯函数自动生成的路由仅支持 `GET` 和 `POST` 方法,且全栈应用中,不支持传递 `Query / Params / Header` 参数 * 简易模式下,仍可以使用 `Api()` 定义路由,且支持手动定义路径,拼接的路径将自动加上 `basePath` ### Get 请求[​](#get-请求 "Get 请求的直接链接") ``` import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } ``` 一体化调用: ``` import { getPath } from './api/lambda'; const path = await getPath(); console.log(path); // /api/getPath ``` 手动调用: ``` fetcher .get('/api/getPath') .then((res) => { console.log(res.data); // /api/getPath }); ``` ### Post 请求[​](#post-请求 "Post 请求的直接链接") ``` import { useContext } from '@midwayjs/hooks'; export async function post( name: string ) { const ctx = useContext(); return { message: `Hello ${name}!`, method: ctx.method, }; } ``` 一体化调用: ``` import { post } from './api/lambda'; const response = await post('Midway'); console.log(response.data); // { message: 'Hello Midway!', method: 'POST' } ``` 手动调用: ``` fetch('/api/post', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ args: ['Midway'], }), }).then((res) => { console.log(res.data); // { message: 'Hello Midway!', method: 'POST' } }); ``` ### 通过 `Api()` 创建路由[​](#通过-api-创建路由 "通过-api-创建路由的直接链接") 简易模式下,我们仍支持通过 `Api()` 创建路由。 无效的例子:`Api(Get('/specify_path'))`,简易模式下不支持手动指定路径。 有效的例子,导出了两个路由。 ``` import { Api, Get, } from '@midwayjs/hooks'; import { useContext } from '@midwayjs/hooks'; export async function getPath() { // Get HTTP request context by Hooks const ctx = useContext(); return ctx.path; } export default Api(Get(), async () => { return 'Hello Midway!'; }); ``` ## 文件系统路由[​](#文件系统路由 "文件系统路由的直接链接") 在 `midway.config.js` 中启用 `routes` 配置即启用文件路由系统 + 简易模式。 配置示例如下: ``` import { defineConfig } from '@midwayjs/hooks'; export default defineConfig({ source: './src/apis', routes: [ { baseDir: 'lambda', basePath: '/api', }, ], }); ``` 字段解释: * source: 后端目录,默认为 `./src/apis`,你也可以指定为 `./src/functions` 等自定义目录 * routes: 路由配置,默认为数组 * baseDir: 函数文件夹,文件夹下任意 `.ts` 文件导出的异步函数都会生成为 Api 接口 * basePath: 生成的 Api 地址前缀 ### Index 路由[​](#index-路由 "Index 路由的直接链接") 我们会将目录下 `index.ts` 文件,作为根路由。 * `/lambda/index.ts` → `/` * `/lambda/about/index.ts` → `/about` ### 嵌套路由[​](#嵌套路由 "嵌套路由的直接链接") 嵌套的文件也将生成嵌套的路由
* `/lambda/about.ts` → `/about` * `/lambda/blog/index.ts` → `/blog` * `/lambda/about/contact.ts` → `/about/contact` ### 导出方法与对应路由[​](#导出方法与对应路由 "导出方法与对应路由的直接链接") 默认导出的方法则会生成为根路径,而具名方法则会在路径上拼接函数名。 在此以 `/lambda/about.ts` 为例 * `export default () => {}` → `/about` * `export function contact ()` → `/about/contact` ### 通配路由[​](#通配路由 "通配路由的直接链接") 如果需要生成通配符路由,例如:`/api/*` ,用于匹配 /api、/api/about、/api/about/a/b/c 等。文件名按 `[...file]` 命名即可。 📢 推荐在通配路由中,只使用 `export default` 方法导出函数,从而避免不必要的路由冲突 示例: * `/lambda/[...index].ts` → `/api/*` * `/lambda/[...user].ts` → `/api/user/*` * `/lambda/about/[...contact].ts` → `/api/about/contact/*` ### 路径参数[​](#路径参数 "路径参数的直接链接") 如果需要生成动态路径参数,文件名按 `[file]` 格式命名即可。 例子: * `/lambda/[name]/project.ts` → `/api/about/:name/project` * `/about/midwayjs/project` -> `{ name: 'midwayjs' }` * `/lambda/[type]/[page].ts` → `/api/about/:type/:page` * `/blog/1` -> `{ type: 'blog', page: '1' }` * `/articles/3` -> `{ type: 'articles', page: '3' }` 使用路径参数时,后端接口仅支持使用 `Api()` 开发,并使用 `Params` 标注类型。 以 `/lambda/[name]/project.ts` 为例: ``` // lambda/[name]/project.ts import { Api, Get, Params, useContext, } from '@midwayjs/hooks'; export default Api( Get(), Params<{ name: string }>(), async () => { const ctx = useContext(); return { name: ctx.params.name, }; } ); ``` 一体化调用: ``` import getProject from './api/[name]/project'; const response = await getProject({ params: { name: 'midwayjs' }, }); console.log(response); // { name: 'midwayjs' } ``` 手动调用: ``` fetch('/api/about/midwayjs/project') .then((res) => res.json()) .then((res) => console.log(res)); // { name: 'midwayjs' } ``` --- # 全栈套件 在 Midway Hooks 中,我们提供了 `@midwayjs/hooks-kit` 来快速开发全栈应用。目前我们提供了以下可直接使用的模版: * [react](https://github.com/midwayjs/hooks/blob/main/examples/react) * [vue](https://github.com/midwayjs/hooks/blob/main/examples/vue) * [prisma](https://github.com/midwayjs/hooks/blob/main/examples/prisma) ## 命令行界面[​](#命令行界面 "命令行界面的直接链接") 在使用了 `@midwayjs/hooks-kit` 的项目中,可以在 npm scripts 中使用 hooks 可执行文件,或者通过 `npx hooks` 运行。下面是通过脚手架创建的 Midway 全栈项目中默认的 npm scripts: ``` { "scripts": { "dev": "hooks dev", // 启动开发服务器 "start": "hooks start", // 启动生产服务器,使用前请确保已运行 `npm run build` "build": "hooks build" // 为生产环境构建产物 } } ``` 在使用命令行时,可以通过命令行参数传入选项,具体选项可以通过 --help 参考。 如:`hooks build --help` 输出: ``` Usage: $ hooks build [root] Options: --outDir [string] output directory (default: dist) --clean [boolean] clean output directory before build (default: false) -h, --help Display this message ``` --- # 介绍 警告 一体化方案将逐步停止维护,已有项目可以继续使用,新建项目请谨慎选择。 Midway 的一体化方案,是以 Midway Hooks 为主函数式全栈框架,支持四大核心特性:"零" Api & 类型安全 & 全栈套件 & 强大后端。 ## 和标准项目差异[​](#和标准项目差异 "和标准项目差异的直接链接") 一体化方案,基于标准项目,在其之上扩展出了一层前端适配层,在复用所有标准项目能力的同时,又可以和前端进行无缝协作开发,即在项目中,既有前端代码,又有 Node 代码。 ## 特性介绍[​](#特性介绍 "特性介绍的直接链接") ### 零 Api[​](#零-api "零 Api的直接链接") 在 Midway Hooks 全栈应用中开发的后端接口函数,可以直接导入并调用,无需前后端手写 Ajax 胶水层。以下是一个简单的例子: 后端代码: ``` import { Api, Post, } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 前端调用: ``` import say from './api'; const response = await say('Midway'); console.log(response); // Hello Midway! ``` ### 类型安全与运行时安全[​](#类型安全与运行时安全 "类型安全与运行时安全的直接链接") 使用 `@midwayjs/hooks` 提供的 [Validate](/docs/hooks/validate.md) 校验器,可以实现从前端到后端的类型安全 + 运行时安全链路。以下是一个简单的例子: 后端代码: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; export default Api( Post('/hello'), Validate(z.string(), z.number()), async (name: string, age: number) => { return `Hello ${name}, you are ${age} years old.`; } ); ``` 一体化调用: ``` import hello from './api'; try { await hello(null, null); } catch (error) { console.log(error.message); // 'name must be a string' console.log(error.status); // 422 } ``` 整个过程中。 * 前端:基于类型,静态校验输入参数,并获取类型提示 * 后端:校验前端传入参数 * 数据库等业务逻辑:使用正确的数据 通过这种方式,我们可以低成本的实现静态类型安全 + 运行时安全。 ### 全栈套件[​](#全栈套件 "全栈套件的直接链接") 在 Midway Hooks 中,我们提供了 `@midwayjs/hooks-kit` 来快速开发全栈应用。 你可以通过 `hooks dev` 来启动全栈应用,`hooks build` 来打包全栈应用,同时在服务端你也可以使用 `hooks start` 一键启动应用。 解决你在使用全栈应用时的后顾之忧。 ### 强大后端[​](#强大后端 "强大后端的直接链接") Midway Hooks 基于 Midway 开发。 Midway 是一个有着 8 年历史的 Node.js 框架,具有强大的后端功能,包含 Cache / Redis / Mongodb / Task / Config 等 Web 下常用的组件。 而这些你在使用 Midway Hooks 时都可以无缝享受到。 ## 创建应用[​](#创建应用 "创建应用的直接链接") Midway Hooks 目前提供了如下模板: * 全栈应用 * [react](https://github.com/midwayjs/hooks/blob/main/examples/react) * [vue](https://github.com/midwayjs/hooks/blob/main/examples/vue) * [prisma](https://github.com/midwayjs/hooks/blob/main/examples/prisma) * Api Server * [api](https://github.com/midwayjs/hooks/blob/main/examples/api) 基于指定创建应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/ ``` 创建 react 模版的全栈应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/react ./hooks-app ``` 创建 api 模版的应用命令如下: ``` npx degit https://github.com/midwayjs/hooks/examples/api ./hooks-app ``` ## 下一步[​](#下一步 "下一步的直接链接") * 了解如何开发接口并提供给前端调用:[接口开发](/docs/hooks/api.md) * 如何使用和创建可复用的 Hooks:[Hooks](/docs/hooks/builtin-hooks.md) * 如何在运行时校验用户参数:[校验器](/docs/hooks/validate.md) --- # Web 中间件 Midway Hooks 支持通过函数 + `useContext()` 来定义 Web 中间件。 ## 语法[​](#语法 "语法的直接链接") 中间件仅有 `next` 一个参数,`ctx` 需要通过 `useContext` 获得。你也可以在中间件中使用任意的 `Hooks`。 ### 基础示例[​](#基础示例 "基础示例的直接链接") 以记录请求日志为例: ``` import { Context } from '@midwayjs/koa'; import { useContext } from '@midwayjs/hooks'; const logger = async (next: any) => { const ctx = useContext(); console.log( `<-- [${ctx.method}] ${ctx.url}` ); const start = Date.now(); await next(); const cost = Date.now() - start; console.log( `--> [${ctx.method}] ${ctx.url} ${cost}ms` ); }; ``` ## 全局中间件[​](#全局中间件 "全局中间件的直接链接") 全局中间件在 `configuration.ts` 中定义,此处定义的中间件对所有接口生效。 ``` import { hooks, createConfiguration, } from '@midwayjs/hooks'; import logger from './logger'; // Global Middleware export default createConfiguration({ imports: [ hooks({ middleware: [logger], }), ], }); ``` ## 文件级中间件[​](#文件级中间件 "文件级中间件的直接链接") 文件级中间件在 Api 文件中定义,通过导出的 `config.middleware`,该中间件对文件内所有 Api 函数生效。 ``` import { ApiConfig, Api, Get, } from '@midwayjs/hooks'; import logger from './logger'; // File Level Middleware export const config: ApiConfig = { middleware: [logger], }; export default Api(Get(), async () => { return 'Hello World!'; }); ``` ## 单函数中间件[​](#单函数中间件 "单函数中间件的直接链接") 通过 `Middleware(...middlewares: HooksMiddleware[])` 定义的中间件仅对单个函数生效 ``` import { Api, Get, Middleware, } from '@midwayjs/hooks'; import logger from './logger'; export default Api( Get(), Middleware(logger), async () => { return 'Hello World!'; } ); ``` ## 使用 Koa 中间件[​](#使用-koa-中间件 "使用 Koa 中间件的直接链接") 你可以在上述的例子中直接传入 Koa 中间件。 以 [@koa/cors](https://www.npmjs.com/package/@koa/cors) 为例 全局启用: ``` import { hooks, createConfiguration, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; // Global Middleware export default createConfiguration({ imports: [ hooks({ middleware: [logger, cors()], }), ], }); ``` 文件级别启用: ``` import { ApiConfig, Api, Get, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; // File Level Middleware export const config: ApiConfig = { middleware: [logger, cors], }; export default Api(Get(), async () => { return 'Hello World!'; }); ``` 函数级别启用: ``` import { Api, Get, Middleware, } from '@midwayjs/hooks'; import logger from './logger'; import cors from '@koa/cors'; export default Api( Get(), Middleware(logger, cors), async () => { return 'Hello World!'; } ); ``` --- # Prisma ORM 在 Midway Hooks 中,我们推荐使用 [Prisma](https://prisma.io/) 来构建数据库,并实现我们静态类型安全的目标。 [Prsima](https://www.prisma.io/) 是面向 Node.js & TypeScript 设计的 ORM,它提供了一系列友好的功能(Schema 定义、客户端生成、完全的 TypeScript 支持),可以帮助用户快速构建应用。 ## Example[​](#example "Example的直接链接") 我们提供了一个简单的例子 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/prisma/README.md),来演示在 Midway Hooks 如何使用 Prisma。 下面我也会简单介绍,Midway Hooks 配合 Prisma 开发应用会有多么的简单。 ### 数据库 Schema[​](#数据库-schema "数据库 Schema的直接链接") 例子基于 sqlite,数据库 Schema 如下: ``` model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] } model Post { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt title String content String? published Boolean @default(false) viewCount Int @default(0) author User? @relation(fields: [authorId], references: [id]) authorId Int? } ``` 具体的数据库设置 & 初始数据填充工作,参考 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/prisma/README.md) 文档即可。 ### 初始化 Prisma[​](#初始化-prisma "初始化 Prisma的直接链接") 在项目的 src/api 下新建 prisma 文件,使用如下代码即可初始化 Client。 ``` import { PrismaClient } from '@prisma/client'; export const prisma = new PrismaClient(); ``` #### 使用代理镜像[​](#使用代理镜像 "使用代理镜像的直接链接") Prisma 在安装时会根据平台动态下载可执行文件,如果你的网络环境不好,可以通过环境变量来设置镜像。 ``` PRISMA_ENGINES_MIRROR=https://registry.npmmirror.com/-/binary/prisma/ ``` 相关 Issue: [mirror prisma](https://github.com/cnpm/mirrors/issues/248) ### 查询数据[​](#查询数据 "查询数据的直接链接") 以获取所有发布的文章为例,你可以通过生成的 Prisma Client 快速完成操作。 后端代码: ``` import { Api, Get, } from '@midwayjs/hooks'; import { prisma } from './prisma'; export default Api(Get(), async () => { const posts = await prisma.post.findMany({ where: { published: true }, include: { author: true }, }); return posts; }); ``` 一体化调用: ``` import fetchFeeds from '../api/feeds'; fetchFeeds().then((feeds) => { console.log(feeds); }); ``` ### 增加数据[​](#增加数据 "增加数据的直接链接") 以注册登录为例,基于一体化调用 + Prisma 生成的客户端,可以在简单的几行代码中完成所有的工作。 包含: * 前端类型提示 * 后端参数校验 * 数据库操作 ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; import { prisma } from './prisma'; export const signUp = Api( Post(), Validate( z.string(), z.string().email() ), async ( name: string, email: string ) => { const result = await prisma.user.create({ data: { name, email, }, }); return result; } ); ``` 一体化调用: ``` import { signUp } from '../api/feeds'; signUp('John', 'test@test.com').then( (user) => { console.log(user); } ); ``` ### 更多示例[​](#更多示例 "更多示例的直接链接") 关于 Prisma 的更多示例,可以参考 [Prisma 官网文档](https://www.prisma.io/)。 --- # 静态类型安全 + 运行时安全 使用 [Prisma](/docs/hooks/prisma.md) 和 `@midwayjs/hooks` 提供的 [Validate](/docs/hooks/validate.md) 校验器,可以实现从前端到后端再到数据库的类型安全 + 运行时安全链路。 以 [hooks-prisma-starter](https://github.com/midwayjs/hooks/blob/main/examples/fullstack/prisma/README.md) 中的 `POST /api/post` 接口为例,代码如下: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { prisma } from './prisma'; import { z } from 'zod'; const PostSchema = z.object({ title: z.string().min(1), content: z.string().min(1), authorEmail: z.string().email(), }); export const createPost = Api( Post('/api/post'), Validate(PostSchema), async ( post: z.infer ) => { const result = await prisma.post.create({ data: { title: post.title, content: post.content, author: { connect: { email: post.authorEmail, }, }, }, }); return result; } ); ``` 前端调用: ``` import { createPost } from '../api/post'; await createPost({ title: 'Hello Midway', content: 'Hello Prisma', authorEmail: 'test@test.com', }); ``` 此时,前端基于 Zod 的 Schema 获取类型提示,后端则使用 `Validate` 校验器进行类型检查,最终调用 `prisma.post.create` 方法来创建用户。 整个过程中。 * 前端:基于类型,静态校验输入参数,并获取类型提示 * 后端:校验前端传入参数 * 数据库:使用正确的数据 通过这种方式,我们可以低成本的实现静态类型安全 + 运行时安全。 --- # 测试 在 Midway Hooks 中,我们可以快速的对 Http 接口进行测试。 ## 接口测试[​](#接口测试 "接口测试的直接链接") 此处以 Hello World 为例,我们在 `src/hello.ts` 中,导出了一个接口,代码如下。 ``` import { Api, Get } from '@midwayjs/hooks'; export default Api(Get('/hello'), async () => { return 'Hello World!'; }); ``` 在测试中,你可以通过 `@midwayjs/mock` 去启动应用,并调用接口完成测试。 ### 通过 `@midwayjs/hooks` 调用[​](#通过-midwayjshooks-调用 "通过-midwayjshooks-调用的直接链接") `@midwayjs/hooks` 提供了 `getApiTrigger(api: ApiFunction)` 方法,可以用于获取触发器。 以上面的 `hello` 接口为例,`getApiTrigger(hello)` 将返回: ``` { "type": "HTTP", "method": "GET", "path": "/hello" } ``` 在此,我们使用 `@midwayjs/mock` 提供的 `createHttpRequest` 方法来调用接口。`createHttpRequest` 的使用文档可以参考 [supertest](https://github.com/visionmedia/supertest)。 ``` // src/hello.test.ts import { close, createApp, createHttpRequest, } from '@midwayjs/mock'; import { Framework, IMidwayKoaApplication, } from '@midwayjs/koa'; import { getApiTrigger, HttpTriger } from '@midwayjs/hooks'; import hello from './hello'; describe('test koa with api router', () => { let app: IMidwayKoaApplication; beforeAll(async () => { app = await createApp(); }); afterAll(async () => { await close(app); }); test('Hello World', async () => { const trigger = getApiTrigger(hello); const response = await createHttpRequest(app) .get(trigger.path) .expect(200); expect(response.text).toBe('Hello World!'); }); }); ``` ### 手动调用[​](#手动调用 "手动调用的直接链接") 手动调用的情况下,需要填入 `Path` 等参数。 ``` test('Hello World', async () => { const response = await createHttpRequest(app) .get('/hello') .expect(200); expect(response.text).toBe('Hello World!'); }); ``` ### 请求参数 Data[​](#请求参数-data "请求参数 Data的直接链接") 后端代码: ``` import { Api, Post } from '@midwayjs/hooks'; export default Api( Post(), // Http Path: /api/say, async (name: string) => { return `Hello ${name}!`; } ); ``` 测试代码: ``` test('Hello World', async () => { const trigger = getApiTrigger(say); const response = await createHttpRequest(app) .post(trigger.path) .send({ args: ['Midway'] }) .expect(200); expect(response.text).toBe('Hello Midway!'); }); ``` ### 查询参数 Query[​](#查询参数-query "查询参数 Query的直接链接") 后端代码: ``` import { Api, Get, Query, useContext, } from '@midwayjs/hooks'; export default Api( Get('/hello'), Query<{ name: string }>(), async () => { const ctx = useContext(); return `Hello ${ctx.query.name}!`; } ); ``` 测试代码: ``` test('Hello World', async () => { const trigger = getApiTrigger(hello); const response = await createHttpRequest(app) .get(trigger.path) .query({ name: 'Midway' }) .expect(200); expect(response.text).toBe('Hello Midway!'); }); ``` ### 路径参数 Params[​](#路径参数-params "路径参数 Params的直接链接") 后端代码: ``` import { Api, Get, Params, useContext } from '@midwayjs/hooks' export default Api( Get('/article/:id'), Params<{ id: string }>(, async () => { const ctx = useContext() return { article: ctx.params.id } } ) ``` 测试代码: ``` test('Get Article', async () => { const response = await createHttpRequest(app) .get('/article/1') .expect(200); expect(response.body).toEqual({ article: '1' }); }); ``` ### 请求头 Headers[​](#请求头-headers "请求头 Headers的直接链接") 后端代码: ``` import { Api, Get, Headers, useContext, } from '@midwayjs/hooks'; export default Api( Get('/auth'), Headers<{ token: string }>(), async () => { const ctx = useContext(); return { token: ctx.headers.token, }; } ); ``` 测试代码: ``` test('Auth', async () => { const response = await createHttpRequest(app) .get('/auth') .set('token', '123456') .expect(200); expect(response.body).toEqual({ token: '123456' }); }); ``` --- # 文件上传 Midway Hooks 提供了 `@midwayjs/hooks-upload` 并配合 `@midwayjs/upload` 来实现纯函数 + 一体化项目中的文件上传功能。 ## 起步[​](#起步 "起步的直接链接") 安装依赖: ``` npm install @midwayjs/upload @midwayjs/hooks-upload ``` ## 使用[​](#使用 "使用的直接链接") ### 启用 upload 组件[​](#启用-upload-组件 "启用 upload 组件的直接链接") 在后端目录的 `configuration.ts` 中启用 `@midwayjs/upload` 组件,具体支持的配置项可查看 [文件上传](/docs/extensions/upload.md) ``` import { createConfiguration, hooks } from '@midwayjs/hooks'; import * as Koa from '@midwayjs/koa'; + import * as upload from '@midwayjs/upload'; /** * setup midway server */ export default createConfiguration({ imports: [ Koa, hooks(), + upload ], importConfigs: [{ default: { keys: 'session_keys' } }], }); ``` ### 创建接口[​](#创建接口 "创建接口的直接链接") 在后端目录下,新建接口文件。 ``` import { Api } from '@midwayjs/hooks'; import { Upload, useFiles, } from '@midwayjs/hooks-upload'; export default Api( Upload('/api/upload'), async () => { const files = useFiles(); return files; } ); ``` > 一体化调用 ``` import upload from './api/upload'; function Form() { const [file, setFile] = React.useState(null); const handleSubmit = async ( e: React.FormEvent ) => { e.preventDefault(); const files = { images: file }; const response = await upload({ files, }); console.log(response); }; const handleOnChange = ( e: React.ChangeEvent ) => { console.log(e.target.files); setFile(e.target.files); }; return (

Hooks File Upload

); } ``` > 手动调用(通过 FormData 上传) ``` const input = document.getElementById('file'); const formdata = new FormData(); formdata.append('file', input.files[0]); fetch('/api/upload', { method: 'POST', body: formdata, }) .then((res) => res.json()) .then((res) => console.log(res)); ``` ## Api[​](#api "Api的直接链接") ### Upload(path?: string)[​](#uploadpath-string "Upload(path?: string)的直接链接") 声明上传接口,可以指定路径。默认为 `POST` 接口,只支持 `multipart/form-data` 类型的请求。 ### useFiles()[​](#usefiles "useFiles()的直接链接") 在函数中使用 `useFiles()` 可以获取上传的文件。返回值为 Object,key 为上传时的字段名。有多个文件字段名相同时,Value 为 Array。 ``` // frontend await upload({ pdf }); // backend const files = useFiles(); { pdf: { filename: 'test.pdf', // 文件原名 data: '/var/tmp/xxx.pdf', // mode 为 file 时为服务器临时文件地址 fieldname: 'test1', // 表单 field 名 mimeType: 'application/pdf', // mime } } ``` ### useFields()[​](#usefields "useFields()的直接链接") 返回 FormData 中非文件的字段。 ``` // frontend const formdata = new FormData(); formdata.append('name', 'test'); post(formdata); // backend const fields = useFields(); // { name: 'test' } ``` --- # 参数校验 ## 校验[​](#校验 "校验的直接链接") Midway Hooks 使用 [zod@3](https://www.npmjs.com/package/zod) 作为校验器,并提供 `Validate(...schemas: any[])` 校验用户入参,`ValidateHttp(options)` 函数来校验 Http 结构。 使用前请安装 [zod](https://www.npmjs.com/package/zod)。 ``` npm install zod ``` ## Validate[​](#validate "Validate的直接链接") `Validate` 传入的 Schema 顺序与用户入参顺序匹配。 ### 基础示例[​](#基础示例 "基础示例的直接链接") ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; export default Api( Post('/hello'), Validate(z.string(), z.number()), async (name: string, age: number) => { return `Hello ${name}, you are ${age} years old.`; } ); ``` 一体化调用: ``` import hello from './api'; try { await hello(null, null); } catch (error) { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .post('/hello', { args: [null, null], }) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` ### 错误处理[​](#错误处理 "错误处理的直接链接") 通过 Try/Catch 可以捕捉到校验失败的错误。 ``` try { // 调用接口 } catch (error) { console.log(error.data.code); // VALIDATION_FAILED console.log( JSON.parse(error.data.message) ); } ``` `error.data.message` 包含完整的[错误信息](https://zod.js.org/docs/errors/),你需要使用 `JSON.parse` 解析,解析后的示例如下: ``` [ { code: 'invalid_type', expected: 'string', received: 'number', path: [0, 'name'], message: 'Expected string, received number', }, ]; ``` 其中: * `message`: 错误信息 * `path` 参数代表错误路径,如 `0` 代表第一个参数校验出错,`name` 代表是 `name` 字段校验出错。 你可以手动解析错误消息,并展示给用户。 ### ValidateHttp[​](#validatehttp "ValidateHttp的直接链接") ValidateHttp(options) 支持传入 `options` 参数,类型如下。 ``` type ValidateHttpOption = { query?: z.Schema; params?: z.Schema; headers?: z.Schema; data?: z.Schema[]; }; ``` 以校验 `Query` 参数为例。 后端代码: ``` import { Api, Get, Query, useContext, ValidateHttp, } from '@midwayjs/hooks'; import { z } from 'zod'; const QuerySchema = z.object({ searchString: z.string().min(5), }); export const filterPosts = Api( Get('/api/filterPosts'), Query>(), ValidateHttp({ query: QuerySchema }), async () => { const ctx = useContext(); return ctx.query.searchString; } ); ``` 一体化调用: ``` import filterPosts from './api'; try { await filterPosts({ query: { searchString: '' }, }); } catch (error) { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .get( '/api/filterPosts?searchString=1' ) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` ## TypeScript 支持[​](#typescript-支持 "TypeScript 支持的直接链接") 你可以通过 zod 内置的 TypeScript 功能,来实现复杂类型的推导与校验。 示例如下: ``` import { Api, Post, Validate, } from '@midwayjs/hooks'; import { z } from 'zod'; const Project = z.object({ name: z.string(), description: z.string(), owner: z.string(), members: z.array(z.string()), }); export default Api( Post('/project'), Validate(Project), async ( // { name: string, description: string, owner: string, members: string[] } project: z.infer ) => { return project; } ); ``` 一体化调用: ``` import createProject from './api'; try { await createProject({ name: 1, description: 'test project', owner: 'test', members: ['test'], }); } catch (error) { console.log(error.message); console.log(error.status); // 422 } ``` 手动调用: ``` fetcher .post('/project', { args: [ { name: 1, description: 'test project', owner: 'test', members: ['test'], }, ], }) .catch((error) => { console.log( JSON.parse(error.data.message) ); console.log(error.status); // 422 }); ``` --- # 如何安装 Node.js 环境 ## 使用场景[​](#使用场景 "使用场景的直接链接") 一般来说,直接从 [Node.js 官网](https://nodejs.org/)下载对应的安装包,即可完成环境配置。 但在**本地开发**的时候,经常需要快速更新或切换版本。 社区有 [nvm](https://github.com/creationix/nvm)、[n](https://github.com/tj/n) 等方案,我们推荐跨平台的 [nvs](https://github.com/jasongin/nvs)。 * nvs 是跨平台的。 * nvs 是基于 Node 编写的,我们可以参与维护。 > 友情提示:Node 12.x 和 14.x 分别于2022和2023年4月结束生命期(EOL),请尽快升级到 16 或者 18 。 **PS:nvs 我们一般只用于本地开发,线上参见:**[科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) *** ## 如何安装[​](#如何安装 "如何安装的直接链接") ### Linux / macOS 环境[​](#linux--macos-环境 "Linux / macOS 环境的直接链接") 通过 Git Clone 对应的项目即可。 ``` $ export NVS_HOME="$HOME/.nvs" $ git clone https://github.com/jasongin/nvs --depth=1 "$NVS_HOME" $ . "$NVS_HOME/nvs.sh" install ``` ### Windows 环境[​](#windows-环境 "Windows 环境的直接链接") 由于 Windows 环境配置比较复杂,所以还是推荐使用 `msi` 文件完成初始化工作。 访问 [nvs/releases](https://github.com/jasongin/nvs/releases) 下载最新版本的 `nvs.msi`,然后双击安装即可。 *** ## 配置镜像地址[​](#配置镜像地址 "配置镜像地址的直接链接") 在国内由于大家都懂的原因,需要把对应的镜像地址修改下: ``` $ nvs remote node https://npmmirror.com/mirrors/node/ $ nvs remote default node chakracore https://github.com/nodejs/node-chakracore/releases/ chakracore-nightly https://nodejs.org/download/chakracore-nightly/ nightly https://nodejs.org/download/nightly/ node https://nodejs.org/dist/ ``` *** ## 使用指南[​](#使用指南 "使用指南的直接链接") 通过以下命令,即可非常简单的安装 Node.js 最新的 LTS 版本。 ``` # 安装最新的 LTS 版本 $ nvs add lts # 配置为默认版本 $ nvs link lts ``` 安装其他版本: ``` # 安装其他版本尝尝鲜 $ nvs add 12 # 查看已安装的版本 $ nvs ls # 在当前 Shell 切换版本 $ nvs use 12 ``` 更多指令参见 `nvs --help` 。 *** ## 共用 npm 全局模块[​](#共用-npm-全局模块 "共用 npm 全局模块的直接链接") 使用 `nvs` 时,默认的 `prefix` 是当前激活的 Node.js 版本的安装路径。 带来一个问题是:切换版本之后,之前安装全局命令模块需要重新安装,非常不方便。 解决方案是配置统一的全局模块安装路径到 `~/.npm-global`,如下: ``` $ mkdir -p ~/.npm-global $ npm config set prefix ~/.npm-global ``` 还需配置环境变量到 `~/.bashrc` 或 `~/.zshrc` 文件里面: ``` $ echo "export PATH=~/.npm-global/bin:$PATH" >> ~/.zshrc $ source ~/.zshrc ``` *** ## Mac Silicon 芯片使用低版本 Node.js[​](#mac-silicon-芯片使用低版本-nodejs "Mac Silicon 芯片使用低版本 Node.js的直接链接") 如果你使用的是 Apple 芯片,由于 Node.js 16 以下没有 arm64 的芯片支持构建版本,所以没法直接安装。 幸运的是,有一些解决方法可以使 Node.js 14与 Mac Silicon一起使用。Apple提供了Rosetta,这是一款翻译应用程序,允许为Intel芯片 (或上一代Mac) 构建的应用程序在 Apple Silicon下运行。 有两个步骤: * 1、安装 Rosetta * 2、切换到 intel 环境,安装低版本 Node.js **安装 Rosetta** 打开终端,执行 ``` $ /usr/sbin/softwareupdate --install-rosetta --agree-to-license ``` **切换环境,安装低版本 Node.js** * 1、打开终端,执行 `arch` ,确认运行的是 `arm64` * 2、执行 `arch -x86_64 zsh`,开启新的终端 * 3、执行 `arch` ,确认运行的是 `i386` * 4、安装低版本 Node.js,你可以使用上面提到的 nvs 或者 nvm 来安装 ## 相关阅读[​](#相关阅读 "相关阅读的直接链接") * [科普文:Node.js 安全攻防 - 如何伪造和获取用户真实 IP ?](https://zhuanlan.zhihu.com/p/62265144) * [科普文:运维不给升级 Node 版本怎么办?](https://zhuanlan.zhihu.com/p/39226941) * [科普文:为什么不能在服务器上 npm install ?](https://zhuanlan.zhihu.com/p/39209596) * [Using NodeJs 14 with Mac Silicon (M1)](https://devzilla.io/using-nodejs-14-with-mac-silicon-m1) --- # 如何更新 Midway ## 什么时候要更新 Midway[​](#什么时候要更新-midway "什么时候要更新 Midway的直接链接") 一般来说,在下面的情况下,你可能需要更新: * 1、Midway 发了新版本之后,你希望用到新功能的时候 * 2、你安装了一个新的组件且带有 lock 文件的时候 * 3、出现方法找不到的错误的时候 * ... 等等 比如出现下面错误的时候 1、一般是装了组件的新包,但是老的 @midwayjs/core 未包含该方法从而报错。 ![](https://img.alicdn.com/imgextra/i3/O1CN01dDNRZr1MBPewPo7Xg_!!6000000001396-2-tps-1196-317.png) 2、一般原因为 mock 依赖的 @midwayjs/core 版本没这个方法,说明版本不对,可能是错误引用了版本,也可能是版本太低 ![](https://img.alicdn.com/imgextra/i3/O1CN01HVMJKP1xNuFO2Wv73_!!6000000006432-2-tps-1055-135.png) 3、新装组件的时候,我们发现某个包的版本实例不止一个 ![](https://img.alicdn.com/imgextra/i3/O1CN01jZxQu91YBCs0N9S9Y_!!6000000003020-2-tps-1133-43.png) ## 更新注意事项[​](#更新注意事项 "更新注意事项的直接链接") 危险 midway 项目的依赖使用 lerna 发布,**请不要**: * 1、单独升级某个 @midwayjs/\* 的包 * 2、将 package.json 中的版本号移除 ^ 符号 ## 检查包版本异常[​](#检查包版本异常 "检查包版本异常的直接链接") 你可以使用下面的命令在项目根目录执行进行检查。 ``` # 社区用户 $ npx midway-version # 内部用户 $ tnpx @ali/midway-version ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version # 内部用户 $ pnpx @ali/midway-version ``` ## 使用工具更新版本[​](#使用工具更新版本 "使用工具更新版本的直接链接") 你可以使用下面的命令在项目根目录执行进行更新提示。 ``` # 社区用户 $ npx midway-version -u # 内部用户 $ tnpx @ali/midway-version -u ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version -u # 内部用户 $ pnpx @ali/midway-version -u ``` 如果你希望将更新写入到 `package.json` 中,请使用下面的命令。 ``` # 社区用户 $ npx midway-version -u -w # 内部用户 $ tnpx @ali/midway-version -u -w ``` 如果项目为 pnpm 安装的依赖,请使用下面的命令。 ``` # 社区用户 $ pnpx midway-version -u -w # 内部用户 $ pnpx @ali/midway-version -u -w ``` 提示 更新的版本会写入 `package.json` 和 `package-lock.json`,并需要重新安装依赖。 ## 手动更新版本[​](#手动更新版本 "手动更新版本的直接链接") ### 普通项目更新[​](#普通项目更新 "普通项目更新的直接链接") 普通使用 npm/yarn 的项目,升级请按照下面的流程 * 1、删除 package-lock.json 或者 yarn.lock * 2、彻底删除 node\_modules(比如 rm -rf node\_modules) * 3、重新安装依赖( npm install 或者 yarn) **我们不保证使用其他工具、cli 单独升级包的效果。** ### lerna 项目更新[​](#lerna-项目更新 "lerna 项目更新的直接链接") 使用 lerna 开发项目,由于有 hoist 模式的存在,升级请按照下面的流程(以 lerna3 为例) * 1、清理子包的 node\_modules,比如(lerna clean --yes) * 2、删除主包的 node\_modules(比如 rm -rf node\_modules) * 3、删除 package-lock.json 或者 yarn.lock * 4、重新安装依赖( npm install && lerna bootstrap) **我们不保证使用其他工具、cli 单独升级包的效果。** ## 大版本更新[​](#大版本更新 "大版本更新的直接链接") 请手动修改版本号,比如从 `^1.0.0` 修改为 `^2.0.0` 。 ## 查看当前包版本[​](#查看当前包版本 "查看当前包版本的直接链接") Midway 包采用标准的 Semver 版本进行管理和发布,在 `package.json` 指定的版本一般为 `^` 开头,表示在大版本范围内都兼容。 比如,`package.json` 中 `@midwayjs/core` 为 `^2.3.0` ,那么按照 npm 安装规则,会安装 `2.x` 这个版本下最新的 latest 版本。 所以实际安装的版本高于 `package.json` 中指定的版本都是正常的。 你可以使用 `npm ls 包名` 来查看具体的版本,比如 `npm ls @midwayjs/core` 来查看 `@midwayjs/core` 的版本。 ## 版本匹配查询[​](#版本匹配查询 "版本匹配查询的直接链接") 由于 lerna 发包有一定的依赖性,比如修改到的包才会更新,就会出现 **midway 下的包版本不一定完全一致的情况。** 比如,`@midwayjs/web` 的版本高于 `@midwayjs/core`,这都是很正常的。 midway 每次发布会提交一个 [@midwayjs/version ](https://www.npmjs.com/package/@midwayjs/version)的包,其中包含了我们每个版本,以及该版本的包所匹配的全部包版本,请 [访问这里](https://github.com/midwayjs/midway/tree/2.x/packages/version/versions) 查看。 目录中的文件名按照 `@midwayjs/decorator版本 - @midwayjs/core版本.json` 规则创建,每个版本对应一个 JSON 文件。 文件内容以包名作为 key,以可兼容匹配的版本名作为值。 比如,当前文件 decorator(v2.10.18)和 core(v2.10.18) 所能兼容的 egg-layer 包版本为 v2.10.18 和 v2.10.19。 如果 decorator 和 core 组合的文件名未找到,或者文件里的版本不匹配,都说明 **版本可能产生了问题**。 内容示例如下: ``` { "@midwayjs/egg-layer": [ "2.10.18", "2.10.19" ], "@midwayjs/express-layer": "2.10.18", "@midwayjs/faas-typings": "2.10.7", "@midwayjs/koa-layer": "2.10.18", "@midwayjs/runtime-engine": "2.10.14", "@midwayjs/runtime-mock": "2.10.14", "@midwayjs/serverless-app": "2.10.18", "@midwayjs/serverless-aws-starter": "2.10.14", "@midwayjs/serverless-fc-starter": "2.10.18", "@midwayjs/serverless-fc-trigger": "2.10.18", "@midwayjs/serverless-http-parser": "2.10.7", "@midwayjs/serverless-scf-starter": "2.10.14", "@midwayjs/serverless-scf-trigger": "2.10.18", "@midwayjs/static-layer": "2.10.18", "@midwayjs/bootstrap": "2.10.18", "@midwayjs/cache": "2.10.18", "@midwayjs/consul": "2.10.18", "@midwayjs/core": "2.10.18", "@midwayjs/decorator": "2.10.18", "@midwayjs/faas": "2.10.18", "@midwayjs/grpc": "2.10.18", "@midwayjs/logger": "2.10.18", "midway-schedule": "2.10.18", "midway": [ "2.10.18", "2.10.19" ], "@midwayjs/mock": "2.10.18", "@midwayjs/prometheus": "2.10.18", "@midwayjs/rabbitmq": "2.10.18", "@midwayjs/socketio": "2.10.18", "@midwayjs/task": [ "2.10.18", "2.10.19" ], "@midwayjs/typegoose": "2.10.18", "@midwayjs/version": [ "2.10.18", "2.10.19" ], "@midwayjs/express": "2.10.18", "@midwayjs/koa": "2.10.18", "@midwayjs/web": [ "2.10.18", "2.10.19" ] } ``` --- # 介绍 Midway 基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。 Midway 基于 TypeScript 开发,结合了`面向对象(OOP + Class + IoC)`与`函数式(FP + Function + Hooks)`两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验。 ## 我们的优势[​](#我们的优势 "我们的优势的直接链接") 1. Midway 框架是在内部已经使用 5 年以上的 Node.js 框架,有着长期投入和持续维护的团队做后盾 2. 已经在每年的大促场景经过考验,稳定性无须担心 3. 丰富的组件和扩展能力,例如数据库,缓存,定时任务,进程模型,部署以及 Web,Socket 甚至 Serverless 等新场景的支持 4. 一体化调用方案可以方便快捷和前端页面协同开发 5. 良好的 TypeScript 定义支持 6. 国产化文档和沟通容易简单 ## 多编程范式[​](#多编程范式 "多编程范式的直接链接") Midway 支持面向对象与函数式两种编程范式,你可以根据实际研发的需要,选择不同的编程范式来开发应用。 ### 面向对象(OOP + Class + IoC)[​](#面向对象oop--class--ioc "面向对象(OOP + Class + IoC)的直接链接") Midway 支持面向对象的编程范式,为应用提供更优雅的架构。 下面是基于面向对象,开发路由的示例。 ``` // src/controller/home.ts import { Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context @Get('/') async home() { return { message: 'Hello Midwayjs!', query: this.ctx.ip } } } ``` ### 函数式(FP + Function + Hooks)[​](#函数式fp--function--hooks "函数式(FP + Function + Hooks)的直接链接") Midway 也支持函数式的编程范式。当前推荐的函数式写法,是通过 `defineApi` 在 `src/server/api` 中声明接口契约,并在函数体里使用 `useContext`、`useInject` 等能力。 下面是基于函数式,开发路由接口的示例。 ``` // src/server/api/home.api.ts import { defineApi, useContext } from '@midwayjs/core/functional'; export const homeApi = defineApi('/', api => ({ getHome: api.get('/', async () => { const ctx = useContext(); return { message: 'Hello Midwayjs!', query: ctx.ip, }; }), })); ``` ## 环境准备工作[​](#环境准备工作 "环境准备工作的直接链接") Midway 运行请预先安装 Node.js 环境和 npm,在国内可以修改 npm 源,使用 pnpm 等。 * 操作系统:支持 macOS,Linux,Windows * 运行环境:建议选择 [LTS 版本](http://nodejs.org/),最低要求 **20.0.0**。 在经过不断迭代之后,Midway 的版本要求如下: | Midway 版本 | 开发环境 Node.js 版本要求 | 部署环境 Node.js 版本要求 | | -------------- | ------------------------- | ------------------------- | | >=v4.0.0 | >= v20,推荐 LTS 版本 | >= v20.0.0 | | >=v3.9.0 | >= v14,推荐 LTS 版本 | >= v12.11.0 | | 3.0.0 \~ 3.9.0 | >= v12,推荐 LTS 版本 | >= v12.0.0 | | 2.x | >= v12,推荐 LTS 版本 | >= v10.0.0 | 如果需要帮助,请参考 [如何安装 Node.js 环境](/docs/how_to_install_nodejs.md)。 ## 正确的提问[​](#正确的提问 "正确的提问的直接链接") * ✅ 在 [github issue](https://github.com/midwayjs/midway/issues) 提问,可追踪,可沉淀,可 Star * 1、描述你的问题,提供尽可能详细的复现方法,框架版本,场景(Serverless 还是应用) * 2、尽可能提供报错截图,堆栈信息,最小复现的 repo ## 答疑分享群[​](#答疑分享群 "答疑分享群的直接链接") 群里会有热心的朋友,也会有新版本发布推送。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01LyI8r91S91RsKsD29_!!6000000002203-0-tps-3916-2480.jpg) ## 官方宣传渠道[​](#官方宣传渠道 "官方宣传渠道的直接链接") * [哔哩哔哩](https://space.bilibili.com/1746017680),会提供更新信息和教程 --- # MongoDB 提示 本文档从 v3.4.0 版本起废弃。 在这一章节中,我们选择 [Typegoose](https://github.com/typegoose/typegoose) 作为基础的 MongoDB ORM 库。就如同他描述的那样 " Define Mongoose models using TypeScript classes",和 TypeScript 结合的很不错。 简单的来说,Typegoose 使用 TypeScript 编写 Mongoose 模型的 “包装器”,它的大部分能力还是由 [mongoose](https://www.npmjs.com/package/mongoose) 库来提供的。 也可以直接选择 [mongoose](https://www.npmjs.com/package/mongoose) 库来使用,我们会分别描述。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## Mongoose 版本依赖[​](#mongoose-版本依赖 "Mongoose 版本依赖的直接链接") mongoose 和你服务器使用的 MongoDB Server 的版本也有着一定的关系,如下,请务必注意。 * MongoDB Server 2.4.x: mongoose ^3.8 or 4.x * MongoDB Server 2.6.x: mongoose ^3.8.8 or 4.x * MongoDB Server 3.0.x: mongoose ^3.8.22, 4.x, or 5.x * MongoDB Server 3.2.x: mongoose ^4.3.0 or 5.x * MongoDB Server 3.4.x: mongoose ^4.7.3 or 5.x * MongoDB Server 3.6.x: mongoose 5.x * MongoDB Server 4.0.x: mongoose ^5.2.0 * MongoDB Server 4.2.x: mongoose ^5.7.0 * MongoDB Server 4.4.x: mongoose ^5.10.0 * MongoDB Server 5.x: mongoose ^6.0.0 **mongoose 相关的依赖比较复杂,且对应不同的版本,现阶段,我们使用的主要是 mongoose v5 和 v6。** 信息 从 mongoose\@v5.11.0 开始,mongoose 官方支持了定义,所以不再需要安装 @types/mongoose 依赖包。 安装包依赖版本如下: **支持 MongoDB Server 5.x** ``` "dependencies": { "mongoose": "^6.0.7", "@typegoose/typegoose": "^9.0.0", // 使用 typegoose 需要安装此依赖 }, ``` **支持 MongoDB Server 4.4.x** 以下版本不需要安装额外定义包。 ``` "dependencies": { "mongoose": "^5.13.3", "@typegoose/typegoose": "^8.0.0", // 使用 typegoose 需要安装此依赖 }, ``` 以下版本需要安装额外定义包(不推荐)。 ``` "dependencies": { "mongodb": "3.6.3", // mongoose 内部写死了该版本 "mongoose": "~5.10.18", "@typegoose/typegoose": "^7.0.0", // 使用 typegoose 需要安装此依赖 }, "devDependencies": { "@types/mongodb": "3.6.3", // 只能使用此版本 "@types/mongoose": "~5.10.3", } ``` 其余的 MongoDB 安装模块类似,未测。 ## 使用 Typegoose[​](#使用-typegoose "使用 Typegoose的直接链接") ### 1、安装组件[​](#1安装组件 "1、安装组件的直接链接") 安装 Typegoose 组件,提供访问 MongoDB 的能力。 **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/typegoose@4 --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/typegoose": "^4.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as typegoose from '@midwayjs/typegoose'; @Configuration({ imports: [ typegoose // 加载 typegoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` 信息 在该组件中,midway 只是做了简单的配置规则化,并将其注入到初始化流程中。 ### 2、配置连接信息[​](#2配置连接信息 "2、配置连接信息的直接链接") 在 `src/config/config.default.ts` 中加入连接的配置。 ``` export default { // ... mongoose: { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } }, } ``` ### 3、简单的目录结构[​](#3简单的目录结构 "3、简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── user.ts // 实体文件 │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ### 3、创建实体文件[​](#3创建实体文件 "3、创建实体文件的直接链接") ``` import { prop } from '@typegoose/typegoose'; import { EntityModel } from '@midwayjs/typegoose'; @EntityModel() export class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 等价于使用 mongoose 的下列代码 ``` const userSchema = new mongoose.Schema({ name: String, jobs: [{ type: String }] }); const User = mongoose.model('User', userSchema); ``` 信息 所以说,typegoose 只是简化了 model 的创建过程。 ### 4、引用实体,调用数据库[​](#4引用实体调用数据库 "4、引用实体,调用数据库的直接链接") 示例代码如下: ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typegoose'; import { ReturnModelType } from '@typegoose/typegoose'; import { User } from '../entity/user'; @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; async getTest(){ // create data const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties // find data const user = await this.userModel.findById(id).exec(); console.log(user) } } ``` ### 5、多库的情况[​](#5多库的情况 "5、多库的情况的直接链接") 首先配置多个连接。 在 `src/config/config.default.ts` 中加入连接的配置,`default` 代表了默认的连接。 ``` export default { // ... mongoose: { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` 定义实例时使用固定的连接,比如: ``` @EntityModel() // 默认使用了 default 连接 class User { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } @EntityModel({ connectionName: 'db1' // 这里使用了 db1连接 }) class User2 { @prop() public name?: string; @prop({ type: () => [String] }) public jobs?: string[]; } ``` 在使用时,注入特定的连接 ``` @Provide() export class TestService { @InjectEntityModel(User) userModel: ReturnModelType; @InjectEntityModel(User2) user2Model: ReturnModelType; async getTest(){ const { _id: id } = await this.userModel.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User); // an "as" assertion, to have types for all properties const user = await this.userModel.findById(id).exec(); console.log(user) const { _id: id2 } = await this.user2Model.create({ name: 'JohnDoe', jobs: ['Cleaner'] } as User2); // an "as" assertion, to have types for all properties const user2 = await this.user2Model.findById(id2).exec(); console.log(user2) } } ``` ## 直接使用 mongoose[​](#直接使用-mongoose "直接使用 mongoose的直接链接") mongoose 组件是 typegoose 的基础组件,有时候我们可以直接使用它。 ### 1、安装组件[​](#1安装组件-1 "1、安装组件的直接链接") **请务必注意,请查看第一小节提前编写/安装 mongoose 等相关依赖包。** ``` $ npm i @midwayjs/mongoose --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { // 组件 "@midwayjs/mongoose": "^4.0.0", // 上一节中的 mongoose 依赖 }, "devDependencies": { // 上一节中的 mongoose 依赖 // ... } } ``` ### 2、开启组件[​](#2开启组件 "2、开启组件的直接链接") 安装后需要手动在 `src/configuration.ts` 配置,代码如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as mongoose from '@midwayjs/mongoose'; @Configuration({ imports: [ mongoose // 加载 mongoose 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration { } ``` ### 2、配置[​](#2配置 "2、配置的直接链接") 和 typegoose 相同,或者说 typegoose 使用的就是 mongoose 的配置。 单库: ``` export default { // ... mongoose: { client: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '**********' } } }, } ``` 多库: ``` export default { // ... mongoose: { clients: { default: { uri: 'mongodb://localhost:27017/test', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } }, db1: { uri: 'mongodb://localhost:27017/test1', options: { useNewUrlParser: true, useUnifiedTopology: true, user: '***********', pass: '***********' } } } }, } ``` ### 3、使用[​](#3使用 "3、使用的直接链接") 在只有一个默认连接或者直接使用 default 连接时,我们可以直接使用封装好的 `MongooseConnectionService` 对象来创建 model。 ``` import { Provide, Inject } from '@midwayjs/core'; import { MongooseConnectionService } from '@midwayjs/mongoose'; import { Schema, Document } from 'mongoose'; interface User extends Document { name: string; email: string; avatar: string; } @Provide() export class TestService { @Inject() conn: MongooseConnectionService; async invoke(){ const schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, avatar: String }); const UserModel = this.conn.model('User', schema); const doc = new UserModel({ name: 'Bill', email: 'bill@initech.com', avatar: 'https://i.imgur.com/dM7Thhn.png' }); await doc.save(); } } ``` 如果配置了多个其他连接,请从工厂方法中获取连接后再使用。 ``` import { MongooseConnectionServiceFactory } from '@midwayjs/mongoose'; import { Schema } from 'mongoose'; @Provide() export class TestService { @Inject() connFactory: MongooseConnectionServiceFactory; async invoke(){ // get db1 connection const conn = this.connFactory.get('db1'); // get default connection const defaultConn = this.connFactory.get('default'); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、E002: You are using a NodeJS Version below 12.22.0[​](#1e002-you-are-using-a-nodejs-version-below-12220 "1、E002: You are using a NodeJS Version below 12.22.0的直接链接") 在新版本 @typegoose/typegoose (v8, v9) 中增加了 Node 版本的校验,如果你的 Node.js 版本低于 v12.22.0,就会出现这个提示。 普通情况下,请升级 Node.js 到这个版本以上即可解决。 在特殊场景下,比如 Serverless 无法修改 Node.js 版本且版本低于 v12.22 的情况下,由于 v12 版本子版本其实都可以,可以通过临时修改 process.version 绕过。 ``` // src/configuration.ts Object.defineProperty(process, 'version', { value: 'v12.22.0', writable: true, }); // other code export class MainConfiguration {} ``` --- # TypeORM 提示 本文档从 v3.4.0 版本起废弃。 [TypeORM](https://github.com/typeorm/typeorm) 是 `node.js` 现有社区最成熟的对象关系映射器(`ORM` )。Midway 和 TypeORM 搭配,使开发更简单。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## 安装组件[​](#��安装组件 "安装组件的直接链接") 安装 orm 组件,提供数据库 ORM 能力。 ``` $ npm i @midwayjs/orm@4 typeorm --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/orm": "^4.0.0", "typeorm": "~0.3.0", // ... }, "devDependencies": { // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `src/configuration.ts` 引入 orm 组件,示例如下。 ``` // configuration.ts import { Configuration } from '@midwayjs/core'; import * as orm from '@midwayjs/orm'; import { join } from 'path'; @Configuration({ imports: [ // ... orm // 加载 orm 组件 ], importConfigs: [ join(__dirname, './config') ] }) export class ContainerConfiguratin { } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` 信息 To make the\*\* Oracle driver work\*\*, you need to follow the installation instructions from [their](https://github.com/oracle/node-oracledb) site. ## 简单的目录结构[​](#简单的目录结构 "简单的目录结构的直接链接") 我们以一个简单的项目举例,其他结构请自行参考。 ``` MyProject ├── src // TS 根目录 │ ├── config │ │ └── config.default.ts // 应用配置文件 │ ├── entity // 实体(数据库 Model) 目录 │ │ └── photo.ts // 实体文件 │ │ └── photoMetadata.ts │ ├── configuration.ts // Midway 配置文件 │ └── service // 其他的服务目录 ├── .gitignore ├── package.json ├── README.md └── tsconfig.json ``` 在这里,我们的数据库实体主要放在 `entity` 目录(非强制),这只是一个简单的约定。 ## 入门[​](#入门 "入门的直接链接") 下面,我们将以 mysql 举例。 ### 1、创建 Model[​](#1创建-model "1、创建 Model的直接链接") 我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。 在示例中,需要一个实体,我们这里拿 `photo` 举例。新建 entity 目录,在其中添加实体文件 `photo.ts` ,一个简单的实体如下。 ``` // entity/photo.ts export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。 ### 2、添加实体模型装饰器[​](#2添加实体模型装饰器 "2、添加实体模型装饰器的直接链接") 我们使用 `EntityModel` 来定义一个实体模型类。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 警告 注意,这里的 EntityModel 是 midway 做了封装的特殊装饰器,为了和 midway 更好的结合使用。请不要直接使用 typeorm 中的 Entity。 如果表名和当前的实体名不同,可以在参数中指定。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo_table_name') export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` 这些实体列也可以使用 [typeorm\_generator](/docs/tool/typeorm_generator.md) 工具生成。 ### 3、添加数据库列[​](#3添加数据库列 "3、添加数据库列的直接链接") 通过 typeorm 提供的 `@Column` 装饰器来修饰属性,每一个属性对应一个列。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column } from 'typeorm'; @EntityModel() export class Photo { @Column() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` 现在 `id` , `name` , `description` ,`filename` , `views` , `isPublished` 列将添加到 `photo` 表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 `@Column`装饰器中显式指定列类型来使用数据库支持的任何列类型。 我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。 数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 [官方文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/entities.md#%E5%88%97%E9%80%89%E9%A1%B9)。 ### 4、创建主键列[​](#4创建主键列 "4、创建主键列的直接链接") 每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 `@PrimaryColumn` 装饰器。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 5、创建自增主键列[​](#5创建自增主键列 "5、创建自增主键列的直接链接") 现在,如果要设置自增的 id 列,需要将 `@PrimaryColumn` 装饰器更改为 `@PrimaryGeneratedColumn` 装饰器: ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean; } ``` ### 6、列数据类型[​](#6列数据类型 "6、列数据类型的直接链接") 接下来,让我们调整数据类型。默认情况下,字符串映射到类似 `varchar(255)` 的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn } from 'typeorm'; @EntityModel() export class Photo { @PrimaryGeneratedColumn() id: number; @Column({ length: 100 }) name: string; @Column('text') description: string; @Column() filename: string; @Column("double") views: number; @Column() isPublished: boolean; } ``` 示例,不同列名 ``` @Column({ length: 100, name: 'custom_name' }) name: string; ``` 此外还有有几种特殊的列类型可以使用: * `@CreateDateColumn` 是一个特殊列,自动为实体插入日期。 * `@UpdateDateColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。 * `@VersionColumn` 是一个特殊列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。 * `@DeleteDateColumn` 是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。 列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见[此处](https://github.com/typeorm/typeorm/blob/master/docs/entities.md#column-types)。 提示 `CreateDateColumn` 和 `UpdateDateColumn` 是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。 ### 7、配置连接信息[​](#7配置连接信息 "7、配置连接信息的直接链接") 请参考 [配置](/docs/env_config.md) 章节,增加配置文件。 然后在 `config.default.ts` 中配置数据库连接信息。 ``` // src/config/config.default.ts export default { // ... orm: { /** * 单数据库实例 */ type: 'mysql', host: '', port: 3306, username: '', password: '', database: undefined, synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true logging: false, }, } ``` 默认存储的是 utc 时间(推荐)。 也可以配置时区(不建议) ``` // src/config/config.default.ts export default { // ... orm: { // ... timezone: '+08:00', }, } ``` 这个 `type` 字段你可以使用其他的数据库类型,包括`mysql`, `mariadb`, `postgres`, `cockroachdb`, `sqlite`, `mssql`, `oracle`, `cordova`, `nativescript`, `react-native`, `expo`, or `mongodb` 比如 sqlite,则只需要以下信息。 ``` // src/config/config.default.ts export default { // ... orm: { type: 'sqlite', database: path.join(__dirname, '../../test.sqlite'), synchronize: true, logging: true, }, } ``` 信息 注意:synchronize 字段用于同步表结构。使用 `synchronize: true` 进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。 ### 8、使用 Model 插入数据库数据[​](#8使用-model-插入数据库数据 "8、使用 Model 插入数据库数据的直接链接") 在常见的 Midway 文件中,使用 `@InjectEntityModel` 装饰器注入我们配置好的 Model。我们所需要做的只是: * 1、创建实体对象 * 2、执行 `save()` ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // save async savePhoto() { // create a entity object let photo = new Photo(); photo.name = 'Me and Bears'; photo.description = 'I am near polar bears'; photo.filename = 'photo-with-bears.jpg'; photo.views = 1; photo.isPublished = true; // save entity const photoResult = await this.photoModel.save(photo); // save success console.log('photo id = ', photoResult.id); } } ``` ### 9、查询数据[​](#9查询数据 "9、查询数据的直接链接") 更多的查询参数,请查询 [find文档](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/find-options.md)。 自 typeorm\@0.3.0 起,查询 API 有所变化。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhotos() { // find All let allPhotos = await this.photoModel.find(); // v0.2.x let allPhotos = await this.photoModel.find({}); // v0.3.x console.log("All photos from the db: ", allPhotos); // find first let firstPhoto = await this.photoModel.findOne(1); let firstPhoto = await this.photoModel.findOne({ // v0.3.x where: { id: 1 } }); console.log("First photo from the db: ", firstPhoto); // find one by name // v0.2.x let meAndBearsPhoto = await this.photoModel.findOne({ name: "Me and Bears" }); // v0.3.x let meAndBearsPhoto = await this.photoModel.findOne({ where: { name: "Me and Bears" } }); console.log("Me and Bears photo from the db: ", meAndBearsPhoto); // find by views // v0.2.x let allViewedPhotos = await this.photoModel.find({ views: 1 }); // v0.3.x let allViewedPhotos = await this.photoModel.find({ where: { views: 1 } }); console.log("All viewed photos: ", allViewedPhotos); // v0.2.x let allPublishedPhotos = await this.photoModel.find({ isPublished: true }); // v0.3.x let allPublishedPhotos = await this.photoModel.find({ where: { isPublished: true } }); console.log("All published photos: ", allPublishedPhotos); // find and get count // v0.2.x let [allPhotos, photosCount] = await this.photoModel.findAndCount(); // v0.3.x let [allPhotos, photosCount] = await this.photoModel.findAndCount({}); console.log("All photos: ", allPhotos); console.log("Photos count: ", photosCount); } } ``` ### 10、更新数据库[​](#10更新数据库 "10、更新数据库的直接链接") 现在,让我们从数据库中加载一个 Photo,对其进行更新并保存。 ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { let photoToUpdate = await this.photoModel.findOne(1); photoToUpdate.name = "Me, my friends and polar bears"; await this.photoModel.save(photoToUpdate); } } ``` ### 11、删除数据[​](#11删除数据 "11、删除数据的直接链接") ``` import { Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from '../entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { /*...*/ let photoToRemove = await this.photoModel.findOne(1); // typeorm@0.2.x await this.photoModel.remove(photoToRemove); } } ``` 现在,ID = 1的 Photo 将从数据库中删除。 此外还有软删除的方法。 ``` await this.photoModel.softDelete(1); ``` ### 12、创建一对一关联[​](#12创建一对一关联 "12、创建一对一关联的直接链接") 让我们与另一个类创建一对一的关系。让我们在 `entity/photoMetadata.ts` 中创建一个新类。这个类包含 photo 的其他元信息。 ``` import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { EntityModel } from '@midwayjs/orm'; import { Photo } from "./photo"; @EntityModel() export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column("int") height: number; @Column("int") width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string; @OneToOne(type => Photo) @JoinColumn() photo: Photo; } ``` 在这里,我们使用一个名为 `@OneToOne` 的新装饰器。它允许我们在两个实体之间创建一对一的关系。`type => Photo`是一个函数,它返回我们要与其建立关系的实体的类。 由于语言的特殊性,我们被迫使用一个返回类的函数,而不是直接使用该类。我们也可以将其写为 `() => Photo` ,但是我们使用 `type => Photo`作为惯例来提高代码的可读性。类型变量本身不包含任何内容。 我们还添加了一个 `@JoinColumn`装饰器,它指示关系的这一侧将拥有该关系。关系可以是单向或双向的。关系只有一方可以拥有。关系的所有者端需要使用@JoinColumn装饰器。 如果您运行该应用程序,则会看到一个新生成的表,该表将包含一列,其中包含用于 Photo 关系的外键。 ``` +-------------+--------------+----------------------------+ | photo_metadata | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | height | int(11) | | | width | int(11) | | | comment | varchar(255) | | | compressed | boolean | | | orientation | varchar(255) | | | photoId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 接下去我们要在代码中关联他们。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(PhotoMetadata) photoMetadataModel: Repository; async updatePhoto() { // create a photo let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create a photo metadata let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; metadata.photo = photo; // this way we connect them // first we should save a photo await this.photoModel.save(photo); // photo is saved. Now we need to save a photo metadata await this.photoMetadataModel.save(metadata); // done console.log("Metadata is saved, and relation between metadata and photo is created in the database too"); } } ``` ### 13、反向关系映射[​](#13反向关系映射 "13、反向关系映射的直接链接") 关系映射可以是单向或双向的。当在 PhotoMetadata 和 Photo之间的关系是单向的。关系的所有者是PhotoMetadata,而 Photo对 PhotoMetadata 是一无所知的。这使得从 Photo 端访问 PhotoMetadata 变得很复杂。若要解决此问题,我们添加一个反向的关系映射,使 PhotoMetadata 和 Photo之间变成双向关联。让我们修改我们的实体。 ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm'; import { Photo } from './photo'; @EntityModel() export class PhotoMetadata { /* ... other columns */ @OneToOne(type => Photo, photo => photo.metadata) @JoinColumn() photo: Photo; } ``` ``` import { EntityModel } from '@midwayjs/orm'; import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from 'typeorm'; import { PhotoMetadata } from './photoMetadata'; @EntityModel() export class Photo { /* ... other columns */ @OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo) metadata: PhotoMetadata; } ``` `photo => photo.metadata` 是一个返回反向映射关系的函数。在这里,我们显式声明 Photo 类的 metadata 属性用于关联 PhotoMetadata。除了传递返回 photo 属性的函数外,您还可以直接将字符串传递给 `@OneToOne` 装饰器,例如 `“metadata”` 。但是我们使用了这种函数回调的方法来让我们的代码写法更简单。 请注意,只会在关系映射的一侧使用 `@JoinColumn` 装饰器。无论您放置此装饰器的哪一侧,都是关系的所有者。关系的拥有方在数据库中包含带有外键的列。 ### 14、加载对象及其依赖关系[​](#14加载对象及其依赖关系 "14、加载对象及其依赖关系的直接链接") 现在,让我们尝试在单个查询中一起加载出 Photo 和 PhotoMetadata。有两种方法可以执行此操作,使用 `find *` 方法或使用 `QueryBuilder` 功能。让我们首先使用 `find *` 方法。 `find *` 方法允许您使用 `FindOneOptions` / `FindManyOptions` 接口指定对象。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel.find({ relations: [ 'metadata' ] }); // typeorm@0.2.x } } ``` 在这里,photos 的值是一个数组,包含了整个数据库的查询结果,并且每个 photo 对象都包含其关联的 metadata 属性。在[此文档](https://github.com/typeorm/typeorm/blob/master/docs/find-options.md)中了解有关 `Find Options` 的更多信息。 使用 `Find Options` 很简单,但如果需要更复杂的查询,则应改用 `QueryBuilder` 。 `QueryBuilder` 允许以优雅的方式使用更复杂的查询。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; // find async findPhoto() { /*...*/ let photos = await this.photoModel .createQueryBuilder('photo') .innerJoinAndSelect('photo.metadata', 'metadata') .getMany(); } } ``` `QueryBuilder`允许创建和执行几乎任何复杂的 SQL 查询。使用 `QueryBuilder` 时,请像创建 SQL 查询一样思考。在此示例中,“photo” 和 “metadata” 是应用于所选 photos 的别名。您可以使用别名来访问所选数据的列和属性。 ### 15、使用级联操作自动保存关联对象[​](#15使用级联操作自动保存关联对象 "15、使用级联操作自动保存关联对象的直接链接") 在我们希望在每次保存另一个对象时都自动保存关联的对象,这个时候可以在关系中设置级联。让我们稍微更改照片的 `@OneToOne` 装饰器。 ``` export class Photo { /// ... other columns @OneToOne(type => PhotoMetadata, metadata => metadata.photo, { cascade: true, }) metadata: PhotoMetadata; } ``` 使用 `cascade` 允许我们现在不再单独保存 Photo 和 PhotoMetadata,由于级联选项,元数据对象将被自动保存。 ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; async updatePhoto() { // create photo object let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.isPublished = true; // create photo metadata object let metadata = new PhotoMetadata(); metadata.height = 640; metadata.width = 480; metadata.compressed = true; metadata.comment = "cybershoot"; metadata.orientation = "portrait"; photo.metadata = metadata; // this way we connect them // save a photo also save the metadata await this.photoModel.save(photo); // done console.log("Photo is saved, photo metadata is saved too"); } } ``` 注意,我们现在设置 Photo 的元数据,而不需要像之前那样设置元数据的 Photo 属性。这仅当您从 Photo 这边将 Photo 连接到 PhotoMetadata 时,级联功能才有效。如果在 PhotoMetadata 侧设置,则不会自动保存。 ### 16、创建多对一/一对多关联[​](#16创建多对一一对多关联 "16、创建多对一/一对多关联的直接链接") 让我们创建一个多对一/一对多关系。假设一张照片有一个作者,每个作者可以有很多照片。首先,让我们创建一个 Author 类: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm"; import { Photo } from './entity/photo'; @EntityModel() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below photos: Photo[]; } ``` `Author` 包含了一个反向关系。 `OneToMany` 和 `ManyToOne` 需要成对出现。 现在,将关系的所有者添加到 Photo 实体中: ``` import { EntityModel } from '@midwayjs/orm'; import { Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm"; import { PhotoMetadata } from "./photoMetadata"; import { Author } from "./author"; @Entity() export class Photo { /* ... other columns */ @ManyToOne(type => Author, author => author.photos) author: Author; } ``` 在多对一/一对多关系中,所有者方始终是多对一。这意味着使用 `@ManyToOne` 的类将存储相关对象的 ID。 运行应用程序后,ORM 将创建 `author` 表: ``` +-------------+--------------+----------------------------+ | author | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | +-------------+--------------+----------------------------+ ``` 它还将修改 `photo` 表,添加新的 `author` 列并为其创建外键: ``` +-------------+--------------+----------------------------+ | photo | +-------------+--------------+----------------------------+ | id | int(11) | PRIMARY KEY AUTO_INCREMENT | | name | varchar(255) | | | description | varchar(255) | | | filename | varchar(255) | | | isPublished | boolean | | | authorId | int(11) | FOREIGN KEY | +-------------+--------------+----------------------------+ ``` ### 17、创建多对多关联[​](#17创建多对多关联 "17、创建多对多关联的直接链接") 让我们创建一个多对一/多对多关系。假设一张照片可以在许多相册中,并且每个相册可以包含许多照片。让我们创建一个 `Album` 类。 ``` import { EntityModel } from '@midwayjs/orm'; import { PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm"; @EntityModel() export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany(type => Photo, photo => photo.albums) @JoinTable() photos: Photo[]; } ``` `@JoinTable` 用来指明这是关系的所有者。 现在,将反向关联添加到 `Photo` 。 ``` export class Photo { /// ... other columns @ManyToMany(type => Album, album => album.photos) albums: Album[]; } ``` 运行应用程序后,ORM将创建一个 album\_photos\_photo\_albums 联结表: ``` +-------------+--------------+----------------------------+ | album_photos_photo_albums | +-------------+--------------+----------------------------+ | album_id | int(11) | PRIMARY KEY FOREIGN KEY | | photo_id | int(11) | PRIMARY KEY FOREIGN KEY | +-------------+--------------+----------------------------+ ``` 现在,让我们将相册和照片插入数据库: ``` import { Provide, Inject, Func } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; import { PhotoMetadata } from './entity/photoMetadata'; import { Repository } from 'typeorm'; @Provide() export class PhotoService { @InjectEntityModel(Photo) photoModel: Repository; @InjectEntityModel(Album) albumModel: Repository async updatePhoto() { // create a few albums let album1 = new Album(); album1.name = "Bears"; await this.albumModel.save(album1); let album2 = new Album(); album2.name = "Me"; await this.albumModel.save(album2); // create a few photos let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.albums = [album1, album2]; await this.photoModel.save(photo); // now our photo is saved and albums are attached to it // now lets load them: const loadedPhoto = await this.photoModel.findOne(1, { relations: ["albums"] }); // typeorm@0.2.x } } ``` `loadedPhoto` 的值为: ``` { id: 1, name: "Me and Bears", description: "I am near polar bears", filename: "photo-with-bears.jpg", albums: [{ id: 1, name: "Bears" }, { id: 2, name: "Me" }] } ``` ### 18、使用 QueryBuilder[​](#18使用-querybuilder "18、使用 QueryBuilder的直接链接") 您可以使用QueryBuilder来构建几乎任何复杂的SQL查询。例如,您可以这样做: ``` let photos = await this.photoModel .createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it. .innerJoinAndSelect("photo.metadata", "metadata") .leftJoinAndSelect("photo.albums", "album") .where("photo.isPublished = true") .andWhere("(photo.name = :photoName OR photo.name = :bearName)") .orderBy("photo.id", "DESC") .skip(5) .take(10) .setParameters({ photoName: "My", bearName: "Mishka" }) .getMany(); ``` 该查询选择所有带有 “My” 或 “Mishka” 名称的已发布照片。它将从位置 5 开始返回结果(分页偏移),并且将仅选择 10 个结果(分页限制)。选择结果将按 ID 降序排列。该照片的相册将 left-Joined,元数据将自动关联。 您将在应用程序中大量使用查询生成器。在 [此处](https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/select-query-builder.md) 了解有关QueryBuilder的更多信息。 ### 19、Event Subscriber[​](#19event-subscriber "19、Event Subscriber的直接链接") typeorm 提供了一个事件订阅机制,方便在做一些数据库操作时的日志输出,为此 midway 提供了一个 `EventSubscriberModel` 装饰器,用来标注事件订阅类,代码如下。 ``` import { Provide } from '@midwayjs/core'; import { EventSubscriberModel } from '@midwayjs/orm'; import { EntitySubscriberInterface, InsertEvent, UpdateEvent, RemoveEvent } from 'typeorm'; @Provide() @EventSubscriberModel() export class EverythingSubscriber implements EntitySubscriberInterface { /** * Called before entity insertion. */ beforeInsert(event: InsertEvent) { console.log(`BEFORE ENTITY INSERTED: `, event.entity); } /** * Called before entity insertion. */ beforeUpdate(event: UpdateEvent) { console.log(`BEFORE ENTITY UPDATED: `, event.entity); } /** * Called before entity insertion. */ beforeRemove(event: RemoveEvent) { console.log(`BEFORE ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity insertion. */ afterInsert(event: InsertEvent) { console.log(`AFTER ENTITY INSERTED: `, event.entity); } /** * Called after entity insertion. */ afterUpdate(event: UpdateEvent) { console.log(`AFTER ENTITY UPDATED: `, event.entity); } /** * Called after entity insertion. */ afterRemove(event: RemoveEvent) { console.log(`AFTER ENTITY WITH ID ${event.entityId} REMOVED: `, event.entity); } /** * Called after entity is loaded. */ afterLoad(entity: any) { console.log(`AFTER ENTITY LOADED: `, entity); } } ``` 这个订阅类提供了一些常用的接口,用来在数据库操作时执行一些事情。 ### 20、OrmConnectionHook[​](#20ormconnectionhook "20、OrmConnectionHook的直接链接") 在 3.4.0(不包含) 之前的版本中, Midway 封装提供了一种 Hook 机制,用于监听数据库连接与断连事件;代码如下。 ``` import { Provide } from '@midwayjs/core'; import { OrmConnectionHook, OrmHook } from '@midwayjs/orm'; import { Connection, ConnectionOptions } from 'typeorm'; @Provide() @OrmHook() export class OrmConnectionListener implements OrmConnectionHook { /** * Called before connection create * @param opts * @returns */ async beforeCreate(opts?: ConnectionOptions): Promise { console.log('BEFORE CONNECTION CREATE'); return opts; } /** * Called after connection create * @param conn * @param opts * @returns */ async afterCreate(conn?: Connection, opts?: ConnectionOptions): Promise { console.log('AFTER CONNECTION CREATE'); return conn; } /** * Called before connection close * @param conn * @param connectionName * @returns */ async beforeClose(conn?: Connection, connectionName?: string): Promise { console.log('BEFORE CONNECTION CLOSE'); return conn; } /** * Called after connection close * @param conn * @returns */ async afterClose(conn?: Connection): Promise { console.log('AFTER CONNECTION CLOSE'); return conn; } } ``` ## 高级功能[​](#高级功能 "高级功能的直接链接") ### 多数据库支持[​](#多数据库支持 "多数据库支持的直接链接") 有时候,我们一个应用中会有多个数据库连接(Connection)的情况,这个时候会有多个配置。我们使用**对象的形式**来定义配置。 比如下面定义了 `default` 和 `test` 两个数据库连接(Connection)。 ``` import {join} from 'path'; export default { orm: { default: { type: 'sqlite', database: join(__dirname, '../../default.sqlite'), logging: true, }, test: { type: 'mysql', host: '127.0.0.1', port: 3306, username: '*********', password: '*********', database: undefined, synchronize: true, logging: false, } } } ``` 在使用时,需要指定模型归属于哪个连接(Connection)。 ``` // entity/photo.ts import { InjectEntityModel } from '@midwayjs/orm'; import { User } from './model/user'; export class XXX { @InjectEntityModel(User, 'test') testUserModel: Repository; //... } ``` 同样的,在使用注入 Model 时,需要指定连接。 ``` // entity/photo.ts import { EntityModel } from '@midwayjs/orm'; @EntityModel('photo', { connectionName: 'test' }) export class Photo { id: number; name: string; description: string; filename: string; views: number; isPublished: boolean; } ``` ### 获取连接池[​](#获取连接池 "获取连接池的�直接链接") ``` import { Configuration } from '@midwayjs/core'; import { getConnection } from 'typeorm'; @Configuration() export class MainConfiguration { async onReady() { const conn = getConnection('default'); console.log(conn.isConnected); } } ``` ### Hooks 场景支持[​](#hooks-场景支持 "Hooks 场景支持的直接链接") 针对函数式编程的场景,我们提供了简化的函数式写法。 ``` import { useEntityModel } from '@midwayjs/orm'; import { Photo } from './entity/photo'; export async function getPhoto() { // get model const photoModel = useEntityModel(Photo); const photo = new Photo(); // create entity photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.views = 1; photo.isPublished = true; // find const newPhoto = await photoModel.save(photo); return 'hello world'; } ``` ### 关于表结构同步[​](#关于表结构同步 "关于表结构同步的直接链接") * 如果你已有表结构,想自动创建 Entity,使用 [生成器](/docs/tool/typeorm_generator.md) * 如果已经有 Entity 代码,想创建表结构请使用配置中的 `synchronize: true` 。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### Handshake inactivity timeout[​](#handshake-inactivity-timeout "Handshake inactivity timeout的直接链接") 一般是网络原因,如果本地出现,可以 ping 但是telnet不通,可以尝试执行如下命令: ``` $ sudo sysctl -w net.inet.tcp.sack=0 ``` ### 关于 mysql 时间列的当前时区展示[​](#关于-mysql-时间列的当前时区展示 "关于 mysql 时间列的当前时区展示的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,一般情况下,数据库中保存的是 UTC 时间,如果你希望返回当前时区的时间,可以使用下面的方式。 在配置时,开启时间转字符串的选项。 ``` // src/config/config.default.ts export default { // ... orm: { //... dateStrings: true, }, } ``` 实体中的时间列需要列类型。 ``` @EntityModel() export class Photo { //... @UpdateDateColumn({ name: "gmt_modified", type: 'timestamp' }) gmtModified: Date; @CreateDateColumn({ name: "gmt_create", type: 'timestamp' }) gmtCreate: Date; } ``` 这样,输出的时间字段就是当前的时区了。 效果如下: **配置前:** ``` gmtModified: 2021-12-13T03:49:43.000Z, gmtCreate: 2021-12-13T03:49:43.000Z ``` **配置后:** ``` gmtModified: '2021-12-13 11:49:43', gmtCreate: '2021-12-13 11:49:43' ``` ### 关于时间列的默认值[​](#关于时间列的默认值 "关于时间列的默认值的直接链接") 如果使用 `@UpdateDateColumn` 和 `@CreateDateColumn` 列,那么注意,typeorm 是在建表语句中自动添加了默认值,如果表是用户自建的,该字段会由于没有默认值而写入 00:00:00 的时间。 解决方案有两个 **1、修改表的默认值** 或者 **2、修改代码中列的默认值** **如果不想修改表,而想修改代码,请参考下面的代码。** ``` @Column({ default: () => "NOW()", type: 'timestamp' }) createdOn: Date; @Column({ default: () => "NOW()", type: 'timestamp' }) modifiedOn: Date; ``` ### 同时安装 mysql 和 mysql2[​](#同时安装-mysql-和-mysql2 "同时安装 mysql 和 mysql2的直接链接") 在 node\_modules 中同时有 mysql 和 mysql2 时,typeorm 会自动加载 mysql,而不是 mysql2。 这个时候如需使用 mysql2,请指定 driver。 ``` // src/config/config.default.ts export default { // ... orm: { //... type: 'mysql', driver: require('mysql2'), }, } ``` --- # Sequelize 提示 本文档从 v3.4.0 版本起废弃。 本文档介绍如何在 Midway 中使用 Sequelize 模块。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ✅ | | 可用于一体化 | ✅ | ## 使用方法:[​](#使用方法 "使用方法:的直接链接") ``` $ npm i @midwayjs/sequelize@4 sequelize --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/sequelize": "^4.0.0", "sequelize": "^6.13.0" // ... }, "devDependencies": { // ... } } ``` ## 安装数据库 Driver[​](#安装数据库-driver "安装数据库 Driver的直接链接") 常用数据库驱动如下,选择你对应连接的数据库类型安装: ``` # for MySQL or MariaDB,也可以使用 mysql2 替代 npm install mysql --save npm install mysql2 --save # for PostgreSQL or CockroachDB npm install pg --save # for SQLite npm install sqlite3 --save # for Microsoft SQL Server npm install mssql --save # for sql.js npm install sql.js --save # for Oracle npm install oracledb --save # for MongoDB(experimental) npm install mongodb --save ``` ## 引入模块[​](#引入模块 "引入模块的直接链接") 在 configuration.ts 文件中 ``` import { App, Configuration, ILifeCycle } from '@midwayjs/core'; import { Application } from '@midwayjs/web'; import { join } from 'path'; import * as sequelize from '@midwayjs/sequelize'; @Configuration({ imports: [sequelize], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration implements ILifeCycle { @App() app: Application; async onReady() {} } ``` ## 配置[​](#配置 "配置的直接链接") 在 config.default.ts 中配置: ``` // src/config/config.default.ts export default { // ... sequelize: { dataSource: { default: { database: 'test4', username: 'root', password: '123456', host: '127.0.0.1', // 此处支持idb上面vipserver key的那种方式,也支持aliyun的地址。 port: 3306, encrypt: false, dialect: 'mysql', define: { charset: 'utf8' }, timezone: '+08:00', logging: console.log, }, }, sync: false, // 本地的时候,可以通过sync: true直接createTable }, }; ``` ## 业务层[​](#业务层 "业务层的直接链接") ### 定义 Entity[​](#定义-entity "定义 Entity的直接链接") ``` import { Column, Model, BelongsTo, ForeignKey } from 'sequelize-typescript'; import { BaseTable } from '@midwayjs/sequelize'; import { User } from './User'; @BaseTable export class Photo extends Model { @ForeignKey(() => User) @Column({ comment: '用户Id', }) userId: number; @BelongsTo(() => User) user: User; @Column({ comment: '名字', }) name: string; } ``` ``` import { Model, Column, HasMany } from 'sequelize-typescript'; import { BaseTable } from '@midwayjs/sequelize'; import { Photo } from './Photo'; @BaseTable export class User extends Model { @Column name!: string; @HasMany(() => Photo) Photo: Photo[]; } ``` ### 使用 Entity:[​](#使用-entity "使用 Entity:的直接链接") #### 查询列表[​](#查询列表 "查询列表的直接链接") ``` import { Config, Controller, Get, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { let result = await Photo.findAll(); console.log(result); return 'hello world'; } } ``` 增加数据: ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/add') async home() { let result = await Photo.create({ name: '123', }); console.log(result); return 'hello world'; } } ``` #### 删除:[​](#删除 "删除:的直接链接") ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { await Photo.destroy({ where: { name: '123', }, }); return 'hello world'; } } ``` #### 查找单个:[​](#查找单个 "查找单个:的直接链接") ``` import { Controller, Post, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/') export class HomeController { @Post('/delete') async home() { let result = await Photo.findOne({ where: { name: '123', }, }); return 'hello world'; } } ``` #### 联合查询:[​](#联合查询 "联合查询:的直接链接") ``` import { Controller, Get, Provide } from '@midwayjs/core'; import { Photo } from '../entity/Photo'; import { Op } from 'sequelize'; @Provide() @Controller('/') export class HomeController { @Get('/') async home() { // SELECT * FROM photo WHERE name = "23" OR name = "34"; let result = await Photo.findAll({ where: { [Op.or]: [{ name: '23' }, { name: '34' }], }, }); console.log(result); return 'hello world'; } } ``` #### 连表查询[​](#连表查询 "连表查询的直接链接") ``` import { Controller, Get, Provide } from '@midwayjs/core'; import { User } from '../entity/User'; import { Photo } from '../entity/Photo'; @Provide() @Controller('/users') export class HomeController { @Get('/') async home() { let result = await User.findAll({ include: [Photo] }); console.log(result); return 'hello world'; } } ``` 关于 OP 的更多用法: midway + sequelize 完整使用案例 如果遇到比较复杂的,可以使用 raw query 方法: --- # 任务调度 提示 本文档从 v3.6.0 版本起废弃。 @midwayjs/task 是为了解决任务系列的模块,例如分布式定时任务、延迟任务调度。例如每日定时报表邮件发送、订单2小时后失效等工作。 分布式定时任务依赖 bull,其通过 redis 进行实现,所以配置中,需要配置额外的 Redis,本地定时任务基于 Cron 模块,不需要额外配置。 相关信息: | 描述 | | | ----------------- | -- | | 可用于标准项目 | ✅ | | 可用于 Serverless | ❌ | | 可用于一体化 | ✅ | **其他** | 描述 | | | -------------------- | -- | | 可作为主框架独立使用 | ✅ | | 包含自定义日志 | ✅ | | 可独立添加中间件 | ❌ | ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 首先安装 Midway 提供的任务组件: ``` $ npm install @midwayjs/task@4 @types/bull --save ``` 或者在 `package.json` 中增加如下依赖后,重新安装。 ``` { "dependencies": { "@midwayjs/task": "^4.0.0", // ... }, "devDependencies": { "@types/bull": "^3.15.8", // ... } } ``` ## 引入组件[​](#引入组件 "引入组件的直接链接") 在 `configuration.ts` 中,引入这个组件: ``` // src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as task from '@midwayjs/task'; // 导入模块 import { join } from 'path'; @Configuration({ imports: [task], importConfigs: [join(__dirname, 'config')] }) export class MainConfiguration { } ``` ## 分布式定时任务[​](#分布式定时任务 "分布式定时任务的直接链接") 这是我们最常用的定时任务方式。 分布式定时任务,可以做到分布在多个进程,多台机器去执行单一定时任务方式。 分布式定义任务依赖 Redis 服务,需要提前申请。 ### 配置[​](#配置 "配置的直接链接") 在 `config.default.ts` 文件中配置对应的模块信息: ``` // src/config/config.default.ts export default { // ... task: { redis: `redis://127.0.0.1:32768`, // 任务依赖redis,所以此处需要加一个redis prefix: 'midway-task', // 这些任务存储的key,都是midway-task开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }, } ``` 有账号密码情况: ``` // src/config/config.default.ts export default { // ... task: { // ioredis的配置 https://www.npmjs.com/package/ioredis redis: { port: 6379, host: '127.0.0.1', password: 'foobared', }, prefix: 'midway-task', // 这些任务存储的 key,都是 midway-task 开头,以便区分用户原有redis 里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task 等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 }, }, }, } ``` ### 代码使用[​](#代码使用 "代码使用的直接链接") ``` import { Provide, Inject, Task, FORMAT } from '@midwayjs/core'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每分钟执行一次,并且是分布式任务 @Task({ repeat: { cron: FORMAT.CRONTAB.EVERY_MINUTE} }) async test() { console.log(this.helloService.getName()) } } ``` ### 设置进度[​](#设置进度 "设置进度的直接链接") 例如我们在做音视频或者发布这种比较耗时的任务的时候,我们希望能设置进度。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01WPYaAz21NgV3VNzjV_!!6000000006973-2-tps-576-454.png) 相当于第二个参数,将 bull 的 job 传递给了用户。用户可以通过 `job.progress` 来设置进度。 然后查询进度: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Controller, Get } from '@midwayjs/core'; @Controller() export class HelloController{ @Inject() queueService: QueueService; @Get("/get-queue") async getQueue(@Query() id: string){ return await this.queueService.getClassQueue(TestJob).getJob(id); } } ``` ### 任务的相关内容[​](#任务的相关内容 "任务的相关内容的直接链接") ``` let job = await this.queueService.getClassQueue(TestJob).getJob(id) ``` 然后 job 上面有类似停止的方法,或者查看进度的方法。 ### 启动就触发[​](#启动就触发 "启动就触发的直接链接") 有朋友由于只有一台机器,希望重启后立马能执行一下对应的定时任务。 ``` import { Configuration, Context, ILifeCycle, IMidwayBaseApplication, IMidwayContainer } from '@midwayjs/core'; import { Queue } from 'bull'; import { join } from 'path'; import * as task from '@midwayjs/task'; import { QueueService } from '@midwayjs/task'; @Configuration({ imports: [ task ], importConfigs: [ join(__dirname, './config') ] }) export class MainConfiguration implements ILifeCycle { async onServerReady(container: IMidwayContainer, app?: IMidwayBaseApplication): Promise { // Task这块的启动后立马执行 let result: QueueService = await container.getAsync(QueueService); // 此处第一个是你任务的类名,第二个任务的名字也就是装饰器Task的函数名 let job: Queue = result.getQueueTask(`HelloTask`, 'task') // 表示立即执行。 job.add({}, {delay: 0, repeat: null}) // LocalTask的启动后立马执行 const result = await container.getAsync(QueueService); let job = result.getLocalTask(`HelloTask`, 'task'); // 参数1:类名 参数2: 装饰器TaskLocal的函数名 job(); // 表示立即执行 } } ``` ## 常用 Cron 表达式[​](#常用-cron-表达式 "常用 Cron 表达式的直接链接") 关于 Task 任务的配置: ``` * * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional) ``` 常见表达式: * 每隔5秒执行一次:`*/5 * * * * *` * 每隔1分钟执行一次:`0 */1 * * * *` * 每小时的20分执行一次:`0 20 * * * *` * 每天 0 点执行一次:`0 0 0 * * *` * 每天的两点35分执行一次:`0 35 2 * * *` 可以使用 [在线工具](https://cron.qqe2.com/) 执行确认下一次执行的时间。 Midway 在框架侧提供了一些常用的表达式,放在 `@midwayjs/core` 中供大家使用。 ``` import { FORMAT } from '@midwayjs/core'; // 每分钟执行的 cron 表达式 FORMAT.CRONTAB.EVERY_MINUTE ``` 内置的还有一些其他的表达式。 | 表达式 | 对应时间 | | --------------------------------- | --------------- | | CRONTAB.EVERY\_SECOND | 每秒钟 | | CRONTAB.EVERY\_MINUTE | 每分钟 | | CRONTAB.EVERY\_HOUR | 每小时整点 | | CRONTAB.EVERY\_DAY | 每天 0 点 | | CRONTAB.EVERY\_DAY\_ZERO\_FIFTEEN | 每天 0 点 15 分 | | CRONTAB.EVERY\_DAY\_ONE\_FIFTEEN | 每天 1 点 15 分 | | CRONTAB.EVERY\_PER\_5\_SECOND | 每隔 5 秒 | | CRONTAB.EVERY\_PER\_10\_SECOND | 每隔 10 秒 | | CRONTAB.EVERY\_PER\_30\_SECOND | 每隔 30 秒 | | CRONTAB.EVERY\_PER\_5\_MINUTE | 每隔 5 分钟 | | CRONTAB.EVERY\_PER\_10\_MINUTE | 每隔 10 分钟 | | CRONTAB.EVERY\_PER\_30\_MINUTE | 每隔 30 分钟 | ## 手动触发任务[​](#手动触发任务 "手动触发任务的直接链接") 任务的定义,通过 `@Queue` 装饰器,定义一个任务类,必须含有一个 `async execute()` 方法。 ``` import { Provide, Inject, Queue } from '@midwayjs/core'; @Queue() export class HelloTask{ async execute(params){ console.log(params); } } ``` 触发: ``` import { QueueService } from '@midwayjs/task'; import { Provide, Inject } from '@midwayjs/core'; @Provide() export class UserTask{ @Inject() queueService: QueueService; async execute(params = {}){ // 3秒后触发分布式任务调度。 const xxx = await this.queueService.execute(HelloTask, params, {delay: 3000}); } } ``` 3 秒后,会触发 HelloTask 这个任务。 提示 注意,如果没触发,请检查上面的 params,保证其不为空。 ## 运维[​](#运维 "运维的直接链接") ### 日志[​](#日志 "日志的直接链接") 在Midway Task Component上面,增加了两个日志: * midway-task.log * midway-task-error.log 分别在task、localTask、queue触发开始和结束的时候会打印对应的日志。 task日志基本配置: ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... }, taskLog: { disableConsole: false, // 是否禁用打印到控制台,默认禁用 level: 'warn', // 服务器默认warn consoleLevel: 'warn', }, } }, } as MidwayConfig; ``` 分布式的Task触发日志: ``` logger.info(`task start.`) // 异常情况: logger.error(err.stack) logger.info(`task end.`) ``` 非分布式的LocalTask触发日志: ``` logger.info(`local task start.`) // 异常情况: // logger.error(`${e.stack}`) logger.info(`local task end.`) ``` 任务队列的触发日志: ``` logger.info(`queue process start.`) // 异常情况: // logger.error(`${e.stack}`) logger.info(`queue process end.`) ``` ### 排查问题链路:[​](#排查问题链路 "排查问题链路:的直接链接") ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01xL1mQE25kMZnB5ygb_!!6000000007564-2-tps-1614-847.png) 用户可以搜索这个相同的id,找到同一次请求的日志。 为了方便用户在自己的业务代码中串联对应的日志,我在ctx上面挂了traceId变量。 例如异常情况:当异常的时候,**本地可以在控制台和 midway-task.log 栏内看到这个错误相关的情况:** ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01WYBjbL1lGKHmsdSnH_!!6000000004791-2-tps-1964-324.png) ### traceId[​](#traceid "traceId的直接链接") localTask 则是自己生成了一个 uuid 的 id 作为 traceId。 task 和 queue 则采用 job 的 id 作为 traceId。 ### 业务内部的代码[​](#业务内部的代码 "业务内部的代码的直接链接") 在 service 内可以通过 inject 注入 logger,或者注入 ctx 拿 logger 变量 ``` import { App, Inject, Provide, Queue } from '@midwayjs/core'; import { Application } from "@midwayjs/koa"; @Queue() export class QueueTask{ @App() app: Application; @Inject() logger; async execute(params){ this.logger.info(`====>QueueTask execute`) this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 或者 ``` import { App, Inject, Provide, Queue } from '@midwayjs/core'; import { Application } from "@midwayjs/koa"; @Queue() export class QueueTask{ @App() app: Application; @Inject() ctx; async execute(params){ this.ctx.logger.info(`====>QueueTask execute`) this.app.getApplicationContext().registerObject(`queueConfig`, JSON.stringify(params)); } } ``` 打印的日志 ``` 2021-07-30 13:00:13,101 INFO 5577 [Queue][12][QueueTask] queue process start. 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] ====>QueueTask execute 2021-07-30 13:00:13,102 INFO 5577 [Queue][12][QueueTask] queue process end. ``` ## 本地定时任务[​](#本地定时任务 "本地定时任务的直接链接") 本地定时任务和分布式任务不同,无需依赖和配置 Redis,只能做到单进程的事情,即每台机器的每个进程都会被执行。 ``` import { Provide, Inject, TaskLocal, FORMAT } from '@midwayjs/core'; @Provide() export class UserService { @Inject() helloService: HelloService; // 例如下面是每分钟执行一次 @TaskLocal(FORMAT.CRONTAB.EVERY_MINUTE) async test(){ console.log(this.helloService.getName()) } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、EVALSHA错误[​](#1evalsha错误 "1、EVALSHA错误的直接链接") ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01KfjCKT1yypmNPDkIL_!!6000000006648-2-tps-3540-102.png) 这个问题基本明确,问题会出现在 redis 的集群版本上。原因是 redis 会对 key 做 hash 来确定存储的 slot,集群下这一步 @midwayjs/task 的 key 命中了不同的 slot。临时的解决办法是 task 里的 prefix 配置用 包括,强制 redis 只计算 里的hash,例如 `prefix: '{midway-task}'`。 ### 2、历史日志删除[​](#2历史日志删除 "2、历史日志删除的直接链接") 当每次redis执行完他会有日志,那么如何让其在完成后删除: ``` import { Provide, Task } from '@midwayjs/core'; import { IUserOptions } from '../interface'; @Provide() export class UserService { async getUser(options: IUserOptions) { return { uid: options.uid, username: 'mockedName', phone: '12345678901', email: 'xxx.xxx@xxx.com', }; } @Task({ repeat: { cron: '* * * * * *'}, removeOnComplete: true // 加了一行这个 }) async test(){ console.log(`====`) } } ``` 目前是否默认删除,需要跟用户沟通。 ### 3、配置 Redis 集群[​](#3配置-redis-集群 "3、配置 Redis 集群的直接链接") 你可以使用 bull 提供的 `createClient` 方式来接入自定义的 redis 实例,这样你可以接入 Redis 集群。 比如: ``` // src/config/config.default import Redis from 'ioredis'; const clusterOptions = { enableReadyCheck: false, // 一定要是false retryDelayOnClusterDown: 300, retryDelayOnFailover: 1000, retryDelayOnTryAgain: 3000, slotsRefreshTimeout: 10000, maxRetriesPerRequest: null // 一定要是null } const redisClientInstance = new Redis.Cluster([ { port: 7000, host: '127.0.0.1' }, { port: 7002, host: '127.0.0.1' }, ], clusterOptions); export default { task: { createClient: (type, opts) => { return redisClientInstance; }, prefix: '{midway-task}', // 这些任务存储的key,都是相同开头,以便区分用户原有redis里面的配置。 defaultJobOptions: { repeat: { tz: "Asia/Shanghai" // Task等参数里面设置的比如(0 0 0 * * *)本来是为了0点执行,但是由于时区不对,所以国内用户时区设置一下。 } } } } ``` --- # 生命周期 在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。 ## 项目生命周期[​](#项目生命周期 "项目生命周期的直接链接") 框架提供了这些生命周期函数供开发人员处理: * 配置文件加载,我们可以在这里去修改配置(`onConfigLoad`) * 依赖注入容器准备完毕,可以在这个阶段做大部分的事情(`onReady`) * 服务启动完成,可以拿到 server(`onServerReady`) * 应用即将关闭,在这里清理资源(`onStop`) Midway 的生命周期是通过 `src/configuration.ts` 文件,实现 ILifeCycle 接口,就可以在项目启动时候自动加载。 接口定义如下。 ``` interface ILifeCycle { /** * 在应用配置加载后执行 */ onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在依赖注入容器 ready 的时候执行 */ onReady(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用服务启动后执行 */ onServerReady?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在应用停止的时候执行 */ onStop?(container: IMidwayContainer, app: IMidwayApplication): Promise; /** * 在健康检查时执行 */ onHealthCheck?(container: IMidwayContainer): Promise; } ``` ### onConfigLoad[​](#onconfigload "onConfigLoad的直接链接") 一般用于修改项目的配置文件。 举个例子。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onConfigLoad(): Promise { // 直接返回数据,会自动合并到配置中 return { test: 1 } } } ``` 这个时候,`@Config` 拿到的配置就包含了返回的数据,具体可以参考 [异步初始化配置](/docs/env_config.md#%E5%BC%82%E6%AD%A5%E5%88%9D%E5%A7%8B%E5%8C%96%E9%85%8D%E7%BD%AE) 章节。 ### onReady[​](#onready "onReady的直接链接") onReady 是一个大部分场景下都会使用到的生命周期。 信息 注意,这里的 ready 指的是依赖注入容器 ready,并不是应用 ready,所以你可以对应用做任意扩展,比如添加中间件,连接数据库等等。 我们需要在初始化时提前连接一个数据库,由于在类中,所以也可以通过 `@Inject` 装饰器注入 db 这样一个数据库的连接工具类,这个实例包含 connect 和 close 两个函数: ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { // 建立数据库连接 await this.db.connect(); } async onStop(): Promise { // 关闭数据库连接 await this.db.close(); } } ``` 这样,我们就能够在应用启动时建立数据库连接,而不是在请求响应时再去创建。同时,在应用停止时,也可以优雅的关闭数据库连接。 除此之外,通过这个方式,可以对默认注入的对象做扩充。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as sequelize from 'sequelize'; @Configuration() export class MainConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer): Promise { // 三方包对象 container.registerObject('sequelize', sequelize); } } ``` 在其他的类中可以直接注入使用。 ``` export class IndexHandler { @Inject() sequelize; async handler() { console.log(this.sequelize); } } ``` ### onServerReady[​](#onserverready "onServerReady的直接链接") 当要获取框架的服务对象,端口等信息时,就需要用到这个生命周期。 我们以 `@midwayjs/koa` 为例,在启动时获取它的 Server。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { async onServerReady(container: IMidwayContainer): Promise { // 获取到 koa 中暴露的 Framework const framework = await container.getAsync(koa.Framework); const server = framework.getServer(); // ... } } ``` ### onStop[​](#onstop "onStop的直接链接") 我们可以在这个阶段清理一些资源,比如关闭连接等。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; @Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { // 建立数据库连接 await this.db.connect(); } async onStop(): Promise { // 关闭数据库连接 await this.db.close(); } } ``` ### onHealthCheck[​](#onhealthcheck "onHealthCheck的直接链接") 当内置的健康检查服务调用状态获取 API 时,所有组件的该方法都被自动执行。 下面模拟了一个 db 健康检查的方法。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, HealthResult } from '@midwayjs/core'; @Configuration({ namespace: 'db' }) export class MainConfiguration implements ILifeCycle { @Inject() db: any; async onReady(container: IMidwayContainer): Promise { await this.db.connect(); } async onHealthCheck(): Promise { try { const result = await this.db.isConnect(); if (result) { return { status: true, }; } else { return { status: false, reason: 'db is disconnect', }; } } catch (err) { return { status: false, reason: err.message, }; } } } ``` 上述 `onHealthCheck` 中,调用了一个 `isConnect` 的状态检查,根据结果返回了固定的 `HealthResult` 类型格式。 注意,外部调用 `onHealthCheck` 可能会非常频繁,请尽可能保持检查逻辑的可靠性和效率,确保不会对检查依赖有较大的压力。同时请自行处理检查超时后资源释放的逻辑,避免资源频繁请求却未返回结果,导致内存泄露的风险。 ## 全局对象生命周期[​](#全局对象生命周期 "全局对象生命周期的直接链接") 所谓对象生命周期,指的是每个对象,在依赖注入容器中创建,销毁的事件。我们通过这些生命周期,可以在对象创建后,销毁时做一些操作。 ``` export interface IObjectLifeCycle { onBeforeObjectCreated(/**...**/); onObjectCreated(/**...**/); onObjectInit(/**...**/); onBeforeObjectDestroy(/**...**/); } ``` `ILifeCycle` 定义中已经包含了这些阶段。 警告 注意,对象生命周期 API 会影响整个依赖注入容器以及业务的使用,请谨慎操作。 ### onBeforeObjectCreated[​](#onbeforeobjectcreated "onBeforeObjectCreated的直接链接") 在业务对象实例创建前执行,框架内部的某些对象由于已经初始化,无法被拦截。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeCreatedOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectCreated(Clzz: new (...args), options: ObjectBeforeCreatedOptions): Promise { // ... } } ``` 这里入参有两个参数: * `Clzz` 当前待创建对象的原型类 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ----------------------- | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | | options.constructorArgs | any\[] | 构造器入参 | ### onObjectCreated[​](#onobjectcreated "onObjectCreated的直接链接") 在对象实例创建后执行,这个阶段可以替换创建的对象。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectCreatedOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectCreatedOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ----------------------- | ------------------ | ------------------ | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | | options.replaceCallback | (ins: any) => void | 对象替换的回调方法 | **示例:动态添加属性** ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promise { // 每个创建的对象都会添加一个 _name 的属性 ins._name = 'xxxx'; // ... } } ``` **示例:替换对象** ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promise { // 之后每个创建的对象都会被替换为 { bbb: 'aaa' } options.replaceCallback({ bbb: 'aaa' }); // ... } } ``` ### onObjectInit[​](#onobjectinit "onObjectInit的直接链接") 在对象实例创建后执行异步初始化方法后执行。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onObjectInit(ins: any, options: ObjectInitOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ------------------ | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | 信息 在这个阶段也可以动态给对象附加属性,方法等,和 `onObjectCreated` 的区别是,这个阶段是在初始化方法执行之后。 ### onBeforeObjectDestroy[​](#onbeforeobjectdestroy "onBeforeObjectDestroy的直接链接") 在对象实例销毁前执行。 ``` // src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeDestroyOptions } from '@midwayjs/core'; @Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectDestroy(ins: any, options: ObjectBeforeDestroyOptions): Promise { // ... } } ``` 这里入参有两个参数: * `ins` 当前通过构建器创出来的对象 * `options` 一些参数 参数如下: | 属性 | 类型 | 描述 | | ------------------ | ----------------- | ---------------- | | options.context | IMidwayContainer | 依赖注入容器本身 | | options.definition | IObjectDefinition | 对象定义 | ## 超时机制[​](#超时机制 "超时机制的直接链接") 从 v4 开始,框架内置了超时机制,防止某些生命周期函数阻塞应用启动。 ### 默认超时时间[​](#默认超时时间 "默认超时时间的直接链接") 不同生命周期方法有不同的默认超时时间: | 生命周期方法 | 默认超时时间 | 配置项 | 说明 | | --------------- | ------------ | ------------------------- | ------------ | | `onConfigLoad` | 10 秒 | `core.configLoadTimeout` | 配置加载阶段 | | `onReady` | 30 秒 | `core.readyTimeout` | 容器准备阶段 | | `onServerReady` | 30 秒 | `core.serverReadyTimeout` | 服务启动阶段 | | `onStop` | 默认无限制 | `core.stopTimeout` | 应用停止阶段 | | `onHealthCheck` | 1 秒 | `core.healthCheckTimeout` | 健康检查阶段 | ### 自定义超时时间[​](#自定义超时时间 "自定义超时时间的直接链接") 可以通过配置修改每个生命周期的超时时间: 提示 注意,这个配置是全局的。 ``` // src/config/config.default.ts export default { core: { // 配置加载超时(毫秒) configLoadTimeout: 15_000, // 15秒 } } as MidwayConfig; ``` ### 在生命周期中处理超时[​](#在生命周期中处理超时 "在生命周期中处理超时的直接链接") 在生命周期方法中,可以通过入参获取到当前的超时配置,以及中断信号。 ``` @Configuration() export class MainConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer, app: IMidwayApplication, options: { timeout?: number; abortController?: AbortController; }): Promise { // 可以获取到超时配置 console.log('当前超时配置:', options.timeout); // 30000 // 可以监听中断信号 if (options.abortController) { options.abortController.signal.addEventListener('abort', () => { console.log('生命周期被中断'); }); } // 执行初始化逻辑 await this.initializeServices(); } } ``` --- # 日志(v2) 提示 本文档为 `@midwayjs/logger` v2.0 版本的文档。 Midway 为不同场景提供了一套统一的日志接入方式。通过 `@midwayjs/logger` 包导出的方法,可以方便的接入不同场景的日志系统。 Midway 的日志系统基于社区的 [winston](https://github.com/winstonjs/winston),是现在社区非常受欢迎的日志库。 实现的功能有: * 日志分级 * 按大小和时间自动切割 * 自定义输出格式 * 统一错误日志 ## 日志路径和文件[​](#日志路径和文件 "日志路径和文件的直接链接") Midway 会在日志根目录创建一些默认的文件。 * `midway-core.log` 框架、组件打印信息的日志,对应 `coreLogger` 。 * `midway-app.log` 应用打印信息的日志,对应 `appLogger` * `common-error.log` 所有错误的日志(所有 Midway 创建出来的日志,都会将错误重复打印一份到该文件中) 本地开发和服务器部署时的 **日志路径** 和 **日志等级** 不同,具体请参考 [配置日志根目录](#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95) 和 [框架的默认等级](#%E6%A1%86%E6%9E%B6%E7%9A%84%E9%BB%98%E8%AE%A4%E7%AD%89%E7%BA%A7)。 ## 默认日志对象[​](#默认日志对象 "默认日志对象的直接链接") Midway 默认在框架提供了三种不同的日志,对应三种不同的行为。 | 日志 | 释义 | 描述 | 常见使用 | | ----------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | coreLogger | 框架,组件层面的日志 | 默认会输出控制台日志和文本日志 `midway-core.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 框架和组件的错误,一般会打印到其中。 | | appLogger | 业务层面的日志 | 默认会输出控制台日志和文本日志 `midway-app.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 业务使用的日志,一般业务日志会打印到其中。 | | 上下文日志(复用 appLogger 的配置) | 请求链路的日志 | 默认使用 `appLogger` 进行输出,除了会将错误日志发送到 `common-error.log` 之外,还增加了上下文信息。 | 修改日志输出的标记(Label),不同的框架有不同的请求标记,比如 HTTP 下就会输出路由信息。 | ## 使用日志[​](#使用日志 "使用日志的直接链接") Midway 的常用日志使用方法。 ### 上下文日志[​](#上下文日志 "上下文日志的直接链接") 上下文日志是关联框架上下文对象(Context) 的日志。 我们可以通过 [获取到 ctx 对象](/docs/req_res_app.md) 后,使用 `ctx.logger` 对象进行日志打印输出。 比如: ``` ctx.logger.info("hello world"); ctx.logger.debug('debug info'); ctx.logger.warn('WARNNING!!!!'); // 错误日志记录,直接会将错误日志完整堆栈信息记录下来,并且输出到 errorLog 中 // 为了保证异常可追踪,必须保证所有抛出的异常都是 Error 类型,因为只有 Error 类型才会带上堆栈信息,定位到问题。 ctx.logger.error(new Error('custom error')); ``` 在执行后,我们能在两个地方看到日志输出: * 控制台看到输出。 * 日志目录的 midway-app.log 文件中 输出结果: ``` 2021-07-22 14:50:59,388 INFO 7739 [-/::ffff:127.0.0.1/-/0ms GET /api/get_user] hello world ``` 在注入的形式中,我们也可以直接使用 `@Inject() logger` 的形式来注入 `ctx.logger` ,和直接调用 `ctx.logger` 等价。 比如: ``` import { Get, Inject, Controller, Provide } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Controller() export class HelloController { @Inject() logger: ILogger; @Inject() ctx; @Get("/") async hello(){ // ... // this.logger === ctx.logger } } ``` ### 应用日志(App Logger)[​](#应用日志app-logger "应用日志(App Logger)的直接链接") 如果我们想做一些应用级别的日志记录,如记录启动阶段的一些数据信息,可以通过 App Logger 来完成。 ``` import { Configuration, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Configuration() export class MainConfiguration implements ILifeCycle { @Logger() logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` 注意,这里使用的是 `@Logger()` 装饰器。 ### CoreLogger[​](#corelogger "CoreLogger的直接链接") 在组件或者框架层面的研发中,我们会使用 coreLogger 来记录日志。 ``` @Configuration() export class MainConfiguration implements ILifeCycle { @Logger('coreLogger') logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` ## 输出方法和格式[​](#输出方法和格式 "输出方法和格式的直接链接") Midway 的日志对象继承与 winston 的日志对象,一般情况下,只提供 `error()` , `warn()` , `info()` , `debug` 四种方法。 示例如下。 ``` logger.debug('debug info'); logger.info('启动耗时 %d ms', Date.now() - start); logger.warn('warning!'); logger.error(new Error('my error')); ``` ### 默认的输出行为[​](#默认的输出行为 "默认的输出行为的直接链接") 在大部分的普通类型下,日志库都能工作的很好。 比如: ``` logger.info('hello world'); // 输出字符串 logger.info(123); // 输出数字 logger.info(['b', 'c']); // 输出数组 logger.info(new Set([2, 3, 4])); // 输出 Set logger.info(new Map([['key1', 'value1'], ['key2', 'value2']])); // 输出 Map ``` > Midway 针对 winston 无法输出的 `Array` , `Set` , `Map` 类型,做了特殊定制,使其也能够正常的输出。 不过需要注意的是,日志对象在一般情况下,只能传入一个参数,它的第二个参数有其他作用。 ``` logger.info('plain error message', 321); // 会忽略 321 ``` ### 错误输出[​](#错误输出 "错误输出的直接链接") 针对错误对象,Midway 也对 winston 做了定制,使其能够方便的和普通文本结合到一起输出。 ``` // 输出错误对象 logger.error(new Error('error instance')); // 输出自定义的错误对象 const error = new Error('named error instance'); error.name = 'NamedError'; logger.error(error); // 文本在前,加上 error 实例 logger.info('text before error', new Error('error instance after text')); ``` 警告 注意,错误对象只能放在最后,且有且只有一个,其后面的所有参数都会被忽略。 ### 格式化内容[​](#格式化内容 "格式化内容的直接链接") 基于 `util.format` 的格式化方式。 ``` logger.info('%s %d', 'aaa', 222); ``` 常用的有 * `%s` 字符串占位 * `%d` 数字占位 * `%j` json 占位 更多的占位和详细信息,请参考 node.js 的 [util.format](https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_format_format_args) 方法。 ### 输出自定义对象或者复杂类型[​](#输出自定义对象或者复杂类型 "输出自定义对象或者复杂类型的直接链接") 基于性能考虑,Midway(winston)大部分时间只会输出基本类型,所以当输出的参数为高级对象时,**需要用户手动转换为需要打印的字符串**。 如下示例,将不会得到希望的结果。 ``` const obj = {a: 1}; logger.info(obj); // 默认情况下,输出 [object Object] ``` 需要手动输出希望打印的内容。 ``` const obj = {a: 1}; logger.info(JSON.stringify(obj)); // 可以输出格式化文本 logger.info(obj.a); // 直接输出属性值 logger.info('%j', a); // 直接占位符输出整个 json ``` ### 纯输出内容[​](#纯输出内容 "纯输出内容的直接链接") 特殊场景下,我们需要单纯的输出内容,不希望输出时间戳,label 等和格式相关的信息。这种需求我们可以使用 `write` 方法。 `write` 方法是个非常底层的方法,并且不管什么级别的日志,它都会写入到文件中。 虽然 `write` 方法在每个 logger 上都有,但是我们只在 `IMidwayLogger` 定义中提供它,我们希望你能明确的知道自己希望调用它。 ``` (logger as IMidwayLogger).write('hello world'); // 文件中只会有 hello world ``` ## 日志类型定义[​](#日志类型定义 "日志类型定义的直接链接") 默认的情况,用户应该使用最简单的 `ILogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; // 获取上下文日志 async getUser() { this.logger.info('hello user'); } } ``` `ILogger` 定义只提供最简单的 `debug` , `info` , `warn` 以及 `error` 方法。 在某些场景下,我们需要更为复杂的定义,比如修改日志属性或者动态调节,这个时候需要使用更为复杂的 `IMidwayLogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { IMidwayLogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: IMidwayLogger; // 获取上下文日志 async getUser() { this.logger.disableConsole(); // 禁止控制台输出 this.logger.info('hello user'); // 这句话在控制台看不到 this.logger.enableConsole(); // 开启控制台输出 this.logger.info('hello user'); // 这句话在控制台可以看到 } } ``` `IMidwayLogger` 的定义可以参考 interface 中的描述,或者查看 [代码](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ## 日志基本配置[​](#日志基本配置 "日志基本配置的直接链接") 我们可以在配置文件中配置日志的各种行为。 Midway 中的的日志配置包含 **全局配置** 和 **单个日志配置** 两个部分,两者配置会合并和覆盖。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... } } }, } as MidwayConfig; ``` 如上所述,`clients` 配置段中的每个对象都是一个独立的日志配置项,其配置会和 `default` 段落合并后创建 logger 实例。 如果你发现没有定义,请将 `@midawyjs/logger` 在 `src/interface.ts` 中显式声明一次。 ``` // ... import type {} from '@midwayjs/logger'; ``` ## 配置日志等级[​](#配置日志等级 "配置日志等级的直接链接") winston 的日志等级分为下面几类,日志等级依次降低(数字越大,等级越低): ``` const levels = { none: 0, error: 1, trace: 2, warn: 3, info: 4, verbose: 5, debug: 6, silly: 7, all: 8, } ``` 在 Midway 中,为了简化,一般情况下,我们只会使用 `error` , `warn` , `info` , `debug` 这四种等级。 日志等级表示当前可输出日志的最低等级。比如当你的日志 level 设置为 `warn` 时,仅 `warn` 以及更高的 `error` 等级的日志能被输出。 在 Midway 中,针对不同的输出行为,可以配置不同的日志等级。 * `level` 写入文本的日志等级 * `consoleLevel` 控制台输出的日志等级 ### 框架的默认等级[​](#框架的默认等级 "框架的默认等级的直接链接") 在 Midway 中,有着自己的默认日志等级。 * 在开发环境下(local,test,unittest),文本和控制台日志等级统一为 `info` 。 * 在服务器环境(除开发环境外),为减少日志数量,`coreLogger` 日志等级为 `warn` ,而其他日志为 `info`。 ### 调整日志等级[​](#调整日志等级 "调整日志等级的直接链接") 一般情况下,我们不建议调整全局默认的日志等级,而是调整特定的 logger 的日志等级,比如: 调整 `coreLogger` 或者 `appLogger` 。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { clients: { coreLogger: { level: 'warn', consoleLevel: 'warn' // ... }, appLogger: { level: 'warn', consoleLevel: 'warn' // ... } } }, } as MidwayConfig; ``` 特殊场景,也可以临时调整全局的日志等级。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', consoleLevel: 'warn' }, // ... }, } as MidwayConfig; ``` ## 配置日志根目录[​](#配置日志根目录 "配置日志根目录的直接链接") 默认情况下,Midway 会在本地开发和服务器部署时输出日志到 **日志根目录**。 * 本地的日志根目录为 `${app.appDir}/logs/项目名` 目录下 * 服务器的日志根目录为用户目录 `${process.env.HOME}/logs/项目名` (Linux/Mac)以及 `${process.env.USERPROFILE}/logs/项目名` (Windows)下,例如 `/home/admin/logs/example-app`。 我们可以配置日志所在的根目录。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { dir: '/home/admin/logs', }, // ... }, } as MidwayConfig; ``` ## 配置日志切割(轮转)[​](#配置日志切割轮转 "配置日志切割(轮转)的直接链接") 默认行为下,同一个日志对象 **会生成两个文件**。 以 `midway-core.log` 为例,应用启动时会生成一个带当日时间戳 `midway-core.YYYY-MM-DD` 格式的文件,以及一个不带时间戳的 `midway-core.log` 的软链文件。 > windows 下不会生成软链 为方便配置日志采集和查看,该软链文件永远指向最新的日志文件。 当凌晨 `00:00` 时,会生成一个以当天日志结尾 `midway-core.log.YYYY-MM-DD` 的形式的新文件。 同时,当单个日志文件超过 200M 时,也会自动切割,产生新的日志文件。 可以通过配置调整按大小的切割行为。 ``` export default { midwayLogger: { default: { maxSize: '100m', }, // ... }, } as MidwayConfig; ``` ## 配置日志清理[​](#配置日志清理 "配置日志清理的直接链接") 默认情况下,日志会存在 31 天。 可以通过配置调整该行为,比如改为保存 3 天。 ``` export default { midwayLogger: { default: { maxFiles: '3d', }, // ... }, } as MidwayConfig; ``` ## 高级配置[​](#高级配置 "高级配置的直接链接") 如果用户不满足于默认的日志对象,也可以自行创建和修改。 ### 增加自定义日志[​](#增加自定义日志 "增加自定义日志的直接链接") 可以如下配置: ``` export default { midwayLogger: { clients: { abcLogger: { fileLogName: 'abc.log' // ... } } // ... }, } as MidwayConfig; ``` 自定义的日志可以通过 `@Logger('abcLogger')` 获取。 更多的日志选项可以参考 interface 中 [LoggerOptions 描述](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ### 配置日志输出格式[​](#配置日志输出格式 "配置日志输出格式的直接链接") 显示格式指的是日志输出时单行文本的字符串结构。Midway 对 Winston 的日志做了定制,提供了一些默认对象。 每个 logger 对象,都可以配置一个输出格式,显示格式是一个返回字符串结构的方法,参数为 Winston 的 [info 对象](https://github.com/winstonjs/logform#info-objects)。 ``` export default { midwayLogger: { clients: { appLogger: { format: info => { return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.labelText}${info.message}`; } // ... }, customOtherLogger: { format: info => { return 'xxxx'; } } } // ... }, } as MidwayConfig; ``` info 对象的默认属性如下: | **属性名** | **描述** | **示例** | | ----------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | timestamp | 时间戳,默认为 `'YYYY-MM-DD HH:mm:ss,SSS` 格式。 | 2020-12-30 07:50:10,453 | | level | 小写的日志等级 | info | | LEVEL | 大写的日志等级 | INFO | | pid | 当前进程 pid | 3847 | | labelText | 标签的聚合文本 | \[abcde] | | message | 普通消息 + 错误消息 + 错误堆栈的组合 | 1、普通文本,如 `123456` , `hello world`
2、错误文本(错误名+堆栈)Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18)
3、普通文本+错误文本 hello world Error: another test error at Object.anonymous (/home/runner/work/midway/midway/packages/logger/test/index.test.ts:224:18) | | stack | 错误堆栈 | | | originError | 原始错误对象 | 错误实例本身 | | originArgs | 原始的用户入参 | \[ 'a', 'b', 'c' ] | ### 获取自定义上下文日志[​](#获取自定义上下文日志 "获取自定义上下文日志的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,他们的关系如下。 ``` // 伪代码 const contextLogger = customLogger.createContextLogger(ctx); ``` `@Inject` 只能注入默认的上下文日志,我们可以通过 `ctx.getLogger` 方法获取其他 **自定义日志** 对应的 **上下文日志**。上下文日志和 ctx 关联,同一个上下文会相同的 key 会获取到同一个日志对象,当 ctx 被销毁,日志对象也会被回收。 ``` import { Provide } from '@midwayjs/core'; import { IMidwayLogger } from '@midwayjs/logger'; import { Context } from '@midwayjs/koa'; @Provide() export class UserService { @Inject() ctx: Context; async getUser() { // 这里获取的是 customLogger 对应的上下文日志对象 const customLogger = this.ctx.getLogger('customLogger'); customLogger.info('hello world'); } } ``` ### 配置上下文日志输出格式[​](#配置上下文日志输出格式 "配置上下文日志输出格式的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,但是我们可以单独配置日志对象的对应的上下文日志格式。 上下文日志的 info 对象中多了 ctx 对象,我们以修改 `customLogger` 的上下文日志为例。 ``` export default { midwayLogger: { clients: { customLogger: { contextFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... } } // ... }, } as MidwayConfig; ``` 则你在使用上下文日志输出时,会默认变成你 format 的样子。 ``` ctx.getLogger('customLogger').info('hello world'); // 2021-01-28 11:10:19,334 INFO 9223 [2ms POST] hello world ``` 注意,由于 `App Logger` 是所有框架默认的日志对象,较为特殊,现有部分框架默认配置了其上下文格式,导致在 `midwayLogger` 字段中配置无效。 为此你需要单独修改某一框架的上下文日志格式配置,请跳转到不同的框架查看。 * [修改 koa 的上下文日志格式](/docs/extensions/koa.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 egg 的上下文日志格式](/docs/extensions/egg.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 express 的上下文日志格式](/docs/extensions/express.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) ### 日志默认 Transport[​](#日志默认-transport "日志默认 Transport的直接链接") 每个日志包含几个默认的 Transport。 | 名称 | 默认行为 | 描述 | | ----------------- | -------- | ------------------------------ | | Console Transport | 开启 | 用于输出到控制台 | | File Transport | 开启 | 用于输出到文本文件 | | Error Transport | 开启 | 用于将错误输出到特定的错误日志 | | JSON Transport | 关闭 | 用于输出 JSON 格式的文本 | 可以通过配置进行修改。 **示例:只开启控制台输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableFile: false, enableError: false, // ... } } // ... }, } as MidwayConfig; ``` **示例:关闭控制台输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableConsole: false, // ... } } // ... }, } as MidwayConfig; ``` **示例:开启文本和 JSON 同步输出,关闭错误输出** ``` export default { midwayLogger: { clients: { abcLogger: { enableConsole: false, enableFile: true, enableError: false, enableJSON: true, // ... } } // ... }, } as MidwayConfig; ``` ### 自定义 Transport[​](#自定义-transport "自定义 Transport的直接链接") 框架提供了扩展 Transport 的功能,比如,你可以写一个 Transport 来做日志的中转,上传到别的日志库等能力。 比如下面的示例,我们就将日志中转到另一个本地文件中。 ``` import { EmptyTransport } from '@midwayjs/logger'; class CustomTransport extends EmptyTransport { log(info, callback) { const levelLowerCase = info.level; if (levelLowerCase === 'error' || levelLowerCase === 'warn') { writeFileSync(join(logsDir, 'test.log'), info.message); } callback(); } } ``` 我们可以初始化,加到 logger 中,也可以单独对 Transport 设置 level。 ``` const customTransport = new CustomTransport({ level: 'warn', }); logger.add(customTransport); ``` 这样,原有的 logger 打印日志时,会自动执行该 Transport。 所有的 Transport 是附加在原有的 logger 实例之上(非 context logger),如需 ctx 数据,可以从 info 获取,注意判空。 ``` class CustomTransport extends EmptyTransport { log(info, callback) { if (info.ctx) { // ... } else { // ... } callback(); } } ``` 我们也可以使用依赖注入的方式来定义 Transport。 ``` import { EmptyTransport, IMidwayLogger } from '@midwayjs/logger'; import { MidwayLoggerService, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum) export class CustomTransport extends EmptyTransport { log(info, callback) { // ... callback(); } } // src/configuration.ts @Configuration(/*...*/) export class MainConfiguration { @Inject() loggerService: MidwayLoggerService; @Inject() customTransport: CustomTransport; async onReady() { const appLogger = this.loggerService.getLogger('customLogger') as IMidwayLogger; appLogger.add(this.customTransport); } } ``` ### 延迟初始化[​](#延迟初始化 "延迟初始化的直接链接") 可以使用 `lazyLoad` 配置让日志延迟初始化。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { level: 'DEBUG', }, customLoggerB: { lazyLoad: true, }, } // ... }, } as MidwayConfig; ``` `customLoggerA` 会在框架启动时立即初始化,而 `customLoggerB` 会在业务实际第一次使用 `getLogger` 或者 `@Logger` 注入时才被初始化。 这个功能非常适合动态化创建日志,但是配置却希望合并到一起的场景。 ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、服务器环境日志不输出[​](#1服务器环境日志不输出 "1、服务器环境日志不输出的直接链接") 服务器环境,默认日志等级为 warn,即 `logger.warn` 才会打印输出,请查看 ”日志等级“ 部分。 我们不推荐在服务器环境打印太多的日志,只打印必须的内容,过多的日志输出影响性能,也影响快速定位问题。 ### 2、服务器没有控制台日志[​](#2服务器没有控制台日志 "2、服务器没有控制台日志的直接链接") 一般来说,服务器控制台日志(console)是关闭的,只会输出到文件中,如有特殊需求,可以单独调整。 --- # 日志 Midway 为不同场景提供了一套统一的日志接入方式。通过 `@midwayjs/logger` 包导出的方法,可以方便的接入不同场景的日志系统。 实现的功能有: * 日志分级 * 按大小和时间自动切割 * 自定义输出格式 * 统一错误日志 提示 当前版本为 3.0 的日志 SDK 文档,如需 2.0 版本,请查看 [这个文档](/docs/logger.md)。 ## 从 2.0 升级到 3.0[​](#从-20-升级到-30 "从 2.0 升级到 3.0的直接链接") 从 midway v3.13.0 开始,支持使用 3.0 版本的 `@midwayjs/logger`。 将 `package.json` 中的依赖版本升级,注意是 `dependencies` 依赖。 ``` { "dependencies": { - "@midwayjs/logger": "2.0.0", + "@midwayjs/logger": "^3.0.0" } } ``` 如果在配置中没有了 midwayLogger 的类型提示,你需要在 `src/interface.ts` 中加入日志库的引用。 ``` // src/interface.ts + import type {} from '@midwayjs/logger'; ``` 在大部分场景下,两个版本是兼容的,但是由于是大版本升级,肯定会有一定的差异性,完整的 Breaking Change 变化,请查看 [变更文档](https://github.com/midwayjs/logger/blob/main/BREAKING-3.md)。 ## 日志路径和文件[​](#日志路径和文件 "日志路径和文件的直接链接") Midway 会在日志根目录创建一些默认的文件。 * `midway-core.log` 框架、组件打印信息的日志,对应 `coreLogger` 。 * `midway-app.log` 应用打印信息的日志,对应 `appLogger`,在 `@midawyjs/web` 中,该文件是 `midway-web.log` * `common-error.log` 所有错误的日志(所有 Midway 创建出来的日志,都会将错误重复打印一份到该文件中) 本地开发和服务器部署时的 **日志路径** 和 **日志等级** 不同,具体请参考 [配置日志根目录](#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95) 和 [框架的默认等级](#%E6%A1%86%E6%9E%B6%E7%9A%84%E9%BB%98%E8%AE%A4%E7%AD%89%E7%BA%A7)。 ## 默认日志对象[​](#默认日志对象 "默认日志对象的直接链接") Midway 默认在框架提供了三种不同的日志,对应三种不同的行为。 | 日志 | 释义 | 描述 | 常见使用 | | ----------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | | coreLogger | 框架,组件层面的日志 | 默认会输出控制台日志和文本日志 `midway-core.log` ,并且默认会将错误日志发送到 `common-error.log` 。 | 框架和组件的错误,一般会打印到其中。 | | appLogger | 业务层面的日志 | 默认会输出控制台日志和文本日志 `midway-app.log` ,并且默认会将错误日志发送到 `common-error.log` ,在 `@midawyjs/web` 中,该文件是 `midway-web.log`。 | 业务使用的日志,一般业务日志会打印到其中。 | | 上下文日志(复用 appLogger 的配置) | 请求链路的日志 | 默认使用 `appLogger` 进行输出,除了会将错误日志发送到 `common-error.log` 之外,还增加了上下文信息。 | 不同的协议有不同的请求日志格式,比如 HTTP 下就会输出路由信息。 | ## 使用日志[​](#使用日志 "使用日�志的直接链接") Midway 的常用日志使用方法。 ### 上下文日志[​](#上下文日志 "上下文日志的直接链接") 上下文日志是关联框架上下文对象(Context) 的日志。 我们可以通过 [获取到 ctx 对象](/docs/req_res_app.md) 后,使用 `ctx.logger` 对象进行日志打印输出。 比如: ``` ctx.logger.info("hello world"); ctx.logger.debug('debug info'); ctx.logger.warn('WARNNING!!!!'); // 错误日志记录,直接会将错误日志完整堆栈信息记录下来,并且输出到 errorLog 中 // 为了保证异常可追踪,必须保证所有抛出的异常都是 Error 类型,因为只有 Error 类型才会带上堆栈信息,定位到问题。 ctx.logger.error(new Error('custom error')); ``` 在执行后,我们能在两个地方看到日志输出: * 控制台看到输出。 * 日志目录的 midway-app.log 文件中 输出结果: ``` 2021-07-22 14:50:59,388 INFO 7739 [-/::ffff:127.0.0.1/-/0ms GET /api/get_user] hello world ``` 在注入的形式中,我们也可以直接使用 `@Inject() logger` 的形式来注入 `ctx.logger` ,和直接调用 `ctx.logger` 等价。 比如: ``` import { Get, Inject, Controller, Provide } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Controller() export class HelloController { @Inject() logger: ILogger; @Inject() ctx; @Get("/") async hello(){ // ... // this.logger === ctx.logger } } ``` ### 应用日志(App Logger)[​](#应用日志app-logger "应用日志(App Logger)的直接链接") 如果我们想做一些应用级别的日志记录,如记录启动阶段的一些数据信息,可以通过 App Logger 来完成。 ``` import { Configuration, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Configuration() export class MainConfiguration implements ILifeCycle { @Logger() logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` 注意,这里使用的是 `@Logger()` 装饰器。 ### CoreLogger[​](#corelogger "CoreLogger的直接链接") 在组件或者框架层面的研发中,我们会使用 coreLogger 来记录日志。 ``` @Configuration() export class MainConfiguration implements ILifeCycle { @Logger('coreLogger') logger: ILogger; async onReady(container: IMidwayContainer): Promise { this.logger.debug('debug info'); this.logger.info('启动耗时 %d ms', Date.now() - start); this.logger.warn('warning!'); this.logger.error(someErrorObj); } } ``` ## 输出方法和格式[​](#��输出方法和格式 "输出方法和格式的直接链接") Midway 的日志对象提供 `error()` , `warn()` , `info()` , `debug()`,`write()` 五种方法。 示例如下。 ``` logger.debug('debug info'); logger.info('启动耗时 %d ms', Date.now() - start); logger.warn('warning!'); logger.error(new Error('my error')); logger.write('abcdef'); ``` 提示 `write` 方法用于输出用户的原始格式日志。 基于 `util.format` 的格式化方式。 ``` logger.info('%s %d', 'aaa', 222); ``` 常用的有 * `%s` 字符串占位 * `%d` 数字占位 * `%j` json 占位 更多的占位和详细信息,请参考 node.js 的 [util.format](https://nodejs.org/dist/latest-v14.x/docs/api/util.html#util_util_format_format_args) 方法。 ## 日志类型定义[​](#日志类型定义 "日志类型定义的直接链接") 大部分情况下,用户应该使用 `@midwayjs/core` 中最简单的 `ILogger` 定义。 ``` import { Provide, Logger, ILogger } from '@midwayjs/core'; @Provide() export class UserService { @Inject() logger: ILogger; async getUser() { this.logger.info('hello user'); } } ``` `ILogger` 定义只提供最简单的 `debug` , `info` , `warn` 以及 `error` 方法。 在某些场景下,我们需要更为复杂的定义,这个时候需要使用 `@midwayjs/logger` 提供的 `ILogger` 定义。 ``` import { Provide, Logger } from '@midwayjs/core'; import { ILogger } from '@midwayjs/logger'; @Provide() export class UserService { @Inject() logger: ILogger; async getUser() { // ... } } ``` `ILogger` 的定义可以参考 interface 中的描述,或者查看 [代码](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ## 日志配置[​](#日志配置 "日志配置的直接链接") ### 基本配置结构[​](#基本配置结构 "基本配置结构的直接链接") 我们可以在配置文件中配置日志的各种行为。 Midway 中的的日志配置包含 **全局配置** 和 **单个日志配置** 两个部分,两者配置会合并和覆盖。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // ... }, clients: { coreLogger: { // ... }, appLogger: { // ... } } }, } as MidwayConfig; ``` 如上所述,`clients` 配置段中的每个对象都是一个独立的日志配置项,其配置会和 `default` 段落合并后创建 logger 实例。 ### 默认 Transport[​](#默认-transport "默认 Transport的直接链接") 在日志模块中,默认内置了 `console`,`file`,`error` ,`json` 四个 Transport,其中 Midway 默认启用了 `console`,`file`,`error` ,更多信息可以通过配置进行修改。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { console: { // console transport 配置 }, file: { // file transport 配置 }, error: { // error transport 配置 }, } }, // ... }, } as MidwayConfig; ``` 如果不需要某个 transport,可以设置为 `false`。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { console: false, } }, // ... }, } as MidwayConfig; ``` ### 配置日志等级[​](#配置日志等级 "配置日志等级的直接链接") 在 Midway 中,一般情况下,我们只会使用 `error` , `warn` , `info` , `debug` 这四种等级。 日志等级表示当前可输出日志的最低等级。比如当你的日志 level 设置为 `warn` 时,仅 `warn` 以及更高的 `error` 等级的日志能被输出。 在 Midway 中,有着自己的默认日志等级。 * 在开发环境下(local,test,unittest),文本和控制台日志等级统一为 `info` 。 * 在服务器环境,为减少日志数量,`coreLogger` 日志等级为 `warn` ,而其他日志为 `info`。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', }, // ... }, } as MidwayConfig; ``` logger 的 level 和 Transport 的 level 可以分开设置,Tranport 的 level 优先级高于 logger 的 level。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { // logger 的 level level: 'info', transports: { file: { // file transport 的 level level: 'warn' } } }, // ... }, } as MidwayConfig; ``` 我们也可以调整特定的 logger 的日志等级,比如: 调整 `coreLogger` 或者 `appLogger` 。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { clients: { coreLogger: { level: 'warn', // ... }, appLogger: { level: 'warn', // ... } } }, } as MidwayConfig; ``` 特殊场景,也可以临时调整全局的日志等级。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { level: 'info', transports: { console: { level: 'warn' } } }, // ... }, } as MidwayConfig; ``` ### 配置日志根目录[​](#配置日志根目录 "配置日志根目录的直接链接") 默认情况下,Midway 会在本地开发和服务器部署时输出日志到 **日志根目录**。 * 本地的日志根目录为 `${app.appDir}/logs/项目名` 目录下 * 服务器的日志根目录为用户目录 `${process.env.HOME}/logs/项目名` (Linux/Mac)以及 `${process.env.USERPROFILE}/logs/项目名` (Windows)下,例如 `/home/admin/logs/example-app`。 我们可以配置日志所在的根目录,注意,要将所有 Transport 的路径都修改。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { file: { dir: '/home/admin/logs', }, error: { dir: '/home/admin/logs', }, } }, // ... }, } as MidwayConfig; ``` ### 配置日志切割(轮转)[​](#配置日志切割轮转 "配置日志切割(轮转)的直接链接") 默认行为下,同一个日志对象 **会生成两个文件**。 以 `midway-core.log` 为例,应用启动时会生成一个带当日时间戳 `midway-core.YYYY-MM-DD` 格式的文件,以及一个不带时间戳的 `midway-core.log` 的软链文件。 > windows 下不会生成软链 为方便配置日志采集和查看,该软链文件永远指向最新的日志文件。 当凌晨 `00:00` 时,会生成一个以当天日志结尾 `midway-core.log.YYYY-MM-DD` 的形式的新文件。 同时,当单个日志文件超过 200M 时,也会自动切割,产生新的日志文件。 可以通过配置调整按大小的切割行为。 ``` export default { midwayLogger: { default: { transports: { file: { maxSize: '100m', }, error: { maxSize: '100m', }, } }, // ... }, } as MidwayConfig; ``` ### 配置日志清理[​](#配置日志清理 "配置日志清理的直接链接") 默认情况下,日志会存在 7 天。 可以通过配置调整该行为,比如改为保存 3 天。 ``` export default { midwayLogger: { default: { transports: { file: { maxFiles: '3d', }, error: { maxFiles: '3d', }, } }, // ... }, } as MidwayConfig; ``` 也可以配置数字,表示最多保留日志文件的个数。 ``` export default { midwayLogger: { default: { transports: { file: { maxFiles: '3', }, error: { maxFiles: '3d', }, } }, // ... }, } as MidwayConfig; ``` ### 配置自定义日志[​](#配置自定义日志 "配置自定义日志的直接链接") 可以如下配置: ``` export default { midwayLogger: { clients: { abcLogger: { fileLogName: 'abc.log' // ... } } // ... }, } as MidwayConfig; ``` 自定义的日志可以通过 `@Logger('abcLogger')` 获取。 更多的日志选项可以参考 interface 中 [LoggerOptions 描述](https://github.com/midwayjs/logger/blob/main/src/interface.ts)。 ### 配置日志输出格式[​](#配置日志输出格式 "配置日志输出格式的直接链接") 显示格式指的是日志输出时单行文本的字符串结构。 每个 logger 对象,都可以配置一个输出格式,显示格式是一个返回字符串结构的方法,参数为一个 info 对象。 ``` import { LoggerInfo } from '@midwayjs/logger'; export default { midwayLogger: { clients: { appLogger: { format: (info: LoggerInfo) => { return `${info.timestamp} ${info.LEVEL} ${info.pid} ${info.labelText}${info.message}`; } // ... }, customOtherLogger: { format: (info: LoggerInfo) => { return 'xxxx'; } } } // ... }, } as MidwayConfig; ``` info 对象的默认属性如下: | **属性名** | **描述** | **示例** | | ----------- | ------------------------------------------------ | ----------------------- | | timestamp | 时间戳,默认为 `'YYYY-MM-DD HH:mm:ss,SSS` 格式。 | 2020-12-30 07:50:10,453 | | level | 小写的日志等级 | info | | LEVEL | 大写的日志等级 | INFO | | pid | 当前进程 pid | 3847 | | message | util.format 的结果 | | | args | 原始的用户入参 | \[ 'a', 'b', 'c' ] | | ctx | 使用 ContextLogger 时关联的上下文对象 | | | originError | 原始错误对象,遍历参数后获取,性能较差 | 错误实例本身 | | originArgs | 同 args,仅做兼容老版本使用 | | ### 获取自定义上下文日志[​](#获取自定义上下文日志 "获取自定义上下文日志的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,他们的关系如下。 ``` // 伪代码 const contextLogger = customLogger.createContextLogger(ctx); ``` `@Inject` 只能注入默认的上下文日志,我们可以通过 `ctx.getLogger` 方法获取其他 **自定义日志** 对应的 **上下文日志**。上下文日志和 ctx 关联,同一个上下文会相同的 key 会获取到同一个日志对象,当 ctx 被销毁,日志对象也会被回收。 ``` import { Provide } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() export class UserService { @Inject() ctx: Context; async getUser() { // 这里获取的是 customLogger 对应的上下文日志对象 const customLogger = this.ctx.getLogger('customLogger'); customLogger.info('hello world'); } } ``` ### 配置上下文日志输出格式[​](#配置上下文日志输出格式 "配置上下文日志输出格式的直接链接") 上下文日志是基于 **原始日志对象** 来打日志的,会复用原始日志的所有格式,但是我们可以单独配置日志对象的对应的上下文日志格式。 上下文日志的 info 对象中多了 ctx 对象,我们以修改 `customLogger` 的上下文日志为例。 ``` export default { midwayLogger: { clients: { customLogger: { contextFormat: info => { const ctx = info.ctx; return `${info.timestamp} ${info.LEVEL} ${info.pid} [${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; } // ... } } // ... }, } as MidwayConfig; ``` 则你在使用上下文日志输出时,会默认变成你 format 的样子。 ``` ctx.getLogger('customLogger').info('hello world'); // 2021-01-28 11:10:19,334 INFO 9223 [2ms POST] hello world ``` 注意,由于 `App Logger` 是所有框架默认的日志对象,较为特殊,现有部分框架默认配置了其上下文格式,导致在 `midwayLogger` 字段中配置无效。 为此你需要单独修改某一框架的上下文日志格式配置,请跳转到不同的框架查看。 * [修改 koa 的上下文日志格式](/docs/extensions/koa.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 egg 的上下文日志格式](/docs/extensions/egg.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) * [修改 express 的上下文日志格式](/docs/extensions/express.md#%E4%BF%AE%E6%94%B9%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A5%E5%BF%97) ### 配置延迟初始化[​](#配置延迟初始化 "配置延迟初始化的直接链接") 可以使用 `lazyLoad` 配置让日志延迟初始化。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { // .. }, customLoggerB: { lazyLoad: true, }, } // ... }, } as MidwayConfig; ``` `customLoggerA` 会在框架启动时立即初始化,而 `customLoggerB` 会在业务实际第一次使用 `getLogger` 或者 `@Logger` 注入时才被初始化。 这个功能非常适合动态化创建日志,但是配置却希望合并到一起的场景。 ### 配置关联日志[​](#配置关联日志 "配置关联日志的直接链接") 日志对象可以配置一个关联的日志对象名。 比如: ``` export default { midwayLogger: { clients: { customLoggerA: { aliasName: 'customLoggerB', // ... }, } // ... }, } as MidwayConfig; ``` 当使用 API 获取时,不同的名字将取到同样的日志对象。 ``` app.getLogger('customLoggerA') => customLoggerA app.getLogger('customLoggerB') => customLoggerA ``` ### 配置控制台输出颜色[​](#配置控制台输出颜色 "配置控制台输出颜色的直接链接") 控制台输出时,在命令行支持颜色输出的情况下,针对不同的的日志等级会输出不同的颜色,如果不支持颜色,则不会显示。 你可以通过配置直接关闭颜色输出。 ``` export default { midwayLogger: { default: { transports: { console: { autoColors: false, } } } // ... }, } as MidwayConfig; ``` ### 配置 JSON 输出[​](#配置-json-输出 "配置 JSON 输出的直接链接") 通过开启 `json` Transport,可以将日志输出为 JSON 格式。 比如所有 logger 开启。 ``` export default { midwayLogger: { default: { transports: { file: false, json: { fileLogName: 'midway-app.json.log' } } } // ... }, } as MidwayConfig; ``` 或者单个 logger 开启。 ``` export default { midwayLogger: { default: { // ... }, clients: { appLogger: { transports: { json: { // ... } } } } }, } as MidwayConfig; ``` `json` Transport 的配置格式和 `file` 相同,输出略有不同。 比如我们可以修改 `format` 中输出的内容,默认情况下,输出至少会包含 `level` 和 `pid` 字段 ``` export default { midwayLogger: { default: { transports: { json: { format: (info: LoggerInfo & {data: string}) => { info.data = 'custom data'; return info; } } } } // ... }, } as MidwayConfig; ``` 输出为: ``` {"data":"custom data","level":"info","pid":89925} {"data":"custom data","level":"debug","pid":89925} ``` ## 自定义 Transport[​](#自定义-transport "自定义 Transport的直接链接") 框架提供了扩展 Transport 的功能,比如,你可以写一个 Transport 来做日志的中转,上传到别的日志库等能力。 ### 继承现有 Transport[​](#继承现有-transport "继承现有 Transport的直接链接") 如果是写入到新的文件,可以通过使用 `FileTransport` 来实现。 ``` import { FileTransport, isEnableLevel, LoggerLevel, LogMeta } from '@midwayjs/logger'; // Transport 的配置 interface CustomOptions { // ... } class CustomTransport extends FileTransport { log(level: LoggerLevel | false, meta: LogMeta, ...args) { // 判断 level 是否满足当前 Transport if (!isEnableLevel(level, this.options.level)) { return; } // 使用内置的格式化方法格式化消息 let buf = this.format(level, meta, args) as string; // 加上换行符 buf += this.options.eol; // 写入自己想写的日志 if (this.options.bufferWrite) { this.bufSize += buf.length; this.buf.push(buf); if (this.buf.length > this.options.bufferMaxLength) { this.flush(); } } else { // 没启用缓存,则直接写入 this.logStream.write(buf); } } } ``` 在使用前,需要注册到日志库中。 ``` import { TransportManager } from '@midwayjs/logger'; TransportManager.set('custom', CustomTransport); ``` 之后就可以在配置中使用这个 Transport 了。 ``` // src/config/config.default.ts import { MidwayConfig } from '@midwayjs/core'; export default { midwayLogger: { default: { transports: { custom: { dir: 'xxxx', fileLogName: 'xxx', // ... } } } }, } as MidwayConfig; ``` 这样,原有的 logger 打印日志时,会自动执行该 Transport。 ### 完全自定义 Transport[​](#完全自定义-transport "完全自定义 Transport的直接链接") 除了写入文件之外,也可以将日志投递到远端服务,比如下面的示例,将日志中转到另一个服务。 注意,Transport 是一个可异步执行的操作,但是 logger 本身不会等待 Transport 执行返回。 ``` import { Transport, ITransport, LoggerLevel, LogMeta } from '@midwayjs/logger'; // Transport 的配置 interface CustomOptions { // ... } class CustomTransport extends Transport implements ITransport { log(level: LoggerLevel | false, meta: LogMeta, ...args) { // 使用内置的格式化方法格式化消息 let msg = this.format(level, meta, args) as string; // 异步写入日志库 remoteSdk.send(msg).catch(err => { // 记录下错误或者忽略 console.error(err); }); } } ``` ## 动态 API[​](#动态-api "动态 API的直接链接") 通过 `getLogger` 方法动态获取日志对象。 ``` // 获取 coreLogger const coreLogger = app.getLogger('coreLogger'); // 获取默认的 contextLogger const contextLogger = ctx.getLogger(); // 获取特定 logger 创建出来的 contextLogger,等价于 customALogger.createContextLogger(ctx) const customAContextLogger = ctx.getLogger('customA'); ``` 框架内置的 `MidwayLoggerService` 也拥有上述的 API。 ``` import { MidwayLoggerService } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Provide() export class MainConfiguration { @Inject() loggerService: MidwayLoggerService; @Inject() ctx: Context; async getUser() { // get custom logger const customLogger = this.loggerService.getLogger('customLogger'); // 创建 context logger const customContextLogger = this.loggerService.createContextLogger(this.ctx, customLogger); } } ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### 1、服务器环境日志不输出[​](#1服务器环境日志不输出 "1、服务器环境日志不输出的直接链接") 我们不推荐在服务器环境打印太多的日志,只打印必须的内容,过多的日志输出影响性能,也影响快速定位问题。 如需调整日志等级,请查看 ”配置日志等级“ 部分。 ### 2、服务器没有控制台日志[​](#2服务器没有控制台日志 "2、服务器没有控制台日志的直接链接") 一般来说,服务器控制台日志(console)是关闭的,只会输出到文件中,如有特殊需求,可以单独调整。 ### 3、部分 Docker 环境启动失败[​](#3部分-docker-环境启动失败 "3、部分 Docker 环境启动失败的直接链接") 检查日志写入的目录当前应用启动的用户是否有权限。 ### 4、如果有老的配置如何转换[​](#4如果有老的配置如何转换 "4、如果有老的配置如何转换的直接链接") 新版本日志库已经兼容老配置,一般情况下无需额外处理,老配置和新配置在合并时有优先级关系,请查看 [变更文档](https://github.com/midwayjs/logger/blob/main/BREAKING-3.md)。 为了减少排查问题,在使用新版本日志库时请尽可能使用新配置格式。 --- # Web 中间件 Web 中间件是在控制器调用 **之前** 和 **之后(部分)** 调用的函数。 中间件函数可以访问请求和响应对象。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01h6hYvW1ogNexjJ3Nl_!!6000000005254-2-tps-2196-438.png) 不同的上层 Web 框架中间件形式不同,Midway 标准的中间件基于 [洋葱圈模型](https://eggjs.org/zh-cn/intro/egg-and-koa.html#midlleware)。而 Express 则是传统的队列模型。 Koa 和 EggJs 可以在 **控制器前后都被执行**,在 Express 中,中间件 **只能在控制器之前** 调用,将在 Express 章节单独介绍。 下面的代码,我们将以 `@midwayjs/koa` 举例。 ## 编写中间件[​](#编写中间件 "编写中间件的直接链接") 一般情况下,我们会在 `src/middleware` 文件夹中编写 Web 中间件。 创建一个 `src/middleware/report.middleware.ts` 。我们在这个 Web 中间件中打印了控制器(Controller)执行的时间。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.controller.ts │ │ └── home.controller.ts │ ├── interface.ts │ ├── middleware ## 中间件目录 │ │ └── report.middleware.ts │ └── service │ └── user.service.ts ├── test ├── package.json └── tsconfig.json ``` Midway 使用 `@Middleware` 装饰器标识中间件,完整的中间件示例代码如下。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // 控制器前执行的逻辑 const startTime = Date.now(); // 执行下一个 Web 中间件,最后执行到控制器 // 这里可以拿到下一个中间件或者控制器的返回值 const result = await next(); // 控制器之后执行的逻辑 console.log(Date.now() - startTime); // 返回给上一个中间件的结果 return result; }; } static getName(): string { return 'report'; } } ``` 简单来说, `await next()` 则代表了下一个要执行的逻辑,这里一般代表控制器执行,在执行的前后,我们可以进行一些打印和赋值操作,这也是洋葱圈模型最大的优势。 注意,Midway 对传统的洋葱模型做了一些微调,使得其可以获取到下一个中间件的返回值,同时,你也可以将这个中间件的结果,通过 `return` 方法返回给上一个中间件。 这里的静态 `getName` 方法,用来指定中间件的名字,方便排查问题。 ## 使用中间件[​](#使用中间件 "使用中间件的直接链接") Web 中间件在写完之后,需要应用到请求流程之中。 根据应用到的位置,分为两种: * 1、全局中间件,所有的路由都会执行的中间件,比如 cookie、session 等等 * 2、路由中间件,单个/部分路由会执行的中间件,比如某个路由的前置校验,数据处理等等 他们之间的关系一般为: ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01oQZ5Rk1jReqck6YMn_!!6000000004545-2-tps-2350-584.png) ### 路由中间件[​](#路由中间件 "路由中间件的直接链接") 在写完中间件之后,我们需要把它应用到各个控制器路由之上。 `@Controller` 装饰器的第二个参数,可以让我们方便的在某个路由分组之上添加中间件。 ``` import { Controller } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; @Controller('/', { middleware: [ ReportMiddleware ] }) export class HomeController { } ``` Midway 同时也在 `@Get` 、 `@Post` 等路由装饰器上都提供了 middleware 参数,方便对单个路由做中间件拦截。 ``` import { Controller, Get } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; @Controller('/') export class HomeController { @Get('/', { middleware: [ ReportMiddleware ]}) async home() { } } ``` ### 全局中间件[​](#全局中间件 "全局中间件的直接链接") 所谓的全局中间件,就是对所有的路由生效的 Web 中间件。 我们需要在应用启动前,加入当前框架的中间件列表中,`useMiddleware` 方法,可以把中间件加入到中间件列表中。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { this.app.useMiddleware(ReportMiddleware); } } ``` 你可以同时添加多个中间件。 ``` async onReady() { this.app.useMiddleware([ReportMiddleware1, ReportMiddleware2]); } ``` ## 忽略和匹配路由[​](#忽略和匹配路由 "忽略和匹配路由的直接链接") 在中间件执行时,我们可以添加路由忽略的逻辑。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... }; } ignore(ctx: Context): boolean { // 下面的路由将忽略此中间件 return ctx.path === '/' || ctx.path === '/api/auth' || ctx.path === '/api/login'; } static getName(): string { return 'report'; } } ``` 同理,也可以添加匹配的路由,只有匹配到的路由才会执行该中间件。`ignore` 和 `match` 同时只有一个会生效。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { // ... }; } match(ctx: Context): boolean { // 下面的匹配到的路由会执行此中间件 if (ctx.path === '/api/index') { return true; } } static getName(): string { return 'report'; } } ``` 除此之外,`match` 和 `ignore` 还可以是普通字符串或者正则,以及他们的数组形式。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { // 字符串 match = '/api/index'; // 正则 match = /^\/api/; // 数组 match = ['/api/index', '/api/user', /^\/openapi/, ctx => { if (ctx.path === '/api/index') { return true; } }]; } ``` 我们也可以在初始化阶段对属性进行修改,比如: ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { // 某个中间件的配置 @Config('report') reportConfig; @Init() async init() { // 动态合并一些规则 if (this.reportConfig.match) { this.match = ['/api/index', '/api/user'].concat(this.reportConfig.match); } else if (this.reportConfig.ignore) { this.match = [].concat(this.reportConfig.ignore); } } } ``` ## 复用中间件[​](#复用中间件 "复用中间件的直接链接") 中间件的本质是函数,函数可以传递不同的配置来复用中间件,但是在 class 场景下较难实现。Midway 提供了 `createMiddleware` 方法辅助 class 场景下创建不同的中间件函数。 可以在 `useMiddleware` 阶段使用 `createMiddleare` 复用。 ``` // src/configuration.ts import { App, Configuration, createMiddleare } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // 添加 ReportMiddleware 中间件 this.app.useMiddleware(ReportMiddleware); // 添加一个不同参数的 ReportMiddleware this.app.useMiddleware(createMiddleare(ReportMiddleware, { text: 'abc' }, 'anotherReportMiddleare')); } } ``` 我们可以在中间件中获取到这个参数,从而执行不同的逻辑,。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { initData = 'text1'; resolve(_, options?: { text: string; }) { return async (ctx: Context, next: NextFunction) => { this.ctx.setAttr('data', options?.text || this.initData); return await next(); }; } } ``` `createMiddleare` 方法定义如下,包含三个参数。 ``` function createMiddleware(middlewareClass: new (...args) => IMiddleware, options, name?: string); ``` | 参数 | 描述 | | --------------- | ---------------- | | middlewareClass | 中间件类 | | options | 传递的自定义参数 | | name | 可选,中间件名称 | `options` 可以传递中间件的自定义函数,在逻辑中可以自行进行处理。 `name` 字段用于中间件的排序和展示,一般会选择一个和原中间件名不同的字符串。 `createMiddleare` 方法还可以在路由中间件使用。 ``` import { Controller, Get, createMiddleware } from '@midwayjs/core'; import { ReportMiddleware } from '../middleware/report.middlweare'; const anotherMiddleware = createMiddleware(ReportMiddleware, { // ... }); @Controller('/') export class HomeController { @Get('/', { middleware: [anotherMiddleware], }) async home() {} } ``` 注意,装饰器会在框架启动前加载,这个时候 `createMiddleware` 的参数无法从框架配置中获取,一般为固定的对象值。 ## 函数中间件[​](#函数中间件 "函数中间件的直接链接") Midway 依旧支持函数中间件的形式,并且可以使用 `useMiddleware` 来加入到中间件列表。 ``` // src/middleware/another.middleware.ts export async function fnMiddleware(ctx, next) { // ... await next(); // ... } // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; import { fnMiddleware } from './middleware/another.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // add middleware this.app.useMiddleware([ReportMiddleware, fnMiddleware]); } } ``` 这样的话,社区很多 koa 三方中间件都可以比较方便的接入。 ## 使用社区中间件[​](#使用社区中间件 "使用社区中间件的直接链接") 我们以 `koa-static` 举例。 在 `koa-static` 文档中,是这样写的。 ``` const Koa = require('koa'); const app = new Koa(); app.use(require('koa-static')(root, opts)); ``` 那么, `require('koa-static')(root, opts)` 这个,其实就是返回的中间件方法,我们直接导出,并且调用 `useMiddleware` 即可。 ``` async onReady() { // add middleware this.app.useMiddleware(require('koa-static')(root, opts)); } ``` 如果中间件支持在路由上引入,比如: ``` const Koa = require('koa'); const app = new Koa(); app.get('/controller', require('koa-static')(root, opts)); ``` 我们也可以将中间件看成普通函数,放在装饰器参数中。 ``` const staticMiddleware = require('koa-static')(root, opts); // ... class HomeController { @Get('/controller', {middleware: [staticMiddleware]}) async getMethod() { // ... } } ``` 也可以作为作为路由方法体使用。 ``` const staticMiddleware = require('koa-static')(root, opts); // ... class HomeController { @Get('/controller') async getMethod(ctx, next) { // ... return staticMiddleware(ctx, next); } } ``` 提示 三方中间件写法有很多种,上面只是列出最基本的使用方式。 ## 获取中间件名[​](#获取中间件名 "获取中间件名的直接链接") 每个中间件应当有一个名字,默认情况下,类中间件的名字将依照下面的规则获取: * 1、当 `getName()` 静态方法存在时,以其返回值作为名字 * 2、如果不存在 `getName()` 静态方法,将使用类名作为中间件名 一个好认的中间件名在手动排序或者调试代码时有很大的作用。 ``` @Middleware() export class ReportMiddleware implements IMiddleware { // ... static getName(): string { return 'report'; // 中间件名 } } ``` 函数中间件也是类似,定义的方法名就是中间件的名字,比如下面的 `fnMiddleware` 。 ``` export async function fnMiddleware(ctx, next) { // ... await next(); // ... } ``` 假如三方中间件导出了一个匿名的中间件函数,那么你可以使用 `_name` 来添加一个名字。 ``` const fn = async (ctx, next) => { // ... await next(); // ... }; fn._name = 'fnMiddleware'; ``` 我们可以使用 `getMiddleware().getNames()` 来获取当前中间件列表中的所有中间件名。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; import { fnMiddleware } from './middleware/another.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // add middleware this.app.useMiddleware([ReportMiddleware, fnMiddleware]); // output console.log(this.app.getMiddleware().getNames()); // => report, fnMiddleware } } ``` ## 中间件顺序[​](#中间件顺序 "中间件顺序的直接链接") 有时候,我们需要在组件或者应用中修改中间件的顺序。 Midway 提供了 `insert` 系列的 API,方便用户快速调整中间件。 我们需要先使用 `getMiddleware()` 方法获取中间件列表,然后对其进行操作。 ``` // src/configuration.ts import { App, Configuration } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { ReportMiddleware } from './middleware/user.middleware'; @Configuration({ imports: [koa] // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // 把中间件添加到最前面 this.app.getMiddleware().insertFirst(ReportMiddleware); // 把中间件添加到最后面,等价于 useMiddleware this.app.getMiddleware().insertLast(ReportMiddleware); // 把中间件添加到名为 session 的中间件之后 this.app.getMiddleware().insertAfter(ReportMiddleware, 'session'); // 把中间件添加到名为 session 的中间件之前 this.app.getMiddleware().insertBefore(ReportMiddleware, 'session'); } } ``` ## 常见示例[​](#常见示例 "常见示例的直接链接") ### 中间件中获取请求作用域实例[​](#中间件中获取请求作用域实例 "中间件中获取请求作用域实例的直接链接") 由于 Web 中间件在生命周期的特殊性,会在应用请求前就被加载(绑定)到路由上,所以无法和请求关联。中间件类的作用域 **固定为单例(Singleton)**。 由于 **中间件实例为单例**,所以中间件中注入的实例和请求不绑定,**无法获取到 ctx**,无法使用 `@Inject()` 注入请求作用域的实例,只能获取 Singleton 的实例。 比如,**下面的代码是错误的。** ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { @Inject() userService; // 这里注入的实例和上下文不绑定,无法获取到 ctx resolve() { return async (ctx: Context, next: NextFunction) => { // TODO await next(); }; } } ``` 如果要获取请求作用域的实例,可以使用从请求作用域容器 `ctx.requestContext` 中获取,如下面的方法。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class ReportMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const userService = await ctx.requestContext.getAsync(UserService); // TODO userService.xxxx await next(); }; } } ``` ### 统一返回数据结构[​](#统一返回数据结构 "统一返回数据结构的直接链接") 比如在 `/api` 返回的所有数据都是用统一的结构,减少 Controller 中的重复代码。 我们可以增加一个类似下面的中间件代码。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class FormatMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const result = await next(); return { code: 0, msg: 'OK', data: result, } }; } match(ctx) { return ctx.path.indexOf('/api') !== -1; } } ``` 上面的仅是正确逻辑返回的代码,如需错误的返回包裹,可以使用 [过滤器](/docs/error_filter.md)。 ### 关于中间件返回 null 的情况[​](#关于中间件返回-null-的情况 "关于中间件返回 null 的情况的直接链接") 在 koa/egg 下,如果中间件中返回 null 值,会使得状态码变为 204,如果需要返回其他状态码(如 200),需要在中间件中显式额外赋值状态码。 ``` import { Middleware, IMiddleware } from '@midwayjs/core'; import { NextFunction, Context } from '@midwayjs/koa'; @Middleware() export class FormatMiddleware implements IMiddleware { resolve() { return async (ctx: Context, next: NextFunction) => { const result = await next(); if (result === null) { ctx.status = 200; } return { code: 0, msg: 'OK', data: result, } }; } match(ctx) { return ctx.path.indexOf('/api') !== -1; } } ``` --- # 使用组件 组件是 Midway 的扩展机制,我们会将复用的业务代码,或者逻辑,抽象的公共的能力开发成组件,使得这些代码能够在所有的 Midway 场景下复用。 ## 组件结构[​](#组件结构 "组件结构的直接链接") 普通项目本身也是一个组件,组件的入口文件一般是 `src/index.ts` 或者 `src/configuration.ts`。 其中会导出一个带有 `@Configuration` 装饰器的类。 比如: ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration {} ``` ## 启用组件[​](#启用组件 "启用组件的直接链接") 组件一般以 npm 包形式进行复用。每个组件都是一个可以被直接 `require` 或者 `import` 的代码包。我们以 `@midwayjs/validation` 组件为例。 首先,在应用中加入依赖。 ``` // package.json { "dependencies": { "@midwayjs/validation": "^4.0.0" } } ``` 我们需要在代码中启用这个组件,Midway 的组件加载能力设计在 `src/configuration.ts` 文件中。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as validation from '@midwayjs/validation'; @Configuration({ imports: [validation], }) export class MainConfiguration {} ``` ## 不同环境启用组件[​](#不同环境启用组件 "不同环境启用组件的直接链接") 有时候,我们需要在特殊环境下才使用组件,比如本地开发时。 `imports` 属性可以传入对象数组,我们可以在对象中针对组件启用的环境进行配置。 比如常用的 `info` 组件,为了安全考虑,我们就可以只让他在本地环境启用。 ``` // 应用或者函数的 src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as info from '@midwayjs/info'; @Configuration({ imports: [ { component: info, enabledEnvironment: ['local'], }, ], }) export class MainConfiguration {} ``` * `component` 用于指定组件对象,组件对象必须包含一个 `Configuration` 导出的属性 * `enabledEnvironment` 组件启用的环境数组 ## 开发组件[​](#开发组件 "开发组件的直接链接") 参见文档:[组件开发](/docs/component_development.md)。 --- # 关于 Midway 启动慢的问题 Midway 在本地开发时会使用 ts-node 实时扫描并 require 模块,如果 ts 文件太多(比如 200+)个,启动时可能会导致比较慢,在 Windows 下非 SSD 硬盘的情况下特别明显,导致 ts-node 的类型检查的 Server 频繁 fullGC,每个文件加载可能会达到 1-2s。 一般 Mac 都是 SSD,所以基本没有问题,而 Windows 会有出现,构建后执行无此问题。 如下图所示。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523014939-40121f9c-bc19-4f9e-a7e6-e744d409a9ea.png) ## 如何判断[​](#如何判断 "如何判断的直接链接") 1、先清理下 ts-node 缓存。 在临时目录中有一个 `ts-node-*` 的目录,删除即可(不知道临时目录的可以在命令行执行 `require('os').tmpdir()` 输出查看)。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523402032-7e9c162a-762e-4cba-82b4-8ae63fe37280.png) 删了下面类似的这个目录。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523340452-7924affe-96b5-4544-85b7-e41ace4206e8.png) 2、用 ts-node 启动 Midway 执行下面的启动命令。 ``` // midway v1 cross-env DEBUG=midway* NODE_ENV=local midway-bin dev --ts // midway v2 cross-env NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 会出现每个文件的 require 时长,如果时间比较久一般就是了。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1601523470970-1812326a-39d9-4b39-af57-7723f80f6e17.png) ## 解决问题[​](#解决问题 "解决问题的直接链接") 由于 `TS_NODE_TYPE_CHECK` 内部会启动一个 Server,在文件特别的多的情况下,每次 require 都会做类型检查,如果造成严重启动影响,建议关闭。**代价是启动运行时不会做类型校验,由于一般在编辑器里已经有提示,运行时不再做检查也可以。** 在执行命令前增加下面两个环境变量。 ``` TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true ``` 比如: ``` cross-env TS_NODE_TYPE_CHECK=false TS_NODE_TRANSPILE_ONLY=true NODE_DEBUG=midway* NODE_ENV=local midway-bin dev --ts ``` 下面是使用相同的项目的对比效果。 | | 第一次执行(无缓存) | 第二次执行(有缓存) | | ------------ | -------------------- | -------------------- | | 不加优化参数 | 约 258s | 约 5.6s | | 加优化参数 | 约 15s | 约 4.7s | | | | | ## 其他[​](#其他 "其他的直接链接") 如果任有问题,请提交你的仓库 + node\_modules 给我们。 --- # 数据模拟 Midway 提供了内置的在开发和测试时模拟数据的能力。 ## 测试时 Mock[​](#测试时-mock "测试时 Mock的直接链接") `@midwayjs/mock` 提供了一些更为通用的 API,用于在测试时进行模拟。 ### 模拟上下文[​](#模拟上下文 "模拟上下文的直接链接") 使用 `mockContext` 方法来模拟上下文。 ``` import { mockContext } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); // 模拟上下文 mockContext(app, 'user', 'midway'); const result1 = await createHttpRequest(app).get('/'); // ctx.user => midway // ... }); ``` 如果你的数据比较复杂,或者带有逻辑,也可以使用回调形式。 ``` import { mockContext } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); // 模拟上下文 mockContext(app, (ctx) => { ctx.user = 'midway'; }); }); ``` 注意,这个 mock 行为是在所有中间件之前执行。 ### 模拟 Session[​](#模拟-session "模拟 Session的直接链接") 使用 `mockSession` 方法来模拟 Session。 ``` import { mockSession } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); mockSession(app, 'user', 'midway'); const result1 = await createHttpRequest(app).get('/'); // ctx.session.user => midway // ... }); ``` ### 模拟 Header[​](#模拟-header "模拟 Header的直接链接") 使用 `mockHeader` 方法来模拟 Header。 ``` import { mockHeader } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const app = await createApp(); mockHeader(app, 'x-abc', 'bbb'); const result1 = await createHttpRequest(app).get('/'); // ctx.headers['x-abc'] => bbb // ... }); ``` ### 模拟类属性[​](#模拟类属性 "模拟类属性的直接链接") 使用 `mockClassProperty` 方法来模拟类的属性。 假如有下面的服务类。 ``` @Provide() export class UserService { data; async getUser() { return 'hello'; } } ``` 我们可以在使用时进行模拟。 ``` import { mockClassProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { mockClassProperty(UserService, 'data', { bbb: 1 }); // userService.data => {bbb: 1} // ... }); ``` 也可以模拟方法。 ``` import { mockClassProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { mockClassProperty(UserService, 'getUser', async () => { return 'midway'; }); // userService.getUser() => 'midway' // ... }); ``` ### 模拟普通对象属性[​](#模拟普通对象属性 "模拟普通对象属性的直接链接") 使用 `mockProperty` 方法来模拟对象的属性。 ``` import { mockProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const a = {}; mockProperty(a, 'name', 'hello'); // a['name'] => 'hello' // ... }); ``` 也可以模拟方法。 ``` import { mockProperty } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { const a = {}; mockProperty(a, 'getUser', async () => { return 'midway'; }); // a.getUser() => 'midway' // ... }); ``` ### 分组[​](#分组 "分组的直接链接") 从 `3.19.0` 开始,Midway 的 mock 功能支持通过分组来管理不同的 mock 数据。你可以在创建 mock 时指定一个分组名称,这样可以在需要时单独恢复或清理某个分组的 mock 数据。 ``` import { mockContext, restoreMocks } from '@midwayjs/mock'; it('should test mock with groups', async () => { const app = await createApp(); // 创建普通对象的 mock const a = {}; mockProperty(a, 'getUser', async () => { return 'midway'; }, 'group1'); // 创建上下文的 mock mockContext(app, 'user', 'midway', 'group1'); mockContext(app, 'role', 'admin', 'group2'); // 恢复单个分组 restoreMocks('group1'); // 恢复所有分组 restoreAllMocks(); }); ``` 通过分组,你可以更灵活地管理和控制 mock 数据,特别是在复杂的测试场景中。 ### 清理 mock[​](#清理-mock "清理 mock的直接链接") 在每次调用 `close` 方法时,会自动清理所有的 mock 数据。 如果希望手动清理,也可以执行方法 `restoreAllMocks` 。 ``` import { restoreAllMocks } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { restoreAllMocks(); // ... }); ``` 从 `3.19.0` 开始,支持指定 group 清理。 ``` import { restoreMocks } from '@midwayjs/mock'; it('should test create koa app with new mode with mock', async () => { restoreMocks('group1');(); // ... }); ``` ## 标准 Mock 服务[​](#标准-mock-服务 "标准 Mock 服务的直接链接") Midway 提供了标准的 MidwayMockService 服务,用于在代码中进行模拟数据。 `@midwayjs/mock` 中的各种模拟方法,底层皆调用了此服务。 具体 API 请参考 [内置服务](/docs/built_in_service.md#midwaymockservice) ## 开发期 Mock[​](#开发期-mock "开发期 Mock的直接链接") 每当后端服务没有上线,或者在开发阶段未准备好数据的时候,就需要用到开发期模拟的能力。 ### 编写模拟类[​](#编写模拟类 "编写模拟类的直接链接") 一般情况下,我们会在 `src/mock` 文件夹中编写开发期使用的模拟数据,我们的模拟行为实际是一段逻辑代码。 提示 不要对模拟数据放在代码中不习惯,事实上它是逻辑的一部分。 我们举个例子,假如现在有一个获取 Index 数据的服务,但是服务还未开发完毕,我们只能编写模拟代码。 ``` // src/service/indexData.service.ts import { Singleton, makeHttpRequest, Singleton } from '@midwayjs/core'; @Singleton() export class IndexDataService { @Config('index') indexConfig: {indexUrl: string}; private indexData; async load() { // 从远端获取数据 this.indexData = await this.fetchIndex(this.indexConfig.indexUrl); } public getData() { if (!this.indexData) { // 数据不存在,就加载一次 this.load(); } return this.indexData; } async fetchIndex(url) { return makeHttpRequest>(url, { method: 'GET', dataType: 'json', }); } } ``` 提示 上面的代码,故意抽离了 `fetchIndex` 方法,用来方便后续的模拟行为。 当接口未开发完毕的时候,我们本地开发就很困难,常见的做法是定义一份 JSON 数据, 比如,创建一个 `src/mock/indexData.mock.ts` ,用于初始化的服务接口模拟。 ``` // src/mock/indexData.mock.ts import { Mock, ISimulation } from '@midwayjs/core'; @Mock() export class IndexDataMock implements ISimulation { } ``` `@Mock` 用于代表它是一个模拟类,用于模拟一些业务行为,`ISimulation` 是需要业务实现的一些接口。 比如,我们要模拟接口的数据。 ``` // src/mock/indexData.mock.ts import { App, IMidwayApplication, Inject, Mock, ISimulation, MidwayMockService } from '@midwayjs/core'; import { IndexDataService } from '../service/indexData.service'; @Mock() export class IndexDataMock implements ISimulation { @App() app: IMidwayApplication; @Inject() mockService: MidwayMockService; async setup(): Promise { // 使用 MidwayMockService API 模拟属性 this.mockService.mockClassProperty(IndexDataService, 'fetchIndex', async (url) => { // 根据逻辑返回不同的数据 if (/current/.test(url)) { return { data: require('./resource/current.json'), }; } else if (/v7/.test(url)) { return { data: require('./resource/v7.json'), }; } else if (/v6/.test(url)) { return { data: require('./resource/v6.json'), }; } }); } enableCondition(): boolean | Promise { // 模拟类启用的条件 return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` 上面的代码中,`enableCondition` 是必须实现的方法,代表当前模拟类的启用条件,比如上面的代码仅在 `local` ,`test` 和 `unittest` 环境下生效。 ### 模拟时机[​](#模拟时机 "模拟时机的直接链接") 模拟类包含一些模拟的时机,都已经定义在 `ISimulation` 接口中,比如: ``` export interface ISimulation { /** * 最开始的模拟时机,在生命周期 onConfigLoad 之后执行 */ setup?(): Promise; /** * 在生命周期关闭时执行,一般用于数据清理 */ tearDown?(): Promise; /** * 在每种框架初始化时执行,会传递当前框架的 app */ appSetup?(app: IMidwayApplication): Promise; /** * 在每种框架的请求开始时执行,会传递当前框架的 app 和 ctx */ contextSetup?(ctx: IMidwayContext, app: IMidwayApplication): Promise; /** * 每种框架的请求结束时执行,在错误处理之后 */ contextTearDown?(ctx: IMidwayContext, app: IMidwayApplication): Promise; /** * 每种框架的停止时执行 */ appTearDown?(app: IMidwayApplication): Promise; /** * 模拟的执行条件,一般是特定环境,或者特定框架下 */ enableCondition(): boolean | Promise; } ``` 基于上面的接口,我们实现非常自由的模拟逻辑。 比如,在不同的框架上添加不同的中间件。 ``` import { App, IMidwayApplication, Mock, ISimulation } from '@midwayjs/core'; @Mock() export class InitDataMock implements ISimulation { @App() app: IMidwayApplication; async appSetup(app: IMidwayApplication): Promise { // 针对不同的框架类型,添加不同的测试中间件 if (app.getNamespace() === 'koa') { app.useMiddleware(/*...*/); app.useFilter(/*...*/); } if (app.getNamespace() === 'bull') { app.useMiddleware(/*...*/); app.useFilter(/*...*/); } } enableCondition(): boolean | Promise { return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` --- # 服务器启动失败排查 应用启动失败是非常常见的现象,逻辑错误,编译错误,配置错误,环境问题,都有可能导致你的项目无法启动。 ## 快速定位代码问题[​](#快速定位代码问题 "快速定位代码问题的直接链接") 大多数情况下,我们说的启动失败一般都是服务器环境启动失败,下面以 Linux 为例。 1、使用 `ps aux | grep node` 检查进程是否存在,进程数量是否正确 2、打开 [项目的日志目录](/docs/logger_v3.md#%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E6%A0%B9%E7%9B%AE%E5%BD%95),查看 `common-error.log` 文件的内容,根据最新的堆栈来排查原因 3、启动的控制台日志,比如 `pm2 logs` 相关的信息 大多数问题都会在日志中发现,请尽可能养成登录机器查看日志的习惯,这是开发者必备的技能。 ## 可能的环境问题[​](#可能的环境问题 "可能的环境问题的直接链接") 除了代码本身的问题之外,环境可能也会带来一些问题,这些问题查起来就比较困难,往往和系统,权限,环境变量,启动参数,网络环境,甚至内核本身有关系。 下面列举一些可能的情况。 ### 1、文件不完整或不是最新[​](#1文件不完整或不是最新 "1、文件不完整或不是最新的直接链接") 确保的你的项目在部署前执行过以下的流程 * 1、使用 `npm run dev` 或者类似命令本地启动并运行成功 * 2、使用 `npm run build` 已经将 ts 文件编译为 js 文件,在根目录生成出 `dist` 目录 * 3、使用 `npm run start` 在本地使用 js 文件执行成功 检查服务器上的文件,目录结构是否完整,比如: * 1、`node_modules` 目录是否存在 * 2、`dist` 目录以及其中的 js 文件是否存在,或者为最新 ### 2、启动用户的权限问题[​](#2启动用户的权限问题 "2、启动用户的权限问题的直接链接") 我们一般会使用一个普通账户来执行,比如 admin 账户,而不是使用 sudo 去部署。 * 1、检查用户是否用创建目录,启动 node 的权限 * 2、检查项目的服务端日志目录是否有写入的权限 ### 3、启动端口冲突[​](#3启动端口冲突 "3、启动端口冲突的直接链接") 如果你启动了多个 Node.js 项目,如果使用了相同的端口,那么就会抛出端口重复使用的错误。 --- # 管道 管道是参数装饰器的内部机制,可以在参数装饰器逻辑之后执行一些自定义代码,一般用于以下的场景: * 1、数据的校验 * 2、参数的转换 ## 组件提供的管道[​](#组件提供的管道 "组件提供的管道的直接链接") `@midwayjs/validate` 默认提供了验证管道,只需要启用组件即可使用。 例如: ``` @Controller('/api/user') export class HomeController { @Post('/') async updateUser(@Body() user: UserDTO ) { // ... } } ``` `@Body` 装饰器已经被自动注册了 `ValidatePipe` ,如果 `UserDTO` 是一个已经经过 `@Rule` 装饰器修饰的 DTO,会自动校验并转换。 如果使用了基础类型,则也可以通过数据转换管道进行校验和转换。 例如: ``` import { ParseIntPipe } from '@midwayjs/validate'; @Controller('/api/user') export class HomeController { @Post('/update_age') async updateAge(@Body('age', [ParseIntPipe]) age: number ) { // ... } } ``` `ParseIntPipe` 管道可以将字符串,数字数据转换为数字,这样从请求参数获取到的 `age` 字段则会通过管道的校验并转换为数字格式。 除此之外,还提供了 `ParseBoolPipe` ,`ParseFloatPipe` 等更多数据转换管道,具体请查看 [Validate 组件](/docs/extensions/validate.md)。 ## 自定义管道[​](#自定义管道 "自定义管道的直接链接") 管道可以是一个实现 `PipeTransform` 接口的类或者方法,我们一般将管道放在 `src/pipe` 目录。 比如: ``` // src/pipe/validate.pipe.ts import { Pipe, PipeTransform, TransformOptions } from '@midwayjs/core'; @Pipe() export class ValidatePipe implements PipeTransform { transform(value: T, options: TransformOptions): R { return value; } } ``` `PipeTransform` 是每个管道必须要实现的泛型接口。泛型 `T` 表明输入的 `value` 的类型,`R` 表明 `transfrom()` 方法的返回类型。 为实现 `PipeTransfrom`,每个管道必须声明 `transfrom()` 方法。该方法有两个参数: * `value` * `options` `value` 是当前处理的参数值,`options` 是当前处理的选项,包含以下属性。 ``` export TransformOptions { metaType: TSDesignType; metadata: Record; target: any; methodName: string; } ``` | 参数 | 描述 | | ---------- | ----------------------------------------------------------------------------------- | | metaType | 一个 ts 元数据类型的解析对象,包含 `name` 、`originDesign`、`isBaseType` 三个属性。 | | metadata | 参数装饰器的元数据对象 | | target | 当前装饰的实例本身 | | methodName | 当前参数装饰器装饰器的方法名 | ## 绑定管道[​](#绑定管道 "绑定管道的直接链接") 管道必须依附在参数装饰器上使用。 在自定义装饰器的选项中,我们可以透传管道参数达到应用管道的目的。 例如我们自定义一个 `RegValid` 参数装饰器,用于传入正则和另一个管道参数: ``` import { PipeUnionTransform, createCustomParamDecorator } from '@midwayjs/core'; function RegValid(reg: RegExp, pipe: PipeUnionTransform) { return createCustomParamDecorator('reg-valid', { reg, }, { // ... pipes: [pipe] }); } ``` `createCustomParamDecorator` 的第三个参数支持传入一个 `pipes` 属性,我们需要将管道传入其中,这样管道就会和装饰器绑定,在后续的运行中自动执行。 具体可以查询 [自定义装饰器](/docs/custom_decorator.md) 中的参数装饰器章节。 `RegValid` 装饰器用于正则的校验,实现部分我们暂时忽略。 另外,我们再定义一个管道用于截取数据。 ``` @Pipe() export class CutPipe implements PipeTransform { transform(value: number, options: TransformOptions): string { return String(value).slice(5); } } ``` 现在我们可以使用他们了。 ``` class UserService { async invoke(@RegValid(/\d{11}/, CutPipe) phoneNumber: string) { return phoneNumber; } } invoke(13712345678) => '345678' ``` ## 默认绑定的管道[​](#默认绑定的管道 "默认绑定的管道的直接链接") 假如我们希望向一个现成的参数装饰器能拥有管道能力,但是不希望该装饰器有管道参数。 就像内置的 `@Query` 等装饰器,没有管道参数,却可以在 validate 组件启用时自动执行管道逻辑。 我们使用 `decoratorService` 提供的反向注册 API,这在跨组件提供能力时非常有用。 我们以上面编写的 `RegValid` 为例。 ``` @Configuration({ // ... }) export class MainConfiguration { @Inject() decoratorService: MidwayDecoratorService; async onReady(container: IMidwayContainer) { // register default pipe this.decoratorService.registerParameterPipes('reg-valid', [ CutPipe, ]); } } ``` `registerParameterPipes` 方法用于向某一种参数装饰器隐式注册一些管道,上述实例中,`reg-valid` 是自定义参数的 key,通过 key 我们可以向这个参数装饰器注册。 这些管道会在显式传入的管道之前被默认执行。 这样在使用时,即使我们不传递管道参数,也依旧会执行管道。 ``` class UserService { async invoke(@RegValid(/\d{11}/) phoneNumber: string) { return phoneNumber; } } invoke(13712345678) => '345678' ``` --- # 流程控制 4.0 中,我们移除了该功能。 --- # 快速入门 如果你没有接触过 Midway,没关系,本章节我们将从实例的角度,一步步地搭建出一个 Midway 标准应用,展示天气信息,让你能快速的入门 Midway。 ## 环境准备[​](#环境准备 "环境准备的直接链接") * 操作系统:支持 macOS,Linux,Windows * 运行环境:[Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C) ## 初始化项目[​](#初始化项目 "初始化项目的直接链接") 我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目。 ``` $ npm init midway@latest -y ``` 选择 `koa-v4` 项目进行初始化创建,项目名可以自定,比如 `weather-sample`。如果你想创建函数式一体化项目,可以选择 `react-functional-v4` 或 `vue-functional-v4`。 现在可以启动应用来体验下。 ``` $ npm run dev $ open http://localhost:7001 ``` 如果你想体验函数式一体化开发,也可以在 `npm init midway@latest` 后选择 `react-functional-v4` 或 `vue-functional-v4`,方便对照学习。 ## 编写 Controller[​](#编写-controller "编写 Controller的直接链接") 如果你熟悉 Web 开发或 MVC,就知道第一步我们需要编写 [Controller 和 Router](/docs/controller.md)。 在脚手架创建的文件中,我们已经有了一些文件,我们暂时忽略他们。 在 `controller` 目录中,新建一个 `src/controller/weather.controller.ts` 文件,内容如下。 ``` import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class WeatherController { // 这里是装饰器,定义一个路由 @Get('/weather') async getWeatherInfo(): Promise { // 这里是 http 的返回,可以直接返回字符串,数字,JSON,Buffer 等 return 'Hello Weather!'; } } ``` 现在我们可以通过访问 `/weather` 接口返回数据了。 ## 添加参数处理[​](#添加参数处理 "添加参数处理的直接链接") 在示例中,我们需要一个 URL 参数来动态展示不同城市的天气。 通过添加 `@Query` 装饰器,我们可以获取到 URL 上的参数。 ``` import { Controller, Get, Query } from '@midwayjs/core'; @Controller('/') export class WeatherController { @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { return cityId; } } ``` 除了 `@Query` 装饰器,Midway 也提供了其他请求参数的获取,可以查看 [路由和控制](/docs/controller.md) 文档。 ## 编写 Service[​](#编写-service "编写 Service的直接链接") 在实际项目中,Controller 一般用来接收请求参数,校验参数,不会包括特别复杂的逻辑,复杂而复用的逻辑,我们应该封装为 Service 文件。 我们来添加一个 Service 用来获取天气信息,其中包括一个 http 请求,获取远端的数据。 代码如下: ``` // src/service/weather.service.ts import { Provide, makeHttpRequest } from '@midwayjs/core'; @Provide() export class WeatherService { async getWeather(cityId: string) { return makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); } } ``` 信息 * 1、`makeHttpRequest` 方法是 Midway 内置的 http 请求方法,更多参数请查看 [文档](/docs/extensions/axios.md) 然后我们来添加定义,良好的类型定义可以帮助我们减少代码错误。 在 `src/interface.ts` 文件中,我们增加天气信息的数据定义。 ``` // src/interface.ts // ... export interface WeatherInfo { weatherinfo: { city: string; cityid: string; temp: string; WD: string; WS: string; SD: string; AP: string; njd: string; WSE: string; time: string; sm: string; isRadar: string; Radar: string; } } ``` 这样,我们就可以在 Service 中进行标注了。 ``` import { Provide, makeHttpRequest } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; @Provide() export class WeatherService { async getWeather(cityId: string): Promise { const result = await makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); if (result.status === 200) { return result.data as WeatherInfo; } } } ``` 信息 * 1、这里使用 `@Provide` 装饰器修饰类,便于后续 Controller 注入该类 同时,我们修改下之前的 Controller 文件。 ``` import { Controller, Get, Inject, Query } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; import { WeatherService } from '../service/weather.service'; @Controller('/') export class WeatherController { @Inject() weatherService: WeatherService; @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { return this.weatherService.getWeather(cityId); } } ``` 信息 * 1、这里使用 `@Inject` 装饰器注入 `WeatherService`,是 Midway 依赖注入的标准用法,可以查看 [这里](/docs/service.md) 了解更多 * 2、这里也同步修改了方法的返回值类型 到这里,我们可以请求 `http://127.0.0.1:7001/weather?cityId=101010100` 查看返回的结果。 你的第一个 Midway 接口已经开发完成了,你可以在前端代码中直接调用了,接下去,我们将利用这个接口完成一个服务端渲染的页面。 ## 模板渲染[​](#模板渲染 "模板渲染的直接链接") 从这里开始,我们需要用到一些 Midway 的扩展能力。 Midway 对应的扩展包我们称为 “组件”,也是标准的 npm 包。 这里我们需要用到 `@midwayjs/view-nunjucks` 组件。 可以使用下面的命令安装。 ``` $ npm i @midwayjs/view-nunjucks --save ``` 安装完成后,我们在 `src/configuration.ts` 文件中启用组件。 ``` // ... import * as view from '@midwayjs/view-nunjucks'; @Configuration({ imports: [ koa, // ... view ], importConfigs: [join(__dirname, './config')], }) export class MainConfiguration { // ... } ``` 信息 * 1、`configuration` 文件是 Midway 的生命周期入口文件,承担了组件开关,配置加载和生命周期管理的作用 * 2、`imports` 就使用来导入(开启)组件的方法 在 `src/config/config.default.ts` 中配置组件,指定为 `nunjucks` 模板。 ``` import { MidwayConfig } from '@midwayjs/core'; export default { // ... view: { defaultViewEngine: 'nunjucks', }, } as MidwayConfig; ``` 在根目录(非 src 里)添加模板 `view/info.html` 文件,内容如下: ``` 天气预报

{{city}}({{WD}}{{WS}})

{{temp}}

气压

湿度

``` 同时,我们调整 Controller 的代码,将返回 JSON 变为模板渲染。 ``` // src/controller/weather.controller.ts import { Controller, Get, Inject, Query } from '@midwayjs/core'; import { WeatherService } from '../service/weather.service'; import { Context } from '@midwayjs/koa'; @Controller('/') export class WeatherController { @Inject() weatherService: WeatherService; @Inject() ctx: Context; @Get('/weather') async getWeatherInfo(@Query('cityId') cityId: string): Promise { const result = await this.weatherService.getWeather(cityId); if (result) { await this.ctx.render('info', result.weatherinfo); } } } ``` 到这一步,我们访问 `http://127.0.0.1:7001/weather?cityId=101010100` 已经可以看到渲染的模板内容了。 ## 错误处理[​](#错误处理 "错误处理的直接链接") 别忘了,我们还有一些异常的逻辑需要处理。 一般来说,每个对外的调用都需要做异常捕获,并且将异常转变为我们自己业务的错误,这样才能有更好的体验。 为此,我们需要定义一个我们自己的业务错误,创建一个 `src/error/weather.error.ts` 文件。 ``` // src/error/weather.error.ts import { MidwayError } from '@midwayjs/core'; export class WeatherEmptyDataError extends MidwayError { constructor(err?: Error) { super('weather data is empty', { cause: err, }); if (err?.stack) { this.stack = err.stack; } } } ``` 然后,我们调整 Service 代码抛出异常。 ``` // src/service/weather.service.ts import { Provide, makeHttpRequest } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; import { WeatherEmptyDataError } from '../error/weather.error'; @Provide() export class WeatherService { async getWeather(cityId: string): Promise { if (!cityId) { throw new WeatherEmptyDataError(); } try { const result = await makeHttpRequest(`https://midwayjs.org/resource/${cityId}.json`, { dataType: 'json', }); if (result.status === 200) { return result.data as WeatherInfo; } } catch (error) { throw new WeatherEmptyDataError(error); } } } ``` 信息 * 1、将 http 的调用请求进行错误捕获,将错误包裹,返回一个我们系统的业务错误 * 2、如有必要,我们可以定义更多的错误,分配错误 Code 等 到这一步,我们还需要将异常进行业务处理,比如有多个位置抛出 `WeatherEmptyDataError` 时,我们需要统一的格式返回。 错误处理器可以完成这个功能,我们需要创建一个 `src/filter/weather.filter.ts` 文件,内容如下: ``` //src/filter/weather.filter.ts import { Catch } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { WeatherEmptyDataError } from '../error/weather.error'; @Catch(WeatherEmptyDataError) export class WeatherErrorFilter { async catch(err: WeatherEmptyDataError, ctx: Context) { ctx.logger.error(err); return '

weather data is empty

'; } } ``` 然后应用到当前的框架中。 ``` import { Configuration, App } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import { WeatherErrorFilter } from './filter/weather.filter'; // ... @Configuration({ // ... }) export class MainConfiguration { @App() app: koa.Application; async onReady() { // ... // add filter this.app.useFilter([WeatherErrorFilter]); } } ``` 这样,当每次请求中获取到了 `WeatherEmptyDataError` 错误,会使用相同的返回值返回给浏览器,同时会在日志中记录原始的错误信息。 异常处理的更多信息,可以查阅 [文档](/docs/error_filter.md)。 ## 数据模拟[​](#数据模拟 "数据模拟的直接链接") 在编写代码时,我们的接口经常还处在无法使用的阶段,为了尽可能降低影响,可以使用模拟数据来代替。 比如我们的天气接口,就可以在本地和测试环境模拟掉。 我们需要创建一个 `src/mock/data.mock.ts` 文件,内容如下: ``` // src/mock/data.mock.ts import { Mock, ISimulation, App, Inject, IMidwayApplication, MidwayMockService, } from '@midwayjs/core'; import { WeatherService } from '../service/weather.service'; @Mock() export class WeatherDataMock implements ISimulation { @App() app: IMidwayApplication; @Inject() mockService: MidwayMockService; async setup(): Promise { const originMethod = WeatherService.prototype.getWeather; this.mockService.mockClassProperty( WeatherService, 'getWeather', async cityId => { if (cityId === '101010100') { return { weatherinfo: { city: '北京', cityid: '101010100', temp: '27.9', WD: '南风', WS: '小于3级', SD: '28%', AP: '1002hPa', njd: '暂无实况', WSE: '<3', time: '17:55', sm: '2.1', isRadar: '1', Radar: 'JC_RADAR_AZ9010_JB', }, }; } else { return originMethod.apply(this, [cityId]); } } ); } enableCondition(): boolean | Promise { // 模拟类启用的条件 return ['local', 'test', 'unittest'].includes(this.app.getEnv()); } } ``` `WeatherDataMock` 类用于模拟天气数据,其中的 `setup` 方法,用于实际的初始化模拟,其中,我们使用了内置的 `MidwayMockService` 的 `mockClassProperty` 方法,将 `WeatherService` 的 `getWeather` 方法模拟掉。 在模拟过程中,我们仅仅将单个城市的数据进行了处理,其他依旧走了原来的接口。 `enableCondition` 用于标识这个模拟类在哪些场景下生效,比如我们上面的代码就仅在本地和测试环境生效。 这样,当本地开发和测试时,我们请求 `101010100` 的数据,将直接被拦截和返回,且在部署到服务器环境后,也不会受到影响。 数据模拟还有更多的接口可以使用,可以查阅 [文档](/docs/mock.md)。 ## 单元测试[​](#单元测试 "单元测试的直接链接") Midway 默认使用 jest 作为基础的测试框架,一般我们的测试文件会放在根目录的 `test` 目录中,以 `*.test.ts` 作为后缀。 比如我们要测试编写的 `/weather` 接口。 我们需要测试它的成功和失败两种状态。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/koa'; describe('test/controller/weather.test.ts', () => { let app: Application; beforeAll(async () => { // create app app = await createApp(); }); afterAll(async () => { // close app await close(app); }); it('should test /weather with success request', async () => { // make request const result = await createHttpRequest(app).get('/weather').query({ cityId: 101010100 }); expect(result.status).toBe(200); expect(result.text).toMatch(/北京/); }); it('should test /weather with fail request', async () => { const result = await createHttpRequest(app).get('/weather'); expect(result.status).toBe(200); expect(result.text).toMatch(/weather data is empty/); }); }); ``` 执行测试: ``` $ npm run test ``` 就这么简单,更多请参见 [测试](/docs/testing.md)。 信息 * 1、jest 测试时,以单文件作为单位,使用 `beforeAll` 和 `afterAll` 控制 app 的启停 * 2、使用 `createHttpRequest` 来创建一个测试请求 * 3、使用 expect 来断言返回的结果是否符合预期 ## 继续学习[​](#继续学习 "继续学习的直接链接") 恭喜你,你对 Midway 已经有了一些初步的认识,我们来简单的回顾一下。 * 1、我们使用 `npm init midway` 来创建了示例 * 2、使用 `@Controller` 装饰器定义路由和控制器类 * 3、使用 `@Query` 获取请求参数 * 4、使用 `@Provide` 和 `@Inject` 注入服务类 * 5、使用 `imports` 启用组件,并配置了 nunjucks 模板 * 6、自定义了错误,并使用错误过滤器来拦截错误,返回自定义的数据 * 7、使用 jest 创建了测试,添加了成功和失败的测试用例 以上的这些,仅仅是 Midway 的一小部分内容,随着使用的深入,会使用到更多的能力。 你可以从 [创建](/docs/quickstart.md) 开始,去选择 Midway 不同场景下的解决方案,也可以继续深入 [路由和控制器](/docs/controller.md) 的部分,增加一些请求方法,也可以了解 [Web 中间件](/docs/middleware.md) 或者 [依赖注入](/docs/container.md) 相关的知识。 --- # 创建第一个应用 ## 技术选型[​](#技术选型 "技术选型的直接链接") Midway 有多套技术方案可以选择,我们以部署的方式来做区分: | 技术选型 | 描述 | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 纯 Node.js 项目 | Midway 传统项目,纯 Node.js 研发,以 `@midwayjs/koa` 为代表的模块,最完整的支持后端项目,采用 **依赖注入 + Class** 为技术栈。 | | Serverless 项目 | Midway 为 Serverless 场景单独开发的技术栈,以 `@midwayjs/faas` 为代表的模块,使用轻量的方式接入不同的 Serverless 平台。 | | 一体化项目 | Midway 创新技术方案,采用前后端一体化开发方式,节省前后端联调时间,以 `@midwayjs/core/functional`、`@midwayjs/web-bridge` 为代表,使用 **函数式** 为主要编码范式。 | 提示 本章节及后续的文档将以 **纯 Node.js 项目** 作为基础示例,如需使用 Serverless 项目,请跳转到 [Serverless](/docs/serverless/serverless_intro.md),如需了解一体化项目,请访问 [函数式](/docs/functional/intro.md)。 ## 快速初始化[​](#快速初始化 "快速初始化的直接链接") 使用 `npm init midway` 查看完整的脚手架列表,选中某个项目后,Midway 会自动创建示例目录,代码,以及安装依赖。 ``` $ npm init midway@latest -y ``` 针对 v4 项目,请选择 `koa-v4`,注意 [Node.js 环境要求](/docs/intro.md#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C)。 示例将创建一个类似下面的目录结构,其中最精简的 Midway 项目示例如下。 ``` ➜ my_midway_app tree . ├── src ## midway 项目源码 │ └── controller ## Web Controller 目录 │ └── home.controller.ts ├── test ├── package.json └── tsconfig.json ``` 整个项目包括了一些最基本的文件和目录。 * `src` 整个 Midway 项目的源码目录,你之后所有的开发源码都将存放于此 * `test` 项目的测试目录,之后所有的代码测试文件都在这里 * `package.json` Node.js 项目基础的包管理配置文件 * `tsconfig.json` TypeScript 编译配置文件 除了整个目录,我们还有一些其他的目录,比如 `controller` 目录。 ## 开发习惯[​](#开发习惯 "开发习惯的直接链接") Midway 对目录没有特别的限制,但是我们会遵守一些简单的开发习惯,将一部分常用的文件进行归类,放到一些默认的文件夹中。 以下 ts 源码文件夹均在 `src` 目录下。 常用的有: * `controller` Web Controller 目录 * `middleware` 中间件目录 * `filter` 过滤器目录 * `aspect` 拦截器 * `service` 服务逻辑目录 * `entity` 或 `model` 数据库实体目录 * `config` 业务的配置目录 * `util` 工具类存放的目录 * `decorator` 自定义装饰器目录 * `interface.ts` 业务的 ts 定义文件 随着不同场景的出现,目录的习惯也会不断的增加,具体的目录内容会体现在不同的组件功能中。 ## Web 框架选择[​](#web-框架选择 "Web 框架选择的直接链接") Midway 设计之初就可以兼容多种上层框架,比如常见的 `Express`、`Koa` 和 `EggJS` 。 从 v3 开始,我们使用 Koa 来做基础示例的演示。 这些上层框架在 Midway 中都以组件的能力提供,都可以使用 Midway 提供的装饰器能力,但是 Midway 不会对特有的能力做出封装,比如 Egg.js 的插件体系,或者 Express 的中间件能力,如果你对其中的某个框架比较熟悉,或者希望使用特定框架的能力,就可以选择它作为你的主力 Web 框架。 | 名称 | 描述 | | ----------------- | --------------------------------------------------------------------------------------------------------- | | @midwayjs/koa | 默认,Koa 是一个 Express 的替代框架,它默认支持了异步中间件等能力,是第二大通用的 Node.js Web 框架。 | | @midwayjs/web | Egg.js 是国内相对常用的 Web 框架,包含一些默认插件。 | | @midwayjs/express | Express 是一个众所周知的 node.js 简约 Web 框架。 这是一个经过实战考验,适用于生产的库,拥有大量社区资源。 | 如果你希望替代默认的 Web 框架,请参考对应的 [egg](/docs/extensions/egg.md) 或者 [express](/docs/extensions/express.md) 章节。 ## 启动项目[​](#启动项目 "启动项目的直接链接") ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 `http://127.0.0.1:7001` ,浏览器会打印出 `Hello midwayjs!` 的信息。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01KoUxO91jydMw41Vv4_!!6000000004617-2-tps-1268-768.png) 如果需要修改开发的启动端口,可以在 `package.json` 的 scripts 段落里修改,如修改为 6001: * 使用 mwtsc * 使用 @midwayjs/cli ``` "scripts": { //... "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js --port 6001", }, ``` ``` "scripts": { //... "dev": "cross-env NODE_ENV=local midway-bin dev --ts --port=6001", }, ``` ## 常见问题[​](#常见问题 "常见问题的直接链接") ### windows eslint 报错[​](#windows-eslint-报错 "windows eslint 报错的直接链接") 警告 Windows 可能会碰到 eslint 报错的问题,请关注 [windows 下换行问题](/docs/faq/git_problem.md#XCAgm)。 --- # Midway 维护计划 下表是 Midway 整体的维护节奏和计划。 | Release | Status | Initial Release | Active LTS Start | Maintenance LTS Start | End-of-life | | -------------------- | ------------------- | --------------- | ---------------- | --------------------- | ----------- | | midway v1(inner v6) | **End-of-Life** | 2018-06-14 | 2018-10 | 2020-04 | 2022-04 | | midway v2(inner v7) | **End-of-Life** | 2020-10 | 2021-02 | 2021-10 | 2024-04 | | midway v3(inner v8) | **Maintenance LTS** | 2022-01 | 2022-06 | 2023-10 | 2027-04 | | midway v4(inner v9) | **Active LTS** | 2026-02 | 2026-04 | | | --- # Application 和 Context Midway 的应用会同时对外暴露不同协议,比如 Http,WebSocket 等等,这里每个协议对 Midway 来说都是由独立的组件提供的。 比如我们前面示例中的 `@midwayjs/koa` ,就是一个提供 Http 服务的组件,下面我们将以这个组件为例,来介绍内置对象。 每个使用的 Web 框架会提供自己独特的能力,这些独特的能力都会体现在各自的 **上下文**(Context)和 **应用**(Application)之上。 ## 定义约定[​](#定义约定 "定义约定的直接链接") 为了简化使用,所有的暴露协议的组件会导出 **上下文**(Context)和 **应用**(Application)定义,我们都保持一致。即 `Context` 和 `Application` 。 比如: ``` import { Application, Context } from '@midwayjs/koa'; import { Application, Context } from '@midwayjs/faas'; import { Application, Context } from '@midwayjs/web'; import { Application, Context } from '@midwayjs/express'; ``` 且非 Web 框架,我们也保持了一致。 ``` import { Application, Context } from '@midwayjs/socketio'; import { Application, Context } from '@midwayjs/grpc'; import { Application, Context } from '@midwayjs/rabbitmq'; ``` ## Application[​](#application "Application的直接链接") Application 是某一个组件中的应用对象,在不同的组件中,可能有着不同的实现。Application 对象上会包含一些统一的方法,这些方法统一来自于 `IMidwayApplication` 定义。 ``` import { Application } from '@midwayjs/koa'; ``` ### 获取方式[​](#获取方式 "获取方式的直接链接") 在所有被依赖注入容器管理的类中,都可以使用 `@MainApp()` 装饰器来获取 **当前最主要** 的 Application,使用 `@App('koa')` 和参数来获取具名的 Application。 比如: ``` import { MainApp, App, Controller, Get } from '@midwayjs/core'; import { Application } from '@midwayjs/koa'; @Controller('/') export class HomeController { @MainApp() app: Application; @App('koa') koaApp: Application; @Get('/') async home() { // this.app.getConfig() // this.app.getEnv() } } ``` ### Main Application[​](#main-application "Main Application的直接链接") Midway 应用对外暴露的协议是组件带来的,每个组件都会暴露自己协议对应的 Application 对象。 这就意味着在一个应用中会包含多个 Application,我们默认约定,在 `src/configuration.ts` 中第一个引入的 Application 即为 **Main Application** (**主要的 Application**)。 比如,下面的 koa 中的 Application 实例即为 **Main Application** (**主要的 Application**)。 ``` // src/configuration.ts import { Configuration, ILifeCycle } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws] }) export class MainConfiguration implements ILifeCycle { // ... } ``` 事实上 Application 都实现与 `IMidwayApplication` 接口,如果使用通用的 API,没有差别。 成为 Main Application 稍微有一些优势: * 在大部分的场景下,使用 `@App()` 即可注入获取,无需其他参数 * 优先初始化 比如在多个导出 Application 组件需要加载中间件的情况下,可以简单的编码。 ``` // src/configuration.ts import { MainApp, App, Configuration, ILifeCycle } from '@midwayjs/core'; import * as koa from '@midwayjs/koa'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [koa, ws] }) export class MainConfiguration implements ILifeCycle { @MainApp() koaApp: koa.Application; @App('webSocket') wsApp: ws.Application; async onReady() { this.koaApp.useMiddleweare(...); this.wsApp.useMiddleweare(...); } } ``` 非主要的 Application,需要通过 `@App()` 装饰器的参数或者 [ApplicationManager](/docs/built_in_service.md#midwayapplicationmanager) 来获取。 `@App()` 装饰器的参数为组件的 `namespace`。 常见的 namespace 如下: | Package | Namespace | | ------------------ | --------- | | @midwayjs/web | egg | | @midwayjs/koa | koa | | @midwayjs/express | express | | @midwayjs/grpc | gRPC | | @midwayjs/ws | webSocket | | @midwayjs/socketio | socketIO | | @midwayjs/faas | faas | | @midwayjs/kafka | kafka | | @midwayjs/rabbitmq | rabbitMQ | | @midwayjs/bull | bull | | @midwayjs/cron | cron | ### getAppDir[​](#getappdir "getAppDir的直接链接") 用于获取项目根目录路径。 ``` this.app.getAppDir(); // => /my_project ``` ### getBaseDir[​](#getbasedir "getBaseDir的直接链接") 用于获取项目 TypeScript 基础路径,默认开发中为 `src` 目录,编译后为 `dist` 目录。 ``` this.app.getBaseDir(); // => /my_project/src ``` ### getEnv[​](#getenv "getEnv的直接链接") 获取当前项目环境。 ``` this.app.getEnv(); // => production ``` ### getApplicationContext[​](#getapplicationcontext "getApplicationContext的直�接链接") 获取当前全局依赖注入容器。 ``` this.app.getApplicationContext(); ``` ### getConfig[​](#getconfig "getConfig的直接链接") 获取配置。 ``` // 获取所有配置 this.app.getConfig(); // 获取特定 key 配置 this.app.getConfig('koa'); // 获取多级配置 this.app.getConfig('midwayLoggers.default.dir'); ``` ### getLogger[​](#getlogger "getLogger的直接链接") 获取某个 Logger,不传参数,默认返回 appLogger。 ``` this.app.getLogger(); // => app logger this.app.getLogger('custom'); // => custom logger ``` ### getCoreLogger[​](#getcorelogger "getCoreLogger的直接链接") 获取 Core Logger。 ``` this.app.getCoreLogger(); ``` ### getProjectName[​](#getprojectname "getProjectName的直接链接") 获取项目名,一般从 `package.json` 中获取。 ### setAttr & getAttr[​](#setattr--getattr "setAttr & getAttr的直接链接") 直接在 Application 上挂载一个对象会导致定义和维护的困难。 在大多数情况下,用户需要的是临时的全局数据存储的方式,比如在一个应用或者组件内部跨文件临时存取一个数据,从一个类保存,另一个类获取。 为此 Midway 提供了一个全局数据存取的 API,解决这类需求。 ``` this.app.setAttr('abc', { a: 1, b: 2, }); ``` 在另一个地方获取即可。 ``` const value = this.app.getAttr('abc'); console.log(value); // { a: 1, b: 2 } ``` ### getNamespace[​](#getnamespace "getNamespace的直接链接") 通过 `getNamespace` API ,可以获取到当前 app 归属的组件的 [框架的类型](#main-application)(即组件的 `namespace`)。 比如在 `koa` 组件中。 ``` this.app.getNamespace(); // 'koa' ``` ## Context[​](#context "Context的直接链接") Context 是一个**请求级别的对象**,在每一次收到用户请求时,框架会实例化一个 Context 对象, 在 Http 场景中,这个对象封装了这次用户请求的信息,或者其他获取请求参数,设置响应信息的方法,在 WebSocket,Rabbitmq 等场景中,Context 也有各自的属性,以框架的定义为准。 下面的 API 是每个上下文实现通用的属性或者接口。 ### 获取方式[​](#获取方式-1 "获取方式的直接链接") 在 **默认的请求作用域** 中,也就是说在 控制器(Controller)或者普通的服务(Service)中,我们可以使用 `@Inject` 来注入对应的实例。 比如可以这样获取到对应的 ctx 实例。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { // ... } } ``` 由于 `ctx` 是一个框架内置 ctx 实例关键字,如果你希望用不同的属性名,也可以通过修改装饰器参数。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject('ctx') customContextName: Context; @Get('/') async home() { // ... } } ``` 如果一个服务可以被多个上层框架调用,由于不同框架提供的 ctx 类型不同,可以通过类型组合来解决。 ``` import { Inject, Controller, Get } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; import { Context as BullContext } from '@midwayjs/bull'; @Provide() export class UserService { @Inject() ctx: Context & BullContext; async getUser() { // ... } } ``` 除了显式声明外,在拦截器或者装饰器设计的时候,由于我们无法得知用户是否写了 ctx 属性,还可以通过内置的 `REQUEST_OBJ_CTX_KEY` 字段来获取。 比如: ``` import { Inject, Controller, Get, REQUEST_OBJ_CTX_KEY } from '@midwayjs/core'; import { Context } from '@midwayjs/koa'; @Controller('/') export class HomeController { @Inject() ctx: Context; @Get('/') async home() { ctx.logger.info(this.ctx === this[REQUEST_OBJ_CTX_KEY]); // => true } } ``` ### requestContext[​](#requestcontext "requestContext的直接链接") Midway 会为每个 Context 挂载一个 `requestContext` 属性,即请求作用域下的依赖注入容器,用来创建请求作用域下的对象。 ``` const userService = await this.ctx.requestContext.getAsync(UserService); // ... ``` ### logger[​](#logger "logger的直接链接") 请求作用域下的默认 logger 对象,包含上下文数据。 ``` this.ctx.logger.info('xxxx'); ``` ### startTime[​](#starttime "startTime的直接链接") 上下文执行开始的时间。 ``` this.ctx.startTime // 1642820640502 ``` ### setAttr & getAttr[​](#setattr--getattr-1 "setAttr & getAttr的直接链接") 和 `app` 上的方法相同,这些方法的数据是保存在请求链路中,随着请求销毁,你可以在其中放一些请求的临时数据。 ``` this.ctx.setAttr('abc', { a: 1, b: 2, }); ``` 在另一个地方获取即可。 ``` const value = this.ctx.getAttr('abc'); console.log(value); // { a: 1, b: 2 } ``` ### getLogger[​](#getlogger-1 "getLogger的直接链接") 获取某个自定义 Logger 对应的上下文日志。 ``` this.ctx.getLogger('custom'); // => custom logger ``` ### getApp[​](#getapp "getApp的直接链接") 从 ctx 上获取当前框架类型的 app 对象。 ``` const app = this.ctx.getApp(); // app.getConfig(); ``` --- # 重试机制 从 Midway v3.5.0 开始,支持方法自定义重试逻辑。 很多时候,我们在某些容易失败,或者异步的方法调用上,需要多次使用 `try` 去包裹函数,同时处理错误。 比如: ``` // 定义了一个异步函数 async function invoke(id) { // 一些远程调用逻辑 } async invokeNew() { let error; try { return await invoke(1); } catch(err) { error = err; } try { return await invoke(2); } catch(err) { error = err; } if (error) { // .... } } ``` 我们可能会尝试多次调用 `invoke`执行,同时配合 try/catch 的异常捕获,导致业务代码写起来重复且冗长。 ## 定义重试函数[​](#定义重试函数 "定义重试函数的直接链接") 我们可以使用 `retryWithAsync`方法进行包裹,简化整个流程。 ``` import { retryWithAsync } from '@midwayjs/core'; async function invoke(id) { // ... } async function someServiceMethod() { // 默认调用,加上重试两次,最多执行三次 const invokeNew = retryWithAsync(invoke, 2); try { return await invokeNew(1); } catch(err) { // err } } ``` 包裹后的方法参数和返回值,和原有方法完全一致。 当在重试周期内调用成功,未抛出错误,则会将成功的返回值返回。 如果失败,则会抛出 `MidwayRetryExceededMaxTimesError` 异常。 如果在类中使用,可能要注意 `this` 的指向。 示例如下: ``` import { retryWithAsync } from '@midwayjs/core'; export class UserService { async getUserData(userId: string) { // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote, 2, { receiver: this, } ); // invoke return getUserDataOrigin(userId); } async getUserDataFromRemote(userId: string) { // get data from remote } } ``` ## this 绑定[​](#this-绑定 "this 绑定的直接链接") 从 Midway v3.5.1 起,增加了一个 `receiver` 参数,用于在类的场景下绑定 this,用于处理: * 1、方法正确的 this 指向 * 2、包裹方法定义的正确性 ``` // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote, 2, { receiver: this, // 此参数用于处理 this 指向 } ); ``` 如果没有该参数,代码需要写成下面的样子才能绑定 this,同时返回的 `getUserDataOrigin` 方法的定义才正确。 ``` // wrap const getUserDataOrigin = retryWithAsync( this.getUserDataFromRemote.bind(this) as typeof this.getUserDataFromRemote, 2, { receiver: this, } ); ``` ## 重试次数[​](#重试次数 "重试次数的直接链接") `retryWithAsync` 提供了第二个参数,用于声明额外的重试次数,默认为 1(仅重试一次)。 这个值指代的是在默认调用后,额外重试的次数。 ## 同步的重试[​](#同步的重试 "同步的重试的直接链接") 和 `retryWithAsync` 类似,我们也提供了 `retryWith` 这个同步方法,参数和 `retryWithAsync` 几乎相同,不再额外描述。 ## 重试延迟[​](#重试延迟 "重试延迟的直接链接") 为了避免频繁重试对服务端造成压力,可以设置重试的间隔。 比如: ``` const invokeNew = retryWithAsync(invoke, 2, { retryInterval: 2000, // 执行失败后,2s 后继续重试 }); ``` 提示 同步方法 `retryWith` 没有该属性。 ## 抛出的错误[​](#抛出的错误 "抛出的错误的直接链接") 默认情况下,如果超过重试次数,则会抛出 `MidwayRetryExceededMaxTimesError` 异常。 `MidwayRetryExceededMaxTimesError` 是框架默认的异常,可以进行错误过滤器的捕获梳理,或者从其属性中拿到原始的异常进行处理。 ``` import { retryWithAsync, MidwayRetryExceededMaxTimesError } from '@midwayjs/core'; async function invoke(id) { // ... } async function someServiceMethod() { // 默认调用,加上重试两次,最多执行三次 const invokeNew = retryWithAsync(invoke, 2); try { return await invokeNew(1); } catch(err) { // err.name === 'MidwayRetryExceededMaxTimesError' // err.cause instanceof CustomError => true } } async invokeNew() { throw new CustomError('customError'); } ``` 如果希望直接抛出原始的 error 对象,可以通过配置参数。 比如: ``` const invokeNew = retryWithAsync(invoke, 2, { throwOriginError: true, }); ``` --- # Web 路由表 从 v2.8.0 开始,Midway 提供了内置的路由表能力,所有的 Web 框架都将使用这份路由表注册路由。 从 v3.4.0 开始,路由服务将作为 Midway 内置服务提供。 在应用启动,onReady 生命周期以及之后可用。 ## 获取路由表服务[​](#获取路由表服务 "获取路由表服务的直接链接") 已默认实例化,可以直接注入使用。 ``` import { Configuration, Inject, MidwayWebRouterService, MidwayServerlessFunctionService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { // Web 路由 const routes = await this.webRouterService.getFlattenRouterTable(); // serverless 函数 const routes = await this.serverlessFunctionService.getFunctionList(); } } ``` `MidwayServerlessFunctionService` 仅在 Serverless 场景下生效,方法和 `MidwayWebRouterService` 几乎相同。 ## 路由信息定义[​](#路由信息定义 "路由信息定义的直接链接") 每个路由信息由一个 `RouterInfo` 定义表示,包含一些属性。 定义如下: ``` export interface RouterInfo { /** * router prefix */ prefix: string; /** * router alias name */ routerName: string; /** * router path, without prefix */ url: string | RegExp; /** * request method for http, like get/post/delete */ requestMethod: string; /** * invoke function method */ method: string; description: string; summary: string; /** * router handler function key,for IoC container load */ handlerName: string; /** * serverless func load key */ funcHandlerName: string; /** * controller provideId */ controllerId: string; /** * router middleware */ middleware: any[]; /** * controller middleware in this router */ controllerMiddleware: any[]; /** * request args metadata */ requestMetadata: any[]; /** * response data metadata */ responseMetadata: any[]; } ``` | 属性 | 类型 | 描述 | | -------------------- | --------- | --------------------------------------------------------------- | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | routerName | string | 路由名 | | url | string | 路由的去除路由前缀的部分,也是用户写在 @Get 等装饰器上的部分 | | requestMethod | string | get/post/delete/put/all 等 | | method | string | 实际调用的类上的方法名 | | description | string | 描述,路由装饰器上的参数 | | summary | string | 摘要,路由装饰器上的参数 | | handlerName | string | 等价于 controllerId.method | | funcHandlerName | string | 使用 @Func 写的 handler 名字 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | middleware | string\[] | 路由中间件字符串数组 | | controllerMiddleware | string\[] | 控制器中间件字符串数组 | | requestMetadata | any\[] | 请求参数的元数据,@Query/@Body 等元数据 | | responseMetadata | any\[] | 响应参数的元数据,@SetHeader/@ContentType 等元数据 | ## 路由优先级[​](#路由优先级 "路由优先级的直接链接") 以往我们需要关心路由的加载顺序,比如通配的 `/*` 比如在实际的 `/abc` 之后,否则会加载到错误的路由。在新版本中,我们对此种情况做了自动排序。 规则如下: * 1. 绝对路径规则优先级最高如 `/ab/cb/e` * 2. 星号只能出现最后且必须在/后面,如 `/ab/cb/**` * 3. 如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高 * 4. 有多个通配能匹配一个路径时,最长的规则匹配,如 `/ab/**` 和 `/ab/cd/**` 在匹配 `/ab/cd/f` 时命中 `/ab/cd/**` * 5. 如果 `/` 与 `/*` 都能匹配 / ,但 `/` 的优先级高于 `/*` 此规则也与 Serverless 下函数的路由规则保持一致。 简单理解为,“明确的路由优先级最高,长的路由优先级高,通配的优先级最低”。 比如,排序完的优先级如下(高到低): ``` /api/invoke/abc /api/invoke/* /api/abc /api/* /abc /* ``` ## 当前匹配的路由[​](#当前匹配的路由 "当前匹配的路由的直接链接") 通过 `getMatchedRouterInfo` 方法,我们可以知道当前的路由,匹配到哪个路由信息(RouterInfo),从而进一步处理,这个逻辑在鉴权等场景很有用。 比如,在中间件中,我们可以在进入控制器之前提前判断。 ``` import { Middleware, Inject, httpError, MidwayWebRouterService } from '@midwayjs/core'; @Middleware() export class AuthMiddleware { @Inject() webRouterService: MidwayWebRouterService; resolve() { return async (ctx, next) => { // 查询当前路由是否在路由表中注册 const routeInfo = await this.webRouterService.getMatchedRouterInfo(ctx.path, ctx.method); if (routeInfo) { await next(); } else { throw new httpError.NotFoundError(); } } } } ``` ## 路由信息[​](#路由信息 "路由信息的直接链接") ### 获取扁平化路由列表[​](#获取扁平化路由列表 "获取扁平化路由列表的直接链接") 获取当前所有可注册到 HTTP 服务的路由列表(包括 @Func/@Controller,以及一切按照标准信息注册的自定义装饰器)。 会按照优先级从高到低自动排序。 定义: ``` async getFlattenRouterTable(): Promise ``` 获取路由表 API。 ``` const result = await this.webRouterService.getFlattenRouterTable(); ``` 输出示例: ``` [ { "prefix": "/", "routerName": "", "url": "/set_header", "requestMethod": "get", "method": "homeSet", "description": "", "summary": "", "handlerName": "apiController.homeSet", "funcHandlerName": "apiController.homeSet", "controllerId": "apiController", "middleware": [], "controllerMiddleware": [], "requestMetadata": [], "responseMetadata": [ { "type": "web:response_header", "setHeaders": { "ccc": "ddd" } }, { "type": "web:response_header", "setHeaders": { "bbb": "aaa" } } ], }, { "prefix": "/", "routerName": "", "url": "/ctx-body", "requestMethod": "get", "method": "getCtxBody", "description": "", "summary": "", "handlerName": "apiController.getCtxBody", "funcHandlerName": "apiController.getCtxBody", "controllerId": "apiController", "middleware": [], "controllerMiddleware": [], "requestMetadata": [], "responseMetadata": [], }, // ... ] ``` ### 获取 Router 信息列表[​](#获取-router-信息列表 "获取 Router 信息列表的直接链接") 在 Midway 中,每个 Controller 对应一个 Router 对象,每个 Router 都会有一个路由前缀(prefix),在此之中的所有路由都会按照上面的规则进行排序。 Router 本身也会按照 prefix 进行排序。 定义: ``` export interface RouterPriority { prefix: string; priority: number; middleware: any[]; routerOptions: any; controllerId: string; } async getRoutePriorityList(): Promise ``` Router 的数据相对简单。 | 属性 | 类型 | 描述 | | ------------- | --------- | ------------------------------------------------------------------------------ | | prefix | string | 路由前缀,比如 / 或者 /api,用户写在 @Controller 装饰器上的部分 | | priority | number | Router 的优先级,@Priority 装饰器填写的值,/ 根 Router 默认优先级最低,为 -999 | | middleware | string\[] | 控制器中间件字符串数组 | | controllerId | string | controller 的依赖注入容器的 key(providerId) | | routerOptions | any | @Controller 装饰器的 options | 获取路由表 API。 ``` const list = await collector.getRoutePriorityList(); ``` 输出示例: ``` [ { "prefix": "/case", "priority": 0, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "caseController" }, { "prefix": "/user", "priority": 0, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "userController" }, { "prefix": "/", "priority": -999, "middleware": [], "routerOptions": { "middleware": [], "sensitive": true }, "controllerId": "apiController" } ] ``` ### 获取带层级的路由[​](#获取带层级的路由 "获取带层级的路由的直接链接") 某些情况下,我们需要拿到带层级的路由,包括哪些路由在哪个控制器(Controller)下,这样能更好的创建路由。 Midway 也提供了获取带层级的路由表方法。层级内会按照优先级从高到低自动排序。 定义: ``` async getRouterTable(): Promise> ``` 获取层级路由表 API,返回的是个 Map,key 为控制器的路由前缀 prefix 字符串。未明确写明路由前缀的(比如函数或者其他场景),都将归为 / 路由前缀下。 ``` const result = await collector.getRouterTable(); ``` 输出示例: ``` Map(3) { '/' => [ { prefix: '/', routerName: '', url: '/set_header', requestMethod: 'get', method: 'homeSet', description: '', summary: '', handlerName: 'apiController.homeSet', funcHandlerName: 'apiController.homeSet', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [Array], }, { prefix: '/', routerName: '', url: '/ctx-body', requestMethod: 'get', method: 'getCtxBody', description: '', summary: '', handlerName: 'apiController.getCtxBody', funcHandlerName: 'apiController.getCtxBody', controllerId: 'apiController', middleware: [], controllerMiddleware: [], requestMetadata: [], responseMetadata: [], }, // ... ] } ``` ### 获取所有函数信息[​](#获取所有函数信息 "获取所有函数信息的直接链接") 和 `getFlattenRouterTable` 相同,只是返回的内容多了函数部分的信息。 定义: ``` async getFunctionList(): Promise ``` 获取函数路由表 API。 ``` const result = await this.serverlessFunctionService.getFunctionList(); ``` ## 添加路由[​](#添加路由 "添加路由的直接链接") ### 动态添加 Web 控制器[​](#动态添加-web-控制器 "动态添加 Web 控制器的直接链接") 有些时候我们希望根据某些条件动态的添加一个控制器,就可以使用这个方法。 首先,我们需要有一个控制器类,但是不使用 `@Controller` 装饰器修饰。 ``` import { Get, Provide } from '@midwayjs/core'; // 注意这里未使用 @Controller 修饰 @Provide() export class DataController { @Get('/query_data') async getData() { return 'hello world'; } } ``` 我们可以通过 `addController` 方法动态添加它。 ``` // src/configuration.ts import { Configuration, Inject, MidwayWebRouterService } from '@midwayjs/core'; import { DataController } from './controller/data.controller'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { if (process.env.NODE_ENV === 'test') { this.webRouterService.addController(DataController, { prefix: '/test', routerOptions: { middleware: [ // ... ] } }); } // ... } } ``` `addController` 的方法,第一个参数为类本身,第二个参数和 `@Controller` 装饰器参数相同。 ### 动态添加 Web 路由函数[​](#动态添加-web-路由函数 "动态添加 Web 路由函数的直接链接") 在某些场景下,用户可以直接动态添加方法。 ``` // src/configuration.ts import { Configuration, Inject, MidwayWebRouterService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() webRouterService: MidwayWebRouterService; async onReady() { // koa/egg 格式 this.webRouterService.addRouter(async (ctx) => { return 'hello world'; }, { url: '/api/user', requestMethod: 'GET', }); // ... // express 格式 this.webRouterService.addRouter(async (req, res) => { return 'hello world'; }, { url: '/api/user', requestMethod: 'GET', }); } } ``` `addRouter` 的方法,第一个参数为路由方法体,第二个参数为路由的元数据。 ### 动态添加 Serverless 函数[​](#动态添加-serverless-函数 "动态添加 Serverless 函数的直接链接") 和添加动态 Web 路由类似,使用内置的 `MidwayServerlessFunctionService` 服务来添加。 比如,添加一个 http 函数。 ``` // src/configuration.ts import { Configuration, Inject, MidwayServerlessFunctionService } from '@midwayjs/core'; @Configuration({ // ... }) export class MainConfiguration { @Inject() serverlessFunctionService: MidwayServerlessFunctionService; async onReady() { this.serverlessFunctionService.addServerlessFunction(async (ctx, event) => { return 'hello world'; }, { type: ServerlessTriggerType.HTTP, metadata: { method: 'get', path: '/api/hello' }, functionName: 'hello', handlerName: 'index.hello', }); } } ``` `metadata` 的信息和 @ServerlessTrigger 的参数相同。 --- # 部署到阿里云函数计算 阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。 阿里云 Serverless 包含许多产品,如函数计算 FC,轻量应用引擎 SAE 等,本文主要使用了其 **函数计算** 部分。 下面是常见的函数触发器的使用、测试和部署方法。 ## 部署类型[​](#部署类型 "部署类型的直接链接") 阿里云的函数计算部署类型比较多,根据运行的不同容器有以下几种。 | 名称 | 能力限制 | 描述 | 部署媒介 | | ------------------------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------- | --------------- | | 内置运行时 | 不支持流式请求和响应;不支持太大的请求和响应入参 | 只能部署函数接口,不需要自定义端口,构建出 zip 包给平台部署 | zip 包部署 | | 自定义运行时(Custom Runtime) | | 可以部署标准应用,启动 9000 端口,使用平台提供的系统镜像,构建出 zip 包给平台部署 | zip 包部署 | | 自定义容器(Custom Container) | | 可以部署标准应用,启动 9000 端口,自己控制所有环境依赖,构建出 Dockerfile 提供给平台部署 | Dockerfile 部署 | 在平台上分别对应创建函数时的三种方式。 ![](https://img.alicdn.com/imgextra/i1/O1CN01JrlhOw1EJBZmHklbq_!!6000000000330-2-tps-1207-585.png) ## 纯函数开发(内置运行时)[​](#纯函数开发内置运行时 "纯函数开发(内置运行时)的直接链接") 下面我们将以使用 **"内置运行时部署"** 纯函数作为示例。 ### 触发器代码[​](#触发器代码 "触发器代码的直接链接") * Event * HTTP * API 网关 * Timer * OSS * MNS 发布不包含触发器的函数,这是最简单的类型,可以直接通过 event 手动触发参数,也可以在平台绑定其他触发器。 通过直接在代码中的 `@ServerlessTrigger` 装饰器绑定事件触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.EVENT) async handleEvent(event: any) { return event; } } ``` 阿里云的 HTTP 触发器和其他平台的有所区别,是独立于 API 网关的另一套服务于 HTTP 场景的触发器。相比于 API 网关,该触发器更易于使用和配置。 通过直接在代码中的 `@ServerlessTrigger` 装饰器绑定 HTTP 触发器。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` API 网关在阿里云函数体系中比较特殊,他类似于创建一个无触发器函数,通过平台网关的绑定到特定的路径上。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.API_GATEWAY, { path: '/api_gateway_aliyun', method: 'post', }) async handleAPIGatewayEvent(@Body() name) { return `hello ${name}`; } } ``` 定时任务触发器用于定时执行一个函数。 信息 温馨提醒,测试函数后请及时关闭触发器自动执行,避免超额扣费。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { TimerEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.TIMER) async handleTimerEvent(event: TimerEvent) { this.ctx.logger.info(event); return 'hello world'; } } ``` **事件结构** Timer 消息返回的结构如下,在 `TimerEvent` 类型中有描述。 ``` { triggerTime: new Date().toJSON(), triggerName: 'timer', payload: '', } ``` OSS 用于存储一些资源文件,是阿里云的资源存储产品。 当 OSS 中有文件创建,更新,对应的函数就会被触发而执行。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { OSSEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.OS) async handleOSSEvent(event: OSSEvent) { // xxx } } ``` **事件结构** OSS 消息返回的结构如下,在 `FC.OSSEvent` 类型中有描述。 ``` { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161e853" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.128.221" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] } ``` 信息 * 1、阿里云消息队列会对 Topic 和 Queue 产生一定的费用。 * 2、提供的默认消息队列格式为 JSON ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; import type { MNSEvent } from '@midwayjs/fc-starter'; @Provide() export class HelloAliyunService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.MQ) async handleMNSEvent(event: MNSEvent) { // ... } } ``` **事件结构** MNS 消息返回的结构如下,在 `FC.MNSEvent` 类型中有描述。 ``` { "Context": "user custom info", "TopicOwner": "1186202104331798", "Message": "hello topic", "Subscriber": "1186202104331798", "PublishTime": 1550216302888, "SubscriptionName": "test-fc-subscibe", "MessageMD5": "BA4BA9B48AC81F0F9C66F6C909C39DBB", "TopicName": "test-topic", "MessageId": "2F5B3C281B283D4EAC694B7425288675" } ``` 信息 触发器的更多配置由于和平台相关,将写在 `s.yaml` 中,如定时任务的时间间隔等,更多细节请查看下面的部署段落。 ### 类型定义[​](#类型定义 "类型定义的直接链接") FC 的定义将由适配器导出,为了让 `ctx.originContext` 的定义保持正确,需要将其添加到 `src/interface.ts` 中。 ``` // src/interface.ts import type {} from '@midwayjs/fc-starter'; ``` 此外,还提供了各种 Event 类型的定义。 ``` // Event 类型 import type { OSSEvent, MNSEvent, SLSEvent, CDNEvent, TimerEvent, APIGatewayEvent, TableStoreEvent, } from '@midwayjs/fc-starter'; // InitializeContext 类型 import type { InitializeContext } from '@midwayjs/fc-starter'; ``` ### 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 触发器和 API Gateway 类型可以通过本地 `npm run dev` 和传统应用类似的开发方式进行本地开发,其他类型的触发器本地无法使用 dev 开发,只能通过运行 `npm run test` 进行测试执行。 ### 本地测试[​](#本地��测试 "本地测试的直接链接") 和传统应用测试类似,使用 `createFunctionApp` 方法创建函数 app, 使用 `close` 方法关闭。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: mockContext(), }); // ... await close(app); }); }); ``` `mockContext` 方法用来模拟一个 FC Context 数据结构,可以自定传递一个类似的结构或者修改部分数据。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: Object.assign(mockContext(), { function: { name: '***', handler: '***' } }), }); // ... await close(app); }); }); ``` 不同的触发器有着不同的测试方法,下面列出了一些常见的触发器。 * Event * HTTP * API 网关 * Timer * OSS * MNS 通过 `getServerlessInstance` 获取类实例,直接调用实例方法,传入参数进行测试。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleEvent('hello world')).toEqual('hello world'); // ... }); }); ``` 和应用类似相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; describe('test/hello_aliyun.test.ts', () => { it('should get result from http trigger', async () => { // ... const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); // ... }); }); ``` 和 HTTP 测试相同,通过 `createFunctionApp` 创建函数 app,通过 `createHttpRequest` 方式进行测试。 ``` import { createHttpRequest } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from http trigger', async () => { // ... const result = await createHttpRequest(app).post('api_gateway_aliyun').send({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `mockTimerEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockTimerEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from timer trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleTimerEvent(mockTimerEvent())).toEqual('hello world'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createOSSEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockOSSEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from oss trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleOSSEvent(mockOSSEvent())).toEqual('hello world'); // ... }); }); ``` 和 HTTP 测试不同,通过 `createFunctionApp` 创建函数 app,通过 `getServerlessInstance` 获取整个类的实例,从而调用到特定方法来测试。 可以通过 `createMNSEvent` 方法快速创建平台传入的结构。 ``` import { HelloAliyunService } from '../src/function/hello_aliyun'; import { mockMNSEvent } from '@midwayjs/fc-starter'; describe('test/hello_aliyun.test.ts', () => { it('should get result from oss trigger', async () => { // ... const instance = await app.getServerlessInstance(HelloAliyunService); expect(await instance.handleMNSEvent(mockMNSEvent())).toEqual('hello world'); // ... }); }); ``` ## 纯函数部署(内置运行时)[​](#纯函数部署内置运行时 "纯函数部署(内置运行时)的直接链接") 以下将简述如何使用 Serverless Devs 部署到阿里云函数。 ### 1、确认启动器[​](#1确认启动器 "1、确认启动器的直接链接") 在项目根目录的 `f.yml` 的 `provider` 段落处确保 starter 为 `@midwayjs/fc-starter`。 ``` provider: name: aliyun starter: '@midwayjs/fc-starter' ``` ### 2、安装 Serverless Devs 工具[​](#2安装-serverless-devs-工具 "2、安装 Serverless Devs 工具的直接链接") aliyun 使用 [Serverless Devs 工具](https://www.serverless-devs.com/) 进行函数部署。 你可以将其安装到全局。 ``` $ npm install @serverless-devs/s -g ``` 参考 [密钥配置](https://docs.serverless-devs.com/serverless-devs/quick_start) 文档进行配置。 ### 3、编写一个 Serverless Devs 描述文件[​](#3编写一个--serverless-devs-描述文件 "3、编写一个 Serverless Devs 描述文件的直接链接") 在根目录创建一个 `s.yaml` ,添加以下内容。 ``` edition: 1.0.0 name: "midwayApp" # 项目名称 access: "default" # 秘钥别名 vars: service: name: fc-build-demo description: 'demo for fc-deploy component' services: project-0981cd9b07: component: devsapp/fc props: region: cn-hangzhou service: ${vars.service} function: name: hello # 函数名 handler: helloHttpService.handleHTTPEvent codeUri: '.' initializer: helloHttpService.initializer customDomains: - domainName: auto protocol: HTTP routeConfigs: - path: /* serviceName: ${vars.service.name} functionName: helloHttpService-handleHTTPEvent triggers: - name: http type: http config: methods: - GET authType: anonymous ``` 每加一个函数都需要调整 `s.yaml` 文件,为此Midway 提供了一个 `@midwayjs/serverless-yaml-generator` 工具用来将装饰器函数信息写入 `s.yaml`。 ``` { "scripts": { + "generate": "serverless-yaml-generator", }, "devDependencies": { + "@midwayjs/serverless-yaml-generator": "^1.0.0", }, } ``` 通过执行下面的命令,可以将现有函数信息填充到 `s.yaml` 中,并生成入口文件,方便排查问题。 ``` $ npm run generate ``` 工具将以函数名作为 key 在 `s.yaml` 中查找配置。 * 1、如果存在函数,则会覆盖特定字段,比如 handler,http 触发器的 methods * 2、如果不存在函数,则会添加一个新函数 * 3、工具不会写入 http 的路由方法,为了简化后续更新,可以提供一个 `/*` 路由(如示例) 我们推荐用户只在装饰器定义基础函数名,函数 handler,以及基础触发器信息(比如 http 触发器的 path 和 method),其余都写在 `yaml` 中。 `s.yaml` 的完整配置较为复杂,具体请参考 [描述文件规范](https://docs.serverless-devs.com/serverless-devs/yaml)。 ### 4、编写一个部署脚本[​](#4编写一个部署脚本 "4、编写一个部署脚本的直接链接") 由于部署有构建,拷贝等多个步骤,我们可以编写部署脚本统一这个过程。 比如在项目根目录新建一个 `deploy.sh` 文件,内容如下。 ``` #!/bin/bash set -e # 构建产物目录 export BUILD_DIST=$PWD/.serverless # 构建开始时间,单位毫秒 export BUILD_START_TIME=$(date +%s%3N) echo "Building Midway Serverless Application" # 打印当前目录 cwd echo "Current Working Directory: $PWD" # 打印结果目录 BUILD_DIST echo "Build Directory: $BUILD_DIST" # 安装当前项目依赖 npm i # 执行构建 ./node_modules/.bin/tsc || return 1 # 生成入口文件 ./node_modules/.bin/serverless-yaml-generator || return 1 # 如果 .serverless 文件夹存在,则删除后重新创建 if [ -d "$BUILD_DIST" ]; then rm -rf $BUILD_DIST fi mkdir $BUILD_DIST # 拷贝 dist、 *.json、*.yml 到 .serverless 目录 cp -r dist $BUILD_DIST cp *.yaml $BUILD_DIST 2>/dev/null || : cp *.json $BUILD_DIST 2>/dev/null || : # 移动入口文件到 .serverless 目录 mv *.js $BUILD_DIST 2>/dev/null || : # 进入 .serverless 目录 cd $BUILD_DIST # 安装线上依赖 npm install --production echo "Build success" # 在 .serverless 目录进行部署 s deploy ``` 可以将这个 `deploy.sh` 文件放到 `package.json` 的 `deploy` 指令中,后续部署执行 `npm run deploy` 即可。 ``` { "scripts": { "deploy": "sh deploy.sh" } } ``` 提示 * 1、 `deploy.sh` 只测试了 mac,其余平台可以自行调整 * 2、脚本内容可以根据业务逻辑自行调整,比如拷贝的文件等 ## 自定义运行时部署[​](#自定义运行时部署 "自定义运行时部署的直接链接") ### 1、创建项目[​](#1创建项目 "1、创建项目的直接链接") 自定义运行时可以使用标准项目来部署,由于需要提供 9000 端口,需要创建 Midway koa/express/express 项目。 初始化项目请参考 [创建第一个应用](/docs/quickstart.md)。 ### 2、调整端口[​](#2调整端口 "2、调整端口的直接链接") 为了避免影响本地开发,我们仅在入口 `bootstrap.js` 处增加端口。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ globalConfig: { koa: { port: 9000, } } }).run() ``` 不同的框架修改端口请参考: * [koa 修改端口](/docs/extensions/koa.md) * [Egg 修改端口](/docs/extensions/egg.md) * [Express 修改端口](/docs/extensions/express.md) ### 3、平台部署配置[​](#3平台部署配置 "3、平台部署配置的直接链接") * 1、选择运行环境,比如 `Node.js 18` * 2、选择代码上传方式,比如可以本地打 zip 包上传 * 3、启动命令指定 node bootstrap.js * 4、监听端口 9000 ![](https://img.alicdn.com/imgextra/i3/O1CN010JA2GU1lxNeqm81AR_!!6000000004885-2-tps-790-549.png) 配置完成之后,上传压缩包即可部署完成。 --- # 部署到 AWS Lambda AWS Lambda是Amazon Web Services (AWS)提供的无服务器计算服务。它允许您在无需预配或管理服务器的情况下运行代码。您可以为几乎任何类型的应用程序或后端服务运行代码,全部无需管理。 下面我们将介绍如何将 Midway 标准应用部署到 AWS Lambda。 ### 1、创建项目[​](#1创建项目 "1、创建项目的直接链接") 需要创建 Midway koa/express/express 项目。 初始化项目请参考 [创建第一个应用](/docs/quickstart.md),下面以 koa 应用为例。 ### 2、调整端口[​](#2调整端口 "2、调整端口的直接链接") 为了避免影响本地开发,我们仅在入口 `bootstrap.js` 处增加端口,比如 `8080`。 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); // 显式以组件方式引入用户代码 Bootstrap.configure({ globalConfig: { koa: { port: 8080, } } }).run() ``` 不同的框架修改端口请参考: * [koa 修改端口](/docs/extensions/koa.md) * [Egg 修改端口](/docs/extensions/egg.md) * [Express 修改端口](/docs/extensions/express.md) ### 3、安装和配置 AWS 工具[​](#3安装和配置-aws-工具 "3、安装和配置 AWS 工具的直接链接") * [安装 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) * [配置AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) * [安装 AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) ### 4、编写 template.yaml[​](#4编写-templateyaml "4、编写 template.yaml的直接链接") ``` AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: EasySchoolBackendFunction: Type: AWS::Serverless::Function Properties: CodeUri: ./dist.zip Handler: dist/index/index.handler Runtime: nodejs14.x Timeout: 900 PackageType: Zip Events: ApiEvent: Type: Api Properties: Path: /{any+} Method: ANY ``` ### 4、构建和部署[​](#4构建和部署 "4、构建和部署的直接链接") ``` $ cd sam $ sam build # builds sam $ sam local start-api # start local api ``` --- # 函数上下文 ## Event 转换[​](#event-转换 "Event 转换的直接链接") Midway Serverless 针对不同平台的情况,进行了入参包裹,同时,在函数使用了 apigw(API 网关)和 http (阿里云)触发器的情况下,对入参(event)做了特殊处理,为了简化和统一写法,将 event 统一规则化成了类似 koa 写法的代码。 普通触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/core'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler(event) { return 'hello world'; } } ``` HTTP 、API 网关触发器场景: ``` import { Context } from '@midwayjs/faas'; import { Provide } from '@midwayjs/core'; @Provide() export class Index { @Inject() ctx: Context; @ServerlessTrigger(...) async handler() { // 下面两种写法相同 // this.ctx.body = 'hello world'; return 'hello world'; } } ``` ## Context[​](#context "Context的直接链接") 每次函数调用,都会创建一个全新的 ctx(函数上下文)。针对 ctx 上的属性或者方法,我们提供 ts 定义。 信息 在 Serverless v1 时代,我们的定义叫 FaaSContext,在 v2 我们将定义和应用做了统一,更为一致。 ### ctx.logger[​](#ctxlogger "ctx.logger的直接链接") * return `ILogger` 运行时传递下来的每次请求的日志对象,默认为 console。 ``` ctx.logger.info('hello'); ctx.logger.warn('hello'); ctx.logger.error('hello'); ``` ### ctx.env[​](#ctxenv "ctx.env的直接链接") * return `string` 当前启动的环境,即 NODE\_ENV 或者 MIDWAY\_SERVER\_ENV 的值,默认为 prod。 ``` ctx.env; // 默认 prod ``` ### ctx.requestContext[​](#ctxrequestcontext "ctx.requestContext的直接链接") * return `MidwayRequestContainer` midway faas 的 IoC 请求作用域容器,用于获取其他 IoC 容器中的对象实例。 ``` const userService = await ctx.requestContext.getAsync(UserService); ``` ## FaaSHTTPContext[​](#faashttpcontext "FaaSHTTPContext的直接链接") `Context` 定义继承于 `FaaSHTTPContext`,前者保留了后者,大部分场景下可以直接使用前者,后者是在 apigw(API 网关)和 http (阿里云)触发器下才有的能力。 对于普通用户,直接使用 `Context` 定义即可。 ``` import { Context } from '@midwayjs/faas'; @Inject() ctx: Context; ``` 在 ctx 对象中,我们提供了一些和编写传统 Koa Web 应用程序类似的 API。这样的好处是减少用户的认知成本,并且,在一定程度上,兼容原有传统代码,兼容社区 middleware 成为了可能。 我们提供了一些和传统类似的 API,支持常用的能力,**在不同的平台可能不一定完全相同**,我们会在特定 API 中指出。 ### ctx.request[​](#ctxrequest "ctx.request的直接链接") * return `FaaSHTTPRequest` FaaS 模拟的 HTTP Request 对象。 ### ctx.response[​](#ctxresponse "ctx.response的直接链接") * return `FaaSHTTPResponse` FaaS 模拟的 HTTP Response 对象。 ### ctx.params[​](#ctxparams "ctx.params的直接链接") 代理自 `request.pathParameters`,在 http 触发器(阿里云)和 API 网关触发器下可用。 ``` // /api/user/[id] /api/user/faas ctx.params.id; // faas ``` ### ctx.set[​](#ctxset "ctx.set的直接链接") 设置响应头,此方法代理自 `response.setHeader` 。 ``` ctx.set('X-FaaS-Duration', 2100); ``` ### ctx.status[​](#ctxstatus "ctx.status的直接链接") 设置返回状态码,此属性代理自 `response.statusCode` 。 ``` ctx.status = 404; ``` ### Request aliases[​](#request-aliases "Request aliases的直接链接") 以下列出的属性是从 [Request](#k6AZp) 对象代理过来 * `ctx.headers` * `ctx.method` * `ctx.url` * `ctx.path` * `ctx.ip` * `ctx.query` * `ctx.get()` ### Response aliases[​](#response-aliases "Response aliases的直接链接") 以下列出的属性是从 [Response](#kfTOD) 对象代理过来 * `ctx.body=` * `ctx.status=`alias to `response.statusCode` * `ctx.type=` * `ctx.set()`alias to `response.setHeader` ## FaaSHTTPRequest[​](#faashttprequest "FaaSHTTPRequest的直接链接") 此对象是通过将函数的 `event` 和 `context` 入参进行转换得来。 ### request.headers[​](#requestheaders "request.headers的直接链接") 包含所有请求头的对象,键值对存储。 ### request.ip[​](#requestip "request.ip的直接链接") 获取客户端请求 ip。 信息 在阿里云 FC 上,只有 HTTP 触发器能获取到值,api 网关暂时无法获取。 ### request.url[​](#requesturl "request.url的直接链接") 客户端请求完整 url。 ### request.path[​](#requestpath "request.path的直接链接") 客户端请求 path。 ### request.method[​](#requestmethod "request.method的直接链接") 请求的 method。 ### request.body[​](#requestbody "request.body的直接链接") POST 请求的 body,已经解析为 JSON。 ## FaaSHTTPResponse[​](#faashttpresponse "FaaSHTTPResponse的直接链接") 此对象是通过将函数的 `event` 和 `context` 入参进行转换得来。 ### response.setHeader[​](#responsesetheader "response.setHeader的直接链接") 设置响应头。 ### response.statusCode[​](#responsestatuscode "response.statusCode的直接链接") 设置返回状态码。 ### response.body[​](#responsebody "response.body的直接链接") 设置返回响应体内容, `string` 或者 `buffer`。 --- # 开发函数 ## 初始化代码[​](#初始化代码 "初始化代码的直接链接") 让我们来开发第一个纯 HTTP 函数,来尝试将它部署到云环境。 执行 `npm init midway`,选择 `faas` 脚手架。 ## 目录结构[​](#目录结构 "目录结构的直接链接") 以下就是一个函数的最精简的结构,核心会包括一个 `f.yml` 标准化函数文件,以及 TypeScript 的项目结构。 ``` . ├── f.yml # 标准化 spec 文件 ├── package.json # 项目依赖 ├── src │ └── function │ └── hello.ts ## 函数文件 └── tsconfig.json ``` 我们来简单了解一下文件内容。 * `f.yml` 函数定义文件 * `tsconfig.json` TypeScript 配置文件 * `src` 函数源码目录 * `src/function/hello.ts` 示例函数文件 我们将函数放在 `function`目录下,是为了更好的和其他类型的代码分开。 ## 函数文件[​](#函数文件 "函数文件的直接链接") 我们首先来看看函数文件,传统的函数是一个 `function` ,为了更符合 midway 体系,以及使用我们的依赖注入,这里将它变成了 Class。 通过 `@ServerlessTrigger` 装饰器,我们将方法标注为一个 HTTP 接口,并且标示 `path` 和 `method` 属性。 ``` import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType, Query } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloHTTPService { @Inject() ctx: Context; @ServerlessTrigger(ServerlessTriggerType.HTTP, { path: '/', method: 'get', }) async handleHTTPEvent(@Query() name = 'midway') { return `hello ${name}`; } } ``` 除了触发器外,我们还可以使用 `@ServerlessFunction` 装饰器描述函数层面的元信息,比如函数名,并发度等等。 这样,当我们在一个函数上,使用多个触发器时,就可以这样设置。 ``` import { Provide, Inject, ServerlessFunction, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core'; import { Context } from '@midwayjs/faas'; @Provide() export class HelloServerlessService { @Inject() ctx: Context; // 一个函数多个触发器 @ServerlessFunction({ functionName: 'abcde', }) @ServerlessTrigger(ServerlessTriggerType.TIMER, { name: 'timer' }) async handleTimerEvent() { // TODO } } ``` 警告 注意,有些平台无法将不同类型的触发器放在同一个函数中,比如阿里云规定,HTTP 触发器和其他触发器不能同时在一个函数生效。 ## 函数定义文件[​](#函数定义文件 "函数定义文件的直接链接") `f.yml` 是框架识别函数信息的文件,内容如下。 ``` provider: name: aliyun # 发布的平台,这里是阿里云 starter: '@midwayjs/fc-starter' ``` 这里的 `@midwayjs/fc-starter` 就是适配 aliyun 函数的适配器。 ## 触发器装饰器参数[​](#触发器��装饰器参数 "触发器装饰器参数的直接链接") `@ServerlessTrigger` 装饰器用于定义不同的触发器,它的参数为每个触发器信息,以及通用触发器参数。 比如触发器的名称修改为 abc。 ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { name: 'abc', // 触发器名称 }) ``` 如果只有一个触发器,可以将函数名信息写入到触发器上。 ``` @ServerlessTrigger(ServerlessTriggerType.TIMER, { functionName: 'hello' // 如果只有一个触发器,可以省略一个装饰器 name: 'abc', }) ``` ## 函数装饰器参数[​](#函数装饰器参数 "函数装饰器参数的直接链接") `@ServerlessFunction` 装饰器用于定义函数,如果有多个触发器,通过它可以统一修改函数名。 比如: ``` @ServerlessFunction({ functionName: 'abcde' // 函数名称 }) ``` ## 本地开发[​](#本地开发 "本地开发的直接链接") HTTP 函数本地开发和传统 Web 相同,输入以下命令。 ``` $ npm run dev $ open http://localhost:7001 ``` Midway 会启动 HTTP 服务器,打开浏览器,访问 ,浏览器会打印出 `Hello midwayjs` 的信息。 非 HTTP 函数,无法直接触发,作为代替,可以编写测试函数执行。 --- # 默认错误行为 ## 错误值处理[​](#错误值处理 "错误值处理的直接链接") 为了保证安全性,Midway 针对 Serverless 场景下返回的错误做了一些特殊处理。 在函数业务抛出错误的情况下,框架侧会捕获所有的错误,并返回 “Internal Server Error” 的错误。 比如我们的函数返回一个错误: ``` @ServerlessTrigger(//...) async invoke() { throw new Error('abc'); } ``` 不管是 HTTP 还是非 HTTP 触发器,框架部分都有相应的处理。 在 **非线上环境**,比如 `NODE_ENV=local` 环境,框架会将整个错误通过网关透出。 比如(完整的错误堆栈): ``` 2021-07-02T05:57:08.553Z 19be4d99-c9cb-4c4c-aac2-9330d31b4408 [error] Error: abc at hello (/code/dist/function/index.js:17:15) at invokeHandler (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:174:56) at processTicksAndRejections (internal/process/task_queues.js:97:5) at (/code/node_modules/_@midwayjs_faas@2.11.2-beta.1@@midwayjs/faas/dist/framework.js:117:40) at cors (/code/node_modules/_@koa_cors@3.1.0@@koa/cors/index.js:98:16) at invokeHandlerWrapper (/code/node_modules/_@midwayjs_runtime-engine@2.11.1@@midwayjs/runtime-engine/dist/lightRuntime.js:18:28) { } ``` 在 线上环境,框架将直接返回 **“Internal Server Error”** ,但是日志中是完整的堆栈。 如图所示。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1625205528496-96f7d2b8-d728-4f04-82f4-f2617e00720b.png) ## 调整错误返回[​](#调整错误返回 "调整错误返回的直接链接") 以上为默认行为,在特殊环境下,如果需要显示出错误,可以使用环境变量开启强制输出。 ``` process.env.SERVERLESS_OUTPUT_ERROR_STACK = 'true'; ``` --- # 介绍 ## Midway Serverless 能做什么[​](#midway-serverless-能做什么 "Midway Serverless 能做什么的直接链接") Midway Serverless 是用于构建 Node.js 云函数的 Serverless 框架。帮助您在云原生时代大幅降低维护成本,更专注于产品研发。 ## Midway Serverless 和 Midway 的关系[​](#midway-serverless-和-midway-的关系 "Midway Serverless 和 Midway 的关系的直接链接") Midway Serverless 是 Midway 产出的一套面向 Serverless 云平台的开发方案。其内容主要包括函数框架 `@midwayjs/faas`,以及一系列跟平台配套的工具链,启动器等。 在 Midway Serverless 2.0 之后,Midway Serverless 和 Midway 的能力复用,有着相同的 CLI 工具链,编译器,装饰器等等。 当前,Midway Serverless 主要面向的是 函数(FaaS)场景。 ## 函数(FaaS)能做什么[​](#函数faas能做什么 "函数(FaaS)能做什么的直接链接") 很多人对函数还不是很清楚或者不了解他能做什么。当前的函数,可以当做一个小容器,原来我们要写一个完整的应用来承载能力,现在只需要写中间的逻辑部分,以及考虑输入和输出的数据。 通过绑定平台的触发器,可以承载例如 HTTP,Socket 等流量。 通过平台提供的 BaaS SDK,可以对外调用数据库,Redis 等服务。 通过函数,能提供传统的 HTTP API 服务,结合现有的前端框架(react,vue 等)渲染出一个个美丽的页面,也可以做为一个独立的数据模块,等待被调用(触发),比如常见的文件上传变更,解压等等,也能作为定时任务的逻辑部分,到了指定的时间或者时间间隔被执行。 随着时间的更替,平台的迭代,函数的能力会越来越强,而用户的上手成本,服务器成本则会越来越低。 ## 函数不能做什么[​](#函数不能做什么 "函数不能做什么的直接链接") 函数的架构决定了,有些需求是无法支持的,另外,函数和应用在能力上还是有一定的区别。 函数不适用: * 执行时间超过函数配置下限制的(最好不超过 5s) * 有状态,在本地存储数据的 * 长链接,比如 ws 等 * 后台任务,有大数据执行的 * 依赖多进程通信的 * 大文件上传(比如网关限制的 2M 以上) * 自定义环境的,比如 nginx 配置,c++ 库(c++ addon 动态链接库等),python 版本依赖的 * 大量服务端缓存的 * 固定 ip 的情况 ## 术语描述[​](#术语描述 "术语描述的直接链接") ### 函数[​](#函数 "函数的直接链接") 逻辑意义上的一段代码片段,通过常见的入口文件包裹起来执行。函数是单一链路,并且无状态的,现在很多人认为,Serverless = FaaS + BaaS ,而 FaaS 则是无状态的函数,BaaS 解决带状态的服务。 ### 函数组[​](#函数组 "函数组的直接链接") 多个函数聚合到一起的逻辑分组名,对应原有的应用概念。 ### 触发器[​](#触发器 "触发器的直接链接") 触发器,也叫 Event(事件),Trigger 等,特指触发函数的方式。 与传统的开发理念不同,函数不需要自己启动一个服务去监听数据,而是通过绑定一个(或者多个)触发器,数据是通过类似事件触发的机制来调用到函数。 ### 函数运行时[​](#函数运行时 "函数运行时的直接链接") 英文叫 Runtime,具体指执行函数的环境,具体在各个平台可能是镜像,也可能是 Node.js 代码包,比如常见的社区运行时有 kubeless 等,该代码包会实现对接平台的各种接口,处理异常,转发日志等能力。 ### 发布平台[​](#发布平台 "发布平台的直接链接") 函数最后承载的平台,现在社区最常见的有阿里云 FC 、腾讯云 SCF,AWS 的 Lambda 等等。 ### Layer[​](#layer "Layer的直接链接") 由于运行时的代码比较简单,且需要保证稳定性无法经常性的更新,Layer 被设计出来扩展运行时的能力,并且可以精简本地的函数代码量(有一些平台限制了上传压缩包的大小)。 --- # Serverless 触发器 POST 情况差异 ## 阿里云 API 网关[​](#阿里云-api-网关 "阿里云 API 网关的直接链接") 阿里云 API 网关支持不同类型的的 POST 请求。 ### 入参透传的 POST[​](#入参透传的-post "入参透传的 POST的直接链接") 网关配置如下。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593175823751-f9b305fc-ddeb-4b04-ba13-481a616be260.png) 网关透传的 event 特征为有 `body` 字段以及 `isBase64Encoded` 为 true,解码比较容易,直接解 base64 即可。 信息 透传了之后,即为所有的结果交给函数处理。 #### 示例一 (text/html)[​](#示例一-texthtml "示例一 (text/html)的直接链接") 下面的 event,是一个最简单的透传示例,因为其中的 `content-type` 为 `text/html`,所以 body 传递过来 base64 解码的结果也同样是字符串。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "x-ca-dashboard-action": "DEBUG", "x-ca-dashboard-uid": "125087", "x-ca-stage": "RELEASE", "x-ca-dashboard-role": "USER", "user-agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "accept-encoding": "gzip,deflate", "content-md5": "Kry+hjKjc2lvIrwoJqdY9Q==", "content-type": "text/html; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // '{"c":"b"}' => string ``` #### 示例二(application/json)[​](#示例二applicationjson "示例二(application/json)的直接链接") 使用 `content-type` 为 `application/json` ,这样框架认为是一个 JSON,会自动被 JSON.parse。 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "125087", "X-Ca-Stage": "RELEASE", "X-Ca-Dashboard-Role": "USER", "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_172)", "Accept-Encoding": "gzip,deflate", "Content-MD5": "Kry+hjKjc2lvIrwoJqdY9Q==", "Content-Type": "application/json; charset=utf-8" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` #### 示例三 (application/x-www-form-urlencoded)[​](#示例三-applicationx-www-form-urlencoded "示例三 (application/x-www-form-urlencoded)的直接链接") 使用 `content-type` 为 `application/x-www-form-urlencoded`,这个时候网关不会以 base64 格式透传,这也是前端原生表单的默认提交类型。 信息 在 API 网关侧测试,保持“入参透传”下,似乎没有效果,于是我换到了 Postman 进行测试。 Postman 模拟请求如下: ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593188653464-2a5659de-40ad-4611-ba86-f5754c7d4425.png) 函数拿到的 event 值如下。 ``` { "body": "{\"c\":\"b\"}", "headers": { "accept": "*/*", "cache-control": "no-cache", "user-agent": "PostmanRuntime/7.24.1", "postman-token": "feb51b11-9103-463a-92ff-73076d37b683", "accept-encoding": "gzip, deflate, br", "content-type": "application/x-www-form-urlencoded" }, "httpMethod": "POST", "isBase64Encoded": false, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数结果。 ``` ctx.request.body; // {"c":"b"} => object ``` ### 入参映射的 POST[​](#入参映射的-post "入参映射的 POST的直接链接") 网关配置选择入参映射之后,body 数据类型有两种选择。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593186831907-7975c65c-aee5-4f96-9ae4-ffaeee66c7dd.png) 一旦选了映射,整个函数拿到的 Headers 中就 **没有了 content-type**。 这个时候,网关的返回 event 为 ``` { "body": "eyJjIjoiYiJ9", "headers": { "X-Ca-Dashboard-Action": "DEBUG", "X-Ca-Dashboard-Uid": "111111", "X-Ca-Dashboard-Role": "USER" }, "httpMethod": "POST", "isBase64Encoded": true, "path": "/api/321", "pathParameters": { "userId": "321" }, "queryParameters": {} } ``` 函数由于默认没有拿到 header 头,只会对 base64 的结果做处理,结果为字符串。 ``` ctx.request.body; // '{"c":"b"}' => string ``` ## 阿里云 HTTP 触发器[​](#阿里云-http-触发器 "阿里云 HTTP 触发器的直接链接") 函数提供的 HTTP 触发器(和网关不同)。 ### 普通 POST(application/json)[​](#普通-postapplicationjson "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 字符串格式。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321679770-a7609684-ec5e-4f93-99f2-d346ed79c1fa.png) ``` ctx.request.body; // "bbb" => string ``` JSON 格式 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321730423-f9b2860f-7902-4f3a-81cf-bfbcfd4ee57f.png) ``` ctx.request.body; // {"b":"c"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded "表单(application/x-www-form-urlencoded)的直接链接") ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593321823455-23ec3970-35a5-4746-8995-d9146eaa4ab0.png) ``` ctx.request.body; // {"b":"c"} => object ``` ### 文件上传(Binary)[​](#文件上传binary "文件上传(Binary)的直接链接") 暂未支持 ## 腾讯云网关[​](#腾讯云网关 "腾讯云网关的直接链接") 腾讯云提供单独网关。 ### 普通 POST(application/json)[​](#普通-postapplicationjson-1 "普通 POST(application/json)的直接链接") 验证代码如下。 ``` const body = this.ctx.request.body; return { type: typeof body, body, }; ``` 使用 Postman 请求。 字符串格式,正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323223487-c4e5f365-b500-4a2d-85e3-45bd4aba4653.png) ``` ctx.request.body; // "bbb" => string ``` JSON 格式,能正常解析。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323187488-e7b4e32e-4195-404d-b309-ba436c3f5f8e.png) ``` ctx.request.body; // {"c":"b"} => object ``` ### 表单(application/x-www-form-urlencoded)[​](#表单applicationx-www-form-urlencoded-1 "表单(application/x-www-form-urlencoded)的直接链接") 正常解析为 JSON。 ![](https://cdn.nlark.com/yuque/0/2020/png/501408/1593323279728-983fd844-f37d-419b-90f3-f96d1ee8236d.png) ``` ctx.request.body; // {"c":"b"} => object ``` --- # 测试函数 ## HTTP 类的函数[​](#http-类的函数 "HTTP 类的函数的直接链接") 该方法适用于所有的类 HTTP 触发器的函数,包括 `HTTP` 和 `API_GATEWAY`。 使用和应用相同的测试方法来测试,针对 HTTP 函数,使用封装了 supertest 的 `createHttpRequest` 方法创建 HTTP 客户端。 唯一和应用不同的是,使用 `createFunctionApp` 方法创建函数应用(app)。 `createFunctionApp` 是 `createApp` 在函数场景下的定制方法。 HTTP 测试代码如下: ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/faas'; describe('test/hello_aliyun.test.ts', () => { it('should get result from api gateway trigger', async () => { const app: Application = await createFunctionApp(); const result = await createHttpRequest(app).get('/').query({ name: 'zhangting', }); expect(result.text).toEqual('hello zhangting'); await close(app); }); }); ``` ## 普通触发器[​](#普通触发器 "普通触发器的直接链接") 除了类 HTTP 触发器之外,我们还有其他比如定时器、对象存储等函数触发器,这些触发器由于和网关关系密切,不能使用 HTTP 行为来测试,而是使用传统的方法调用来做。 通过 `createFunctionApp` 方法创建函数 app,通过 `getServerlessInstance` 方法获取类实例,然后通过实例的方法直接调用,传入参数进行测试。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/faas'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // 创建函数 app let app: Application = await createFunctionApp(); // 拿到服务类 const instance = await app.getServerlessInstance(HelloAliyunService); // 调用函数方法,传入参数 expect(await instance.handleEvent('hello world')).toEqual('hello world'); await close(app); }); }); ``` --- # 从 Serverless v2 迁移到 v3 基于 Midway 升级到 v3 的缘故,Serverless 体系也同步升级到了 v3 版本。 本文章介绍如何从 Serverless v2.0 迁移到 Serverless v3.0,和传统应用升级非常的类似。 警告 新的 Serverless 当前只支持阿里云函数。 ## 1、项目包版本的升级[​](#1项目包版本的升级 "1、项目包版本的升级的直接链接") 一些依赖包升级,包括: * midway 及组件版本升级到 3.x * CLI,Jest 等版本升级 * 移除了一些不再使用的依赖,比如 `@midwayjs/serverless-app` ``` "scripts": { "dev": "cross-env NODE_ENV=local midway-bin dev --ts", "test": "cross-env midway-bin test --ts", - "deploy": "cross-env UDEV_NODE_ENV=production midway-bin deploy", "lint": "mwts check", "lint:fix": "mwts fix" }, "dependencies": { - "@midwayjs/core": "^2.3.0", - "@midwayjs/decorator": "^2.3.0", - "@midwayjs/faas": "^2.0.0" + "@midwayjs/core": "^3.12.0", + "@midwayjs/faas": "^3.12.0", + "@midwayjs/fc-starter": "^3.12.0", + "@midwayjs/logger": "^2.0.0" }, "devDependencies": { - "@midwayjs/cli": "^1.2.45", - "@midwayjs/cli-plugin-faas": "^1.2.45", - "@midwayjs/fcli-plugin-fc": "^1.2.45", - "@midwayjs/mock": "^2.8.7", - "@midwayjs/serverless-app": "^2.8.7", - "@midwayjs/serverless-fc-trigger": "^2.10.3", - "@midwayjs/serverless-fc-starter": "^2.10.3", - "@types/jest": "^26.0.10", - "@types/node": "14", - "cross-env": "^6.0.0", - "jest": "^26.4.0", - "mwts": "^1.0.5", - "ts-jest": "^26.2.0", - "typescript": "~4.6.0" + "@midwayjs/mock": "^3.12.0", + "@types/jest": "29", + "@types/node": "16", + "cross-env": "^7.0.3", + "jest": "29", + "mwts": "^1.3.0", + "ts-jest": "29", + "ts-node": "^10.9.1", + "typescript": "~5.1.0" } ``` ## 2、入口主框架的变化[​](#2入口主框架的变化 "2、入口主框架的变化的直接链接") 显式声明 faas 作为主框架。 ``` // src/configuration import * as faas from '@midwayjs/faas'; @Configuration({ // ... imports: [ faas ], }) export class MainConfiguration { // ... } ``` ## 3、测试代码变化[​](#3测试代码变化 "3、测试代码变化的直接链接") 移除了 `@midwayjs/serverless-app` 的依赖。 ``` import { createFunctionApp, close, createHttpRequest } from '@midwayjs/mock'; - import { Framework, Application } from '@midwayjs/serverless-app'; + import { Framework, Application } from '@midwayjs/faas'; ``` 移除了 `@midwayjs/serverless-fc-trigger` 和 `@midwayjs/serverless-fc-starter` 依赖,修改为 `@midwayjs/fc-starter`。 ``` import { Application, Context, Framework } from '@midwayjs/faas'; import { mockContext } from '@midwayjs/fc-starter'; import { createFunctionApp } from '@midwayjs/mock'; describe('test/hello_aliyun.test.ts', () => { it('should get result from event trigger', async () => { // create app const app: Application = await createFunctionApp(join(__dirname, '../'), { initContext: Object.assign(mockContext(), { function: { name: '***', handler: '***' } }), }); // ... await close(app); }); }); ``` 一些 API 的替代,比如原有的 `createXXXEvent`,将变为 `mockXXXEvent`,原有的 `createInitializeContext` 将变为 `mockContext` 方法。 这些 API 将直接从 `@midwayjs/fc-starter` 中导出。 ## 5、部署方式的变化[​](#5部署方式的变化 "5、部署方式的变化的直接链接") 不再使用 `midway-bin deploy` 进行部署,将采用平台自己的 CLI 工具,Midway 只提供框架和本地开发能力。 更多的部署调整,请查询 [纯函数部署](/docs/serverless/aliyun_faas.md)。 --- # 服务和注入 在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01LLV2Qd20Fbu1NWXVA_!!6000000006820-2-tps-2130-344.png) 提供这个抽象有以下几个好处: * 保持 Controller 中的逻辑更加简洁。 * 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。 * 将逻辑和展现分离,更容易编写测试用例。 ## 创建服务[​](#创建服务 "创建服务的直接链接") 在 Midway 中,普通的服务就是一个 Class,比如我们之前创建了一个接受 user 请求的 Controller,我们来新增一个处理这些数据的服务。 对于服务的文件,我们一般会存放到 `src/service` 目录中。我们来添加一个 user 服务。 ``` ➜ my_midway_app tree . ├── src │ ├── controller │ │ ├── user.ts │ │ └── home.ts │ ├── interface.ts │ └── service │ └── user.ts ├── test ├── package.json └── tsconfig.json ``` 内容为: ``` // src/service/user.ts import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async getUser(id: number) { return { id, name: 'Harry', age: 18, }; } } ``` 除了一个 `@Provide` 装饰器外,整个服务的结构和普通的 Class 一模一样,这样就行了。 之前我们还增加了一个 User 定义,这里也可以直接使用。 ``` import { Provide } from '@midwayjs/core'; import { User } from '../interface'; @Provide() export class UserService { async getUser(id: number): Promise { return { id, name: 'Harry', age: 18', }; } } ``` ## 使用服务[​](#使用服务 "使用服务的直接链接") 在 Controller 处,我们需要来调用这个服务。传统的代码写法,我们需要初始化这个 Class(new),然后将实例放在需要调用的地方。在 Midway 中,你**不需要这么做**,只需要编写我们提供的\*\* "依赖注入" \*\*的代码写法。 ``` import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core'; import { UserService } from '../service/user'; @Controller('/api/user') export class APIController { @Inject() userService: UserService; @Get('/') async getUser(@Query('id') uid) { const user = await this.userService.getUser(uid); return {success: true, message: 'OK', data: user}; } } ``` 使用服务的过程分为几部分: * 1、使用 `@Provide` 装饰器暴露你的服务 * 2、在调用的代码处,使用 `@Inject` 装饰器注入你的服务 * 3、调用注入服务,执行对应的方法 Midway 的核心 “依赖注入” 容器会**自动关联**你的控制器(Controller) 和服务(Service),在运行过程中**会自动初始化**所有的代码,你**无需手动初始化**这些 Class。 ## 注入行为描述[​](#注入行为描述 "注入行为描述的直接链接") 看到这里,你会有一些疑惑,为什么服务(Service)上有一个 `@Provide` 装饰器,但是控制器(Controller) 上没有。 事实上,控制器(Controller) 上也有这个装饰器,只是在新版本中,Controller 包含了 Provide 的功能。如果你不确定什么时候可以隐藏,可以都写上。 你如果不写,默认等价于下面的代码。 ``` @Provide() @Controller('/api/user') export class APIController { ``` `@Provide` 装饰器的作用: * 1、这个 Class,被依赖注入容器托管,会自动被实例化(new) * 2、这个 Class,可以被其他在容器中的 Class 注入 而对应的 `@Inject` 装饰器,作用为: * 1、在依赖注入容器中,找到对应的属性名,并赋值为对应的实例化对象 信息 `@Inject` 的类中,必须有对应的 `@Provide` 才会生效。 `@Provide` 和 `@Inject` 装饰器是成对出现的,两者通过冒号后的类名进行关联。 ``` // service @Provide() export class UserService { //... } // controller @Provide() // <------ 由于有 Controller 包含了 Provide 的能力,这里展示的更加完整 @Controller('/api/user') export class APIController { @Inject() userService: UserService; // <------ 这里的类型是 Class,即会注入一个该类型的实例 //... } ``` 这样的组合之后会用到很多地方,**请务必记住这个用法**。 依赖注入还有更为复杂的情况,可以阅读 [依赖注入](/docs/container.md) 参考。 --- # 服务发现(Service Discovery) 在分布式架构中,服务发现用于自动注册和发现可用的服务实例,并通过健康检查与负载均衡确保调用的稳定与高可用。Midway 在核心层提供了统一的抽象与基类,并在不同的注册中心上提供了具体实现(Consul、ETCD、Redis),以适配多种使用场景。 ## 基本概念与抽象[​](#基本概念与抽象 "基本概念与抽象的直接链接") 服务发现是指在分布式系统中,服务消费者能够自动发现并调用服务提供者的实例。它通常包括以下几个组件: * 服务提供者(Service Provider):注册自身实例到服务发现中心,保持实例状态(如健康、可用)。 * 服务发现中心(Service Registry):负责存储服务提供者的实例信息,提供查询接口。 * 服务消费者(Service Consumer):通过服务发现中心查询可用实例,根据负载均衡策略选择实例调用。 * 负载均衡器(LoadBalancer):在服务消费者端,根据策略(如轮询、随机)选择实例进行调用。 * 健康检查(Health Check):服务发现中心定时检查实例状态,确保调用的实例是健康的。 ``` flowchart TB SR[服务发现中心] SP[服务提供者] SC[服务消费者] SR -->|注册/上线| SP SR -->|查询/选择| SC SP -->|下线/注销| SR SC -->|调用| SP ``` Midway 基于业界的基本概念,抽象了服务发现的基本组件,包括服务提供者、服务发现中心、服务消费者、负载均衡器与健康检查。 ``` flowchart TB subgraph 外部服务 direction TB Registry[服务发现中心(泛化,Consul,ETCD,Redis 等)] end subgraph Midway 抽象实现 direction LR SDClient[ServiceDiscoveryClient(抽象)] SD[ServiceDiscovery(抽象入口)] LB[ILoadBalancer(接口)] HC[健康检查工厂] Consumer[业务代码(消费者)] end SDClient -- 注册/上线/下线/注销 --> Registry Registry -- 监听/查询 --> SD SD -. 使用 .-> LB SD -. 创建 .-> HC SD -- getInstances/getInstance --> Consumer ``` ### 抽象与扩展点[​](#抽象与扩展点 "抽象与扩展点的直接链接") * ServiceDiscoveryClient(面向注册中心的客户端基类) * 负责实例生命周期:`register`、`deregister`、`online`、`offline`、`beforeStop`。 * 提供 `defaultMeta`(包含默认实例信息)与 `getSelfInstance` 获取已注册实例。 * 封装 `stop`:先执行 `beforeStop`,再自动调用 `deregister` 清理资源。 * 使用泛型指定:底层 Client 类型、配置选项、注册实例类型与查询实例类型。 * ServiceDiscovery(统一入口类) * 创建客户端:`createClient(options?)` 合并默认配置与覆盖项,并记录在内部存储中。 * 查询实例:`getInstances(options)` 返回候选集合;`getInstance(options)` 结合负载均衡选择单个实例。 * 负载均衡:`setLoadBalancer(type|impl)` 设置策略或注入自定义实现,默认轮询。 * 生命周期:`destroy` 会先调用自身的 `beforeStop`,再逐一停止并注销所有已创建客户端。 * 扩展方法需实现:`getServiceClient`、`createServiceDiscoverClientImpl`、`getDefaultServiceDiscoveryOptions`、`getInstances`。 * 负载均衡(ILoadBalancer 与工厂) * 接口:`select(instances)` 根据策略返回一个实例。 * 内置策略:`RANDOM`(随机)、`ROUND_ROBIN`(轮询)。 * 自定义:实现 `ILoadBalancer` 并通过 `setLoadBalancer(customImpl)` 注入。 * 健康检查(IServiceDiscoveryHealthCheck 与工厂) * 基类 `AbstractHealthCheck` 提供检查节流与最近结果记录:`shouldCheck()`、`getLastCheckResult()`。 * 工厂创建:`ttl`、`http`、`tcp`、`self`、`custom`;不同类型适用于不同场景(如 TTL 适配键值 TTL 刷新模式,HTTP/TCP 适配网络探活)。 ## 逐步实现一个服务发现[​](#逐步实现一个服务发现 "逐步实现一个服务发现的直接链接") 以下以核心抽象为基础,分步骤说明如何实现一个新的服务发现能力。 ### 第 1 步:定义类型[​](#第-1-步定义类型 "第 1 步:定义类型的直接链接") * 定义注册实例与配置选项类型,约定必要字段(如 `serviceName/id/meta/ttl`)。 ``` type MyRegisterInstance = { serviceName: string; id: string; ttl?: number; meta?: Record; }; type MyOptions = { ttl?: number; loadBalancer?: any; }; ``` ### 第 2 步:实现客户端基类[​](#第-2-步实现客户端基类 "第 2 步:实现客户端基类的直接链接") * 继承 `ServiceDiscoveryClient`,落地注册中心的具体交互与状态切换。 ``` class MyServiceDiscoverClient extends ServiceDiscoveryClient { async register(instance: MyRegisterInstance): Promise { this.instance = instance; } async deregister(): Promise {} async online(): Promise {} async offline(): Promise {} async beforeStop(): Promise {} } ``` 要点: * `register` 持有实例并完成注册中心写入。 * `online`/`offline` 切换可用状态(如键写入与删除、心跳管理)。 * `deregister` 注销实例并清理资源。 * `beforeStop` 用于停止心跳、订阅、定时器等。 ### 第 3 步:实现统一入口类[​](#第-3-步实现统一入口类 "第 3 步:实现统��一入口类的直接链接") * 继承 `ServiceDiscovery`,将客户端与负载均衡整合为统一入口。 ``` class MyServiceDiscovery extends ServiceDiscovery { protected getServiceClient() { return {}; } protected createServiceDiscoverClientImpl(options: MyOptions) { return new MyServiceDiscoverClient(this.getServiceClient(), options); } protected getDefaultServiceDiscoveryOptions(): MyOptions { return { ttl: 30 }; } public async getInstances(serviceName: string): Promise { return []; } } ``` 要点: * `createClient` 自动合并默认配置与覆盖项,统一创建客户端。 * `getInstances` 返回候选集合,供负载均衡选择。 * `getInstance` 内部按策略选择一个实例。 ### 第 4 步:配置与使用[​](#第-4-步配置与使用 "第 4 步:配置与使�用的直接链接") * 创建客户端,注册并获取实例。 ``` const discovery = await container.getAsync(MyServiceDiscovery); const client = discovery.createClient({ ttl: 20 }); await client.register({ serviceName: 'order', id: 'order-1' }); const instances = await discovery.getInstances('order'); const one = await discovery.getInstance('order'); ``` ### 第 5 步:设置负载均衡[​](#第-5-步设置负载均衡 "第 5 步:设置负载均衡的直接链接") * 使用内置策略或注入自定义实现。 ``` import { LoadBalancerType } from '@midwayjs/core'; discovery.setLoadBalancer(LoadBalancerType.ROUND_ROBIN); ``` ### 第 6 步:集成健康检查(可选)[​](#第-6-步集成健康检查可选 "第 6 步:集成健康检查(可选)的直接链接") * 按需选择 `ttl/http/tcp/custom` 类型,并在上线或周期任务中使用。 ``` import { ServiceDiscoveryHealthCheckFactory } from '@midwayjs/core'; const check = ServiceDiscoveryHealthCheckFactory.create('http', { url: 'http://127.0.0.1:7001/health' }); const result = await check.check({}); ``` ### 第 7 步:生命周期清理[​](#第-7-步生命周期清理 "第 7 步:生命周期清理的直接链接") * 容器销毁时,入口类会调用所有客户端的 `stop`,确保注销与资源回收。 ## 获取实例与负载均衡[​](#获取实例与负载均衡 "获取实例与负载均衡的直接链接") 所有实现均遵循统一的接口: ``` // 获取所有可用实例 await serviceDiscovery.getInstances(/* 参见具体实现签名 */); // 获取一个实例(带负载均衡) await serviceDiscovery.getInstance(/* 参见具体实现签名 */); // 设置负载均衡策略 serviceDiscovery.setLoadBalancer(LoadBalancerType.RANDOM); ``` ## 生命周期与清理[​](#生命周期与清理 "生命周期与清理的直接链接") * 在容器销毁时,`ServiceDiscovery` 会调用所有 `ServiceDiscoveryClient.stop()` 完成注销与资源回收。 * 各实现均在 `beforeStop` 中完成健康检查、订阅、租约等资源的关闭。 ## 类型定义与扩展[​](#类型定义与扩展 "类型定义与扩展的直接链接") * 服务发现配置使用 `ServiceDiscoveryOptions`,在各实现中可扩展(例如 ETCD 的 `ttl/namespace`、Redis 的 `prefix/scanCount`、Consul 的 `autoHealthCheck`)。 * 可通过实现自定义的 `ILoadBalancer` 或健康检查来扩展行为。 ## 小结[​](#小结 "小结的直接链接") 服务发现以统一抽象组织:入口类负责客户端创建与负载均衡选择,客户端负责注册中心适配与实例生命周期管理。使用时仅需:创建客户端 → 注册并上线 → 通过入口类获取实例列表或单个实例(可设置负载均衡策略)→ 生命周期结束自动清理。 --- # 服务工厂 有时候编写组件或者编写服务,会碰到某个服务有多实例的情况,这个时候服务工厂(Service Factory)就适合这种场景。 比如我们的 oss 组件,由于会创建多个 oss 对象,在编写的时候就需要留好多实例的接口。为了这种场景,midway 抽象了 `ServiceFactory` 类。 `ServiceFactory` 是个抽象类,每个需要实现的服务,都需要继承他。 我们以一个 http 客户端为例,需要准备一个创建 http 客户端实例的方法,其中包含几个部分: * 1、创建客户端实例的方法 * 2、客户端的配置 * 3、实例化服务类 ``` // 创建客户端的配置 const config = { baseUrl: '', timeout: 1000, }; // 创建客户端实例的方法 const httpClient = new HTTPClient(config); ``` ## 实现一个服务类[​](#实现一个服务类 "实现一个服务类的直接链接") 我们希望实现一个上述 HTTPClient 的服务工厂,用于在 midway 体系中创建多个 httpClient 对象。 服务工厂在 midway 中也是一个普通的导出类,作为服务的一员,比如我们也可以把他放到 `src/service/httpServiceFactory.ts` 中。 ### 1、实现创建实例接口[​](#1实现创建实例接口 "1、实现创建实例接口的直接链接") `ServiceFactory` 是个用于继承的抽象类,它包含一个泛型(创建的实例类型,比如下面就是创建出 HTTPClient 类型)。 我们只需要继承它,同时,一般服务工厂为单例。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { // ... } ``` 由于是抽象类,我们需要实现其中的两个方法。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { // 创建单个实例 protected createClient(config: any): any { return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `createClient` 方法用于传入一个创建服务配置(比如 httpClient 配置),返回一个具体的实例,就像示例中的那样。 `getName` 方法用于返回这个服务工厂的名字,方便框架识别和日志输出。 ### 2、增加配置和初始化方法[​](#2增加配置和初始化方法 "2、增加配置和初始化方法的直接链接") 我们需要注入一个配置,比如我们使用 `httpClient` 作为这个服务的配置。 ``` // config.default.ts export const httpClient = { // ... } ``` 然后注入到服务工厂中,同时,我们还需要在初始化时,调用创建多个实例的方法。 ``` import { ServiceFactory, Provide, Scope, ScopeEnum } from '@midwayjs/core'; @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { @Config('httpClient') httpClientConfig; @Init() async init() { await this.initClients(this.httpClientConfig); } protected createClient(config: any): any { // 创建实例 return new HTTPClient(config); } getName() { return 'httpClient'; } } ``` `initClients` 方法是基类中实现的,它需要传递一个完整的用户配置,并循环调用 `createClient` 来创建对象,保存到内存中。 从 v4.0.0 开始,`initClients` 方法支持第二个参数,用于传递初始化选项。 你可以通过 `concurrent` 参数来控制是否并发初始化,为了向前兼容,默认是 `false`。 如果确认所有实例的初始化之间没有干扰,可以设置为 `true`,以提高初始化速度。 ``` await this.initClients(this.httpClientConfig, { concurrent: true }); ``` ### 3、实例化服务类[​](#3实例化服务类 "3、实例化服务类的直接链接") 为了方便用户使用,我们还需要提前将服务类创建,一般来说,只需要在组件或者项目的生命周期中实例化即可。 ``` import { Configuration } from '@midwayjs/core'; @Configuration({ imports: [ // ... ] }) export class ContainerConfiguration { async onReady(container) { // 实例化服务类 await container.getAsync(HTTPClientServiceFactory); } } ``` ## 获取实例[​](#获取实例 "获取实例的直接链接") `createClient` 方法只是定义了创建对象的方法,我们还需要定义配置的结构。 配置的结构分为几部分: * 1、默认配置,即所有对象都能复用的配置 * 2、单个实例需要的配置 * 3、多个实例需要的配置 我们来分别说明, **默认配置** 默认的配置,我们约定为 `default` 属性。 在创建实例时,普通的实例配置以及动态创建的实例配置都会和 `default` 配置合并。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000 } } ``` ### 单个实例[​](#单个实例 "单个实例的直接链接") **单个配置** ``` // config.default.ts export const httpClient = { default: { timeout: 3000 }, client: { baseUrl: '' } } ``` `client` 用于单个实例结构的描述,创建对象时会和 `default` 做合并。使用 `get` 方法获取默认实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const httpClient = this.serviceFactory.get(); } } ``` ### 多个实例[​](#多个实例 "多个实例的直接链接") 使用 `clients` 来配置多个实例,每个 key 都是一个独立的实例配置。 ``` // config.default.ts export const httpClient = { default: { timeout: 3000 }, clients: { aaa: { baseUrl: '' }, bbb: { baseUrl: '' } } } ``` 通过 key 来获取实例。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { const aaaInstance = this.serviceFactory.get('aaa'); // ... const bbbInstance = this.serviceFactory.get('bbb'); // ... } } ``` ### 装饰器获取实例[​](#装饰器获取实例 "装饰器获取实例的直接链接") 从 v3.9.0 开始,ServiceFactory 添加了一个 `@InjectClient` 装饰器,方便在多客户端的的时候选择注入。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; import { InjectClient } from '@midwayjs/core'; @Provide() export class UserService { @InjectClient(HTTPClientServiceFactory, 'aaa') aaaInstance: HTTPClientServiceFactory; @InjectClient(HTTPClientServiceFactory, 'bbb') bbbInstance: HTTPClientServiceFactory; async invoke() { // this.aaaInstance.xxx // this.bbbInstance.xxx // ... } } ``` `@InjectClient` 装饰器用于快速注入 `ServiceFactory` 派生实现的多实例,所有扩展与 `ServiceFactory` 的类,都能使用。 装饰器包含两个参数,定义如下: ``` export function InjectClient( serviceFactoryClz: new (...args) => IServiceFactory, clientName?: string ) { // ... } ``` | 参数 | 描述 | | ----------------- | ------------------------------------------------------------------------- | | serviceFactoryClz | 必填,`ServiceFactory` 的派生类,装饰器会从中获取查找实例。 | | clientName | 可选,如果不填,默认会查找配置中的默认实例名 `defaultClientName` 配置项。 | ### 动态创建实例[​](#动态创建实例 "动态创建实例的直接链接") 也可以通过基类的 `createInstance` 方法动态获取实例。 警告 注意,这里使用的不是子类的 createClient,createClient 不包含和默认配置的逻辑。 ``` import { HTTPClientServiceFactory } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() serviceFactory: HTTPClientServiceFactory; async invoke() { // 会合并 config.bucket3 和 config.default let customHttpClient = await this.serviceFactory.createInstance({ baseUrl: 'xxxxx' }, 'custom'); // 传了名字之后也可以从 factory 中获取 customHttpClient = this.serviceFactory.get('custom'); } } ``` `createInstance` 方法的第一个参数是配置,如果动态调用的时候,可以手动传参,第二个参数是一个字符串名称,如果传入了名称,创建完的实例将会保存到内存中,后续可以从服务工厂中再次获取。 ## 实例配置合并逻辑[​](#实例配�置合并逻辑 "实例配置合并逻辑的直接链接") 在实际代码运行时,即使是单实例,配置一个 `client`,也会在内存中将配置变换为 `clients`。 比如下面的代码: ``` // config.default.ts export const httpClient = { client: { baseUrl: '' } } ``` 在内存中会变为: ``` // config.default.ts export const httpClient = { clients: { default: { baseUrl: '' } } } ``` 会多出一个名为 `default` 的默认实例,服务工厂会以 `clients` 的配置进行初始化。 ## 默认实例代理(可选)[​](#默认实例代理可选 "默认实例代理(可选)的直接链接") 如果用户每次使用时,都通过 `serviceFactory` 去获取,会非常的繁琐,对于最常用的默认实例,可以提供一个代理类,使其代理所有的目标实例方法。 ``` import { Provide, Scope, ScopeEnum, Init, ServiceFactory, MidwayCommonError, delegateTargetAllPrototypeMethod } from '@midwayjs/core'; // ... export class HTTPClientServiceFactory extends ServiceFactory { // ... } // 下面是默认代理类 @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientService implements HTTPClient { @Inject() private serviceFactory: HTTPClientServiceFactory; // 这个属性用于保存实际的实例 private instance: HTTPClient; @Init() async init() { // 在初始化阶段,从工厂拿到默认实例 this.instance = this.serviceFactory.get( this.serviceFactory.getDefaultClientName() || 'default' ); if (!this.instance) { throw new MidwayCommonError('http client default instance not found.'); } } } // 下面这段代码,用于默认实例类的 ts 定义正确被继承 // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface HTTPClientService extends HTTPClient { // empty } // 下面这段代码,用于默认实例类的实现可以被代理 delegateTargetAllPrototypeMethod(HTTPClientService, HTTPClient); ``` 通过上面的代码,我们就可以直接使用 `HTTPClientService` ,而无需从 `HTTPClientServiceFactory` 获取默认实例。 `delegateTargetAllPrototypeMethod` 是 Midway 提供的代理实例方法的工具方法。 此外,还有一些其他可用的工具方法,列举如下: * `delegateTargetAllPrototypeMethod` 用于代理目标所有的原型方法,包括原型链,不包括构造器和内部隐藏方法 * `delegateTargetPrototypeMethod` 用于代理目标所有的原型方法,不包括构造器和内部隐藏方法 * `delegateTargetMethod` 代理目标上指定的方法 ## 修改默认实例名[​](#修改默认实例名 "修改默认实例名的直接链接") 默认情况下,默认的实例名为 `default` ,默认的实例代理内部会根据该实例进行代理。 假如用户没有配置 `default` 实例,或者希望修改默认实例,用户通过配置修改。 ``` // config.default.ts export const httpClient = { clients: { default: { baseUrl: '' }, default2: { baseUrl: '' } }, defaultClientName: 'default2', } ``` 在默认的实例代理中,会通过 `this.serviceFactory.getDefaultClientName()` 来获取这个值。 ``` import { HTTPClientService } from './service/httpClientServiceFactory'; import { join } from 'path'; @Provide() export class UserService { @Inject() httpClientService: HTTPClientService; async invoke() { // this.httpClientService 中指向的是 default2 } } ``` ## 实例优先级[​](#实例优先级 "实例优先级的直接链接") 从 v3.14.0 开始,服务工厂的实例可以增加一个优先级属性,在不同的场景,会根据优先级做一些不同处理。 实例的优先级有 `L1`,`L2`, `L3` 三个等级,分别对应高,中,低三个层级。 定义如下: ``` export const DEFAULT_PRIORITY = { L1: 'High', L2: 'Medium', L3: 'Low', }; ``` 通过配置,我们可以指定不同实例的优先级。 ``` // config.default.ts import { DEFAULT_PRIORITY } from '@midwayjs/core'; export default { httpClient: { clients: { default: { baseUrl: '' }, default2: { baseUrl: '' } }, clientPriority: { default: DEFAULT_PRIORITY.L1, default2: DEFAULT_PRIORITY.L2, } } } ``` 如果不做设置, 默认情况下优先级为中等,即 `DEFAULT_PRIORITY.L2`。 为了更好的判断优先级,`ServiceFactory` 基类中会增加一些方法。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientService implements HTTPClient { @Inject() private serviceFactory: HTTPClientServiceFactory; @Init() async init() { // 获取优先级 this.serviceFactory.getClientPriority('default'); // DEFAULT_PRIORITY.L2 // 判断优先级 this.serviceFactory.isHighPriority('default'); this.serviceFactory.isMediumPriority('default'); this.serviceFactory.isLowPriority('default'); } } ``` ## 销毁服务类和实例[​](#销毁服务类和实例 "销毁服务类和实例的直接链接") 服务工厂提供了 `destroyClient` 方法,会在服务工厂类 `stop` 方法调用时被自动调用,用于销毁实例,如果不需要销毁实例,可以不实现。 ``` @Provide() @Scope(ScopeEnum.Singleton) export class HTTPClientServiceFactory extends ServiceFactory { // ... async destroyClient(client: HTTPClient, clientName: string) { // 销毁实例 } } ``` 除了实现 `destroyClient` 方法,还需要在生命周期中显式调用 `stop` 方法。 ``` import { Configuration } from '@midwayjs/core'; @Configuration({ imports: [ // ... ] }) export class ContainerConfiguration { private httpClientServiceFactory: HTTPClientServiceFactory; async onReady(container) { // 实例化服务类 this.httpClientServiceFactory = await container.getAsync(HTTPClientServiceFactory); } async onStop() { // 销毁服务类 if (this.httpClientServiceFactory) { await this.httpClientServiceFactory.stop(); } } } ``` ## 类型定义[​](#类型定义 "类型定义的直接链接") 在使用服务工厂时,我们需要正确定义类型。Midway 提供了 `ServiceFactoryConfigOption` 核心类型来帮助你定义服务工厂配置。 ``` import { ServiceFactoryConfigOption } from '@midwayjs/core'; // 定义 HTTPClient 配置 interface HTTPClientConfig { baseUrl: string; timeout?: number; } // 使用 ServiceFactoryConfigOption 定义配置 declare module '@midwayjs/core' { interface MidwayConfig { httpClient?: ServiceFactoryConfigOption; } } ``` --- # Midway Skill 使用 `@midwayjs/skill-midway` 是 Midway 官方提供的 AI Skill 包。 它主要解决两个问题: * 在项目里安装一份和当前 Midway 版本对应的 Skill * 在本地查询 Midway 的文档、API、包信息和变更记录 如果你希望在 Codex、Cursor、Trae 等 AI 编程工具里获得更稳定的 Midway 上下文,推荐在项目里安装这个包。 ## 安装依赖[​](#安装依赖 "安装依赖的直接链接") 在项目中安装依赖: ``` $ npm i @midwayjs/skill-midway@4 --save-dev ``` 或者在 `package.json` 中增加如下依赖后重新安装: ``` { "devDependencies": { "@midwayjs/skill-midway": "^4.0.0" } } ``` ## 安装到 AI 工具[​](#安装到-ai-工具 "安装到 AI 工具的直接链接") ### 交互式安装[​](#交互式安装 "交互式安装的直接链接") 如果你不确定要安装到哪个工具,可以直接执行: ``` $ npx midway-skill install ``` 命令会进入交互式选择,让你选择安装目标。 ### 指定安装目标[​](#指定安装目标 "指定安装目标的直接链接") 也可以显式指定目标。下面只是常见示例: ``` $ npx midway-skill install --target codex $ npx midway-skill install --target cursor $ npx midway-skill install --target trae ``` 如果你希望一次安装到所有已支持的工具: ``` $ npx midway-skill install --target all ``` 当前已支持的目标包括: ``` amazon-q antigravity auggie claude cline codebuddy codex continue costrict crush cursor factory gemini github-copilot iflow kilocode kiro opencode pi qoder qwen roocode trae windsurf ``` 默认安装是**项目级**的,会写入当前项目目录,而不是写入全局目录。 例如: * Codex: `.codex/skills/midway/SKILL.md` * Cursor: `.cursor/commands/opsx-midway.md` * Trae: `.trae/skills/midway/SKILL.md` 如果你后续升级了 `@midwayjs/skill-midway`,可以执行: ``` $ npx midway-skill update ``` 或者: ``` $ npx midway-skill update --target codex ``` ## 查询 Midway 文档和 API[​](#查询-midway-文档和-api "查询 Midway 文档和 API的直接链接") 这个包也提供了一组本地查询命令,适合给 AI 工具或脚本调用。 ### 解析版本[​](#解析版本 "解析版本的直接链接") 先解析用户请求的 Midway 版本: ``` $ npx midway-skill resolve-version 3.20.12 ``` 如果没有传版本,默认使用当前版本。 ### 查询文档[​](#查询文档 "查询文档的直接链接") ``` $ npx midway-skill lookup-docs --query "mcp" $ npx midway-skill lookup-docs --query "configuration" --locale en ``` ### 查询 API[​](#查询-api "查询 API的直接链接") ``` $ npx midway-skill lookup-api --symbol "Configuration" $ npx midway-skill lookup-api --symbol "MidwayMCPFramework" --package "@midwayjs/mcp" ``` ### 查询包信息[​](#查询包信息 "查询包信息的直接链接") ``` $ npx midway-skill lookup-packages --query "mcp" ``` ### 查询变更记录[​](#查询变更记录 "查询变更记录的直接链接") ``` $ npx midway-skill lookup-changelog --package "@midwayjs/mcp" ``` 所有查询命令都会输出 JSON,便于 AI 工具直接消费。 ## 版本说明[​](#版本说明 "版本说明的直接链接") * 当前 major 版本:支持 `docs + api + changelog` * 历史 major 版本:支持 `docs + changelog` 这意味着历史大版本通常不保证精确 API 查询。如果你查询的是旧版本 API,结果可能为空,这属于预期行为。 --- # 测试 应用开发中,测试十分重要,在传统 Web 产品快速迭代的时期,每个测试用例都给应用的稳定性提供了一层保障。 API 升级,测试用例可以很好地检查代码是否向下兼容。 对于各种可能的输入,一旦测试覆盖,都能明确它的输出。 代码改动后,可以通过测试结果判断代码的改动是否影响已确定的结果。 所以,应用的 Controller、Service 等代码,都必须有对应的单元测试保证代码质量。 当然,框架和组件的每个功能改动和重构都需要有相应的单元测试,并且要求尽量做到修改的代码能被 100% 覆盖到。 当前社区的测试库主要是 `jest` 和 `mocha` ,本文以 `jest` 作为示例 。 ## 测试目录结构[​](#测试目录结构 "测试目录结构的直接链接") 我们约定 `test` 目录为存放所有测试脚本的目录,测试所使用到的 `fixtures` 和相关辅助脚本都应该放在此目录下。 测试脚本文件统一按 `${filename}.test.ts` 命名,必须以 `.test.ts` 作为文件后缀。 一个应用的测试目录示例: ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.controller.test.ts ├── package.json └── tsconfig.json ``` ## 测试运行工具[​](#测试运行工具 "测试运行工具的直接链接") Midway 默认提供 `midway-bin` 命令来运行测试脚本。在新版本中,Midway 默认将 mocha 替换成了 Jest,它的功能更为强大,集成度更高,这让我们**聚焦精力在编写测试代码**上,而不是纠结选择那些测试周边工具和模块。 只需要在 `package.json` 上配置好 `scripts.test` 即可。 * 直接使用 jest * 使用 @midwayjs/cli ``` { "scripts": { "test": "jest" } } ``` 然后就可以按标准的 `npm test` 来运行测试了,默认脚手架中,我们都已经提供了此命令,所以你可以开箱即用的运行测试。 ``` ➜ my_midway_app npm run test > my_midway_project@1.0.0 test /Users/harry/project/application/my_midway_app > jest Testing all *.test.ts... PASS test/controller/home.controller.test.ts PASS test/controller/api.controller.test.ts Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.26 s Ran all test suites matching /\/test\/[^.]*\.test\.ts$/i. ``` ``` { "scripts": { "test": "midway-bin test --ts" } } ``` 然后就可以按标准的 `npm test` 来运行测试了,默认脚手架中,我们都已经提供了此命令,所以你可以开箱即用的运行测试。 ``` ➜ my_midway_app npm run test > my_midway_project@1.0.0 test /Users/harry/project/application/my_midway_app > midway-bin test Testing all *.test.ts... PASS test/controller/home.controller.test.ts PASS test/controller/api.controller.test.ts Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.26 s Ran all test suites matching /\/test\/[^.]*\.test\.ts$/i. ``` ## 断言库[​](#断言库 "断言库的直接链接") jest 中自带了强大的 `expect` 断言库,可以直接在全局使用它。 比如常用的。 ``` expect(result.status).toBe(200); // 值是否等于某个值,引用相等 expect(result.status).not.toBe(200); expect(result).toEqual('hello'); // 简单匹配,对象属性相同也为 true expect(result).toStrictEqual('hello'); // 严格匹配 expect(['lime', 'apple']).toContain('lime'); // 判断是否在数组中 ``` 更多断言方法,请参考文档 ## 创建测试[​](#创建测试 "创建测试的直接链接") 不同的上层框架的测试方法不同,以最常用的 HTTP 服务举例,如果需要测试一个 HTTP 服务,一般来说,我们需要创建一个 HTTP 服务,然后用客户端请求它。 Midway 提供了一套基础的 `@midwayjs/mock` 工具集,可以帮助上层框架在这方面进行测试。同时也提供了方便的创建 Framework,App ,以及关闭的方法。 整个流程方法分为几个部分: * `createApp` 创建某个 Framework 的 app 对象 * `close` 关闭一个 Framework 或者一个 app 为保持测试简单,整个流程目前就透出这两个方法。 ``` // create app const app = await createApp(); ``` 这里传入的 `Framework` 是用来给 TypeScript 推导类型的。这样就可以返回主框架 app 实例了。 当 app 运行完成后,可以使用 `close` 方法关闭。 ``` import { createApp, close } from '@midwayjs/mock'; await close(app); ``` 事实上, `createApp` 方法中都是封装了 `@midwayjs/bootstrap` ,有兴趣的小伙伴可以阅读源码。 ## 测试 HTTP 服务[​](#测试-http-服务 "测试 HTTP 服务的直接链接") 除了创建 app 之外, `@midwayjs/mock` 还提供了简单的客户端方法,用于快速创建各种服务对应的测试行为。 比如,针对 HTTP,我们封装了 supertest,提供了 `createHttpRequest` 方法创建 HTTP 客户端。 ``` // 创建一个客户端请求 const result = await createHttpRequest(app).get('/'); // 测试返回结果 expect(result.text).toBe('Hello Midwayjs!'); ``` 推荐在一个测试文件中复用 app 实例。完整的测试示例如下。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/koa'; import * as assert from 'assert'; describe('test/controller/home.test.ts', () => { let app: Application; beforeAll(async () => { // 只创建一次 app,可以复用 app = await createApp(); }); afterAll(async () => { // close app await close(app); }); it('should GET /', async () => { // make request const result = await createHttpRequest(app) .get('/') .set('x-timeout', '5000'); // use expect by jest expect(result.status).toBe(200); expect(result.text).toBe('Hello Midwayjs!'); // or use assert assert.deepStrictEqual(result.status, 200); assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); }); it('should POST /', async () => { // make request const result = await createHttpRequest(app) .post('/') .send({id: '1'}); // use expect by jest expect(result.status).toBe(200); }); }); ``` **示例:** 创建 get 请求,传递 query 参数。 ``` const result = await createHttpRequest(app) .get('/set_header') .query({ name: 'harry' }); ``` 创建 post 请求,传递 body 参数。 ``` const result = await createHttpRequest(app) .post('/user/catchThrowWithValidate') .send({id: '1'}); ``` 创建 post 请求,传递 form body 参数。 ``` const result = await createHttpRequest(app) .post('/param/body') .type('form') .send({id: '1'}) ``` 传递 header 头。 ``` const result = await createHttpRequest(app) .get('/set_header') .set({ 'x-bbb': '123' }) .query({ name: 'harry' }); ``` 传递 cookie。 ``` const cookie = [ "koa.sess=eyJuYW1lIjoiaGFycnkiLCJfZXhwaXJlIjoxNjE0MTQ5OTQ5NDcyLCJfbWF4QWdlIjo4NjQwMDAwMH0=; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly", "koa.sess.sig=mMRQWascH-If2-BC7v8xfRbmiNo; path=/; expires=Wed, 24 Feb 2021 06:59:09 GMT; httponly" ] const result = await createHttpRequest(app) .get('/set_header') .set('Cookie', cookie) .query({ name: 'harry' }); ``` ## 测试服务[​](#测试服务 "测试服务的直接链接") 在控制器之外,有时候我们需要对单个服务进行测试,我们可以从依赖注入容器中获取这个服务。 假设需要测试 `UserService` 。 ``` // src/service/user.ts import { Provide } from '@midwayjs/core'; @Provide() export class UserService { async getUser() { // xxx } } ``` 那么在测试代码中这样写。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 class 获取实例(推荐) const userService = await app.getApplicationContext().getAsync(UserService); // 根据依赖注入 Id 获取实例 const userService = await app.getApplicationContext().getAsync('userService'); // 传入 class 忽略泛型也能正确推导 const userService = await app.getApplicationContext().getAsync(UserService); // close app await close(app); }); }); ``` 如果你的服务和请求相关联(ctx),可以使用请求作用域获取服务。 ``` import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework } from '@midwayjs/web'; import * as assert from 'assert'; import { UserService } from '../../src/service/user'; describe('test/controller/home.test.ts', () => { it('should GET /', async () => { // create app const app = await createApp(); // 根据依赖注入 Id 获取实例 const userService = await app.createAnonymousContext() .requestContext.getAsync('userService'); // 也能传入 class 获取实例 const userService = await app.createAnonymousContext() .requestContext.getAsync(UserService); // close app await close(app); }); }); ``` ## createApp 选项参数[​](#createapp-选项参数 "createApp 选项参数的直接链接") `createApp` 方法用于创建一个框架的 app 实例,通过传入泛型的框架类型,来使得我们推断出的 app 能够是该框架返回的 app。 比如: ``` import { Framework } from '@midwayjs/grpc'; // 这里的 app 能确保是 grpc 框架返回的 app const app = await createApp(); ``` `createApp` 方法其实是有参数的,它的方法签名如下。 ``` async createApp( appDir = process.cwd(), options: IConfigurationOptions = {} ) ``` 第一个参数为项目的绝对根目录路径,默认为 `process.cwd()` 。 第二个参数为 Bootstrap 的启动参数,比如一些全局行为的配置,具体可以参考 ts 定义。 ## close 选项参数[​](#close-选项参数 "close 选项参数的直接链接") `close` 方法用于关闭该 app 实例相关的框架。 ``` await close(app); ``` 其有一些参数。 ``` export declare function close( app: IMidwayApplication | IMidwayFramework, options?: { cleanLogsDir?: boolean; cleanTempDir?: boolean; sleep?: number; }): Promise; ``` 第一个参数是 app 或者 framework 的实例。 第二个参数是个对象,在执行关闭时可以执行一些行为: * 1、 `cleanLogsDir` 默认为 false,控制测试完成后删除日志 logs 目录(windows 除外) * 2、 `cleanTempDir` 默认为 false,清理一些临时目录(比如 egg 生成的 run 目录) * 3、 `sleep` 默认为 50,单位毫秒,关闭 app 后延迟的时间(防止日志没有成功写入) ## 使用 bootstrap 文件测试[​](#使用-bootstrap-文件测试 "使用 bootstrap 文件测试的直接链接") 一般情况下,你无需用到 `bootstrap.js` 来测试。如果你希望直接使用 `bootstrap.js` 入口文件直接测试,那么可以在测试的时候传递入口文件信息。 和 dev/test 启动不同的是,使用 `bootstrap.js` 启动是一个真实的服务,会同时运行多个框架,创建出多个框架的 app 实例。 `@midwayjs/mock` 提供了 `createBootstrap` 方法做启动文件类型的测试。我们可以将入口文件 `bootstrap.js` 作为启动参数传入,这样 `createBootstrap` 方法会通过入口文件来启动代码。 ``` it('should GET /', async () => { // create app const bootstrap = await createBootstrap(join(process.cwd(), 'bootstrap.js')); // 根据框架类型获取 app 实例 const app = bootstrap.getApp('koa'); // expect and test // close bootstrap await bootstrap.close(); }); ``` ## 运行单个测试[​](#运行单个测试 "运行单个测试的直接链接") 和 mocha 的 `only` 不同,jest 的 `only` 方法只针对单个文件生效。 * 直接使用 jest * 使用 @midwayjs/cli 执行单个文件。 ``` $ jest test/controller/api.ts ``` 如果你想运行文件中的特定测试,你可以使用 jest 的 `-t` 或 `--testNamePattern` 选项,后面跟上你想运行的测试的名称。例如: ``` $ jest -t "name of your test" ``` 这将只运行名称匹配的测试。 `midway-bin` 提供可以运行单个文件的能力。 ``` $ midway-bin test -f test/controller/api.ts ``` 这样可以指定运行某个文件的测试,再配合 `describe.only` 和 `it.only` ,这样可以只运行单个文件中的单个测试方法。 `midway-bin test --ts` 等价于直接使用 jest 的下面的命令。 ``` $ node --require=ts-node/register ./node_modules/.bin/jest ``` ## 自定义 Jest 文件内容[​](#自定义-jest-文件内容 "自定义 Jest 文件内容的直接链接") 一般情况下,Midway 工具链内置了 jest 配置,使得用户无需再添加该文件,但是有些特殊的场景下,比如使用 VSCode 或者 Idea 等编辑器,需要在可视化区域进行开发和测试时,可能会需要指定一个 `jest.config.js` 的场景,这种情况下,Midway 支持创建一个自定义的 jest 配置文件。 在项目根目录创建一个 `jest.config.js` 文件。 ``` ➜ my_midway_app tree . ├── src ├── test │ └── controller │ └── home.test.ts ├── jest.config.js ├── package.json └── tsconfig.json ``` 内容如下,配置和标准的 jest 相同。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], }; ``` ## 常见设置[​](#常见设置 "常见设置的直接链接") 如果需要在单测前执行一些代码,可以增加 `jest.setup.js` ,增加配置如下。 ``` const path = require('path'); module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], setupFilesAfterEnv: ['/jest.setup.js'], // 预先读取 jest.setup.js }; ``` 警告 注意, `jest.setup.js` 只能使用 js 文件。 ### 示例一:测试代码时间较长的问题[​](#示例一测试代码时间较长的问题 "示例一:测试代码时间较长的问题的直接链接") 如果测试出现下面的错误,说明你的代码执行时间比较长(比如连接数据库,跑任务等),如果确定代码没有问题,就需要延长启动时间。 ``` Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout. ``` jest 默认时间为 **5000ms(5秒钟)**,我们可以将它调整到更多。 可以通过在 `package.json` 启动时修改。 * 直接使用 jest * 使用 @midwayjs/cli ``` { "scripts": { "test": "jest --testTimeout=30000" } } ``` ``` { "scripts": { "test": "midway-bin test --ts --testTimeout=30000" } } ``` 这里的 `testTimeout` 是 jest 的启动参数。 我们可以在 `jest.setup.js` 文件中写入下面的代码,对 jest 超时时间做调整。 ``` // jest.setup.js jest.setTimeout(30000); ``` ### 示例二:全局环境变量[​](#示例二全局环境变量 "示例二:全局环境变量的直接链接") 同理, `jest.setup.js` 也可以执行自定义的代码,比如设置全局环境变量。 ``` // jest.setup.js process.env.MIDWAY_TS_MODE = 'true'; ``` ### 示例三:程序无法正常退出的处理[​](#示例三程序无法正常退出的处理 "示例三:程序无法正常退出的处理的直接链接") 有时候,由于一些代码(定时器,监听等)在后台运行,导致单测跑完后会无法退出进程,对于这个情况,jest 提供了 `--forceExit` 参数。 * 直接使用 jest * 使用 @midwayjs/cli ``` $ jest --forceExit $ jest --coverage --forceExit ``` ``` $ midway-bin test --ts --forceExit $ midway-bin cov --ts --forceExit ``` 这里的 `testTimeout` 是 jest 的启动参数。 也可以在自定义文件中,增加属性。 ``` module.exports = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/test/fixtures'], coveragePathIgnorePatterns: ['/test/'], forceExit: true, }; ``` ### 示例四:并行改串行执行[​](#示例四并行改串行执行 "示例四:并行改串行执行的直接链接") jest 默认为每个测试文件并行处理,如果测试代码中有启动端口等场景,并行处理可能会导致端口冲突而报错,这个时候需要加 `--runInBand` 参数,注意,这个参数只能加载命令中。 * 直接使用 jest * 使用 @midwayjs/cli ``` $ jest --runInBand $ jest --coverage --runInBand ``` ``` $ midway-bin test --ts --runInBand $ midway-bin cov --ts --runInBand ``` ## 编辑器配置[​](#编辑器配置 "编辑器配置的直接链接") ### Jetbrain Webstorm/Idea 配置[​](#jetbrain-webstormidea-配置 "Jetbrain Webstorm/Idea 配置的直接链接") 在 Jetbrain 的编辑器使用,需要启用 "jest" 插件,由于使用了子进程的方式启动,我们依旧需要在启动时指定加载 `--require=ts-node/register` 。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01Wa6UaE1p0zU82gnpL_!!6000000005299-2-tps-1500-951.png) ### VSCode 配置[​](#vscode-配置 "VSCode 配置的直接链接") 先搜索插件,安装 Jest Runner。 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01D6zTxi1GiwwrqhHVW_!!6000000000657-2-tps-1242-877.png) 打开配置,配置 jest 命令路径。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN017BK54o1n2FL7x8hI0_!!6000000005031-2-tps-1266-849.png) 在 jest command 处填入 `node --require=ts-node/register ./node_modules/.bin/jest` 。 或者是在工作区文件夹 .vscode 里面设置 settings.json。 ``` { "jest.pathToJest": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles", "jestrunner.jestCommand": "node --require=ts-node/register ./node_modules/.bin/jest --detectOpenHandles" } ``` 由于 jest runner 插件的调试使用的是 VSCode 的调试,需要单独配置 VSCode 的 launch.json。 在文件夹 .vscode 里面设置 launch.json ``` { "version": "0.0.1", "configurations": [ { "name": "Debug Jest Tests", "type": "node", "request": "launch", "runtimeArgs": [ "--inspect-brk", "--require=ts-node/register", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "--detectOpenHandles" ], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] } ``` ## 关于 alias paths[​](#关于-alias-paths "关于 alias paths的直接链接") `mwtsc` 工具不支持 Alias Path 功能。 ## 关于 mock 数据[​](#关于-mock-数据 "关于 mock 数据的直接链接") 模拟数据是一个可以在开发和测试中都通用的能力,更多请查看 [模拟数据](/docs/mock.md)。 --- # Midway CLI 提示 由于 CLI 底层能力都来源于社区现有的模块功能,为了减少过渡封装带来的维护成本和理解成本,CLI 中的各项功能都将逐步变为社区现有的模块,同时 CLI 库将停止继续迭代。 为此后续的变化为 * 开发将从 `midway-bin dev` 变为 `mwtsc` * 编译将从 `midway-bin build` 变为 `tsc` * 测试将从 `midway-bin test` 变为 `mocha` 或者 `jest` * 覆盖率将从 `midway-bin cov` 变为 `jest --coverage` 或者其他类似指令 `@midwayjs/cli` 是新版本的 Midway 体系工具链,和 Serverless,以及原应用的工具链进行了整合。 ## 基础入口[​](#基础入口 "基础入口的直接链接") `@midwayjs/cli` 提供了两个入口命令。 `midway-bin` 和 `mw` 命令。 当 `@midwayjs/cli` 安装到全局时,一般使用 `mw` 命令,比如 `mw dev` 。当安装到项目中,做 cli 工具时,我们一般使用 `midway-bin` 命令,但是请记住,这两个命令是相同的。 ## dev 命令[​](#dev-命令 "dev 命令的直接链接") 以当前目录启动本地开发命令。 ``` $ mw dev --baseDir 应用目录,一般为 package.json 所在文件夹,默认为 process.cwd() --sourceDir ts代码目录,默认会自动分析 -p, --port dev侦听的端口,默认为 7001 --ts TS模式运行代码 --fast 极速模式 --framework 指定框架,默认会自动分析 -f, --entryFile 指定使用入口文件来启动 bootstrap.js --watchFile 更多的文件或文件夹修改侦听 --notWatch 代码变化时不自动重启 ``` ### **标准启动**[​](#标准启动 "标准启动的直接链接") ``` $ midway-bin dev --ts ``` ### **修改启动端口**[​](#修改启动端口 "修改启动端口的直接链接") 针对 HTTP 场景, `-p` 或者 `--port` 可以临时修改端口。 ``` $ midway-bin dev --ts --port=7002 ``` ### **修改启动路径**[​](#修改启动路径 "修改启动路径的直接链接") 指定应用根目录,一般为 package.json 所在文件夹,默认为 process.cwd() ``` $ midway-bin dev --ts --baseDir=./app ``` ### **修改ts源码路径**[​](#修改ts源码路径 "修改ts源码路径的直接链接") 指定ts代码目录,默认会自动分析 ``` $ midway-bin dev --ts --sourceDir=./app/src ``` ### **修改 tsconfig.json 的位置**[​](#修改-tsconfigjson-的位置 "修改-tsconfigjson-的位置的直接链接") 通过设置 [TS\_NODE\_PROJECT](https://github.com/TypeStrong/ts-node#project) 环境变量来指定tsconfig.json的位置。 ``` $ cross-env TS_NODE_PROJECT=./tsconfig.dev.json midway-bin dev -ts ``` ### **更快的启动方式**[​](#更快的启动方式 "更快的启动方式的直接链接") 默认的启动方式为 ts-node,在文件数量特别多的情况下会比较慢,可以切换为 swc 等新的编译方式。 ``` // 使用 ts-node 的快速dev模式 $ midway-bin dev --ts --fast // 使用 swc 的快速dev模式 $ midway-bin dev --ts --fast=swc ``` ### 监听文件变化[​](#监听文件变化 "监听文件变化的直接链接") `--watchFile` 用于指定更多的文件或文件夹修改侦听,默认侦听 `sourceDir` 目录中 `.ts`、`.yml`和 `.json`结尾的文件(可通过 --watchExt 参数指定更多扩展名),以及 `baseDir` 目录中的 `f.yml` 文件 ``` // 指定多个文件,使用英文逗号分隔 $ midway-bin dev --ts --watchFile=./a.txt,./b.txt // 指定多个文件夹和文件,使用英文逗号分隔 $ midway-bin dev --ts --watchFile=./test,./b.txt ``` * `--watchExt`:指定更多的侦听文件扩展名,默认为 `.ts`、`.yml`和 `.json` ``` // 指定多个文件扩展名,使用英文逗号分隔 $ midway-bin dev --ts --watchExt=.js,.html ``` ### 本地单步Debug调试[​](#本地单步debug调试 "本地单步Debug调试的直接链接") `--debug` 参数启动 debug 模式,可以通过 `chrome devtools` 进行单步代码调试: ![69456694-513D-4388-B52F-001562D4A520.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994136312-f1eda8ba-165d-4322-82b8-b21d3b9c6beb.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=177\&id=z4u1f\&margin=%5Bobject%20Object%5D\&name=69456694-513D-4388-B52F-001562D4A520.png\&originHeight=666\&originWidth=1538\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=276022\&status=done\&style=none\&taskId=ud161d835-1e96-4246-8061-c795e9a0ff1\&title=\&width=409) 您可以通过 `chrome://inspect/` 打开 `nodejs devtools` 进行断点调试: ![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995391144-a9ec0d4a-c6fb-4638-a292-615a3588d33d.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=236\&id=u4986bfa4\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=942\&originWidth=1948\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=572568\&status=done\&style=none\&taskId=u07555349-8e09-42b2-bd94-f93160b0431\&title=\&width=488) ![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635995418427-282d256a-de65-4eba-9a83-b474d3d74f9f.png#clientId=u069cda7c-313b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=445\&id=u83271ad1\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1280\&originWidth=2280\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=710504\&status=done\&style=none\&taskId=uc2614db9-dea9-48d7-b87d-8cb608c8770\&title=\&width=792) 您也可以直接通过 chrome 浏览器打开命令行中输出的 `devtools` 协议的链接,给对应代码添加断点后调试: ![10016148-385E-46A4-8B3A-0A0110BECD18.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1635994137067-f663409a-483d-41f5-bc86-4798182edb38.png#clientId=u32db4720-b7d0-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=ui\&height=135\&id=GooAh\&margin=%5Bobject%20Object%5D\&name=10016148-385E-46A4-8B3A-0A0110BECD18.png\&originHeight=950\&originWidth=2878\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=744085\&status=done\&style=none\&taskId=u892d9925-9206-4946-a1ed-cb6043c557d\&title=\&width=409) 如果您使用 `vscode` ,那么您可以使用 vscode 的 js debug terminal,在其中执行 dev 命令(无需添加 `--debug` 参数)启动就可以打断点调试了。![image.png](https://cdn.nlark.com/yuque/0/2021/png/128621/1625237917317-8e7bf448-fded-4bc7-b743-6aade0ebcba2.png#clientId=u7c8a3183-c32b-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=650\&id=u75e3aec7\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=1300\&originWidth=2868\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=1140427\&status=done\&style=none\&taskId=ubcffa6c8-02eb-4256-ba7e-7ab3128c1ee\&title=\&width=1434) ## test 命令[​](#test-命令 "test 命令的直接链接") 以当前目录启动测试,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin test --ts -c, --cov 获取代码测试覆盖率 -f, --file 指定测试文件,例如 ./test/index.test.ts --ts TS模式运行单测 --forceExit jest forceExit --runInBand jest runInBand -w, --watch watch模式 --mocha 使用 mocha 进行单测 ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 信息 如果项目中使用了 TypeScript 的 path alias,请参考:[测试](/docs/testing.md#%E9%85%8D%E7%BD%AE-alias-paths) ### 使用 mocha 替代 jest[​](#使用-mocha-替代-jest "使用 mocha 替代 jest的直接链接") 有些同学对 mocha 情有独钟,希望使用 mocha 作为测试工具。 可以使用 mocha 模式进行测试。 ``` $ midway-bin test --ts --mocha ``` 使用 mocha 进行单测时,需要手动安装 `mocha` 和 `@types/mocha` 两个依赖到 `devDependencies` 中:`npm i mocha @types/mocha -D` 。 ### 配置 alias paths[​](#配置-alias-paths "配置 alias paths的直接链接") 当你在 `tsconfig.json` 中配置了 paths 之后,并且模块包导入使用了 paths ,则会存在 mocha 做单元测试会导致路径无法被解析,无法使用通过导入 `tsconfig-paths/register` 解决 ``` // src/configuration.ts import 'tsconfig-paths/register'; // ... ``` 需要添加 `tsconfig-paths` 并且在测试的时候引用进行处理 ``` $ npm install --save-dev tsconfig-paths ``` ``` $ midway-bin test --ts --mocha -r tsconfig-paths/register ``` 信息 注意,由于 mocha 没有自带断言工具,需要使用其他如 assert,chai 等工具进行断言。 ## cov 命令[​](#cov-命令 "cov 命令的直接链接") 以当前目录启动测试,并输出覆盖率信息,默认使用 jest 工具,可以使用 --mocha 参数指定使用 mocha。 ``` $ midway-bin cov --ts ``` 当使用 mocha 进行单测覆盖率时,您需要安装以下额外依赖。 ``` $ npm i mocha @types/mocha nyc --save-dev ``` ## check 命令[​](#check-命令 "check 命令的直接链接") 自动分析代码中存在的问题,并给出修复建议。 ``` $ midway-bin check ``` 目前已提供 `32` 项问题的校验。 ## build 命令[​](#build-命令 "build 命令的直接链接") 使用 mwcc(tsc)进行 ts 代码编译,适用于标准项目,Serverless 项目请使用 package。 ``` $ midway-bin build -c -c, --clean 清理构建结果目录 --srcDir 源代码目录,默认 src --outDir 构建输出目录,默认为 tsconfig 中的 outDir 或 dist --tsConfig tsConfig json 字符串或文件位置 --buildCache 保留构建缓存 ``` ## deploy 命令[​](#deploy-命令 "deploy 命令的直接链接") 适用于 Serverless 项目发布到 Aliyun FC、Tencent SCF、Aws Lambda 等运行时。 执行 deploy 命令会自动执行 package。 ``` $ midway-bin deploy -y, --yes 发布的确认都是yes --resetConfig 重置发布配置,AK/AK/Region等 --serverlessDev 使用 Serverless Dev 进行aliyun fc函数发布,目前默认为 funcraft ...兼容package命令的所有参数 ``` #### 函数发布时域名配置[​](#函数发布时域名配置 "函数发布时域名配置的直接链接") 在 `f.yml` 中配置 `custom.customDomain` 为 `auto` ,则在发布时会配置一个临时的自动域名: ``` custom: customDomain: auto ``` 如果要取消自动的域名,将 `customDomain` 改为 `false`: ``` custom: customDomain: false ``` 如果有自定义域名,在 `customDomain` 中配置即可: ``` custom: customDomain: domainName: test.example.com ``` 如果自定义的域名,需要使用 https,那么在 云控制台 配置好 https 证书之后,需要将 customDomain 设置为 false,避免下次发布时重置成 http: ``` custom: customDomain: false ``` #### 每个路由都部署成了一个函数[​](#每个路由都部署成了一个函数 "每个路由都部署成了一个函数的直接链接") 可以使用高密度方案,合并成一个函数,f.yml 加如下配置 ``` aggregation: main: functionsPattern: - '*' ``` #### #### aliyun 发布 AK 错误问题[​](#aliyun-发布-ak-错误问题 "aliyun 发布 AK 错误问题的直接链接") 在第一次进行aliyun发布或使用 `--resetConfig`参数的时候都可以重置 ak。 不过要注意的是每次 ak 都会默认创建一个新的 `access` 分组,在修改配置时会自动生成分组名,如果要覆盖之前的 AK 需要手动输入,如图: ![image.png](https://cdn.nlark.com/yuque/0/2022/png/128621/1645609990378-8a7f92c0-bda4-46e0-93a6-4d6feb6ec66d.png#clientId=u9f50c864-5385-4\&crop=0\&crop=0\&crop=1\&crop=1\&from=paste\&height=122\&id=u8a756167\&margin=%5Bobject%20Object%5D\&name=image.png\&originHeight=122\&originWidth=693\&originalType=binary\&ratio=1\&rotation=0\&showTitle=false\&size=17245\&status=done\&style=none\&taskId=u3b825703-abe6-4a2b-ae5f-86a88027cf8\&title=\&width=693) 发布时默认使用的分组为 `default`,如果您在修改配置时如上图使用了 `default-2`,那么需要在发布的时候通过 `--access`参数指定使用 `default-2`: ``` midway-bin deploy --access=default-2 ``` ## package 命令[​](#package-命令 "package 命令的直接链接") 适用于 Serverless 项目构建 ``` $ midway-bin package --npm npm client,默认为自动识别添加registry --sourceDir 源代码所在目录,默认会自动分析 --buildDir 构建结果目标目录 --sharedTargetDir 共享文件目标目录,默认为static,参考 --sharedDir 参数 --sharedDir 构建时会拷贝此目录到结果目录内的 $sharedTargetDir 目录 --skipZip 跳过zip打包 --skipBuild 跳过ts代码构建 --tsConfig tsConfig json 字符串或文件位置 --function 指定打包哪几个函数,多个使用英文 , 分隔 ``` #### 参数详解[​](#参数详解 "参数详解的直接链接") * `--function`:指定打包哪几个函数,多个函数使用英文 , 分隔 ``` // 打包 midway-bin package --function=a,b,c // 发布 midway-bin deploy --function=a,b,c ``` #### 函数构建打包时文件拷贝逻辑[​](#函数构建打包时文件拷贝逻辑 "函数构建打包时文件拷贝逻辑的直接链接") 默认拷贝的内容包含 `后端代码文件夹` (一般为 `src` 、faas前后端一体化一般为 `src/apis`)内的所有非 `.ts` 后缀的文件,以及 `项目根目录` 下的以 `.js`、`.json`、`.yml` 为扩展名的所有文件和 `config` 、`app` 文件夹内的所有文件。 如果要拷贝额外的文件,可以通过在 `f.yml` 文件中添加 `package`字段 中的 `include` 来指定,可以配置文件名,也可以通过 `fast-glob` [语法↗](https://github.com/mrmlnc/fast-glob#pattern-syntax) 匹配,使用示例如下: ``` # ...已省略其他属性的展示 package: include: # 通过 include 属性指定额外打包文件配置 - static # 项目根目录下的 static 文件夹 - a.json # 项目根目录下的 a.json 文件 - a/b/c.js # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - a/b/c.json # 项目根目录下的 a 目录下的 b 目录下的 c.js 文件 - xxx/**/*.js # 项目根目录下的 xxx 目录下的所有 js 文件 ``` ## 实验性功能[​](#实验性功能 "实验性功能的直接链接") 在 `f.yml` 中通过 `experimentalFeatures` 配置开启实验性功能 ### 1. ignoreTsError[​](#1-ignoretserror "1. ignoreTsError的直接链接") 在构建时忽略ts error,不中断构建过程。 ``` experimentalFeatures: ignoreTsError: true ``` ### 2. removeUselessFiles[​](#2-removeuselessfiles "2. removeUselessFiles的直接链��接") 在构建时移除大量无效文件,例如 `LICENSE`、`*.ts.map`、`**/test/` 等文件,可以有效减少构建包尺寸。 ``` experimentalFeatures: removeUselessFiles: true ``` ### 3. fastInstallNodeModules[​](#3-fastinstallnodemodules "3. fastInstallNodeModules的直接链接") 在构建时从当前的 devDependencies 中挑选出 production 依赖进行发布,可能会显著提升发布速度。 ``` experimentalFeatures: fastInstallNodeModules: true ``` ## CLI 扩展[​](#cli-扩展 "CLI 扩展的直接链接") ### 1. 生命周期扩展[​](#1-生命周期扩展 "1. 生命周期扩展的直接链接") 用户可以在 `package.json` 中添加 `midway-integration` 字段来根据各个命令的生命周期扩展 cli 的行为。 比如,在 package 命令 `installDevDep` 的后面添加自定义逻辑: ``` { "midway-integration": { "lifecycle": { "after:package:installDevDep": "npm run build" } } } ``` 其中 `lifecycle` 的格式为 `${ 'before' | 'after' | '' }:${ 命令 }:${ 命令生命周期 }` 。 package命令的声明周期列表: ``` 'cleanup', // 清理构建目录 'installDevDep', // 安装开发期依赖 'copyFile', // 拷贝文件: package.include 和 shared content 'compile', // 'emit', // 编译函数 'package:after:tscompile' 'analysisCode', // 分析代码 'copyStaticFile', // 拷贝src中的静态文件到dist目录,例如 html 等 'checkAggregation', // 检测高密度部署 'generateSpec', // 生成对应平台的描述文件,例如 serverless.yml 等 'generateEntry', // 生成对应平台的入口文件 'installLayer', // 安装layer 'installDep', // 安装依赖 'package', // 函数打包 'finalize', // 完成 ``` ### 2. 通过插件进行扩展[​](#2-通过插件进行扩展 "2. 通过插件进行扩展的直接链接") 用户可以自己编写 cli 插件,通过插件来实现更为复杂的 cli 的行为,也可以添加自定义命令。 目前支持两种插件: * npm 插件,插件是一个npm包 * local 插件,插件在本地位置 * 通过在 f.yml 文件中配置 `plugins` 字段使 cli 加载插件: ``` plugins: - npm::test-plugin-model - local::./test/plugin ``` plugin 配置格式为: `${ 'npm' | 'local' }:${ provider || '' }:${ pluginName || path }` 插件的代码参考: ``` // src/index.ts import { BasePlugin } from '@midwayjs/command-core'; export class TestLalalaPlugin extends BasePlugin { commands = { lalala: { usage: '自定义命令', lifecycleEvents: [ 'a', // 自定义生命周期 'b', ], // 暂无 options: { name: { usage: '参数 name, 例如: mw lalala --name=123', shortcut: 'n', // 参数缩写 }, }, }, }; hooks = { // 添加当前插件内的命令生命周期扩展 // lalala 命令的 a 生命周期 'lalala:a': async () => { // 输出 this.core.cli.log('lalala command hook'); // 获取用户输入的参数 this.core.cli.log(this.core.options); // f.yml 内容 this.core.cli.log(this.core.service); // 仅在 -V 参数下输出的内容 this.core.debug('lalala'); }, // 添加其他插件内的命令生命周期扩展 // 在 package 命令的 copyFile 生命周期 “之前” 执行 'before:package:copyFile': async () => { console.log('package command hook'); }, }; } ``` --- # 脚手架 Midway 编写了 `create-midway` 包,通过 npx 命令,可以方便的使用 `npm init midway` 命令创建脚手架。 ``` $ npm init midway@latest -y ``` 提示 如果不加 @latest 的 tag,可能不会更新到最新版本。 ## 通过 CLI 创建脚手架[​](#通过-cli-创建脚手架 "通过 CLI 创建脚手架的直接链接") ### 默认行为[​](#默认行为 "默认行为的直接链接") 不传递参数,可以列出当前最常用的模版列表。 比如执行 ``` $ npm init midway@latest -y ``` 会进入模板选择界面。当前文档以 v4 为准,默认会优先展示最新模板。下面的输出为示意,具体列表以 CLI 实际输出为准。 ``` ➜ ~ npm init midway@latest ? Hello, traveller. Which template do you like? … ⊙ v4 ❯ koa-v4 - A web application boilerplate with midway v4(koa) koa-v4-esm - A web application boilerplate with midway v4(koa) react-functional-v4 - A functional web application boilerplate with midway v4(react) vue-functional-v4 - A functional web application boilerplate with midway v4(vue) ``` 该模式下,会根据用户选择,按照指引创建模版。 ### 关于参数传递[​](#关于参数传递 "关于参数传递的直接链接") 由于 `npm init midway` 等价与 `npm exec create-midway`,根据不同的 npm 版本,[传递参数](https://docs.npmjs.com/cli/v10/commands/npm-exec) 的格式不同。 比如在最新的 npm 中,使用额外的 `--` 传递参数。 比如 ``` $ npm init midway -- -h ``` `-h` 参数可以显式所有的可用选项。 下面所有的参数示例,都将以这个模式展示。 ### 显式所有模版[​](#显式所有模版 "显式所有模版的直接链接") 非当前版本的模版,会默认隐藏,可以通过 `-a` 参数展示所有内置的模版。 ``` $ npm init midway -- -a ``` ### 指定模版名[​](#指定模版名 "指定模版名的直接链接") 每个模版都有一个模版名和模版描述,比如 `koa-v4 - A web application boilerplate with midway v4 (koa)` 的模板名为 `koa-v4`。 可以通过 `--type` 参数指定模板名。 ``` $ npm init midway -- --type=koa-v4 ``` ### 指定模版包名[​](#指定模版包名 "指定模版包名的直接链接") 当自定义模版在 npm 上发布时,我们可以使用 `-t` 或者 `--template` 来指定包名。 ``` $ npm init midway -- -t=custom-template ``` 如果包还在本地开发,也可以指定一个相对路径或者绝对路径。 ``` $ npm init midway -- -t=./custom-template ``` ### 指定创建目标目录[​](#指定创建目标目录 "指定创建目标目录的直接链接") 通过 `--target` 参数可以指定创建的目录,必须和 `type` 或者 `template` 参数一同使用。 比如,下面的命令指定了 `koa-v4` 模版,将其生成到当前 `abc` 目录下,如果目录不存在,则会新建。 ``` $ npm init midway -- --type=koa-v4 --target=abc ``` 一般 `target` 可以省略,把路径放到最后一个参数即可。 ``` $ npm init midway -- --type=koa-v4 abc ``` ### 指定客户端[​](#指定客户端 "指定客户端的直接链接") 如果有私有客户端,可以使用 `--npm` 指定客户端。 ``` $ npm init midway -- --npm=tnpm ``` ### 指定源[​](#指定源 "指定源的直接链接") 如果有私有源,可以使用 `--registry` 指定私有源。 ``` $ npm init midway -- --registry=https://registry.npmmirror.com ``` ### 脚手架参数[​](#脚手架参数 "脚手架参数的直接链接") 如果脚手架中包含用户可传递的参数,也可以通过命令行传递。 ``` $ npm init midway -- --bbb=ccc ``` 如果参数名和工具的参数重复了,可以使用 `t_` 的参数,在工具传递给脚手架时,会自动处理。 ``` $ npm init midway -- --type=koa-v4 --t_type=ccc ``` ## 编写脚手架[​](#编写脚手架 "编写脚手架的直接链接") Midway 脚手架使用了自研的 light-generator 工具,具体的使用可以参考 。 也可以参考 Midway 自己的 [模版工程](https://github.com/midwayjs/midway-boilerplate)。 --- # egg:ts-helper 针对 midway 支持 Egg.js 的场景,重写了原 [egg-ts-helper](https://github.com/whxaxes/egg-ts-helper) 包,移除了原有的 TS,AST 分析等大依赖。 原来的包依赖的 ts v3 环境,依赖 egg 的目录结构,考虑非常多的可能性,在 midway 的场景中不会使用到。基于上述考虑 midway 将此包进行了重写,用最简单的方式提供 egg 定义。 [@midwayjs/egg-ts-helper](https://github.com/midwayjs/egg-ts-helper) 包提供 `ets` 全局命令。 ``` $ npm i @midwayjs/egg-ts-helper --save-dev $ ets ``` 一般我们会在开发命令里加入。 ``` "scripts": { "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", }, ``` 信息 此包是针对 midway 定制的,只能用于新版本 midway 及其配套代码。 最终会在项目根目录生成 `typings` 目录,其定义结构和文件如下: ``` . ├── ... └── typings ├── extend │ ├── request.d.ts │ ├── response.d.ts │ ├── application.d.ts │ └── context.d.ts ├── app │ └── index.d.ts └── config ├── index.d.ts └── plugin.d.ts ``` 警告 注意,该模块只是将 midway v2(Egg.js)的框架 + 插件定义聚合到一起,让当前的业务代码能够顺利的读取到框架和插件的定义,不支持生成业务代码本身的定义,也不支持在开发 egg 插件时生成定义。 --- # 规则检查工具 Midway 为常见的错误提供了一些检查工具,以方便用户快速排错。`@midwayjs/luckyeye` 包提供了一些基础的检查规则,配合 Midway 新版本可以快速排查问题。 > luckyeye,寓意为幸运眼,能快速发现和定位问题。 ## 使用[​](#使用 "使用的直接链接") 首先安装 `@midwayjs/luckyeye` 包。 ``` npm i @midwayjs/luckyeye --save-dev ``` 一般情况下,我们会将它加入到一个检查脚本中,比如: ``` "scripts": { // ...... "check": "luckyeye" }, ``` 接下去,我们需要配置“规则包”,比如 `midway_v2` 就是针对 midway v2 版本的规则检查包。 在 `package.json` 中加入下面的段落。 ``` "midway-luckyeye": { "packages": [ "midway_v2" ] }, ``` ## 执行[​](#执行 "执行的直接链接") 配置完后,可以执行上面添加的检查脚本。 ``` npm run check ``` **蓝色**代表输出的信息,用于排错,**绿色**代表检查项通过,**红色**代表检查项有问题,需要修改,**黄色**代表检查项可以做修改,但是可选。 执行效果如下。 ![](https://cdn.nlark.com/yuque/0/2021/png/501408/1610983986151-79c54e7c-3ff0-4f94-98bc-359dda0fa694.png) ## 自定义规则包[​](#自定义规则包 "自定义规则包的直接链接") 请参考 的 README。 --- # Lint 和格式化 Midway 的框架和业务代码主要由 TypeScript 编写,默认使用 [mwts](https://github.com/midwayjs/mwts) 统一 lint 和格式化。 ## 代码风格库[​](#代码风格库 "代码风格库的直接链接") `mwts` 是 Midway 的 TypeScript 规范工具链,提供: * ESLint 检查(`check` / `lint`) * 自动修复(`fix`) * 默认格式化配置(默认 `Prettier + ESLint`) `mwts` 的设计思路来源于 [gts](https://github.com/google/gts),但不直接依赖 `gts` 包。 信息 在 Midway 项目中,一般脚手架会默认集成 `mwts`,这里主要说明配置方式和升级方式。 ## 依赖与运行时要求[​](#依赖与运行时要求 "依赖与运行时要求的直接链接") `mwts 2.x` 建议搭配: ``` { "engines": { "node": ">=20" }, "devDependencies": { "mwts": "^2.0.0", "typescript": "^5.0.0" } } ``` ## 初始化与迁移[​](#初始化与迁移 "初始化与迁移的直接链接") 新项目可直接初始化: ``` npx mwts init ``` 如果是历史 `mwts 1.x` 项目(`.eslintrc.json`),可执行一次迁移: ``` npx mwts migrate ``` 迁移后会生成 `eslint.config.js`(ESLint Flat Config)。 ## ESLint 配置(mwts 2.x)[​](#eslint-配置mwts-2x "ESLint 配置(mwts 2.x)的直接链接") `mwts 2.x` 使用 `eslint.config.js`,推荐配置如下(可按项目调整 `ignores`): ``` const mwtsConfig = require('mwts/eslint.config.js'); module.exports = [ { ignores: ['**/node_modules', '**/dist'], }, ...mwtsConfig, ]; ``` 如果你的项目使用 Jest,建议按需为测试文件增加 globals: ``` const globals = require('globals'); module.exports = [ ...require('mwts/eslint.config.js'), { files: ['**/*.test.ts', '**/*.spec.ts', '**/jest.setup.js'], languageOptions: { globals: { ...globals.jest, }, }, }, ]; ``` ## 执行检查和修复[​](#执行检查和修复 "执行检查和修复的直接链接") 常用脚本如下(仓库一般已内置): ``` { "scripts": { "lint": "mwts check", "lint:fix": "mwts fix" } } ``` `mwts check/lint/fix` 也支持单文件参数,例如: ``` mwts check src/index.ts mwts fix src/index.ts ``` ## Prettier 配置[​](#prettier-配置 "Prettier 配置的直接链接") 默认模式下,保留 `.prettierrc.js`: ``` module.exports = { ...require('mwts/.prettierrc.json'), }; ``` ## 可选 formatter 模式[​](#可选-formatter-模式 "可选 formatter 模式的直接链接") `mwts init` 支持三种模式: * 默认:`Prettier + ESLint` * `--formatter stylistic`:`ESLint + Stylistic` * `--formatter biome`:`Biome + ESLint` 未使用默认模式时,按生成的配置文件执行即可。 --- # 开发工具 基于标准的 tsc 模块,midway 开发了一个简单的工具,用于本地开发和构建 ts 文件。 它的使用和标准 tsc 几乎一致。 ``` $ npx mwtsc ``` 等价于执行 `tsc` 命令。 ## 常用命令[​](#常用命令 "常用命令的直接链接") 由于 mwtsc 基于 tsc 进行开发,它可以使用所有 tsc 的命令。 比如 ``` # 监听模式 $ npx mwtsc --watch # 使用不同的 tsconfig 文件 $ npx mwtsc --project tsconfig.production.json ``` 更多的参数可以查询 [tsc cli 工具](https://www.typescriptlang.org/docs/handbook/compiler-options.html)。 下面介绍更多 midway 新增的参数。 ## 运行指令[​](#运行指令 "运行指令的直接链接") 为了使得 tsc 在代码开发期生效,midway 提供了一个 `run` 参数,用于在 tsc 编译成功后执行一个文件,这和 `tsc-watch` 模块类似。 比如 ``` $ mwtsc --watch --run @midwayjs/mock/app.js ``` 上述命令会执行下面的逻辑: * 1、编译代码,编译成功后执行 `@midwayjs/mock/app.js` 文件 * 2、如果修改代码,则会自动触发编译,杀掉上一次执行的文件之后,自动执行 `@midwayjs/mock/app.js` 文件 `run` 参数可以执行任意的 js 文件,midway 依靠这个参数本地开发。 比如 ``` $ npx mwtsc --watch --run ./bootstrap.js ``` 当然也可以配合其他参数一起使用。 ``` $ npx mwtsc --watch --project tsconfig.production.json --run ./bootstrap.js ``` 注意 `run` 命令必须放在最后,它之后的所有参数,都将传递给子进程。 ## 框架配置[​](#框架配置 "框架配置的直接链接") 可以在 Midway 项目中用 mwtsc 进行开发测试,比如: ``` { "scripts": { "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app", "build": "cross-env rm -rf dist && tsc" }, } ``` 这里的 `@midwayjs/mock/app` 指代的是 `@midwayjs/mock` 包中的 `app.js` 文件,这个文件用于本地开发时启动框架。针对 Serverless 环境,也有相应的启动文件。 ``` { "scripts": { "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/function", }, } ``` ## 常用能力[​](#常用能力 "常用能力的直接链接") ### 调整端口[​](#调整端口 "调整端口的直接链接") 可以通过参数 `--port` 动态修改启动的 http 端口,这个参数的优先级高于代码中的端口配置。 ``` $ npx mwtsc --watch --run @midwayjs/mock/app --port 7001 ``` ### 开启 https[​](#开启-https "开启 https的直接链接") 框架内置了一个 https 证书用来本地测试,可以通过参数 `--ssl` 启用。 ``` $ npx mwtsc --watch --run @midwayjs/mock/app --ssl ``` --- # sequelize-auto-midway forked from [sequelize/sequelize-auto](https://github.com/sequelize/sequelize-auto) 通过已存在的数据库生成用于 `Midway` 的 `Sequelize` 实体。 其他详细文档和用法请参考 [sequelize/sequelize-auto](https://github.com/sequelize/sequelize-auto) ## Installation[​](#installation "Installation的直接链接") ``` $ npm i sequelize-auto-midway ``` ## Usage[​](#usage "Usage的直接链接") ``` # 推荐 # 请替换配置信息 npx sequelize-auto-midway -h localhost -d yourDBname -u root -x yourPassword -p 13306 --dialect mysql -o ./models --noInitModels true --caseModel c --caseProp c --caseFile c --indentation 1 -a ./additional.json ``` additional.json ``` { "timestamps": true, "paranoid": true } ``` 自动生成的模板文件如下: ``` import { Column, DataType, Table, Model } from 'sequelize-typescript'; @Table({ tableName: 'task', timestamps: false, indexes: [ { name: 'PRIMARY', unique: true, using: 'BTREE', fields: [{ name: 'task_id' }], }, ], }) export class TaskEntity extends Model { @Column({ autoIncrement: true, type: DataType.INTEGER.UNSIGNED, allowNull: false, primaryKey: true, field: 'task_id', }) taskId: number; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务所属应用ID: 0-无所属', field: 'app_id', }) appId: number; @Column({ type: DataType.STRING(64), allowNull: false, comment: '任务名称', field: 'task_name', }) taskName: string; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务类别:1-cron,2-interval', }) type: number; @Column({ type: DataType.TINYINT.UNSIGNED, allowNull: false, defaultValue: 0, comment: '任务状态:0-暂停中,1-启动中', }) status: number; @Column({ type: DataType.DATE, allowNull: true, comment: '任务开始时间', field: 'start_time', }) startTime: string; @Column({ type: DataType.DATE, allowNull: true, comment: '任务结束时间', field: 'end_time', }) endTime: string; @Column({ type: DataType.INTEGER, allowNull: false, defaultValue: -1, comment: '任务执行次数', }) limit: number; @Column({ type: DataType.STRING(128), allowNull: true, defaultValue: '', comment: '任务cron配置', }) cron: string; @Column({ type: DataType.INTEGER.UNSIGNED, allowNull: true, defaultValue: 0, comment: '任务执行间隔时间', }) every: number; @Column({ type: DataType.STRING(255), allowNull: true, comment: '参数', }) args: string; @Column({ type: DataType.STRING(255), allowNull: true, comment: '备注', }) remark: string; } ``` Use `npx sequelize-auto-midway --help` to see all available parameters with their descriptions. Some basic parameters below: ``` Usage: npx sequelize-auto-midway -h -d -p [port] -u -x [password] -e [engine] Options: --help Show help [boolean] --version Show version number [boolean] -h, --host IP/Hostname for the database. [string] -d, --database Database name. [string] -u, --user Username for database. [string] -x, --pass Password for database. If specified without providing a password, it will be requested interactively from the terminal. -p, --port Port number for database (not for sqlite). Ex: MySQL/MariaDB: 3306, Postgres: 5432, MSSQL: 1433 [number] -c, --config Path to JSON file for Sequelize-Auto options and Sequelize's constructor "options" flag object as defined here: https://sequelize.org/master/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor [string] -o, --output What directory to place the models. [string] -e, --dialect The dialect/engine that you're using: postgres, mysql, sqlite, mssql [string] -a, --additional Path to JSON file containing model options (for all tables). See the options: https://sequelize.org/master/class/lib/model.js~Model.html#static-method-init [string] --indentation Number of spaces to indent [number] -t, --tables Space-separated names of tables to import [array] -T, --skipTables Space-separated names of tables to skip [array] --caseModel, --cm Set case of model names: c|l|o|p|u c = camelCase l = lower_case o = original (default) p = PascalCase u = UPPER_CASE --caseProp, --cp Set case of property names: c|l|o|p|u --caseFile, --cf Set case of file names: c|l|o|p|u|k k = kebab-case --noAlias Avoid creating alias `as` property in relations [boolean] --noInitModels Prevent writing the init-models file [boolean] -n, --noWrite Prevent writing the models to disk [boolean] -s, --schema Database schema from which to retrieve tables[string] -v, --views Include database views in generated models [boolean] -l, --lang Language for Model output: es5|es6|esm|ts es5 = ES5 CJS modules (default) es6 = ES6 CJS modules esm = ES6 ESM modules ts = TypeScript [string] --useDefine Use `sequelize.define` instead of `init` for es6|esm|ts --singularize, --sg Singularize model and file names from plural table names ``` --- # typeorm:Model Generator 感谢社区用户 @youtiao66 提供此模块。 通过该工具,你可以快速创建 for Midway 的 TypeORM Model。 ## 使用[​](#使用 "使用的直接链接") 比如生成 mysql 的 model。 ``` # 推荐 # 请替换配置信息 $ npx mdl-gen-midway -h localhost -p 3306 -d yourdbname -u root -x yourpassword -e mysql --noConfig --case-property none ``` 完整参数: ``` Usage: npx mdl-gen-midway -h -d -p [port] -u -x [password] -e [engine] Options: --help Show help [boolean] --version Show version number [boolean] -h, --host IP address/Hostname for database server [default: "127.0.0.1"] -d, --database Database name(or path for sqlite) [required] -u, --user Username for database server -x, --pass Password for database server [default: ""] -p, --port Port number for database server -e, --engine Database engine [choices: "mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"] [default: "mssql"] -o, --output Where to place generated models [default: "./output"] -s, --schema Schema name to create model from. Only for mssql and postgres. You can pass multiple values separated by comma eg. -s scheme1,scheme2,scheme3 --ssl [boolean] [default: false] --noConfig Doesn't create tsconfig.json and ormconfig.json [布尔] [默认值: false] --cp, --case-property Convert property names to specified case [可选值: "pascal", "camel", "snake", "none"] [默认值: "camel"] ``` --- # 版本检查工具 由于依赖安装版本的不确定性,Midway 提供了 `midway-version` 这一版本检查工具,可以快速检查版本之间的兼容性错误。 ## 检查兼容性[​](#检查兼容性 "检查兼容性的直接链接") 你可以使用下面的命令在项目根目录执行进行检查。 以下命令会检查 `node_modules` 中实际安装的版本,而非 `package.json` 中写的版本。 * npm * pnpm * yarn ``` $ npx midway-version@latest ``` ``` $ pnpx midway-version@latest ``` ``` $ yarn add midway-version@latest $ yarn midway-version ``` ## 升级到最新版本[​](#升级到最新版本 "升级到最新版本的直接链接") 你可以使用下面的命令在项目根目录执行进行升级。 `-u` 参数会检查 midway 所有模块,根据 `node_modules` 中实际安装的版本以及 `package.json` 中编写的版本,将其升级到 `最新` 版本。 如当前安装的组件版本为 `3.16.2`,最新版本为 `3.18.0` ,则会提示升级到 `3.18.0`。 在使用 `-u -w` 参数时: * 更新 `package.json` 的版本,保留前缀写法,比如 `^3.16.0` 会变为 `^3.18.0` * 将 `3.18.0` 版本写入到锁文件(如有) - npm - pnpm - yarn ``` $ npx midway-version@latest -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `package-lock.json` 文件(如有)。 ``` $ npx midway-version@latest -u -w ``` ``` $ pnpx midway-version@latest -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `pnpm-lock.yaml` 文件(如有)。 ``` $ pnpx midway-version@latest -u -w ``` ``` $ yarn add midway-version@latest $ yarn midway-version -u ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `yarn.lock` 文件(如有)。 ``` $ yarn midway-version -u -w ``` ## 升级到可兼容的最新版本[​](#升级到可兼容的最新版本 "升级到可兼容的最新版本的直接链接") `-m` 参数会检查 midway 所有模块,根据 `node_modules` 中实际安装的版本以及 `package.json` 中编写的版本,将其升级到 `最新的兼容` 版本。 如当前安装的组件版本为 `3.16.0`,最新版本为 `3.18.0` ,兼容版本为 `3.16.1` 和 `3.16.2`,则会提示升级到 `3.16.2`。 一般使用 `-m` 参数的场景为固化低版本,检查错误的组件版本,所以策略和 `-u` 有所不同。 在使用 `-m -w` 参数时: * 更新 `package.json` 的版本 * 如果有锁文件,将会保留前缀,比如 `^3.16.0` 会变为 `^3.16.2` * 如果没有锁文件,将会移除前缀,固定版本,比如 `^3.16.0` 会变为 `3.16.2` * 将 `3.16.2` 版本写入到锁文件(如有) - npm - pnpm - yarn ``` $ npx midway-version@latest -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `package-lock.json` 文件(如有)。 ``` $ npx midway-version@latest -m -w ``` ``` $ pnpx midway-version@latest -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `pnpm-lock.yaml` 文件(如有)。 ``` $ pnpx midway-version@latest -m -w ``` ``` $ yarn add midway-version@latest $ yarn midway-version -m ``` 输出确认无误后,可以使用 `-w` 参数写入 `package.json` 和 `yarn.lock` 文件(如有)。 ``` $ yarn midway-version -m -w ``` --- # 链路追踪 从 Midway v4 开始,框架侧 tracing 能力已合并到 `@midwayjs/core`,不再需要安装和启用 `@midwayjs/otel` 组件。 ## 使用须知[​](#使用须知 "使用须知的直接链接") * Midway 会自动在入口/出口创建和传播 span。 * `tracing.enable` 是全局总开关(只控制“是否开启 tracing”)。 * 协议级行为在各组件里配置(例如 `koa.tracing`、`grpc.tracing`、`kafka.tracing`),`core` 不区分具体协议。 * 各组件可通过 `.tracing.enable` 单独开关,也可以配置 `meta`、`extractor`、`injector`。 * 如果你需要在 Jaeger/Zipkin/OTLP 平台看到链路,仍需初始化 OpenTelemetry SDK 并配置 exporter。 ## OpenTelemetry 基础概念[​](#opentelemetry-基础概念 "OpenTelemetry 基础概念的直接链接") * Trace:一次完整请求链路,包含多个 Span。 * Span:链路中的一个操作节点,记录开始/结束时间、状态和属性。 * Context Propagation:上下文传播,把上游 Trace 信息透传到下游(HTTP header、MQTT properties、gRPC metadata 等)。 * Attributes:Span 上的键值属性,用于检索和过滤。 * TraceId:Trace 的全局唯一 ID,用于关联整条链路。 ## 快速开始[​](#快速开始 "快速开始的直接链接") ### 1) 开启框架 tracing(默认已开启)[​](#1-开启框架-tracing默认已开启 "1) 开启框架 tracing(默认已开启)的直接链接") ``` // src/config/config.default.ts export default { tracing: { enable: true, onError: 'ignore', // 或 throw logOnError: false, }, }; ``` ### 2) 组件级开关[​](#2-组件级开关 "2) 组件级开关的直接链接") ``` // src/config/config.default.ts export default { tracing: { enable: true, // 全局总开关 }, koa: { tracing: { enable: true, }, }, kafka: { tracing: { enable: false, // 单独关闭 kafka tracing }, }, }; ``` 开关规则: * `tracing.enable=false`:全局关闭(所有组件都不产出 span)。 * `tracing.enable=true`:由各组件 `tracing.enable` 决定是否启用。 ### 3) 导出到控制台(最简示例)[​](#3-导出到控制台最简示例 "3) 导出到控制台(最简示例)的直接链接") 按本页的 `bootstrap.js` 初始化方式,你需要安装以下依赖: ``` $ npm install --save @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base ``` ``` { "dependencies": { "@opentelemetry/api": "latest", "@opentelemetry/sdk-trace-node": "latest", "@opentelemetry/sdk-trace-base": "latest" } } ``` * `@opentelemetry/api` * `@opentelemetry/sdk-trace-node` * `@opentelemetry/sdk-trace-base` `bootstrap.js` 示例: ``` const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { ConsoleSpanExporter, SimpleSpanProcessor, } = require('@opentelemetry/sdk-trace-base'); const { Bootstrap } = require('@midwayjs/bootstrap'); const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); Bootstrap.configure().run(); ``` 启动后你会看到应用正常启动日志。真正的 tracing 输出会在有请求/消息进入后打印。 例如请求一次接口后,控制台会出现类似内容(不同版本字段会略有差异): ``` Span: { name: 'GET /api/user', kind: 1, traceId: '4bf92f3577b34da6a3ce929d0e0e4736', parentId: undefined, attributes: { 'midway.protocol': 'http' }, status: { code: 1 } } ``` 你可以重点看这几个字段,确认链路已接通: * `traceId`:存在且是 32 位十六进制字符串。 * `name`:能对应到你的请求/任务。 * `attributes.midway.protocol`:能看到 `http` / `grpc` / `kafka` 等协议标记。 如果没有看到 span 输出,优先检查: * `provider.register()` 是否在 `Bootstrap.configure().run()` 之前执行。 * 代码是否真的走到了被 tracing 覆盖的入口(例如发起了一次 HTTP 请求)。 提示 在 `dev` 模式下,主进程控制台无法看到这些 span 输出(`dev` 不走这里的 `bootstrap.js` 初始化代码)。 ### 4) 对接观测平台(按需)[​](#4-对接观测平台按需 "4) 对接观测平台(按需)的直接链接") 常见 exporter: * OTLP/HTTP:`@opentelemetry/exporter-trace-otlp-http` * OTLP/gRPC:`@opentelemetry/exporter-trace-otlp-grpc` * Jaeger:`@opentelemetry/exporter-jaeger` * Zipkin:`@opentelemetry/exporter-zipkin` 下面以 Jaeger 为例: 1. 安装 Jaeger exporter 依赖(示例) ``` $ npm install --save @opentelemetry/exporter-jaeger ``` ``` { "dependencies": { "@opentelemetry/exporter-jaeger": "latest" } } ``` 2. 修改 `bootstrap.js`,把 Console exporter 替换为 Jaeger exporter ``` const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { Bootstrap } = require('@midwayjs/bootstrap'); const exporter = new JaegerExporter({ host: process.env.JAEGER_AGENT_HOST || '127.0.0.1', port: Number(process.env.JAEGER_AGENT_PORT || 6832), }); const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); provider.register(); Bootstrap.configure().run(); ``` 3. 验证是否生效 * 启动应用后发起一次请求。 * 打开 Jaeger UI(通常是 `http://127.0.0.1:16686`)。 * 按服务名检索,确认能看到对应 span。 ## 框架能力[​](#框架能力 "框架能力的直接链接") ### ctx.traceId[​](#ctxtraceid "ctx.traceId的直接链接") `@midwayjs/core` 提供 `ctx.traceId` 字段。 所有使用 Midway 上下文的 framework 都可读取该字段(例如 web、koa、express、ws、grpc、faas 等)。 ``` ctx.traceId => '4bf92f3577b34da6a3ce929d0e0e4736' ``` ### @Trace 装饰器[​](#trace-装饰器 "@Trace 装饰器的直接链接") ``` import { Trace } from '@midwayjs/core'; export class UserService { @Trace('user.get') async getUser() { // ... } } ``` ### MidwayTraceService[​](#midwaytraceservice "MidwayTraceService的直接链接") ``` import { Inject, MidwayTraceService } from '@midwayjs/core'; export class UserService { @Inject() traceService: MidwayTraceService; } ``` ## 进阶配置[​](#进阶配置 "进阶配置的直接链接") ### 自定义 meta 信息[​](#自定义-meta-信息 "自定义 meta 信息的直接链接") 你可以把业务信息加到链路里(例如用户 ID、租户 ID、队列名)。这些信息最终会出现在 tracing 平台里,方便检索和排查。 `meta` 有 3 种常见写法: 1. 固定写死 适合所有场景都一样的字段。 ``` meta: { 'biz.app': 'user-center', } ``` 2. 用函数动态生成 适合根据当前请求动态决定字段。 ``` meta: ({ protocol, direction }) => ({ 'biz.protocol': protocol, 'biz.direction': direction, }) ``` 3. 分入口/出口分别配置 适合入口和出口要打不同字段。 ``` meta: { common: { 'biz.app': 'user-center' }, entry: { 'biz.side': 'in' }, exit: { 'biz.side': 'out' }, } ``` 上面函数里常用参数有: * `direction`:当前是入口(`entry`)还是出口(`exit`) * `protocol`:当前协议(比如 `http`、`grpc`、`kafka`、`redis`) * `ctx`:当前上下文(入口场景常用) * `request` / `response`:请求和响应对象 * `custom`:组件补充信息(如 `queueName`、`eventName`、`clientName`) 注意:`meta` 最终只会保留字符串、数字、布尔值。空值会被忽略。 组件级 `meta` 示例: ``` // src/config/config.default.ts export default { koa: { tracing: { meta: { common: ({ ctx }) => ({ 'biz.app': 'user-center', 'biz.userId': (ctx as any)?.user?.id ?? 'anonymous', }), entry: ({ spanName }) => ({ 'biz.entry.span': spanName, }), exit: ({ spanName }) => ({ 'biz.exit.span': spanName, }), }, }, }, redis: { tracing: { meta: ({ custom }) => ({ 'biz.redis.client': (custom as any)?.clientName ?? 'default', }), }, }, }; ``` ### 自定义入口/出口上下文位置(extractor / injector)[​](#自定义入口出口上下文位置extractor--injector "自定义入口/出口上下文位置(extractor / injector)的直接链接") 这两个配置是给“上下文传播”用的: * `extractor`:入口读取。Midway 在创建入口 span 前调用,用它决定“从哪里读取上游 trace 信息”。 * `injector`:出口写入。Midway 在发送下游请求/消息前调用,用它决定“往哪里写 trace 信息”。 什么时候需要你自己配: * 默认行为能满足你,就不用配。 * 你的 header/metadata 结构比较特殊,需要改读取位置或写入位置时再配。 * 不同协议要走不同字段时(例如 HTTP 从 `headers`,gRPC 从 `metadata`,Kafka 从 `message.headers`)。 回调参数(最常用): * `request`:当前请求/消息对象。 * `response`:当前响应对象(HTTP/WS 常见)。 * `ctx`:当前上下文对象(框架相关)。 * `carrier`:组件默认 carrier(部分组件会提供)。 * `custom`:组件附加信息(如 `queueName`、`eventName`、`clientName`)。 回调返回值要求: * 返回一个可读写的键值对象(例如普通对象、headers 对象、metadata 容器)。 * 返回 `undefined` 时,组件会回退到默认 carrier。 默认对照(当前实现) 先看入口(extractor,读取): 默认情况下,Midway 使用 OpenTelemetry 全局 propagator。未自定义时通常是 W3C: * `traceparent` * `tracestate` * `baggage` 可以直接理解为:默认就是从各协议载体里的同名字段读取链路信息。
例如 HTTP Header 里的 `traceparent`,gRPC metadata 里的 `traceparent`,Kafka/RabbitMQ 消息 headers 里的 `traceparent`。 | 组件 | 默认从哪里读 | 默认读取 key | | ---------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------- | | `web-koa` | `ctx.headers` | `traceparent` / `tracestate` / `baggage` | | `web-express` | `req.headers` | `traceparent` / `tracestate` / `baggage` | | `ws` | `request.headers` | `traceparent` / `tracestate` / `baggage` | | `socketio` | `socket.handshake.headers` | `traceparent` / `tracestate` / `baggage` | | `grpc` provider | `call.metadata.getMap()` | `traceparent` / `tracestate` / `baggage`(metadata key) | | `kafka` consumer | `payload.message.headers` | `traceparent` / `tracestate` / `baggage`(message headers key) | | `mqtt` consumer | `packet.properties.userProperties` | `traceparent` / `tracestate` / `baggage`(userProperties key) | | `rabbitmq` consumer | `message.properties.headers` | `traceparent` / `tracestate` / `baggage`(AMQP headers key) | | `bull`/`bullmq` consumer | `job.data.__midwayTraceCarrier` | `traceparent` / `tracestate` / `baggage`(内部 carrier key) | | `cron`/`commander`/`faas`/`one-shot`/`piscina`/`mcp` | 组件内部默认 carrier | 通常无上游协议头;有 carrier 时按 `traceparent` / `tracestate` / `baggage` 读取 | 再看出口(injector,写出): | 组件 | 默认写到哪里 | | ---------------------------------------------------------------- | ------------------------------------------------- | | `web-koa` | `ctx.response` | | `web-express` | `res` | | `ws` | 事件 payload 对象 | | `socketio` | 事件 payload 对象 | | `grpc` consumer | `clientOptions.metadata`(默认 `new Metadata()`) | | `kafka` producer | `message.headers` | | `mqtt` producer | `publishOptions.properties.userProperties` | | `rabbitmq` producer | `options.headers` | | `bull`/`bullmq` producer | `jobData.__midwayTraceCarrier` | | `axios` | `requestConfig.headers` | | `redis`/`cache-manager`/`oss`/`cos`/`etcd`/`consul`/`tablestore` | 默认新建 `{}`(可用 `injector` 覆盖) | 按组件配置示例(可直接改): ``` // src/config/config.default.ts export default { // HTTP 入口/出口 koa: { tracing: { extractor: ({ request }) => (request as any)?.headers || {}, injector: ({ response }) => response as any, }, }, // gRPC provider 入口 grpc: { tracing: { extractor: ({ request }) => (request as any)?.metadata?.getMap?.() || {}, }, }, // Kafka consumer 入口 + producer 出口 kafka: { tracing: { extractor: ({ request }) => (request as any)?.message?.headers || {}, injector: ({ request }) => (request as any)?.headers || {}, }, }, // WS 入口/出口(示例) ws: { tracing: { extractor: ({ request }) => (request as any)?.headers || {}, injector: ({ request }) => (request as any)?.headers || {}, }, }, }; ``` 一个常见业务例子(HTTP): * 你希望入口优先从自定义 header `x-traceparent` 读取。 * 你希望出口统一写到 `x-traceparent`。 ``` export default { koa: { tracing: { extractor: ({ request }) => { const headers = (request as any)?.headers || {}; if (headers['x-traceparent'] && !headers.traceparent) { headers.traceparent = headers['x-traceparent']; } return headers; }, injector: ({ response }) => response as any, }, }, }; ``` ### 自定义 propagator(可选)[​](#自定义-propagator可选 "自定义 propagator(可选)的直接链接") 可以。
Midway 会使用 OpenTelemetry 的全局 propagator。你可以在 `bootstrap.js` 里改成自己的实现(例如 B3)。 示例(B3): 先安装依赖: ``` $ npm install --save @opentelemetry/propagator-b3 ``` ``` { "dependencies": { "@opentelemetry/propagator-b3": "latest" } } ``` 然后在 Midway 启动前设置全局 propagator: ``` const { Bootstrap } = require('@midwayjs/bootstrap'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { propagation } = require('@opentelemetry/api'); const { B3Propagator } = require('@opentelemetry/propagator-b3'); const provider = new NodeTracerProvider(); provider.register(); // 设置全局 propagator(示例:B3) propagation.setGlobalPropagator(new B3Propagator()); Bootstrap.configure().run(); ``` 注意: * 这会影响 `extractor/injector` 默认读写的 key(不再是 `traceparent`/`tracestate`)。 * 建议全链路统一一种 propagator,避免上下游格式不一致。 ### 自定义 traceId[​](#自定义-traceid "自定义 traceId的直接链接") 方式 1(推荐):上游传入标准 `traceparent`,Midway 自动继承 TraceId。 ``` traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 ``` 方式 2(高级):在 OpenTelemetry SDK 层配置自定义 `IdGenerator`(不属于 Midway 配置项)。 `bootstrap.js` 示例: ``` const crypto = require('crypto'); const { Bootstrap } = require('@midwayjs/bootstrap'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { SimpleSpanProcessor, ConsoleSpanExporter, } = require('@opentelemetry/sdk-trace-base'); class CustomIdGenerator { // 32位十六进制(16 bytes) generateTraceId() { return crypto.randomBytes(16).toString('hex'); } // 16位十六进制(8 bytes) generateSpanId() { return crypto.randomBytes(8).toString('hex'); } } const provider = new NodeTracerProvider({ idGenerator: new CustomIdGenerator(), }); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); Bootstrap.configure().run(); ``` 注意: * 这只影响“本服务新建”的 trace/span ID。 * 如果上游已传入 `traceparent`,会优先沿用上游 traceId。 ## 从 @midwayjs/otel 迁移[​](#从-midwayjsotel-迁移 "从 @midwayjs/otel 迁移的直接链接") * 包迁移:`@midwayjs/otel` -> `@midwayjs/core` * 配置迁移:删除 `imports: [otel]` * 使用方式:`ctx.traceId` 保持不变 * 行为兼容:`@Trace` 与 `MidwayTraceService` 能力继续可用 迁移清单: 1. 删除依赖:`npm uninstall @midwayjs/otel` 2. 删除配置:移除 `Configuration.imports` 中的 `otel` 3. 更新导入路径 * `import { Trace } from '@midwayjs/otel'` -> `import { Trace } from '@midwayjs/core'` * `import { TraceService } from '@midwayjs/otel'` -> `import { MidwayTraceService } from '@midwayjs/core'` ## 相关阅读[​](#相关阅读 "相关阅读的直接链接") * [OpenTelemetry 官方文档](https://opentelemetry.io/docs/) --- # 2.x 升级指南 本篇将介绍从 midway v2 升级为 midway v3 的方式。 从 Midway v2 升级到 Midway v3,会有一些 Breaking Change。本篇文档会详细列出这些 Breaking 的地方,让用户可以提前知道变化,做出应对。 ## 自动升级工具[​](#自动升级工具 "自动升级工具的直接链接") **在升级前,请切出一个新的分支,避免升级失败导致无法恢复!!!** 拷贝以下脚本,在项目根目录执行: ``` $ npx --ignore-existing midway-upgrade ``` 提示 由于业务情况各异,请在脚本升级之后,再进行手动升级的核对。 ## 手动升级[​](#手动升级 "手动升级的直接链接") **midway v3 支持从 node v12 起。** ### 包版本更新[​](#包版本更新 "包版本更新的直接链接") 所有的组件包,核心包都将升级为 3.x 版本。 ``` { "dependencies": { "@midwayjs/bootstrap": "^3.0.0", "@midwayjs/core": "^3.0.0", "@midwayjs/decorator": "^3.0.0", "@midwayjs/koa": "^3.0.0", "@midwayjs/task": "^3.0.0", }, "devDependencies": { "@midwayjs/cli": "^1.2.90", "@midwayjs/luckyeye": "^1.0.0", "@midwayjs/mock": "^3.0.0", // ... } } ``` `@midwayjs/cli` 和 `@midwyajs/luckeye`, `@midwayjs/logger` 的版本除外。 ### Query/Body/Param/Header 装饰器变更[​](#querybodyparamheader-装饰器变更 "Query/Body/Param/Header 装饰器变更的直接链接") 主要是默认无参数下的行为。 旧 ``` async invoke(@Query() name) { // ctx.query.name } ``` 新 ``` async invoke(@Query() name) { // ctx.query } async invoke(@Query('name') name) { // ctx.query.name } ``` ### Validate/Rule 装饰器[​](#validaterule-装饰器 "Validate/Rule 装饰器的直接链接") 旧 ``` import { Validate, Rule, RuleType } from '@midwayjs/decorator'; ``` 新 ``` import { Validate, Rule, RuleType } from '@midwayjs/validate'; ``` 由于 validate 抽象成了组件,需要在代码中安装依赖并开启。 ``` // src/configuration import * as validate from '@midwayjs/validate'; @Configuration({ // ... imports: [ validate ], }) export class MainConfiguration { // ... } ``` ### task 组件配置 key 变更[​](#task-组件配置-key-变更 "task 组件配置 key 变更的直接链接") 旧 ``` export const taskConfig = {}; ``` 新 ``` export const task = {}; ``` ### 配置的绝对路径[​](#配置的绝对路径 "配置的绝对路径的直接链接") 不再支持相对路径 旧 ``` // src/configuration @Configuration({ // ... importConfigs: [ './config' // ok ] }) export class MainConfiguration { // ... } ``` 新 ``` // src/configuration import { join } from 'path'; @Configuration({ // ... importConfigs: [ - './config' // error + join(__dirname, './config') // ok ] }) export class MainConfiguration { // ... } ``` ### 使用默认框架/多框架[​](#使用默认框架多框架 "使用默认框架/多框架的直接链接") 旧,会在 bootstrap.js 中引入 ``` const WebFramework = require('@midwayjs/koa').Framework; const GRPCFramework = require('@midwayjs/grpc').Framework; const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap .load(config => { return new WebFramework().configure(config.cluster); }) .load(config => { return new GRPCFramemwork().configure(config.grpcServer); }) .run(); ``` 新版本 bootstrap.js 中不再需要单独实例化 ``` const { Bootstrap } = require('@midwayjs/bootstrap'); Bootstrap.run(); ``` 作为替代,以组件的形式引入 ``` // src/configuration import * as web from '@midwayjs/web'; import * as grpc from '@midwayjs/grpc'; @Configuration({ // ... imports: [ web, grpc, //... ], }) export class MainConfiguration { // ... } ``` 其他影响: * 1、测试中不再需要使用 createBootstrap 方法从 bootstrap.js 启动 * 2、原有入口 Framework 的配置现在可以放到 config.\*.ts 中,以框架名作为 key ### 删除了一批 IoC 容器 API[​](#删除了一批-ioc-容器-api "删除了一批 IoC 容器 API的直接链接") 移除 container 上的下列方法 * getConfigService(): IConfigService; * getEnvironmentService(): IEnvironmentService; * getInformationService(): IInformationService; * setInformationService(service: IInformationService): void; * getAspectService(): IAspectService; * getCurrentEnv(): string; 现在都有相应的框架内置服务来替代。 比如旧写法: ``` const environmentService = app.getApplicationContext().getEnvironmentService(); const env = environmentService.getCurrentEnvironment(); ``` 新写法 ``` const environmentService = app.getApplicationContext().get(MidwayEnvironmentService) const env = environmentService.getCurrentEnvironment(); ``` ## @midwayjs/web(egg)部分[​](#midwayjswebegg部分 "@midwayjs/web(egg)部分的直接链接") ### 启动端口[​](#启动端口 "启动端口的直接链接") 新版本框架启动会读取一个端口配置,如果未配,可能不会启动端口监听。 ``` // src/config/config.default export default { // ... egg: { port: 7001, }, } ``` ### 添加 egg-mock[​](#添加-egg-mock "添加 egg-mock的直接链接") 由于框架移除了 egg-mock 包,在新版本 `package.json` 需要手动引用。 ``` { "devDependencies": { "egg-mock": "^1.0.0", // ... } } ``` ### 日志[​](#日志 "日志的直接链接") 新版本,统一使用 @midwayjs/logger,不管是不是启用 egg logger。 为了和 egg 日志不冲突,我们使用了新的 key,原有的 `midwayFeature` 字段不再使用。 旧 ``` export const logger = { level: 'warn', consoleLevel: 'info' } ``` 新 ``` export const midwayLogger = { default: { level: 'warn', consoleLevel: 'info' } } ``` Egg 的 `customLogger` 字段,针对无法修改的 egg 插件,我们做了兼容,对于业务代码,最好做修改。 ``` export const midwayLogger = { default: { level: 'warn', consoleLevel: 'info' }, clients: { // 自定义日志 customLoggerA: { // ... } } } ``` 其余的更具体配置,请参考 [日志章节 ](/docs/logger.md)中的自定义部分。 ### egg 插件[​](#egg-插件 "egg 插件的直接链接") 在 Midway3 中,为了文档和行为统一,我们关闭了大部分 egg 默认插件。 新版本默认插件如下: ``` module.exports = { onerror: true, security: true, static: false, development: false, watcher: false, multipart: false, logrotator: false, view: false, schedule: false, i18n: false, } ``` 请酌情开启(可能会和 midway 能力冲突)。 默认的 egg 日志切割插件(logrotator),由于日志不再支持 egg logger,我们在框架中直接关闭了(midway logger 自带了切割)。 ### 定时任务[​](#定时任务 "定时任务的直接链接") 如果希望使用老的 `@Schedule` 装饰器,需要额外安装 `midway-schedule` 包,并以 egg 插件的形式引入。 ``` // src/config/plugin.ts export default { schedule: true, schedulePlus: { enable: true, package: 'midway-schedule', } // ... } ``` ## 其他面对组件/框架开发者的调整[​](#其他面对组件框架开发者的调整 "其他面对组件/框架开发者的调整的直接链接") ### 组件中 registerObject 不再增加 namespace[​](#组件中-registerobject-不再增加-namespace "组件中 registerObject 不再增加 namespace的直接链接") 在组件开发时,不再增加 namespace 前缀。 旧,组件入口 ``` @Configuration({ namespace: 'A' // ... }) export class MainConfiguration { async onReady(container) { container.registerObject('aaa', 'bbb'); } } container.getAsync('A:aaa'); // => OK ``` 新组件入口 ``` @Configuration({ namespace: 'A' // ... }) export class MainConfiguration { async onReady(container) { container.registerObject('aaa', 'bbb'); } } container.getAsync('aaa'); // => OK ``` ### 自定义框架部分[​](#自定义框架部分 "自定义框架部分的直接链接") 自定义框架的变化比较大,框架组件化是这一版本的目标。有几个地方需要修改。 **1、在原框架上增加 @Framework 标识** 旧 ``` export class CustomKoaFramework extends BaseFramework { // ... } ``` 新 ``` import { Framework } from '@midwayjs/core'; @Framework() export class CustomKoaFramework extends BaseFramework { // ... } ``` **2、在入口处按组件规范导出 Configuration** 你可以在 configuration 中使用生命周期,和组件相同。`run` 方法将在新增的 `onServerReady` 这个生命周期显式调用执行。 ``` import { Configuration,Inject } from '@midwayjs/core'; import { MidwayKoaFramework } from './framework'; @Configuration({ namespace: 'koa', }) export class KoaConfiguration { @Inject() framework: MidwayKoaFramework; async onReady() {} async onServerReady() { // ... } } ``` **3、框架开发时** **需要注意的是,由于框架初始化在用户生命周期前,所以 applicationInit 的时候,不要通过 @Config 装饰器注入配置,而是调用 configService 去获取。** ``` import { Framework } from '@midwayjs/core'; @Framework() export class CustomKoaFramework extends BaseFramework { configure() { /** * 这里返回你的配置 * 返回的值会赋值到 this.configurationOptions,对接原来的用户显式入参 * */ return this.configService.getConfiguration('xxxxxxx'); } /** * 这个新增的方法,用来判断框架是否加载 * 有时候组件中包括 server 端(框架)和 client 端,就需要判断 * */ isEnable(): boolean { return this.configurationOptions.services?.length > 0; } // ... } ``` 这样在外面使用时也可以判断。 ``` import { Configuration,Inject } from '@midwayjs/core'; import { MidwayKoaFramework } from './framework'; @Configuration({ namespace: 'koa', }) export class KoaConfiguration { @Inject() framework: MidwayKoaFramework; async onReady() {} async onServerReady() { // 如果 isEnable 为 true,框架会默认调用 framework.run() // 如果一开始 enable 为 false,也可以延后去手动 run if (/* 延后执行 */) { await this.framework.run(); } } } ``` --- # 3.x 升级指南 本篇将介绍从 midway v3 升级为 midway v4 的方式。 从 Midway v3 升级到 Midway v4,会有一些 Breaking Change。本篇文档仅列出这些 Breaking 的地方,让用户可以提前知道变化,做出应对。 ## Node.js 的变化[​](#nodejs-的变化 "Node.js 的变化的直接链接") midway v4 支持从 node v20 起,最好使用 LTS 版本。 ## 包版本更新[​](#包版本更新 "包版本更新的直接链接") 所有的组件包,核心包都将升级为 4.x 版本。 ``` { "dependencies": { - "@midwayjs/bootstrap": "^3.0.0", - "@midwayjs/core": "^3.0.0", - "@midwayjs/koa": "^3.0.0", - "@midwayjs/logger": "^3.0.0", + "@midwayjs/bootstrap": "^4.0.0", + "@midwayjs/core": "^4.0.0", + "@midwayjs/koa": "^4.0.0", + "@midwayjs/logger": "^4.0.0", }, "devDependencies": { - "@midwayjs/mock": "^3.0.0", + "@midwayjs/mock": "^4.0.0", // ... } } ``` `@midwyajs/luckeye` 的版本除外。 ## 移除 `@midwayjs/decorator`[​](#移除-midwayjsdecorator "移除-midwayjsdecorator的直接链接") 从 v4 开始,移除了 `@midwayjs/decorator` 包,用户可以直接使用 `@midwayjs/core` 来代替。 ``` - import { Controller } from '@midwayjs/decorator'; + import { Controller } from '@midwayjs/core'; ``` ## 入口自动扫描能力[​](#入口自动扫描能力 "入口自动扫描能力的直接链接") 从 v4 开始,框架移除了隐式的自动扫描能力,用户需要显式的声明需要扫描的目录。 ``` import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector(), // ... }) export class MainContainer { // ... } ``` 你也可以指定要忽略的目录。 ``` import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector({ ignore: [ '**/logs/**', ], }), // ... }) export class MainContainer { // ... } ``` 重复检查配置也放到了参数中。 ``` import { Configuration, CommonJSFileDetector } from '@midwayjs/core'; @Configuration({ detector: new CommonJSFileDetector({ conflictCheck: true, }), // ... }) export class MainContainer { // ... } ``` ## 主框架日志配置[​](#主框架日志配置 "主框架日志配置的直接链接") 从 v4 开始,主框架日志格式回归到 midwayLogger 配置中。 * Koa * Express * Egg * Bull ``` // *.config.ts export default { koa: { - contextLoggerFormat: info => { - const ctx = info.ctx; - return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; - } }, midwayLogger: { clients: { appLogger: { + contextFormat: info => { + const ctx = info.ctx; + return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; + } } } }, } as MidwayConfig; ``` ``` // *.config.ts export default { express: { - contextLoggerFormat: info => { - const ctx = info.ctx; - return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; - } }, midwayLogger: { clients: { appLogger: { + contextFormat: info => { + const ctx = info.ctx; + return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; + } } } }, } as MidwayConfig; ``` ``` // *.config.ts export default { egg: { - contextLoggerFormat: info => { - const ctx = info.ctx; - return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; - } }, midwayLogger: { clients: { appLogger: { + contextFormat: info => { + const ctx = info.ctx; + return `${info.timestamp} ${info.LEVEL} ${info.pid} [${ctx.userId} - ${Date.now() - ctx.startTime}ms ${ctx.method}] ${info.message}`; + } } } }, } as MidwayConfig; ``` ``` // *.config.ts export default { bull: { - contextLoggerFormat: info => { - const { jobId, from } = info.ctx; - return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`; - } }, midwayLogger: { clients: { bullLogger: { + contextFormat: info => { + const { jobId, from } = info.ctx; + return `${info.timestamp} ${info.LEVEL} ${info.pid} [${jobId} ${from.name}] ${info.message}`;`; + } } } }, } as MidwayConfig; ``` 其余的 `cron`、`mqtt`, `kafka` 等组件,如有相关配置,均和上述类似。 ## 可选变更对照[​](#可选变更对照 "可选变更对照的直接链接") 以下是各个包的 Breaking Changes 对照表,按照包名分类展示具体的变更内容。 ### @midwayjs/core[​](#midwayjscore "@midwayjs/core的直接链接") #### @App() 装饰器变更[​](#app-装饰器变更 "@App() 装饰器变更的直接链接") 使用 `@MainApp()` 代替 `@App()` 空参数的场景: ``` - @App() + @MainApp() private app; ``` #### @Config() 装饰器变更[​](#config-装饰器变更 "@Config() 装饰器变更的直接链接") 使用 `@AllConfig()` 替换 `@Config(ALL)` 的场景: ``` - @Config(ALL) + @AllConfig() private allConfig; ``` #### DecoratorManager API 调整[​](#decoratormanager-api-调整 "DecoratorManager API 调整的直接链接") `DecoratorManager` 中的 API 名称调整: ``` import { DecoratorManager } from '@midwayjs/core'; - DecoratorManager.listPrelaodModules() + DecoratorManager.listPreStartModule() - DecoratorManager.savePreloadModule('xxxx', xxx) + DecoratorManager.savePreStartModule('xxxx', xxx) ``` #### @Configuration 参数变更[​](#configuration-参数变更 "@Configuration 参数变更的直接链接") 移除 `@Configuration` 中的 `conflictCheck` 和 `detectorOptions`,这些配置将移动到 `detector` 中: ``` @Configuration({ - conflictCheck: true, - detectorOptions: { ... }, + detector: new CommonJSFileDetector({ + conflictCheck: true, + // ... 其他配置 + }), // ... }) ``` #### Container API 简化[​](#container-api-简化 "Container API 简化的直接链接") 移除了 `container.get` 和 `container.getAsync` 的一部分无用的参数: ``` // 之前有额外的参数 - container.get(identifier, args, options) + container.get(identifier, args) - container.getAsync(identifier, args, options) + container.getAsync(identifier, args) ``` #### Pipeline 流程控制移除[​](#pipeline-流程控制移除 "Pipeline 流程控制移除的直接链接") 由于使用率较低且影响依赖注入容器逻辑,移除了流程控制 `Pipeline` 相关的能力: ``` - import { Pipeline } from '@midwayjs/core'; - - @Pipeline() - export class MyPipeline { - // pipeline 相关代码 - } ``` 如果需要类似功能,建议使用中间件或拦截器替代。 #### 自动 DTO 转换移除[​](#自动-dto-转换移除 "自动 DTO 转换移除的直接链接") 移除了会和 validate 的转换产生歧义的请求参数自动 DTO 转换功能,现在自动转换仅在 `validate` 或者 `validation` 组件开启时生效: ``` // v3 中,即使没有开启 validate,也会自动转换 export class UserController { @Post() async create(@Body() user: CreateUserDTO) { - // v3: 自动转换为 CreateUserDTO 实例 + // v4: 需要显式开启 validate 或 validation 组件才会转换 return user; } } // v4 中需要显式配置 + import { Configuration } from '@midwayjs/core'; + import * as validate from '@midwayjs/validate'; // 或 @midwayjs/validation + + @Configuration({ + imports: [validate], + }) + export class MainConfiguration {} ``` #### MidwayFrameworkType 移除[​](#midwayframeworktype-移除 "MidwayFrameworkType 移除的直接链接") ``` - import { MidwayFrameworkType } from '@midwayjs/core'; - - // 获取框架类型 - const frameworkType = app.getFrameworkType(); - if (frameworkType === MidwayFrameworkType.WEB_KOA) { - // koa 框架相关逻辑 - } ``` #### BaseFramework Hook 方法移除[​](#baseframework-hook-方法移除 "BaseFramework Hook 方法移除的直接链接") ``` export class CustomFramework extends BaseFramework { - async beforeContainerReady() { - // 容器准备前的逻辑 - } - - async afterContainerReady() { - // 容器准备后的逻辑 - } } ``` #### DataSourceManager 配置废弃[​](#datasourcemanager-配置废弃 "DataSourceManager 配置废弃的直接链接") ``` // 数据源管理器配置 export const dataSourceConfig = { - cacheInstance: true, - validateConnection: true, // 其他配置保持不变 }; ``` ### @midwayjs/async-hooks-context-manager[​](#midwayjsasync-hooks-context-manager "@midwayjs/async-hooks-context-manager的直接链接") #### 默认开启 async\_local\_storage[​](#默认开启-async_local_storage "默认开启 async_local_storage的直接链接") 现在默认开启 async\_local\_storage,代码合并至 core 模块中,用户无需手动导入: ### @midwayjs/axios[​](#midwayjsaxios "@midwayjs/axios的直�接链接") #### axios 导出移除[​](#axios-导出移除 "axios 导出移除的直接链接") 移除了废弃的 `axios` 导出: ``` - import { axios } from '@midwayjs/axios'; + import { HttpService } from '@midwayjs/axios'; export class UserService { - @Inject() - axios: axios; + @Inject() + httpService: HttpService; async getUser() { - return this.axios.get('/api/user'); + return this.httpService.get('/api/user'); } } ``` ### @midwayjs/socketio[​](#midwayjssocketio "@midwayjs/socketio的直接链接") #### 内置 socket.io-redis 移除[​](#内置-socketio-redis-移除 "内置 socket.io-redis 移除的直接链接") 移除了内置的 `socket.io-redis`,如果需要 Redis 适配器,请手动安装和配置 `socket.io-redis`。 ### @midwayjs/validate[​](#midwayjsvalidate "@midwayjs/validate的直接链接") 不再更新,推荐使用 @midwayjs/validation 组件。 ### @midwayjs/mock[​](#midwayjsmock "@midwayjs/mock的直接链接") #### createApp 方法参数调整[​](#createapp-方法参数调整 "createApp 方法参数调整的直接链接") 移除了 `createApp`,`createLightApp`, `createFunctionApp` 方法的最后一个参数,现在额外指定组件可以写到 `options.imports` 中: ``` - createApp('path', {}, ['extra-component']) + createApp('path', { imports: ['extra-component'] }) ``` 如果有大量历史测试不方便修改,可以使用提供的 `createLegacyApp`,`createLegacyLightApp`,`createLegacyFunctionApp`。 ### @midwayjs/sequelize[​](#midwayjssequelize "@midwayjs/sequelize的直接链接") #### @BaseTable 装饰器移除[​](#basetable-装饰器移除 "@BaseTable 装饰器移除的直接链接") ``` - import { BaseTable } from '@midwayjs/sequelize'; - - @BaseTable() - export class User extends Model {} + import { Table } from 'sequelize-typescript'; + + @Table + export class User extends Model {} ``` #### validateConnection 配置移除[​](#validateconnection-配置移除 "validateConnection 配置移除的直接链接") ``` // 配置文件 export default { sequelize: { dataSource: { default: { database: 'test', username: 'root', password: '', - validateConnection: true, // 默认不再校验连接 // 如有需要可以手动开启 + // validateConnection: true, } } } } ``` ### @midwayjs/tags[​](#midwayjstags "@midwayjs/tags的直接链接") #### 包完全移除[​](#包完全移除 "包完全移除的直接链接") 此包在 v4 中不再提供,需要移除相关导入和配置: ``` - import * as tags from '@midwayjs/tags'; - - @Configuration({ - imports: [ - // 其他组件 - tags, - ], - }) - export class MainConfiguration {} ``` ### @midwayjs/processAgent[​](#midwayjsprocessagent "@midwayjs/processAgent的直接链接") #### 包完全移除[​](#包完全移除-1 "包完全移除的直接链接") 此包在 v4 中不再提供,需要移除相关导入和配置: ``` - import * as processAgent from '@midwayjs/processAgent'; - - @Configuration({ - imports: [ - // 其他组件 - processAgent, - ], - }) - export class MainConfiguration {} ``` --- # 路由版本化 在现代 API 开发中,版本化是一个非常重要的话题。当你的 API 需要进行不兼容的更改时,版本化可以确保现有的客户端不会受到影响,同时允许新的客户端使用新的功能。 Midway 提供了灵活的路由版本化方案,支持多种版本化策略,让你可以轻松地管理 API 的不同版本。 ## 支持的框架[​](#支持的框架 "支持的框架的直接链接") 路由版本化功能在以下框架中可用: | 框架 | 支持状态 | | --------------------- | -------- | | @midwayjs/web-koa | ✅ | | @midwayjs/web | ✅ | | @midwayjs/web-express | ✅ | | Serverless | ❌ | ## 快速开始[​](#快速开始 "快速开始的直接链接") ### 启用版本化[​](#启用版本化 "启用版本化的直接链接") 首先,你需要在框架配置中启用版本化: ``` // src/config/config.default.ts export default { // Koa 框架 koa: { versioning: { enabled: true, type: 'URI', // 版本化类型 prefix: 'v', // 版本前缀 } }, // Express 框架 express: { versioning: { enabled: true, type: 'URI', prefix: 'v', } }, // Web (Egg) 框架 egg: { versioning: { enabled: true, type: 'URI', prefix: 'v', } } }; ``` ### 在控制器中使用版本[​](#在控制器中使用版本 "在控制器中使用版本的直接链接") 然后在控制器装饰器中指定版本: ``` import { Controller, Get, Post } from '@midwayjs/core'; @Controller('/users', { version: '1', // 指定版本 description: 'Users API v1' }) export class UsersV1Controller { @Get('/') async getUsers() { return { version: 'v1', users: [ { id: 1, name: 'John', email: 'john@example.com' } ] }; } @Post('/') async createUser(@Body() user: any) { return { version: 'v1', user: { id: 2, ...user } }; } } @Controller('/users', { version: '2', // 新版本 description: 'Users API v2' }) export class UsersV2Controller { @Get('/') async getUsers() { return { version: 'v2', data: { users: [ { id: 1, name: 'John', email: 'john@example.com', profile: { avatar: 'avatar.jpg' } } ], meta: { total: 1, page: 1 } } }; } @Post('/') async createUser(@Body() user: any) { return { version: 'v2', data: { user: { id: 2, ...user, profile: {} } }, meta: { created: new Date().toISOString() } }; } } ``` 现在你可以通过不同的 URL 访问不同版本的 API: ``` # 访问 v1 版本 curl http://localhost:7001/v1/users # 访问 v2 版本 curl http://localhost:7001/v2/users ``` ## 版本化策略[​](#版本化策略 "版本化策略的直接链接") Midway 支持多种版本化策略,你可以根据需要选择合适的方式。 ### URI 版本化(推荐)[​](#uri-版本化推荐 "URI 版本化(推荐)的直接链接") 这是最常见和直观的版本化方式,版本信息包含在 URL 路径中。 ``` // 配置 export default { koa: { versioning: { enabled: true, type: 'URI', prefix: 'v', // 可自定义前缀 } } }; ``` ``` # 请求示例 GET /v1/users GET /v2/users POST /v1/users ``` ### Header 版本化[​](#header-版本化 "Header 版本化的直接链接") 通过 HTTP Header 指定版本信息。 ``` // 配置 export default { koa: { versioning: { enabled: true, type: 'HEADER', header: 'x-api-version', // 可自定义 header 名称 } } }; ``` ``` # 请求示例 curl -H "x-api-version: 1" http://localhost:7001/users curl -H "x-api-version: 2" http://localhost:7001/users ``` ### Media Type 版本化[​](#media-type-版本化 "Media Type 版本化的直接链接") 通过 `Accept` header 的参数指定版本。 ``` // 配置 export default { koa: { versioning: { enabled: true, type: 'MEDIA_TYPE', mediaTypeParam: 'version', // 参数名称 } } }; ``` ``` # 请求示例 curl -H "Accept: application/json;version=1" http://localhost:7001/users curl -H "Accept: application/json;version=2" http://localhost:7001/users ``` ### 自定义版本化[​](#自定义版本化 "自定义版本化的直接链接") 你还可以提供自定义的版本提取函数: ``` // 配置 export default { koa: { versioning: { enabled: true, type: 'CUSTOM', extractVersionFn: (ctx) => { // 从查询参数中提取版本 return ctx.query.version; // 或者从其他地方提取版本 // return ctx.headers['custom-version']; } } } }; ``` ``` # 请求示例 curl "http://localhost:7001/users?version=1" curl "http://localhost:7001/users?version=2" ``` ## 高级用法[​](#高级用法 "高级用法的直接链接") ### 多版本支持[​](#多版本支持 "多版本支持的直接链接") 一个控制器可以支持多个版本: ``` @Controller('/api', { version: ['1', '2'], // 支持 v1 和 v2 }) export class ApiController { @Get('/info') async getInfo(ctx) { // 可以通过 ctx.apiVersion 获取当前请求的版本 return { version: ctx.apiVersion, message: `This is API version ${ctx.apiVersion}` }; } } ``` ### 默认版本[​](#默认版本 "默认版本的直接链接") 你可以设置默认版本,当没有指定版本时使用: ``` export default { koa: { versioning: { enabled: true, type: 'URI', prefix: 'v', defaultVersion: '1', // 默认版本 } } }; ``` ### 获取版本信息[​](#获取版本信息 "获取版本信息的直接链接") 在控制器中,你可以通过上下文获取当前请求的版本信息: ``` @Controller('/api') export class ApiController { @Get('/version') async getVersion(ctx) { return { currentVersion: ctx.apiVersion, // 当前版本 originalPath: ctx.originalPath, // 原始路径(版本化之前) }; } } ``` ## 配置选项[​](#配置选项 "配置选项的直接链接") 完整的配置选项说明: ``` interface VersioningConfig { // 是否启用版本化 enabled: boolean; // 版本化类型 type?: 'URI' | 'HEADER' | 'MEDIA_TYPE' | 'CUSTOM'; // 默认版本(当无法提取版本时使用) defaultVersion?: string; // URI 版本化的前缀(默认:'v') prefix?: string; // Header 版本化的 header 名称(默认:'x-api-version') header?: string; // Media Type 版本化的参数名称(默认:'version') mediaTypeParam?: string; // 自定义版本提取函数 extractVersionFn?: (ctx) => string | undefined; } ``` ## 最佳实践[​](#最佳实践 "最佳实践的直接链接") ### 版本命名[​](#版本命名 "版本命名的直接链接") 建议使用简单的数字版本号: * ✅ 推荐:`'1'`, `'2'`, `'3'` * ❌ 不推荐:`'v1.0'`, `'1.2.3'`, `'latest'` ### 版本策略选择[​](#版本策略选择 "版本策略选择的直接链接") * **URI 版本化**:最直观,便于缓存,推荐用于公开 API * **Header 版本化**:URL 保持简洁,适合内部 API * **Media Type 版本化**:符合 REST 原则,但实现复杂 * **自定义版本化**:最灵活,但需要额外的文档说明 ### 向后兼容[​](#向后兼容 "向后兼容的直接链接") 在设计新版本时,尽量保持向后兼容: ``` // 好的版本化设计 @Controller('/users', { version: '1' }) export class UsersV1Controller { @Get('/') async getUsers() { return { users: [] }; // 简单格式 } } @Controller('/users', { version: '2' }) export class UsersV2Controller { @Get('/') async getUsers() { return { data: { users: [] }, // 添加了 data 包装 meta: { total: 0 } // 添加了元信息 }; } } ``` ### 版本废弃[​](#版本废弃 "版本废弃的直接链接") 当需要废弃旧版本时,建议: 1. 在响应头中添加废弃警告 2. 提供迁移指南 3. 设置合理的废弃时间表 ``` @Controller('/users', { version: '1' }) export class UsersV1Controller { @Get('/') async getUsers(ctx) { // 添加废弃警告 ctx.set('X-API-Deprecated', 'true'); ctx.set('X-API-Deprecation-Date', '2024-01-01'); ctx.set('X-API-Sunset-Date', '2024-06-01'); return { users: [] }; } } ``` ## 注意事项[​](#注意事项 "注意事项的直接链接") 1. **版本前缀**:URI 版本化会在路由前添加版本前缀,确保控制器的路由路径设计合理 2. **中间件影响**:版本化中间件会修改请求路径,可能影响其他依赖路径的中间件 3. **性能考虑**:版本化会增加路由匹配的复杂度,但影响通常很小 4. **测试覆盖**:确保为每个版本的 API 编写充分的测试 通过 Midway 的版本化功能,你可以优雅地管理 API 的演进,为用户提供稳定可靠的服务。 ---