中文名檔案下載瀏覽器相容處理

逆風之羽發表於2014-03-13

前言

檔案下載功能中的檔名處理,這又是個老生長談的問題了,網路上也有各種解決方式,但可能由於各自專案語言以及編碼不同導致多數方案都不盡如人意,最近又遇到這個問題,姑且根據自己的環境和編碼總結一下

後續觀點都是基於如下環境

  • 服務端語言:JAVA
  • 專案編碼:GBK
  • 應用伺服器Resin 3.1

分析

Firefox會截斷空格問題

在Firefox下,如果檔名中有空格,那麼空格後面部分的文字會被瀏覽器擷取掉,客戶端獲取不到完整的檔名

解決方案:

  1. 將檔名使用雙引號包裹起來
  2. 使用 MimeUtility.encodeWord(filename)方法,將其編碼為“=?gb2312?B?xxxxxxxx?=”格式,其中的空格會被編碼掉,並且Firefox可以識別該格式將其還原為原始的檔名

IE6下請求頭長度有限制,檔名長度只能在150位元組左右

經過測試,IE6下當要下載的檔名長度超過150位元組後,超過部分會被瀏覽器擷取掉(為了保證副檔名完整,瀏覽器會從前面擷取),並且如果是中文還有可能亂碼(應該是由於編碼後再擷取後不能再次還原為中文字元),這個是IE6自身的機制,因此我們只能考慮使用較短的檔名或者自己使用程式碼合理將其擷取

關於亂碼

這一塊我也不是理解的十分透徹,就我的理解簡單分析一下:

首先,大家都知道中文是多位元組字元,由於計算機的基本儲存單元是位元組(byte),而一個byte顯然不能夠表示包括中文在內的所有字元,因此中文、日文等等語言在儲存時都會被編碼為多個位元組儲存到計算機中,然後顯示時在相應解碼顯示即可。

然後,網路傳輸的單位也是位元組,因此java中的字串在傳輸之前如果不進行手工編碼那麼會被預設按照作業系統的編碼格式進行編碼,到客戶端再按照預設格式解碼,如果都是中文環境通常沒有問題,但是如果兩邊的預設編碼不一致就比較容易導致編碼,因此還是建議手動指定特定的編碼和解碼格式。

而對於檔案下載,客戶端不同瀏覽器識別的編碼也不同,但是基本上都識別UTF-8編碼以及ISO-8859-1編碼,後者firefox不能識別,並且如果檔名不是全中文還會導致被截斷,因此我還是選擇採用UTF-8編碼

最後,貼上程式碼

由於其它功能都被拆分出去了,就不貼了,核心部分程式碼都在這裡。

下面的程式碼在IE6-9、firefox、chrome測試都可以正常下載

String us = request.getHeader("user-Agent");
if(ua!=null){
    ua = ua.toLowerCase();
    //IE6擷取檔名避免亂碼
    if(ua.contains("msie 6")){
        //檔名中有空格,encode後會變成+,為讓其正確顯示空格將其替換為%20
     //getSubStr方法是根據位元組數擷取長度超過150位元組後的字元 filename = URLEncoder.encode(getSubStr(filename),"utf-8").replaceAll("\\+","20%"); }else if(ua.contains("firefox")){ //編碼成 =?gb2312?B?xxxxxxxx?=的格式,firefox支援這種格式,這裡儘量指定編碼型別,否則可能解析不了 filename = MimeUtility.encodeWord(filename,"utf-8","B");
response.setHeader("Content-disposition", "attachment; filename=\"+filename+\"");
    }else{
        filename = URLEncoder.encode(filename,"utf-8").replaceAll("\\+","20%");
    }
}

response.setContentType("application/x-download;");
response.addHeader("Content-Disposition",filename)
OutputStream out = response.getOutputStream();
out.write(contents);
out.flush()

 

參考資料:http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http

 

相關文章