FormData 是一种用于构造表单数据的格式,通常用于在 HTML 表单中通过 POST 方法提交数据,特别是包含文件上传的场景,在 Python 中,我们通常不直接操作字符串来构建 FormData,而是使用专门的库来帮助我们轻松创建和发送它。

核心概念
multipart/form-data: 这是FormData在 HTTP 协议中使用的Content-Type,它是一种多部分、二进制的数据格式,可以同时发送文本数据和文件数据。requests库: 这是 Python 中最流行、最简单的 HTTP 请求库,它提供了requests.post()方法,并可以方便地处理multipart/form-data。files参数: 在requests.post()中,files参数就是用来发送文件和表单数据的关键。
使用 requests 库(最常用)
这是最直接、最推荐的方法。requests 库封装了所有复杂的细节。
安装 requests
如果你还没有安装,请先安装它:
pip install requests
发送纯文本表单数据
如果你想发送普通的键值对(如用户名、密码等),可以直接使用 data 参数。requests 会自动将其编码为 application/x-www-form-urlencoded 格式,对于 FormData,我们需要使用 files 参数。
import requests
# 目标 URL
url = 'https://httpbin.org/post' # httpbin.org 是一个测试 HTTP 请求的网站
# 表单数据 (键值对)
form_data = {
'username': 'test_user',
'password': '123456',
'description': 'This is a test description.'
}
# 发送 POST 请求
# 使用 data 参数会自动编码为 application/x-www-form-urlencoded
# 对于 FormData,我们需要使用 files 参数,即使没有文件
response = requests.post(url, data=form_data)
# 打印响应
print("Status Code:", response.status_code)
print("Response Text:")
print(response.text)
发送包含文件的表单数据(核心用法)
这是 FormData 最常见的用途,在 files 参数中,你需要指定一个字典,其中键是表单字段名,值是一个元组 (文件名, 文件对象, content_type)。

import requests
url = 'https://httpbin.org/post'
# 准备要上传的文件
# 假设你有一个名为 'my_image.png' 的文件在当前目录
try:
with open('my_image.png', 'rb') as f:
files = {
# 'file_field_name': (file_name, file_object, content_type)
'profile_pic': ('my_image.png', f, 'image/png')
}
# 表单数据
data = {
'username': 'file_uploader',
'caption': 'My beautiful photo'
}
# 发送请求
# files 和 data 可以同时使用
response = requests.post(url, files=files, data=data)
print("Status Code:", response.status_code)
print("Response JSON:")
# httpbin.org 会返回你发送的所有数据,方便你检查
print(response.json())
except FileNotFoundError:
print("错误:请确保 'my_image.png' 文件存在于当前目录。")
files 参数详解:
files 参数的值是一个字典,字典的每个键对应表单中的一个字段名,值通常是一个元组,格式为:
(filename, file_object, content_type)
filename(字符串): 你希望在服务器上看到的文件名。file_object: 一个文件类的对象,必须以二进制模式 ('rb') 打开。content_type(字符串): 文件的 MIME 类型,'image/png','text/plain','application/pdf',这个值会自动设置请求头Content-Type中的boundary和type。
简写形式:
如果你不关心文件名和 content_type,可以只提供文件对象:
files = {'some_file': open('report.pdf', 'rb')}
requests 会尝试自动推断文件名和类型,但最好明确指定,以确保兼容性。
手动构建 multipart/form-data(不推荐,仅用于理解)
虽然 requests 能自动处理,但了解其背后的原理也很有帮助。multipart/form-data 格式由多个部分组成,每个部分之间用 boundary(一个随机字符串)分隔。
一个简单的 FormData 示例:
POST /upload HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="username" John Doe ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="file"; filename="example.txt" Content-Type: text/plain This is the content of the file. ------WebKitFormBoundary7MA4YWxkTrZu0gW--
手动构建这个字符串非常繁琐且容易出错,你需要:
- 生成一个唯一的
boundary。 - 为每个部分构建头部(
Content-Disposition,Content-Type)。 - 添加数据内容。
- 用
boundary正确地分隔所有部分。 - 在末尾添加
--boundary--表示结束。
强烈建议你始终使用 requests 或其他高级库来处理,而不是手动拼接字符串。
完整示例:同时上传文件和文本数据
这个例子综合了前面的知识点,模拟一个真实的用户头像上传场景。
import requests
# 目标 API 端点 (使用 httpbin.org 进行演示)
url = 'https://httpbin.org/post'
# 1. 准备要上传的文件
try:
with open('my_image.png', 'rb') as f_image:
# 2. 准备文本表单数据
# 使用 data 参数来发送非文件字段
form_data = {
'user_id': 'user123',
'action': 'update_avatar'
}
# 3. 准备文件数据
# 使用 files 参数来发送文件
# 'avatar' 是服务器期望的字段名
files = {
'avatar': ('my_image.png', f_image, 'image/png')
}
# 4. 发送 POST 请求
# requests 会自动设置正确的 Content-Type (multipart/form-data)
# 和 boundary
print("正在发送请求...")
response = requests.post(url, data=form_data, files=files)
# 5. 处理响应
if response.status_code == 200:
print("\n请求成功!")
# httpbin.org 返回的 JSON 中,'form' 包含文本数据,'files' 包含文件数据
response_json = response.json()
print("\n服务器收到的表单数据:")
print(response_json.get('form'))
print("\n服务器收到的文件数据:")
print(response_json.get('files'))
else:
print(f"\n请求失败,状态码: {response.status_code}")
print(response.text)
except FileNotFoundError:
print("错误:请确保 'my_image.png' 文件存在于当前目录。")
except Exception as e:
print(f"发生错误: {e}")
总结与关键点
| 任务 | 推荐方法 | 示例代码 |
|---|---|---|
| 发送纯文本表单 | 使用 requests.post() 的 data 参数 |
requests.post(url, data={'key': 'value'}) |
| 发送文件 | 使用 requests.post() 的 files 参数 |
requests.post(url, files={'file': ('name', f_obj, 'type')}) |
| 同时发送文件和文本 | data 和 files 参数一起使用 |
requests.post(url, data=text_data, files=files_data) |
| 获取文件对象 | 使用 with open('file.png', 'rb') as f: |
确保文件以二进制读模式打开 |
| Content-Type | requests 自动设置 |
无需手动设置,它会变成 multipart/form-data; boundary=... |
对于任何涉及 FormData 的请求,requests 库都是你的首选工具,它简单、强大且能避免手动处理复杂格式的痛苦。
