Kotlin 签名 SDK 接入指南
功能说明
Kotlin 签名 SDK 用于为美图开放平台 API 请求生成以下认证请求头:
X-Sdk-Date:UTC 请求时间。Authorization:基于 AK/SK 和SDK-HMAC-SHA256算法生成的签名。
SDK 支持 GET、POST 等 HTTP 方法,并提供同步 HTTP 调用接口和基于协程的异步调用方式。SK 只应保存在受信任的服务端,不要写入 Android 或其他客户端应用。
环境要求
- JDK 8 或更高版本。
- Kotlin 1.5 或更高版本。
- 使用
MTHttpClient.kt或MTDemo.kt时,需要添加kotlinx-coroutines-core。 - SDK 下载包为 Kotlin 源码包,需要将源码复制到 Kotlin/JVM 服务端工程中使用。
下载与引入
解压后包含:
AIGCP-API-kotlin-sdk-1.0.0/
├── MTSigner.kt
├── MTHttpClient.kt
├── MTDemo.kt
└── README.md将 MTSigner.kt 和 MTHttpClient.kt 复制到工程的以下目录:
src/main/kotlin/com/meitu/signer/在 Gradle 工程中添加协程依赖。以下版本可用于 Kotlin 1.9 工程;已有工程也可以使用其统一管理的兼容版本:
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
}业务代码中的导入方式:
import com.meitu.signer.MTHttpClient
import com.meitu.signer.MTSigner
import com.meitu.signer.SignatureInfo接口说明
创建签名器
val signer = MTSigner(accessKey, secretKey)| 参数 | 说明 |
|---|---|
accessKey | 应用的 API Key(AK) |
secretKey | 应用的 Secret Key(SK) |
生成签名
fun sign(
url: String,
method: String,
headers: Map<String, String>,
body: String = ""
): SignatureInfo| 参数 | 说明 |
|---|---|
url | 完整请求 URL,包含路径和查询参数 |
method | HTTP 方法,使用大写形式,例如 GET、POST |
headers | 待签名请求头;必须包含 Host |
body | 实际发送的请求体;GET 请求通常使用空字符串 |
返回值:
data class SignatureInfo(
val url: String,
val method: String,
val headers: Map<String, String>,
val body: String?
)headers 中包含 SDK 生成的 X-Sdk-Date 和 Authorization,发送请求时必须使用返回对象中的 URL、方法、请求头和 body。
HTTP 调用
同步调用:
val client = MTHttpClient.createDefault()
val response = client.execute(signedInfo)协程调用:
val client = MTHttpClient.createDefault()
val response = with(MTHttpClient.Companion) {
client.executeAsync(signedInfo)
}响应结构:
data class Response(
val code: Int,
val headers: Map<String, List<String>>,
val body: String?
)不校验 body 摘要
默认情况下,body 的 SHA-256 摘要会参与签名。如果目标接口允许使用 UNSIGNED-PAYLOAD,请在签名前设置:
headers[MTSigner.HEADER_CONTENT_SHA256] = "UNSIGNED-PAYLOAD"POST 完整调用示例
以下示例调用正式任务提交接口:
https://openapi.meitu.com/api/v1/sdk/sync/push
请求 body 包含 task、task_type、init_images、params 和 sync_timeout 五个顶层字段,params 为 JSON 字符串。示例中的任务、业务参数、图片地址和超时时间需要按目标能力 API 文档替换。
package example
import com.meitu.signer.MTSigner
import com.meitu.signer.MTHttpClient
suspend fun main() {
val signer = MTSigner(
requireEnv("MEITU_OPENAPI_AK"),
requireEnv("MEITU_OPENAPI_SK")
)
val url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
val body = """
{
"task": "/v1/Text_Chart_High_Definition/472492",
"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
}
""".trimIndent()
val headers = mapOf(
MTSigner.HEADER_HOST to "openapi.meitu.com",
"Content-Type" to "application/json; charset=UTF-8"
)
val signedInfo = signer.sign(url, "POST", headers, body)
val client = MTHttpClient.createDefault()
val response = with(MTHttpClient.Companion) {
client.executeAsync(signedInfo)
}
println("HTTP ${response.code}")
println(response.body.orEmpty())
}
private fun requireEnv(name: String): String {
return requireNotNull(System.getenv(name)) {
"Missing environment variable: $name"
}
}示例将签名后返回的 signedInfo 直接交给 HTTP 客户端,确保发送内容与签名内容一致。
GET 调用示例
以下示例查询任务状态。将该函数与 POST 示例中的 requireEnv 放在同一文件中即可使用:
suspend fun queryTask(taskId: String) {
val signer = MTSigner(
requireEnv("MEITU_OPENAPI_AK"),
requireEnv("MEITU_OPENAPI_SK")
)
val url = "https://openapi.meitu.com/api/v1/sdk/status?task_id=$taskId"
val headers = mapOf(
MTSigner.HEADER_HOST to "openapi.meitu.com",
"Accept" to "application/json"
)
val signedInfo = signer.sign(url, "GET", headers)
val client = MTHttpClient.createDefault()
val response = with(MTHttpClient.Companion) {
client.executeAsync(signedInfo)
}
println("HTTP ${response.code}")
println(response.body.orEmpty())
}任务 ID 如果包含特殊字符,应先进行 URL 编码,再构造并签名 URL。
注意事项
Host必须设置为openapi.meitu.com,不能包含协议或路径。- URL、HTTP 方法、查询参数、已签名请求头和 body 在签名后不得修改。
- POST 请求必须使用签名时的同一 body,并按 UTF-8 字节发送。
params必须是 JSON 字符串,不是嵌套 JSON 对象。task、task_type、图片字段和sync_timeout以目标能力 API 文档为准。- 默认让 SDK 生成
X-Sdk-Date;调用服务器需要保持系统时间准确。 - 内置发送器按 JVM 默认字符集写入 body;body 含非 ASCII 字符时,必须确保 JVM 默认字符集为 UTF-8。
- 下载包内置发送器基于阻塞式 HTTP;服务端应在 I/O 线程或协程
Dispatchers.IO中调用并设置超时。
常见错误
| 现象 | 处理方法 |
|---|---|
| HTTP 401 或签名校验失败 | 检查 AK/SK、服务器时间、Host,并确认签名后没有修改 URL、请求头或 body |
| HTTP 400 或业务参数错误 | 确认 body 是合法 JSON,params 已序列化为字符串,业务字段符合目标能力文档 |
kotlinx.coroutines 无法解析 | 添加与工程 Kotlin 版本兼容的 kotlinx-coroutines-core 依赖 |
| GET 签名失败 | 在签名前完成查询参数编码,签名后不要改变参数顺序或编码形式 |
| 含中文的 body 验签失败 | 确认签名和发送使用完全相同的 UTF-8 body 字节 |
| 请求超时或无响应 | 设置连接超时和读取超时,并检查网络、DNS 和接口地址 |