Python持久化TCP连接HTTP服务器页面加载转圈问题排查
问题:持久化TCP连接的HTTP服务器导致浏览器加载圆圈持续转动
我尝试构建一个基于持久化TCP连接(Persistent TCP Connections)的简单HTTP Web服务器,用于提供单个文件(index.html)。目标是让浏览器通过同一个TCP套接字发送多个HTTP请求(同一时间仅使用一个套接字),编写的代码如下:
from socket import * import sys serverPort = int(sys.argv[1]) serverSocket = socket(AF_INET, SOCK_STREAM) serverSocket.bind(("localhost", serverPort)) serverSocket.listen(1) print("Listening on port " + str(serverPort) + "...") while True: connectionSocket, addr = serverSocket.accept() while True: request = connectionSocket.recv(4096) if not request: print("BROKEN") break request = request.decode() headers = request.split("\n") requestedFile = headers[0].split(" ")[1] if (requestedFile[0] == "/"): requestedFile = requestedFile[1:] fileInput = open(requestedFile) content = fileInput.read() fileInput.close() response = "HTTP/1.1 200 OK\r\n" + "Connection: Keep-Alive\r\n\r\n" + content connectionSocket.send(response.encode()) connectionSocket.close()
运行后现象:在1000端口启动服务器,用Microsoft Edge访问http://localhost:1000/index.html时,HTML页面正常显示,浏览器网络面板无异常,但标签页的加载圆圈一直转动,仿佛内容未加载完成。
原因及解决方法
核心原因:缺少Content-Length响应头
HTTP/1.1的持久连接模式下,浏览器需要明确的响应长度标记来判断当前请求的响应是否完全接收。你的响应仅设置了Connection: Keep-Alive,但没有告知浏览器响应内容的字节大小,导致浏览器无法确定是否还有后续数据,因此一直维持加载状态。
修复方案
修改响应头,添加Content-Length字段,值为响应内容的字节长度:
from socket import * import sys serverPort = int(sys.argv[1]) serverSocket = socket(AF_INET, SOCK_STREAM) serverSocket.bind(("localhost", serverPort)) serverSocket.listen(1) print("Listening on port " + str(serverPort) + "...") while True: connectionSocket, addr = serverSocket.accept() while True: request = connectionSocket.recv(4096) if not request: print("BROKEN") break request = request.decode() headers = request.split("\n") requestedFile = headers[0].split(" ")[1] if requestedFile[0] == "/": requestedFile = requestedFile[1:] # 增加异常处理,避免文件不存在崩溃 try: with open(requestedFile, 'r') as fileInput: content = fileInput.read() content_bytes = content.encode() # 构造包含Content-Length的响应 response_header = ( "HTTP/1.1 200 OK\r\n" "Connection: Keep-Alive\r\n" f"Content-Length: {len(content_bytes)}\r\n\r\n" ).encode() connectionSocket.send(response_header + content_bytes) except FileNotFoundError: # 处理文件不存在的情况 error_response = "HTTP/1.1 404 Not Found\r\nConnection: Keep-Alive\r\nContent-Length: 13\r\n\r\nFile Not Found".encode() connectionSocket.send(error_response) connectionSocket.close()
额外注意事项
- 必须添加异常处理:原代码中如果请求的文件不存在,会直接抛出异常导致服务器崩溃,上面的修复版本增加了
try-except块处理这种情况。 - 处理不完整请求:
recv(4096)可能只拿到部分HTTP请求(比如大请求分多次发送),需要循环读取直到拿到完整的请求头(以\r\n\r\n为结束标记),否则解析请求行时会出错。
内容的提问来源于stack exchange,提问作者i'mlearningtocode
相关产品推荐
相关产品推荐

