Files
files/README.md
2026-08-03 23:51:21 +08:00

6.7 KiB
Raw Blame History

Files 文件服务

Files 是 OPS 的公共文件服务,统一管理文件元数据,并通过阿里云 OSS 预签名地址让调用方直传文件。调用方只选择已配置的命名空间,不能指定 OSS 厂商、Bucket 或对象路径。

当前仅支持阿里云 OSS。服务不在本地保存文件已完成上传的文件持续保留临时文件由调用方在使用结束后主动删除只有超时且未完成的上传会被后台任务自动清理。

主要能力

  • 生成 OSS 预签名 PUT 地址,文件不经过 Files 服务中转。
  • 校验命名空间、扩展名、文件大小和上传后的对象大小。
  • 记录文件归属、状态、对象路径、ETag 和公开访问地址。
  • 支持 JWT 用户调用和内部服务调用,二者数据相互隔离。
  • 支持查询与删除本人或本服务创建的文件。
  • 自动清理超过预签名有效期但未完成的上传。

运行依赖

  • Go 1.25.1
  • PostgreSQL
  • Redis
  • 阿里云 OSS Bucket

配置

配置文件位于 etc

etc/files_dev.yaml
etc/files_test.yaml
etc/files_prod.yaml

运行环境由 BSM_RuntimeMode 决定,默认值为 dev。服务读取 ${BSM_Prefix}/etc/files_<mode>.yaml;开发模式未设置 BSM_Prefix 时,使用当前工作目录。

核心配置示例:

ServiceClients:
  assets: <assets 调用密钥>
  dc-control: <dc-control 调用密钥>
  visual: <visual 调用密钥>

ObjectStorage:
  Provider: aliyun
  Endpoint: https://oss-cn-beijing.aliyuncs.com
  Region: cn-beijing
  Bucket: ops-app
  PublicBaseURL: https://ops-app.oss-cn-beijing.aliyuncs.com
  AccessKeyID: ${FILES_OSS_ACCESS_KEY_ID}
  AccessKeySecret: ${FILES_OSS_ACCESS_KEY_SECRET}
  PresignTTLSeconds: 600

Namespaces:
  reports:
    Prefix: reports
    MaxSizeMB: 512
    AllowedExtensions: [.csv, .xlsx, .json, .pdf, .zip]

Cleanup:
  IntervalSeconds: 600

配置说明:

  • ServiceClients:允许调用内部接口的服务名和密钥,服务名必须与请求头 Service-Name 完全一致。
  • Provider:当前只能填写 aliyun
  • EndpointOSS SDK 请求地址,不包含 Bucket 名称。
  • PublicBaseURL:完成上传后返回给调用方的公开访问地址前缀。
  • PresignTTLSeconds:上传地址有效期,允许范围为 603600 秒。
  • Namespaces:调用方可使用的命名空间,以及对应的目录、大小和扩展名限制。
  • Cleanup.IntervalSeconds:扫描并清理超时未完成上传的时间间隔。

OSS 凭证必须通过环境变量提供:

$env:FILES_OSS_ACCESS_KEY_ID = '<AccessKey ID>'
$env:FILES_OSS_ACCESS_KEY_SECRET = '<AccessKey Secret>'

使用用户接口时,还要保证 Files 与 JWT 签发方使用相同密钥:

$env:BSM_JwtSecretKey = '<与 JWT 签发方一致的密钥>'

不要将 AccessKey、数据库密码或生产环境服务密钥写入 README 或提交到代码仓库。

本地启动

files 目录执行:

$env:BSM_RuntimeMode = 'dev'
go run ./cmd/main/main.go

默认监听配置文件中的 12452 端口。启动时会自动创建或更新 files_object 表。

如需只执行表结构迁移:

go run ./cmd/cli/main.go migrate

健康检查:

HEAD /
GET /Files/v1/ping/hello

构建

构建当前 Windows 环境程序:

go build -o build/files.exe ./cmd/main/main.go

打包 Linux amd64 程序:

powershell -ExecutionPolicy Bypass -File ./scripts/pack.ps1

产物为 build/ops-files

调用鉴权

文件接口提供两套路径,功能和请求结构相同。

用户接口使用 JWT

Authorization: <JWT 原始字符串>

JWT 直接放入 Authorization,不要添加 Bearer 前缀。

内部服务接口使用服务名和独立密钥:

Service-Name: assets
Secret-Key: <与 ServiceClients.assets 一致的值>

服务密钥只用于服务之间调用,不是阿里云 AccessKey。调用方不能通过请求选择 OSS 厂商或 Bucket。

文件接口

操作 用户接口 内部服务接口
初始化上传 POST /Files/v1/uploads/init POST /Files/v1/internal/uploads/init
确认上传完成 POST /Files/v1/uploads/:file_id/complete POST /Files/v1/internal/uploads/:file_id/complete
查询文件 GET /Files/v1/files/:file_id GET /Files/v1/internal/files/:file_id
删除文件 DELETE /Files/v1/files/:file_id DELETE /Files/v1/internal/files/:file_id

同一个文件只能由创建它的用户或内部服务访问。用户接口和内部服务接口之间不能交叉访问文件。

上传流程

  1. 调用初始化接口:
POST /Files/v1/internal/uploads/init
Content-Type: application/json
Service-Name: assets
Secret-Key: <服务密钥>

{
  "namespace": "assets",
  "filename": "example.png",
  "size": 102400,
  "content_type": "image/png"
}

成功结果的 details 中包含:

{
  "file_id": "文件标识",
  "object_key": "assets/年/月/文件标识.png",
  "upload": {
    "method": "PUT",
    "url": "OSS 预签名地址",
    "headers": {
      "接口返回的请求头": "接口返回的值"
    },
    "expires_at": "过期时间"
  }
}
  1. 使用 upload.methodupload.url 将文件内容直接上传到 OSS并原样携带 upload.headers。此请求不携带 Files 的 JWT、Service-NameSecret-Key

  2. OSS 上传成功后调用确认接口:

POST /Files/v1/internal/uploads/<file_id>/complete
Service-Name: assets
Secret-Key: <服务密钥>

确认接口会检查 OSS 对象是否存在以及实际大小是否与初始化请求一致。成功后返回文件信息,其中 url 是公开访问地址。

查询和删除

GET /Files/v1/internal/files/<file_id>
DELETE /Files/v1/internal/files/<file_id>

删除接口同时删除 OSS 对象和文件元数据。处于 ready 状态的临时文件不会自动删除,调用方必须在业务使用结束后主动调用删除接口。

响应约定

业务接口使用统一响应结构:

{
  "code": 0,
  "message": "",
  "details": {},
  "timeseq": 0
}
  • code = 0 表示成功。
  • 业务错误通常仍返回 HTTP 200通过非零 code 判断失败。
  • JWT 或内部服务鉴权失败返回 HTTP 401。

OSS 前置设置

当前 PublicBaseURL 使用 OSS Bucket 公网域名,因此 Bucket 需要设置为“公共读”,不能设置为“公共读写”。如果由浏览器直接上传,还需要给 Bucket 配置 CORS

来源:实际前端域名
MethodsPUT、GET、HEAD
允许 Headers*
暴露 HeadersETag、x-oss-request-id

生产环境应使用 RAM 用户的 AccessKey并只授予目标 Bucket 所需的对象上传、查询和删除权限。