Go 1.27.1 (Gin+GORM) + Vue 3 文件快传服务: - 安全审计全部修复(docs/security-audit-2026-09-05.md): bcrypt 密码哈希与自动升级、presign 直传服务端大小/内容校验、 全局请求体上限、依赖升级(govulncheck 0 命中)、janitor 后台清理、 管理端审计动作落库、/admin CORS 收紧、通知内容白名单净化、 会话默认 7 天、限流缓存故障降级、robots.txt 端点等 - 前端:取件链接复制修复(不再重复拼接提取码)、markdown 净化器加固 - Redis 支持库号(FCB_REDIS_DB / redis://…/db URL) - 文档:docs/api/* 与 openapi.yaml 同步最新行为(robots.txt、 提码 5 位起、chunk 32MiB 上限、admin 审计动作等) 验证:gofmt/go vet/go test 全绿;二进制端到端冒烟通过
120 lines
6.2 KiB
Markdown
120 lines
6.2 KiB
Markdown
# 存储引擎配置
|
||
|
||
存储引擎只支持三种:**本地磁盘 / S3 / WebDAV**,由进程级环境变量 `FCB_STORAGE_ENGINE` 选择。
|
||
引擎与引擎相关配置在启动时一次性读取(`storage.SetEngineOptions` → `NewEngine`),
|
||
**运行时修改引擎 KV 需重启服务**(管理端 `GET /admin/config/get` 的 `_engine_hint` 亦有提示)。
|
||
|
||
## 引擎选择
|
||
|
||
```bash
|
||
FCB_STORAGE_ENGINE=local # 启动默认(KV storage_engine 为空时生效)
|
||
FCB_STORAGE_ENGINE=s3
|
||
FCB_STORAGE_ENGINE=webdav
|
||
```
|
||
|
||
非法值直接启动失败:`FCB_STORAGE_ENGINE 无效值 "xxx",仅支持 local|s3|webdav`。
|
||
|
||
**v3 运行时热切换**:管理端 `POST /admin/storage/switch`(或后台设置页「存储引擎」卡)可在不重启的情况下切换引擎——
|
||
先构建新引擎并健康检查,通过才生效;失败 503 保持原引擎。当前引擎持久化在 settings KV `storage_engine`(空=回落启动值)。
|
||
各引擎参数(存储目录/服务地址/存储桶/密钥)同样在后台设置页运行时可改;保存后对应引擎实例缓存失效,下次切换/构建生效。
|
||
|
||
## 文件归属引擎(v3)
|
||
|
||
每条分享记录(`file_codes.engine`)与上传会话(`upload_chunks.engine` / `presign_upload_sessions.engine`)
|
||
在创建时戳记当时的引擎名。下载、分片合并、删除按**归属引擎**操作——切换引擎后,旧引擎里的文件仍可正常下载与删除
|
||
(空戳为历史数据,回落当前引擎)。
|
||
|
||
## 按日期目录存储
|
||
|
||
文件落盘路径:`[storage_path/]share/data/YYYY/MM/DD/<uuid>/<文件名>`(如 `share/data/2026/09/04/…`)。
|
||
按日嵌套目录自然排序、无日月歧义、避免单日海量文件挤在单目录;三种引擎一致适用;历史路径记录在
|
||
`file_codes.file_path`,不受路径规则调整影响。
|
||
|
||
## 配置键与环境变量
|
||
|
||
引擎相关配置键(DB settings KV)可由环境变量种子注入(优先级:默认 < 环境变量 < DB KV):
|
||
|
||
| KV 键 | 环境变量 | 引擎 | 说明 |
|
||
|---|---|---|---|
|
||
| `local_storage_path` | `FCB_LOCAL_STORAGE_PATH` | local | 本地存储根目录(容器内默认 `/app/data`) |
|
||
| `storage_path` | `FCB_STORAGE_PATH` | 全部 | 存储相对路径前缀(空 = `share/data/…`) |
|
||
| `s3_access_key_id` | `FCB_S3_ACCESS_KEY_ID` | s3 | 访问密钥 |
|
||
| `s3_secret_access_key` | `FCB_S3_SECRET_ACCESS_KEY` | s3 | 私有密钥 |
|
||
| `aws_session_token` | `FCB_AWS_SESSION_TOKEN` | s3 | 可选临时会话令牌 |
|
||
| `s3_bucket_name` | `FCB_S3_BUCKET_NAME` | s3 | 桶名 |
|
||
| `s3_endpoint_url` | `FCB_S3_ENDPOINT_URL` | s3 | S3 兼容端点(MinIO/R2 等;AWS 原生可空) |
|
||
| `s3_region_name` | `FCB_S3_REGION_NAME` | s3 | 区域(默认 `auto`) |
|
||
| `s3_addressing_style` | `FCB_S3_ADDRESSING_STYLE` | s3 | `auto`/`path`/`virtual` |
|
||
| `webdav_url` | `FCB_WEBDAV_URL` | webdav | WebDAV 服务地址(如 `http://webdav:5000`) |
|
||
| `webdav_username` | `FCB_WEBDAV_USERNAME` | webdav | 用户名 |
|
||
| `webdav_password` | `FCB_WEBDAV_PASSWORD` | webdav | 密码 |
|
||
| `webdav_root_path` | `FCB_WEBDAV_ROOT_PATH` | webdav | 根目录(默认 `filebox_storage`,不存在自动逐级创建) |
|
||
|
||
`FCB_STORAGE_ENGINE` 本身不落库(`GET /admin/config/get` 中的 `file_storage` 为 KV 记忆键,
|
||
进程实际引擎以 `FCB_STORAGE_ENGINE` 与 `_engine_hint.storage_backend` 为准)。
|
||
|
||
## 各引擎要点
|
||
|
||
### 本地引擎(local)
|
||
|
||
- 原子写:临时文件 + fsync + rename,避免半写文件。
|
||
- 路径安全:`SanitizePath` + 符号链接逃逸双重防穿越。
|
||
- Range 下载基于 `SectionReader`;分片按索引有序合并 + SHA256 校验,合并后清理分片目录。
|
||
|
||
### S3 引擎(s3)
|
||
|
||
- 原生 multipart 流式合并(失败自动 Abort),分片落临时文件保证精确 Content-Length 与可重放。
|
||
- 预签名 GET/PUT 直链(预签名直传唯一 `direct` 模式引擎)。
|
||
- SDK 内置 5xx 指数退避重试;`when_required` 校验模式兼容 MinIO/R2 与纯流式转发。
|
||
|
||
### WebDAV 引擎(webdav,重点优化)
|
||
|
||
- **连接复用**:池化 Transport,连接复用(实测 25 次请求仅 1 条 TCP 连接)。
|
||
- **认证**:Basic + Digest(RFC 2617 `qop=auth`,MD5/SHA-256)自动协商,401 挑战驱动。
|
||
- **Range**:`Range` 头透传 + `206` 解析,支持分块/断点下载。
|
||
- **重试**:5xx/429/408 指数退避(封顶 2s ± 20% 抖动,尊重 `Retry-After`)。
|
||
- **流式**:下载经 `io.Pipe` 流式转发不落盘;上下文取消挂到响应体读完之后,防止提前断连。
|
||
- **目录**:按需逐级 `MKCOL` + 目录缓存,避免重复建目录。
|
||
- **超时**:可配置(`webdav_url` 同级暂无独立超时键,引擎默认值内置)。
|
||
|
||
## 健康检查
|
||
|
||
三引擎均实现 `HealthCheck`:local 写探针、s3 `ListObjectsV2`、webdav `PROPFIND`(根目录不存在时自建)。
|
||
服务启动时预检失败仅告警不阻断;运行状态可经 `GET /api/v1/health` 的 `data.storage` 查看当前引擎名。
|
||
|
||
## 预签名直传支持矩阵
|
||
|
||
| 引擎 | `PresignPutURL` / `PresignGetURL` | init 返回 mode |
|
||
|---|---|---|
|
||
| s3 | ✅ | `direct` |
|
||
| local / webdav | ❌(`ErrNotSupported`) | `proxy`(走服务端代理上传) |
|
||
|
||
引擎不支持的操作经统一映射返回 501:
|
||
|
||
```json
|
||
{ "code": 501, "msg": "当前存储引擎不支持该操作" }
|
||
```
|
||
|
||
## Docker Compose 冒烟编排
|
||
|
||
`deploy/docker-compose.yml` 提供可选 profile(详见 deploy/README.md):
|
||
|
||
```bash
|
||
docker compose --profile minio up -d --build # MinIO(含 mc 自动建桶)+ FCB_STORAGE_ENGINE=s3
|
||
docker compose --profile webdav up -d --build # dufs WebDAV 冒烟(admin/admin123)+ FCB_STORAGE_ENGINE=webdav
|
||
docker compose --profile redis up -d --build # Redis 缓存增强(非引擎)
|
||
```
|
||
|
||
## 存储哨兵错误 → HTTP 状态
|
||
|
||
| 哨兵错误 | HTTP | 文案 |
|
||
|---|---|---|
|
||
| `ErrNotFound` | 404 | 文件不存在 |
|
||
| `ErrInvalidPath` | 400 | 非法文件路径 |
|
||
| `ErrUnavailable` | 503 | 存储服务不可用,请稍后再试 |
|
||
| `ErrNotSupported` | 501 | 当前存储引擎不支持该操作 |
|
||
| `ErrRangeNotSatisfiable` | 416 | 请求范围超出文件大小 |
|
||
| `ErrHashMismatch` | 400 | 分片哈希校验失败,请重新上传 |
|
||
|
||
容量超限(`storageLimit`,经容量预留判定)返回 507:`存储空间已达到管理员设置的容量上限`。
|