Python3中urllib.request.Request搭配BaseHTTPRequestHandler总是超时问题
问题原因分析
问题来自两处不符合HTTP协议规范的处理逻辑:
- 服务端未读取POST请求的请求体:当POST请求携带
Content-Length头时,HTTP协议要求服务端必须完整读取对应长度的请求体数据,否则TCP连接缓冲区存在未消费数据,连接无法进入响应完成状态。 - 响应未携带长度标识:当前服务端仅返回200状态码和空响应头,没有通过
Content-Length头告知客户端响应体的总长度,客户端无法判断响应是否已经完全传输,会持续等待直到触发超时阈值,所以会出现“已经收到响应但仍然触发超时”的现象。
修复方案
服务端修改
补充请求体读取逻辑,同时明确指定响应的Content-Length头:
from http.server import HTTPServer, BaseHTTPRequestHandler class SampleHTTPRequestHandler(BaseHTTPRequestHandler): def do_POST(self): # 读取完整请求体,避免TCP连接卡住 content_length = int(self.headers.get('Content-Length', 0)) if content_length > 0: self.rfile.read(content_length) print('Posted!') self.send_response(200) # 明确指定响应体长度为0,客户端可以直接判断响应结束 self.send_header('Content-Length', '0') self.end_headers() httpd = HTTPServer(('localhost', 8000), SampleHTTPRequestHandler) httpd.serve_forever()
客户端修改
补充datetime导入,同时主动读取响应内容、使用上下文管理器自动释放连接:
import urllib import urllib.request from datetime import datetime req = urllib.request.Request(url='http://localhost:8000', method='POST') t0 = datetime.now() # 用with上下文自动管理连接生命周期 with urllib.request.urlopen(req, timeout=2) as reader: # 读取响应内容,即使是空内容也要读取,确保连接状态正常 reader.read() print('Received', datetime.now() - t0)
多请求场景优化
顺序发送多个POST请求时,只要沿用上述修复后的逻辑,每次请求都完成请求体读取、合法响应头返回、响应体读取的完整流程,就不会出现超时卡顿问题。如果有更高性能要求,可以使用第三方HTTP库自带的连接池能力,减少TCP重复握手的开销。
内容的提问来源于stack exchange,提问作者Jason M
相关产品推荐
相关产品推荐

