JavaScript 签名 SDK 接入指南

功能说明

javaScript 签名 SDK 用于为美图开放平台 API 请求生成 X-Sdk-DateAuthorization 请求头。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);
参数类型说明
accessKeystringAccess Key。
secretKeystringSecret Key。

签名请求

const requestOptions = signer.sign(url, method, headers, body);
参数类型说明
urlstring最终请求 URL,包含路径和查询参数。
methodstring大写 HTTP 方法,例如 GETPOST
headersobject待签名请求头。必须包含与 URL 一致的 Host
bodystringBuffer最终请求正文。空正文传 ''

sign() 会向 headers 写入 X-Sdk-DateAuthorization,并返回 https.request() 所需的 methodhostnamepathportheaders

常用请求头如下:

常量请求头说明
HeaderHostHost必填,值应为最终 URL 的 host
HeaderXDateX-Sdk-Date可选;不传时由 SDK 按 UTC 时间自动生成。
HeaderAuthorizationAuthorization由 SDK 自动生成。
HeaderContentSha256X-Sdk-Content-Sha256可选;目标 API 明确允许时可设为 UNSIGNED-PAYLOAD

默认情况下,SDK 会计算正文的 SHA-256 摘要并纳入签名。如果目标 API 明确允许正文不参与签名,可在调用 sign() 前设置:

headers[HeaderContentSha256] = 'UNSIGNED-PAYLOAD';

POST 完整调用示例

以下示例调用正式同步推送地址 https://openapi.meitu.com/api/v1/sdk/sync/pushbody 只序列化一次,同一个字符串同时用于签名和发送。

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

示例中的 tasktask_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,不要复用包含旧 AuthorizationX-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 先序列化为字符串;空正文传 '',不要传 nullundefined
时间校验失败同步服务器时间,删除手动设置的 X-Sdk-Date 后重新签名。
请求超时检查网络、代理和 API 地址,并按业务场景调整请求超时。
返回 4xx 或 5xx读取响应体中的错误码和信息,并按目标能力 API 文档处理。