
后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载MidwayNode.js Serverless Framework提供了贯穿整个应用生命周期的多环境配置能力。本文以site/i18n/en/docusaurus-plugin-content-docs/version-3.0.0/env_config.md为骨架结合仓库核心源码系统讲解 Midway 3.x 的环境配置加载机制、MidwayConfig类型体系、Config注入与动态修改配置的四种手段并给出常见踩坑排查清单。配置文件两种导出形式Midway 的配置能力面向所有业务代码与组件开放贯穿整个应用生命周期。配置文件的导出有两种形式对象形式Object form与函数形式Function form。官方实践表明对象形式更简单、更友好能避免许多错误用法因此多数文档以对象形式示例为主。本文也将围绕这一推荐形式展开同时说明函数形式的适用场景与appInfo参数。配置目录与命名约定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.{环境名}命名环境概念详见运行环境配置不是必需的按需添加对应环境的配置文件即可。对象形式配置文件导出为对象并显式声明MidwayConfig类型以获得类型提示// 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其字段含义如下appInfoDescriptionpkgpackage.jsonnameapplication name, same as pkg.namebaseDirsrc本地开发或 dist线上下的应用代码目录appDirapplication code directory应用代码所在目录HOME用户目录例如 admin 账户下为 /home/adminroot应用根目录仅在 local 与 unittest 环境下等于 baseDir其余环境为 HOME从源码看MidwayAppInfo在 packages/core/src/interface.ts#L1186-L1194 中定义除文档列出的字段外还包含env当前环境。该对象由 MidwayConfigService.init() 在初始化时基于MidwayInformationService与MidwayEnvironmentService组装之后在 configService.ts#L145-L148 中被调用若加载到的模块是函数则以config.apply(null, [this.appInfo, target])的形式执行第二参数是此前已合并的配置对象方便函数形式基于已有配置做增量计算。MidwayConfig统一配置类型定义Midway 提供MidwayConfig作为统一配置项定义。所有组件都会把自身配置定义合并进这一类型——每当一个组件被启用configuration.ts中的importsMidwayConfig就会自动包含该组件的配置定义。这一设计带来两个实用效果类型提示自动扩展尽量使用文档推荐的配置格式即可获得最佳的使用体验新增组件后无需手动维护类型组件启用的旁证每当新组件被启用其配置定义会自动加入MidwayConfig据此可反向确认组件是否已被正确启用。例如启用 view 组件后配置类型提示即出现 view 相关配置项。源码中MidwayConfig的定义位于 packages/core/src/interface.ts#L1199-L1201它继承FileConfigOptionMidwayCoreDefaultConfig并通过索引签名[customConfigKey: string]: unknown兼容任意自定义配置键——这正是用户可以自由定义业务配置如keys、oss等的类型基础。为什么推荐对象导出而不是平铺 key 导出文档明确列出三点理由用户不理解配置项时仍需查文档理解含义除第一层提示外后续层级提示的效率提升并不明显key 平铺导出在过深结构下展示没有任何优势key 导出可能重复但代码层面不会有任何警告或错误难以排查对象形式更友好。加载配置文件两种方式框架提供按环境加载配置文件的能力需要在src/configuration.ts中启用。从 Midway v3 起对象形式是主要的配置加载方式在单文件构建、ESM 等场景下只支持这种标准模块加载方式来加载配置。每个环境的配置文件必须显式指定加入框架随后按实际环境合并。对象形式加载importConfigs 传对象数组// 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 是环境名value 是对应环境的配置值。Midway 启动时会根据当前环境加载对应配置。从 packages/core/src/context/componentLoader.ts#L156-L168 可以看到addImportConfigs的处理逻辑当importConfigs是数组时调用MidwayConfigService.add()否则调用addObject()。add()方法的实现细节configService.ts#L57-L90值得注意字符串且带文件扩展名 → 按文件处理用getConfigEnv解析环境并加入对应环境集合字符串且为目录 →statSync确认目录后readdirSync递归处理目录内所有文件对象 → 遍历每个环境 key加入对应环境集合。同时这里有一个别名机制aliasMap { prod: production, unittest: test }即prod环境的配置同时也会被注册到production环境、unittest会注册到test环境这正是文档合并规则表格中特殊环境映射的底层来源。指定目录和文件加载指定目录加载时会扫描并加载目录下所有config.*.ts文件。注意ESM、单文件部署等场景不支持目录配置加载。importConfigs在这里只是指定需要加载的文件实际运行时会自动选择当前环境去匹配对应的文件后缀。配置文件规则可以指定目录推荐传统的src/config目录也可以指定文件指定文件时不需要带 ts 后缀配置文件必须显式指定加入。示例指定目录// 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 { }文件名的环境解析逻辑在 configService.ts#L122-L131 的getConfigEnv中取文件 basename 按.切分去掉最后一段若非 js/ts 后缀则该段就是环境名再取倒数第二段作为环境名。例如custom.local.ts会被解析为local环境。加载项目外部的配置也可以使用项目外部的配置但必须使用绝对路径且带*.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 环境下加载顺序如下后加载的同名配置会覆盖先加载的- Component config.default.ts - Apply config.default.ts - component config.prod.ts - apply config.prod.ts合并规则与环境文件映射默认情况下会加载**/config.default.ts与**/config.{environment}.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计算出的结果环境值读取的配置文件prod*.default.ts *.prod.tsproduction*.default.ts *.production.ts *.prod.tsunittest*.default.ts *.unittest.tstest*.default.ts *.test.ts *.unittest.ts除上述表格外其余环境一律读取*.default.ts *.{当前环境}.ts。环境的判定逻辑在 packages/core/src/util/index.ts#L30-L32 中export const getCurrentEnvironment () { return process.env[MIDWAY_SERVER_ENV] || process.env[NODE_ENV] || prod; };即MIDWAY_SERVER_ENV优先级最高其次NODE_ENV两者都未设置时默认为prod。对应特殊环境映射prod→production、unittest→test则在 configService.ts#L25-L28 的aliasMap中定义。而load()合并时configService.ts#L133-L199会把default集合与当前环境集合拼接逐个extend(true, target, config)合并。合并使用 extend2数组直接覆盖配置合并使用 extend2 模块进行深拷贝合并extend2 是 extend 的 fork二者在处理数组时有差异const a { arr: [ 1, 2 ], }; const b { arr: [ 3 ], }; extend(true, a, b); // { arr: [ 3 ] }根据上述示例框架会直接覆盖数组而不是做数组合并。这在高危场景如中间件数组、cors 白名单值得特别留意。仓库中的实现在 packages/core/src/util/extend.ts仅对 plain object 递归深合并Types.isPlainObject(copy)其余值直接覆盖同时会跳过undefined值与__proto__键extend.ts#L42-L50。获取配置Config 注入Midway 将配置保存在内部配置服务中整个结构是一个对象。业务代码通过Config装饰器注入使用。Config装饰器定义在 packages/core/src/decorator/common/framework.ts#L42-L52通过DecoratorManager.createCustomPropertyDecorator(CONFIG_KEY, { identifier })注册为属性装饰器。底层取值由 configService.ts#L201-L207 的getConfiguration提供使用safelyGet按路径安全取值。单个配置值默认根据装饰器的字符串参数从配置对象中取值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 提供了三处入口。生命周期中修改onConfigLoadMidway 增加了异步配置加载生命周期onConfigLoad在配置加载完成后执行。返回值会与全局配置合并// 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(); // 返回值会与全局配置合并 // 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; } }cautiononConfigLoad生命周期在 egg 插件如有初始化之后执行不能用于覆盖 egg 插件的配置。从源码看该生命周期由 packages/core/src/service/lifeCycleService.ts#L98-L110 驱动runContainerLifeCycle(lifecycleInstanceList, onConfigLoad, ...)遍历所有生命周期实例执行onConfigLoad每个实例的返回值configData若非空则调用this.configService.addObject(configData)合并进配置并支持通过core.configLoadTimeout配置超时时间。这也是实现远程配置中心 本地配置组合的推荐落点。启动时修改Bootstrap.configure在代码启动前可以使用 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从源码看IMidwayBootstrapOptions.globalConfig的类型定义packages/core/src/interface.ts#L1128-L1130同时允许按环境分组对象数组或普通对象两种形态在 packages/core/src/setup.ts#L332-L338 中框架启动准备阶段会判断数组形态走configService.add()按环境注册对象形态走configService.addObject()直接追加合并随后统一执行configService.load()。BootstrapStarter.configure只是保存 optionspackages/bootstrap/src/bootstrap.ts#L29-L32真正生效在init()传递全局 options 给initializeGlobalApplicationContext之时。这也是 mock 测试中动态注入配置的常用路径。使用 API 修改其他场景下修改配置可以使用 Midway 提供的 API。对应服务即 MidwayConfigService其getConfiguration(configKey?, defaultValue?)支持带默认值的安全取值addObject(obj, reverse)支持在运行期追加合并reversetrue时反向合并可覆盖既有值addFilter支持注册配置过滤器对加载结果做统一加工见 configService.ts#L92-L113 与runWithFilter实现 configService.ts#L254-L265。环境变量与配置dotenv 实践社区中如dotenv等库可以把.env文件加载进环境变量从而把一些密钥放入环境变量中Midway 可以直接依赖它们。$ npm i dotenv --save在项目根目录添加.env文件例如OSS_SECRET12345 OSS_ACCESSKEY54321在入口处初始化例如bootstrap.js或configuration.tsimport { 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 }常见错误与排查思路配置不生效的可能性很多排查思路如下检查配置文件里是否显式配置了与importConfigs相关的文件或目录检查应用启动环境是否与配置文件一致。例如prod 配置绝对不会出现在 local 环境中检查是否混用了普通导出与函数回调导出如以下混用情况。1. 在构造函数中获取 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. 混用回调导出与普通导出以下是错误用法。export default (appInfo) { const config {}; // xxx return config; }; export const keys 12345;用export const定义的值会被忽略。3. 混用 export default 与 export const以下是错误用法。export default { keys: 12345, } export const anotherKey 54321;位于后面的配置会被忽略。4. export 与其他导出混用export 与其他配置混用时如果后面还有其他配置export 的值会被忽略。export { a: 1 } export const b 2;编译结果export const b 2;这四条错误的底层机制可在 configService.ts#L213-L234 的loadConfig中印证当模块为 ES Moduleexports.__esModule且存在default导出时若同时存在其他命名导出Object.keys(exports).length 1会直接抛出MidwayInvalidConfigErrorshould not have both a default export and named export。因此请始终保证每个配置文件只存在单一形式的导出。小结多环境配置是 Midway 应用走向生产环境的必经之路。本文从配置文件组织对象/函数两种导出、importConfigs的三种加载形态对象数组、目录、指定文件、特殊环境映射与合并覆盖规则、Config注入、onConfigLoad/Bootstrap.configure/MidwayConfigService三种动态修改手段以及 dotenv 环境变量实践与四大常见错误完整覆盖了 Midway 3.x 配置体系的实战要点。把握配置必须显式声明、环境由MIDWAY_SERVER_ENV/NODE_ENV决定、数组覆盖而非合并、单一导出形式这几条核心原则即可在本地、测试、预发、生产等环境中游刃有余地管理应用配置。赞分享后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载相关推荐Midway 多环境配置完全指南从配置加载、合并规则到动态修改Midway 多环境配置完全指南从配置加载、合并规则到动态修改 导读 在真实业务中本地开发、单元测试与线上生产往往需要截然不同的配置——数据库地址、缓存连接后端微服务云原生如何永久保存微信聊天记录WeChatMsg完整数据留痕指南如何永久保存微信聊天记录WeChatMsg完整数据留痕指南 你是否曾担心手机更换或意外丢失导致珍贵的聊天记录消失那些与家人朋友的温馨对话、重要的工作沟通、成Midway 多环境配置指南Midway 多环境配置指南 Midway 提供了一套完整的 多环境业务配置 加载机制允许开发者为 local、unittest、prod 等不同环境维护独立后端微服务云原生上一篇终极网盘直链解析指南8大平台免费高速下载完整教程 下一篇抖音批量下载终极指南douyin-downloader免费工具快速上手创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考