☰
Midway 静态资源组件 @midwayjs/static-file 完全指南:从配置到源码实现
2026/9/28 8:24:53 网站建设 项目流程
  • 后端
  • 微服务
  • 云原生

【免费下载链接】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 仓库中 packages/static-file/CHANGELOG.md 的版本演进为主线,结合 packages/static-file/README.md 与组件源码,系统讲解@midwayjs/static-file的安装引入、默认行为、全部配置项、多目录静态服务以及中间件底层实现。读完本文,你将能够在 koa / egg / faas 三种应用中快速搭建静态资源服务,理解懒加载、内存缓存与生产/非生产环境差异,并掌握如何通过源码与测试验证组件行为。


组件定位:Midway 的静态资源服务方案

@midwayjs/static-file是 Midway 官方提供的静态资源托管组件,其定位在 packages/static-file/README.md 中描述得很清楚:基于 koa 生态的 koa-static-cache 实现,可同时用于koa / egg / faas三种应用形态。

从 CHANGELOG.md 可以看到该组件的引入节点:v3.0.0-beta.17(2022-01-18)的 Feature 条目 "add static file" 正是它的诞生记录,随后在 v3 系列中持续迭代修复。当前仓库中组件版本号已演进到4.2.3(见 packages/static-file/package.json),要求 Node.js>=20。

在 packages/static-file/src/index.ts 中,组件对外统一导出Configuration(即 configuration.ts)、中间件、全部配置接口类型以及错误类型,是标准的 Midway 组件接入形态。


安装与引入

安装命令(README 原文):

$ npm i @midwayjs/static-file --save

引入方式是在应用的configuration.ts中通过imports声明组件,示例代码如下:

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 ContainerConfiguration { }

组件内部的挂载逻辑见 packages/static-file/src/configuration.ts:

  • 在onReady阶段,通过MidwayApplicationManager.getApplications(['koa', 'faas', 'egg'])获取三类应用实例;
  • 若容器中已存在cross-domain命名空间(即引入了跨域组件),静态中间件会插入到 CORS 中间件之后(insertAfter(StaticMiddleware, 'cors')),避免跨域头被静态响应覆盖;否则插入到最前(insertFirst),保证静态文件请求最先被处理;
  • onConfigLoad中检测到 faas 环境时会额外强制buffer: true(详见后文 serverless 适配)。

默认配置与默认行为

组件的默认配置定义在 packages/static-file/src/config/config.default.ts:

export default appInfo => { return { staticFile: { dirs: { default: { prefix: '/public', dir: join(appInfo.appDir, 'public'), }, }, dynamic: true, preload: false, buffer: false, maxFiles: 1000, }, }; };

生产环境配置 packages/static-file/src/config/config.prod.ts 在此基础上覆盖两项:

export const staticFile = { maxAge: 31536000, buffer: true, };

汇总为下表:

配置项默认值(开发环境)生产环境(config.prod)说明
dirs.default.prefix/public/public静态资源 URL 前缀
dirs.default.dir$appDir/public$appDir/public静态资源目录
dynamictruetrue是否懒加载(动态发现文件)
preloadfalsefalse是否初始化时预加载全部资源
bufferfalsetrue是否将文件读入内存返回
maxFiles10001000缓存条目上限
maxAge031536000(约 1 年)浏览器缓存有效期(秒)

由此可以得出 README 中强调的核心行为:

  • $appDir/public下的所有静态文件,可通过/public前缀访问,且均为懒加载;
  • 非生产环境不缓存资源,修改文件后立即生效,方便开发调试;
  • 生产环境访问过的资源会被缓存,更新资源后需要重启进程才能生效(buffer: true+ 1 年maxAge的强缓存策略)。

配置项详解

组件完整支持koa-static-cache的全部配置,并在类型定义 packages/static-file/src/interface.ts 中显式声明了每个选项的含义:

配置项类型说明
prefixstringURL 前缀
dirstring要托管的静态目录
dynamicboolean是否在初始化后动态加载文件(不预缓存)
preloadboolean初始化时是否预缓存全部资源,默认 true,通常与dynamic配合使用
bufferboolean是否将文件存入内存返回,而不是每次请求都从文件系统流式读取
maxFilesnumber缓存条目上限,仅在dynamic为 true 时生效,默认 1000
maxAgenumber缓存控制最大有效期(秒),默认 0
cacheControlstring可选的 Cache-Control 响应头,优先级高于maxAge
gzipboolean当请求的 Accept-Encoding 包含 gzip 时,对文件进行 gzip 压缩
aliasobject路径别名映射
filterfunction \| string[]初始化扫描目录时过滤文件,例如跳过非构建产物;传数组则仅允许列出的文件

其中maxFiles是组件额外提供的选项(README 原文),用于控制动态缓存规模。


多目录静态服务配置

默认只托管$appDir/public一个目录,但组件支持通过dirs配置同时托管多个目录,每个目录可独立指定前缀:

// {app_root}/src/config/config.default.ts export const staticFile = { dirs: { default: { prefix: '/public', dir: 'xxx' }, antoherDir: { prefix: '/', dir: 'xxx' } } };

如果只想覆盖默认前缀(例如让/public目录直接以根路径/访问),只需改写dirs.default:

// {app_root}/src/config/config.default.ts export const staticFile = { dirs: { default: { prefix: '/', }, } };

测试夹具 packages/static-file/test/fixtures/koa-with-different-dirs/src/config.default.ts 展示了双目录、双前缀的完整写法——default目录绑定/、another目录绑定/static:

export const staticFile = { dirs: { default: { prefix: '/', dir: join(__dirname, '../public') }, another: { prefix: '/static', dir: join(__dirname, '../static') } } };

注意:dirs中多个目录也可以共享同一个前缀(见 koa-with-dirs 的夹具,两个目录均绑定/),静态中间件会依次尝试匹配,因此同名文件在靠前的目录命中后即返回。


中间件实现原理

组件核心是 packages/static-file/src/middleware/static.middleware.ts 中的StaticMiddleware,其resolve方法揭示了完整的处理链路:

  1. 汇总目录:读取staticFileConfig.dirs的每个值,若还存在顶层dir配置也一并加入,统一遍历处理;
  2. Range 支持:注册一个前置rangeMiddleware,一旦请求路径命中任一已注册前缀,就交由koa-range(package.json 中的依赖koa-range@0.3.0)处理 Range 请求,支持视频/大文件的断点续传;
  3. 逐目录创建缓存器:将全局配置与单个目录配置合并(Object.assign({}, this.staticFileConfig, dirObj),目录级配置优先);当dynamic为 true 且未提供files时,使用ylru库构造LRU(maxFiles)作为动态缓存;
  4. 目录存在性校验:pkg 打包环境用fs.existsSync同步校验,源码运行环境用异步FileUtils.exists校验;目录不存在则抛出DirectoryNotFoundError(定义于 packages/static-file/src/error.ts,错误码static_file/10000,消息为Path xxx not exist, please check it.);
  5. 组合执行:将rangeMiddleware与每个目录的staticCache(newOptions)依次compose成一个中间件串返回。

StaticMiddleware.getName()返回'staticFile',与 configuration.ts 中的命名空间static-file对应,也便于日志中标识(启动时会打印[midway:static] starting static serve <prefix> -> <dir>)。


测试与验证

组件的行为在 packages/static-file/test/index.test.ts 中有三个典型用例可直接验证:

  • 同前缀多目录:koa-with-dirs夹具下,/foo.js与/index.html都能正确返回文件内容(console、<body>hello</body>);
  • 不同前缀多目录 + Range:koa-with-different-dirs夹具下,/foo.js走根前缀、/static/index.html走/static前缀;且对/foo.js发起Range: bytes=0-10请求时,响应携带content-length: 11、Accept-Ranges: bytes、Content-Range: bytes 0-10/20,验证了断点续传能力;
  • faas 环境:faas-with-dirs夹具通过createLegacyFunctionApp启动,/foo.js同样正常返回。

运行方式(package.json):

$ npm run test # 或 npm run ci / npm run cov

版本演进与关键修复

CHANGELOG 中除大量 "Version bump only"(lerna 发布时生成的版本号占位记录,不包含实际代码变更)外,可以梳理出如下实质性演进:

版本类型变更内容
3.0.0-beta.17Feature新增 static-file 组件,首次落地
3.0.0-beta.3Feature增加组件与框架配置定义(StaticFileOptions类型体系)
3.0.1Bug Fix补充缺失的maxAge配置,修复静态响应缺失缓存头的问题
3.0.2Bug Fix修复 singleton 调用下 request scope 不生效的问题
3.0.4Bug Fix修复 supertest 类型与createFunctionApp相关问题
3.1.0Bug Fix使用 hook 加载 egg 应用,适配 egg 场景
3.2.1Bug Fix修复 swagger UI 替换 json path(静态资源与 swagger 路径协同)
3.4.0-beta.4Bug Fixserverless 环境下返回 buffer——与 configuration.ts 中 faas 环境强制buffer: true的实现对应
3.6.0Feature增加 guard 支持,使静态中间件可被 guard 体系保护

其中 3.4.0-beta.4 的 "return buffer in serverless environment" 尤其值得关注:在函数计算场景下,流式读取文件系统可能受限,组件因此在检测到 faas 应用时自动开启内存缓冲模式,这正是 configuration.ts 中onConfigLoad钩子的实现动机,也解释了为什么生产环境默认buffer: true。


使用建议小结

  • 开发环境:保持默认即可,dynamic: true+buffer: false保证改文件即时生效;
  • 生产环境:默认 1 年maxAge与buffer: true适合内容基本不变的打包产物,更新资源后需重启进程;若资源频繁变动,可自行覆盖maxAge或关闭buffer;
  • 多目录场景:用dirs为不同目录(如用户上传目录、前端构建产物目录)分配不同前缀,并注意目录必须真实存在,否则启动时会抛出DirectoryNotFoundError;
  • 大文件/音视频:组件内置 Range 支持,可放心用于断点续传场景,相关断言可在测试用例中复现验证。
  • 后端
  • 微服务
  • 云原生

【免费下载链接】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
点击查看免费下载
上一篇:如何免费解锁WeMod专业版:Wand-Enhancer增强工具终极指南
下一篇:一条命令跑通 go2rtc:零配置实现摄像头多协议串流与 WebRTC 低延迟预览

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询