简体   繁体   English

WebAPI无法解析multipart / form-data帖子

[英]WebAPI cannot parse multipart/form-data post

I'm trying to accept a post from a client (iOS app) and my code keeps failing on reading the stream. 我正在尝试接受来自客户端(iOS应用程序)的帖子,而我的代码仍然无法读取流。 Says the message is not complete. 说消息不完整。 I've been trying to get this working for hours it seems like something is wrong in my message format or something. 我一直试图让这个工作好几个小时似乎我的消息格式有些不对劲。 All I'm trying to do is read a string but the developer I'm working with who is doing the iOS part only knows how to send multipart/form-data not content-type json. 我所要做的就是读取一个字符串,但我正在处理iOS开发人员的开发人员只知道如何发送multipart / form-data而不是content-type json。

Here is exact error: 这是确切的错误:

Unexpected end of MIME multipart stream. MIME多部分流的意外结束。 MIME multipart message is not complete." MIME多部分邮件不完整。“

It fails here: await Request.Content.ReadAsMultipartAsync(provider); 它失败了: await Request.Content.ReadAsMultipartAsync(provider);

Headers: 头:

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

Body: 身体:

--------------nx-oauth216807
Content-Disposition: form-data; name="token"

CAAH5su8bZC1IBAC3Qk4aztKzisZCd2Muc3no4BqVUycnZAFSKuleRU7V9uZCbc8DZCedYQTIFKwJbVZCANJCs4ZCZA654PgA22Nei9KiIMLsGbZBaNQugouuLNafNqIOTs9wDvD61ZA6WSTd73AVtFp9tQ1PmFGz601apUGHSimYZCjLfGBo40EBQ5z6eSMNiFeSylym1pK4PCvI17fXCmOcRix4cs96EBl8ZA1opGKVuWizOsS0WZCMiVGvT
--------------nx-oauth216807--

Here is the WebAPI code: 这是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);
        }
    }

My application was experiencing this error periodically too. 我的应用程序也定期遇到此错误。 Upgrading to WEB API 2.1 did nothing and the exception message is completely useless. 升级到WEB API 2.1什么也没做,异常消息完全没用。

I think what was actually happening though is it was choking on large files. 我认为实际发生的事情是它在大文件上窒息。 Increasing my max request limits in web.config seemed to fix it right up. 在web.config中增加我的最大请求限制似乎正好解决了这个问题。

<system.web>
    <httpRuntime maxRequestLength="30000" />
</system.web>

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="30000" />
      </requestFiltering>
    </security>
</system.webServer>

(This sets the ceiling to 30 megs. Set it to whatever you need. More info here ) (这将天花板设置为30兆。将其设置为您需要的任何东西。更多信息在这里

I encountered this error too. 我也遇到了这个错误。 The InnerException is Cannot access a disposed object. InnerExceptionCannot access a disposed object. This means that something is reading your stream before your call to ReadAsMultipartAsync . 这意味着在调用ReadAsMultipartAsync之前有些东西正在读取您的流。
Somewhere before this call Request.Content.ReadAsMultipartAsync(provider) , you can call Request.Content.LoadIntoBufferAsync().Wait() , which will load this tream into a buffer and allow you to read it more than once. 在调用Request.Content.ReadAsMultipartAsync(provider)之前的某个地方,您可以调用Request.Content.LoadIntoBufferAsync().Wait() ,它会将此tream加载到缓冲区并允许您多次读取它。
This is not an optimal solution, but it works. 这不是最佳解决方案,但可行。

I am leaving this here since it took me quite some time trying other workarounds until I bumped onto the following helpful answer and some people having this issue may end up on this post. 我要离开这里,因为我花了很长时间尝试其他解决方法,直到我碰到以下有用的答案,有些人遇到这个问题可能会在这篇文章中结束。

A \\r\\n needs to be appended at the end of request content stream. 需要在请求内容流的末尾追加\\ r \\ n。

Instead of using this line to read the data: 而不是使用此行来读取数据:

await Request.Content.ReadAsMultipartAsync(provider);

You will need to: 你需要:

  1. load the request stream to memory 将请求流加载到内存

  2. append the \\r\\n string that is required 附加所需的\\ r \\ n字符串

  3. create a stream content from the memory content 从内存内容创建流内容

  4. manually add the request headers to the stream content 手动将请求标头添加到流内容

  5. Finally use this instead: 最后用这个代替:

     streamContent.ReadAsMultipartAsync(provider); 

Check the answer of Landuber Kassa here for the complete code: ASP.NET Web API, unexpected end of MIME multi-part stream when uploading from Flex FileReference 在这里查看Landuber Kassa的答案以获取完整的代码: ASP.NET Web API,从Flex FileReference上传时出现的MIME多部分流的意外结束

Just a modification for Shaw Levin answer in case anyone wants to use it. 只是对Shaw Levin的修改,以防有人想要使用它。

boundary = value.Substring(0, value.IndexOf("\\r\\n")); will find the first occurance of the CRLF, you should change it to boundary = value.Substring(0, value.LastIndexOf("\\r\\n")); 将找到CRLF的第一个出现,你应该将它改为boundary = value.Substring(0, value.LastIndexOf("\\r\\n")); so it looks for the last occurance. 所以它寻找最后一次出现。 Otherwise if the content includes a CRLF somewhere in the middle you will lose part of the data in the request. 否则,如果内容在中间某处包含CRLF,您将丢失请求中的部分数据。

There were similar error posts, for some, the solution worked is: to mention Id="", name="" attribute to file upload html control, thanks to WebAPI upload error. 有类似的错误帖子,对于一些人来说,解决方案的工作原理是:提到Id =“”,name =“”属性来文件上传html控件,感谢WebAPI上传错误。 Expected end of MIME multipart stream. MIME多部分流的预期结束。 MIME multipart message is not complete MIME多部分消息未完成

But in my case, it did not resolve with above simple tweak :( 但在我的情况下,它没有解决上述简单的调整:(

I would not recommend this answer - hopefully there is a better way available now. 我不推荐这个答案 - 希望现在有更好的方法。

Someone asked so here is my custom parser which has been working fine: 有人问这是我的自定义解析器,它一直工作正常:

Boundary comes from here: 边界来自这里:

        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"));

And then we parse the content of the request here: 然后我们在这里解析请求的内容:

   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;        
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM