【问题标题】:Using Python Requests to send file and JSON in single request使用 Python 请求在单个请求中发送文件和 JSON
【发布时间】:2026-01-06 02:20:03
【问题描述】:

我正在尝试发布到 API(使用 SlimPHP 构建),该 API 接受图像以及 JSON 形式的附加图像元数据。

我已使用 REST 客户端工具验证 API 可以正常工作,并且可以成功 POST 到服务。所有数据都正确存储。

我现在正在尝试使用 Python 发布 - 但是我的 JSON 数据似乎没有保存。

我的代码:

    data = {'key1': 'value1', 'key2': 'value2'}
    url = 'http://mydomain.com/api/endpoint'
    headers = {'Authorization': 'my-api-key'}
    files = {'file': (FILE, open(PATH, 'rb'), 'image/jpg', {'Expires': '0'})}
    r = requests.post(url, files=files, headers=headers, data=data)

--

我已尝试设置其他标题,

即:/

headers = {'Authorization': 'unique-auth-key', 'Content-type': 'multipart/form-data'}

headers = {'Authorization': 'unique-auth-key', 'Content-type': 'application/json'}

这些会导致 500 错误。


2014 年 7 月 14 日更新:

使用 chrome 扩展(高级 Rest 客户端)我的 POST 成功 - 这是控制台显示为有效负载的内容:

------WebKitFormBoundarysBpiwrA3hnGPUbMA
Content-Disposition: form-data; name="data"
test
------WebKitFormBoundarysBpiwrA3hnGPUbMA
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: image/jpeg
------WebKitFormBoundarysBpiwrA3hnGPUbMA--

我不太确定这意味着什么......

【问题讨论】:

  • 您必须提供 API 规范才能运行调用。使用curl、HTTPie 或类似工具的示例会有所帮助。通常,JSON 数据作为唯一的内容在正文中发送。如果你想将它与文件上传结合起来,你可能会使用某种形式,一个文件是图像,另一个包含 JSON 的文本字段。无论如何,data 应该是一个字符串,你提供一个字典。将其更改为 data=json.dumps(data) 可能会有所帮助。
  • 这个 cURL 请求有效: curl -i -F data='{"key": "value", "key": "value", "key": "value"}' -F name =image.jpg -F file=@image.jpg -H "授权:abcd-efgh-ijkl-mnop" my-url.com/api/endpoint

标签: python rest python-requests


【解决方案1】:

您的问题是您使用图像元数据作为要发布的键/值对的来源。而不是将其作为这些键/值对之一的值发送。

以下代码将发送一个请求,很像您提供的 curl 语句:

url = 'my-url.com/api/endpoint'
headers = {'Authorization': 'my-api-key'}
image_metadata = {'key1': 'value1', 'key2': 'value2'}
data = {'name': 'image.jpg', 'data': json.dumps(image_metadata)}
files = {'file': (FILE, open(PATH, 'rb'), 'image/jpg', {'Expires': '0'})}
r = requests.post(url, files=files, headers=headers, data=data)

【讨论】:

  • 尽管我很想要赏金,但在调查了这一点后,我同意了。在查看docs.python-requests.org/en/latest/user/quickstart/… 并将测试请求发布到“httpbin.org/post”之后,我使用 python 复制了几乎与此答案相同的 curl 输出。 (两个警告:image_metadata dict 显然不能支持 'key':'value' 的多个实例,我猜 FILE 是文件名。)
  • 嗨杰里米。你能解释一下 FILE 变量代表什么吗?尝试对我的代码使用类似的解决方案
【解决方案2】:

如果您需要在单个请求中发布嵌套的JSON数据发送文件,则需要使用json.dumps 用于这些元素(以下示例中的列表和映射)

import requests

session = requests.Session()
session.post(login_url, json=your_credentials_dict)  # auth , not required
mapping = {"email": "Email", "First Name": "first_name"}
post_data = dict(
   mode=1,
   lists=json.dumps(["133", "899", "911"]),
   mapping=json.dumps(mapping),
)
files_data = {'file': ('your-file-name.csv', file_bytes_content)}
response = session.post(<your-url>, data=post_data, files=files_data)

因此会发送这样的请求:

********** post file data with mapping **********
 --> REQUEST: POST /v3/contacts/import/file/ HTTP/1.1
 --> REQUEST: Host: <your-host>:4000
 --> REQUEST: User-Agent: python-requests/2.23.0
 --> REQUEST: Accept-Encoding: gzip, deflate
 --> REQUEST: Accept: */*
 --> REQUEST: Connection: keep-alive
 --> REQUEST: Cookie: jwt=eyJ0e***
 --> REQUEST: Content-Length: 654
 --> REQUEST: Content-Type: multipart/form-data; boundary=db850c3230988e010b1ebe21be3fb344
 --> REQUEST: 
 --> REQUEST: --db850c3230988e010b1ebe21be3fb344
Content-Disposition: form-data; name="lists"

["7syewz9qUz0CbaqhaGm", "LBfWKJwq4Q"]
--db850c3230988e010b1ebe21be3fb344
Content-Disposition: form-data; name="mode"

2
--db850c3230988e010b1ebe21be3fb344
Content-Disposition: form-data; name="mapping"

{"email": "Email", "First Name": "first_name"}
--db850c3230988e010b1ebe21be3fb344
Content-Disposition: form-data; name="file"; filename="good.csv"

first_name;last_name;email;age
John;Doe;test.testson_1@test.com;50
Mark;Twen;test.testson_2@test.com;20

--db850c3230988e010b1ebe21be3fb344--

requests-toolbelt包用于生成上面的日志 https://pypi.org/project/requests-toolbelt/

【讨论】:

    最近更新 更多