middleware

中间件文档

CloudFS 中间件通过 cloudfs.WrapFunc 包装已有的 cloudfs.FS,用于在不修改底层驱动实现的前提下增加路径映射、缓存、限速、压缩、加密等能力。

使用方式

 1base, err := local.New(&local.Option{Path: "/data"})
 2if err != nil {
 3	panic(err)
 4}
 5
 6fs, err := middleware.NewFS(
 7	base,
 8	middleware.PrefixFS("/team-a"),
 9	middleware.CacheFS(&middleware.CacheOption{ExpireTime: 60}),
10)

middleware.NewFS 实际上等价于 cloudfs.New

中间件列表

CacheFS

用于缓存目录列表,减少重复 List() 调用。

1fs, err := middleware.NewFS(
2	base,
3	middleware.CacheFS(&middleware.CacheOption{ExpireTime: 60}),
4)

参数:

字段 类型 默认值 说明
expire_time time.Duration 60 缓存有效时长,代码中按“秒”使用

行为说明:

  • List() 会按路径缓存目录结果
  • Stat() 会优先从父目录缓存中查找目标项
  • Create()Rename()Move()Copy()MakeDir()Remove() 会主动失效相关目录缓存
  • ExpireTime <= 0 时,内部会回退到 60

注意事项:

  • 当前缓存只缓存目录项,不缓存文件内容
  • ExpireTime 字段类型是 time.Duration,但实现里按秒处理,因此传入 60 表示 60 秒,传入 time.Minute 会得到更大的数值

RateLimitFS

用于限制调用频率,适合 API 限流较严格的远程驱动。

1fs, err := middleware.NewFS(
2	base,
3	middleware.RateLimitFS(&middleware.RateLimitOption{
4		Wait:  true,
5		Burst: 10,
6		Limit: 1,
7	}),
8)

参数:

字段 类型 默认值 说明
wait bool false 触发限流时是否等待令牌
burst int 100 桶容量
limit time.Duration 1 单个令牌的时间间隔,代码中按秒处理

行为说明:

  • 会拦截 ListCopyMoveRenameRemoveMakeDirStatOpenCreate
  • Wait=false 且无可用令牌时,返回错误 访问频率限制
  • Wait=true 时,会阻塞直到拿到令牌或 context.Context 取消

注意事项:

  • 默认值相当于“每秒约 1 次补充,桶容量 100”
  • Limit 不是 QPS,而是令牌补充间隔

CompressFS

对写入内容进行 gzip 压缩,对读取内容进行 gzip 解压。

1fs, err := middleware.NewFS(
2	base,
3	middleware.CompressFS(&middleware.CompressOption{
4		Level: gzip.BestCompression,
5	}),
6)

参数:

字段 类型 默认值 说明
level int gzip.BestCompression gzip 压缩级别

行为说明:

  • Create() 返回的 writer 会把写入内容压缩后再交给底层驱动
  • Open() 返回的 reader 会自动解压底层内容

注意事项:

  • 底层存储的是压缩后的二进制内容,不会自动追加 .gz 后缀
  • 只适合由同一层中间件读写的场景

EncryptFS

对文件内容以及路径名做透明加密/解密。

 1fs, err := middleware.NewFS(
 2	base,
 3	middleware.EncryptFS(&middleware.EncryptOption{
 4		Password:     "secret",
 5		PasswordSalt: "secret-salt",
 6		Mode:         "CFB",
 7		DirName:      true,
 8		FileName:     true,
 9		Version:      "v2",
10	}),
11)

参数:

字段 类型 默认值 说明
mode string CFB 加密模式,可选 CTROFB、其他值回退 CFB
dir_name bool false 是否加密目录名
file_name bool false 是否加密文件名
suffix string "" 不加密文件名时,为底层文件追加后缀
password string 必填,加密密码
password_salt string password 相同 生成 IV 使用
version string v1 兼容模式 v2 使用新版 IV 生成方式

行为说明:

  • 文件内容通过流式 AES 加密/解密
  • 可分别控制目录名和文件名是否加密
  • suffix 常用于“不加密文件名但隐藏真实扩展名”的场景
  • Stat() 因为无法预先判断路径是文件还是目录,必要时会尝试两次

注意事项:

  • password 为空时会直接返回错误
  • Version 不是校验字段,只有 v2 会启用新版 IV,其余值都走兼容逻辑
  • 修改 PasswordPasswordSaltModeVersion 后,旧数据可能无法再正常读取

HookFS

提供完全自定义的路径映射和文件信息映射能力,适合高级场景。

 1fs, err := middleware.NewFS(
 2	base,
 3	middleware.HookFS(&middleware.HookOption{
 4		PathFn: func(path string) string {
 5			return "/tenant-a" + path
 6		},
 7		FileFn: func(file cloudfs.FileInfo) (cloudfs.FileInfo, bool) {
 8			return file, true
 9		},
10	}),
11)

参数:

字段 类型 说明
PathFn func(string) string 将外部路径转换为底层路径
FileFn func(cloudfs.FileInfo) (cloudfs.FileInfo, bool) 转换文件信息,bool=false 时会过滤掉当前文件

行为说明:

  • PathFn 会应用于 ListStatOpenCreateCopyMoveRenameRemoveMakeDir
  • FileFn 会应用于 ListStat
  • 这是代码级扩展点,不适合通过 JSON 配置动态构造

PrefixFS

给底层驱动自动追加固定前缀,是 HookFS 的常见封装。

1fs, err := middleware.NewFS(base, middleware.PrefixFS("/project-a"))

效果:

  • 访问 /docs/a.txt 时,底层会访问 /project-a/docs/a.txt
  • 对外暴露的路径会自动去掉该前缀

TrimPrefixFS

把外部路径上的指定前缀裁剪后再传给底层驱动。

1fs, err := middleware.NewFS(base, middleware.TrimPrefixFS(base, "/mnt"))

效果:

  • 对外访问 /mnt/docs/a.txt
  • 底层实际访问 /docs/a.txt

注意事项:

  • 这个函数签名为 TrimPrefixFS(fs cloudfs.FS, prefix string),但返回值仍然是 cloudfs.WrapFunc
  • 常见用途是兼容某些底层驱动不接受以 / 开头的路径,例如 SMB 驱动内部就使用了它

组合建议

推荐组合顺序:

  1. 路径类中间件:PrefixFSTrimPrefixFSHookFS
  2. 内容类中间件:EncryptFSCompressFS
  3. 行为类中间件:CacheFSRateLimitFS

原因:

  • 先统一路径,再处理内容,最后做缓存和限流,通常更容易理解和排查问题
  • 如果同时使用加密和压缩,常见顺序是“先压缩再加密”

已知限制

  • 中间件没有统一的动态注册机制,通常需要在代码中显式拼装
  • HookOption 包含函数,不能直接从 JSON 动态反序列化
  • CacheOptionRateLimitOptiontime.Duration 字段当前实现都按秒使用

©2026 · 红枫文档