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

使用Raw Socket获取Multipart/Form-Data遇UTF-8解码错误求助

解决Raw Socket处理multipart/form-data时的UnicodeDecodeError问题

这个问题我之前也碰到过!核心原因很简单:当表单包含文件上传字段时,整个请求体是文本和二进制数据的混合体——文本字段(比如username、password)是UTF-8编码的,但文件内容是原始二进制(比如PNG的开头字节0x89就不是合法的UTF-8字符),直接把整个字节流用decode('utf-8')转成字符串肯定会报错。

下面给你一步步的解决方案:

1. 先保留原始字节数据,不要立刻解码

把你原来的代码:

request = conn.recv(10240).decode()

改成:

raw_data = conn.recv(10240)  # 保留字节类型,不急于解码

注意:实际生产环境中,一次recv可能无法获取完整的请求体,需要循环接收直到读取完所有数据(可以通过Content-Length头判断总长度)。

2. 从请求头中提取multipart的边界标识(boundary)

multipart/form-data的请求头里会包含一个boundary参数,用来分隔不同的表单字段。我们需要先解析这个边界:

# 分割请求头和请求体(用\r\n\r\n作为分隔符)
header_part, body_part = raw_data.split(b'\r\n\r\n', 1)

# 解析请求头,提取boundary
boundary = None
headers = header_part.decode('utf-8').split('\r\n')
for header in headers:
    if header.startswith('Content-Type: multipart/form-data'):
        # 提取boundary字符串,转成字节类型
        boundary_str = header.split('boundary=')[1]
        boundary = b'--' + boundary_str.encode('utf-8')
        break

3. 按边界分割各个表单字段,分别处理文本和文件

拿到boundary后,就可以把请求体分割成一个个独立的字段部分,然后针对文本字段和文件字段做不同处理:

import re

# 分割请求体为各个字段部分
parts = body_part.split(boundary)
for part in parts:
    if not part.strip():  # 跳过空的分割部分
        continue
    
    # 分割每个字段的头部和内容
    part_header, part_content = part.split(b'\r\n\r\n', 1)
    # 去掉内容末尾多余的\r\n和--标记
    part_content = part_content.rstrip(b'\r\n--')
    
    # 解析字段头部,判断是文本还是文件
    part_header_str = part_header.decode('utf-8')
    if 'filename=' in part_header_str:
        # 这是文件字段,直接处理二进制内容
        filename_match = re.search(r'filename="(.+)"', part_header_str)
        if filename_match:
            filename = filename_match.group(1)
            # 保存文件到本地
            with open(filename, 'wb') as f:
                f.write(part_content)
            print(f"成功保存文件: {filename}")
    else:
        # 这是文本字段,解码成字符串
        name_match = re.search(r'name="(.+)"', part_header_str)
        if name_match:
            field_name = name_match.group(1)
            field_value = part_content.decode('utf-8').strip()
            print(f"{field_name}: {field_value}")

关键注意事项

  • 处理大文件时,不要一次性把整个请求体加载到内存,应该分块接收并写入文件;
  • 不同浏览器生成的boundary格式可能略有差异,但核心逻辑都是通过--boundary来分隔字段;
  • 要注意请求头中的Content-Length,确保接收完所有的请求数据,避免解析不完整。

内容的提问来源于stack exchange,提问作者Milan Vjestica

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:50:16