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

如何仅用urllib.request发送含请求头、字段及文件的POST请求?

仅使用urllib.request实现含二进制文件的multipart/form-data POST请求

问题描述

请问是否有人有现成的urllib方案,能够仅使用urllib.request发送POST请求,同时在请求载荷中结合请求头、自定义字段与二进制文件?

注意:环境受限(插件环境),无法使用urllib2/3、requests、poster等其他库!尽管环境缺少便捷工具,但仍需完成该任务。

目前我找到的示例均依赖上述库,希望有人能分享可用的实现示例。

以下是我们当前用于仅发送文本数据(urlencoded格式)的POST请求示例,若要包含文件则需切换为multipart/form-data格式,无支持库的情况下实现难度较大:

import urllib.request
url = "https://wwww.target.com/upload/"
values = {
  'param1' : 'value1',
  'param2' : 'value2',
  'param3' : 'value3',
}
postdata = urllib.parse.urlencode(values)
postdata = postdata.encode("utf-8")
req = urllib.request.Request(url, data=postdata)
req.add_header("Accept-Encoding", "gzip, deflate, br")
req.add_header("Accept-Language", "en-US,en;q=0.5")
#req.add_header("Cookie", str("; ".join(cookies_tuple)))
req_stream = urllib.request.urlopen(req)
resp_code = req_stream.getcode()
resp = req_stream.read()
req_stream.close()

实现方案

要实现multipart/form-data格式的POST请求,需要手动构造请求体(包括边界分隔符、文本字段、文件二进制数据),同时设置正确的请求头。以下是纯urllib.request的实现:

import urllib.request
import uuid

def multipart_post(url, fields, files, headers=None):
    # 生成唯一边界符,避免与内容冲突
    boundary = uuid.uuid4().hex.encode('utf-8')
    crlf = b'\r\n'
    form_parts = []

    # 拼接文本字段
    for field_name, field_value in fields.items():
        form_parts.append(b'--' + boundary)
        form_parts.append(f'Content-Disposition: form-data; name="{field_name}"'.encode('utf-8'))
        form_parts.append(b'')
        form_parts.append(str(field_value).encode('utf-8'))

    # 拼接文件字段
    for file_field_name, file_info in files.items():
        filename, file_bytes = file_info
        form_parts.append(b'--' + boundary)
        disp_header = f'Content-Disposition: form-data; name="{file_field_name}"; filename="{filename}"'
        form_parts.append(disp_header.encode('utf-8'))
        # 根据文件类型调整Content-Type,比如图片用image/jpeg,文档用application/pdf
        form_parts.append(b'Content-Type: application/octet-stream')
        form_parts.append(b'')
        form_parts.append(file_bytes)

    # 添加结束标记
    form_parts.append(b'--' + boundary + b'--')
    form_parts.append(b'')

    # 合并所有部分为请求体
    request_body = crlf.join(form_parts)

    # 创建请求对象
    req = urllib.request.Request(url, data=request_body)
    # 设置multipart/form-data的Content-Type头
    req.add_header('Content-Type', f'multipart/form-data; boundary={boundary.decode("utf-8")}')

    # 添加自定义请求头
    if headers:
        for key, val in headers.items():
            req.add_header(key, val)

    # 发送请求并获取响应
    with urllib.request.urlopen(req) as resp_stream:
        return resp_stream.getcode(), resp_stream.read()

# 示例调用
if __name__ == '__main__':
    target_url = "https://www.target.com/upload/"
    # 自定义文本参数
    text_fields = {
        'param1': 'value1',
        'param2': 'value2',
        'param3': 'value3'
    }
    # 文件参数:键是表单的文件字段名,值是(文件名, 二进制文件数据)
    file_fields = {
        'upload_file': ('test_image.jpg', open('test_image.jpg', 'rb').read())
    }
    # 自定义请求头
    custom_headers = {
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "en-US,en;q=0.5"
        # "Cookie": "; ".join(cookies_tuple)  # 按需启用
    }

    status_code, response_data = multipart_post(target_url, text_fields, file_fields, custom_headers)
    print(f"响应状态码: {status_code}")
    print(f"响应内容: {response_data.decode('utf-8')}")

关键说明

  • 边界符(Boundary):用UUID生成唯一字符串,作为multipart各部分的分隔标记,防止与内容中的字符串冲突。
  • 字段构造规则:每个文本/文件字段都需要以--{boundary}开头,后跟Content-Disposition头描述字段信息,空行后是字段内容。
  • Content-Type设置:必须在请求头中指定multipart/form-data; boundary={你的边界符},否则服务端无法正确解析请求体。
  • 文件类型适配:文件字段的Content-Type需要根据实际文件类型调整,比如图片用image/jpeg,PDF用application/pdf,通用二进制文件可以用application/octet-stream。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:35:24