一、淘宝 API 签名生成的核心规则
核心规则梳理
参数准备:收集所有请求参数(如
app_key、method、timestamp等),排除sign字段本身;参数排序:按参数名的 ASCII 码升序 排列(如
app_key在method前,timestamp在v前);字符串拼接:
拼接规则:
AppSecret + 排序后的key1value1key2value2... + AppSecret;示例:AppSecret 为
123456,排序后参数是app_key=abc&method=taobao.item.get,则拼接为123456app_keyabcmethodtaobao.item.get123456;加密计算:对拼接后的字符串进行 HMAC-MD5 加密,并将结果转为 大写(淘宝要求签名为大写);
参数添加:将生成的签名作为
sign参数加入请求,最终发送给 API 接口。
关键注意事项
所有参数值需保持原始格式(如时间戳
2025-01-12 10:00:00不能额外转义);不允许参数名 / 值前后加空格,否则会导致签名错误;
编码统一为
UTF-8,避免中文参数乱码导致签名失效。
二、Python 实现签名生成(完整代码)
taobao.item.get),可直接复用:import hmacimport hashlibfrom urllib.parse import quote # 可选:处理特殊字符参数def generate_taobao_sign(params: dict, app_secret: str) -> str:
"""
生成淘宝API的HMAC-MD5签名
:param params: 接口请求参数(字典,不含sign字段)
:param app_secret: 淘宝开放平台的AppSecret
:return: 大写的签名字符串
"""
# 步骤1:过滤空值参数(可选,淘宝API允许空值但建议过滤)
valid_params = {k: v for k, v in params.items() if v is not None and v != ""}
# 步骤2:按参数名ASCII升序排序
sorted_items = sorted(valid_params.items(), key=lambda x: x[0])
# 步骤3:拼接key=value(注意:淘宝不需要URL编码,特殊字符除外)
# 若参数含中文/特殊字符(如&、=),需用quote编码,示例:quote(str(v), safe='')
sign_str = ""
for k, v in sorted_items:
# 确保参数值为字符串(处理数字/布尔值)
value = str(v)
# 特殊字符编码(可选,根据实际参数调整)
# value = quote(value, safe='') # 仅参数含特殊字符时启用
sign_str += f"{k}{value}"
# 步骤4:拼接AppSecret(前后都加)
sign_str = app_secret + sign_str + app_secret
# 步骤5:HMAC-MD5加密并转大写
sign = hmac.new(
app_secret.encode("utf-8"), # 密钥编码为bytes
sign_str.encode("utf-8"), # 待加密字符串编码为bytes
digestmod=hashlib.md5 # 加密算法:MD5
).hexdigest().upper() # 转16进制字符串并大写
return sign# -------------------------- 测试示例 --------------------------if __name__ == "__main__":
# 模拟淘宝商品详情API的请求参数
request_params = {
"app_key": "你的AppKey", # 替换为自己的AppKey
"method": "taobao.item.get",
"format": "json",
"v": "2.0",
"sign_method": "hmac",
"timestamp": "2025-01-12 10:00:00", # 需与请求的时间戳一致
"num_iid": "1234567890", # 商品ID
"fields": "num_iid,title,price" # 要获取的字段
}
# 替换为自己的AppSecret
app_secret = "你的AppSecret"
# 生成签名
sign = generate_taobao_sign(request_params, app_secret)
print(f"生成的签名:{sign}")
# 将签名加入请求参数,即可调用API
request_params["sign"] = sign print(f"最终请求参数:{request_params}")三、关键代码说明
1. 参数过滤(可选但推荐)
valid_params),因为淘宝 API 若传入空值参数,排序后会参与签名计算,可能导致本地签名与服务端不一致。2. 特殊字符处理
若参数值包含中文、
&、=、空格等特殊字符,需用urllib.parse.quote编码(示例中已注释,启用即可);编码时
safe=''表示所有特殊字符都编码(符合淘宝要求),避免部分字符漏编码。
3. 数据类型转换
str(v)),因为淘宝 API 要求参数值为字符串类型,若直接传入数字(如v=2.0),需转为"2.0"再参与计算。四、签名验证与常见错误排查
1. 如何验证签名是否正确?
方式 1:调用淘宝 API 时,若返回
sign check fail,说明签名错误;若返回正常数据,说明签名正确;方式 2:使用淘宝开放平台的「签名测试工具」(需登录开发者后台),输入相同参数和 AppSecret,对比工具生成的签名与代码生成的签名是否一致。
2. 常见签名错误原因及解决
| 错误现象 | 常见原因 | 解决方法 |
|---|---|---|
sign check fail | 参数排序错误 | 确认按参数名 ASCII 升序排序(可打印sorted_items核对) |
| 签名不一致 | 拼接时多 / 少加了 AppSecret | 确保AppSecret在拼接字符串的开头和结尾各加一次 |
| 中文参数导致签名错误 | 中文未编码或编码格式错误 | 用quote(value, safe='')编码中文,确保编码为 UTF-8 |
| 时间戳导致签名错误 | 本地时间与服务器时间偏差过大 | 时间戳格式为YYYY-MM-DD HH:MM:SS,且与服务器时间偏差≤5 分钟 |
| 参数值含空格 | 参数值前后有多余空格 | 对参数值做strip()处理,去除首尾空格 |
五、实战:结合签名调用淘宝商品详情 API
import requestsimport time# 复用上面的generate_taobao_sign函数def generate_taobao_sign(params: dict, app_secret: str) -> str:
valid_params = {k: v for k, v in params.items() if v is not None and v != ""}
sorted_items = sorted(valid_params.items(), key=lambda x: x[0])
sign_str = ""
for k, v in sorted_items:
sign_str += f"{k}{str(v)}"
sign_str = app_secret + sign_str + app_secret
sign = hmac.new(
app_secret.encode("utf-8"),
sign_str.encode("utf-8"),
hashlib.md5 ).hexdigest().upper()
return sign# 调用淘宝商品详情APIdef call_taobao_item_api(app_key, app_secret, item_id):
# 1. 构造基础参数
params = {
"app_key": app_key,
"method": "taobao.item.get",
"format": "json",
"v": "2.0",
"sign_method": "hmac",
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"num_iid": item_id,
"fields": "num_iid,title,price,sales,stock"
}
# 2. 生成签名
sign = generate_taobao_sign(params, app_secret)
params["sign"] = sign
# 3. 调用API
api_url = "https://eco.taobao.com/router/rest"
response = requests.get(api_url, params=params)
result = response.json()
# 4. 解析结果
if "error_response" in result:
print(f"调用失败:{result['error_response']['msg']}")
else:
print(f"商品标题:{result['item']['title']}")
print(f"商品价格:{result['item']['price']}")# 测试调用(替换为自己的AppKey、AppSecret、商品ID)if __name__ == "__main__":
APP_KEY = "你的AppKey"
APP_SECRET = "你的AppSecret"
ITEM_ID = "1234567890"
call_taobao_item_api(APP_KEY, APP_SECRET, ITEM_ID)总结
规则严格:必须按「参数排序→拼接→加 AppSecret→HMAC-MD5 加密→大写」的步骤执行;
细节避坑:处理空值、特殊字符、数据类型转换,避免因小细节导致签名错误;
验证优先:生成签名后先通过测试工具验证,再调用 API,减少调试成本。