URL 解码和反序列化失败
URL decode and deserialization fails
我使用 Protocol Buffer 序列化数据并通过将其作为参数添加到发送到 Flask 的 HTTP GET 请求来传输它。数据的反序列化有时会失败,具体取决于参数的内容(例如,如果 url 参数包含“%F0”)。
我尝试为 encoding/decoding 使用不同的字符集,还尝试将适当的 header 添加到请求设置 content-type 到 application/x-protobuf。
这是 flask 处理传入 GET 请求的代码。
def _ai_request_stub(min_params: List[str], on_parameter_available: Callable[[], Response]) -> Response:
"""
This stub is designed for GET requests.
"""
from flask import request
missing_params = list(filter(lambda p: p not in request.args, min_params))
if missing_params:
return Response(response="The request misses one of the parameters [\"" + "\", ".join(missing_params) + "\"]",
status=400, mimetype="text/plain")
else:
return on_parameter_available()
@app.route("/ai/control", methods=["GET"])
def control():
def do() -> Response:
from aiExchangeMessages_pb2 import Control
from flask import request
control_msg = Control()
control_msg.ParseFromString(request.args["control"].encode())
return Response(response="Fine", status=200, mimetype="application/x-protobuf")
return _ai_request_stub(["control"], do)
这是创建和发送 GET 请求的代码。
class AIExchangeService:
from aiExchangeMessages_pb2 import SimStateResponse, DataRequest, DataResponse, Control, Void, AiID
from typing import Dict, AnyStr, Any
def __init__(self, host: str, port: int):
self.host = host
self.port = port
[...]
def _do_get_request(self, address: str, params: Dict[str, AnyStr]) -> HTTPResponse:
"""
:return: The response object of the request
"""
from urllib.parse import urlencode
from http.client import HTTPConnection
connection = HTTPConnection(host=self.host, port=self.port)
print(params)
connection.request("GET", address + "?" + urlencode(params),
headers={"content-type": "application/x-protobuf; charset=utf-8"})
return connection.getresponse()
def control(self, commands: Control) -> Void:
response = self._do_get_request("/ai/control", {"control": commands.SerializeToString()})
if response.status == 200:
print("Controlled")
else:
print(response.status)
print(response.reason)
[...]
这是显示控件结构的 protobuffer 代码 object。
message AiID {
[...]
}
message Control {
message AvCommand {
double accelerate = 1;
double steer = 2;
double brake = 3;
}
enum SimCommand {
RESUME = 0;
FAIL = 1;
CANCEL = 2;
}
AiID aid = 1;
oneof command {
AvCommand avCommand = 2;
SimCommand simCommand = 3;
}
}
方法 control(...)
的第二个片段中的调用 commands.SerializeToString()
产生 b'\n\x13\n\n\n\x08fancySid\x12\x05\n\x03ego\x12\t\t\x00\x00\x00\x00\x00\x00\xf0?'
。在方法 _do_get_request(...)
的第二个片段中对 address + "?" + urlencode(params)
的评估产生了输出 /ai/control?control=%0A%13%0A%0A%0A%08fancySid%12%05%0A%03ego%12%09%09%00%00%00%00%00%00%F0%3F
,它似乎是相同的但 url 编码。
在方法 control()
的第一个片段中将此 GET 请求发送到 flask request.args["control"]
时会产生 '\n\x13\n\n\n\x08fancySid\x12\x05\n\x03ego\x12\t\t\x00\x00\x00\x00\x00\x00�?'
,这不再是相同的序列化字符串。尝试反序列化此字符串失败并出现错误 google.protobuf.message.DecodeError: Error parsing message
.
如何让flask正确读取参数?
GET 请求不是为了传送大量原始二进制数据而发出的。相反,必须使用 POST 请求。
事实上,post 请求工作得很好。
我使用 Protocol Buffer 序列化数据并通过将其作为参数添加到发送到 Flask 的 HTTP GET 请求来传输它。数据的反序列化有时会失败,具体取决于参数的内容(例如,如果 url 参数包含“%F0”)。
我尝试为 encoding/decoding 使用不同的字符集,还尝试将适当的 header 添加到请求设置 content-type 到 application/x-protobuf。
这是 flask 处理传入 GET 请求的代码。
def _ai_request_stub(min_params: List[str], on_parameter_available: Callable[[], Response]) -> Response:
"""
This stub is designed for GET requests.
"""
from flask import request
missing_params = list(filter(lambda p: p not in request.args, min_params))
if missing_params:
return Response(response="The request misses one of the parameters [\"" + "\", ".join(missing_params) + "\"]",
status=400, mimetype="text/plain")
else:
return on_parameter_available()
@app.route("/ai/control", methods=["GET"])
def control():
def do() -> Response:
from aiExchangeMessages_pb2 import Control
from flask import request
control_msg = Control()
control_msg.ParseFromString(request.args["control"].encode())
return Response(response="Fine", status=200, mimetype="application/x-protobuf")
return _ai_request_stub(["control"], do)
这是创建和发送 GET 请求的代码。
class AIExchangeService:
from aiExchangeMessages_pb2 import SimStateResponse, DataRequest, DataResponse, Control, Void, AiID
from typing import Dict, AnyStr, Any
def __init__(self, host: str, port: int):
self.host = host
self.port = port
[...]
def _do_get_request(self, address: str, params: Dict[str, AnyStr]) -> HTTPResponse:
"""
:return: The response object of the request
"""
from urllib.parse import urlencode
from http.client import HTTPConnection
connection = HTTPConnection(host=self.host, port=self.port)
print(params)
connection.request("GET", address + "?" + urlencode(params),
headers={"content-type": "application/x-protobuf; charset=utf-8"})
return connection.getresponse()
def control(self, commands: Control) -> Void:
response = self._do_get_request("/ai/control", {"control": commands.SerializeToString()})
if response.status == 200:
print("Controlled")
else:
print(response.status)
print(response.reason)
[...]
这是显示控件结构的 protobuffer 代码 object。
message AiID {
[...]
}
message Control {
message AvCommand {
double accelerate = 1;
double steer = 2;
double brake = 3;
}
enum SimCommand {
RESUME = 0;
FAIL = 1;
CANCEL = 2;
}
AiID aid = 1;
oneof command {
AvCommand avCommand = 2;
SimCommand simCommand = 3;
}
}
方法 control(...)
的第二个片段中的调用 commands.SerializeToString()
产生 b'\n\x13\n\n\n\x08fancySid\x12\x05\n\x03ego\x12\t\t\x00\x00\x00\x00\x00\x00\xf0?'
。在方法 _do_get_request(...)
的第二个片段中对 address + "?" + urlencode(params)
的评估产生了输出 /ai/control?control=%0A%13%0A%0A%0A%08fancySid%12%05%0A%03ego%12%09%09%00%00%00%00%00%00%F0%3F
,它似乎是相同的但 url 编码。
在方法 control()
的第一个片段中将此 GET 请求发送到 flask request.args["control"]
时会产生 '\n\x13\n\n\n\x08fancySid\x12\x05\n\x03ego\x12\t\t\x00\x00\x00\x00\x00\x00�?'
,这不再是相同的序列化字符串。尝试反序列化此字符串失败并出现错误 google.protobuf.message.DecodeError: Error parsing message
.
如何让flask正确读取参数?
GET 请求不是为了传送大量原始二进制数据而发出的。相反,必须使用 POST 请求。 事实上,post 请求工作得很好。