为了从ASP.NET Core 2应用程序下载文件,我一直在使用PhysicalFileResultIActionResult的实现)从控制器GET操作返回文件。对于带有“典型”字符的文件名,一切正常。这包括到目前为止我测试过的重音和汉字字符集。

但是,如果文件名包含表情符号(Windows文件系统允许的某种符号),则结果文件名格式错误或编码错误。

例如,我希望下面的代码传递一个名为😀.png的文件,而不是传递一个名为��.png的文件。

public async Task<IActionResult> GetByIdAsync([FromRoute] long id)
{
    return PhysicalFile("c:\\file.png", "image/png", "😀.png");
}


是否有一种特殊的方式需要对包含Emoji表情的文件名进行编码以保留文件名,或者这是PhysicalFileResult的问题?

最佳答案

现实情况是,您的问题与Content-Disposition标头以及HTTP标头中的字符编码的混乱有关。有一个非常古老的堆栈溢出问题:How to encode the filename parameter of Content-Disposition header in HTTP,其日期过早的答案涵盖了很多问题,但让我们对其进行分解。

PhysicalFileResult继承自FileResult,并且在准备返回客户端时由FileResultExecutorBase处理,并且您对该类感兴趣的代码包含在SetContentDispositionHeader方法中:

private static void SetContentDispositionHeader(ActionContext context, FileResult result)
{
    if (!string.IsNullOrEmpty(result.FileDownloadName))
    {
        // From RFC 2183, Sec. 2.3:
        // The sender may want to suggest a filename to be used if the entity is
        // detached and stored in a separate file. If the receiving MUA writes
        // the entity to a file, the suggested filename should be used as a
        // basis for the actual filename, where possible.
        var contentDisposition = new ContentDispositionHeaderValue("attachment");
        contentDisposition.SetHttpFileName(result.FileDownloadName);
        context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
    }
}


最终使您从ContentDispositionHeaderValue命名空间进入类Microsoft.Net.Http.Headers。考虑到HTTP响应标头的复杂性质,其中大多数用于确保返回的值有效。

RFC7230指定在标头中,除了ASCII外没有有用的编码:


  历史上,HTTP允许字段内容中包含文本
  ISO-8859-1字符集[ISO-8859-1],仅支持其他字符集
  通过使用[RFC2047]编码。实际上,大多数HTTP标头字段
  值仅使用US-ASCII字符集[USASCII]的子集。新
  定义的标头字段应将其字段值限制为US-ASCII
  八位位组。接收者应在字段内容中对待其他八位位组
  (obs-text)作为不透明数据。


最终,随着2017年9月的currently 725 lines of code in this class的澄清,可能会减轻一些麻烦。 RFC8187涵盖了将该RFC合并到ASP.Net中的需求。

同时,您可以尝试将适当的http编码的文件名插入URI(http://example.com/filedownload/33/%F0%9F%98%80.png)中,而不是依赖有缺陷的Content-Disposition标头来建议文件名。需要明确的是,这是一个不完整的修复程序,可能无法在所有客户端上正常工作。

09-20 06:15