Python requests库向RPi Pico W发送数据时常为空的原因咨询
RPi Pico W Web服务器无法接收Python requests请求数据的问题
问题描述
在RPi Pico W上运行简易Web服务器,可通过浏览器、cURL正常接收数据并返回JSON,但使用Python requests库发送PUT请求时,多数情况下数据无法传递到服务器。
请求代码
import json import requests data = json.dumps({"KEY":"VALUE"}) res = requests.put("http://webserver.ip:port", data=data) print(res.json())
(注:尝试改用json={"KEY":"VALUE"}参数,问题仍存在)
Pico W服务器代码
i = 0 while True: client = conn.accept()[0] print(f"[{i}] Client connected: {client}") msg = client.recv(8192) print(f"Message: {msg}") data = msg.decode("utf-8").split("\r")[-1].strip() print(f'Data: {data}, {type(data)}, {data == ""}') message = { "data": ujson.loads(data) if data != "" else None, "key1": "value1", "key2": "value2", "key3": "value3", } client.send(b"HTTP/1.1 200 OK\n") client.send(b"Content-Type: application/json\n") client.send(b"Connection: keep-alive\n\n") client.sendall(ujson.dumps(message).encode("utf-8")) client.close() i += 1
预期返回
{"key1": "value1", "key2": "value2", "key3": "value3", "data": {"KEY":"VALUE"}}
实际返回
{"key1": "value1", "key2": "value2", "key3": "value3", "data": None}
问题原因
- 请求接收不完整:
client.recv(8192)仅尝试一次读取数据,但requests发送的请求可能因TCP缓冲机制被拆分为多个数据包,第一次recv仅获取到请求头,未拿到body内容。而curl/浏览器的请求可能刚好一次性完成传输,因此能正常解析。 - HTTP请求解析错误:代码通过
split("\r")[-1]提取body的方式完全不符合HTTP协议规范。HTTP请求的body是位于请求头与body分隔符\r\n\r\n之后的内容,而非简单分割\r的最后一项。 - 未处理分块编码:requests默认可能使用
Transfer-Encoding: chunked发送请求(尤其是当请求体较大时),而当前服务器代码完全未处理这种编码格式,导致无法正确读取body。
解决办法
1. 正确解析HTTP请求,读取完整body
修改服务器代码,严格按照HTTP协议规范解析请求头与body:
import ujson i = 0 while True: client = conn.accept()[0] print(f"[{i}] Client connected: {client}") # 循环接收直到拿到完整的请求头(找到分隔符) full_request = b"" while b"\r\n\r\n" not in full_request: chunk = client.recv(1024) if not chunk: break full_request += chunk # 分割请求头和body if b"\r\n\r\n" not in full_request: # 无效请求,直接返回 client.send(b"HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n") client.close() i += 1 continue header_part, body_part = full_request.split(b"\r\n\r\n", 1) header_str = header_part.decode("utf-8") # 处理body内容 body = b"" if "Transfer-Encoding: chunked" in header_str: # 解析分块编码内容 while b"0\r\n\r\n" not in body_part: chunk = client.recv(1024) if not chunk: break body_part += chunk chunks = body_part.split(b"\r\n") for idx in range(0, len(chunks)-2, 2): chunk_len = int(chunks[idx], 16) if chunk_len > 0: body += chunks[idx+1][:chunk_len] else: # 按Content-Length读取完整body content_length = 0 for line in header_str.split("\r\n"): if line.startswith("Content-Length:"): content_length = int(line.split(":")[1].strip()) break # 补充读取剩余的body内容 while len(body_part) < content_length: chunk = client.recv(1024) if not chunk: break body_part += chunk body = body_part[:content_length] # 解析JSON数据 data_str = body.decode("utf-8").strip() print(f'Data: {data_str}, {type(data_str)}, {data_str == ""}') message = { "data": ujson.loads(data_str) if data_str != "" else None, "key1": "value1", "key2": "value2", "key3": "value3", } # 发送响应(改用标准HTTP换行符\r\n,关闭连接避免复用问题) client.send(b"HTTP/1.1 200 OK\r\n") client.send(b"Content-Type: application/json\r\n") client.send(b"Connection: close\r\n\r\n") client.sendall(ujson.dumps(message).encode("utf-8")) client.close() i += 1
2. 临时简化请求发送(可选)
如果暂时不想修改服务器代码,可以强制requests使用Content-Length而非分块编码,减少请求拆分概率:
import requests headers = {"Transfer-Encoding": "identity"} res = requests.put("http://webserver.ip:port", json={"KEY":"VALUE"}, headers=headers) print(res.json())
(注:此方法仅为临时 workaround,建议优先修改服务器代码以符合HTTP规范)
内容的提问来源于stack exchange,提问作者Parsia Hedayat
相关产品推荐
相关产品推荐

