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)

【讨论】:

这实际上解决了这个问题。异常消息是错误的。谢谢! &lt;httpRuntime maxRequestLength="30000000" /&gt; 中的 maxRequestLength 属性应以千字节为单位指定。 30MB 将是 30000。source 我知道这是一个旧答案,但非常感谢。这解决了我已经研究了两个星期的问题。 还设置 executionTimeout 并将调试设置为 false 可能会有所帮助。【参考方案2】:

我也遇到了这个错误。 InnerExceptionCannot 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 无法解析多部分/表单数据帖子的主要内容,如果未能解决你的问题,请参考以下文章

解析多部分/表单数据,从请求后接收

MIME::Parser 无法正确解析多部分/混合部分

解析Servlet中传入的多部分/表单数据参数的便捷方法[重复]

如何使用带有 Rocket 的 abonander/multipart 解析多部分表单?

Oracle 表单:TNS:无法解析指定的连接标识符

使用 Python/Pandas 库无法解析来自 JSON 响应的数据