txt亂碼怎么解決 下載的txt文檔顯示亂碼怎么辦



文章插圖
txt亂碼怎么解決 下載的txt文檔顯示亂碼怎么辦

文章插圖
Web 開發過程中,相信大家都遇到過附件下載的場景,其中,各瀏覽器下載后的文件名中文亂碼問題或許一度讓你苦惱不已 。
網上搜索一下,大部分都是通過Request Headers中的UserAgent字段來判斷瀏覽器類型,根據不同的瀏覽器做不同的處理,類似下面的代碼:
// MicroSoft Browserif (agent.contains("msie") || agent.contains("trident") || agent.contains("edge")) {// filename 特殊處理}// firefoxelse if (agent.contains("firefox")) {// filename 特殊處理}// safarielse if (agent.contains("safari")) {// filename 特殊處理}// Chromeelse if (agent.contains("chrome")) {// filename 特殊處理}// 其他else{ // filename 特殊處理}//最后把特殊處理后的文件名放到head里response.setHeader("Content-Disposition","attachment;fileName=" + filename);不過,這樣的代碼看起來很魔幻,為什么每個瀏覽器的處理方式都不一樣?難道每次新出一個瀏覽器都要做兼容嗎?就沒有一個統一標準來約束一下這幫瀏覽器嗎?
帶著這個疑惑,我翻閱了 RFC 文檔,最終得出了一個優雅的解決方案:
// percentEncodedFileName 為百分號編碼后的文件名response.setHeader("Content-disposition","attachment;filename=" + percentEncodedFileName +";filename*=utf-8''" + percentEncodedFileName);經過測試,這段響應頭可以兼容市面上所有主流瀏覽器,由于是 HTTP 協議范疇,所以語言無關 。只要按這個規則設置響應頭,就能一勞永逸地解決惱人的附件名中文亂碼問題 。
接下來課代表帶大家抽絲剝繭,通過閱讀 RFC 文檔,還原一下這個響應頭的產出過程 。
1. Content-Disposition
一切要從 RFC 6266 開始,在這份文檔中,介紹了Content-Disposition響應頭,其實它并不屬于HTTP標準,但是因為使用廣泛,所以在該文檔中進行了約束 。它的語法格式如下:
content-disposition = "Content-Disposition" ":"disposition-type *( ";" disposition-parm )disposition-type= "inline" | "attachment" | disp-ext-type; case-insensitivedisp-ext-type= tokendisposition-parm= filename-parm | disp-ext-parmfilename-parm= "filename" "=" value| "filename*" "=" ext-value其中的disposition-type有兩種:
inline 代表默認處理,一般會在頁面展示attachment 代表應該被保存到本地,需要配合設置filename或filename*
注意到disposition-parm中的filename和filename*,文檔規定:這里的信息可以用于保存的文件名 。
它倆的區別在于,filename 的 value 不進行編碼,而filename*遵從 RFC 5987中定義的編碼規則:
Producers MUST use either the "UTF-8" ([RFC3629]) or the "ISO-8859-1" ([ISO-8859-1]) character set.由于filename*是后來才定義的,許多老的瀏覽器并不支持,所以文檔規定,當二者同時出現在頭字段中時,需要采用filename*,忽略filename 。
至此,響應頭的骨架已經呼之欲出了,摘錄 [RFC 6266] 中的示例如下:
Content-Disposition: attachment;filename="EURO rates";filename*=utf-8''%e2%82%ac%20rates這里對filename*=utf-8”%e2%82%ac%20rates做一下說明,這個寫法乍一看可能會覺得很奇怪,它其實是用單引號作為分隔符,將等號右邊分成了三部分:第一部分是字符集(utf-8),中間部分是語言(未填寫),最后的%e2%82%ac%20rates代表了實際值 。對于這部分的組成,在RFC 2231.section 4 中有詳細說明:
A single quote is used toseparate the character set, language, and actual value information inthe parameter value string, and an percent sign is used to flagoctets encoded in hexadecimal.2.PercentEncode
PercentEncode 又叫 Percent-encoding 或 URL encoding.
正如前文所述,filename*遵守的是[RFC 5987] 中定義的編碼規則,在[RFC 5987] 3.2中定義了必須支持的字符集:
recipients implementing this specificationMUST support the character sets "ISO-8859-1" and "UTF-8".并且在[RFC 5987] 3.2.1規定,百分號編碼遵從 RFC 3986.section 2.1中的定義,摘錄如下:
A percent-encoding mechanism is used to represent a data octet in acomponent when that octet's corresponding character is outside theallowed set or is being used as a delimiter of, or within, thecomponent.A percent-encoded octet is encoded as a charactertriplet, consisting of the percent character "%" followed by the twohexadecimal digits representing that octet's numeric value.Forexample, "%20" is the percent-encoding for the binary octet"00100000" (ABNF: %x20), which in US-ASCII corresponds to the spacecharacter (SP).Section 2.4 describes when percent-encoding anddecoding is applied.注意了,[RFC 3986] 明確規定了空格 會被百分號編碼為%20
而在另一份文檔 RFC 1866.Section 8.2.1