【问题标题】:HTTP Upload Corrupts Zip File?HTTP 上传损坏 Zip 文件?
【发布时间】:2014-02-25 14:58:05
【问题描述】:

我有一个 zip 文件,我可以使用 DotNetZipLib 从文件系统中读取该文件。但是,当我通过form 将其发布到我的 MVC 应用程序时,它无法作为流读取。目前我最好的猜测是 HTTP 上传以某种方式破坏了 zip 文件。不乏同样问题的问题,我认为我已经正确解释了流,但也许我没有按预期使用 .NET 对象。

这是我的 WebAPI POST 处理程序:

public void Post(HttpRequestMessage request)
{
    using(var fileData = request.Content.ReadAsStreamAsync().Result)
        if (fileData.Length > 0)
        {
            var zip = ZipFile.Read(fileData); // exception
        }
}

当然,来自 DotNetZipLib ZipFile 的例外只是说不能将流读取为 zip。如果我只用文件的路径替换fileData(这都是在同一台机器上测试的)然后它会读取它,所以它必须是 HTTP 上传。

在 FireBug 中,POST 的标题是:

Response Headers:
    Cache-Control       no-cache
    Content-Length      1100
    Content-Type        application/xml; charset=utf-8
    Date                Sat, 01 Feb 2014 23:18:32 GMT
    Expires             -1
    Pragma              no-cache
    Server              Microsoft-IIS/8.0
    X-AspNet-Version    4.0.30319
    X-Powered-By        ASP.NET
    X-SourceFiles       =?UTF-8?B?QzpcRGF0YVxDb2RlXE9yZ1BvcnRhbFxPcmdQb3J0YWxTZXJ2ZXJcYXBpXGFwcHg=?=

Request Headers
    Accept              text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Encoding     gzip, deflate
    Accept-Language     en-US,en;q=0.5
    Connection          keep-alive
    Cookie              uvts=ENGUn8FXEnEQFeS
    Host                localhost:48257
    Referer             http://localhost:48257/Home/Test
    User-Agent          Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0

Request Headers From Upload Stream
    Content-Length      31817
    Content-Type        multipart/form-data; boundary=---------------------------265001916915724

form 很简单:

<form action="/api/appx" method="post" enctype="multipart/form-data">
    <input name="postedFile" type="file" />
    <input type="submit" />
</form>

我的蒸汽有什么问题吗?从HttpRequestMessage 错误地提取数据?或者也许我应该以完全不同的方式接收上传?

【问题讨论】:

  • 据我所知,您应该对文件使用 HttpPostedFileBase。在这里查看darins的答案:*.com/a/9500609/1026459。这里有可能使用这种方法吗?
  • @TravisJ:这可能确实是要走的路,尽管我在尝试发布时遇到了一个完全不同的错误 (UnsupportedMediaTypeException):"The request entity's media type 'multipart/form-data' is not supported for this resource. No MediaTypeFormatter is available to read an object of type 'HttpPostedFileBase' from content with media type 'multipart/form-data'." 当我之前研究过时,网上的其他各种文章使我采用了目前的方法。 Darin 的回答是针对 MVC 操作,看起来 WebAPI 处理程序可能不同?
  • 你试过IEnumerable&lt;HttpPostedFileBase&gt;吗?也许它是作为 1 的集合发送的。
  • 啊,我明白了,从我读过的多篇文章中,似乎没有为 Web API 设置模型绑定器以支持 HttpPostedFileBase。我遇到的一些建议是使用类似于此答案的方法:*.com/a/13734209/1026459,它建议使用 MultipartFormDataStreamProvider 类 msdn.microsoft.com/en-us/library/…,然后从中获取 MultipartFileData。
  • 我怀疑流可能需要可搜索以进行 zip 读取。尝试将上传内容写入 MemoryStream 并对其进行操作。如果它有效,那么你已经找到了你的问题。

标签: c# asp.net-mvc upload asp.net-web-api zip


【解决方案1】:

当您使用 HTML 表单发布文件时,媒体类型为 multipart/form-data,它具有一些特殊的格式语法,您可以从 Firebug 详细信息中看到。您不能只将其作为流读取并期望它与发送的文件匹配。有一组ReadAsMultipartAsync 扩展方法用于处理这种媒体类型。

【讨论】:

  • 成功了,谢谢!我需要先ReadAsMultipartAsync(),然后在结果的Contents 集合中获取第一个条目和ReadAsStreamAsync()
【解决方案2】:

以下代码适用于 Zip 和文本文件。你可以试试这个

        public HttpStatusCode Post(string fileName)
        {
                    var task = this.Request.Content.ReadAsStreamAsync();
                    task.Wait();
                    Stream requestStream = task.Result;

                    try
                    {
                        Stream fileStream =    File.Create(HttpContext.Current.Server.MapPath("~/" + fileName));
                        requestStream.CopyTo(fileStream);
                        fileStream.Close();
                        requestStream.Close();
                    }
                    catch (IOException)
                    {
                        throw new HttpResponseException(HttpStatusCode.InternalServerError);
                    }

                    HttpResponseMessage response = new HttpResponseMessage();
                    response.StatusCode = HttpStatusCode.Created;
                    return response.StatusCode;

        }

【讨论】:

  • 恐怕同样的错误也会持续存在。我尝试的越多,看起来我真的在与文件流的 WebAPI 模型绑定作斗争。这似乎是一个边缘案例,为了畅通无阻,我可能会将其变成常规 MVC 控制器而不是 WebAPI 控制器。
  • 您是否上传了多个文件,我还没有检查那部分。 Darrel 建议的 ReadAsMultipartAsync 是否解决了您的问题?