Content-Disposition中filename字段的字符編碼技巧[轉]


本文是關於“如何編碼http包的Content-Disposition中的filename字段?”這個問題的又一次探討。這個問題在很久之前被提出來以后,到現在仍然沒有滿意的答案,至少我認為是這樣的,所以今天我再次把這個問題拋出來,附上我的解決辦法。

我編寫了一個基於C++的CGI應用,他可以解析包含特殊字符文件名的文件,比如像這樣:weird # € = { } ; filename.txt。

似乎沒有一種通用方法來搞定HTTP中的Content-Dispostion使之可以在每個瀏覽器中都正常工作,測試的瀏覽器有以下:

  •    Internet Explorer
  •    Firefox
  •    Chrome
  •    Opera
  •    Safari

不過我倒是很樂意針對不同的瀏覽器用不同的辦法來編碼。

下面就說說我采用的辦法:

Internet Explorer(添加雙引號並且替換#和;符號):

Content-Disposition: attachment; filename="weird %23 € = { } %3B filename.txt"

Firefox(雙引號仍然有用,無需其他改動):

Content-Disposition: attachment; filename="weird # € = { } ; filename.txt"

另有一種可行的替代方案:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

Chrome:

只用雙引號的時候會出現下面這些問題:

  1. 文件名中的=符號會丟失
  2. €會被替換成-符號

用這種辦法就能搞定了:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

Opera:

用雙引號或者語法:filename*=UTF-8”,會產生下面這些問題:

  1. 文件名中的多個連續空格只剩下一個
  2. 成對的{}丟失:”ab{}cd.txt” -> “abcd.txt”
  3. 文件名中的分號會截斷后面的字符:”abc ; def.txt” -> “abc”

這是由於文件名長度限制造成的,下面的例子可以在Opera中工作:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

Safari:

如果用雙引號,€符號會被替換成不可見字符,很遺憾沒有合適的辦法來解決這個小問題。

但是從上面提到的那個問題原文中得到一個可以參考的辦法:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt

但是這個方案對我來說沒有用,這些轉義字符沒辦法被正確的還原所以瀏覽器嘗試了用cgi應用的名稱來保存文件。造成這個問題的原因是我采用的編碼方式不正確。我沒有按照RFC 5987的原則來編碼。不過Safari也同樣沒有采用這種編碼方式。所以只能說€字符的編碼方法暫時無解了。

順便提一下,一個UTF-8編碼轉換器:http://www.rishida.net/tools/conversion/

上文提到的所有測試均用了當前最新版本的瀏覽器:

  •     Firefox 7
  •     Internet Explorer 9
  •     Chrome 15
  •    Opera 11.5
  •     Safari 5.1

PS:我嘗試過鍵盤上所有的特殊字符,但是被我提到的是那些會造成問題的字符。

我順便嘗試了下在文件名中同時包含所有可能出現的特殊字符,測試結果和上面提到的不太一樣:

完整的測試字符串:

0!§ $%&()=`´{}  []²³@€µ^°~+' # - _ . , ; ü ä ö ß 9.jpg

編碼后:

0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg

Content-Disposition用這種方式來寫:

Content-Disposition: attachment; filename*=UTF-8''0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg

得到了如下測試結果:

火狐可以正常工作

Chrome可以正常工作

IE顯示:$ % & ( ) = ` ´ { } [ ] ² ³ @ € µ ^ ° ~ + ‘ # – _ . , ; ü ä ö ß 9.jpg 丟失了頭6個字符

解釋下:出現這個問題是因為瀏覽器對文件名字符長度的限制造成的:從字符串的開頭舍棄一些字符。我沒有深入挖掘這一點,不過正常的文件名大約可以長達大概200個字符,那些文件名包含許多轉義字符序列的長度甚至可以更多,但是不超過250個字符。所以說這個其實沒啥問題。

Opera:0 ! § $ % & ( ) = ` ´ [ ] ² ³ @ € µ ^ ° ~ + ‘ # – _ . , ; ü ä ö ß 9.jpg 和IE中的那樣也丟失了一些字符。

說明:我縮減過我的測試字符串,因為我懷疑Opera中也有像IE那樣的長度限制問題。

Safari中這種編碼無法正常使用。

測試到現在說明一個事實:形如“filename*=UTF-8”filname escape sequence”這樣的語法可在除了safari外的其他瀏覽器中正常工作。但是在Safari中用這種方法也只有€會被替換掉。所以這個問題不大。

 

關於文件名長度:

測試中發現了一些文件名長度的問題。

在Internet Explorer中:文件名長度最多可以長達147個字符。如果字符串中沒有出現轉移字符的話,這就是文件名的總長度了。如果字符串中出現了轉移字符,情況就有些變化。最終的文件名長度小於147個字符。但是規則有點奇怪,我找不出一個准確的規則。如果我用了兩個轉義字符,文件名縮短了5個字符長度,但是我用很多轉義字符的話文件名最終只縮短了兩個字符。

其他瀏覽器沒有這個長度限制問題。只要系統能夠處理這個文件,它就能順利保存這個文件。我測試了下250個字符長度的文件名,chrome提示我要縮減文件名長度,opera會自動縮減到220個字符,火狐自動縮減為210個字符。Opera會從文件名末尾開始縮減。Safari嘗試保存那么長的文件名,但是處理失敗無法保存,同時在下載列表的文件名中會顯示成-1。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM