Python FastAPI处理URL编码SHA1格式info_hash的异常问题排查
解决FastAPI解析BitTorrent info_hash字段的问题
问题原因
BitTorrent的info_hash是20字节的SHA1原始二进制值,URL编码后会包含大量非UTF-8兼容的字节。FastAPI默认会按照UTF-8编码自动解码URL查询参数,遇到无效UTF-8字节时,会用Unicode替换字符�(对应字节\xef\xbf\xbd)替代,导致原始的info_hash数据损坏:
- 用
str类型接收时,得到的是乱码字符串; - 用
bytes类型接收时,FastAPI会先将损坏的字符串转回字节,最终得到的是包含大量\xef\xbf\xbd的错误数组。
修复方法
方法1:直接读取原始查询参数
绕过FastAPI的自动解码,直接获取URL的原始编码查询字符串,自行解析info_hash:
from fastapi import FastAPI, Request from urllib.parse import parse_qs app = FastAPI() @app.get("/announce") async def handle_announce(request: Request): # 获取原始URL编码的查询参数 raw_query = request.query_params._urlencoded # 解析原始字节形式的查询参数 parsed_params = parse_qs(raw_query) # 提取info_hash(确保取第一个值) info_hash = parsed_params.get(b"info_hash", [b""])[0] # 验证:转成十六进制字符串查看是否正确 return {"info_hash_hex": info_hash.hex()}
方法2:使用自定义依赖项封装逻辑
如果多个路由需要处理info_hash,可以封装成依赖项复用:
from fastapi import FastAPI, Request, Depends from urllib.parse import parse_qs app = FastAPI() def get_info_hash(request: Request) -> bytes: raw_query = request.query_params._urlencoded parsed_params = parse_qs(raw_query) return parsed_params.get(b"info_hash", [b""])[0] @app.get("/announce") async def handle_announce(info_hash: bytes = Depends(get_info_hash)): return {"info_hash_hex": info_hash.hex()}
注意事项
- 如果同时支持POST请求(部分BT客户端会用POST提交宣告请求),需要额外处理请求体的原始数据,类似
raw_query = await request.body(); - 解析后得到的
info_hash是20字节的原始二进制数据,如需对外展示或存储,建议转成十六进制字符串(如示例中的.hex()方法)。
内容的提问来源于stack exchange,提问作者Steven Venham
相关产品推荐
相关产品推荐

