Python HTTP服务器触发UnicodeDecodeError编码错误求助
问题描述
我编写了如下Python HTTP服务器代码:
import socket import os import mimetypes import threading content_types={ '.html': 'text/html', '.css': 'text/css', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.txt': 'text/plain' } HTTP_METHODS = { 'GET', 'POST', 'PUT', 'DELETE' } def handle_request(client): request = client.recv(1024).decode('utf-8') lines = request.split("\r\n") request_line = lines[0].split(" ") method = request_line[0] path = request_line[1] if method == 'GET': handle_get(client,path) elif method == 'POST': content = lines[-1] handle_post(client,path,content.encode()) elif method == 'PUT': content = lines[-1] handle_put(client,path,content.encode()) elif method == 'DELETE': handle_delete(client,path) else: response = 'HTTP/1.0 400 Bad Request\n\nUnsupported HTTP method' client.sendall(response.encode()) client.close() def handle_delete(client_socket, path): # Delete the requested file os.remove(path) # Send a 200 OK response response_headers = 'HTTP/1.1 200 OK\r\n\r\n' client_socket.send(response_headers.encode()) client.close() def run_server(): server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server_socket.bind(('localhost', 8189)) server_socket.listen(1) print("The server will start on port 8189 ") while True : client, adress = server_socket.accept() handle_request(client) run_server()
当我发起任意类型的请求时,都会收到以下错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf7 in position 4: invalid start byte
目前我还未实现handle_get和handle_put函数,但不清楚编码解码环节的问题出在哪里,希望得到帮助。
问题分析与解决
核心问题
错误根源在request = client.recv(1024).decode('utf-8')这一行:
- HTTP请求的头部是ASCII兼容UTF-8的,但**请求体(body)**可能包含非UTF-8的二进制数据(比如文件上传、字节流),直接解码整个请求会触发错误。
recv(1024)仅读取部分请求数据,拆分\r\n时可能得到不完整的行,进一步引发后续处理异常。- 分支逻辑存在漏洞:当调用GET/POST/PUT/DELETE的处理函数后,依然会执行
client.sendall(response.encode())和client.close(),导致连接被重复关闭。
修复步骤
拆分头部与请求体的读取逻辑
HTTP请求头部和体之间用\r\n\r\n分隔,先读取完整头部再按需处理体:def handle_request(client): # 读取完整请求头部,直到\r\n\r\n分隔符 request_data = b'' while b'\r\n\r\n' not in request_data: chunk = client.recv(1024) if not chunk: break request_data += chunk # 拆分头部和请求体 header_part, *body_parts = request_data.split(b'\r\n\r\n', 1) request_header = header_part.decode('utf-8') request_body = b''.join(body_parts) if body_parts else b'' lines = request_header.split("\r\n") request_line = lines[0].split(" ") method = request_line[0] path = request_line[1]修正分支逻辑的重复关闭问题
让各请求方法的处理函数自行负责响应和关闭连接,避免重复操作:response = None if method == 'GET': handle_get(client, path) return elif method == 'POST': handle_post(client, path, request_body) return elif method == 'PUT': handle_put(client, path, request_body) return elif method == 'DELETE': handle_delete(client, path) return else: response = 'HTTP/1.0 400 Bad Request\r\n\r\nUnsupported HTTP method' if response: client.sendall(response.encode('utf-8')) client.close()修复
handle_delete的错误
修正连接关闭的变量名,同时处理文件不存在的异常:def handle_delete(client_socket, path): try: # 去掉路径开头的/,避免绝对路径风险 os.remove(path.lstrip('/')) response_headers = 'HTTP/1.1 200 OK\r\n\r\n' client_socket.send(response_headers.encode('utf-8')) except FileNotFoundError: response = 'HTTP/1.1 404 Not Found\r\n\r\nFile not exists' client_socket.send(response.encode('utf-8')) finally: client_socket.close()
额外建议
- HTTP响应头必须用
\r\n换行,原代码中的\n要统一替换成\r\n,避免客户端解析异常。 - 实现
handle_get时,需以二进制模式读取文件,根据后缀从content_types中匹配正确的Content-Type,再发送响应头和文件内容。
内容的提问来源于stack exchange,提问作者houssamsolh
相关产品推荐
相关产品推荐

