Web 下载文件名乱码解决以及多浏览器兼容方案

发布时间 2023-04-20 10:43:33作者: DHclly

在 web 开发中,经常我们会遇到如导出或者下载网页这种需求,但是往往会遇到在chrome浏览器下载的文件名正常,但是到 firefox,Safari上却乱码的情况,经过网上的资料多次研究,最终总结出了如下的方法,代码如下:

/// <summary>
/// 浏览器下载文件,完整文件下载,不支持分片下载,为了兼容safari,下载url请保持这个格式,
/// 否则safari下载会乱码:/api/WebFile/DownloadFile/encodeURIComponent(要下载的文件名.txt),即末尾这一段路径为文件名,
/// 如果需要取值则通过[FromRoute]实现
/// </summary>
/// <param name="response">响应</param>
/// <param name="fileName">下载文件名</param>
/// <param name="bodyStream">文件流</param>
/// <returns></returns>
public static async Task DownloadFileAsync(HttpResponse response, string fileName, Stream bodyStream)
{
    //文件名UTF 8 编码
    fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8);
    fileName = fileName.Replace("+", "%20");

    //指定响应类型
    response.ContentType = "application/octet-stream; charset=UTF-8";
    response.Headers.Add("Cache-Control", "no-cache");
    response.Headers.Add("Pragma", "no-cache");
    response.Headers.Add("Content-Disposition", $"attachment;filename={fileName};filename*=utf-8''{fileName};");//不同浏览器只会用自己可以识别的格式
    response.ContentLength = bodyStream.Length;
    await bodyStream.CopyToAsync(response.Body);
    bodyStream.Close();
}

上面是一个帮助类,对外的接口名可以自定义,如 /api/File/Export?fileId=5,然后路由对应的方法实现里面调用上面的方法即可。但是这种方式在Safari浏览器下下载下来的文件名仍然会有乱码,解决办法是把接口定义为 /api/File/Export/图片.png?fileId=5 这种格式,即url末尾段是想要下载的实际文件名即可,注意文件名记得用 js 函数 encodeURIComponent(图片.png) 形式编码,否则文件名带有如 % 字符会报错。这样就能完美下载文件了。