跳到主要内容

initDynamicResourceMiddleware(options)

initDynamicResourceMiddleware 是一个功能强大的 Express 中间件,旨在动态地从一个或多个指定目录提供文件。与 initStaticResourceMiddleware 不同,它会实时主动监视文件系统的变化(添加、删除、修改),因此非常适合用于提供在运行时可能发生变化的内容,例如用户上传的文件、主题或插件。

它会构建一个内存中的资源映射以实现快速查找,并能妥善处理缓存、文件过滤和冲突解决。

工作原理

该中间件遵循清晰的生命周期:初始化、扫描、监视和服务。当请求传入时,它会在其内部映射中执行快速查找。如果被监视的目录中有文件被添加或删除,该映射会自动更新。

基本用法

以下是如何配置该中间件以从动态的 uploads 目录提供图片。

Server Setup

javascript
import express from 'express';
import { initDynamicResourceMiddleware } from '@blocklet/uploader-server';
import path from 'path';

const app = express();

const dynamicResourceMiddleware = initDynamicResourceMiddleware({
  resourcePaths: [
    {
      path: path.join(__dirname, 'uploads/images'),
      whitelist: ['.jpg', '.jpeg', '.png', '.gif'],
    },
  ],
  onReady: (count) => {
    console.log(`${count} 个动态资源已准备就绪,可以提供服务。`);
  },
  onFileChange: (filePath, event) => {
    console.log(`文件 ${filePath} 的事件为 ${event}。`);
  },
});

// 挂载中间件
app.use('/uploads/images', dynamicResourceMiddleware);

// 服务器关闭时,清理监视器
process.on('SIGINT', () => {
  if (dynamicResourceMiddleware.cleanup) {
    dynamicResourceMiddleware.cleanup();
  }
  process.exit();
});

app.listen(3000, () => {
  console.log('服务器正在端口 3000 上运行');
});

配置选项

initDynamicResourceMiddleware 函数接受一个包含以下属性的选项对象:

选项类型描述
componentDidstring可选。如果提供,只有当当前组件的 DID 与此值匹配时,中间件才会激活。
resourcePathsDynamicResourcePath[]必需。 一个对象数组,用于定义要监视和提供服务的目录。详见下文。
watchOptionsobject可选。文件系统监视器的配置。
cacheOptionsobject可选。HTTP 缓存头的配置。
onFileChange(filePath: string, event: string) => void可选。当文件被更改、添加或删除时触发的回调函数。event 可以是 'change''rename''delete'
onReady(resourceCount: number) => void可选。在初始扫描完成以及资源映射发生变化时运行的回调函数,提供可用资源的总数。
setHeaders(res, filePath, stat) => void可选。在提供文件之前,用于在响应上设置自定义头的函数。
conflictResolution'first-match' | 'last-match' | 'error'可选。用于处理多个目录包含同名文件时文件名冲突的策略。默认为 'first-match'

DynamicResourcePath 对象

resourcePaths 数组中的每个对象都定义了一个动态资源的来源。

属性类型描述
pathstring必需。 目录的绝对路径。它支持 glob 模式(例如 /path/to/plugins/*/assets),以监视多个匹配的目录。
whiteliststring[]可选。要包含的文件扩展名数组(例如 ['.png', '.svg'])。如果指定,则只提供具有这些扩展名的文件。
blackliststring[]可选。要排除的文件扩展名数组。

watchOptions 对象

属性类型描述
ignorePatternsstring[]在监视期间要忽略的字符串模式或正则表达式数组。
persistentboolean如果为 true,只要文件被监视,进程就会继续运行。默认为 true
usePollingboolean是否使用轮询来监视文件。对于某些网络文件系统可能是必需的。
depthnumber要监视的子目录深度。如果为 undefined,则递归监视。

cacheOptions 对象

属性类型描述
maxAgestring | number设置 Cache-Control 的 max-age 头。可以是一个以毫秒为单位的数字,或一个类似 '365d' 的字符串。默认为 '365d'
immutableboolean如果为 true,则向 Cache-Control 头添加 immutable 指令。默认为 true
etagboolean是否启用 ETag 生成。
lastModifiedboolean是否启用 Last-Modified 头。

高级用法

使用 Glob 模式

要从多个插件目录提供资源,您可以使用 glob 模式。中间件将找到所有匹配的目录并监视它们的变化。

Glob Pattern Example

javascript
const middleware = initDynamicResourceMiddleware({
  resourcePaths: [
    {
      // 监视 'plugins' 下每个目录内的 'assets' 文件夹
      path: path.join(__dirname, 'plugins', '*', 'assets'),
      whitelist: ['.css', '.js', '.png'],
    },
  ],
});

冲突解决

如果两个被监视的目录都包含一个名为 logo.png 的文件,conflictResolution 策略将决定提供哪一个:

  • 'first-match' (默认): 使用初始扫描期间找到的第一个。后续找到的将被忽略。
  • 'last-match': 最后找到的将覆盖任何先前的条目。如果您有覆盖机制,这会很有用。
  • 'error': 向控制台记录一个错误以指示冲突,并且通常使用 first-match 的行为。

返回值

initDynamicResourceMiddleware 函数返回一个 Express 中间件函数。这个返回的函数上还附加了一个 cleanup 方法。

cleanup()

在平滑关闭服务器期间应调用此方法。它会停止所有文件系统监视器并清除内部资源映射,以防止内存泄漏并释放文件句柄。

Cleanup Example

javascript
const server = app.listen(3000);
const dynamicMiddleware = initDynamicResourceMiddleware(/* ...options */);

// ...

function gracefulShutdown() {
  console.log('正在关闭服务器...');
  if (dynamicMiddleware.cleanup) {
    dynamicMiddleware.cleanup();
  }
  server.close(() => {
    console.log('服务器已关闭。');
    process.exit(0);
  });
}

process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);