【问题标题】:WebAPI returns corrupted, incomplete fileWebAPI 返回损坏的、不完整的文件
【发布时间】:2017-07-05 12:07:09
【问题描述】:

我想从 WebApi 端点返回一个图像。这是我的方法:

[System.Web.Http.HttpGet]
public HttpResponseMessage GetAttachment(string id)
{
    string dirPath = HttpContext.Current.Server.MapPath(Constants.ATTACHMENT_FOLDER);
    string path = string.Format($"{dirPath}\\{id}.jpg");

    try
    {
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new FileStream(path, FileMode.Open, FileAccess.Read);

        var content = new StreamContent(stream);
        result.Content = content;
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = Path.GetFileName(path) };
        return result;
    }
    catch (FileNotFoundException ex)
    {
        _log.Warn($"Image {path} was not found on the server.");
        return Request.CreateResponse(HttpStatusCode.NotFound, "Invalid image ID");
    }
}

很遗憾,下载的文件不完整。消费安卓应用的消息是:

java.io.EOFException: 源过早耗尽

【问题讨论】:

  • 在标题中添加content-length 怎么样? result.Content.Headers.Add(@"Content-Length", content.Length.ToString());
  • 那是因为StreamContent不包含Length的定义
  • 正确,但尝试添加标题。
  • 尝试添加标题并且它已经被设置为正确的值。这闻起来像 StreamContent 类中的错误,或者它在某个地方被使用。

标签: c# asp.net-web-api2 httpresponsemessage


【解决方案1】:

问题很可能是您的 Android 客户端认为下载在实际完成之前就已经结束了。
为了轻松解决此问题,您可以改用此方法,它会立即返回整个文件(而不是流式传输):

result.Content = new ByteArrayContent(File.ReadAllBytes(path));

【讨论】:

  • 这几乎值得一票,因为这有多糟糕!如果文件很大,您将开始大量使用内存。这就是为什么我最终要寻找同样问题的答案!
  • @NormanH 这只是一种非常适用于小文件的方法
【解决方案2】:

原来这是由压缩引起的,这是为该控制器中的所有响应设置的。控制器的构造函数中设置了 GZip 编码:

HttpContext.Current.Response.AppendHeader("Content-Encoding", "gzip");
HttpContext.Current.Response.Filter = new GZipStream(HttpContext.Current.Response.Filter, CompressionMode.Compress);

为了解决这个问题,我将这些行添加到我的方法中 (就在try 块开始之后):

// reset encoding and GZip filter
HttpContext.Current.Response.Headers["Content-Encoding"] = "";
HttpContext.Current.Response.Headers["Content-Type"] = "";    
// later content type is set to image/jpeg, and default is application/json
HttpContext.Current.Response.Filter = null;

另外,我正在像这样设置内容类型和长度:

result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
result.Content.Headers.ContentLength = stream.Length;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2021-05-11
    • 1970-01-01
    相关资源
    最近更新 更多