cos

package
v2.2.20 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

README

ioc/cos 多实例腾讯云 COS 配置中心

基于 cos-go-sdk-v5 的多实例对象存储客户端封装。统一管理:

  • 多个 COS 桶(公开 CDN 桶 / 私有文档桶 / 内部工具桶 一进程并存)
  • 声明式命名(业务用 name 取,杜绝硬编码 secret/bucket)
  • 指针字段继承(实例参数缺省时回退到全局默认值)
  • 业务层重试(指数退避 + ctx 感知 + 结构化日志,已禁用 SDK 内置重试)

1. 配置模型

defaults             —— 全局默认值(连接池 / 超时 / 重试 / 分块 等)
instances []Instance —— 命名实例(secret + bucket_url + 局部覆盖)

继承链:

instance.max_idle_conns ←  defaults.default_max_idle_conns ← 内置 200
instance.part_size      ←  defaults.default_part_size      ← 内置 8(MB)
instance.max_retries    ←  defaults.default_max_retries    ← 内置 3

2. 配置示例

TOML(config.example.toml
[cos]
default_max_idle_conns = 200
default_part_size      = 8

[[cos.instances]]
name       = "public-cdn"
secret_id  = "${COS_PUB_ID}"
secret_key = "${COS_PUB_KEY}"
bucket_url = "https://pub-1234.cos.ap-guangzhou.myqcloud.com"
part_size  = 16

[[cos.instances]]
name       = "private-doc"
secret_id  = "${COS_PRIV_ID}"
secret_key = "${COS_PRIV_KEY}"
bucket_url = "https://priv-1234.cos.ap-shanghai.myqcloud.com"
YAML(config.example.yaml

完全等价的 yaml 写法,参见示例文件。


3. 推荐全局配置(按环境)

下列 YAML 仅展示顶层 defaults 段,直接拷贝即可作为全局基线,业务实例可在 [[cos.instances]] 中按需覆盖。

3.1 默认(NewCOS() 出厂值,零配置时的实际行为)
default_service_url: "https://service.cos.myqcloud.com"
default_max_idle_conns: 200
default_max_idle_conns_per_host: 100
default_max_conns_per_host: 200
default_idle_conn_timeout: 90
default_dial_timeout: 10
default_keep_alive: 60
default_tls_handshake_timeout: 10
default_response_header_timeout: 30
default_expect_continue_timeout: 1
default_client_timeout: 60        # 兜底超时;大文件 Multipart 业务自行 ctx.WithTimeout 覆盖
default_max_retries: 3
default_retry_backoff: 200
default_part_size: 8
default_thread_pool_size: 5
default_check_point: true

为什么这么配

  • max_idle_conns=200 / per_host=100 / max_conns_per_host=200:与 Go HTTP transport 默认(2/2/0)相比大幅放大——COS 是高并发对象存储,连接复用是性能命脉。
  • idle_conn_timeout=90s:与多数 LB / NAT 网关的空连断开时间(90~120s)对齐。
  • dial_timeout=10s / tls_handshake=10s:跨地域 / 公网链路的容忍上限。
  • response_header_timeout=30s:COS API 头部应在 30s 内返回;超过即可视为后端异常。
  • client_timeout=60s:HTTP 整体超时兜底——即使业务忘记加 ctx,单个 Put/Get 也不会 hang 住整个 worker。大文件 Multipart 的 Upload/Download 内部分块进行,每块都受这 60s 限制(不是全文件),不会误伤;如需对单次小请求设更短超时,仍用 ctx.WithTimeout 覆盖。
  • max_retries=3 + retry_backoff=200ms(指数退避:200/400/800ms):抵御瞬态网络抖动。
  • part_size=8MB:腾讯云 COS 推荐起点;单文件 ≤80GB(10000 块上限)够用。
  • thread_pool_size=5:分块并发 5,单实例峰值带宽 ~5×单连接吞吐,适合 4C8G 服务。
  • check_point=true:断点续传,大文件传输中网络抖动可恢复。
3.2 dev(本机开发)
default_max_idle_conns: 50
default_max_idle_conns_per_host: 20
default_max_conns_per_host: 50
default_idle_conn_timeout: 90
default_dial_timeout: 5
default_keep_alive: 60
default_tls_handshake_timeout: 5
default_response_header_timeout: 30
default_expect_continue_timeout: 1
default_client_timeout: 0          # 开发期不要兜底,方便调试长任务
default_max_retries: 1
default_retry_backoff: 200
default_part_size: 8
default_thread_pool_size: 2
default_check_point: true

为什么这么配

  • 池大小缩小:本机不会有几百上千 QPS。
  • client_timeout=0:开发期常常需要打断点 / 慢慢调试,硬超时反而干扰。
  • max_retries=1:开发期重试会掩盖真实问题(如 secret 写错),让它直接报错。
  • thread_pool_size=2:单机带宽通常受限,并发 5 容易把家用宽带打满。

调优建议

  • 调试预签名 URL 失败时,把 dial_timeout 提到 30,避免本机 DNS 抖动误判。
3.3 test(CI / 单元测试)
default_max_idle_conns: 10
default_max_idle_conns_per_host: 5
default_max_conns_per_host: 10
default_idle_conn_timeout: 30
default_dial_timeout: 2
default_keep_alive: 60
default_tls_handshake_timeout: 2
default_response_header_timeout: 10
default_expect_continue_timeout: 1
default_client_timeout: 30
default_max_retries: 0             # 单测要确定性结果,不重试
default_retry_backoff: 100
default_part_size: 8
default_thread_pool_size: 1
default_check_point: false         # CI 临时文件,不需要断点续传

为什么这么配

  • 所有超时压短:CI 中常有 mock COS 或本地 MinIO,2~10s 足够,能更快暴露未启动 / 端口错配问题。
  • max_retries=0:单测应是"一次成功或失败",重试会让"偶发失败"被吞掉造成 flaky test。
  • check_point=false:CI 临时容器跑完即销毁,断点信息无意义。
  • thread_pool_size=1:单测要可重复,多并发引入时序不确定性。

调优建议

  • 用真实 COS 跑端到端测试时,把 dial_timeout / response_header_timeout 与 prod 对齐(10/30)。
3.4 prod(生产环境)
default_max_idle_conns: 200
default_max_idle_conns_per_host: 100
default_max_conns_per_host: 200
default_idle_conn_timeout: 90
default_dial_timeout: 10
default_keep_alive: 60
default_tls_handshake_timeout: 10
default_response_header_timeout: 30
default_expect_continue_timeout: 1
default_client_timeout: 60
default_max_retries: 3
default_retry_backoff: 200
default_part_size: 8
default_thread_pool_size: 5
default_check_point: true

为什么这么配(与"默认"完全一致):

  • 200 个连接配合 100/host 能撑数百 QPS 的对象上传/下载。
  • client_timeout=60 是经过实战检验的"既能保护服务、又不误杀大文件分块"的黄金值。
  • 慢请求 1s 阈值会自动 Warn 级别打印(见 cos.go)。

调优建议(按场景)

业务画像 max_idle_conns per_host thread_pool_size client_timeout
普通业务上传/下载(每秒数十次) 200 100 5 60
高吞吐图片/视频处理(每秒数百次) 500 200 8 60
大文件批量同步(GB 级) 200 100 16 0(用 ctx 控制)
CDN 回源 / 静态资源 1000 500 5 30
跨境 / 公网链路 200 100 3 120

特殊场景调参

  • 超大文件(>10GB)传输:实例级覆盖 part_size=32~64(MB),减少分块数;client_timeout=0 + 业务 ctx 控制总时长。
  • 海量小文件上传(< 1MB):实例级 part_size=8thread_pool_size=1(不需要分块),把 max_idle_conns_per_host 提到 200。
  • 预签名 URL 高并发签发:是纯 CPU 计算,不走 HTTP;与连接池大小无关,重点是 secret_id/key 不要泄露到日志。
  • 公网链路抖动严重max_retries=5retry_backoff=500response_header_timeout=60
  • 私有化部署 COSE / 自建 S3 兼容tls_insecure_skip_verify=true 仅在内网受控环境,否则切勿打开。
  • CDN 回源场景:业务多为 GET,thread_pool_size 不重要;把 idle_conn_timeout 提到 300 减少建连开销。

4. 业务代码用法

业务侧使用本模块的核心动作只有两步:拿到 *COS 配置实例 → 通过 name 路由到对应桶。 下面按"基础对象 / 大文件分块 / 元信息&列举 / 预签名 / 高级直通 SDK / 内省运维"六个最常用场景给出最小可运行示例,所有 API 均与 cos.go / object.go / multipart.go / presign.go 一一对应。

4.1 基础对象上传 / 下载(自动重试)
import (
    "bytes"
    "context"
    "gitee.com/hexug/go-tools/v2/ioc"
    iocs "gitee.com/hexug/go-tools/v2/ioc/cos"
)

// 从容器取 *COS;类型断言失败说明 Init 阶段未注册成功
co := ioc.Container.GetConf(iocs.ConfName).(*iocs.COS)

ctx := context.Background()

// 流式上传:业务自己控制 io.Reader,避免一次性加载到内存
_ = co.Put(ctx, "public-cdn", "img/avatar.png", bytes.NewReader(data), nil)

// 文件路径上传:内部会 Open 并按需重试
_ = co.PutFromFile(ctx, "public-cdn", "img/avatar.png", "/tmp/a.png", nil)

// 流式下载:调用方负责 Close
rc, err := co.Get(ctx, "public-cdn", "img/avatar.png", nil)
if err != nil {
    return err
}
defer rc.Close()

// 直接落盘:内部会 mkdir + 写文件 + 重试
_ = co.GetToFile(ctx, "public-cdn", "img/avatar.png", "/tmp/b.png", nil)
4.2 大文件分块上传 / 下载(断点续传)
// 分块上传:超过 sdk 阈值时自动切片并发;返回 CompleteMultipartUploadResult
_, err := co.Upload(ctx, "private-doc", "big/data.bin", "/tmp/data.bin", nil)
if err != nil {
    return err
}

// 分块下载:自动按 Range 并发拉取,失败可断点续传
_ = co.Download(ctx, "private-doc", "big/data.bin", "/tmp/data.bin", nil)
4.3 元信息 / 删除 / 列举
// Head:拿对象元信息(Content-Length / Last-Modified / 自定义 meta)
_, _ = co.Head(ctx, "public-cdn", "img/avatar.png", nil)

// Delete:变长可选参数对齐 SDK 签名;不传 opt 即为最简删除
_ = co.Delete(ctx, "public-cdn", "img/avatar.png")

// List:opt 可控 Prefix / Marker / MaxKeys 实现分页
_, _ = co.List(ctx, "public-cdn", nil)
4.4 预签名(前端直传 / 临时下载)
import "time"

// PresignGet:临时下载 URL(适合分享、私有桶临时放权)
u, _ := co.PresignGet(ctx, "private-doc", "doc/secret.pdf", 5*time.Minute)

// PresignPut:前端直传 URL(避免文件流经业务后端)
u, _ = co.PresignPut(ctx, "public-cdn", "img/upload.png", time.Hour)

// PresignHead / 通用 PresignURL 见源码 presign.go
4.5 直通底层 SDK Client(覆盖本模块未封装的 API)
// 仅在需要直接调用 cos-go-sdk-v5 的高级接口(如批量、版本控制、跨区域复制)时使用
sdkCli := co.Client("public-cdn")
_ = sdkCli // 例如:sdkCli.Object.MultiUpload(...)
4.6 内省与运维(健康检查)
co.Names()                           // 返回 []string,列出已声明的全部实例 name
_ = co.HealthCheck(ctx)              // 并发探活全部实例;任一失败即返回 error
_ = co.HealthCheckOne(ctx, "public-cdn") // 仅探活某个实例(适合 readiness 探针按桶分级)
4.7 STS 临时凭证(前端直传 / 子进程下放权限)

业务场景:服务端把永久 secret_key 下发到端侧 / 子进程,改为按需向腾讯云 STS 申请最小权限、有时效的临时凭证。本节示例与 sts.go / sts_policy.go / sts_cache.go 一一对应,所有调用零硬编码、按 name 路由实例。

示例 1:申请临时凭证(最小权限)

申请仅能向 uploads/2026/ 前缀写入对象的临时凭证;Action 必须以 name/cos:name/sts: 开头,禁止 * 通配;KeyPrefixKey 必须二选一。

import (
    "context"
    "gitee.com/hexug/go-tools/v2/ioc"
    iocs "gitee.com/hexug/go-tools/v2/ioc/cos"
)

co := ioc.Container.GetConf(iocs.ConfName).(*iocs.COS)
ctx := context.Background()

// scope 描述本次临时凭证的权限范围(最小权限原则)
scope := iocs.STSScope{
    Action:        []string{"name/cos:PutObject"},   // 仅授权写入
    KeyPrefix:     "uploads/2026/",                  // 仅作用于该前缀
    DurationSecs:  600,                              // 有效期 600 秒,越界自动截断到 [60, 7200]
    MaxObjectSize: 5 * 1024 * 1024,                  // 上传上限 5MB
    ContentType:   "image/jpeg",                     // 仅允许 image/jpeg
}
cred, err := co.IssueSTS(ctx, "public-cdn", scope)
if err != nil {
    return err
}
// cred.TmpSecretID / TmpSecretKey / SessionToken / ExpiredTime(已扣 30s 安全垫)
_ = cred
示例 2:用临时凭证派生 *cossdk.Client

派生 Client 复用实例 transport(连接池),适合服务端短时间用临时凭证完成多次 SDK 调用。

// 与生产路径一致:派生 Client 已禁用 SDK 内置重试,业务层 ctx 取消立即返回
tmpCli, err := co.NewClientFromSTS("public-cdn", cred)
if err != nil {
    return err
}
_, err = tmpCli.Object.Put(ctx, "uploads/2026/avatar.jpg", body, nil)
示例 3:用临时凭证签预签名 URL

PresignURLWithCred 在签名后自动把 x-cos-security-token 注入查询参数,端侧拿到 URL 即可直传。

import (
    "net/http"
    "time"
)

// expire 必须 > 0;method 必须显式给出(PUT/GET/HEAD)
u, err := co.PresignURLWithCred(
    ctx, "public-cdn", cred,
    http.MethodPut, "uploads/2026/avatar.jpg", 5*time.Minute, nil,
)
if err != nil {
    return err
}
// u.String() 已包含 sign 与 x-cos-security-token,可直接交给前端
示例 4:带缓存与并发合并的签发

IssueSTSCachedIssueSTS 之上叠加三层能力:① 按 (name, scope) canonical key 命中 LRU 缓存(容量 256,固定值);② 同 key 的并发请求由 singleflight 合并到一次实际签发;③ 剩余有效期 < 30 秒的凭证不写入也不读取(防即将过期的凭证流出)。错误语义、STSScope 校验规则均与 IssueSTS 完全一致。

// 适用场景:高并发签发同一份临时凭证(如批量签发短期上传凭证);
// 不适用:凭证语义跨 scope 频繁变化(cache key 命中率低,缓存收益有限)。
scope := iocs.STSScope{
    Action:    []string{"name/cos:PutObject"},
    KeyPrefix: "uploads/2026/",
    // DurationSecs 越界仍由内部截断到 [60, 7200] 并 Warn
}
// 同一进程内对相同 (name, scope) 的多次调用:
//   - 首次:触发实际 STS 网络请求,命中缓存写入条件时写入
//   - 后续:直接从 LRU 返回副本,零网络
//   - 并发同 key:只有一次实际网络请求,其它 goroutine 共享结果
cred, err := co.IssueSTSCached(ctx, "public-cdn", scope)
if err != nil {
    return err
}
// 返回值与 IssueSTS 一致:cred.ExpiredTime 已扣 30 秒安全垫
示例 5:单对象精确授权(临时下载分享)

业务场景:私有文档桶里某份合同 contracts/2026/c-001.pdf 需对外短期分享。Key 模式比 KeyPrefix 模式更严格——资源 ARN 不带 * 通配,仅命中该单一对象。

// 关键差异:Key 与 KeyPrefix 必须二选一;Key 模式禁止 ".." / "*"
scope := iocs.STSScope{
    Action:       []string{"name/cos:GetObject"},     // 仅授权读取
    Key:          "contracts/2026/c-001.pdf",         // 精确单对象
    DurationSecs: 300,                                // 5 分钟
    SourceIP:     []string{"203.0.113.0/24"},         // 仅允许指定 CIDR 调用
}
cred, err := co.IssueSTS(ctx, "private-doc", scope)
if err != nil {
    // 典型错误:ErrSTSScopeKeyMissing / ErrSTSScopeKeyInvalid
    return err
}

// 用临时凭证签 GET 预签名 URL,下发给收件人即可一次性下载
u, err := co.PresignURLWithCred(
    ctx, "private-doc", cred,
    http.MethodGet, "contracts/2026/c-001.pdf", 5*time.Minute, nil,
)
if err != nil {
    return err
}
shareURL := u.String() // 已包含 sign 与 x-cos-security-token
_ = shareURL
示例 6:多动作组合 + 网段限定

业务场景:审核服务需要在 review/ 前缀下完成「上传 → 校验 → 删除」的完整闭环,且仅允许内网 CIDR 调用。Action 数组去重后上限 20 条;多动作只签发一次凭证比每个动作各签一次更高效,也利于缓存命中。

// 关键参数:Action 中每条均以 name/cos: 开头,禁止 "*" 通配(即便 "name/cos:Get*" 也不允许)
scope := iocs.STSScope{
    Action: []string{
        "name/cos:PutObject",     // 上传
        "name/cos:HeadObject",    // 校验元信息
        "name/cos:DeleteObject",  // 审核失败时删除
    },
    KeyPrefix:    "review/",                          // 仅作用于该前缀(自动追加 "*" 通配生成 ARN)
    DurationSecs: 1800,                               // 30 分钟,匹配审核流程时长
    SourceIP: []string{                               // 仅允许内网网段调用
        "10.0.0.0/8",
        "172.16.0.0/12",
    },
}
cred, err := co.IssueSTSCached(ctx, "private-doc", scope)
if err != nil {
    return err
}
// cred 可在 30 分钟内被审核服务持有,期间多次 SDK 调用复用同一份凭证
_ = cred
示例 7:前端直传完整闭环(HTTP Handler)

业务场景:浏览器侧表单上传图片,服务端只签发最小权限临时凭证后下发;文件流不流经业务后端。STSCredential 已通过 json tag 内置脱敏(RequestID 不进 JSON,但 TmpSecretKey / SessionToken 仍会序列化,必须仅在 HTTPS 链路内下发)。

// 关键约束:本 Handler 仅用于 HTTPS;HTTP 明文链路下发凭证等同泄露
// 业务路径:前端调本接口 → 拿到凭证 → 用凭证调 cos.tencentcloudapi.com 直传
func handleIssueUploadCred(w http.ResponseWriter, r *http.Request) {
    co := ioc.Container.GetConf(iocs.ConfName).(*iocs.COS)
    // 用请求 ctx:客户端断开时立即放弃 STS 调用,避免 goroutine 泄漏
    ctx := r.Context()

    // 按用户 ID 划分前缀,避免越权写入他人目录
    userID := r.Header.Get("X-User-ID")
    if userID == "" {
        http.Error(w, "missing user id", http.StatusBadRequest)
        return
    }
    scope := iocs.STSScope{
        Action:        []string{"name/cos:PutObject"},
        KeyPrefix:     "uploads/" + userID + "/",     // 用户级前缀隔离
        DurationSecs:  600,                           // 10 分钟够端侧选文件 + 上传
        MaxObjectSize: 10 * 1024 * 1024,              // 上限 10MB(违反则 STS 服务侧拒签)
        ContentType:   "image/jpeg",                  // 仅允许 jpeg
    }
    cred, err := co.IssueSTSCached(ctx, "public-cdn", scope)
    if err != nil {
        // ctx 取消会以 context.Canceled 透传;其它走 500 即可
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    // 返回字段:tmpSecretId / tmpSecretKey / sessionToken / startTime / expiredTime
    // expiredTime 已扣 30s 安全垫,端侧据此判定是否需要重新拉凭证
    w.Header().Set("Content-Type", "application/json")
    _ = json.NewEncoder(w).Encode(cred)
}
示例 8:失效检测与失败重签

业务场景:长任务(如批处理上传 1 万个对象)持有同一份凭证可能跨过过期点。ExpiredTime 已扣 30 秒安全垫,业务侧只需判断「剩余有效期 < 阈值」即触发重签即可;IssueSTSCached 在缓存命中时会校验同样的 30 秒下界,过期前自动剔除。

// 关键参数:阈值建议 ≥ 60 秒,留出业务调用栈的兜底时间
const refreshThresholdSecs = 60

// 持有 cred 的 worker 在每轮调用前自检;过期则重签
refreshIfNeeded := func(cred *iocs.STSCredential) (*iocs.STSCredential, error) {
    if cred != nil && cred.ExpiredTime-time.Now().Unix() > refreshThresholdSecs {
        return cred, nil // 仍有效,复用
    }
    // 剩余 ≤ 60s 或 cred==nil:触发签发;IssueSTSCached 命中且足额有效则返回缓存副本
    return co.IssueSTSCached(ctx, "private-doc", iocs.STSScope{
        Action:    []string{"name/cos:PutObject"},
        KeyPrefix: "batch/2026/",
    })
}

var cred *iocs.STSCredential
for _, key := range keys {
    var err error
    if cred, err = refreshIfNeeded(cred); err != nil {
        return err // 网络错误已经走过业务层重试仍失败
    }
    tmpCli, err := co.NewClientFromSTS("private-doc", cred)
    if err != nil {
        return err
    }
    if _, err = tmpCli.Object.Put(ctx, key, bytes.NewReader(payload), nil); err != nil {
        return err
    }
}
示例 9:错误分支精准处理

业务场景:调用方需要按错误类型区分「输入错误(4xx,无重试)」和「网络/服务错误(5xx,已重试仍失败)」给出不同提示。所有哨兵错误均集中在 sts_policy.go,使用 errors.Is 精准匹配。

// 关键约束:所有 ErrSTSScope* 哨兵均在 IssueSTS 返回前由 wrapErr 包装,
// 调用方必须用 errors.Is 而非字符串比较来判定错误类型
scope := iocs.STSScope{
    Action:    []string{"name/cos:PutObject"},
    KeyPrefix: "uploads/2026/",
}
cred, err := co.IssueSTS(ctx, "public-cdn", scope)
if err != nil {
    switch {
    case errors.Is(err, iocs.ErrSTSScopeActionEmpty),
        errors.Is(err, iocs.ErrSTSScopeActionTooMany),
        errors.Is(err, iocs.ErrSTSScopeActionInvalid):
        // Action 配置错误:不会重试;上层应当拒绝服务并打告警
        return fmt.Errorf("invalid action config: %w", err)
    case errors.Is(err, iocs.ErrSTSScopeKeyMissing),
        errors.Is(err, iocs.ErrSTSScopeKeyInvalid):
        // Key / KeyPrefix 配置错误:同上
        return fmt.Errorf("invalid key config: %w", err)
    case errors.Is(err, iocs.ErrSTSAppIDMissing),
        errors.Is(err, iocs.ErrSTSRegionMissing),
        errors.Is(err, iocs.ErrSTSBucketMissing):
        // 实例上下文不足:通常是 bucket_url 写错或缺失 sts_app_id / sts_region
        return fmt.Errorf("instance config incomplete: %w", err)
    case errors.Is(err, context.Canceled),
        errors.Is(err, context.DeadlineExceeded):
        // ctx 取消:业务侧已经决定放弃,无需重试
        return err
    default:
        // 网络错误 / STS 服务端 5xx:runWithRetryFn 已重试 MaxRetries 次仍失败
        return fmt.Errorf("sts issue failed after retry: %w", err)
    }
}
_ = cred
配置示例(启用 STS 的最小 toml 片段)

实例级 sts_* 字段覆盖默认级 default_sts_* 字段;两者均为可选——bucket_url 形如 https://{bucket}-{appid}.cos.{region}.myqcloud.com 时,sts_region / sts_app_id 可由 IssueSTS 自动推断,无需显式配置。

[cos]
default_sts_endpoint         = "sts.tencentcloudapi.com"
default_sts_default_duration = 1800   # 默认 30 分钟,合法区间 [60, 7200]

[[cos.instances]]
name       = "public-cdn"
secret_id  = "${COS_PUB_ID}"
secret_key = "${COS_PUB_KEY}"
bucket_url = "https://pub-1250000000.cos.ap-guangzhou.myqcloud.com"
# 实例级覆盖(仅在自动推断不可用时配置)
sts_region = "ap-guangzhou"
sts_app_id = "1250000000"
STS 配置项一览
字段 作用 默认值
sts_endpoint STS 服务接入点(裸 host,不带协议) sts.tencentcloudapi.com
sts_region 申请临时凭证使用的地域 留空时自动从 bucket_url 推断
sts_default_duration 临时凭证默认有效期(秒),合法区间 [60, 7200] 1800
sts_app_id 腾讯云开发者 AppID(纯数字) 留空时自动从 bucket_url 末段推断

实例级字段(sts_*)覆盖默认级字段(default_sts_*),两者均为可选。


5. ⚠️ 注意事项(生产必看)

5.1 强制约束
  • nameinstances 数组内唯一,重复会启动期 panic
  • secret_id / secret_key / bucket_url(或 service_url)必填
  • 多实例必须用 toml/yaml(env-only 模式仅支持单实例 default)
  • bucket_url 自动解析 region / bucket(无需手动填写),格式:https://{bucket}.cos.{region}.myqcloud.com
5.2 资源生命周期
  • NewCOS() 仅初始化默认值;Init() 时立即为每个实例构建 SDK Client + Transport(不发起 TCP 连接
  • 进程退出时由 ioc.Container.Stop(ctx) 触发 Close(ctx)并发关闭所有实例的 transport 空闲连接池
  • 正在进行中的请求不会被中断;Close(ctx) 后再调用 Client / Put / Get 等会 panic
5.3 重试策略
  • 关闭 SDK 内置重试(cli.Conf.RetryOpt.Count = 1),统一由 runWithRetry 管理
  • 重试条件:网络错误(connection reset / refused / EOF / timeout / no such host)/ 5xx 服务端错误
  • 不重试:4xx 客户端错误 / context.Canceled / context.DeadlineExceeded
  • 退避:RetryBackoff << attempt(200ms / 400ms / 800ms ...),最多 MaxRetries
  • ctx 取消立即放弃
5.4 分块上传 / 下载
  • Upload / Download 走 SDK 的 MultiUpload / Download,自带断点续传(CheckPoint=true
  • 分块大小 part_size(MB)+ 并发数 thread_pool_size 可在实例级覆盖默认值
  • 适合 >5GB 的大文件;中小文件用 Put / PutFromFile / Get / GetToFile 即可
5.5 多实例日志区分
  • 所有命令日志附加 instance 字段(实例 name),方便定位
  • 慢请求阈值 1s(COS 网络 IO 较重),超过后 Warn 级别打印
  • 4xx → Warn,5xx → Error,正常 → Debug(仅 debug 级别)
5.6 密码安全
  • secret_key 强烈推荐通过 ${ENV} 占位(如 secret_key = "${COS_KEY}"
  • toml/yaml 解析前会替换 ${VAR} / ${VAR:default} 为环境变量
5.7 不支持后向兼容
  • 旧版本的 co.Put(ctx, key, ...) / co.Client() API 已删除
  • 业务代码必须改为:co.Put(ctx, name, key, ...) / co.Client(name)
5.8 PresignedURLOptions 的 nil 陷阱
  • PresignURL 内部已处理:opt == nil 时显式传 nil interface{},避免 SDK 内部 nil 解引用
  • 业务直接传 nil 即可,无需手动包装
5.9 STS 安全清单(生产必看)

临时凭证设计的核心是最小权限 + 有时效 + 不可重用。以下条目对应源码中的强校验或运行时行为,违反时会立即返回哨兵错误或被截断。

强校验(启动期 / 签发期立即报错)
  • Action 必须以 name/cos:name/sts: 开头;禁止 * 通配(即便 name/cos:Get* 这种带前缀的也禁止)→ ErrSTSScopeActionInvalid
  • Action 数组为空 / 全为空字符串 / 去重后 > 20 条 → ErrSTSScopeActionEmpty / ErrSTSScopeActionTooMany
  • Action 含空格 / 制表符 / 换行 / 控制字符 → ErrSTSScopeActionInvalid
  • KeyKeyPrefix 必须二选一;两者皆空 → ErrSTSScopeKeyMissing
  • Key / KeyPrefix.. / *KeyPrefix 等于单一 /ErrSTSScopeKeyInvalid(防路径穿越 / 全桶授权)
  • sts_endpoint 不允许包含协议前缀(如 https://),需填裸 host → 启动期 validate() 报错
  • sts_app_id 非空时必须为纯数字字符串 → 启动期 validate() 报错
  • sts_default_duration 越界 [60, 7200] → 启动期 validate() 报错
  • 缺失 sts_region / sts_app_id 且无法从 bucket_url 推断 → ErrSTSRegionMissing / ErrSTSAppIDMissing
运行期截断(保护性 + Warn 日志)
  • STSScope.DurationSecs 越界 [60, 7200] 自动截断(不报错),同时打 cos.sts.duration_truncated Warn 日志,包含 input_durationtruncated_to 字段供排障定位
  • 重复 Action 自动去重,打 cos.sts.action_dedup Debug 日志
日志与脱敏
  • TmpSecretKey / SessionToken / 完整 policy JSON 永远不进日志
  • 仅打 TmpSecretID 前 6 位(tmp_secret_id_prefix 字段)用于排障
  • 失败日志按 cos.sts.issue.failed(Error 级)记录;成功日志按 cos.sts.issue.succeeded(Info 级)记录
时效与可重入
  • 返回的 STSCredential.ExpiredTime 已自动扣减 30 秒安全垫(防本地与服务端时钟漂移),调用方可直接据此判定有效性
  • IssueSTS 默认走 runWithRetryFn:网络错误 / 5xx / RequestLimitExceeded 等可重试 Code 触发重试;InvalidParameter / AuthFailure 等 4xx 类客户端错误重试
  • ctx.Cancel / ctx.Deadline 立即返回,不等待 SDK 阻塞 IO
缓存与并发合并(仅 IssueSTSCached
  • cache key 由 (instance_name, canonical(scope)) 经 sha256 派生;Action / SourceIP 内部排序去重,scope 字段顺序、数组顺序、重复元素都不影响命中
  • LRU 容量包级常量 256;满载时按访问顺序淘汰最久未使用项;不暴露为配置项
  • TTL 下界 30 秒:剩余有效期 < 30 秒的凭证既不写入缓存、也不从缓存读出(读命中后会立即驱逐并重新签发)
  • 缓存命中返回的 STSCredential 是深拷贝副本,调用方修改不会污染缓存内条目
  • 错误路径不写入缓存:scope 校验失败、IssueSTS 网络错误均不会留下任何缓存条目
资源 ARN 拼接规则
  • 资源模板:qcs::cos:{region}:uid/{appid}:{bucket}/{key|prefix*}
  • Key 模式:原样拼接(精确匹配单对象)
  • KeyPrefix 模式:自动追加 *(COS 资源 ARN 通配语法),实现前缀授权

6. FAQ

Q:旧 co.Put(ctx, key, ...) 怎么改? 改为 co.Put(ctx, "default", key, ...),或显式指定其他 instance name。

Q:能否动态新增 / 删除实例? 不能。Init() 时一次性构建并校验。

Q:env 模式可以配多桶吗? 不行。env 模式仅支持 1 个 default 实例。多桶必须用 toml/yaml。

Q:临时密钥(STS)怎么配? 两种用法:

  1. 消费已有临时凭证:在 instances[i] 中填 secret_id / secret_key / session_token 即可,运行时如需更新请重启。
  2. 主动向 STS 申请凭证:使用 IssueSTS / NewClientFromSTS / PresignURLWithCred,详见 §4.7 与 §5.9。两者可独立使用,也可组合(用永久密钥实例签发临时凭证,再下放给前端 / 子进程)。

Q:能否使用代理? SDK 默认走 http.ProxyFromEnvironment,设置 HTTP_PROXY / HTTPS_PROXY 环境变量即可。

Documentation

Overview

Package cos 提供基于腾讯云 COS Go SDK 的多实例对象存储客户端配置中心。

配置模型(两层):

defaults              —— 全局默认值(max_idle_conns / part_size 等)
instances []Instance  —— 命名实例(secret_id/key + bucket_url)

业务取用:

co := ioc.Container.GetConf(cos.ConfName).(*cos.COS)
pub  := co.Client("public-cdn")
priv := co.Client("private-doc")
_ = co.Put(ctx, "public-cdn", "key", reader, nil)
_ = co.Upload(ctx, "private-doc", "key", "/path/file", nil)

Index

Constants

View Source
const ConfName = "cos"

ConfName 注册到 IOC 容器中的名称

Variables

View Source
var (
	// ErrSTSScopeActionEmpty 触发场景:STSScope.Action 为空切片或全部元素为空字符串。
	ErrSTSScopeActionEmpty = errors.New("sts scope: action is empty")

	// ErrSTSScopeActionTooMany 触发场景:去重后 STSScope.Action 长度 > stsActionMaxCount(20)。
	ErrSTSScopeActionTooMany = errors.New("sts scope: action exceeds 20 entries")

	// ErrSTSScopeActionInvalid 触发场景:单条 Action 不以 "name/cos:" 或 "name/sts:" 开头、
	// 包含通配符 "*"、含空白字符(空格 / 制表符 / 换行符)或其它控制字符。
	ErrSTSScopeActionInvalid = errors.New("sts scope: action invalid (must start with name/cos: or name/sts:, no wildcard, no whitespace)")

	// ErrSTSScopeKeyMissing 触发场景:STSScope.Key 与 STSScope.KeyPrefix 同时为空。
	ErrSTSScopeKeyMissing = errors.New("sts scope: key and key_prefix are both empty")

	// ErrSTSScopeKeyInvalid 触发场景:Key / KeyPrefix 含 ".."、"*",或 KeyPrefix 等于
	// 单一 "/"(等价于全桶授权,被禁用)。
	ErrSTSScopeKeyInvalid = errors.New("sts scope: key/key_prefix invalid (forbid '..', '*', single '/')")

	// ErrSTSAppIDMissing 触发场景:IssueSTS 阶段 resolvedInstance.STSAppID 为空,
	// 且无法从 BucketURL 推断(桶名末段非纯数字,或未配置 BucketURL)。
	ErrSTSAppIDMissing = errors.New("sts: app_id is empty (configure sts_app_id or use bucket_url containing -{appid})")

	// ErrSTSRegionMissing 触发场景:IssueSTS 阶段 resolvedInstance.STSRegion 为空,
	// 且无法从 BucketURL 推断(host 不符合 *.cos.{region}.myqcloud.com 模式)。
	ErrSTSRegionMissing = errors.New("sts: region is empty (configure sts_region or use a bucket_url containing region)")

	// ErrSTSBucketMissing 触发场景:IssueSTS 阶段 resolvedInstance.Bucket 为空,
	// 且无法从 BucketURL 推断。多用于配置错误(BucketURL 缺失的 service-only 实例)。
	ErrSTSBucketMissing = errors.New("sts: bucket is empty (configure bucket_url to enable sts)")
)

哨兵错误:STSScope 校验与 IssueSTS 上下文校验。

集中在本文件维护,便于排障时按错误码一站式定位触发场景。

Functions

This section is empty.

Types

type COS

type COS struct {
	CosDefaults `toml:",inline" yaml:",inline"`

	Instances   []CosInstance `toml:"instances" yaml:"instances" json:"instances"`
	EnvInstance CosInstance   `toml:"-" yaml:"-" json:"-"`
	// contains filtered or unexported fields
}

COS 注册到 IoC 容器的顶层配置

func NewCOS

func NewCOS() *COS

NewCOS 创建 COS 配置实例(仅初始化默认值,不创建任何连接)

func (*COS) Client

func (c *COS) Client(name string) *cossdk.Client

Client 取指定实例的 *cos.Client

func (*COS) Close

func (c *COS) Close(ctx context.Context) error

Close 并发关闭所有实例的 transport,幂等且线程安全。

仅释放底层 *http.Transport 的空闲连接;正在进行的请求不会被中断。

func (*COS) Delete

func (c *COS) Delete(ctx context.Context, name, key string, opt ...*cossdk.ObjectDeleteOptions) error

Delete 删除单个对象

func (*COS) Download

func (c *COS) Download(ctx context.Context, name, key, filePath string, override *cossdk.MultiDownloadOptions) error

Download 大文件分块下载,自带断点续传

使用 SDK 内置的 ObjectService.Download,对于大对象推荐使用此方法。

func (*COS) Get

func (c *COS) Get(ctx context.Context, name, key string, opt *cossdk.ObjectGetOptions) (io.ReadCloser, error)

Get 下载对象到 io.ReadCloser,调用方负责 Close

func (*COS) GetToFile

func (c *COS) GetToFile(ctx context.Context, name, key, filePath string, opt *cossdk.ObjectGetOptions) error

GetToFile 下载对象到本地文件(小文件场景;大文件请使用 Download)

func (*COS) Head

func (c *COS) Head(ctx context.Context, name, key string, opt *cossdk.ObjectHeadOptions) (*cossdk.Response, error)

Head 获取对象元信息,常用于探测对象是否存在

func (*COS) HealthCheck

func (c *COS) HealthCheck(ctx context.Context) error

HealthCheck 遍历所有实例探活

func (*COS) HealthCheckOne

func (c *COS) HealthCheckOne(ctx context.Context, name string) error

HealthCheckOne 仅探活指定实例

func (*COS) Init

func (c *COS) Init(_ context.Context) error

Init 初始化方法

完成的工作:

  1. 绑定私有 logger
  2. env-only 模式 fallback:把 EnvInstance 提升为 Instances[0]
  3. 校验:name 唯一 + secret/bucket_url 必填
  4. 立即为每个 instance 构建 *cossdk.Client(不发起 TCP 连接)

选择"立即构建 SDK Client"是为了:

  • 配置错误(bucket_url 拼写、CA 文件不存在等)在启动期暴露
  • SDK Client 创建本身不发起 HTTP 请求,不会拖慢启动

func (*COS) IssueSTS

func (c *COS) IssueSTS(ctx context.Context, name string, scope STSScope) (*STSCredential, error)

IssueSTS 向腾讯云 STS 服务申请临时凭证。

行为:

  • scope 校验失败立即返回(不重试、不入网),错误链中含 ErrSTSScope* 哨兵;
  • 网络错误 / 5xx / 命中 stsRetryableErrorCodes 的 Code → 业务层重试(runWithRetryFn);
  • ctx 取消立即返回(SDK 本身不接受 ctx,内部用 goroutine + select 适配);
  • 返回前 ExpiredTime 自动减去 30 秒安全垫,对应 Duration 也按相同安全垫推算。

并发安全:可被多个 goroutine 并发调用;底层 STS *Client 每次重新构造,零共享状态。

错误语义:

  • ErrSTSScopeActionEmpty / ErrSTSScopeActionTooMany / ErrSTSScopeActionInvalid:scope.Action 不合法;
  • ErrSTSScopeKeyMissing / ErrSTSScopeKeyInvalid:scope.Key / KeyPrefix 不合法;
  • ErrSTSAppIDMissing / ErrSTSRegionMissing / ErrSTSBucketMissing:实例上下文不足;
  • 其余错误经 wrapErr("sts.issue", "", err) 包装后返回。

func (*COS) IssueSTSCached

func (c *COS) IssueSTSCached(ctx context.Context, name string, scope STSScope) (*STSCredential, error)

IssueSTSCached 带缓存的临时凭证签发(Phase 2:LRU + singleflight + canonical key)。

行为:

  • 先按 (name, scope) canonical key 在 LRU 中查找;命中且剩余有效期 ≥ 30s 时直接返回缓存副本;
  • 未命中则走 singleflight 合并并发调用 → 实际触发一次 IssueSTS;
  • 签发成功后剩余有效期 ≥ 30s 时写入缓存;< 30s 时不写入(避免立即过期的凭证污染缓存)。

与 IssueSTS 的差异:

  • 错误语义完全一致:scope 校验失败 / 实例配置缺失 / 网络错误均原样透传;
  • 同时段内对相同 (name, scope) 的多次调用只会触发一次实际网络请求;
  • 返回的 STSCredential 与 IssueSTS 同样已扣 30s 安全垫。

并发安全:可被多个 goroutine 并发调用;缓存与 singleflight 内部已加锁。

func (*COS) List

List 列举对象(封装 Bucket.Get)

func (*COS) Name

func (c *COS) Name() string

Name 实现 ioc.ConfManager 接口

func (*COS) Names

func (c *COS) Names() []string

Names 返回当前已声明的全部 instance name

func (*COS) NewClientFromSTS

func (c *COS) NewClientFromSTS(name string, cred *STSCredential) (*cossdk.Client, error)

NewClientFromSTS 用临时凭证派生临时 *cossdk.Client,复用实例 transport。

行为:

  • 复用 holder.transport.base 作为底层 RoundTripper(避免连接池碎片);
  • 用 cossdk.AuthorizationTransport 注入 cred.SessionToken;
  • 不修改原 holder 的 sdkClient,返回的是仅本次调用使用的全新 *cossdk.Client。

并发安全:可并发调用;返回的 *cossdk.Client 与 cos-go-sdk-v5 一致按读使用。

错误语义:cred 为 nil 或字段不全 → 立即返回,不会真实创建 client。

func (*COS) PresignGet

func (c *COS) PresignGet(ctx context.Context, name, key string, expire time.Duration) (*url.URL, error)

PresignGet 简化版:生成预签名下载 URL

func (*COS) PresignHead

func (c *COS) PresignHead(ctx context.Context, name, key string, expire time.Duration) (*url.URL, error)

PresignHead 简化版:生成预签名 HEAD URL(预检)

func (*COS) PresignPut

func (c *COS) PresignPut(ctx context.Context, name, key string, expire time.Duration) (*url.URL, error)

PresignPut 简化版:生成预签名上传 URL(前端直传场景)

func (*COS) PresignURL

func (c *COS) PresignURL(ctx context.Context, name, method, key string, expire time.Duration, opt *cossdk.PresignedURLOptions) (*url.URL, error)

PresignURL 生成预签名 URL

参数:

  • name 实例名(在配置文件 instances 中声明)
  • method GET / PUT / HEAD / DELETE 等标准 HTTP 方法
  • key 对象 key
  • expire 过期时长(>0),生产环境建议 <= 1h
  • opt 可选 PresignedURLOptions(query / header 等)

func (*COS) PresignURLWithCred

func (c *COS) PresignURLWithCred(
	ctx context.Context, name string, cred *STSCredential,
	method, key string, expire time.Duration, opt *cossdk.PresignedURLOptions,
) (*url.URL, error)

PresignURLWithCred 用指定临时凭证签预签名 URL,并把 SessionToken 写入查询参数。

与 PresignURL 的差异:

  • 使用 cred.TmpSecretID / TmpSecretKey 计算签名;
  • 签名后把 x-cos-security-token=cred.SessionToken 注入到 URL.RawQuery(COS 协议要求)。

适用场景:服务端用 IssueSTS 拿到临时凭证后,无需新建临时 *cossdk.Client, 直接签预签名 URL 下发给端侧。

并发安全:可并发调用,SDK GetPresignedURL 本身是纯 CPU 计算无共享状态。

func (*COS) Put

func (c *COS) Put(ctx context.Context, name, key string, r io.Reader, opt *cossdk.ObjectPutOptions) error

Put 上传一个对象(小文件 / 流式)

参数:

  • name 实例名(在配置文件 instances 中声明)
  • key 对象 key(不带 bucket 前缀)
  • r 数据源(任意 io.Reader)
  • opt COS SDK 的 PutOptions(可为 nil)

行为:

  • 自动包装重试(业务级,按实例的 MaxRetries / RetryBackoff)
  • 重试条件:网络错误 / 5xx 服务端错误
  • ctx 取消立即放弃

func (*COS) PutFromFile

func (c *COS) PutFromFile(ctx context.Context, name, key, filePath string, opt *cossdk.ObjectPutOptions) error

PutFromFile 从本地文件上传(适合中小文件,>5GB 请使用 Upload)

func (*COS) Upload

func (c *COS) Upload(ctx context.Context, name, key, filePath string, override *cossdk.MultiUploadOptions) (*cossdk.CompleteMultipartUploadResult, error)

Upload 大文件分块上传,自带断点续传

使用 SDK 内置的 ObjectService.Upload,对于 >5GB 的文件强烈推荐使用此方法。 通过实例的 PartSize / ThreadPoolSize / CheckPoint 等配置控制并发与续传。

type CosDefaults

type CosDefaults struct {
	// MaxIdleConns HTTP Transport 全局最大空闲连接数。
	// 默认:200;范围:>=0;0 表示不限制。
	MaxIdleConns *int `` /* 149-byte string literal not displayed */
	// MaxIdleConnsPerHost 每个 host 最大空闲连接数。
	// 默认:100;范围:>=0;建议 = MaxIdleConns / 桶数量。
	MaxIdleConnsPerHost *int `` /* 158-byte string literal not displayed */
	// MaxConnsPerHost 每个 host 最大并发连接数(含使用中)。
	// 默认:200;范围:>=0;0 表示不限制。
	MaxConnsPerHost *int `` /* 153-byte string literal not displayed */
	// IdleConnTimeout 空闲连接最大保活时间。
	// 单位:秒;默认:90;范围:>0。
	IdleConnTimeout *int `` /* 152-byte string literal not displayed */
	// DialTimeout TCP 拨号超时。
	// 单位:秒;默认:10;范围:>0。
	DialTimeout *int `` /* 147-byte string literal not displayed */
	// KeepAlive TCP 长连接保活间隔。
	// 单位:秒;默认:60。
	KeepAlive *int `` /* 145-byte string literal not displayed */
	// TLSHandshakeTimeout TLS 握手超时。
	// 单位:秒;默认:10;范围:>0。
	TLSHandshakeTimeout *int `` /* 156-byte string literal not displayed */
	// ResponseHeaderTimeout 等待响应 header 的超时。
	// 单位:秒;默认:30;范围:>0。
	ResponseHeaderTimeout *int `` /* 158-byte string literal not displayed */
	// ExpectContinueTimeout 100-continue 等待时间。
	// 单位:秒;默认:1。
	ExpectContinueTimeout *int `` /* 158-byte string literal not displayed */
	// ClientTimeout HTTP 整体超时(含拨号、读、写)。
	// 单位:秒;默认:60(兼顾一般 Put/Get 的免 Hang 兑底)。
	// 大文件 Multipart 上传/下载场景请在实例级将本值调为 0(仅由 ctx 控制)或业务侧使用 ctx.WithTimeout 覆盖。
	ClientTimeout *int `` /* 149-byte string literal not displayed */
	// TLSInsecureSkipVerify 是否跳过证书校验。
	// 默认:false;生产环境务必保持 false。
	TLSInsecureSkipVerify *bool `` /* 162-byte string literal not displayed */
	// TLSCAFile 自签 CA 证书路径(PEM)。
	TLSCAFile *string `` /* 143-byte string literal not displayed */
	// MaxRetries 最大重试次数。
	// 默认:3;范围:>=0;0 表示不重试。
	MaxRetries *int `` /* 146-byte string literal not displayed */
	// RetryBackoff 重试退避基数(指数退避:base * 2^attempt)。
	// 单位:毫秒;默认:200。
	RetryBackoff *int `` /* 148-byte string literal not displayed */
	// PartSize 分块上传单块大小。
	// 单位:MB;默认:8;范围:>=1(COS 限制:单块 1~5GB,分块数 <= 10000)。
	PartSize *int64 `` /* 144-byte string literal not displayed */
	// ThreadPoolSize 分块上传/下载并发数。
	// 默认:5;范围:>=1。
	ThreadPoolSize *int `` /* 151-byte string literal not displayed */
	// CheckPoint 是否启用断点续传。
	// 默认:true。
	CheckPoint *bool `` /* 146-byte string literal not displayed */
	// ServiceURL 列举所有 bucket 用的服务域名。
	// 默认:"https://service.cos.myqcloud.com"。
	ServiceURL *string `` /* 143-byte string literal not displayed */

	// STSEndpoint STS 服务接入点,仅填裸 host,不带协议;协议固定 https。
	// 默认:"sts.tencentcloudapi.com"。
	STSEndpoint *string `` /* 141-byte string literal not displayed */
	// STSRegion 申请临时凭证时使用的地域。
	// 留空时由 IssueSTS 从 BucketURL 推断的 Region 兜底。
	STSRegion *string `` /* 139-byte string literal not displayed */
	// STSDefaultDuration 临时凭证默认有效期(秒)。
	// 默认:1800;范围:[60, 7200]。Scope.DurationSecs 为 0 时使用本值。
	STSDefaultDuration *int `` /* 149-byte string literal not displayed */
	// STSAppID 腾讯云开发者 AppID(纯数字字符串)。
	// 留空时由 IssueSTS 从 BucketURL 末段推断;推断失败且未配置则签发阶段报错。
	STSAppID *string `` /* 139-byte string literal not displayed */
}

CosDefaults 全局默认值(指针字段,nil = 继承)

type CosInstance

type CosInstance struct {
	// Name 实例唯一标识。业务通过 cosConf.Client(name) 取用,必填且不可重名。
	Name string `toml:"name" yaml:"name" json:"name" env:"-"`

	// SecretID 永久密钥 SecretId。可用 ${COS_SECRET_ID} 占位,生产环境强烈建议环境变量注入。
	SecretID string `toml:"secret_id"     yaml:"secret_id"     json:"secret_id"     env:"COS_SECRET_ID"`
	// SecretKey 永久密钥 SecretKey。可用 ${COS_SECRET_KEY} 占位,生产环境强烈建议环境变量注入。
	SecretKey string `toml:"secret_key"    yaml:"secret_key"    json:"secret_key"    env:"COS_SECRET_KEY"`
	// SessionToken 临时密钥 Token(CAM 角色场景)。永久密钥时留空。
	SessionToken string `toml:"session_token" yaml:"session_token" json:"session_token" env:"COS_SESSION_TOKEN"`

	// BucketURL 桶访问域名,必填。
	// 例:https://my-bucket-1250000000.cos.ap-guangzhou.myqcloud.com
	BucketURL string `toml:"bucket_url"  yaml:"bucket_url"  json:"bucket_url"  env:"COS_BUCKET_URL"`
	// ServiceURL 列举所有桶的服务域名。可继承默认值。
	ServiceURL string `toml:"service_url" yaml:"service_url" json:"service_url" env:"COS_SERVICE_URL"`
	// CIURL 数据万象(CI)域名。仅用图片处理时填写。
	CIURL string `toml:"ci_url"      yaml:"ci_url"      json:"ci_url"      env:"COS_CI_URL"`
	// FetchURL 异步拉取域名。仅用 PutObjectFromURL 时填写。
	FetchURL string `toml:"fetch_url"   yaml:"fetch_url"   json:"fetch_url"   env:"COS_FETCH_URL"`
	// Region 桶所在地域,例 ap-guangzhou。可空,从 BucketURL 推断。
	Region string `toml:"region"      yaml:"region"      json:"region"      env:"COS_REGION"`
	// Bucket 桶名,可空,从 BucketURL 推断。
	Bucket string `toml:"bucket"      yaml:"bucket"      json:"bucket"      env:"COS_BUCKET"`

	// 以下字段均与 CosDefaults 中的同名字段语义一致,nil = 继承默认。
	MaxIdleConns          *int    `toml:"max_idle_conns"          yaml:"max_idle_conns"          json:"max_idle_conns"          env:"COS_MAX_IDLE_CONNS"`
	MaxIdleConnsPerHost   *int    `` /* 126-byte string literal not displayed */
	MaxConnsPerHost       *int    `toml:"max_conns_per_host"      yaml:"max_conns_per_host"      json:"max_conns_per_host"      env:"COS_MAX_CONNS_PER_HOST"`
	IdleConnTimeout       *int    `toml:"idle_conn_timeout"       yaml:"idle_conn_timeout"       json:"idle_conn_timeout"       env:"COS_IDLE_CONN_TIMEOUT"`
	DialTimeout           *int    `toml:"dial_timeout"            yaml:"dial_timeout"            json:"dial_timeout"            env:"COS_DIAL_TIMEOUT"`
	KeepAlive             *int    `toml:"keep_alive"              yaml:"keep_alive"              json:"keep_alive"              env:"COS_KEEP_ALIVE"`
	TLSHandshakeTimeout   *int    `toml:"tls_handshake_timeout"   yaml:"tls_handshake_timeout"   json:"tls_handshake_timeout"   env:"COS_TLS_HANDSHAKE_TIMEOUT"`
	ResponseHeaderTimeout *int    `` /* 126-byte string literal not displayed */
	ExpectContinueTimeout *int    `` /* 126-byte string literal not displayed */
	ClientTimeout         *int    `toml:"client_timeout"          yaml:"client_timeout"          json:"client_timeout"          env:"COS_CLIENT_TIMEOUT"`
	TLSInsecureSkipVerify *bool   `` /* 130-byte string literal not displayed */
	TLSCAFile             *string `toml:"tls_ca_file"             yaml:"tls_ca_file"             json:"tls_ca_file"             env:"COS_TLS_CA_FILE"`
	MaxRetries            *int    `toml:"max_retries"             yaml:"max_retries"             json:"max_retries"             env:"COS_MAX_RETRIES"`
	RetryBackoff          *int    `toml:"retry_backoff"           yaml:"retry_backoff"           json:"retry_backoff"           env:"COS_RETRY_BACKOFF"`
	PartSize              *int64  `toml:"part_size"               yaml:"part_size"               json:"part_size"               env:"COS_PART_SIZE"`
	ThreadPoolSize        *int    `toml:"thread_pool_size"        yaml:"thread_pool_size"        json:"thread_pool_size"        env:"COS_THREAD_POOL_SIZE"`
	CheckPoint            *bool   `toml:"check_point"             yaml:"check_point"             json:"check_point"             env:"COS_CHECK_POINT"`

	// STS 临时凭证签发(实例级覆盖;语义同 CosDefaults 中的同名字段,nil = 继承默认)
	STSEndpoint        *string `toml:"sts_endpoint"          yaml:"sts_endpoint"          json:"sts_endpoint"          env:"COS_STS_ENDPOINT"`
	STSRegion          *string `toml:"sts_region"            yaml:"sts_region"            json:"sts_region"            env:"COS_STS_REGION"`
	STSDefaultDuration *int    `toml:"sts_default_duration"  yaml:"sts_default_duration"  json:"sts_default_duration"  env:"COS_STS_DEFAULT_DURATION"`
	STSAppID           *string `toml:"sts_app_id"            yaml:"sts_app_id"            json:"sts_app_id"            env:"COS_STS_APP_ID"`
}

CosInstance 一个命名 COS 实例(secret + bucket_url)

type STSCredential

type STSCredential struct {
	// TmpSecretID 临时凭证的 SecretId。
	TmpSecretID string `json:"tmpSecretId"`
	// TmpSecretKey 临时凭证的 SecretKey(敏感字段,禁止入日志)。
	TmpSecretKey string `json:"tmpSecretKey"`
	// SessionToken 临时凭证的会话令牌(敏感字段,禁止入日志)。
	SessionToken string `json:"sessionToken"`
	// StartTime 凭证生效起始时间(Unix 秒)。
	StartTime int64 `json:"startTime"`
	// ExpiredTime 凭证过期时间(Unix 秒),已扣除 30 秒安全垫。
	ExpiredTime int64 `json:"expiredTime"`
	// RequestID 腾讯云 STS 服务返回的请求 ID,仅用于排障,不下发端侧。
	RequestID string `json:"-"`
}

STSCredential 临时凭证(透传给前端 / 子进程)。

安全约束:

  • TmpSecretKey / SessionToken 属于敏感凭证,禁止写入日志或 trace;
  • RequestID 仅用于服务端排障,不应下发给端侧(json:"-");
  • ExpiredTime 已扣除 30 秒安全垫,调用方可直接据此判定有效性。

并发安全:作为返回值被调用方持有;本包不会再次修改其字段。

type STSScope

type STSScope struct {
	// Action COS 操作动作列表,如 ["name/cos:PutObject", "name/cos:GetObject"]。
	Action []string
	// Key 单对象授权(与 KeyPrefix 二选一)。
	Key string
	// KeyPrefix 前缀授权(与 Key 二选一),自动追加 "*" 通配。
	KeyPrefix string
	// DurationSecs 凭证有效期(秒),0 时使用实例的 STSDefaultDuration。
	DurationSecs int
	// MaxObjectSize 上传对象大小上限(字节),0 表示不限制。
	MaxObjectSize int64
	// ContentType 限定上传 MIME 类型,空表示不限制。
	ContentType string
	// SourceIP 限定调用来源 IP(CIDR 列表),空表示不限制。
	SourceIP []string
}

STSScope 描述本次临时凭证的权限范围(最小权限原则)。

使用约束:

  • Action 必填,每条以 "name/cos:" 或 "name/sts:" 开头,禁用 "*" 通配;
  • Key 与 KeyPrefix 至少一个非空(互斥使用);
  • DurationSecs 0 时使用 STSDefaultDuration,越界自动截断到 [60, 7200] 并 Warn;
  • MaxObjectSize / ContentType / SourceIP 仅在非零时输出到 policy condition。

并发安全:可被多个 goroutine 并发传入 IssueSTS / IssueSTSCached, 内部不会修改入参;结构体本身可被复制使用。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL