目前,拥有多部分表单请求的唯一方法是r = requests.post(url, data=payload, files=files)
可能有一个组件
Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain
content
--3eeaadbfda0441b8be821bbed2962e4d--
但是,我遇到过帖子需要采用多部分格式而没有关联文件的情况,例如:
Content-Disposition: form-data; name="key1"
value1
--3eeaadbfda0441b8be821bbed2962e4d
但是没有前者,后者是不可能产生的。
也许我们可以添加一个像r = requests.post(url, data=payload, multipart=True)
这样的标志来强制一个帖子是多部分的,即使没有文件。
如果这听起来是个好主意,我很乐意致力于实现这一点。
这个之前已经讨论过了。 这将代表 API 的重大变化,我不确定@kennethreitz是否愿意。
就我个人而言,我更倾向于公开一个函数来从 API 中的字典(元组列表等)生成多部分数据,以便用户可以使用它并将生成的数据传递给请求。 表面上,如果他们不使用文件,就不应该有巨大的内存冲击,但即便如此,他们的内存中已经有一个巨大的字符串,第二个不会真正杀死他们,这将是他们的错,而不是我们的错.
也许@kennethreitz更适合第二种解决方案。 我认为它也不符合请求的设计理念,并且考虑到 API 的其余部分会非常奇怪,但是_耸肩_谁知道。
事实上,当前的 API 不支持发送文件以外的多部分数据,这是一件坏事。 参见问题 #935 和 shazow/urllib3/issues/120
也许我错过了一些东西,但这些变化对我来说似乎很小。 我分叉了存储库,并在此处对我的版本进行了拟议更改: https :
(如果有更好的方法来做到这一点让我知道?我对 github 比较陌生)。
它可能需要几个单元测试,并且需要更改 api.py 中的文档字符串,但是这样的事情合理吗?
更改的问题不在于实现起来很复杂,而在于 API 的差异。 在这个正在进行的讨论中,我有点犹豫:我认为有一种上传多部分表单数据的好方法可能很有用,但我也认为当前的files
API 是一个非常好的 API . 我_不_认为将multipart
到Request
API 是可行的方法。
老实说,我个人更愿意通过内容类型标头来控制它,但这可能比我们目前所做的更容易出错和让新用户感到困惑 100 倍。 我也对此持观望态度,但如果不这样做,我仍然会犯错。
为什么? 如果我们接受此功能请求,则更有可能有人抱怨没有 json 参数。 而且我相信其他人可以想出更多他们希望添加的参数。 就像现在一样,API 完全按照它应该做的,而且几乎没有杂乱无章。 看待这一点的一种方式是 KISS。 这使得请求并返回一个很好的对象,使使用响应变得容易和自然。 它做广告宣传的事情,剩下的由您来做。 它确实宣传了多部分编码,并通过其文档化设计来实现。 它可能看起来很尴尬,但它被记录在案并且有效。
_(...) 有人会抱怨没有 json 参数_
这样的抱怨是没有根据的,因为 json 是application
媒体类型( rfc4627 )的子类型,而不是multipart
媒体类型( httpbis 草案 21 )
_可能看起来很别扭(...)_
这很尴尬,但它不应该。
在阅读了之前的评论后,我想重申我的立场: multipart/form-data
是当前使用的最常见的多部分 MIME 类型(需要引用:)),不支持它是一种严重的遗漏。
@piotr-dobrogost:尽管我上面说了,但我觉得你刚刚提出的论点甚至有点令人信服。
请求不支持 MIME 类型,它支持用例。 这种观点使您上面的评论看起来很奇怪。 例如,关于没有 JSON 参数的抱怨将是因为上传 JSON 格式的数据非常普遍——在请求用户中可能比上传非文件多部分数据更常见。 争辩说我们不会提供它,因为“我们只是multipart
的特殊情况子类型”,这似乎是一件奇怪的事情。
无论如何,问题的核心是:API 是这个库的重点。 如果你不能想出一个_漂亮_的方式来实现这个功能,它就不会发生。
这样的抱怨是没有根据的[原文如此]
@piotr-dobrogost 你对开发人员的未来比我更有希望。 除此之外,请求的参数是不准确的。 它需要被称为更像form_data
不是multipart
。 正如您所注意到的,(虽然是间接的) multipart
可以指代许多不同的媒体类型。
这很尴尬,但它不应该。
并非所有事情都可以优雅(即使在 python 中)。
并且不支持
但它是支持的。 但是,这一边,我们有data
的application/x-www-form-urlencoded
, files
(或files+data
)为multipart/form-data
,为什么我们还需要另一个参数当我们拥有它时,只需multipart/form-data
?
您不需要组合使用data
和files
来获得预期的结果。 您可以执行类似于: requests.post('http://example.com/', files=[('key1', 'param1'), ('key2', 'param2')])
而无需在其中放置实际文件。
如果我们准确地说, form_data
可能不是很明显,那么为什么不使用参数multipart_form_data
,但现在这也很笨拙。 它是明确的,是的,并且 PEP 8 要求明确,但现有的行为是有据可查的。 如果@kennethreitz确实决定接受此功能请求,则所有参数需要做的就是充当 files 参数的别名。 但考虑到该行为已经得到支持,我认为没有必要。
@sigmavirus24和@Lukasa完美地总结了这一点。
@piotr-dobrogost 您的贡献受到赞赏,但不是您的语气。 请停止对我们的项目及其目标做出坚定的断言。
从我的角度来看,请求已经支持多部分帖子是非常令人沮丧的,但不让用户在不使用文件的情况下访问它。 @sigmavirus24建议只在其中粘贴一个文件是不够的。 如果尝试过类似的操作,我使用的 Web 应用程序将返回错误代码。
我怀疑这将在未来继续成为用户的问题,我有点困惑为什么似乎没有努力解决这个问题。
请参阅我对 #935 的回复
哦谢谢。 我很期待!
@卢卡萨
_Requests 不支持 MIME 类型,它支持用例。_
发送multipart/form-data
数据是一个常见的用例。
_(...) 上传JSON格式的数据很常见(...)_
我们无法将发送 json 与发送multipart/form-data
。 发送 json 很容易; 您设置Content-type
,使用内置模块在一行中编码数据,就是这样。 发送multipart/form-data
更加复杂,因为请求的正文必须具有特定的结构。 换句话说,发送 json 与 HTTP 一样透明,但发送multipart/form-data
则不然。 由于 Requests 是 HTTP 库,它应该负责创建这样的结构。
_如果你不能想出一个漂亮的方式来实现这个功能,它就不会发生。_
使用当前的files
参数来发送与文件无关的multipart/form-data
在任何方面都不美观(它很丑),但它以某种方式设法进入代码库:)。 想出一些不那么难看的东西真的很容易:)
@西格玛病毒24
_(...) 但现有的行为有据可查。_
没有多少文档可以从糟糕的 API 中提取出好的 API。 API 越好,需要的文档就越少。
_你可以做一些类似于 (...)_
是的,但这是非常具有误导性和不直观的。 我在之前的评论中描述了为此使用files
参数有什么问题。
底线:想出更好的东西,我们需要承认当前的 api 在发送multipart/form-data
数据方面很糟糕。
@spacecase
_从我的角度来看,请求已经支持多部分帖子是非常令人沮丧的,但不让用户在不使用文件的情况下访问它_
我同意,这就是我创建问题 #935 的原因。
此问题已关闭。
原谅我@kennethreitz但@spacecase我没有在该示例中的任何地方使用文件。 我使用 files 参数来做你想要的。 如果我使用了一个文件,你就会看到open('filename')
。
@sigmavirus24 ,不幸的是,这不是我想要的。 这与客户端是否正在读取文件无关。 这就是告诉服务器的内容。 在您的示例中,帖子正文是
Content-Disposition: form-data; name="key1"; filename="key1"
Content-Type: application/octet-stream
param1
--2f8732ee35564115a6c6e0c1032773e8
Content-Disposition: form-data; name="key2"; filename="key2"
Content-Type: application/octet-stream
param2
--2f8732ee35564115a6c6e0c1032773e8--
注意filename=
。 它告诉服务器一个文件正在发送。 在网络应用程序中,我处理这种不正确的行为会导致错误。
我很抱歉,但你这么冒昧地告诉我这正是我想要的,这冒犯了我。 我是来提供想法和帮助的,在这种情况下,听起来你也不想要。 那很好,但请不要让我觉得被轻视。
嗯,好像我记错了行为。 对于那个很抱歉。 我根本无意冒犯您或让您觉得自己被轻视。 这绝对足以让我动摇需要一种更好的方法来处理multipart/form-data
,但现在我仍然不同意 API 的想法一点也不优雅。
@spacecase请看我对#935 的回复。 事情会更好。 您的反馈很重要,非常感谢。 :)
@spacecase作为表明您的意见确实重要的一种姿态,请查看 sigmavirus24/requests-data-schemes 作为权宜之计。 您必须设置自己的Content-Type
标头,但这可能会带来一些小麻烦。
谢谢@sigmavirus24 ,我会试试的。 看起来它会成功。
我很感激你不是故意冒犯我。 我对此感觉好多了,我不反对你或这个项目。
是的,在某些人看来我显得很傲慢,所以我想我需要完善我在互联网上写的内容。 我不明白,其他人也同意我的看法,但我正在努力。 我想我只需要一个足够大的样本量,就可以在我无意中意识到对人们的冒犯(除了我通过记住一些不可行的方式来使自己变得愚蠢)。
我有一个文件和一些要发布的键值。 那么发送这种多部分表单请求的正确方法是什么? 我希望你能帮助我。
Content-Disposition: form-data; name="up"; filename="aa.PNG"
Content-Type: image/png
file data
---------------------------7dee5302248e
Content-Disposition: form-data; name="exp"
-----------------------------7dee5302248e
Content-Disposition: form-data; name="ptext"
text
-----------------------------7dee5302248e
Content-Disposition: form-data; name="board"
DV_Studio
-----------------------------7dee5302248e--
I tried this way but only got a 504 error.
myfile=[('file',open('bb.jpg')),('exp','python'),('ptext',''),('board','DV_Studio')]
r = requests.post(url,files=myfile)
@deerstalker有问题请使用StackOverflow 。 不过,要回答您的问题,有一个项目正在进行中以解决此问题sigmavirus24/requests-toolbelt
另请注意,我之前已经在 StackOverflow 上回答过这个问题,您可以在这里看到。
我有同样的问题,即在没有文件的情况下生成多部分帖子。 目前,如果您执行requests.post(url, data=data_dict)
或requests.post(url, data=data_dict, files={})
没有区别。 但是,由于files
关键字默认为None
,我们应该能够有两种不同的行为。 指定multipart/form-data
时files={}
未指定时application/x-www-form-urlencoded
。
我错过了什么?
@jwoillez您是否关注了我发布的堆栈溢出链接?
我认为是这样,但是您在那边的回答涉及一个文件的 Multipart POST。 我回到原来的问题:没有文件的多部分 POST。
文件对象可以是字符串。 =) 那应该为您提供您想要的信息。
但是如果我按照你的建议去做,我会不会得到这样的结果:
Content-Disposition: form-data; name="file"; filename="filename.txt"
Content-Type: text/plain
content
--3eeaadbfda0441b8be821bbed2962e4d--
content
是您邀请我使用的字符串而不是文件?
我真的只追求这个:
Content-Disposition: form-data; name="key1"
value1
--3eeaadbfda0441b8be821bbed2962e4d
您不需要的元组中的字段可以保留为默认值:
files = {'name': ('', 'content')}
将来,请将您的问题直接发送到 StackOverflow。 所有的维护人员都会定期跟踪它,这是提出这些问题的更合适的地方。
这就是我要找的答案,谢谢。 对不起,噪音。
也许最后一个问题,是否有以下可能(指定空文件名,空内容)?
Content-Disposition: form-data; name="file"; filename=""
Content-Type: text/plain
--3eeaadbfda0441b8be821bbed2962e4d--
您可以通过在元组的内容部分中使用空字符串来提供空内容。 您不能提供文字空文件名,但应以完全相同的方式处理不存在的文件名。
由于各种奇怪的原因,我偶尔需要这样做。
对于想要将 API 强加到这个用例中的任何人,我建议采用这种方法:
class ForceMultipartDict(dict):
def __bool__(self):
return True
FORCE_MULTIPART = ForceMultipartDict() # An empty dict that boolean-evaluates as `True`.
client.post("/", data={"some": "data"}, files=FORCE_MULTIPART)
或者你可以使用工具带而不是求助于黑客。