中文名文件下載瀏覽器兼容處理
前言
文件下載功能中的文件名處理,這又是個老生長談的問題了,網絡上也有各種解決方式,但可能由于各自項目語言以及編碼不同導致多數方案都不盡如人意,最近又遇到這個問題,姑且根據自己的環境和編碼總結一下
后續觀點都是基于如下環境
- 服務端語言:JAVA
- 項目編碼:GBK
- 應用服務器Resin 3.1
分析
Firefox會截斷空格問題
在Firefox下,如果文件名中有空格,那么空格后面部分的文字會被瀏覽器截取掉,客戶端獲取不到完整的文件名
解決方案:
- 將文件名使用雙引號包裹起來
- 使用 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

浙公網安備 33010602011771號