HTTP请求Chunked分块传输原理、发送方式及Python实现咨询
HTTP分块(Chunked)传输机制解析
核心原理澄清
分块传输不是基于Keep-Alive的多个HTTP请求,它是同一个HTTP请求内的连续数据流。当请求头设置Transfer-Encoding: chunked后,整个请求/响应体被拆分成多个"块"依次发送:
- 每个块的结构为「十六进制的块长度 +
\r\n+ 块内容 +\r\n」 - 最后用「
0\r\n\r\n」标记整个传输结束
你设想的发送方式是错误的——拆分的块必须属于同一个HTTP请求,不能拆成多个独立HTTP请求发送。每个HTTP请求有自己的请求头和边界,分块是在单个请求的体内部做的拆分。
正确格式示例
你看到的标准示例是合规的,格式拆解如下:
4\r\n # 十六进制4,对应4字节数据 Wiki\r\n # 实际数据("Wiki"刚好4字节) 6\r\n # 十六进制6,对应6字节数据 pedia \r\n # 实际数据("pedia "是6字节) E\r\n # 十六进制E=14,对应14字节数据 in \r\n\r\nchunks.\r\n # 实际数据,长度刚好14字节 0\r\n\r\n # 结束标记,0表示无后续块,最后两个\r\n是结束分隔
Python实现示例
服务端(接收分块请求)
用原生socket实现,手动解析分块数据:
import socket def handle_chunked_data(conn): # 读取请求头,直到空行 headers = b"" while b"\r\n\r\n" not in headers: headers += conn.recv(1024) # 检查是否启用分块传输 if b"Transfer-Encoding: chunked" not in headers: conn.send(b"HTTP/1.1 400 Bad Request\r\n\r\nNeed chunked encoding") return # 解析分块数据 body = b"" while True: # 读取块长度行 chunk_len_line = b"" while b"\r\n" not in chunk_len_line: chunk_len_line += conn.recv(1) chunk_len = int(chunk_len_line.strip(), 16) if chunk_len == 0: # 读取结束的空行 conn.recv(2) break # 读取块内容和后续的\r\n chunk_data = conn.recv(chunk_len) conn.recv(2) body += chunk_data # 返回响应 response = f"HTTP/1.1 200 OK\r\nContent-Length: {len(body)}\r\n\r\nReceived data: {body.decode()}" conn.send(response.encode()) conn.close() # 启动服务 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(("localhost", 8080)) server_socket.listen(1) print("Server listening on port 8080...") while True: conn, addr = server_socket.accept() handle_chunked_data(conn)
客户端(发送分块请求)
模拟发送分块数据:
import socket def send_chunked_request(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("localhost", 8080)) # 构造请求头 request_headers = ( "POST /test HTTP/1.1\r\n" "Host: localhost:8080\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" ) sock.send(request_headers.encode()) # 依次发送各个块 sock.send(b"4\r\nWiki\r\n") sock.send(b"6\r\npedia \r\n") sock.send(b"E\r\nin \r\n\r\nchunks.\r\n") # 发送结束块 sock.send(b"0\r\n\r\n") # 接收并打印响应 response = sock.recv(4096) print(response.decode()) sock.close() if __name__ == "__main__": send_chunked_request()
内容的提问来源于stack exchange,提问作者brian
相关产品推荐
相关产品推荐

