哔哩哔哩-API收集整理:API签名验证失败常见原因与解决方法
什么是WBI签名验证
自2023年3月起,哔哩哔哩Web端部分接口开始采用WBI签名鉴权,表现在REST API请求时在Query param中添加了w_rid和wts字段。WBI签名鉴权独立于APP鉴权与其他Cookie鉴权,目前被认为是一种Web端风控手段。
当请求WBI签名鉴权接口时,若签名参数w_rid与时间戳wts缺失、错误,会返回v_voucher,如:
{"code":0,"message":"0","ttl":1,"data":{"v_voucher":"voucher_******"}}
常见签名验证失败原因分析
1. 签名参数缺失或错误
最常见的问题是未正确添加w_rid和wts参数。根据WBI签名文档,这两个参数是必需的,缺少任何一个都会导致验证失败。
2. 时间戳过期
wts字段的值应为当前以秒为单位的Unix时间戳。如果时间戳与服务器时间相差过大(通常超过5分钟),签名将被视为无效。这也是为什么在进行API调用时,动态生成时间戳非常重要。
3. img_key和sub_key不正确或过期
img_key和sub_key是生成签名的关键参数,它们通常每日更替。如果使用了过期的密钥或错误地从图片URL中提取密钥,会导致签名验证失败。
4. 参数排序和编码错误
在生成签名前,需要对参数按key进行升序排序,并正确编码特殊字符。特别是中文和空格等字符,必须使用UTF-8编码,且空格应编码为%20而非+。
5. mixin_key生成错误
mixin_key的生成需要特定的字符重排算法,如果重排映射表或截取长度不正确,会导致最终签名错误。
解决方法与最佳实践
1. 正确获取和缓存密钥
应从nav接口或bili_ticket接口获取最新的img_key和sub_key,并实现合理的缓存机制。
def getWbiKeys() -> tuple[str, str]:
'获取最新的 img_key 和 sub_key'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Referer': 'https://www.bilibili.com/'
}
resp = requests.get('https://api.bilibili.com/x/web-interface/nav', headers=headers)
resp.raise_for_status()
json_content = resp.json()
img_url: str = json_content['data']['wbi_img']['img_url']
sub_url: str = json_content['data']['wbi_img']['sub_url']
img_key = img_url.rsplit('/', 1)[1].split('.')[0]
sub_key = sub_url.rsplit('/', 1)[1].split('.')[0]
return img_key, sub_key
2. 正确实现签名生成算法
确保严格按照文档实现参数排序、编码和mixin_key生成。以下是Python实现示例:
def encWbi(params: dict, img_key: str, sub_key: str):
'为请求参数进行 wbi 签名'
mixin_key = getMixinKey(img_key + sub_key)
curr_time = round(time.time())
params['wts'] = curr_time # 添加 wts 字段
params = dict(sorted(params.items())) # 按照 key 重排参数
# 过滤 value 中的 "!'()*" 字符
params = {
k : ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
for k, v
in params.items()
}
query = urllib.parse.urlencode(params) # 序列化参数
wbi_sign = md5((query + mixin_key).encode()).hexdigest() # 计算 w_rid
params['w_rid'] = wbi_sign
return params
3. 处理特殊字符编码
确保对参数值进行正确的URL编码,特别是中文和特殊符号:
const value = params[key].toString().replace(chr_filter, '')
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
4. 定期更新签名实现
B站API可能会不定期更新签名算法,建议关注官方文档的更新,并定期检查你的实现是否仍然有效。
5. 使用现成的签名库
如果可能,尽量使用经过验证的第三方库或官方SDK,以减少手动实现带来的错误。项目中提供了多种语言的签名实现示例,包括Python、JavaScript、Golang等。
常见问题排查步骤
- 检查是否正确添加了
w_rid和wts参数 - 验证时间戳是否与当前时间同步
- 确认使用了最新的
img_key和sub_key - 检查参数排序和编码是否符合要求
- 验证
mixin_key生成过程是否正确 - 对比官方示例,检查签名生成结果是否一致
总结
WBI签名验证虽然增加了API调用的复杂度,但通过正确理解签名机制、严格按照规范实现,并遵循最佳实践,可以有效避免验证失败的问题。如果遇到复杂问题,建议参考项目中的详细文档或寻求社区支持。
记住,API签名机制的目的是为了保护API的安全使用,正确实现签名不仅能避免调用失败,也是良好开发实践的重要组成部分。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





