logo
3
2
WeChat Login

AssetGateway

AssetGateway 是一个面向对象存储的临时访问网关。

它的核心用途是:

  • 给业务方签发一个短期可控的访问令牌
  • 用这个令牌上传或下载对象,而不是直接暴露存储桶凭证
  • 控制对象访问方式、有效期、命中次数和上传大小
  • 在对象被访问或上传后,按需回调业务系统

适用场景

  • 给前端或第三方发一个一次性上传地址
  • 给外部系统发一个限时下载链接
  • 让业务侧在上传完成后收到回调通知
  • 在不暴露对象存储 AK/SK 的前提下开放文件交换能力

快速开始

1. 准备配置

复制示例配置并按实际环境修改:

cp config.yaml.example config.yaml

最小配置示例:

server: listen: ":8080" host: "https://gateway.example.com" redis: addr: "127.0.0.1:6379" password: "" db: 0 control: tokens: - "control-token-1" credentials: s3-prod: access_key: "your-access-key" secret_key: "your-secret-key" buckets: prod-assets: bucket: "prod-assets" region: "ap-guangzhou" endpoint: "https://cos.ap-guangzhou.myqcloud.com" credential: "s3-prod" force_path_style: false

字段说明:

  • server.listen:服务监听地址
  • server.host:对外访问地址,用于拼接返回给调用方的完整 URL
  • control.tokens:管理接口使用的 Bearer Token 列表
  • credentials:对象存储凭证
  • buckets:可被业务引用的桶别名。接口里传的是别名,不是原始 bucket 名

2. 启动服务

go run . -config config.yaml

3. 健康检查

curl http://127.0.0.1:8080/healthz

返回:

{ "status": "ok" }

接口约定

基本说明

  • 管理接口前缀:/token
  • 对象访问接口前缀:/object
  • /token 下所有接口都需要带 Authorization: Bearer <control-token>
  • /object 下接口只依赖路径里的临时 token,不需要管理令牌
  • 所有错误响应都是 JSON
  • 响应头会带 X-Request-Id

错误响应格式

{ "code": "bad_request", "message": "invalid JSON body", "request_id": "0f4f8f4d-6d59-4df0-8a5c-f8352d2a8f47" }

管理接口

POST /token

创建一个临时访问令牌。

请求头:

Authorization: Bearer control-token-1 Content-Type: application/json

请求体:

{ "bucket": "prod-assets", "key": "videos/demo.mp4", "filename": "demo.mp4", "method": "GET", "expire_at": 1760000000, "max_hits": 3, "size": -1, "callback": "https://example.com/webhook/asset" }

请求字段:

  • token:可选,自定义令牌;不传则自动生成
  • bucket:必填,桶别名
  • key:必填,对象 key
  • filename:可选,下载时用于生成 Content-Disposition
  • method:必填,支持 GETHEADPUT
  • expire_at:可选,Unix 时间戳秒
  • max_hits:可选,最大命中次数,-1 表示不限制
  • size:可选,上传大小限制,单位字节,-1 表示不限制
  • callback:可选,请求成功后异步回调,必须是 httphttps

默认值:

  • expire_at:当前时间后 1800 秒
  • max_hitsPUT 默认 1,其他默认 -1
  • size:默认 -1

成功响应:201 Created

{ "token": "Y2x2b2xJc2hQOENWQ0trdVV6bE81", "method": "GET", "filename": "demo.mp4", "expire_at": 1760000000, "url": "https://gateway.example.com/object/Y2x2b2xJc2hQOENWQ0trdVV6bE81" }

示例:

curl -X POST http://127.0.0.1:8080/token \ -H 'Authorization: Bearer control-token-1' \ -H 'Content-Type: application/json' \ -d '{ "bucket": "prod-assets", "key": "videos/demo.mp4", "filename": "demo.mp4", "method": "GET" }'

GET /token/:token

查询令牌详情。

成功响应:200 OK

{ "token": "Y2x2b2xJc2hQOENWQ0trdVV6bE81", "bucket": "prod-assets", "key": "videos/demo.mp4", "filename": "demo.mp4", "method": "GET", "expire_at": 1760000000, "max_hits": -1, "used_hits": 0, "size": -1, "callback": "https://example.com/webhook/asset", "url": "https://gateway.example.com/object/Y2x2b2xJc2hQOENWQ0trdVV6bE81" }

GET /token/:token/status

查询令牌状态,以及对象当前是否已存在。

成功响应:200 OK

{ "token": "put-token-123", "bucket": "prod-assets", "key": "uploads/report.pdf", "filename": "report.pdf", "method": "PUT", "expire_at": 1760000000, "max_hits": 1, "used_hits": 0, "size": 10485760, "callback": "https://example.com/webhook/asset", "url": "https://gateway.example.com/object/put-token-123", "status_url": "https://gateway.example.com/token/put-token-123/status", "uploaded": true, "object_exists": true, "object_size": 83214, "etag": "6805f2cfc46c0f04559748bb039d69ae" }

说明:

  • 对象不存在时,uploadedobject_exists 会是 false
  • 该接口适合轮询上传是否完成

DELETE /token/:token

删除令牌。

成功响应:204 No Content

对象接口

PUT /object/:token

使用临时令牌上传对象。

请求体就是文件内容本身,可以直接二进制上传。

示例:

curl -X PUT 'http://127.0.0.1:8080/object/put-token-123' \ -H 'Content-Type: application/pdf' \ --data-binary '@/path/to/report.pdf'

成功响应:200 OK

{ "etag": "6805f2cfc46c0f04559748bb039d69ae", "size": 83214 }

说明:

  • 如果 token 配置了 size,超出时返回 413 size_exceeded
  • PUT token 默认只允许成功上传一次
  • HEAD /object/:token 可用于探测上传结果,不消耗 PUT token 次数

GET /object/:token

使用临时令牌下载对象。

示例:

curl -L 'http://127.0.0.1:8080/object/get-token-123' -o demo.mp4

说明:

  • 会透传对象存储返回的响应头
  • 如果创建 token 时带了 filename,响应会带 Content-Disposition
  • 支持 Range 请求头
  • 成功访问后会累计 used_hits

HEAD /object/:token

查询对象元信息,不返回文件内容。

示例:

curl -I 'http://127.0.0.1:8080/object/get-token-123'

典型响应头:

HTTP/1.1 200 OK Content-Length: 83214 ETag: 6805f2cfc46c0f04559748bb039d69ae Content-Disposition: attachment; filename="report.pdf"; filename*=UTF-8''report.pdf

说明:

  • HEAD 不消耗命中次数
  • GET token 和 PUT token 都允许执行 HEAD

回调

创建 token 时传入 callback 后,GETHEADPUT 成功完成都会异步发送回调。

回调示例:

{ "event": "asset.access", "method": "PUT", "status": 200, "bucket": "prod-assets", "key": "uploads/report.pdf", "size": 83214, "etag": "6805f2cfc46c0f04559748bb039d69ae", "range": "", "client_ip": "127.0.0.1", "user_agent": "curl/8.7.1", "referer": "", "request_id": "0f4f8f4d-6d59-4df0-8a5c-f8352d2a8f47", "timestamp": 1760000000 }

说明:

  • 回调是异步发送,不影响主请求返回
  • 当前事件名固定为 asset.access

常见错误码

常见 HTTP 状态与 code

  • 400 bad_request:参数不合法、JSON 格式不合法、bucket 别名不存在、callback 非法
  • 401 unauthorized:缺少或格式错误的 Bearer Token
  • 403 forbidden:管理令牌校验失败
  • 404 token_not_found:token 不存在
  • 404 object_not_found:对象不存在
  • 405 method_not_allowed:token 不允许当前请求方法
  • 409 token_exists:创建时自定义 token 已存在
  • 409 hits_exceeded:token 命中次数已用完
  • 410 token_expired:token 已过期
  • 413 size_exceeded:上传内容超过允许大小
  • 502 upstream_error:对象存储请求失败

一个典型流程

限时下载

  1. 业务服务调用 POST /token 创建 GET token
  2. 从响应里拿到 url
  3. 把这个 URL 发给前端或外部系统
  4. 对方用 GET /object/:token 下载文件

一次性上传

  1. 业务服务调用 POST /token 创建 PUT token
  2. 从响应里拿到 url
  3. 客户端用 PUT /object/:token 直接上传文件
  4. 业务服务可轮询 GET /token/:token/status,或依赖 callback 收到完成通知

About

No description, topics, or website provided.
Language
Go99.1%
Dockerfile0.9%