如何在Python中以Protobuf文本为参数发送HTTP POST请求?
解决Protobuf作为HTTP请求参数的问题
你现在的核心问题是:直接把Python字典传给requests.post的data参数,requests会默认把它编码成表单数据,而服务器需要的是Protobuf二进制序列化后的字节流,这完全是两种不同的格式,所以请求肯定无法被正确解析。
要正确发送Protobuf请求,你需要遵循以下步骤:
1. 定义Protobuf消息结构(.proto文件)
Protobuf是强类型的序列化协议,必须先有对应的消息定义才能生成可序列化的代码。根据你从Charles复制的Protobuf文本1 { 1: "2345654456765" },我们可以推测出大致的嵌套消息结构:
syntax = "proto3"; // 内层消息,对应你文本里的内部{} message AuthInfo { string account = 1; // 字段编号1,对应值"2345654456765" } // 外层请求消息,对应最外层的1 {} message LoginRequest { AuthInfo auth_data = 1; // 外层字段编号1,值是内层消息 }
如果你的文本实际是非嵌套结构(只是1: "2345654456765"),那结构更简单:
syntax = "proto3"; message LoginRequest { string account = 1; }
2. 编译.proto文件生成Python代码
使用Protobuf官方的protoc编译器,把上面的.proto文件编译成Python模块:
protoc --python_out=. login.proto
执行后会生成login_pb2.py文件,这就是我们要在Python里导入的Protobuf操作模块。
3. 序列化消息并发送HTTP请求
现在可以用生成的模块创建消息对象,填充数据后序列化成二进制,再传给requests:
import requests # 导入编译后的Protobuf模块 import login_pb2 # 创建请求消息对象 login_request = login_pb2.LoginRequest() # 如果是嵌套结构,给内层字段赋值 login_request.auth_data.account = "2345654456765" # 如果是非嵌套结构,直接赋值:login_request.account = "2345654456765" # 把消息序列化成二进制字节流 protobuf_binary = login_request.SerializeToString() # 设置请求头,重点要加上Protobuf的Content-Type headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4181.9 Safari/537.36', 'platform': 'web', 'Content-Type': 'application/x-protobuf' # 必须告诉服务器你发的是Protobuf格式 } # 发送POST请求,把二进制数据传给data参数 response = requests.post( 'https://api.website.com/version/auth/login?locale=en', data=protobuf_binary, headers=headers ) print(response.content)
关键注意事项
- Content-Type必须正确:大部分服务器会要求
application/x-protobuf或者application/protobuf,如果请求失败,可以尝试调整这个值。 - 必须有正确的.proto定义:如果你的Protobuf文本结构更复杂,或者你不确定字段含义,最好能拿到服务器端的
.proto文件,否则可能会因为字段不匹配导致请求失败。 - 不要用字典传参:直接传字典会被requests当成表单数据编码,这和Protobuf的二进制格式完全不兼容。
内容的提问来源于stack exchange,提问作者DeviL
相关产品推荐
相关产品推荐

