为了从ASP.NET Core 2应用程序下载文件,我一直在使用PhysicalFileResult
(IActionResult
的实现)从控制器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
标头来建议文件名。需要明确的是,这是一个不完整的修复程序,可能无法在所有客户端上正常工作。