Open API RSA 模式使用指南
本文档旨在详细指导用户如何使用 RSA 模式调用共绩算力 Open API,并提供基于 Python 的实现示例。
1. 前置条件
Section titled “1. 前置条件”在开始之前,请确保您已准备好以下环境和工具:
- Python 环境(可选):确保您的系统已安装 Python 3.6 或更高版本。
- 必要的 Python 库(可选):您需要安装 cryptography 库用于 RSA 加签,以及 requests 库用于发送 HTTP 请求。您可以使用 pip 进行安装:pip install cryptography requests
- OpenSSL 工具:通常用于在本地生成 RSA 密钥对。大多数 Linux/macOS 系统自带,Windows 用户可能需要单独安装。
- 您的 RSA 密钥文件:您需要一个 RSA 密钥文件(通常是 .key 或 .pem 格式),该密钥是您提供给平台所对应的密钥。
2. 获取并设置 RSA 密钥
Section titled “2. 获取并设置 RSA 密钥”使用 RSA 模式的第一步是生成 RSA 密钥对并在平台设置您的公钥。
2.1 获取 RSA 密钥对
Section titled “2.1 获取 RSA 密钥对”- 在本地生成 RSA 密钥对:
- 打开终端或命令行工具(如 PowerShell, CMD, Bash)。
- 使用 OpenSSL 生成私钥文件(例如 2048 位):
openssl genrsa -out private.key 2048
- 从私钥中提取公钥文件:
openssl rsa -pubout -in private.key -out public.pem
- 执行完成后,您将得到
private.key
(私钥,务必妥善保管,切勿泄露)和public.pem
(公钥,用于提供给平台)两个文件。

- 在平台设置您的公钥:
- 登录共绩算力平台。
- 进入 API 密钥管理页面
https://console.suanli.cn/settings/key
。 - 点击“新建密钥”,选择“RSA 加验签模式”。
- 填写备注并提供您的 RSA 公钥。 使用文本编辑器打开您本地生成的
public.pem
文件,复制从-----BEGIN PUBLIC KEY-----
到-----END PUBLIC KEY-----
的全部内容,粘贴到平台对应的输入框。 - 系统将生成并展示与您公钥匹配的 RSA 公钥 以及其他相关信息。
重要: 请务必立即妥善保管生成的私钥和相关信息,因为它们只会显示一次。一旦丢失,您将无法找回,只能重新生成新的密钥对。平台仅保存您的公钥用于验证签名。

2.2 三种 RSA 密钥格式介绍
Section titled “2.2 三种 RSA 密钥格式介绍”在平台设置密钥时,可能会涉及不同的密钥格式。理解这些格式有助于您正确处理密钥文件:
-
RsaPkcs8Pem
- 结构:符合 PKCS#8 标准的 RSA 密钥
- 格式:PEM 编码(含头部/尾部标签的文本文件,如 -----BEGIN PRIVATE KEY-----)
- 用途:通用性强,适用于配置文件、文件存储
-
RsaPkcs1Pem
- 结构:符合 PKCS#1 标准的 RSA 密钥(原始 RSA 参数)
- 格式:PEM 编码(含 RSA 专属标签,如 -----BEGIN RSA PRIVATE KEY----- )
- 用途:兼容需要 PKCS#1 格式的旧系统
-
RsaPkcs8Base64
- 结构:PKCS#8 标准密钥
- 格式:纯 Base64 字符串(无 PEM 标签)
- 用途:适合代码嵌入或 API 直接传输
2.3 RSA 密钥格式选型建议
Section titled “2.3 RSA 密钥格式选型建议”- 首选 RsaPkcs8Pem:平台通常默认此格式,通用性最佳,便于文件保管和配置。
- 特殊场景选其他:
- 需对接传统系统 → RsaPkcs1Pem
- 需密钥值直接嵌入代码 → RsaPkcs8Base64
注:平台在您选择并生成密钥后,密钥内容只会展示一次,请务必及时、妥善保管。
3. 使用 Python 脚本进行加签和调用
Section titled “3. 使用 Python 脚本进行加签和调用”我们已经为您准备了一个 Python 脚本 rsa_sign_util.py
来帮助您实现加签和 API 调用过程。
3.1 脚本代码 (rsa_sign_util.py
)
Section titled “3.1 脚本代码 (rsa_sign_util.py)”"""共绩算力 Open API RSA 模式调用工具类
本模块提供了一个完整的 RSA 加验签和加密的 API 调用工具类,支持:1. RSA-SHA256 签名生成2. RSA 公钥加密请求体3. 自动化的 HTTP 请求发送4. 完整的错误处理
主要特性:- 支持带密码的私钥文件- 自动分段加密大数据- 灵活的请求方法支持- 完整的请求头构建
使用前准备:1. 安装依赖:pip install cryptography requests2. 准备 RSA 密钥对文件3. 获取 API 密钥和平台地址
作者:共绩算力技术团队版本:1.0.0"""
import base64import jsonimport time
import requestsfrom cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import padding
class GjRequest: """ 共绩算力 Open API RSA 模式请求工具类
该类封装了完整的 RSA 加验签和加密流程,提供简单易用的 API 调用接口。
主要功能: - 自动读取和管理 RSA 密钥对 - 生成符合平台规范的签名 - 支持请求体加密 - 发送 HTTP 请求并返回响应
使用流程: 1. 实例化类并传入必要参数 2. 调用 request() 方法发送请求 3. 处理返回的响应对象
示例: gj_request = GjRequest( base_url="https://openapi.suanli.cn", api_key="your-api-key", private_key_path="./private.key", public_key_path="./public.pem", private_key_pwd=None )
response = gj_request.request( uri="/api/deployment/resource/search", method="GET" ) """
# API 版本号,根据平台要求设置 version = 1
def __init__( self, base_url: str, api_key: str, private_key_path: str, public_key_path: str, private_key_pwd: str | None, ): """ 初始化 GjRequest 实例
Args: base_url (str): API 网关基础地址,如 "https://openapi.suanli.cn" api_key (str): 平台分配的 API 密钥,用于认证和签名 private_key_path (str): RSA 私钥文件路径,用于生成签名 public_key_path (str): RSA 公钥文件路径,用于加密请求体 private_key_pwd (str | None): 私钥文件密码,如果私钥未加密则为 None
Raises: Exception: 当密钥文件读取失败或格式错误时抛出异常
注意: - 私钥文件必须妥善保管,切勿泄露 - 公钥文件用于加密,私钥文件用于签名 - 如果私钥有密码保护,请确保传入正确的密码 """ self.base_url = base_url # 初始化时读取密钥文件,避免重复读取 self.public_key = self.read_public_key(public_key_path) self.private_key = self.read_private_key(private_key_path, private_key_pwd) self.api_key = api_key
@staticmethod def read_private_key(private_key_path: str, private_key_pwd: bytes | None = None): """ 读取并解析 RSA 私钥文件
支持多种私钥格式: - PKCS#1 格式 (-----BEGIN RSA PRIVATE KEY-----) - PKCS#8 格式 (-----BEGIN PRIVATE KEY-----)
Args: private_key_path (str): 私钥文件路径 private_key_pwd (bytes | None): 私钥密码,如果私钥未加密则为 None
Returns: 解析后的私钥对象,可直接用于签名操作
Raises: Exception: 当文件不存在或解析失败时抛出异常
注意事项: - 确保私钥文件路径正确 - 如果私钥有密码,请传入正确的密码 - 私钥文件应为 PEM 格式 """ try: # 读取私钥文件 with open(private_key_path, "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=private_key_pwd, # 如果私钥有密码,请在此提供 backend=default_backend() ) except FileNotFoundError: raise Exception(f"错误:私钥文件未找到:{private_key_path}") except Exception as e: raise Exception(f"错误:加载私钥失败:{e}") return private_key
@staticmethod def read_public_key(public_key_path: str): """ 读取并解析 RSA 公钥文件
支持标准 PEM 格式的公钥文件: - PKCS#1 格式 (-----BEGIN RSA PUBLIC KEY-----) - PKCS#8 格式 (-----BEGIN PUBLIC KEY-----)
Args: public_key_path (str): 公钥文件路径
Returns: 解析后的公钥对象,可用于加密操作
Raises: Exception: 当文件不存在或解析失败时抛出异常
注意事项: - 确保公钥文件路径正确 - 公钥文件应为 PEM 格式 - 公钥用于加密,私钥用于签名 """ try: with open(public_key_path, "rb") as key_file: # 尝试加载 PEM 格式的公钥 public_key = serialization.load_pem_public_key( key_file.read(), backend=default_backend() ) except FileNotFoundError: raise Exception(f"错误:公钥文件未找到:{public_key_path}") except Exception as e: raise Exception(f"错误:加载公钥失败:{e}") return public_key
def gen_sign( self, uri: str, version: int, timestamp: int, token: int, body: str ): """ 生成符合平台规范的 RSA-SHA256 签名
签名算法说明: 1. 构建待签名字符串:uri\nversion\ntimestamp\ntoken\nbody 2. 使用 RSA-SHA256 算法进行签名 3. 对签名结果进行 Base64 编码
签名字符串格式: - uri: API 接口路径,如 "/api/deployment/resource/search" - version: API 版本号 - timestamp: 时间戳(毫秒) - token: API 密钥 - body: 请求体内容,如果为空则为空字符串
Args: uri (str): API 接口路径,必须以 "/" 开头 version (int): API 版本号 timestamp (int): 时间戳,毫秒级 token (int): API 密钥 body (str): 请求体内容,如果为空则为空字符串
Returns: str: Base64 编码的签名字符串
注意事项: - 确保时间戳为毫秒级 - 请求体为空时,body 参数应为空字符串 - 签名使用 PKCS1v15 填充和 SHA256 哈希算法 """ # 构建待签名字符串,严格按照平台规范 sign_str = f"{uri}\n{version}\n{timestamp}\n{token}\n{body}"
# 使用 RSA 私钥和 SHA-256 算法进行签名 sign_encrypt = self.private_key.sign( sign_str.encode('utf-8'), padding.PKCS1v15(), # 填充方式:PKCS1v15 hashes.SHA256() # 哈希算法:SHA-256 )
# 将签名结果进行 Base64 编码 sign_str_base64 = base64.b64encode(sign_encrypt).decode('utf-8') return sign_str_base64
def encrypt_body( self, data: str, ): """ 使用 RSA 公钥加密请求体数据
加密流程: 1. 将数据转换为 JSON 字符串 2. 将 JSON 字符串转换为字节数组 3. 分段加密(RSA 加密有长度限制) 4. 合并加密结果并进行 Base64 编码
分段加密说明: - RSA-2048 密钥最大加密长度为 256 字节 - 减去 PKCS1v15 填充后,实际可加密长度为 244 字节 - 超过此长度的数据需要分段加密
Args: data (str): 待加密的数据,通常为 JSON 字符串
Returns: str: Base64 编码的加密数据
Raises: Exception: 当加密失败时抛出异常
注意事项: - 加密会增加数据长度 - 分段加密会生成多个加密块 - 返回结果为 Base64 编码的字符串 """ try: # 将数据转换为紧凑的 JSON 字符串(无空格) json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=False) data_bytes = json_str.encode('utf-8')
encrypted_chunks = []
# 分段加密:每次最多加密 244 字节 start = 0 data_len = len(data_bytes) while start < data_len: end = min(start + 244, data_len) chunk = data_bytes[start:end]
# 使用 RSA 公钥加密当前数据块 encrypted_chunk = self.public_key.encrypt( chunk, padding.PKCS1v15() # 使用 PKCS1v15 填充 ) encrypted_chunks.append(encrypted_chunk) start = end
# 合并所有加密块 encrypted_data = b''.join(encrypted_chunks)
# 将加密结果进行 Base64 编码 encrypted_base64 = base64.b64encode(encrypted_data).decode('utf-8')
return encrypted_base64 except Exception as e: # 记录错误但不暴露敏感信息 raise Exception(f"错误:数据加密失败:{e}")
def request( self, uri: str, is_encrypt: bool = False, method: str | None = None, json_data: dict | None = None, params: dict | None = None ): """ 发送 HTTP 请求到指定的 API 接口
完整的请求流程: 1. 确定 HTTP 方法(GET/POST) 2. 处理请求体(可选加密) 3. 构建完整 URL 4. 生成时间戳和签名 5. 设置请求头 6. 发送请求并返回响应
方法自动判断逻辑: - 如果未指定方法且无请求体 → GET 请求 - 如果未指定方法但有请求体 → POST 请求 - 如果明确指定方法 → 使用指定方法
Args: uri (str): API 接口路径,如 "/api/deployment/resource/search" is_encrypt (bool): 是否加密请求体,默认 False method (str | None): HTTP 方法,如 "GET", "POST",默认自动判断 json_data (dict | None): 请求体数据,JSON 格式,默认 None params (dict | None): URL 查询参数,默认 None
Returns: requests.Response: HTTP 响应对象
请求头说明: - Content-Type: application/json - version: API 版本号 - timestamp: 时间戳(毫秒) - sign_str: RSA 签名 - token: API 密钥
注意事项: - 时间戳自动生成,确保与服务器时间同步 - 签名自动生成,无需手动计算 - 支持 URL 查询参数 - 自动处理 URI 路径格式 """ # 自动判断 HTTP 方法 if method is None and json_data is None: method = "GET" if method is None and json_data is not None: method = "POST"
# 处理请求体 request_body = json.dumps(json_data, separators=(',', ':')) if json_data is not None else ""
# 如果需要加密,使用公钥加密请求体 if is_encrypt and self.public_key is not None and json_data is not None: request_body = self.encrypt_body(json_data)
# 确保 URI 以 "/" 开头<i> if not uri.startswith("/"):</i> uri = "/" + uri
# 构建完整 URL url = self.base_url + uri
# 添加查询参数<i> if params is not None:</i> url += "?" + "&".join(f"{k}={v}" for k, v in params.items())
# 生成时间戳(毫秒级) timestamp = int(time.time() * 1000)
# 生成签名 sign_str = self.gen_sign( uri=uri, version=self.version, timestamp=timestamp, token=self.api_key, body=request_body, )
# 构建请求头 headers = { "Content-Type": "application/json", "version": str(self.version), "timestamp": str(timestamp), "sign_str": sign_str, "token": self.api_key }
# 发送 HTTP 请求 res = requests.request( method=method, url=url, data=request_body, headers=headers )
return res
if __name__ == "__main__": """ 主程序入口,演示如何使用 GjRequest 类
使用前请确保: 1. 已安装必要的依赖库 2. 密钥文件路径正确 3. API 密钥有效 4. 网络连接正常 """
# 创建 GjRequest 实例 gjRequest = GjRequest( base_url="https://openapi.suanli.cn", # API 网关地址 api_key="984de995-3360-4426-931e-8f466d79a50a-20250813173729", # 您的 API 密钥 private_key_path="./private.key", # 私钥文件路径 public_key_path="./public.pem", # 公钥文件路径 private_key_pwd=None, # 私钥密码(如果有) )
# 发送 GET 请求示例 response = gjRequest.request( uri="/api/deployment/resource/search", # API 接口路径 # method="GET", # 可选:明确指定方法 # is_encrypt=False, # 可选:是否加密请求体 # params={"region": "beijing"} # 可选:URL 查询参数 )
# 打印响应结果 print(f"状态码:{response.status_code}") print(f"响应头:{dict(response.headers)}") print(f"响应体:{response.text}")
# POST 请求示例(带加密) # post_response = gjRequest.request( # uri="/api/deployment/task/create", # method="POST", # json_data={ # "task_name": "test-task", # "resources": [{"mark": "resource_mark"}], # "points": 1, # "services": [{ # "service_name": "test-service", # "service_image": "harbor.suanleme.cn/library/ffmpeg-api:cpu", # "remote_ports": [{"service_port": 8000}], # "env": None, # "storage_config": None # }] # }, # is_encrypt=True # 启用请求体加密 # )
3.2 脚本使用说明
Section titled “3.2 脚本使用说明”3.2.1 基于 GjRequest 类的使用方式
Section titled “3.2.1 基于 GjRequest 类的使用方式”我们提供了一个完整的 GjRequest
类,封装了所有 RSA 加验签和加密功能,使用更加简单和灵活。
步骤 1:保存脚本
Section titled “步骤 1:保存脚本”确保您已将完整的 Python 代码保存为 gj_request.py
文件。
步骤 2:准备密钥文件
Section titled “步骤 2:准备密钥文件”将您的 RSA 密钥文件放在与 gj_request.py
相同的目录下:
-
私钥文件:
private.key
(必需,用于生成签名) -
公钥文件:
public.pem
(必需,用于加密请求体)
步骤 3:配置参数
Section titled “步骤 3:配置参数”打开 gj_request.py
文件,找到 if __name__ == "__main__":
部分,修改以下参数:
gjRequest = GjRequest( base_url="https://openapi.suanli.cn", # API 网关地址 api_key="your-api-key-here", # 您的 API 密钥 private_key_path="./private.key", # 私钥文件路径 public_key_path="./public.pem", # 公钥文件路径 private_key_pwd=None, # 私钥密码(如果有))
参数说明:
base_url
: API 网关基础地址api_key
: 平台分配的 API 密钥private_key_path
: RSA 私钥文件路径public_key_path
: RSA 公钥文件路径private_key_pwd
: 私钥文件密码(如果私钥未加密则为 None)
步骤 4:配置请求参数
Section titled “步骤 4:配置请求参数”在 request()
方法调用中配置具体的 API 调用参数:
response = gjRequest.request( uri="/api/deployment/resource/search", # API 接口路径 method="GET", # HTTP 方法(可选,自动判断) is_encrypt=False, # 是否加密请求体 params={"region": "beijing"} # URL 查询参数(可选))
response = gjRequest.request( uri="/api/deployment/task/create", # API 接口路径 method="POST", # HTTP 方法 json_data={ # 请求体数据 "task_name": "test-task", "resources": [{"mark": "resource_mark"}], "points": 1, "services": [{ "service_name": "test-service", "service_image": "harbor.suanleme.cn/library/ffmpeg-api:cpu", "remote_ports": [{"service_port": 8000}], "env": None, "storage_config": None }] }, is_encrypt=True # 启用请求体加密)
请求参数说明:
uri
: API 接口路径,必须以 ”/” 开头method
: HTTP 方法(“GET” 或 “POST”),如果不指定会自动判断is_encrypt
: 是否加密请求体,默认 Falsejson_data
: 请求体数据,JSON 格式字典params
: URL 查询参数,字典格式
步骤 5:运行脚本
Section titled “步骤 5:运行脚本”打开终端或命令行,切换到 gj_request.py
文件所在的目录,然后运行:
python gj_request.py
3.2.2 高级使用方式
Section titled “3.2.2 高级使用方式”您可以根据需要修改类中的默认配置:
class GjRequest: # 修改默认 API 版本 version = "1.0.0" # 从 1 改为 "1.0.0"
# 添加自定义请求头 def request(self, ...): # ... 现有代码 ... headers = { "Content-Type": "application/json", "version": str(self.version), "timestamp": str(timestamp), "sign_str": sign_str, "token": self.api_key, "User-Agent": "MyApp/1.0", # 添加自定义请求头 "Accept": "application/json" }
批量请求处理
Section titled “批量请求处理”gj_request = GjRequest( base_url="https://openapi.suanli.cn", api_key="your-api-key", private_key_path="./private.key", public_key_path="./public.pem", private_key_pwd=None)
apis_to_call = [ "/api/deployment/resource/search", "/api/deployment/task/list", "/api/deployment/storage/list"]
for api_path in apis_to_call: response = gj_request.request(uri=api_path) print(f"API: {api_path}, Status: {response.status_code}")
3.2.3 错误处理和调试
Section titled “3.2.3 错误处理和调试”常见错误及解决方案
Section titled “常见错误及解决方案”- 私钥文件未找到
- 检查文件路径是否正确
- 确认文件是否存在于指定目录
- 密钥格式错误
- 确保密钥文件为 PEM 格式
- 检查密钥是否损坏或格式不正确
- 签名验证失败
- 检查时间戳是否与服务器同步
- 确认 API 密钥是否正确
- 验证请求体格式是否符合要求
import logginglogging.basicConfig(level=logging.DEBUG)
timestamp = int(time.time() * 1000)sign_str = gj_request.gen_sign( uri="/api/test", version=gj_request.version, timestamp=timestamp, token=gj_request.api_key, body="{}")print(f"待签名字符串:/api/test\\n{gj_request.version}\\n{timestamp}\\n{gj_request.api_key}\\n{{}}")print(f"生成的签名:{sign_str}")
3.2.4 依赖安装
Section titled “3.2.4 依赖安装”在运行脚本前,确保已安装必要的 Python 库:
pip install cryptography requests
python -m venv venvsource venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windowspip install cryptography requests
3.3 响应结果说明
Section titled “3.3 响应结果说明”开始处理请求...处理成功。用于签名的 data_str: '{}'计算得到的 Base64 签名字符串 (sign_str): ...使用的时间戳 (timestamp): ...构建的待加签原始字符串(供参考,请确保与平台逻辑一致):---BEGIN STRING TO SIGN---/api/deployment/resource/search1.0.0...//**实际 token 字符串**{}---END STRING TO SIGN---
发送 API 请求至: https://openapi.suanli.cn/api/deployment/resource/search请求方法: GET请求头: { "version": "1.0.0", "timestamp": "...", "token": "实际 token 字符串", "sign_str": "..."}
API 响应:{ "code": 0, "msg": "success", "data": { "device_categories": [ { "device_name": "H20", "region_map": { "xingjiangf-1": { "region": "xingjiangf-1", "region_name": "新疆一区", "mark": { "resource": { "device_name": "H20", "region": "xingjiangf-1", "gpu_name": "H20", "gpu_count": 1, "gpu_memory": 98304, "memory": 196608, "cpu_cores": 24 }, "region_name": null, "mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0VuvbQPOAijLHAl\nL3THz4zxz17CQ2xan6Q2UrnIQ\n6pUPcLqpoLUCh5MaAR9kIet8llTG2oulHTzTR6DoHqgQoSFvtGpGD4Rh7S1F32ACv6i9o7EFy0RPUnKv\nTMUFPSo1heC27vZCm+ab5SZnpZiQ==" }, "price": 2052, "inventory": 0 }, "hebeif-1": { "region": "hebeif-1", "region_name": "河北一区", "mark": { "resource": { "device_name": "H20", "region": "hebeif-1", "gpu_name": "H20", "gpu_count": 1, "gpu_memory": 98304, "memory": 196608, "cpu_cores": 24 }, "region_name": null, "mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0ZtvTTM6x9yfvPw\nu+KYjci3wc3UkKcenSQvVqwc1\nfUVOgLm41GH3chMf1Qrz8UotFVU3Hn7xqS3D53GpC30EtfCecJ8SO4UhLT1UfiU2Oj9tokF2akCb1wba\ns+QFIKvwEvJgaT2WcPA1YY" }, "price": 2052, "inventory": 0 } ], "regions": [ { "region": "xingjiangf-1", "region_name": "新疆一区", "mark": { "resource": { "device_name": "H20", "region": "xingjiangf-1", "gpu_name": "H20", "gpu_count": 1, "gpu_memory": 98304, "memory": 196608, "cpu_cores": 24 }, "region_name": null, "mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0VuvbQPOAijLHAl\nL3THz4zxz17CQ2xan6Q2UrnIQ\n6pUPcLqpoLUCh5MaAR9kIet8llTG2oulHTzTR6DoHqgQoSFvtGpGD4Rh7S1F32ACv6i9o7EFy0RPUnKv\nTMUFPSo1heC27vZCm+ab5SZnpZiQ==" }, "price": 2052, "inventory": 0 },
这个 JSON 数据是运行 rsa_sign_util.py
脚本后收到的 API 响应。
code
: 状态码。0
表示 API 请求成功。message
: 消息字符串。"success"
进一步确认了请求成功。result
: 包含实际数据的结果对象。total
: 表示找到的资源总数。resources
: 这是一个列表,包含了每种资源类型的详细信息。列表中的每个对象代表一种特定的设备配置(例如 “H20 x 8”, “4090 x 8” 等)。device_name
: 设备的名称或配置。region_map
和regions
: 提供该资源在不同区域的可用性和详细信息。regions
是一个列表,每个元素代表一个区域的详情。region
: 区域代码。region_name
: 区域的中文名称(例如 “浙江一区”, “福建一区”)。mark
: 包含资源规格和标记的内部对象。price
: 该资源在该区域的价格。inventory
: 该资源在该区域的库存数量。gpu_name
: 使用的 GPU 型号(例如 “H20”, “4090”)。gpu_memory
: GPU 显存大小。gpu_count
: GPU 数量。memory
: 系统内存大小。cpu_cores
: CPU 核心数。
4. API 接口说明
Section titled “4. API 接口说明”4.1 公共请求头
Section titled “4.1 公共请求头”列名 | 类型 | 是否必填 | 说明 | 实例值 |
version | String | 是 | API 版本 | 1.0.0 |
token | String | 否 | 认证 token | |
sign_str | String(Base64) | 否 | 签名字符串(参考加签流程) | |
timestamp | Integer | 是 | 时间戳(毫秒) | 1721299458423 |
4.2 请求体
Section titled “4.2 请求体”参考具体接口要求。如果请求体需要加密,请参考 4.5 加密流程(先加密再计算加签字符串)。请求参考下面的示例。
4.3 cURL 请求示例
Section titled “4.3 cURL 请求示例”curl --location --request POST 'https://{gateway-host}/{api-path}' \\--header 'token: a0e13fe1-5626-4c05-926b-20f586c69102-20240821144204' \\--header 'timestamp: 1724222524375' \\--header 'version: 1.0.0' \\--header 'sign_str: EowIBAAKCAQEArbNcSNSLjHzqOzrYL+7afEh5TI4hn1BCxsuzY02c1RMn24a2YEvpqCCVDxmgN/dcAdcCcvhO/2wDG389LuEkw+QhVPzdAE29bbzz+Gb/FDusVNo6tl8mbfd/XA53h3sOCekEMP2QCoPAoUO94wUWK5RpjsONf9Bs0Q6YUmL4TWqvPGmWjc/Y8winDtFzKN2his5PhbWlRiSkENGXSma6lr66BA/SduAY/Fl8YxEWThVkYsAurg0rEd83DilN4zp7hZf82Msjgp8kPm/SMHTEF2V2cOo82m12HyRJKuKS0L8WPVIwQmXJ6VN55ue+b96sryUs/WZyfiXTh0thoa9vqQIDAQABAoIBAQCsOMDQSUTPl27aKR7+b5FbVrRF7kpx3i9HUeLcG7DbJrIHHAspcTsLgrqoDR1pQC2OeXMpMP+KirqOAdtU5tAAFenijRBGY83kx0sSSHSyx/O28eTyu2ar84/oY0OqJZ0mwE1ykYXGlxlgC31zYLC5pt3+Oe/LAYlSwmjOjuhoQDMZoiCByIw6oDAVLIlZwTl8A/HAR1yacDTh6lps1vTZ5lBfIDpbn1gHb2GWqHu8q9oD9G9IEyWwwTE1IsNXVwBKEifjLubd2WfTWDmROVZZ9T4AXm/40/Eb6ALApwY5s7lBMIiapmcJZzlyELEukUMmYN7vHBjdMDOPK3tjLSKNA' \\--data-raw '{"task_id": 1}'
4.4 公共响应体
Section titled “4.4 公共响应体”列名 | 类型 | 不是 null | 说明 | 实例值 |
code | String | 是 | 响应 code | 0000 |
message | String | 否 | 响应说明 | success |
data | Object | 否 | 数据体 | {"task_name": "test_task1"} |
4.5 加签流程
Section titled “4.5 加签流程”- 生成待加签字符串:
将以下参数按照顺序用换行符 \n
连接起来:
path
: 接口地址。GET 请求需要包含完整的 URL(含 query 参数)。version
: 请求头中的接口版本。timestamp
: 请求头中的时间戳(毫秒)。token
: 请求头中的 token。data
: 接口请求体。如果接口需要加密,则为加密后的 Base64 字符串。
格式示例:path\nversion\ntimestamp\ntoken\ndata
例如:/api/user/order/get_this_week_residue_withdrawal_count 1.0.0 1724222524375 a0e13fe1-5626-4c05-926b-20f586c69102-20240821144204 {"username":"test1","password":"password1"}
- 计算签名:
使用 RSA-SHA256 签名算法对待签名字符串进行计算,得到签名结果(字节数组)。
- Base64 编码:
将签名结果(字节数组)转换为 Base64 字符串。
- 设置请求头:
将生成的 Base64 签名字符串设置到请求头的 sign_str
字段。
4.6 加密流程
Section titled “4.6 加密流程”- 根据 RSA 公钥对待发送的请求体进行 rsa_pubk_encrypt 算法加密。
- 将加密后的字节数组转换为 Base64 字符串。
- 将该 Base64 字符串作为实际的请求体发送。
- 如果请求同时需要加密和加签 必须先进行加密步骤,再进行加签步骤(加签时使用的 data 即为加密后的 Base64 字符串)。