使用 HttpClient 上传多部分表单文件
Posted
技术标签:
【中文标题】使用 HttpClient 上传多部分表单文件【英文标题】:Uploading multipart form files with HttpClient 【发布时间】:2020-05-27 07:49:42 【问题描述】:我正在尝试使用此处记录的 Support Bee API 创建附件: https://supportbee.com/api#create_attachment
我编写了一个服务,它使用HttpClient
创建并使用文件名发送请求。
如果我在 Postman 中测试,它会成功。我使用 form-data
作为正文,只是从 UI 中选择要上传的文件:
当我尝试通过我的HttpClient
服务上传它时它不起作用:
public async Task<string> CreateAttachmentAsync(string fileName)
// "client" is HttpClient provided via D.I.
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StreamContent(new FileStream(fileName, FileMode.Open)), "files[]");
using (HttpResponseMessage response = await client.PostAsync(
"https://xxx.supportbee.com/attachments?auth_token=xxx",
content))
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
这会导致 500 内部服务器错误。检查MultipartFormDataContent
对象,我可以看到它的标头值正在自动设置:
内容类型:multipart/form-data;边界="c9be3778-4de5-4460-9929-adcaa6bdda79" 内容长度:164
我还尝试先将文件读取到字节数组并使用ByteArrayContent
而不是StreamContent
无济于事。响应没有提供任何有用的信息,但由于请求在 Postman 中有效,我的代码肯定有问题,但我不知道还能尝试什么。
编辑:我使用 Fiddler 进行了测试,以将成功的 Postman 请求与我的代码进行比较。这是 Postman 的请求:
发布 https://xxx.supportbee.com/attachments?auth_token=xxx HTTP/1.1 用户代理:PostmanRuntime/7.22.0 接受:/ 缓存控制: 无缓存邮递员令牌:f84d22fa-b4b1-4bf5-b183-916a786c6385 主机: xx.supportbee.com 内容类型:multipart/form-data; 边界=-------------714700821471353664787346 接受编码:gzip、deflate、br 内容长度:241 连接: 关闭
----------------714700821471353664787346 内容处置:表单数据;名称=“文件[]”;文件名="sample.txt" 内容类型:text/plain
这包含示例文本。 --------------714700821471353664787346--
以及来自我的代码的失败请求:
发布 https://xxx.supportbee.com/attachments?auth_token=xxx HTTP/1.1 主机:xxx.supportbee.com 接受:/ 接受编码: gzip、deflate、br 连接:关闭 内容类型:multipart/form-data; 边界="ea97cbc1-70ea-4cc4-9801-09f5feffc763" 内容长度:206
--ea97cbc1-70ea-4cc4-9801-09f5feffc763 内容处置:表单数据;名称=“文件[]”;文件名=样本;文件名*=utf-8''示例
这包含示例文本。 --ea97cbc1-70ea-4cc4-9801-09f5feffc763--
我可以看到的区别是 Postman 中的各个部分有自己的文件 Content-Type: text/plain
标头,而我的没有。我无法添加这个,因为如果我尝试 content.Headers.Add("Content-Type", "text/plain");
它会失败并显示“无法添加值,因为标头 'Content-Type' 不支持多个值。”
【问题讨论】:
此代码using (var response = await client.SendAsync(message))
发出GET
请求,您需要POST
。首先,删除该行。您的HttpClient
可能在发送前检查BaseAddress
。向我们展示responseString
的价值
@RomanMarusyk 我在编辑问题时留下了一些不好的残留代码,我错过了,现在已被删除。它使用PostAsync
发送将发布的请求。 responseString
只是包含“我们很抱歉,但出了点问题 (500)”的 html。
好的,尝试从 Postman 和您的应用中捕获请求并进行比较 (Fiddler)。你的代码看起来不错。
@RomanMarusyk 我实际上就是这样做的。添加到我的帖子中。
这能回答你的问题吗? C# HttpClient 4.5 multipart/form-data upload
【参考方案1】:
首先,请务必注意,500 响应类似于未处理的异常,即这是他们的错误,或多或少不可能确定您做错了什么。我建议向他们报告,虽然我不熟悉 Support Bee,但我希望他们有很好的支持人员可以帮助您解决问题。 :)
但是,如果您想玩猜谜游戏,我同意您成功的 Postman 调用与您的代码之间的细微差别是一个不错的起点。对于该标头,请注意 content
是 MultipartFormDataContent
。您实际上想在 StreamContent
对象上设置它。
另外,查看 Postman 发送的请求标头,看看 Content-Disposition
是否包含 filename
。如果 API 需要它,您可能还需要将它添加到您的代码中。
以下是如何做到这两点:
var fileContent = new StreamContent(File.OpenRead(path));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
content.Add(fileContent, "files[]", Path.GetFileName(path));
如果这不是问题,请查看 Postman 中请求正文的“原始”版本,以及这 11 个请求标头,看看是否能发现其他可能遗漏的内容。
【讨论】:
直接在StreamContent
对象上设置ContentType
标头使其工作。以上是关于使用 HttpClient 上传多部分表单文件的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Jetty HttpClient 中进行多部分/表单数据发布