JavaScript 签名 SDK 接入指南
功能说明
javaScript 签名 SDK 用于为美图开放平台 API 请求生成 X-Sdk-Date 和 Authorization 请求头。SDK 根据 HTTP 方法、URL、请求头和请求正文计算 SDK-HMAC-SHA256 签名,并返回可传给 https.request() 的请求选项。
SDK 只负责签名,不会主动发送请求。接口地址、请求方法和业务参数以目标能力的 API 文档为准。
环境要求
- Node.js 18 或更高版本
- CommonJS 模块环境
- 可访问目标 API 的 HTTPS 网络环境
- Access Key(AK)和 Secret Key(SK)
下载与引入
SDK 版本:1.0.3
下载:AIGCP-API-javaScript-sdk-1.0.3.zip
解压后,将 sign.js 放入项目目录,并安装依赖:
npm install moment@2.29.4 moment-timezone@0.5.43在业务代码中引入 SDK:
const {
Signer,
HeaderXDate,
HeaderHost,
HeaderAuthorization,
HeaderContentSha256,
} = require('./sign');接口说明
创建签名器
const signer = new Signer(accessKey, secretKey);| 参数 | 类型 | 说明 |
|---|---|---|
accessKey | string | Access Key。 |
secretKey | string | Secret Key。 |
签名请求
const requestOptions = signer.sign(url, method, headers, body);| 参数 | 类型 | 说明 |
|---|---|---|
url | string | 最终请求 URL,包含路径和查询参数。 |
method | string | 大写 HTTP 方法,例如 GET 或 POST。 |
headers | object | 待签名请求头。必须包含与 URL 一致的 Host。 |
body | string 或 Buffer | 最终请求正文。空正文传 ''。 |
sign() 会向 headers 写入 X-Sdk-Date 和 Authorization,并返回 https.request() 所需的 method、hostname、path、port 和 headers。
常用请求头如下:
| 常量 | 请求头 | 说明 |
|---|---|---|
HeaderHost | Host | 必填,值应为最终 URL 的 host。 |
HeaderXDate | X-Sdk-Date | 可选;不传时由 SDK 按 UTC 时间自动生成。 |
HeaderAuthorization | Authorization | 由 SDK 自动生成。 |
HeaderContentSha256 | X-Sdk-Content-Sha256 | 可选;目标 API 明确允许时可设为 UNSIGNED-PAYLOAD。 |
默认情况下,SDK 会计算正文的 SHA-256 摘要并纳入签名。如果目标 API 明确允许正文不参与签名,可在调用 sign() 前设置:
headers[HeaderContentSha256] = 'UNSIGNED-PAYLOAD';POST 完整调用示例
以下示例调用正式同步推送地址 https://openapi.meitu.com/api/v1/sdk/sync/push。body 只序列化一次,同一个字符串同时用于签名和发送。
const https = require('https');
const { Signer, HeaderHost } = require('./sign');
const accessKey = process.env.AIGCP_ACCESS_KEY;
const secretKey = process.env.AIGCP_SECRET_KEY;
if (!accessKey || !secretKey) {
throw new Error('AIGCP_ACCESS_KEY and AIGCP_SECRET_KEY are required');
}
const endpoint = new URL('https://openapi.meitu.com/api/v1/sdk/sync/push');
const body = JSON.stringify({
task: 'replace-with-task',
task_type: 'replace-with-task-type',
init_images: ['https://example.com/input.jpg'],
params: JSON.stringify({
example: 'replace with parameters from the target API reference',
}),
sync_timeout: 30,
});
const headers = {
'Content-Type': 'application/json',
[HeaderHost]: endpoint.host,
};
const signer = new Signer(accessKey, secretKey);
const requestOptions = signer.sign(endpoint.href, 'POST', headers, body);
const request = https.request(requestOptions, (response) => {
response.setEncoding('utf8');
let responseBody = '';
response.on('data', (chunk) => {
responseBody += chunk;
});
response.on('end', () => {
console.log(`status=${response.statusCode}`);
console.log(responseBody);
if (response.statusCode < 200 || response.statusCode >= 300) {
process.exitCode = 1;
}
});
});
request.setTimeout(60_000, () => {
request.destroy(new Error('request timed out'));
});
request.on('error', (error) => {
console.error(error.message);
process.exitCode = 1;
});
request.write(body);
request.end();运行前设置凭据:
export AIGCP_ACCESS_KEY='<your-access-key>'
export AIGCP_SECRET_KEY='<your-secret-key>'
node demo.js示例中的 task、task_type、图片 URL、params 内容和 sync_timeout 仅用于展示请求结构,请按照目标能力 API 文档替换。params 必须是 JSON 字符串。
GET 调用示例
GET 请求应先构造最终查询参数,再进行签名。AIGCP_GET_API_URL 应配置为目标能力文档提供的完整 HTTPS 地址。
const https = require('https');
const { Signer, HeaderHost } = require('./sign');
const accessKey = process.env.AIGCP_ACCESS_KEY;
const secretKey = process.env.AIGCP_SECRET_KEY;
const apiUrl = process.env.AIGCP_GET_API_URL;
if (!accessKey || !secretKey || !apiUrl) {
throw new Error('AIGCP_ACCESS_KEY, AIGCP_SECRET_KEY, and AIGCP_GET_API_URL are required');
}
const endpoint = new URL(apiUrl);
if (endpoint.protocol !== 'https:') {
throw new Error('AIGCP_GET_API_URL must be an HTTPS URL');
}
endpoint.searchParams.set('task_id', 'replace-with-task-id');
const headers = {
[HeaderHost]: endpoint.host,
};
const signer = new Signer(accessKey, secretKey);
const requestOptions = signer.sign(endpoint.href, 'GET', headers, '');
const request = https.request(requestOptions, (response) => {
response.setEncoding('utf8');
response.on('data', (chunk) => process.stdout.write(chunk));
});
request.on('error', (error) => console.error(error.message));
request.end();注意事项
- 使用最终 URL、HTTP 方法、请求头和正文完成签名;签名后不要再修改这些内容。
Host使用最终 URL 的endpoint.host,包含非默认端口。- JSON 正文只执行一次
JSON.stringify(),传给sign()和request.write()的内容必须完全相同。 - 每次请求创建新的
headers,不要复用包含旧Authorization或X-Sdk-Date的对象。 - GET 或其他空正文请求传
'',并在签名前完成全部查询参数设置。 - 保持服务器系统时间同步,通常让 SDK 自动生成
X-Sdk-Date。 - 正式请求使用 HTTPS。
- SK 仅保存在受信任的服务端,浏览器中不要使用本 SDK。
常见错误
| 错误或现象 | 处理方法 |
|---|---|
Cannot find module 'moment' | 在项目目录执行依赖安装命令。 |
| 401 或签名校验失败 | 检查 AK/SK、HTTP 方法、最终 URL、查询参数、Host、请求头和正文是否与签名时完全一致。 |
| 第二次请求签名失败 | 不要复用已签名的 headers;每次请求创建新对象。 |
value.trim is not a function | 将所有参与签名的请求头值设为字符串。 |
| 正文哈希报错 | JSON 先序列化为字符串;空正文传 '',不要传 null 或 undefined。 |
| 时间校验失败 | 同步服务器时间,删除手动设置的 X-Sdk-Date 后重新签名。 |
| 请求超时 | 检查网络、代理和 API 地址,并按业务场景调整请求超时。 |
| 返回 4xx 或 5xx | 读取响应体中的错误码和信息,并按目标能力 API 文档处理。 |