Skip to content

Python 快速接入

本文提供完整的 Python 接入示例,包含签名计算、卡密登录和心跳保活。

环境要求

  • Python >= 3.6
  • requests
bash
pip install requests

完整示例

python
import hashlib
import json
import time
import uuid
import requests

# ========== 配置 ==========
APP_KEY = "your_app_key"
APP_SECRET = "your_app_secret"
API_BASE = "http://api.nullverify.com/api/client/v1"


def make_sign(params: dict) -> str:
    """计算请求签名"""
    # 按 key 字典序排列参数(不含 sign)
    sorted_params = "&".join(
        f"{k}={v}" for k, v in sorted(params.items()) if k != "sign"
    )
    # 拼接签名原文
    raw = sorted_params + APP_SECRET
    return hashlib.md5(raw.encode()).hexdigest()


def make_common_params() -> dict:
    """生成公共参数"""
    return {
        "app_key": APP_KEY,
        "timestamp": str(int(time.time())),
        "nonce": str(uuid.uuid4()),
    }


def parse_response(resp: requests.Response) -> dict:
    """解析响应(自动处理加密响应)"""
    content_type = resp.headers.get("Content-Type", "")
    if "text/plain" in content_type:
        # 加密响应:需先解密再解析
        # 请根据应用配置的加密算法实现解密逻辑
        # 参考 响应加密 文档
        raise NotImplementedError("请实现解密逻辑,参考 /guide/response-encryption")
    return resp.json()


def card_login(card: str, device_id: str) -> dict:
    """卡密登录"""
    params = make_common_params()
    params["card"] = card
    params["device_id"] = device_id
    params["sign"] = make_sign(params)

    resp = requests.post(f"{API_BASE}/card/login", data=params)
    return parse_response(resp)


def card_heartbeat(card: str, token: str) -> dict:
    """卡密心跳"""
    params = make_common_params()
    params["card"] = card
    params["token"] = token
    params["sign"] = make_sign(params)

    resp = requests.post(f"{API_BASE}/card/heartbeat", data=params)
    return parse_response(resp)


def card_logout(card: str, token: str) -> dict:
    """卡密退出"""
    params = make_common_params()
    params["card"] = card
    params["token"] = token
    params["sign"] = make_sign(params)

    resp = requests.post(f"{API_BASE}/card/logout", data=params)
    return parse_response(resp)


def verify_response_sign(resp: dict) -> bool:
    """验证响应签名"""
    result = resp.get("result", {})
    sorted_params = "&".join(
        f"{k}={v}" for k, v in sorted(result.items())
    )
    raw = f"{resp['code']}{resp['message']}{sorted_params}{resp['nonce']}{APP_SECRET}"
    expected = hashlib.md5(raw.encode()).hexdigest()
    return expected == resp.get("sign", "")


# ========== 主流程 ==========
if __name__ == "__main__":
    CARD = "your_card_no"
    DEVICE_ID = "device_001"

    # 1. 登录
    result = card_login(CARD, DEVICE_ID)
    if result["code"] != 0:
        print(f"登录失败: {result['message']}")
        exit(1)

    token = result["result"]["token"]
    hg = result["result"].get("hg", 30)
    print(f"登录成功,到期时间: {result['result']['expires']}")

    # 验证响应签名
    if verify_response_sign(result):
        print("响应签名验证通过")

    # 2. 心跳保活
    try:
        while True:
            time.sleep(hg)
            hb = card_heartbeat(CARD, token)
            if hb["code"] != 0:
                print(f"心跳失败: {hb['message']}")
                break
            print(f"心跳正常,到期时间: {hb['result']['expires']}")
    except KeyboardInterrupt:
        # 3. 退出
        card_logout(CARD, token)
        print("已退出")

关键说明

签名计算

python
# 签名公式: md5(sorted_params + secret)
raw = sorted_params + APP_SECRET
sign = hashlib.md5(raw.encode()).hexdigest()

注意事项

  • 参数值不要进行 URL encode
  • sign 参数本身不参与签名计算
  • timestamp 使用秒级时间戳,不是毫秒

响应处理

启用响应加密后,HTTP 响应体为纯密文字符串,Content-Typetext/plain。客户端需根据 Content-Type 判断是否需要解密:

python
resp = requests.post(url, data=params)
if "text/plain" in resp.headers.get("Content-Type", ""):
    # 纯密文,需先解密
    plaintext = decrypt(resp.text, encrypt_key)
    result = json.loads(plaintext)
else:
    # 明文 JSON
    result = resp.json()

详细解密实现请参考 响应加密

错误处理

建议对所有 API 调用进行错误码判断:

python
resp = card_login(card, device_id)
if resp["code"] == 10210:
    print("卡密已过期,请续费")
elif resp["code"] == 10213:
    print("超过多开上限,请关闭多余客户端")
elif resp["code"] != 0:
    print(f"错误: {resp['message']}")

完整错误码列表请参考 错误码对照表

面向脚本与插件开发者的网络验证系统