下载时会通过添加header
Content-Disposition: attachment;filename=xxx
来达到浏览器弹窗下载。
然后根据rfc2616,要求header使用iso-8859-1进行编码,于是遇到中文后一般会发生这种情况
String fname="中文";
String header=new String(fname.getBytes("UTF-8"),"ISO-8859-1");
response.addHeader("Content-Disposition: attachment;filename="+header);
因为rfc2616没有把Content-Disposition添加进标准中,所以各个浏览器对这个header的实现各不相同,
低版本IE:
request-->服务器编码文件名(一般UTF8)-->ISO-8859-1
response-->ISO-8859-1-->本机编码(中文系统就是GBK)
Chrome:
response-->ISO-8859-1-->UTF-8
这样的话Chrome就貌似正常了,但是如果服务器的编码是GBK,照样扑街。
对此,一般是在服务器编码header的时候根据UA分别编码。
后来RFC6266发布,将Content-Disposition添加到header标准,语法
content-disposition = "Content-Disposition" ":"
disposition-type *( ";" disposition-parm )
disposition-type = "inline" | "attachment" | disp-ext-type
; case-insensitive
disp-ext-type = token
disposition-parm = filename-parm | disp-ext-parm
filename-parm = "filename" "=" value
| "filename*" "=" ext-value
disp-ext-parm = token "=" value
| ext-token "=" ext-value
ext-token = <the characters in token, followed by "*">
Defined in [RFC2616]:
token = <token, defined in [RFC2616], Section 2.2>
quoted-string = <quoted-string, defined in [RFC2616], Section 2.2>
value = <value, defined in [RFC2616], Section 3.6>
; token | quoted-string
Defined in [RFC5987]:
ext-value = <ext-value, defined in [RFC5987], Section 3.2>
同时给出一个兼容性方案
Content-Disposition:attachment;filename="8859-1编码的文件名";filename*=utf-8''UTF8编码的文件名
这是因为旧版本浏览器只识别
filename
而新版本浏览器会使用
filename*
忽略其他部分。
如此一来,不在需要根据UA,只需要直接同时提交2种编码文件名,新旧浏览器直接支持,同时也是符合http协议
ByteArrayOutputStream boas = null;
HttpHeaders header = new HttpHeaders();
String filename = "明细清单.xls";
String filename8859 = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
String filenameutf8 = null;
try {
filenameutf8 = URLEncoder.encode(filename, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
header.add("Content-Type", "application/vnd.ms-excel");
header.add("Content-Disposition", "attachment;filename=" + filename8859 + ";filename*=utf-8''" + filenameutf8);
return new ResponseEntity<>(boas.toByteArray(), header, HttpStatus.OK);