解決IE瀏覽器下載文件,文件名亂碼問題(瀏覽器歷史介紹)


這個問題,CS開發模式總會遇到過。在此詳細記錄,以作技能儲備

 

先說段歷史故事:


史前世界:1945~1994年    有一位美國科學家叫Vannevar Bush3在1945年虛構出來了一台名為Memex的桌面設備作為Web理念最早期的原型。這個Memex呢,用於在微縮膠卷上創建和標注跨文檔鏈接,並按照這些鏈接而跳轉切換到所引用的其他微縮膠卷上,使用方式大略類似於我們現在的書簽和超鏈接。

他超級興奮,認為這將革命性地改變知識管理和數據挖掘;

在當時,一直到20世紀90年代初期,挺多的人覺得這種想法非常的愚笨天真可笑。

 

20世紀60年代,誕生了IBM的GML(Generalized Markup Language,通用標記語言),它用可供機器讀取識別的指令作為文檔的標識符,以標志每段文本的功用,可以明確地指明“這里是文檔的頭部”,“這里是幾個列表項目”諸如此類。

 

在此后經過20多年的發展,GML(一開始只是用在一些IBM笨重大型機的文本編輯器里)逐漸演變成SGML(Standard Generalized Markup Language,標准通用標記語言)。SGML語言更通用靈活,它把GML原來基於冒號和句號的笨拙語法,改成了我們熟悉的尖括號格式的語法。

 

又過10年之后,有兩位科研人員,Tim Berners-Lee 和Dan Connolly 開始尋找新的跨域引用方案—這個方案必須非常簡潔明了。他們草擬了HTML(HyperText Markup Language,超文本標記語言),Html是一套繼承自SGML的精簡版語言。隨后他們又進而開發了HTTP協議(HyperText Transfer Protocol ,超文本傳輸協議)

 

他們研究工作的總成果就是這個誕生於 1991~1993之間由Tim Berners-Lee開發的World Wide Web 程序,這個最原始狀態的瀏覽器可以解析HTML文件,還可以把用戶提交的數據顯示出來,並且只需要點擊一下鼠標,就可以在不同頁面之間切換瀏覽。

 

 
很多人都覺得HTTP 和HTML 的設計簡直是個巨大的倒退。畢竟,很多早期的構想都鼓吹自己包含數據庫整合、安全和數字版權管理,或者整合了內容編輯和出版。
然而,因為HTTP和HTML的門檻低,即時可用,擴展性不受限制(正好與那時計算機的運算能力越來越強,價錢更為人接受,互聯網也開始普及的時機相吻合),原先毫不起眼的WWW項目突然演變成一波熱潮。
 
1993年Mosaic瀏覽器登場了,它由美國伊利諾伊大學(University of Illinois)開發,是第一款廣泛使用的、成熟的Web瀏覽器。
Mosaic 擴展了原先World Wide Web 的代碼,增加的功能包括:在HTML文檔里添加內嵌的圖像,通過表單提交數據,奠定了今天交互式和多媒體應用的基礎。
 
Mosaic 是 另外兩個瀏覽器的基礎:Mosaic Netscape(后來改名為 Netscape Navigator )和Spyglass Mosaic(后來被微軟收購並改名為 Internet Explorer ),同時期還有好幾種非Mosaic引擎的產品瀏覽器,例如挪威的Opera。
 
1994年,為了解決開發上日益混亂的場面和管理HTML的升級擴展,Tim Berners-Lee和一群資助的公司創建了W3C理事會

W3C 成立原因:

       瀏覽器開發商之間的這場軍備競賽主要體現在各競爭產品都在非常快速地開發迭代,以及瘋狂加入各種新功能,也就完全無法顧及產品是否符合規范標准,甚至來不及用正兒八經的文檔記錄下各種新代碼新功能。對核心HTML特性的擅自調整包括各種蠢事(如閃爍的文字,這是Netscape的發明創造,但最終淪為笑柄)乃至一些著名的特性,如可更換字樣(Typeface)或可以在所謂的框架(Frame)里嵌入外部文檔。在各瀏覽器廠商的產品里,往往還內置對自家編程語言(如JavaScript和Visual Basic)支持,以及可在用戶機器上執行跨平台Java或Flash小程序的插件,支持有用但頗詭異的各種HTTP擴展(如Cookie)。這一階段的瀏覽器盡管囿於某些專利和商標上的原因,彼此間會有兼容性問題,但這些不兼容大都還比較表面。

      隨着Web的日益發展壯大和百花齊放,一種隱秘的惡疾悄然在瀏覽器引擎之間傳播開來,盡管表面上還勉強維持着兼容性。這么做最開始的理由聽上去還蠻合情合理的:如果瀏覽器A可以正常顯示一個有問題的頁面,而瀏覽器B卻拒絕解析這個頁面(無論基於何種原因),用戶肯定會認為這是瀏覽器B有問題,而一股腦地選擇貌似更強大的瀏覽器A。為了確保瀏覽器可以正確地顯示任何網頁,工程師的開發變得越來越復雜,也沒有什么正式的文檔來描述瀏覽器對於網站管理員胡亂提供的網頁,是怎么進行主動猜測解析的,而在這些處理過程中往往會犧牲掉安全性,偶爾也會累及兼容性。遺憾的是,這樣的變動往往又會進一步縱容各種不靠譜的網頁設計觀念,迫使其他瀏覽器開發商為免掉隊,也只能亦步亦趨地跟進。當然,相關規范標准的細節缺失,更新也不及時,更是助長了這種惡疾的蔓延。

 

第一次瀏覽器大戰:1995~1999年

網景導航者 Netscape Navigator:

1994公布0.9版,修改后發布1.0版本;

1996年網景的占有率達到70%的高峰。

 
網絡探路者 Internet Explorer

1995年發布IE1;

1996年,Windows操作系統綁定安裝了IE瀏覽器,開始占領市場;

2002年IE擁有了95%的市場份額。

IE完勝。

 


平淡期 2000~2003年

Netscape Navigator退出市場

同時壟斷也滋生了自滿,微軟處於無敵地位之后就完全缺乏動力去改進自己的瀏覽器。

雖然有很多漏洞和安全問題,但其他勢單力孤的瀏覽器廠商難帶來什么翻天覆地的變化。

另一方面,緩慢的開發進展使W3C得以追上瀏覽器的實際狀況,並認真探索未來Web的一些新概念。

XMLHttpRequest微軟推出的一個頗不起眼的專有API,沒想到現在卻如此的大放異彩。

 


第二次瀏覽器大戰:2004年至今

2004年,瀏覽器舞台上出現了一位新選手:

Mozilla Firefox 的圖像結果

Mozilla Firefox(原網景公司Navigator瀏覽器的后裔,由開源社區開發)它針對的正是IE糟糕的安全性和與標准的不兼容性。在獲得IT專欄作家和安全專家的普遍肯定后,Firefox 很快獲得了20%的市場份額。盡管這位后來者很快也被證明和微軟瀏覽器一樣,受到各種安全漏洞困擾,但由於Firefox的開源特性,以及無需迎合頑固的企業用戶,使它的問題修復較為迅速及時。

注意:為什么瀏覽器開發領域里的競爭如此激烈呢?嚴格來說,瀏覽器的市場份額並沒有辦法直接轉化成金錢收入。但專家們認為這關乎權勢地位:因為可以通過瀏覽器來捆綁、推銷或邊緣化某個在線服務(即使像默認搜索引擎這么簡單的服務),也就是說誰控制了瀏覽器,誰就控制了互聯網。注意 為什么瀏覽器開發領域里的競爭如此激烈呢?嚴格來說,瀏覽器的市場份額並沒有辦法直接轉化成金錢收入。但專家們認為這關乎權勢地位:因為可以通過瀏覽器來捆綁、推銷或邊緣化某個在線服務(即使像默認搜索引擎這么簡單的服務),也就是說誰控制了瀏覽器,誰就控制了互聯網。
       這些事實連同突然殺入市場的蘋果公司瀏覽器Safari和Opera瀏覽器在智能手機領域的步步領先,一定使微軟的高層深覺頭痛不已。他們已經錯失了20世紀90年代互聯網第一波高潮;當然他們不想再犯同樣的錯誤。微軟重新加大了對IE瀏覽器的投入,發布了有極大提升和在某些方面來說更安全的版本,從IE7、8迅速迭代到了IE9。
        好像還嫌事情不夠混亂,由於對W3C理事會在創新性上的不滿,一群參與者創建了一個全新的標准組織,叫網頁超文本技術工作小組(Web Hypertext Application Technology Working Group,WHATWG)來主導HTML5協議的開發,這是對現有標准的第一次整體性和把安全也考慮進去的修訂,但據報道,他們經常由於專利紛爭而沒法和微軟達成一致(所以HTML5在IE中存在不兼容)。

 

 

再說個歷史問題。


首先,根據 HTTP 1.1 協議規范( RFC 2616 Section 4 ), HTTP 消息格式其實是基於古老的 ARPA INTERNET TEXT MESSAGES ( RFC 822 Section 3 ),根據其規定,消息只能是 ASCII 編碼的。 RFC 2616 Section 2.2 又一次強調, TEXT 中若要使用其他字符集,必須使用 RFC 2047 的規則將字符串編碼為 ASCII 碼(事實上這個規則原本是針對 MIME 的擴展,使用的是 base64 編碼,格式與百分號編碼有很大不同)。總而言之,按照標准, HTTP Header 中的文本數據必須是 ASCII 編碼的。

filename="TEXT"
 ;這是 RFC 2616 標准,TEXT必須是 ASCII 字符且被認為就是“原文”
filename*=charset'lang'encoded-text
 ;這是按照 RFC 2047 擴展后的,注意格式上的細微區別,采用 base64 編碼(編碼結果也是 ASCII 字符)
然而,事實上在1999年 HTTP 1.1 標准推出之時, Content-Dispostion 這個 Header 尚不是正式標准的一部分,只不過是因為被廣泛使用而從 MIME 標准中直接借用過來了而已(  RFC 2616 Section 19.5.1  )。因而幾乎沒有瀏覽器去支持 Content-Disposition 的多語言編碼特性這樣一個“擴展特性的擴展特性”(事實上, HTTP 1.1 草案中建議的使用 RFC 2047 來進行多語言編碼的特性從未被主流瀏覽器支持過)。 可是這個問題卻的確是現實需要的,所以瀏覽器就各自想出了一些辦法:
  • IE支持兩種格式的混合版:filename="encoded_text" (這里采用的是百分號編碼)。本來按照 RFC 2616 ,引號內的部分應當直接被當作內容,就算它“看起來像是編碼后的字符串”;可是IE卻會“自動”對這樣的文件名進行解碼——前提是該文件名必須有一個不會被編碼的后綴名(即正常的英文字母后綴名)!
  • 其他一些瀏覽器則支持一種更為粗暴的方式——允許在 filename="TEXT" 中直接使用 UTF-8 編碼的字符串!
這兩類瀏覽器的行為是彼此互不兼容的。所以你可以判斷 UA 然后對IE使用前一種辦法,其他瀏覽器使用后一種,這樣便可以達到一般情況下能夠 just work 的效果( Discuz 就是這么做的)。不過對於 Opera 和 Safari ,這樣做可能不一定有效。 時代在進步,2010年  RFC 5987  發布,正式規定了 HTTP Header 中多語言編碼的處理方式,應當采用類似 MIME 擴展的 parameter*=charset'lang'value 的格式,但是其中 value 應根據  RFC 3986 Section 2.1  使用百分號進行編碼,並且規定瀏覽器至少應該支持 ASCII 和 UTF-8 。隨后,2011年  RFC 6266  發布,正式將 Content-Disposition 納入 HTTP 標准,並再次強調了 RFC 5987 中多語言編碼的方法,還給出了一個 范例 用於解決向后兼容的問題
Content-Disposition: attachment;
                      filename="$encoded_fname";
                      filename*=utf-8''$encoded_fname
在這個例子中,對於較新的 Firefox 、 Chrome 、 Opera 、 Safari 等瀏覽器,都支持新標准規定的 filename* ,並且會優先使用,所以盡管 filename=”encoded_text” 不被它們支持, 仍然不會有問題;至於使用 UTF-8 只是因為它是標准中強制要求必須支持的。而對於舊版本的IE瀏覽器,它們無法識別后面的 filename* ,會自動忽略並使用舊的 filename 。
這樣一來就完美解決了多瀏覽器的多語言兼容問題,既不需要 UA 判斷,也符合標准。
 
正文分隔符

 


 

 

 

問題表現:

兩個完全相同的系統,一個在本機,一個在服務器上。

服務器上的系統,部分IE(版本相同)下載文件名會亂碼。

 

解決思路:

查看了兩次請求的 請求頭 與響應頭

正常請求
 
 
亂碼請求
 
 
   
正常響應
 
 
異常響應
 
 
   

 

發現 User-Agent (用戶代理)不同。

更改判斷IE條件並更改對應的編碼。

 

IE的話,通過URLEncoder對filename進行UTF8編碼。

而其他的瀏覽器(firefox、chrome、safari、opera),則要通過字節轉換成ISO8859-1

 

只需要判斷客戶端是否為IE,然后對filename進行相對應的編碼。

 
if ((request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) || (request.getHeader("User-Agent").contains("Trident"))) {  
    filename = URLEncoder.encode(filename, "UTF-8");  
    System.out.println("IE");
} else {  
    filename = new String(filename.getBytes("UTF-8"), "ISO8859-1"); 
    System.out.println("非IE");
}

  

完畢!

 

 




 


免責聲明!

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



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