使用curl来POST multipart/form-data,包括文件和大量的键值对

3
作为模拟应用程序前端在我后端工作时的行为的一部分,我一直在运行各种curl命令。通过Content-Type:application/octet-stream将文件作为内容发送或者只是用Content-Type:application/json发送json都很容易。
我使用以下内容来内联发送json:
curl -X POST -H "Content-Type: application/json" -d '{"username":"xyz","password":"xyz"}' http://127.0.0.1:8088

从文件中提取json并以这种方式发送:
curl -X POST -H "Content-Type: application/json" -H 'Accept: application/json' --data-binary @test.json http://127.0.0.1:8088

(有什么想法关于“接受”是做什么的吗?没有它就不能工作...,解决方案来自这里
只是像这样单独发送一个文件:
curl --request POST -H "Content-Type:application/octet-stream"  --data-binary "@photo.jpg"  http://127.0.0.1:8088

使用内联json和图片的多部分内容可以像这样非常好地进行:

curl --verbose --request POST --header "Content-Type:multipart/form-data" --form key1=value1  --form upload=@photo.jpg   http://127.0.0.1:8088

(来自这里的解决方案)
当我尝试从文件中提取键值对和图片,或者将json粘贴到同时上传文件的curl命令中时,问题就出现了。你能说服curl用来自文件的键值对来自文件的文件附件发送"Content-Type:multipart/form-data"吗? john.json
{
  "surname" : "Doe",
  "name" : "John",
  "city" : "Manchester",
  "address" : "5 Main Street",
  "hobbies" : ["painting","lawnbowls"]
}

还有john.jpg

我尝试了一些方法,但它只给出错误消息:

尝试内联、粘贴json:

$ curl --verbose --request POST --header "Content-Type:multipart/form-data" --data '{"surname" : "Doe","name" : "John","city" : "Manchester","address" : "5 Main Street", "hobbies" : ["painting","lawnbowls"]}'  --form upload=@john.jpg   http://127.0.0.1:8088
Warning: You can only select one HTTP request method! You asked for both POST 
Warning: (-d, --data) and multipart formpost (-F, --form).

然后我尝试从文件中获取它们两个,但它也不接受:

$ curl --verbose --request POST --header "Content-Type:multipart/form-data" --form upload@john.json  --form upload=@john.jpg   http://127.0.0.1:8088
Warning: Illegally formatted input field!
curl: option --form: is badly used here
curl: try 'curl --help' or 'curl --manual' for more information

有什么想法可以使这个工作吗?

在你的问题中,--form key1=value1 --form upload=@photo.jpg 是有效的。那么这个 --form "upload1=<john.json" --form "upload=@photo.jpg" 呢?而且在你的情况下,--header "Content-Type:multipart/form-data" 可能不是必需的。因为我无法测试这个并且我不确定这是否是你的解决方案,所以我在这里进行了评论。如果这行不通,我很抱歉。 - Tanaike
@Tanaike,那个方法似乎不太行,虽然你用了尖括号,但我之前从未见过这种方法。我正在尝试使用此评论中的解决方案这个答案,但还没有成功。 - cardamom
真的很抱歉我不能提供帮助。 - Tanaike
2个回答

7

我认为你走上了正确的道路,但参考下curl手册页面可能会让你更进一步。

--form选项文档中可以得出以下要点:

@和<之间的区别在于@将文件作为文件上传附加到帖子中,而<则创建文本字段,并仅从文件中获取该文本字段的内容。

因此,对于JSON,使用<,但对于图片,请使用@

我认为还应该指定每个部分的内容类型,以帮助Web服务器知道如何解析每个部分。尽管它可能对每个字段都有期望。

您还可以使用“type =”告诉curl要使用的Content-Type,类似于:

curl -F "web=@index.html;type=text/html" example.com

你需要查找JSON和JPEG的MIME类型。

还有最后一点需要记住:此选项可多次使用。

这大部分只是@Tanaike上面所说的的回声,但是文档中有更多解释。我建议进一步详细阅读它。


我认为curl对你的命令最大的抱怨是表单的每个部分都具有键upload。这有点含糊不清。JSON有一个键,图片有一个键吗?

了解Web服务器从表单的每个字段中期望什么非常重要。文件上传和文本字段之间存在很大的差异。


1
是的,现在它可以工作了。如果我将一个“@”更改为“<”,然后使两个键不同,它就可以工作了。再稍微调整一下,我会发布现在可用的命令。 - cardamom

4

在 @Breedly 和 @Tanaike 的帮助下,我得到了以下命令的工作方式,希望有人能在未来受益:

curl --verbose --request POST --header "Content-Type:multipart/form-data" --form "upload1=<john.json" --form "upload2=@john.jpg"  http://127.0.0.1:8088

在这种情况下,只需一次使用"Content-Type:multipart/form-data"就可以覆盖它们两个,这真是太好了。但是json需要"<"而不是"@"。

以下内容也有效:

curl --verbose --request POST  --form "upload1=<john.json;type=application/json" --form "upload2=@john.jpg;type=multipart/form-data"  http://127.0.0.1:8088

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接