前端传参 + 后端处理文件名乱码
记录解决浏览器下载文件时文件名称乱码问题
1.前端传文件名时,统一使用 encodeURIComponent():
fetch(`/download?filename=${encodeURIComponent('测试文件.txt')}`)
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '测试文件.txt'; // 默认文件名(可选)
a.click();
URL.revokeObjectURL(url);
});
2.后端根据不同浏览器设置对应浏览器的编码规则
@GetMapping("/download")
public ResponseEntity<Resource> downloadFile(
@RequestParam String filename,
HttpServletRequest request) throws UnsupportedEncodingException {
String userAgent = request.getHeader("User-Agent");
String contentDisposition;
// Safari 特殊处理
if (userAgent != null && userAgent.contains("Safari") && !userAgent.contains("Chrome")) {
String safariFixedName = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
contentDisposition = "attachment; filename=\"" + safariFixedName + "\"";
}
// 其他浏览器(RFC 5987)
else {
contentDisposition = "attachment; filename=\"" + filename + "\"; filename*=utf-8''" + filename;
}
return ResponseEntity.ok()
.header("Content-Disposition", contentDisposition)
.body(fileResource);
}
3.测试
1.代码测试
import org.springframework.mock.web.MockHttpServletRequest;
@Test
void testDownloadWithDifferentBrowsers() {
MockHttpServletRequest request = new MockHttpServletRequest();
// 1. Chrome 测试
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
testFilenameHandling(request); // Chrome 应使用 filename*=utf-8'' 格式
// 2. Safari 测试(无 Chrome 字符串)
request.removeHeader("User-Agent");
request.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15");
testFilenameHandling(request); // Safari 应使用 ISO-8859-1 解码
// 3. Firefox 测试
request.removeHeader("User-Agent");
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0");
testFilenameHandling(request); // Firefox 应支持 filename*
// 4. Edge 测试
request.removeHeader("User-Agent");
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0");
testFilenameHandling(request); // Edge 同 Chrome
}
private void testFilenameHandling(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
String filename = "测试文件.txt";
String contentDisposition;
if (userAgent != null && userAgent.contains("Safari") && !userAgent.contains("Chrome")) {
// Safari 特殊处理
contentDisposition = "attachment; filename=\"" +
new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + "\"";
} else {
// Chrome/Firefox/Edge 标准处理
contentDisposition = "attachment; filename=\"" + filename + "\"; filename*=utf-8''" + filename;
}
System.out.println("UA: " + userAgent);
System.out.println("Content-Disposition: " + contentDisposition);
}
2.postman设置Headers
Key: User-Agent
Value: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15
Chrome:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Firefox:
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
根据不同浏览器头设置
注:
1.查看前端传递的参数编码次数
2.根据浏览器返回不同的编码规则
3.测试请求头根据不同浏览器设置,测试名称是否正常