对于从ASP.NET Core2应用程序下载文件,我一直在使用PhysicalFileResult (IActionResult的一个实现)从控制器GET操作返回文件。对于带有“典型”字符的文件名,一切正常。这包括我到目前为止测试过的重音和汉字字符集。
但是,如果文件名包含Emoji ( Windows文件系统允许的字符),则生成的文件名的格式不正确或编码错误。
例如,我期望下面的代码传递一个名为.png的文件,而不是传递一个名为��.png的文件。
public async Task<IActionResult> GetByIdAsync([FromRoute] long id)
{
return PhysicalFile("c:\\file.png", "image/png", ".png");
}为了保留文件名,需要对包含表情符号的文件名进行编码,这是一种特殊的方式,还是PhysicalFileResult有问题
发布于 2018-05-15 06:59:07
实际情况是,您的问题与混乱有关,即HTTP头和Content-Disposition头中更普遍的字符编码。有一个非常古老的堆栈溢出问题: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();
}
}这最终使您从Microsoft.Net.Http.Headers名称空间进入ContentDispositionHeaderValue类。考虑到currently 725 lines of code in this class响应头的复杂性,它们中的大多数都是为了确保返回的值是有效的。
RFC7230指定在标头中除了ASCII码之外没有其他有用的编码:
从历史上看,
允许字段内容包含ISO-8859-1字符集的文本ISO-8859-1,仅通过使用RFC2047编码来支持其他字符集。实际上,大多数HTTP标头字段值只使用US-ASCII字符集USASCII的一个子集。接收者应将字段内容(obs-text)中的其他八位字节视为不透明数据。
最终,可能会看到一些缓解,因为2017年9月的RFC8187提供了澄清,这应该会缓解一些混乱。Issue 2688 filed against HTTP Abstractions涵盖了将此RFC合并到ASP.Net中的需要。
同时,您可以尝试将适当的http编码的文件名插入URI (http://example.com/filedownload/33/%F0%9F%98%80.png),而不是依赖有缺陷的Content-Disposition头来提供文件名建议。
https://stackoverflow.com/questions/50277981
复制相似问题