使用Python Socket获取HTTP请求响应体失败的问题排查
问题:使用socket模块获取Flask应用的GET响应仅得到响应头,无法获取响应体
我尝试使用socket模块获取GET请求的响应体,但即使设置了较大的缓冲区大小,也仅能获取到响应头。我访问的Web应用是自己使用Flask搭建的。
sockets.py
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5000)) s.sendall(b'GET / HTTP/1.1\r\nHost:127.0.0.1\r\n\r\n') print(s.recv(4096).decode('utf-8'))
app.py
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def main(): return render_template('main.html')
main.html
<html> <body> <h1>Hello world</h1> </body> </html>
执行sockets.py后得到的结果如下:
HTTP/1.1 200 OK Server: Werkzeug/2.1.2 Python/3.10.5 Date: Sun, 07 Aug 2022 18:33:53 GMT Content-Type: text/html; charset=utf-8 Content-Length: 66 Connection: close
如你所见,我没有获取到响应体。请问我哪里操作出错了?
解决方法
你的问题出在只调用了一次s.recv()。TCP是流式协议,数据不会保证一次性全部到达,哪怕你设置了足够大的缓冲区,服务器可能分批次发送数据,第一次recv可能只接收到了响应头部分,剩下的响应体还在传输通道中。
从响应头的Content-Length: 66可以看到,响应体的长度是66字节,你可以通过循环调用recv来获取完整的响应内容。
方法一:循环接收直到数据传输完成
修改后的sockets.py代码如下:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5000)) s.sendall(b'GET / HTTP/1.1\r\nHost:127.0.0.1\r\n\r\n') # 循环接收所有数据 full_response = b'' while True: chunk = s.recv(4096) if not chunk: # 连接关闭时,recv返回空字节串 break full_response += chunk # 解码并输出完整响应 print(full_response.decode('utf-8'))
方法二:解析响应头后精确接收响应体
如果需要更严谨地处理,可以先解析响应头拿到Content-Length,再精确读取对应长度的响应体:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 5000)) s.sendall(b'GET / HTTP/1.1\r\nHost:127.0.0.1\r\n\r\n') # 先接收完整的响应头(直到\r\n\r\n分隔符) response_header = b'' while b'\r\n\r\n' not in response_header: response_header += s.recv(1) # 解析Content-Length的值 header_content = response_header.decode('utf-8') content_length = int([line for line in header_content.split('\r\n') if line.startswith('Content-Length')][0].split(': ')[1]) # 接收指定长度的响应体 response_body = s.recv(content_length) # 输出完整的响应内容 print(header_content + response_body.decode('utf-8'))
这两种方式都能获取到包含响应体的完整HTTP响应。核心原因是必须通过循环调用recv来处理TCP流式数据的分批传输问题,不能依赖单次recv获取全部内容。
内容的提问来源于stack exchange,提问作者Vitalyk Chernysh
相关产品推荐
相关产品推荐

