Init 初始化握手
Init 是 A7验证两步模型的第一步:用 AppId + AppKey 换取本次会话的 ApiPassword(32 位接口密码)。之后所有业务请求都通过 Handle 发起,并用这个 ApiPassword 做 RC4 加密与 MD5 签名。
| 项目 | 值 |
|---|---|
| 请求方式 | POST |
| 请求地址 | https://api.a7p.cn/api/verify |
| Content-Type | application/x-www-form-urlencoded |
| 是否加密 | 否(Init 阶段明文提交,仅做签名校验) |
| 时间戳窗口 | ±300 秒 |
调用步骤
- 从控制台取得
AppId与AppKey(见获取 AppID 与 API 密钥)。 - 取当前 Unix 秒级时间戳 作为
TimeStamp。 - 按
MD5(AppId + AppKey + TimeStamp + AppKey)计算Sign,注意AppKey出现两次。 - 以表单方式
POST到https://api.a7p.cn/api/verify,提交AppId、AppKey、TimeStamp、Sign四个字段。 - 校验响应
code是否为200。 - 从
data.api_password取出ApiPassword,只保存在内存变量,不要落盘。 - 携带
ApiPassword进入 Handle 阶段调用业务 action。
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
AppId | string | 是 | 程序编号,如 150018,控制台产品详情页可查 |
AppKey | string | 是 | 程序密钥,32 位大写字母 + 数字,机密值 |
TimeStamp | string | 是 | Unix 秒级时间戳,服务端允许 ±300 秒偏差 |
Sign | string | 是 | MD5(AppId + AppKey + TimeStamp + AppKey),推荐小写 32 位 |
签名口诀
AppId → AppKey → TimeStamp → AppKey。第二个 AppKey 相当于「盐」,很多人第一次接入就是漏了它,然后一直卡在 1010。
请求示例
bash
APP_ID="150018"
APP_KEY="YOUR_APP_KEY"
TS=$(date +%s)
SIGN=$(printf "%s%s%s%s" "$APP_ID" "$APP_KEY" "$TS" "$APP_KEY" | md5sum | cut -d' ' -f1)
curl -s -X POST "https://api.a7p.cn/api/verify" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "AppId=${APP_ID}&AppKey=${APP_KEY}&TimeStamp=${TS}&Sign=${SIGN}"python
import hashlib
import json
import time
import urllib.request
BASE = "https://api.a7p.cn/api/verify"
APP_ID = "150018"
APP_KEY = "YOUR_APP_KEY"
ts = int(time.time())
sign = hashlib.md5(f"{APP_ID}{APP_KEY}{ts}{APP_KEY}".encode("utf-8")).hexdigest()
body = f"AppId={APP_ID}&AppKey={APP_KEY}&TimeStamp={ts}&Sign={sign}".encode("utf-8")
req = urllib.request.Request(
BASE, data=body,
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
with urllib.request.urlopen(req, timeout=10) as resp:
result = json.loads(resp.read().decode("utf-8"))
if result["code"] != 200:
raise RuntimeError(f"Init 失败 {result['code']}: {result['message']}")
api_password = result["data"]["api_password"]
print("ApiPassword =", api_password)csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public static class A7Init
{
private static readonly HttpClient Http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
public static string Md5(string text)
{
using var md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
var sb = new StringBuilder(32);
foreach (byte b in hash) sb.Append(b.ToString("x2"));
return sb.ToString();
}
/// <summary>Init 握手,返回 ApiPassword;失败抛出异常。</summary>
public static async Task<string> InitAsync(string appId, string appKey)
{
long ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
string sign = Md5($"{appId}{appKey}{ts}{appKey}");
using var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["AppId"] = appId,
["AppKey"] = appKey,
["TimeStamp"] = ts.ToString(),
["Sign"] = sign
});
using HttpResponseMessage resp =
await Http.PostAsync("https://api.a7p.cn/api/verify", content);
string body = await resp.Content.ReadAsStringAsync();
JsonElement root = JsonDocument.Parse(body).RootElement;
int code = root.GetProperty("code").GetInt32();
if (code != 200)
{
throw new InvalidOperationException(
$"Init 失败 {code}: {root.GetProperty("message").GetString()}");
}
return root.GetProperty("data").GetProperty("api_password").GetString() ?? "";
}
}text
.版本 2
.子程序 A7_Init, 文本型, 公开, 握手成功返回 ApiPassword,失败返回空文本
.参数 AppId, 文本型
.参数 AppKey, 文本型
.局部变量 TimeStamp, 文本型
.局部变量 Sign, 文本型
.局部变量 返回文本, 文本型
TimeStamp = 到文本 (时间_取现行时间戳 ())
Sign = 取数据摘要 (到字节集 (AppId + AppKey + TimeStamp + AppKey))
返回文本 = 到文本 (网页_访问 ("https://api.a7p.cn/api/verify", 1, ;
"AppId=" + AppId + "&AppKey=" + AppKey + "&TimeStamp=" + TimeStamp + "&Sign=" + Sign))
.如果真 (JSON_解析 (返回文本, "code") ≠ "200")
输出调试文本 ("Init 失败:" + JSON_解析 (返回文本, "message"))
返回 ("")
.如果真结束
返回 (JSON_解析 (返回文本, "data.api_password"))原始 HTTP 报文长这样:
http
POST /api/verify HTTP/1.1
Host: api.a7p.cn
Content-Type: application/x-www-form-urlencoded
AppId=150018&AppKey=YOUR_APP_KEY&TimeStamp=1780000000&Sign=3f2a...c91b成功响应
json
{
"code": 200,
"message": "success",
"data": {
"api_password": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6"
}
}| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 200 表示成功 |
message | string | success |
data.api_password | string | 32 位接口密码,用于后续 Handle 阶段的 RC4 加密与 MD5 签名 |
关于 app_name / version 等扩展字段
部分历史版本文档展示过 app_id、app_name、version、version_name 等回显字段。以当前后端实现为准,Init 稳定返回的是 api_password;程序名称与版本信息请通过 GetVariable 与 GetLatestVersion 获取。请勿假设 Init 一定返回版本字段。
失败响应
json
{ "code": 1001, "message": "程序不存在", "data": null }json
{ "code": 1010, "message": "签名错误", "data": null }json
{ "code": 1011, "message": "程序密钥错误", "data": null }json
{ "code": 1012, "message": "程序未审核通过", "data": null }json
{ "code": 1013, "message": "参数不完整", "data": null }json
{ "code": 1014, "message": "时间戳已过期", "data": null }错误码
| 错误码 | 含义 | 解决方案 |
|---|---|---|
1001 | 程序不存在 | 检查 AppId 是否写错、是否属于当前账号 |
1010 | 签名错误 | 核对 MD5(AppId + AppKey + TimeStamp + AppKey),确认 AppKey 拼接两次且无空格 |
1011 | 程序密钥错误 | AppKey 与服务端不一致,去控制台重新复制 |
1012 | 程序未审核通过 | 产品待审核 / 被驳回 / 套餐过期,去控制台确认状态 |
1013 | 参数不完整 | 四个字段 AppId AppKey TimeStamp Sign 缺一不可 |
1014 | 时间戳已过期 | 校准本机时间,或改用服务器时间;偏差需在 ±300 秒内 |
完整列表见错误码对照表。
相关文档
- Handle 业务调用 —— 第二步:业务分发
- API 概述 · 两步模型 —— 协议全貌
- 签名校验与 RC4 加密 —— 签名踩坑排查
- SDK 实现:易语言 · C# · Python · Go · Node.js · Java · C++