You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(),导致连接被重复关闭。

修复步骤

  1. 拆分头部与请求体的读取逻辑
    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]
    
  2. 修正分支逻辑的重复关闭问题
    让各请求方法的处理函数自行负责响应和关闭连接,避免重复操作:

    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()
    
  3. 修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:37:02