使用Flurl提交`multipart/form-data`类型的数据

5

我需要发布以下请求:

POST http://target-host.com/some/endpoint HTTP/1.1
Content-Type: multipart/form-data; boundary="2e3956ac-de47-4cad-90df-05199a7c1f53"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 6971
Host: target-host.com

--2e3956ac-de47-4cad-90df-05199a7c1f53
Content-Disposition: form-data; name="some-label"

value
--2e3956ac-de47-4cad-90df-05199a7c1f53
Content-Disposition: form-data; name="file"; filename="my-filename.txt"

<file contents>
--2e3956ac-de47-4cad-90df-05199a7c1f53--

我可以使用 Python 的 requests 库来轻松完成这个任务,方法如下:

import requests

with open("some_file", "rb") as f:
    byte_string = f.read()

requests.post(
    "http://target-host.com/some/endpoint",
    data={"some-label": "value"},
    files={"file": ("my-filename.txt", byte_string)})

有没有办法使用Flurl.Http库来实现相同的功能?
我对已经记录的方法存在问题,因为它会为每个键值对插入Content-Type头,并且会为文件数据插入filename*=utf-8''头。然而,我试图将请求发布到的服务器不支持此操作。还请注意标题中namefilename值周围的双引号。
编辑:下面是我用Flurl.Http进行POST请求的代码:
using System.IO;
using Flurl;
using Flurl.Http;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var fs = File.OpenRead("some_file");

            var response = "http://target-host.com"
                .AppendPathSegment("some/endpoint")
                .PostMultipartAsync(mp => mp
                    .AddString("some-label", "value")
                    .AddFile("file", fs, "my-filename.txt")
                ).Result;
        }
    }
}

这是一个非常合法的编程问题。请投票关闭它的人解释一下? - Todd Menier
你是说在文件数据的头部包含 filename* 实际上导致了调用失败? - Todd Menier
1个回答

4
根据2011年6月的规范,为了最大限度地提高兼容性,建议同时发送filenamefilename*

许多早于此规范的用户代理实现不理解“filename*”参数。因此,在单个头字段值中同时存在“filename”和“filename*”时,接收者应选择“filename*”并忽略“filename”。这样,发送者就可以通过发送更具表现力的“filename*”参数以及作为遗留接收者回退的“filename”参数来避免对特定用户代理进行特殊处理。

如果filename*实际上导致调用失败,则服务器遵循HTTP规范存在真正的问题。将namefilename括在引号中是非常不标准的。

话虽如此,Flurl的快捷方式覆盖了90%的情况,但您始终可以使用基础的HttpClient API来处理像这种不寻常的情况。在这种情况下,我认为您需要手动构建内容,以便您可以处理那些Content-Disposition头。

var mpc = new MultipartContent();
var sc = new StringContent("value");
sc.Headers.Add("Content-Disposition", "form-data; name=\"some-label\"");
mpc.Add(sc);
var fc = new StreamContent(fs);
fc.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"my-filename.txt\"");
mpc.Add(fc);

然后,你可以像这样在Flurl中使用它:
var response = await "http://target-host.com"....PostAsync(mpc);

我发现一个应用程序(Minio),如果非文件字段具有“content-type”,则会失败。可能不是唯一的。 - Antti Haapala -- Слава Україні

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