IE瀏覽器下載文件中文文件名亂碼問題解決

在web開發工作當中,瀏覽器兼容性問題總是會引來一大波前端攻城獅們的瘋狂吐槽,尤其是IE瀏覽器更是一個神一般的存在,總是讓人頭疼不已。
前段時間用java在做一個文件上傳下載功能時,發現部分IE瀏覽器上下載中文文件名文件時會出現文件名亂碼的現象。經過查看之前調用的兩個文件下載工具類源代碼發現其中一個工具類原來代碼是直接使用ISO8859-1編碼對文件名進行編碼,而另一個工具類則多了一層篩選,通過對瀏覽器請求頭中的User-Agent參數中是否存在MISE關鍵字對進行了判斷,當用戶使用瀏覽器是IE時使用URLEncoder.encode(name,”UTF-8”)函數對文件名進行了編碼,主要代碼如下:

//第一個工具類中的下載方法:
    /**
     * 下載
     * @param request
     * @param response
     * @param fileName
     * @param downLoadPath
     * @param contentType
     * @throws IOException 
     * @throws Exception
     */
    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];
        int bytesRead;
        while(-1 != (bytesRead = bis.read(buff, 0, buff.length))){
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }


//第二個工具類中的主要關鍵代碼:
    String filename = null;
    if(request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0){
        filename = URLEncoder.encode(name, "UTF-8");
    }else{
        filename = new String(name.getBytes(),"ISO8859-1");
    }
    response.setHeader("Content-Disposition", "attachment;filename=" + filename);

爲了知道這樣子到底會有什麼問題,是不是隻有IE會出現問題,其他瀏覽器會不會有其他的問題。抱着這些疑問,我找來了目前市面上用戶量較多的幾款主流的瀏覽器進行測試,包括:兩個不同版本的IE11,Chrome,FireFox,Opera,360瀏覽器,搜狗瀏覽器等。經過我對下載的文件的各種文件名稱使勁地折騰主要發現以下幾個問題:
1.兩個IE11在使用第一個方法下載文件時中文文件名都會亂碼,而使用第二個方法下載時其中一個IE11中文不會亂碼,另一個IE11則會亂碼;
2.文件名中存在空格時兩個IE11瀏覽器下載下來文件文件名空格會變成+號,其他瀏覽器沒有這個問題;
3.火狐瀏覽器下載時遇到文件名中有空格時下載下來的文件的文件名第一個空格後面的文字都會丟失。
經過一番折騰發現原來我們大國產瀏覽器還是可以的,沒有發現明顯的問題;233333。
那麼這些問題該如何解決呢?首先第一個問題,顯然第一段代碼並沒有將IE瀏覽器過濾出來對文件名進行單獨編碼,而是統一採用ISO8859-1編碼,這樣如果文件名是英文的IE就不會出現任何問題,中文就會出現亂碼,其他語言文字則不清楚,其他幾款瀏覽器則沒有任何問題,都能兼容。那第二段代碼則首先對Http請求頭中User-Agent參數進行了判斷,通過MISE字段將IE瀏覽器過濾出來,對文件名進行單獨UTF-8編碼,所以中文文件名不會亂碼了。那麼問題來了,爲什麼兩個IE11瀏覽器,其中一箇中文不亂碼,而另一個卻亂碼呢。經過對程序的單步調試,發現那個中文亂碼的IE在進入這個方法後程序並沒有跳入對文件名進行utf-8編碼的方法,而是進入了else下面的那一行代碼。那也就是說兩個IE11的User-Agent參數中,其中一個有MISE關鍵字,而另一個則沒有。通過查閱資料,原來微軟在IE11之後在瀏覽器的User-Agent參數中去掉了MISE關鍵字,導致的結果是使用低版本的IE下載中文文件名文件時不會亂碼,而採用大部分IE11及以上版本,包括Edge等都會出現中文亂碼現象。難怪大家老是說IE很坑呢,IE在這種地方都埋好了坑,等着我們去踩,我也是醉了。
瀏覽器的User-Agent這個參數主要包含了一些操作系統版本,瀏覽器版本、內核等信息。
那個下載文件中文會亂碼的IE的User-Agent參數如下:
IE11:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko;
顯然裏面並沒有MISE關鍵字,那麼怎麼辦呢?通過對比幾款不同瀏覽器的User-Agent參數,發現這裏面有一個Trident關鍵字比較特別,是其他瀏覽器所沒有的,那麼解決方案來了,我們可以通過Trident關鍵字來進行對部分IE11的過濾了;
那麼針對第二個問題中出現的空格變+號,則是因爲URLEncoder函數在對字符串進行轉碼後將空格替換成了+號,IE就直接把+號顯示出來了,解決方法是在對文件名進行轉碼後,使用replace方法將+號替換爲%20即可,瀏覽器會將%20轉換成空格輸出。
對於第三個問題則是因爲代碼在set響應頭時Content-Disposition參數的attachment;filename=等號後面文件名字符串沒有用雙引號括起來,火狐瀏覽器對於遇到文件名有空格時認爲空格前的字符是一個完整的字符串,故下載下來文件時文件名就只剩下空格前的那幾個字了。解決方法是在filename兩邊加上雙引號並加反斜槓轉義。具體的最終解決這些問題後經過測試兼容性比較好的代碼如下:

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下載文件名空格變+號問題
        } else {
            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];
        int bytesRead;

        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

大家如果遇到類似問題,可以參考!☺☺☺

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章