【问题标题】:HttpHandler not retaining filenames on downloadHttpHandler 在下载时不保留文件名
【发布时间】:2019-01-13 19:41:10
【问题描述】:

我正在使用 HttpHandler 在我的 ASP.NET Web 应用程序中提供文档。我可以让它很好地解决一个我无法弄清楚的问题——文件名没有保留。

例如,如果我尝试提供一个名为“New Patient Information Form.docx”的文档,并且我的处理程序名为“GetDocument.ashx”,则该文件将作为“GetDocument.docx”和“GetDocument(1)”下载。 docx”、“GetDocument(2).docx”等每次下载文件时。

出于安全原因,我想使用处理程序而不是直接链接到文件。我将实际文档保存在 App_Data 文件夹中,因此无法直接浏览它们。

这是我正在使用的代码。我已经在“附件”和“内联”之间切换了内容配置,但似乎对纠正这个问题没有任何影响。

public void ProcessRequest(HttpContext context)
{
    if (!int.TryParse(context.Request.QueryString["ID"], out var id))
        throw new Exception($"Invalid DocumentID value ({id}).");

    var document = DocumentsHelper.GetByID(id);

    if (document == null)
        throw new Exception($"Invalid DocumentID value ({id}).");

    var documentDownloadDirectory = AppSettingsHelper.DocumentDownloadDirectory(); // "App_Data"

    var filePath = Path.Combine(documentDownloadDirectory, document.Filename);
    var fileBytes = File.ReadAllBytes(filePath);

    // A content disposition of "attachment" will force a "Save or Open" dialog to appear when
    // navigating directly to this URL, and "inline" will just show open the file in the default viewer
    context.Response.AppendHeader("Content-Dispositon", $"attachment; filename={document.Filename}");
    context.Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
    context.Response.ContentType = document.ContentType;
    context.Response.BinaryWrite(fileBytes);
    context.Response.Flush();
}

我的代码中的“文档”对象是一个具有与文档元数据相关的属性(例如文件名、ID 等)的类

我同时使用 Chrome 和 Edge 作为浏览器,并且都表现出相同的行为。有没有办法让 HttpHandler 保留原始文件名?

更新:我用简化的代码创建了一个新项目,试图缩小问题的原因。代码如下:

public class DownloadFile : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var fileName = "NoSpaces.docx";
        var basePath = context.Request.MapPath("~/App_Data");
        var filePath = Path.Combine(basePath, fileName);
        var fileBytes = File.ReadAllBytes(filePath);

        context.Response.AppendHeader("Content-Dispositon", $"attachment; filename={fileName}");
        context.Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
        context.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        context.Response.BinaryWrite(fileBytes);
        context.Response.Flush();
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

文件名不包含空格,浏览器尝试将文件保存为“DownloadFile.ashx”而不是“NoSpaces.docx”。我开始怀疑浏览器是否应该受到指责,因为我最后一次记得这项工作是在 5 月。

【问题讨论】:

  • 对不起,“文件名没有保留”是什么意思?由谁保留?你期望会发生什么?你看到发生了什么?
  • document.Filename 的计算结果是什么?
  • @Flydog57 - 下载的文件与处理程序命名相同,而不是文件名。如果我有一个包含大量指向不同文档的链接的页面,并且用户尝试下载它们,它们的名称都相同。
  • @Griswald - document.Filename 评估为磁盘上文件的名称
  • 抱歉,这个感觉很眼熟,不过是旧工作(所以我不能看笔记)。你玩过Content-Type吗?我很确定您只能使用“附件”的内容配置来使用它

标签: c# asp.net download httphandler


【解决方案1】:

尝试将文件名包含在双引号中,如下所示:

context.Response.AppendHeader("Content-Dispositon", $"attachment; filename=\"{document.Filename}\"");

【讨论】:

  • This 可能对原始发布者有用。
  • 文件名中可能也有空格,所以我删除了它们,但没有区别。我已经使用这样的处理程序很多年了,不明白为什么现在会发生这种情况,我几乎可以肯定这在某一时刻有效。
  • 在添加内容处置标头之前添加 context.Response.Clear()
  • @moshin-mehmood - 这也不起作用。我不相信内容处置规范需要在文件名周围加上引号,即使有空格。
【解决方案2】:

我发现了问题,这完全有道理,为什么所有浏览器的行为方式都一样。我有点惊讶没有其他人发现这个,但它是:

我将“Content-Disposition”拼写为“Content-Dispositon”。它忽略了文件名,因为标题名称不正确。

我将需要检查所有其他处理程序并确保那里的拼写也正确!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    相关资源
    最近更新 更多