SpringBoot文件下载

总结摘要
SpringBoot文件下载

背景

HTTP头部默认只支持ISO-8859-1字符集,直接使用中文会导致乱码或解析错误。

文件下载响应体方案

1
2
3
4
5
6
7
8
9
String fileName =  fileNameStrMayBeZhCn + ".xlsx";
fileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");;
byte[] bytes = myservice.exportExcelFile();
return ResponseEntity.status(HttpStatus.OK)
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .header(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + fileName + "\";filename*=utf-8''"+fileName)
        .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(bytes.length))
        .body(bytes);

描述

  1. 使用URLEncoder.encode()对文件名进行UTF-8编码,替换"+“为”%20"以解决URL编码中的空格问题。
  2. Content-Disposition头:同时设置了普通格式和RFC 5987格式(filename*)以兼容不同浏览器。同时提供两种格式(filename和filename*)确保了最大兼容性,符合RFC 6266和RFC 5987标准。
  3. 双引号在绝大多数情况下无副作用,且能避免解析问题。唯一需要警惕的是文件名本身含双引号的情况(需转义)。

中文文件名称乱码无效解决方案

如下方案实测无效,依然乱码。

更现代的解决方案是直接使用RFC 5987标准。

1
2
response.setHeader("Content-Disposition",
				"attachment;filename="+new String(fileName).getBytes("UTF-8"),"ISO8859-1");

描述

  • HTTP头部默认只支持ISO-8859-1字符集,直接使用中文会导致乱码或解析错误。
  • 先将文件名转换为UTF-8编码的字节数组,然后使用ISO-8859-1编码重新构造字符串。
  • 中文字符不在 ISO-8859-1 的字符集范围内,因此无法有效编码中文字符。
  • 为什么这段代码可能“看似”工作?部分浏览器会尝试自动修复。某些浏览器(如 Chrome、Firefox)会检测到 Content-Disposition 头的乱码,并尝试用 UTF-8 重新解码,因此可能“侥幸”显示正确文件名。

END