文章插圖

文章插圖
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.PercentEncodePercentEncode 又叫 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
- 豬肉怎么炒嫩
- 兩個pdf怎么合成一個pdf 兩個pdf合成一個pdf怎么合成
- fileupload控件上傳圖片 uploadfile上傳文件怎么上傳
- 羊肉怎么能燉爛
- 蘿卜餡怎么做
- 怎么腌蘿卜好吃_如何腌蘿卜
- 阿里郵箱怎么使用教程 阿里企業郵箱怎么使用
- 與前男友分手后要怎么挽回 感情老師免費咨詢挽回
- 女朋友變心了怎么辦 如何挽回變心的女友
- 分手對方有新歡怎么挽回 女友有新歡了怎么挽回
