【问题标题】:c# mvc pdf download fails on android chromec# mvc pdf在android chrome上下载失败
【发布时间】:2016-11-09 18:51:59
【问题描述】:

第一次在这里提问,如果我做错了,请告诉我......

我的 C# MVC5 应用程序允许用户下载 pdf 文件。除了在我的安卓手机上,它工作得很好。我正在使用 chrome 并让操作系统处理 PDF。看起来它正在使用 Google Drive 应用程序的内置 PDF 查看器。

当我使用指向文件的直接链接时,它可以正常工作,但是当我通过控制器操作下载它时,它会失败并显示“文件格式无效”。我已将其简化为这个问题的测试用例。

这是我的操作方法:

public ActionResult IndirectTestFile()
{
string filename = "document.pdf";

var disposition = new System.Net.Mime.ContentDisposition("inline") { FileName = filename };
Response.AppendHeader("Content-Disposition", disposition.ToString());

string serverFilename = Server.MapPath("~/files/direct/" + filename);
return File(serverFilename, "application/pdf");
}

还有我的 HTML:

//This fails:
<a href="/report/indirectTestFile">Indirect link to file</a>

//This works:
<a href="/Files/direct/Document.pdf">Direct link to file</a>

我正在使用 Windows(桌面)Chrome 来获取这些请求的标头。

这是直接链接的响应标头:

HTTP/1.1 200 OK
Content-Type: application/pdf
Last-Modified: Thu, 07 Jul 2016 11:46:47 GMT
Accept-Ranges: bytes
ETag: "b8a3dd3d45d8d11:0"
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Thu, 07 Jul 2016 12:33:05 GMT
Content-Length: 51793

以及链接到 MVC 操作的响应标头:

HTTP/1.1 200 OK
Cache-Control: private, s-maxage=0
Content-Type: application/pdf
Server: Microsoft-IIS/10.0
Content-Disposition: inline; filename=document.pdf
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 07 Jul 2016 12:34:09 GMT
Content-Length: 51793

我没有看到任何巨大的差异,但一个可靠地工作,另一个可靠地失败。

这不是一个损坏的下载。如果我在 Windows 上下载“坏”的 PDF 并将其复制到 android 手机,同样的查看器很乐意显示它!

有人看过这个吗?感谢您的帮助。

【问题讨论】:

    标签: c# asp.net-mvc pdf model-view-controller download


    【解决方案1】:

    当我编写 pdf 时,我使用自定义的 PdfResult

    public class PdfResult : FileResult
    {
        private const String DefaultFileName = "file.pdf";
        private readonly Byte[] _byteArray;
    
        public PdfResult(Byte[] byteArray, String fileName = DefaultFileName)
            : base(MediaTypeNames.Application.Pdf)
        {
            _byteArray = byteArray;
            FileDownloadName = fileName;
        }
    
        protected override void WriteFile(HttpResponseBase response) { response.BinaryWrite(_byteArray); }
    }
    

    我会将控制器操作更改为使用 PdfResult,并传入文件的字节。您可以使用 File.ReadAllBytes 获取字节。

    public ActionResult IndirectTestFile()
    {
    string filename = "document.pdf";
    
    var fileBytes = File.ReadAllBytes(Server.MapPath("~/files/direct/" + filename));
    return new PdfResult(fileBytes, filename);
    }
    

    你的第二个链接

    <a href="/Files/direct/Document.pdf">Direct link to file</a>
    

    有效,因为浏览器正在执行直接读取文件的工作。

    【讨论】:

    • 您好 Fran,我尝试了您的代码,但无法判断它是否有效,因为它使用 content-disposition:attachment 强制下载。下载工作正常,可以查看,但不能内联查看。这可以适应内联而不是附件吗?除了将文件加载到流中的不同方式之外,我不确定这里是否有很大区别?
    • 您说浏览器正在直接下载第二个链接 - 据我了解,浏览器正在以完全相同的方式下载两个链接。要么是浏览器同时下载它们,要么是 PDF 查看器。浏览器会下载一个但 PDF 查看器会下载另一个是没有意义的。也许我错了?
    • 我的意思是您的第一个链接将 asp.net mvc 放在中间。带有指向确切文件的 href 的锚标记不会通过控制器操作。因此将解释 a 标签,但浏览器会解释 a 标签。
    • 您是否还需要执行控制器操作?为什么不直接给出文件的链接?
    【解决方案2】:

    对于未来的搜索者:

    我还没有解决这个问题,但我确实找出了原因。查看我的日志,看起来谷歌驱动器/文档应用程序正在处理下载而不是浏览器。请求通过与浏览器不同的用户代理。

    这意味着它发生在不同的会话中。该会话没有登录到网站,所以它没有下载 PDF,而是重定向到登录页面并下载它,并抱怨它不是一个有效的 PDF 文件!这就是它发生的原因。

    我通过从控制器中删除身份验证进行了测试,因此请求不会被重定向,并且 pdf 下载并显示正常。

    我不明白为什么 chrome 自己处理直接下载,而是将控制器链接传递给 google 应用程序。我更改了我的服务器,以便两个请求都传回相同的标头,所以我没有注意到 chrome 如何区分两者之间的差异并以不同的方式对待它们,但确实如此。

    我要么需要弄清楚这一点,要么重新组织我的应用来解决这个问题,但也许这是一个不同的问题。

    感谢 Fran 的想法。

    更新: 我不记得确切的解决方案(很遗憾,就在几周前......),但我认为这是因为我正在重定向到我的控制器操作。例如我会有这样的动作(简化)

        public ActionResult MakePDF(string id)
        {
            // code to create the file removed for clarity.
            return RedirectToAction("IndirectTestFile");
        }
    

    这将生成 PDF 文件并重定向到将其返回给用户的操作。

    所以我像这样切断了重定向

        public ActionResult MakePDF(string id)
        {
            // code to create the file removed for clarity.
            return IndirectTestFile();
        }
    

    这似乎是解决方案 - 无论如何我都在使用这种方法,它对我有用。

    【讨论】:

    • 我也遇到了同样的问题。如果你发现任何东西,你会发布更新吗?我也会继续研究。
    • 所以看起来这是由 Content-Disposition 标头引起的。我已经尝试了各种方法来使它工作,但我没有太多的运气。如果您不尝试内联它,Chrome 只会下载它。
    • 我看到的与 Content-Disposition 的唯一区别是,如果您将其设置为附件,您是在告诉 chrome 下载它,因此它会下载它,因此无需将其传递到 Google 驱动器应用程序。
    • @Danation - 在上面为您添加了更新。我猜如果 android chrome 看到一个指向 PDF 的链接,它会下载它,但如果它看到一个指向 PDF 的重定向,它会关闭它吗?考虑到我原来的帖子,这不太有意义,但我现在就是这么看的。
    猜你喜欢
    • 2016-09-17
    • 2021-05-16
    • 2022-01-24
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2018-11-17
    • 2011-08-05
    • 2016-02-14
    相关资源
    最近更新 更多