處理過程
根據(jù)IE的F12中的log提示,是因?yàn)閔ttp頭信息中的編碼替換了html文件中的編碼,。我最初的思路是設(shè)置Tomcat默認(rèn)編碼,,但是我發(fā)現(xiàn)我已經(jīng)在Server.xml中設(shè)置過,想到這里我想到了上篇文章的文件重命名的問題,,準(zhǔn)備去寫個(gè)filter去修改http響應(yīng)頭,,但是我突然明白,SpringMVC應(yīng)該會(huì)處理過,,但是為什么無效呢,,這種成熟的框架不應(yīng)該會(huì)有bug存在,于是我嘗試在SpringMVC的xml中配置SourceHttpMessageConverter等轉(zhuǎn)換器,,都無效,。
發(fā)現(xiàn)原因
后來發(fā)現(xiàn)web.xml是配置了編碼處理的, 內(nèi)容如下:
public static void download(HttpServletRequest request,HttpServletResponse response,String fileName,String downLoadPath,String contentType) throws IOException{ response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); BufferedInputStream bis = null; BufferedOutputStream bos = null; long fileLength = new File(downLoadPath).length(); response.setContentType(contentType); response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"), "ISO8859-1")); response.setHeader("Content-Length", String.valueOf(fileLength)); bis = new BufferedInputStream(new FileInputStream(downLoadPath)); bos = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[2048]; while(-1 != (bytesRead = bis.read(buff, 0, buff.length))){ bos.write(buff, 0, bytesRead); //第二個(gè)工具類中的主要關(guān)鍵代碼: if(request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0){ filename = URLEncoder.encode(name, "UTF-8"); filename = new String(name.getBytes(),"ISO8859-1"); response.setHeader("Content-Disposition", "attachment;filename=" + filename);
為了知道這樣子到底會(huì)有什么問題,,是不是只有IE會(huì)出現(xiàn)問題,,其他瀏覽器會(huì)不會(huì)有其他的問題,。抱著這些疑問,我找來了目前市面上用戶量較多的幾款主流的瀏覽器進(jìn)行測(cè)試,,包括:兩個(gè)不同版本的IE11,,Chrome,F(xiàn)ireFox,,Opera,,360瀏覽器,搜狗瀏覽器等,。經(jīng)過我對(duì)下載的文件的各種文件名稱使勁地折騰主要發(fā)現(xiàn)以下幾個(gè)問題:
1.兩個(gè)IE11在使用第一個(gè)方法下載文件時(shí)中文文件名都會(huì)亂碼,,而使用第二個(gè)方法下載時(shí)其中一個(gè)IE11中文不會(huì)亂碼,另一個(gè)IE11則會(huì)亂碼,;
2.文件名中存在空格時(shí)兩個(gè)IE11瀏覽器下載下來文件文件名空格會(huì)變成+號(hào),,其他瀏覽器沒有這個(gè)問題;
3.火狐瀏覽器下載時(shí)遇到文件名中有空格時(shí)下載下來的文件的文件名第一個(gè)空格后面的文字都會(huì)丟失,。
經(jīng)過一番折騰發(fā)現(xiàn)原來我們大國產(chǎn)瀏覽器還是可以的,,沒有發(fā)現(xiàn)明顯的問題;233333,。
那么這些問題該如何解決呢,?首先第一個(gè)問題,顯然第一段代碼并沒有將IE瀏覽器過濾出來對(duì)文件名進(jìn)行單獨(dú)編碼,,而是統(tǒng)一采用ISO8859-1編碼,,這樣如果文件名是英文的IE就不會(huì)出現(xiàn)任何問題,中文就會(huì)出現(xiàn)亂碼,,其他語言文字則不清楚,,其他幾款瀏覽器則沒有任何問題,都能兼容,。那第二段代碼則首先對(duì)Http請(qǐng)求頭中User-Agent參數(shù)進(jìn)行了判斷,,通過MISE字段將IE瀏覽器過濾出來,對(duì)文件名進(jìn)行單獨(dú)UTF-8編碼,,所以中文文件名不會(huì)亂碼了,。那么問題來了,為什么兩個(gè)IE11瀏覽器,,其中一個(gè)中文不亂碼,,而另一個(gè)卻亂碼呢。經(jīng)過對(duì)程序的單步調(diào)試,,發(fā)現(xiàn)那個(gè)中文亂碼的IE在進(jìn)入這個(gè)方法后程序并沒有跳入對(duì)文件名進(jìn)行utf-8編碼的方法,,而是進(jìn)入了else下面的那一行代碼。那也就是說兩個(gè)IE11的User-Agent參數(shù)中,其中一個(gè)有MISE關(guān)鍵字,,而另一個(gè)則沒有,。通過查閱資料,原來微軟在IE11之后在瀏覽器的User-Agent參數(shù)中去掉了MISE關(guān)鍵字,,導(dǎo)致的結(jié)果是使用低版本的IE下載中文文件名文件時(shí)不會(huì)亂碼,,而采用大部分IE11及以上版本,包括Edge等都會(huì)出現(xiàn)中文亂碼現(xiàn)象,。難怪大家老是說IE很坑呢,,IE在這種地方都埋好了坑,,等著我們?nèi)ゲ?,我也是醉了?nbsp;
瀏覽器的User-Agent這個(gè)參數(shù)主要包含了一些操作系統(tǒng)版本,瀏覽器版本,、內(nèi)核等信息,。
那個(gè)下載文件中文會(huì)亂碼的IE的User-Agent參數(shù)如下:
IE11:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko;
顯然里面并沒有MISE關(guān)鍵字,,那么怎么辦呢,?通過對(duì)比幾款不同瀏覽器的User-Agent參數(shù),發(fā)現(xiàn)這里面有一個(gè)Trident關(guān)鍵字比較特別,,是其他瀏覽器所沒有的,,那么解決方案來了,我們可以通過Trident關(guān)鍵字來進(jìn)行對(duì)部分IE11的過濾了,;
那么針對(duì)第二個(gè)問題中出現(xiàn)的空格變+號(hào),,則是因?yàn)閁RLEncoder函數(shù)在對(duì)字符串進(jìn)行轉(zhuǎn)碼后將空格替換成了+號(hào),IE就直接把+號(hào)顯示出來了,,解決方法是在對(duì)文件名進(jìn)行轉(zhuǎn)碼后,,使用replace方法將+號(hào)替換為%20即可,瀏覽器會(huì)將%20轉(zhuǎn)換成空格輸出,。
對(duì)于第三個(gè)問題則是因?yàn)榇a在set響應(yīng)頭時(shí)Content-Disposition參數(shù)的attachment;filename=等號(hào)后面文件名字符串沒有用雙引號(hào)括起來,,火狐瀏覽器對(duì)于遇到文件名有空格時(shí)認(rèn)為空格前的字符是一個(gè)完整的字符串,故下載下來文件時(shí)文件名就只剩下空格前的那幾個(gè)字了,。解決方法是在filename兩邊加上雙引號(hào)并加反斜杠轉(zhuǎn)義,。具體的最終解決這些問題后經(jīng)過測(cè)試兼容性比較好的代碼如下:
public static void download(HttpServletRequest request, HttpServletResponse response, String fileName, String downLoadPath, String contenType) throws Exception { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); BufferedInputStream bis = null; BufferedOutputStream bos = null; long fileLength = new File(downLoadPath).length(); response.setContentType(contenType); String header = request.getHeader("User-Agent").toUpperCase(); if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) { fileName = URLEncoder.encode(fileName, "utf-8"); fileName = fileName.replace("+", "%20"); //IE下載文件名空格變+號(hào)問題 fileName = new String(fileName.getBytes(), "ISO8859-1"); response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "\""); response.setHeader("Content-Length", String.valueOf(fileLength)); bis = new BufferedInputStream(new FileInputStream(downLoadPath)); bos = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[2048]; while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead);
或者,使用下面這段代碼也可以處理亂問題,,代碼如下:
String fileName = attachmentFile.originalName(); String userAgent = request.getHeader("user-agent").toLowerCase(); if (userAgent.contains("msie") || userAgent.contains("like gecko") ) { // win10 ie edge 瀏覽器 和其他系統(tǒng)的ie fileName = URLEncoder.encode(fileName, "UTF-8"); fileName = new String(fileName.getBytes("utf-8"), "iso-8859-1"); response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); String path = attachmentFile.path(); InputStream inputStream = new FileInputStream(new File(path)); OutputStream os = response.getOutputStream(); byte[] b = new byte[2048]; while ((length = inputStream.read(b)) > 0) { } catch (FileNotFoundException e) { } catch (IOException e) {
本文轉(zhuǎn)載別人文章,有侵權(quán)什么問題,,聯(lián)系及時(shí)處理,。
|