前言
这是 最近碰到的一个 关于文件下载的一个问题
然后 只有 safari 中出现了 此问题, 大概 可能是 不同的浏览器对于 http 协议的细节支持有所差异吧
大概就是 有一个 服务提供了文件下载的功能, 然后 次服务使用的是 URLEncoder.encode 进行编码了, 然后 大多数 主流浏览器 下载都是正常下载中文名
但是 safari 中下载, 下载的文件名 还是 URLEncoder.encode 编码之后的结果的文件名 然后 造成的问题
测试用例
该测试服务如下, 这里 模拟一下
/**
* downloadTxt
*
* @param response response
* @return void
* @author Jerry.X.He
* @date 2024-09-21 10:56
*/
@GetMapping("/downloadTxt")
public void downloadTxt(HttpServletResponse response) throws Exception {
response.setContentType("application/octet-stream");
// Content-Disposition use URLEncoder.encode
String filename = URLEncoder.encode("下载_2024.txt", "utf8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
// Content-Disposition specify encoding
// String encodedFileName = URLEncoder.encode("下载_2024.txt", "UTF-8").replaceAll("\\+", "%20");
// String contentDispositionValue = "attachment; filename*=UTF-8''" + encodedFileName;
// response.setHeader("Content-Disposition", contentDispositionValue);
try {
OutputStream os = response.getOutputStream();
os.write("1.txt".getBytes());
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
chrome 中下载如下 可以看到 文件名是正常的

safari 中下载如下, 可以看到 是 URLEncoder.encode 之后的结果

问题的解决
在 Content-Disposition 中指定编码, 这样 浏览器支持 RFC 5987 的话, 就可以进行正确的 解码了
String encodedFileName = URLEncoder.encode("下载_2024.txt", "UTF-8").replaceAll("\\+", "%20");
String contentDispositionValue = "attachment; filename*=UTF-8''" + encodedFileName;
response.setHeader("Content-Disposition", contentDispositionValue);

safari 中下载如下, 可以看到 问题解决了

完