Skip to content

文件与存储 ​

概述 ​

文件与存储模块为系统提供统一的文件上传、下载、管理与多存储后端能力。它把"存哪里"和"怎么存"解耦:业务侧只关心文件本身,具体落地到本地磁盘还是 S3 对象存储,由后端的 文件配置 决定。

模块包含两块:

  • 文件配置:维护一组存储客户端配置(本地磁盘 / S3 对象存储),其中一条标记为"主配置",是所有落地上传的默认目标。
  • 文件列表:记录已上传文件的结构化信息(名称、路径、大小、类型、所属配置),并提供上传、下载、删除、预签名等操作。

设计上采用 策略模式 + 工厂模式,新增一种存储类型只需在 FileClientFactory 注册一个客户端实现,业务代码无需改动。

核心概念 ​

存储配置(infra_file_config)

每一条配置描述"如何连接并写入某个存储后端"。核心字段为 storage(存储器类型,见下表)与 config(存储相关的具体参数,以 JSON 字典保存)。

存储器枚举值说明
本地磁盘10写入服务器本地目录,依赖静态资源服务对外提供访问
S3 对象存储20兼容 MinIO、阿里云 OSS、腾讯云 COS、七牛云、华为云 OBS 等 S3 协议服务

主配置(master)

系统中有且仅有一条主配置。所有"落库"上传(文件列表中的上传、头像、参数附件等)都先读取主配置,再由其对应的存储客户端完成写入。删除主配置会被拒绝。

文件记录(infra_file)

记录一次上传的元数据。注意:文件的 url 不落库,而是在查询时根据所属配置和存储策略实时计算,因此更换存储或域名后无需迁移数据即可生效。

架构设计 ​

文件存储能力下沉到 app/framework/file 框架层,业务模块 module_infra 只负责记录与编排,二者通过统一的 FileClient 接口交互:

FileClientFactory 以配置编号为维度缓存已创建的客户端;配置更新时会重建客户端,保证热更新生效。

存储类型 ​

本地存储(LOCAL)

文件写入 STATIC_ROOT 下的子目录(默认 upload)。访问地址由 ROOT_PATH + STATIC_URL + 基础路径 + 文件相对路径 拼接而成,并挂载为静态资源对外提供。

基础路径(basePath)必须落在 STATIC_ROOT 之内,否则视为非法配置,避免文件写到静态目录之外无法访问。

S3 存储(S3)

基于 aiobotocore 异步实现。上传、读取、删除都直接操作对象存储;额外支持 预签名上传 / 读取地址,便于前端直连对象存储、减轻后端流量压力。

  • 未配置自定义域名时,会自动按 endpoint + bucket(MinIO 风格)或 bucket + endpoint(云厂商风格)推断访问域名。
  • 公开访问开启时,读取直接返回公开 URL;私有访问则生成带有效期的 GET 预签名地址。

文件配置管理 ​

image-20260930144615167

在「基础设施 → 文件配置」中维护存储客户端。一条配置的关键信息:

  • 配置名:便于识别的名称。
  • 存储器:本地磁盘(10)或 S3 对象存储(20),创建后不可修改。
  • 主配置:标记当前配置是否为主配置,全局唯一。
  • 备注:可选说明。
  • config:随存储器类型变化的参数集合。

不同存储器所需的 config 参数:

参数本地S3说明
basePath✔本地存储根目录下的子目录,默认 upload
endpoint✔节点地址
bucket✔存储桶
accessKey / accessSecret✔访问密钥
enablePathStyleAccess✔是否启用 Path Style 访问(MinIO 等需要)
enablePublicAccess✔是否公开访问
region△区域,一般仅 AWS 需要
domain✔✔自定义访问域名(主机地址)

配置保存后,可点击 测试 按钮:后端会真实写入一个测试文件并读回校验,确保连接与权限配置正确。

文件管理 ​

image-20260930144641558

文件列表页面(「基础设施 → 文件列表」)展示所有上传记录,支持分页查询、上传、复制访问链接、下载/预览、删除与批量删除。图片类型直接缩略图预览,PDF 可在线预览。

上传流程 ​

系统支持两种上传模式,由前端环境变量 VITE_UPLOAD_TYPE 控制:

  • 后端直传(server):文件先发到后端 /infra/file/upload,由后端写入主配置对应的存储。
  • 前端直连(client,仅 S3):前端先向后端申请预签名地址,再直接 PUT 到对象存储,最后将文件信息异步回写后端。

落库上传的路径规则为:业务目录 / 日期目录(YYYYMMDD) / UUID.扩展名,并带有路径穿越清洗,保证文件名与目录安全。

公开下载 ​

GET /infra/file/{configId}/get/{path:path} 是经鉴权的文件内容读取接口,可直接用于 <img src>、附件下载等场景,由后端按配置编号定位存储客户端再取回二进制内容。

安全与校验 ​

上传链路在多处统一做了安全校验(集中在 FileUploadUtil),与具体存储策略无关:

  • 大小限制:超过 MAX_FILE_SIZE(默认 50MB)拒绝上传。
  • 危险扩展名黑名单:DANGEROUS_EXTENSIONS 中的类型(如 .py、.sh、.exe 等可执行/脚本类)拒绝上传。
  • 路径穿越防护:文件名、业务目录、下载路径均会清洗 ../、..\\、\0 等危险片段;本地客户端在路径解析层还会二次校验,确保文件不会跳出存储根目录。
  • 内容类型校验:通过文件魔数检测真实类型,与声明扩展名不一致时告警,降低伪装文件风险。

相关配置

配置项位置默认值说明
STATIC_ROOT后端 settingsstatic/本地存储根目录
STATIC_URL后端 settings/static静态资源访问前缀
UPLOAD_DIR_NAME后端 settingsupload本地存储默认基础路径
MAX_FILE_SIZE后端 settings50 * 1024 * 1024单文件最大字节数(50MB)
DANGEROUS_EXTENSIONS后端 settings脚本/可执行黑名单禁止上传的扩展名
VITE_UPLOAD_TYPE前端 .env—client 前端直连 / server 后端直传

关键接口 ​

接口方法说明
/infra/file/pageGET分页查询文件列表
/infra/file/uploadPOST上传文件并落库
/infra/file/presigned-urlGET获取预签名上传地址
/infra/file/downloadPOST下载文件
/infra/file/{configId}/get/{path}GET公开读取文件内容
/infra/file/delete-listDELETE批量删除文件(含物理文件)
/infra/file-config/pageGET分页查询文件配置
/infra/file-config/create / /updatePOST / PUT新增 / 修改配置
/infra/file-config/update-masterPUT设置主配置
/infra/file-config/testGET测试存储连通性

前端实现 ​

文件相关页面与组件位于 apps/web-ele:

  • 文件配置页:views/infra/fileConfig,表单 modules/form.vue + data.ts(根据 storage 动态展示本地 / S3 字段),API 封装在 api/infra/file-config。
  • 文件列表页:views/infra/file,支持缩略图预览、复制链接、下载/预览、删除,API 封装在 api/infra/file。
  • 通用上传能力:components/upload/use-upload.ts 提供 useUpload(directory) 钩子,封装"前端直连 / 后端直传"两种模式与预签名逻辑;并基于它封装了 image-upload、file-upload、input-upload 等可复用组件,供头像、知识库、富文本等场景直接使用。