使用 Flurl 发布 `multipart/form-data`
Posting `multipart/form-data` with Flurl
我需要post以下请求:
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
库做同样的事情吗?
我的 documented 方法的问题是它会为每个 key-value 对插入 Content-Type
header 并且它会插入 filename*=utf-8''
header 为文件数据。但是,我尝试向 post 发送请求的服务器不支持此功能。另请注意 header 中 name
和 filename
值周围的双引号。
编辑:下面是我用 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;
}
}
}
根据 spec(日期为 2011 年 6 月),建议同时发送 filename
和 filename*
以获得最大兼容性:
Many user agent implementations predating this specification do not
understand the "filename*" parameter. Therefore, when both "filename"
and "filename*" are present in a single header field value, recipients
SHOULD pick "filename*" and ignore "filename". This way, senders can
avoid special-casing specific user agents by sending both the more
expressive "filename*" parameter, and the "filename" parameter as
fallback for legacy recipients.
如果 filename*
确实导致了对 的调用失败 ,那么遵守 HTTP 规范的服务器确实存在问题。此外,将 name
和 filename
括在引号中非常 non-standard.
也就是说,Flurl 的快捷方式涵盖了 90% 的情况,但您始终可以使用底层 HttpClient API 来涵盖像这种情况这样的异常情况。在这种情况下,我认为您需要手动构建内容,以便处理那些 Content-Disposition
headers:
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);
我需要post以下请求:
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
库做同样的事情吗?
我的 documented 方法的问题是它会为每个 key-value 对插入 Content-Type
header 并且它会插入 filename*=utf-8''
header 为文件数据。但是,我尝试向 post 发送请求的服务器不支持此功能。另请注意 header 中 name
和 filename
值周围的双引号。
编辑:下面是我用 Flurl.Http
:
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;
}
}
}
根据 spec(日期为 2011 年 6 月),建议同时发送 filename
和 filename*
以获得最大兼容性:
Many user agent implementations predating this specification do not understand the "filename*" parameter. Therefore, when both "filename" and "filename*" are present in a single header field value, recipients SHOULD pick "filename*" and ignore "filename". This way, senders can avoid special-casing specific user agents by sending both the more expressive "filename*" parameter, and the "filename" parameter as fallback for legacy recipients.
如果 filename*
确实导致了对 的调用失败 ,那么遵守 HTTP 规范的服务器确实存在问题。此外,将 name
和 filename
括在引号中非常 non-standard.
也就是说,Flurl 的快捷方式涵盖了 90% 的情况,但您始终可以使用底层 HttpClient API 来涵盖像这种情况这样的异常情况。在这种情况下,我认为您需要手动构建内容,以便处理那些 Content-Disposition
headers:
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);