Skip to content

Latest commit

 

History

History
340 lines (240 loc) · 11.5 KB

File metadata and controls

340 lines (240 loc) · 11.5 KB

七牛云 Go SDK — 开发维护指南

七牛云官方 Go SDK,模块路径 github.com/qiniu/go-sdk/v7,Go 1.22+,MIT 许可。

本文档面向 SDK 维护者和贡献者,帮助理解项目结构、架构模式和开发流程。 SDK 的 API 使用说明请参考各包的 doc.go 文件和 examples/ 目录。

项目结构

顶层包

职责
auth 认证凭证(AK/SK)、HMAC-SHA1 签名、上传凭证、回调验证
storage 对象存储 v1:表单上传、分片上传、Bucket/对象管理、数据处理(pfop)
storagev2 对象存储 v2:类型化 API、自动区域检测、连接池、重试、Provider/Interface 模式
cdn CDN 加速:刷新、预取、流量/带宽查询、时间戳防盗链
pili 直播云:流管理、域名管理、推拉流地址生成
rtc 实时音视频:应用管理、房间 Token、用户管理
sms 短信:发送短信、签名/模板管理
linking IoT 设备联网:设备管理、密钥、录像片段
qvs 视频监控(QVS):GB/T 28181 设备接入、空间/设备/流管理
iam 身份与访问管理:用户、组、策略 CRUD(生成代码)
media 多媒体处理:Pfop 触发/Prefop 查询(生成代码)
audit 审计日志:日志查询(生成代码)
sandbox 沙箱环境:创建/管理沙箱、文件操作、命令执行、PTY 终端
client 底层 HTTP 客户端:请求签名、JSON/表单序列化、错误解析
conf 全局配置:SDK 版本号(conf.Version)、User-Agent 设置
reqid 请求 ID:通过 Context 传递 X-Reqid

internal 包

职责
internal/api-generator 代码生成器:读取 YAML API 规范生成类型化 Go 代码
internal/clientv2 HTTP 客户端 v2:拦截器链模式、认证注入、重试、防劫持
internal/cache 通用缓存
internal/hostprovider 主机地址提供者
internal/freezer 主机冻结/降级
internal/context Context 兼容层
internal/env 环境变量读取
internal/log 内部日志
internal/uplog 上传日志
internal/io IO 工具
internal/dialer 网络拨号
internal/configfile 配置文件读取

storagev2 子包

职责
storagev2/apis 低级 API 客户端,所有方法由代码生成器生成
storagev2/apistest API mock/测试辅助
storagev2/credentials 凭证管理(Provider 接口)
storagev2/http_client HTTP 客户端选项、拦截器集成
storagev2/region 区域信息(RegionsProvider 接口)
storagev2/uploader 上传管理器(自动选择上传方式)
storagev2/downloader 下载管理器
storagev2/objects 对象管理(流式 API)
storagev2/uptoken 上传凭证(PutPolicy → Signer)
storagev2/backoff 重试退避策略
storagev2/chooser 主机选择器
storagev2/resolver 域名解析器
storagev2/retrier 重试器
storagev2/defaults 默认配置值
storagev2/errors 类型化错误
storagev2/uplog 上传日志
storagev2/internal storagev2 内部实现

其他目录

目录 说明
api-specs/ API 规范(git submodule),包含 storage、iam、media、audit、sandbox 的 YAML/OpenAPI 定义
examples/ 各功能的使用示例,每个示例是独立子目录(独立 main 包)

核心架构模式

Manager 模式(storage v1)

v1 的对象存储使用 Manager 模式,每个功能域对应一个 Manager 结构体:

  • storage.BucketManager — Bucket 和对象管理
  • storage.FormUploader / storage.ResumeUploader — 上传
  • storage.OperationManager — 数据处理

构造方式统一为 New*(mac, &cfg)New*(&cfg),通过 auth.Credentials 传递认证信息。

Provider/Interface 模式(storagev2)

v2 通过接口抽象实现可插拔:

  • credentials.CredentialsProvider — 凭证提供者
  • region.RegionsProvider — 区域信息提供者
  • chooser.Chooser — 主机选择策略
  • resolver.Resolver — 域名解析
  • retrier.Retrier — 重试策略
  • backoff.Backoff — 退避策略

所有组件通过 http_client.Options 注入,支持自定义替换。

Interceptor 拦截器链(internal/clientv2)

HTTP 请求通过拦截器链处理,拦截器按优先级排序(数字越小优先级越高):

RetryHosts(200) → RetrySimple(300) → Uplog(310) → BufferResponse(320)
  → SetHeader(400) → Normal(500) → Auth(600) → AntiHijacking(700) → Debug(800)

核心接口:

type Interceptor interface {
    Priority() InterceptorPriority
    Intercept(req *http.Request, handler Handler) (*http.Response, error)
}

Context 传递认证

storage v1 通过函数参数传递 auth.Credentials,storagev2 通过 http_client.Options 结构体传递。reqid 包提供 Context 传递请求 ID 的机制(X-Reqid 头)。

双版本共存

storage(v1)和 storagev2(v2)并行维护:

  • v1:稳定的对外 API,Manager 模式,手写代码
  • v2:新一代 API,Provider/Interface 模式,代码生成 + 手写
  • 两者共享 authclientconfreqid 等基础包
  • 新功能优先在 v2 实现,v1 仅做维护性修改

代码生成

API 代码生成(make generate)

internal/api-generator 读取 api-specs/ 中的 YAML 规范,生成类型化 Go 代码:

api-specs/<service>/*.yml  →  internal/api-generator  →  <service>/apis/*.go

涉及的包及 //go:generate 指令:

  • storagev2/storagev2/apis/(struct: Storage)
  • iam/iam/apis/(struct: IAM)
  • media/media/apis/(struct: Media)
  • audit/audit/apis/(struct: Audit)

运行命令:

make generate   # 运行所有 go generate 并格式化代码

Sandbox 代码生成(make generate-sandbox)

sandbox 使用不同的生成工具链:

  • 控制面 APIoapi-codegen(OpenAPI → Go)→ sandbox/internal/apis/
  • envd HTTP APIoapi-codegensandbox/internal/envdapi/
  • envd ConnectRPCbuf + protoc-gen-go + protoc-gen-connect-gosandbox/internal/envdapi/

运行命令:

make generate-sandbox   # 需要安装 buf、protoc-gen-go、protoc-gen-connect-go

生成代码标记

所有生成的代码文件首行包含如下标记之一:

  • // THIS FILE IS GENERATED BY api-generator, DO NOT EDIT DIRECTLY!
  • // Code generated by protoc-gen-go. DO NOT EDIT.
  • // Code generated by protoc-gen-connect-go. DO NOT EDIT.
  • // Code generated by github.com/oapi-codegen/oapi-codegen/v2 ... DO NOT EDIT.

绝对不要手动修改这些文件,如需修改请更新对应的 API 规范后重新生成。

编码规范

格式化

  • 使用 gofmt -s 格式化代码(CI 会检查)
  • make generate 会自动运行 gofmt -w .gofumpt -w .

静态检查

  • 使用 staticcheck(CI 会检查)
  • 运行:make staticcheck

注释规范

  • 注释默认使用中文
  • 导出的 API、函数、类型、常量、变量必须添加注释
  • 注释以被注释的标识符名称开头(符合 Go 官方 godoc 规范)
  • 包级别注释写在 doc.gopackage 声明之前

命名规范

  • 构造函数使用 New*()New*Ex() 命名
  • 错误类型:根包使用 client.ErrorInfo(Code + Err + Reqid),storagev2 使用 storagev2/errors

错误处理

  • 错误使用 Go 标准的 fmt.Errorf("context: %w", err) 包装
  • 使用 errors.Is() / errors.As() 判断错误类型

测试规范

Build Tags

测试文件必须添加 build tag:

//go:build unit

package xxx_test
  • unit — 单元测试,不依赖外部服务
  • integration — 集成测试,需要七牛账号和网络

Makefile 测试命令

命令 说明
make unittest 运行单元测试(提交前必须通过)
make integrationtest 运行集成测试(需要环境变量配置)
make test 运行所有测试

所有测试命令排除 examples/sms/ 目录。

测试实践

  • 使用 testify/assert 进行断言
  • 推荐使用表驱动测试
  • mock 测试可参考 storagev2/apistest

CI 流程

CI 在 push 和 pull_request 时触发(.github/workflows/ci-test.yml):

Linux(主要检查)

Go 1.22 + stable 两个版本矩阵:

  1. gofmt 检查(仅 stable):gofmt -s -l . 检查未格式化文件
  2. staticcheck(仅 stable):make staticcheck
  3. 编译 examples(仅 stable):go build ./examples/...
  4. 单元测试(两个版本):make unittest

Windows / macOS

Linux 通过后依次运行,仅执行 make unittest(stable 版本)。

版本检查

发布 tag 时(.github/workflows/version-check.yml),检查以下三处版本号一致:

  • CHANGELOG.md 包含 ## <version>
  • README.md 包含 require github.com/qiniu/go-sdk/v7 v<version>
  • conf/conf.go 包含 const Version = "<version>"

开发工作流

环境准备

# 初始化 api-specs submodule
git submodule update --init --recursive

# 验证当前状态
make unittest
make staticcheck

日常开发

  1. 确保分支基于最新 master:git fetch upstream && git rebase upstream/master
  2. 修改代码前先运行 make unittest 确认当前状态
  3. 修改 API 规范后运行 make generatemake generate-sandbox
  4. 提交前运行 make unittestmake staticcheck 确保通过
  5. 代码格式化:gofmt -s -w .

修改生成代码的正确流程

  1. 更新 api-specs/ 中对应的 YAML 规范(如需)
  2. 运行 make generate(或 make generate-sandbox
  3. 检查生成结果,确认无误后提交规范和生成代码

测试与验证

实现新功能或修复 bug 时,应同时提供单元测试和集成测试。对于涉及幂等、重试等逻辑的接口,单元测试用 mock 覆盖边界条件,集成测试用真实凭证验证端到端行为。

运行规则

# 单测(提交前必须通过)
make unittest

# 特定包的单测
go test -tags=unit -count=1 -v ./sandbox/

# 集成测试(需要 .env 文件)
set -a && source sandbox/.env && set +a && go test -tags=integration -count=1 -v ./sandbox/

环境变量 .env 文件

sandbox/.env 用于集成测试和示例程序的环境变量配置:

QINIU_API_KEY=          # 七牛 API Key(必填)
QINIU_SANDBOX_API_URL=  # API 端点(可选,默认 https://cn-yangzhou-1-sandbox.qiniuapi.com)
SANDBOX_RETRY_MAX=      # 可重试 API 的最大重试次数(可选,默认 5,设为 0 禁用重试)

使用方式:

cd sandbox/
set -a && source .env && set +a
# 后续 go test / go run 命令可直接读取环境变量

运行示例

# 需要先 source sandbox/.env
go run ./examples/sandbox_idempotency_retry/

重要约定

  1. 不要手动修改生成代码 — 带 DO NOT EDIT DIRECTLY 标记的文件由代码生成器维护
  2. 不要删除 sms 测试排除 — Makefile 中 egrep -v 'examples|sms' 是有意为之
  3. examples 是独立子目录 — 每个示例是独立的 main 包,编译方式为 go build ./examples/...
  4. 版本号三处同步 — 发布时确保 conf/conf.goCHANGELOG.mdREADME.md 版本一致
  5. api-specs 是 git submodule — 更新规范需要在 submodule 中操作
  6. 保持双版本兼容 — storage v1 和 storagev2 v2 并行维护,不要在 v1 中引入 v2 的依赖