java实现浏览器下载文件,并解决兼容各浏览器的乱码与后缀问题

之前用java写了一个文件流输出文件的功能,测试细节功能的时候,发现了许多问题

一、火狐浏览器下载带中文名字的文件会乱码,其他浏览器不会

1、原因:找了下资料后发现,是火狐使用了RFC 2183协议。

文件名存在http header中的filename,Content-Disposition: attachment; filename=FILENAME,该filename参数可用于为浏览器下载资源的文件的名称提供建议。但是,RFC 2183中声明文件名只能使用US-ASCII字符,目前大多数流行的Web浏览器似乎允许非US-ASCII字符(由于缺乏标准)在编码方案和文件名的字符集规范上不同意。那么问题是,如果文件名“naïvefile”(没有引号和第三个字母是U + 00EF)需要编码到Content-Disposition头文件中。 

2、解决方案:因此只需要在Content-Disposition做下处理即可:重点是filename*=utf-8’zh_cn’

byte[] source = (byte[]) result.get("exportData");
HttpServletResponse response = RequestContextHolder.getRequestAttributes().getResponse();
if (response != null) {
    response.reset();
    response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + URLEncoder.encode("导出文件名.csv", "UTF-8"));
    response.setHeader("Connection", "close");
    response.setHeader("Content-Type", "application/octet-stream");
    OutputStream out = response.getOutputStream();
    out.write(source);
    out.flush();
    out.close();
}

二、ios系统safiri浏览器导出任何类型文件都变成dms后缀类型的文件

原因:header请求中,Content-Type设置application/octet-stream,而该type类型对应Mime 类型列表刚好是dms后缀的文件,所以safiri浏览器就直接将该文件生成为dms后缀的文件了

解决方案:大部分浏览器都可以使用通用类型application/octet-stream,但遇到特殊的如safiri,就最好是生成什么类型的文件,就传对应的tpye

//这里Content-Type传对应的文件类型,参考下面的MIME表
response.setHeader("Content-Type", "text/csv");

另附上Mime 类型列表:

扩展名类型/子类型
 application/octet-stream
323text/h323
acxapplication/internet-property-stream
aiapplication/postscript
aifaudio/x-aiff
aifcaudio/x-aiff
aiffaudio/x-aiff
asfvideo/x-ms-asf
asrvideo/x-ms-asf
asxvideo/x-ms-asf
auaudio/basic
avivideo/x-msvideo
axsapplication/olescript
bastext/plain
bcpioapplication/x-bcpio
binapplication/octet-stream
bmpimage/bmp
ctext/plain
catapplication/vnd.ms-pkiseccat
cdfapplication/x-cdf
cerapplication/x-x509-ca-cert
classapplication/octet-stream
clpapplication/x-msclip
cmximage/x-cmx
codimage/cis-cod
cpioapplication/x-cpio
crdapplication/x-mscardfile
crlapplication/pkix-crl
crtapplication/x-x509-ca-cert
cshapplication/x-csh
csstext/css
dcrapplication/x-director
derapplication/x-x509-ca-cert
dirapplication/x-director
dllapplication/x-msdownload
dmsapplication/octet-stream
docapplication/msword
dotapplication/msword
dviapplication/x-dvi
dxrapplication/x-director
epsapplication/postscript
etxtext/x-setext
evyapplication/envoy
exeapplication/octet-stream
fifapplication/fractals
flrx-world/x-vrml
gifimage/gif
gtarapplication/x-gtar
gzapplication/x-gzip
htext/plain
hdfapplication/x-hdf
hlpapplication/winhlp
hqxapplication/mac-binhex40
htaapplication/hta
htctext/x-component
htmtext/html
htmltext/html
htttext/webviewhtml
icoimage/x-icon
iefimage/ief
iiiapplication/x-iphone
insapplication/x-internet-signup
ispapplication/x-internet-signup
jfifimage/pipeg
jpeimage/jpeg
jpegimage/jpeg
jpgimage/jpeg
jsapplication/x-javascript
latexapplication/x-latex
lhaapplication/octet-stream
lsfvideo/x-la-asf
lsxvideo/x-la-asf
lzhapplication/octet-stream
m13application/x-msmediaview
m14application/x-msmediaview
m3uaudio/x-mpegurl
manapplication/x-troff-man
mdbapplication/x-msaccess
meapplication/x-troff-me
mhtmessage/rfc822
mhtmlmessage/rfc822
midaudio/mid
mnyapplication/x-msmoney
movvideo/quicktime
movievideo/x-sgi-movie
mp2video/mpeg
mp3audio/mpeg
mpavideo/mpeg
mpevideo/mpeg
mpegvideo/mpeg
mpgvideo/mpeg
mppapplication/vnd.ms-project
mpv2video/mpeg
msapplication/x-troff-ms
mvbapplication/x-msmediaview
nwsmessage/rfc822
odaapplication/oda
p10application/pkcs10
p12application/x-pkcs12
p7bapplication/x-pkcs7-certificates
p7capplication/x-pkcs7-mime
p7mapplication/x-pkcs7-mime
p7rapplication/x-pkcs7-certreqresp
p7sapplication/x-pkcs7-signature
pbmimage/x-portable-bitmap
pdfapplication/pdf
pfxapplication/x-pkcs12
pgmimage/x-portable-graymap
pkoapplication/ynd.ms-pkipko
pmaapplication/x-perfmon
pmcapplication/x-perfmon
pmlapplication/x-perfmon
pmrapplication/x-perfmon
pmwapplication/x-perfmon
pnmimage/x-portable-anymap
pot,application/vnd.ms-powerpoint
ppmimage/x-portable-pixmap
ppsapplication/vnd.ms-powerpoint
pptapplication/vnd.ms-powerpoint
prfapplication/pics-rules
psapplication/postscript
pubapplication/x-mspublisher
qtvideo/quicktime
raaudio/x-pn-realaudio
ramaudio/x-pn-realaudio
rasimage/x-cmu-raster
rgbimage/x-rgb
rmiaudio/mid
roffapplication/x-troff
rtfapplication/rtf
rtxtext/richtext
scdapplication/x-msschedule
scttext/scriptlet
setpayapplication/set-payment-initiation
setregapplication/set-registration-initiation
shapplication/x-sh
sharapplication/x-shar
sitapplication/x-stuffit
sndaudio/basic
spcapplication/x-pkcs7-certificates
splapplication/futuresplash
srcapplication/x-wais-source
sstapplication/vnd.ms-pkicertstore
stlapplication/vnd.ms-pkistl
stmtext/html
svgimage/svg+xml
sv4cpioapplication/x-sv4cpio
sv4crcapplication/x-sv4crc
swfapplication/x-shockwave-flash
tapplication/x-troff
tarapplication/x-tar
tclapplication/x-tcl
texapplication/x-tex
texiapplication/x-texinfo
texinfoapplication/x-texinfo
tgzapplication/x-compressed
tifimage/tiff
tiffimage/tiff
trapplication/x-troff
trmapplication/x-msterminal
tsvtext/tab-separated-values
txttext/plain
ulstext/iuls
ustarapplication/x-ustar
vcftext/x-vcard
vrmlx-world/x-vrml
wavaudio/x-wav
wcmapplication/vnd.ms-works
wdbapplication/vnd.ms-works
wksapplication/vnd.ms-works
wmfapplication/x-msmetafile
wpsapplication/vnd.ms-works
wriapplication/x-mswrite
wrlx-world/x-vrml
wrzx-world/x-vrml
xafx-world/x-vrml
xbmimage/x-xbitmap
xlaapplication/vnd.ms-excel
xlcapplication/vnd.ms-excel
xlmapplication/vnd.ms-excel
xlsapplication/vnd.ms-excel
xltapplication/vnd.ms-excel
xlwapplication/vnd.ms-excel
xofx-world/x-vrml
xpmimage/x-xpixmap
xwdimage/x-xwindowdump
zapplication/x-compress
zipapplication/zip
csvtext/csv

三、用GBK编码还是UTF-8?

上面的问题其实还有一个原因,就是中文系统默认编码是GBK的,所以当时生成文件流的时候设置了GBK,但导出的时候却用了UTF-8,所以乱码了。必须使用统一的编码。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos, "GBK"))
...
byte[] source = baos.toByteArray();
baos.close();
return source;

byte[] source = (byte[]) result.get("exportData");
HttpServletResponse response = DataUtils.getResponse();
if (response != null) {
    response.reset();
    //这里设置了utf-8,不一致
    response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'"
                        + URLEncoder.encode(result.get("subject") + ".csv", "UTF-8").replace("+", "%20"));
    response.setHeader("Connection", "close");
    response.setHeader("Content-Type", "text/csv");
    OutputStream out = response.getOutputStream();
    out.write(source);
    out.flush();
    out.close();
}

 

·1、解析:

GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准(好像还不是国家标准)。GBK编码专门用来解决中文编码的,是双字节的。不论中英文都是双字节的。
UTF-8 编码是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8 节省空间。另外,如果是外国人访问你的GBK网页,需要下载中文语言包支持。访问UTF-8编码的网页则不出现这问题。可以直接访问。
GBK包含全部中文字符;UTF-8则包含全世界所有国家需要用到的字符。
经常有人问网页编写UTF-8和GBK哪个编码好,根据个人需要,如果你主要做中文程序的开发,客户也主要是中国人的话就用GBK吧,因为UTF-8编码的中文使用了三个字节,用GBK节省了空间。
如果做英文网站开发,还是用utf-8吧,因为utf-8中英文只占一个字节。GBK中英文也是两个字节的,并且国外客户访问GBK要下载语言包。
如果你的网站是中文的,但国外用户也不少,最好也用UTF-8的吧。

 

UTF-8编码的文字可以在各国各种支持UTF8字符集的浏览器上显示。
比如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,而无需他们下载IE的中文语言支持包。 所以,对于英文比较多的论坛 ,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。
UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛,GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大。

    原文作者:Venlenter
    原文地址: https://blog.csdn.net/asd051377305/article/details/81236619
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞