HttpClient POST 上传失败,没有文件传输和格式错误的生成内容处置

Posted

技术标签:

【中文标题】HttpClient POST 上传失败,没有文件传输和格式错误的生成内容处置【英文标题】:HttpClient POST upload fails with no file transfered and maleformed generated ContentDisposition 【发布时间】:2019-12-25 21:23:25 【问题描述】:

我尝试在我自己的图像主机上镜像图像,它包含一个接受默认表单数据上传的简单 API,如下所示:

-----------------------------149841124823007
Content-Disposition: form-data; name="file"; filename="ZMVdEwM.png"
Content-Type: image/png
<Binary image data...>

此上传使用简单的 html 表单进行了测试,效果很好。现在我想在 .NET Core Standard 应用程序中使用这个 API。找到differentexamples:

string url = "https://i.imgur.com/0acC9nr.png";
var client = new HttpClient();
var imageData = client.GetByteArrayAsync(url).Result;

var content = new MultipartFormDataContent($"-----------------------------DateTime.Now.Ticks");
content.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
string fileName = new Uri(url).LocalPath.Replace("/", "");
content.Add(new ByteArrayContent(imageData), "file", fileName);
var postResp = client.PostAsync("https://my-image-hoster/api.php", content).Result;
string resp = postResp.Content.ReadAsStringAsync().Result;
Console.WriteLine(resp);

我正在下载测试图像https://i.imgur.com/0acC9nr.png 作为字节数组并尝试构建相同的表单数据上传。但它在我的 api 上失败了:

if (!isset($_FILES['file'])) 
    echo json_encode(array('errorcode' => 'no_image_transfered'));

在调查问题时,我检查了名为 contentMultipartFormDataContent 实例,因为它负责构建请求正文。它显示了一个包含文件名的ContentDisposition 属性两次:第一个是正确的,但第二个看起来是畸形的:

我的 POST 请求有什么问题?

【问题讨论】:

【参考方案1】:

发现MultipartFormDataContent.Headers.ContentType是HTTP头的值:

Content-Type: multipart/form-data; boundary=--------------149841124823007

这取自example,它破坏了我的API,因为它需要multipart/form-data。因此最好关闭该类型,除非您的 API 检查 $_FILES['file'][0]['type'] 中提供的文件类型,因为这是空的。类型来自正文:

Content-Disposition: form-data; name="file"; filename="ZMVdEwM.png"
Content-Type: image/png <--- type

由于它是客户端提供的值,我们shouldn't trust this data 并在服务器端获取mime-type。如果你有一个检查这个值的 API(并且对 API 本身没有影响),只需像这样为 body 设置它:

content.ElementAt(0).Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");

否则,如果您可以上传不包含 mime 类型的 multipart/form-data,请按以下方式进行上传:

string url = "https://i.imgur.com/0acC9nr.png";
var client = new HttpClient();
var imageData = client.GetByteArrayAsync(url).Result;

var content = new MultipartFormDataContent();
string fileName = new Uri(url).LocalPath.Replace("/", "");
content.Add(new ByteArrayContent(imageData), "file", fileName);
// Optionally when the Content-Type body field is required
// content.ElementAt(0).Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
var postResp = client.PostAsync("https://my-image-hoster/api.php", content).Result;
var resp = postResp.Content.ReadAsStringAsync().Result;

【讨论】:

以上是关于HttpClient POST 上传失败,没有文件传输和格式错误的生成内容处置的主要内容,如果未能解决你的问题,请参考以下文章

java使用httpclient通过post方式提交表单失败求助

[转]httpclient 上传文件下载文件

HttpClient 上传文件

Titanium HTTPCLIENT 无法上传文件

尝试使用 HttpClient 上传文件时来自 Web Api 的 RequestEntityTooLarge 响应

取消 'HttpClient' POST 请求