Go 签名 SDK 接入指南
功能说明
Go 签名 SDK 用于为美图开放平台 API 请求生成 AK/SK 签名。SDK 根据请求方法、URL、请求头和 body 生成 Authorization,并返回可直接发送的 *http.Request。
SDK 负责签名和创建请求;网络请求由业务代码通过 http.Client.Do 发送。
环境要求
- Go
1.20或更高版本 - 已获取开放平台 Access Key(AK)和 Secret Key(SK)
- 服务端可通过 HTTPS 访问
openapi.meitu.com - SK 应仅保存在服务端,不得下发到客户端
下载与引入
SDK 版本:1.0.3
解压后的主要文件:
AIGCP-API-go-sdk-1.0.3/
├── demo.go
├── go.mod
└── signer/
└── sign.go压缩包的模块名为 github.com/mtlab/api,示例中的引入方式为:
import "github.com/mtlab/api/signer"直接运行示例时,将代码保存为解压目录中的 demo.go,然后执行 go run .。集成到已有 Go 项目时,将 signer 目录复制到项目中,并将 import 改为该项目对应的模块路径。
接口说明
创建签名器
signer.NewSigner(accessKey, secretKey) 返回 *signer.Signer。
| 参数 | 类型 | 说明 |
|---|---|---|
accessKey | string | 开放平台 AK |
secretKey | string | 开放平台 SK |
签名请求
Sign 方法定义:
func (s *Signer) Sign(url, method string, headers http.Header, body string) (*http.Request, error)| 参数 | 类型 | 说明 |
|---|---|---|
url | string | 完整请求 URL,包含路径和查询参数 |
method | string | HTTP 方法,如 http.MethodPost 或 http.MethodGet |
headers | http.Header | 待签请求头;必须包含与 URL 一致的 Host |
body | string | 最终发送的请求 body;GET 通常传空字符串 |
| 返回值 | 说明 |
|---|---|
*http.Request | 已写入 X-Sdk-Date 和 Authorization 的请求,可直接发送 |
error | URL、请求或手动设置的签名时间格式无效时返回错误 |
Sign 会修改传入的 headers。签名完成后,应直接发送返回的 request。
POST 完整调用示例
以下示例调用正式同步任务提交地址:
https://openapi.meitu.com/api/v1/sdk/sync/push
请求 body 包含 task、task_type、init_images、params 和 sync_timeout 五个顶层字段。params 的值是 JSON 字符串。示例中的 task、图片地址、params 和超时时间应替换为目标能力 API 文档规定的值。
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/mtlab/api/signer"
)
func main() {
accessKey := os.Getenv("AIGCP_ACCESS_KEY")
secretKey := os.Getenv("AIGCP_SECRET_KEY")
if accessKey == "" || secretKey == "" {
fmt.Fprintln(os.Stderr, "AIGCP_ACCESS_KEY and AIGCP_SECRET_KEY are required")
os.Exit(1)
}
endpoint := "https://openapi.meitu.com/api/v1/sdk/sync/push"
body := `{"task":"/v1/replace-with-product-task","task_type":"formula","init_images":[{"url":"https://example.com/input.jpg","profile":{"media_profiles":{"media_data_type":"url"},"version":"v1"}}],"params":"{\"parameter\":{\"rsp_media_type\":\"url\"}}","sync_timeout":30}`
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
sign := signer.NewSigner(accessKey, secretKey)
req, err := sign.Sign(endpoint, http.MethodPost, headers, body)
if err != nil {
fmt.Fprintln(os.Stderr, "sign request:", err)
os.Exit(1)
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "send request:", err)
os.Exit(1)
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "read response:", err)
os.Exit(1)
}
fmt.Printf("status=%s\n%s\n", resp.Status, responseBody)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
os.Exit(1)
}
}运行:
export AIGCP_ACCESS_KEY='<your-access-key>'
export AIGCP_SECRET_KEY='<your-secret-key>'
go run .GET 调用示例
GET 接口应使用对应能力文档提供的真实 URL。以下函数在签名前添加查询参数,并使用空 body 创建已签请求:
func buildSignedGetRequest(sign *signer.Signer, endpoint, taskID string) (*http.Request, error) {
parsedURL, err := url.Parse(endpoint)
if err != nil {
return nil, err
}
query := parsedURL.Query()
query.Set("task_id", taskID)
parsedURL.RawQuery = query.Encode()
headers := make(http.Header)
headers.Set(signer.HeaderHost, parsedURL.Host)
return sign.Sign(parsedURL.String(), http.MethodGet, headers, "")
}该函数需要引入 net/url。调用时,endpoint 应为目标 GET 接口的完整 HTTPS 地址;task_id 参数名以对应接口文档为准。返回的 request 通过 http.Client.Do 发送。
注意事项
Host必须与请求 URL 的主机一致。URL 含非默认端口时,Host也应包含该端口。- URL、HTTP 方法、查询参数、请求头和 body 必须在调用
Sign前确定;签名后不得修改。 - JSON body 应只序列化一次。传给
Sign的字符串必须与实际发送的字节完全一致。 - GET 通常使用空字符串 body;POST 应传入最终 body。
- 系统时间应保持同步。未设置
X-Sdk-Date时,SDK 会自动写入当前 UTC 时间。 - 默认情况下 SDK 会计算 body 的 SHA-256。仅当目标接口明确支持时,才可在签名前设置以下请求头:
headers.Set(signer.HeaderContentSha256, "UNSIGNED-PAYLOAD")- AK/SK 鉴权支持的 body 大小以平台和目标接口文档为准;现有签名说明规定为
12M以内。
常见错误
| 现象 | 处理方式 |
|---|---|
401、签名错误或鉴权失败 | 确认 AK/SK、HTTP 方法、完整 URL、Host、查询参数、请求头和 body 与签名时一致。 |
| 时间校验失败 | 同步服务器时间,并让 SDK 自动生成 X-Sdk-Date。 |
| POST body 验签失败 | 确认 body 在签名后未被重新序列化、压缩、转码或修改。 |
| 查询参数验签失败 | 使用 url.Values 在签名前构造最终查询字符串,签名后不再修改 URL。 |
UNSIGNED-PAYLOAD 请求失败 | 确认目标接口支持该方式,并确认请求头名称和值完全一致。 |
| 网络超时或连接失败 | 检查 HTTPS 地址、DNS、代理、出站网络和客户端超时配置。 |
| 返回非 2xx | 读取响应 body,并按目标能力 API 文档中的错误码处理。 |