WebAPI 无法解析多部分/表单数据帖子
Posted
技术标签:
【中文标题】WebAPI 无法解析多部分/表单数据帖子【英文标题】:WebAPI cannot parse multipart/form-data post 【发布时间】:2014-01-23 10:10:51 【问题描述】:我正在尝试接受来自客户端(ios 应用)的帖子,但我的代码在读取流时一直失败。说消息不完整。我一直试图让这个工作好几个小时,我的消息格式或其他东西似乎有问题。我要做的只是读取一个字符串,但与我一起做 iOS 部分的开发人员只知道如何发送 multipart/form-data 而不是 content-type json。
这是确切的错误:
MIME 多部分流意外结束。 MIME 多部分消息不完整。”
这里失败了:await Request.Content.ReadAsMultipartAsync(provider);
标题:
POST http://localhost:8603/api/login HTTP/1.1
Host: localhost:8603
Accept-Encoding: gzip,deflate
Content-Type: multipart/form-data; boundary=------------nx-oauth216807
Content-Length: 364
Accept-Language: en-us
Accept: */*
Connection: keep-alive
主体:
--------------nx-oauth216807
Content-Disposition: form-data; name="token"
CAAH5su8bZC1IBAC3Qk4aztKzisZCd2Muc3no4BqVUycnZAFSKuleRU7V9uZCbc8DZCedYQTIFKwJbVZCANJCs4ZCZA654PgA22Nei9KiIMLsGbZBaNQugouuLNafNqIOTs9wDvD61ZA6WSTd73AVtFp9tQ1PmFGz601apUGHSimYZCjLfGBo40EBQ5z6eSMNiFeSylym1pK4PCvI17fXCmOcRix4cs96EBl8ZA1opGKVuWizOsS0WZCMiVGvT
--------------nx-oauth216807--
这里是 WebAPI 代码:
public async Task<HttpResponseMessage> PostFormData()
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
try
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
return Request.CreateResponse(HttpStatusCode.OK);
catch (System.Exception e)
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
【问题讨论】:
5.0 及之前的 Web API 存在一个已知问题,即多部分表单数据请求末尾的额外行会导致 Web API 的多部分解析器出现问题。这个错误在 5.0 之后得到了修复。 传入请求中的“额外行”在哪里?我可以尝试修复该请求。另外,您的意思是 .NET 5.0 吗?我正在使用 .NET 4.5。 我的意思是最后一个边界之后的 CRLF..即--------------nx-oauth216807--
我遇到了同样的错误“读取 MIME 多部分正文部分时出错。”有解决方法吗?还是 web api 2.1 还存在问题?
我无法使用内置解析器来完成这项工作。我必须自己写。
【参考方案1】:
我的应用程序也定期遇到此错误。升级到 WEB API 2.1 什么也没做,异常消息完全没用。
我认为实际发生的情况是大文件令人窒息。在 web.config 中增加我的最大请求限制似乎可以解决问题。
<system.web>
<httpRuntime maxRequestLength="30000" />
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="30000" />
</requestFiltering>
</security>
</system.webServer>
(这将上限设置为 30 兆。将其设置为您需要的任何值。更多信息here)
【讨论】:
这实际上解决了这个问题。异常消息是错误的。谢谢!<httpRuntime maxRequestLength="30000000" />
中的 maxRequestLength 属性应以千字节为单位指定。 30MB 将是 30000。source
我知道这是一个旧答案,但非常感谢。这解决了我已经研究了两个星期的问题。
还设置 executionTimeout 我也遇到了这个错误。 InnerException
是 Cannot access a disposed object.
这意味着在您调用 ReadAsMultipartAsync
之前,有东西正在读取您的流。
在此呼叫Request.Content.ReadAsMultipartAsync(provider)
之前的某个地方,您可以拨打
Request.Content.LoadIntoBufferAsync().Wait()
,这会将这个词组加载到缓冲区中,并允许您多次读取它。
这不是最佳解决方案,但它确实有效。
【讨论】:
我间歇性地遇到一些图像文件的问题,而没有其他问题。不知道问题出在哪里,但效果很好 - 谢谢。【参考方案3】:我把这个留在这里,因为我花了很长时间尝试其他解决方法,直到我遇到了以下有用的答案,并且一些遇到这个问题的人可能会在这篇文章中结束。
需要在请求内容流的末尾附加一个\r\n。
而不是使用这一行来读取数据:
await Request.Content.ReadAsMultipartAsync(provider);
您需要:
将请求流加载到内存
附加所需的\r\n字符串
从内存内容创建流内容
手动将请求头添加到流内容中
最后改用这个:
streamContent.ReadAsMultipartAsync(provider);
在此处查看 Landuber Kassa 的答案以获取完整代码:ASP.NET Web API, unexpected end of MIME multi-part stream when uploading from Flex FileReference
【讨论】:
【参考方案4】:只需修改 Shaw Levin 的答案,以防万一有人想使用它。
boundary = value.Substring(0, value.IndexOf("\r\n"));
将查找 CRLF 的第一次出现,您应该将其更改为 boundary = value.Substring(0, value.LastIndexOf("\r\n"));
以便它查找最后一次出现。否则,如果内容在中间某处包含 CRLF,您将丢失请求中的部分数据。
【讨论】:
【参考方案5】:有类似的错误帖子,对于一些人来说,解决办法是:提到文件上传html控件的Id="",name=""属性,感谢WebAPI upload error. Expected end of MIME multipart stream. MIME multipart message is not complete
但在我的情况下,它并没有通过上述简单的调整来解决:(
【讨论】:
【参考方案6】:我不会推荐这个答案 - 希望现在有更好的方法。
有人问所以这是我的自定义解析器,它一直运行良好:
边界来自这里:
string value;
using (var reader = new StreamReader(tempStream, Encoding.UTF8))
value = reader.ReadToEnd();
// Do something with the value
boundary = value.Substring(0, value.IndexOf("\r\n"));
然后我们在这里解析请求的内容:
public Dictionary<string, BodyContent> ParseContent(string content)
string[] list = content.Split(new string[] boundary , StringSplitOptions.RemoveEmptyEntries);
string name="", val="";
Dictionary<string, BodyContent> temp = new Dictionary<string, BodyContent>();
foreach (String s in list)
if (s == "--" || s == "--\r\n")
//Do nothing.
else
string[] token = s.Split(new string[] "\r\n" , StringSplitOptions.RemoveEmptyEntries);
val = "";
name = "";
foreach (string x in token)
if(x.StartsWith("Content-Disposition"))
//Name
name = x.Substring(x.IndexOf("name=")+5, x.Length - x.IndexOf("name=")-5);
name = name.Replace(@"\","");
name = name.Replace("\"","");
if (x.StartsWith("--"))
break;
if (!x.StartsWith("--") && !x.StartsWith("Content-Disposition"))
val = x;
if (name.Length > 0)
BodyContent b = new BodyContent();
b.content = name;
if (val.Length == 0)
b.value = "";
else
b.value = val;
temp.Add(name, b);
return temp;
【讨论】:
以上是关于WebAPI 无法解析多部分/表单数据帖子的主要内容,如果未能解决你的问题,请参考以下文章
解析Servlet中传入的多部分/表单数据参数的便捷方法[重复]