# Files 文件服务 Files 是 OPS 的公共文件服务,统一管理文件元数据,并通过阿里云 OSS 预签名地址让调用方直传文件。调用方只选择已配置的命名空间,不能指定 OSS 厂商、Bucket 或对象路径。 当前仅支持阿里云 OSS。服务不在本地保存文件,已完成上传的文件持续保留,临时文件由调用方在使用结束后主动删除;只有超时且未完成的上传会被后台任务自动清理。 ## 主要能力 - 生成 OSS 预签名 PUT 地址,文件不经过 Files 服务中转。 - 校验命名空间、扩展名、文件大小和上传后的对象大小。 - 记录文件归属、状态、对象路径、ETag 和公开访问地址。 - 支持 JWT 用户调用和内部服务调用,二者数据相互隔离。 - 支持查询与删除本人或本服务创建的文件。 - 自动清理超过预签名有效期但未完成的上传。 ## 运行依赖 - Go 1.25.1 - PostgreSQL - Redis - 阿里云 OSS Bucket ## 配置 配置文件位于 `etc`: ```text etc/files_dev.yaml etc/files_test.yaml etc/files_prod.yaml ``` 运行环境由 `BSM_RuntimeMode` 决定,默认值为 `dev`。服务读取 `${BSM_Prefix}/etc/files_.yaml`;开发模式未设置 `BSM_Prefix` 时,使用当前工作目录。 核心配置示例: ```yaml ServiceClients: assets: dc-control: 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`。 - `Endpoint`:OSS SDK 请求地址,不包含 Bucket 名称。 - `PublicBaseURL`:完成上传后返回给调用方的公开访问地址前缀。 - `PresignTTLSeconds`:上传地址有效期,允许范围为 60~3600 秒。 - `Namespaces`:调用方可使用的命名空间,以及对应的目录、大小和扩展名限制。 - `Cleanup.IntervalSeconds`:扫描并清理超时未完成上传的时间间隔。 OSS 凭证必须通过环境变量提供: ```powershell $env:FILES_OSS_ACCESS_KEY_ID = '' $env:FILES_OSS_ACCESS_KEY_SECRET = '' ``` 使用用户接口时,还要保证 Files 与 JWT 签发方使用相同密钥: ```powershell $env:BSM_JwtSecretKey = '<与 JWT 签发方一致的密钥>' ``` 不要将 AccessKey、数据库密码或生产环境服务密钥写入 README 或提交到代码仓库。 ## 本地启动 在 `files` 目录执行: ```powershell $env:BSM_RuntimeMode = 'dev' go run ./cmd/main/main.go ``` 默认监听配置文件中的 `12452` 端口。启动时会自动创建或更新 `files_object` 表。 如需只执行表结构迁移: ```powershell go run ./cmd/cli/main.go migrate ``` 健康检查: ```text HEAD / GET /Files/v1/ping/hello ``` ## 构建 构建当前 Windows 环境程序: ```powershell go build -o build/files.exe ./cmd/main/main.go ``` 打包 Linux amd64 程序: ```powershell powershell -ExecutionPolicy Bypass -File ./scripts/pack.ps1 ``` 产物为 `build/ops-files`。 ## 调用鉴权 文件接口提供两套路径,功能和请求结构相同。 用户接口使用 JWT: ```text Authorization: ``` JWT 直接放入 `Authorization`,不要添加 `Bearer ` 前缀。 内部服务接口使用服务名和独立密钥: ```text 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. 调用初始化接口: ```http 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` 中包含: ```json { "file_id": "文件标识", "object_key": "assets/年/月/文件标识.png", "upload": { "method": "PUT", "url": "OSS 预签名地址", "headers": { "接口返回的请求头": "接口返回的值" }, "expires_at": "过期时间" } } ``` 2. 使用 `upload.method` 和 `upload.url` 将文件内容直接上传到 OSS,并原样携带 `upload.headers`。此请求不携带 Files 的 JWT、`Service-Name` 或 `Secret-Key`。 3. OSS 上传成功后调用确认接口: ```http POST /Files/v1/internal/uploads//complete Service-Name: assets Secret-Key: <服务密钥> ``` 确认接口会检查 OSS 对象是否存在以及实际大小是否与初始化请求一致。成功后返回文件信息,其中 `url` 是公开访问地址。 ### 查询和删除 ```http GET /Files/v1/internal/files/ DELETE /Files/v1/internal/files/ ``` 删除接口同时删除 OSS 对象和文件元数据。处于 `ready` 状态的临时文件不会自动删除,调用方必须在业务使用结束后主动调用删除接口。 ## 响应约定 业务接口使用统一响应结构: ```json { "code": 0, "message": "", "details": {}, "timeseq": 0 } ``` - `code = 0` 表示成功。 - 业务错误通常仍返回 HTTP 200,通过非零 `code` 判断失败。 - JWT 或内部服务鉴权失败返回 HTTP 401。 ## OSS 前置设置 当前 `PublicBaseURL` 使用 OSS Bucket 公网域名,因此 Bucket 需要设置为“公共读”,不能设置为“公共读写”。如果由浏览器直接上传,还需要给 Bucket 配置 CORS: ```text 来源:实际前端域名 Methods:PUT、GET、HEAD 允许 Headers:* 暴露 Headers:ETag、x-oss-request-id ``` 生产环境应使用 RAM 用户的 AccessKey,并只授予目标 Bucket 所需的对象上传、查询和删除权限。