Posting `multipart/form-data` with Flurl

本文关键字:with Flurl form-data multipart Posting | 更新日期: 2023-09-27 18:02:36

我需要发布以下请求:

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;
        }
    }
}

Posting `multipart/form-data` with Flurl

根据规范(日期为2011年6月),建议同时发送filenamefilename*以获得最大的兼容性:

在此规范之前的许多用户代理实现没有这样做理解"文件名*"参数。因此,当两个"filename"answers"文件名*";是否存在于单个报头字段值中,收件人应该选择"文件名*"忽略"filename"通过这种方式,发件人可以通过同时发送more来避免特殊的用户代理表达"文件名*";参数,以及"文件名"。参数,遗留收件人的回退。

如果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);