通常HTTP消息包括客戶機向服務(wù)器的請求消息和服務(wù)器向客戶機的響應(yīng)消息,今天來講解下正確處理下載文件時HTTP頭的編碼問題,需要的朋友可以參考下" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java如何正確處理下載文件時HTTP頭的編碼問題

 更新時間:2023年07月03日 11:43:58   作者:今夜無風(fēng)亦無雨  
這篇文章主要介紹了Java如何正確處理下載文件時HTTP頭的編碼問題,
通常HTTP消息包括客戶機向服務(wù)器的請求消息和服務(wù)器向客戶機的響應(yīng)消息,今天來講解下正確處理下載文件時HTTP頭的編碼問題,需要的朋友可以參考下

最近在做項目時遇到了一個 case :需要實現(xiàn)一個強制下載功能(即強制彈出下載對話框),并且文件名必須保持和用戶之前上傳時相同(可能包含非 ASCII 字符)。

前一個需求很容易實現(xiàn):使用 HTTPHeader的Content-Disposition: attachment即可,還可以配合Content-Type: application/octet-stream來確保萬無一失。而后一個需求就比較蛋疼了,牽扯到 Header 的編碼問題(文件名是作為 filename 參數(shù)放在 Content-Disposition 里面的)。眾所周知, HTTP Header 中的 Content-Type 可以指定內(nèi)容的編碼,可 Header 本身的編碼又該如何制定?甚至, Header 究竟是否允許非 ASCII 編碼呢?

如果放任編碼問題不管,那么恭喜你,你一定會遇到在某個系統(tǒng)及瀏覽器下下載文件時文件名亂碼的情況。如果你嘗試搜索解決,那么再一次恭喜你,你會找到一堆自相矛盾的解決方案(我可以負責任地告訴你,其中的99%都是不符合標準的 trick 罷了)。讓我們來看看到底應(yīng)該如何優(yōu)雅完美地解決這個問題吧!

為了探索這個問題,我走了不少彎路。從自己嘗試,到 Google 、百度(分別嘗試過中英文搜索),再到閱讀 Discuz 等經(jīng)典項目的源碼,眾說紛紜、莫衷一是。最后我才想到回歸 RFC ,從標準文檔中找辦法,果然有所收獲。由于探究過程實在太曲折,我就先把標準做法寫下來。

應(yīng)該這樣設(shè)置 Content-Disposition :

Content-Disposition: attachment;
                     filename="$encoded_fname";
                     filename*=utf-8''$encoded_fname

其中,$encoded_fname指的是將 UTF-8 編碼的原始文件名按照RFC 3986進行百分號 urlencode 后得到的( PHP 中使用rawurlencode()函數(shù))。這幾行也可以合并為一行,推薦使用一個空格隔開。

另外,為了兼容 IE6 ,請保證原始文件名必須包含英文擴展名!

好了,接下來我們來看看為什么要這么做以及為什么能這么做。

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

filename="TEXT"
;這是 RFC 2616 標準,TEXT必須是 ASCII 字符且被認為就是“原文”
filename*=charset'lang'encoded-text
;這是按照 RFC 2047 擴展后的,注意格式上的細微區(qū)別,采用 base64 編碼(編碼結(jié)果也是 ASCII 字符)

然而,事實上在1999年 HTTP 1.1 標準推出之時, Content-Dispostion 這個 Header 尚不是正式標準的一部分,只不過是因為被廣泛使用而從 MIME 標準中直接借用過來了而已(RFC 2616 Section 19.5.1)。因而幾乎沒有瀏覽器去支持 Content-Disposition 的多語言編碼特性這樣一個“擴展特性的擴展特性”(事實上, HTTP 1.1 草案中建議的使用 RFC 2047 來進行多語言編碼的特性從未被主流瀏覽器支持過)。

可是這個問題卻的確是現(xiàn)實需要的,所以瀏覽器就各自想出了一些辦法:

  • IE支持兩種格式的混合版:filename="encoded_text"(這里采用的是百分號編碼)。本來按照 RFC 2616 ,引號內(nèi)的部分應(yīng)當直接被當作內(nèi)容,就算它“看起來像是編碼后的字符串”;可是IE卻會“自動”對這樣的文件名進行解碼——前提是該文件名必須有一個不會被編碼的后綴名(即正常的英文字母后綴名)!
  • 其他一些瀏覽器則支持一種更為粗暴的方式——允許在filename="TEXT"中直接使用 UTF-8 編碼的字符串!

這兩類瀏覽器的行為是彼此互不兼容的。所以你可以判斷 UA 然后對IE使用前一種辦法,其他瀏覽器使用后一種,這樣便可以達到一般情況下能夠 just work 的效果( Discuz 就是這么做的)。不過對于 Opera 和 Safari ,這樣做可能不一定有效。

時代在進步,2010年RFC 5987發(fā)布,正式規(guī)定了 HTTP Header 中多語言編碼的處理方式,應(yīng)當采用類似 MIME 擴展的parameter*=charset'lang'value的格式,但是其中 value 應(yīng)根據(jù)RFC 3986 Section 2.1使用百分號進行編碼,并且規(guī)定瀏覽器至少應(yīng)該支持 ASCII 和 UTF-8 。隨后,2011年RFC 6266發(fā)布,正式將 Content-Disposition 納入 HTTP 標準,并再次強調(diào)了 RFC 5987 中多語言編碼的方法,還給出了一個范例用于解決向后兼容的問題——就是我在一開始給出的例子:

Content-Disposition: attachment;
                     filename="encoded_text";
                     filename*=utf-8''encoded_text

在這個例子中,對于較新的 Firefox 、 Chrome 、 Opera 、 Safari 等瀏覽器,都支持新標準規(guī)定的 filename* ,并且會優(yōu)先使用,所以盡管 filename=”encoded_text” 不被它們支持,仍然不會有問題;至于使用 UTF-8 只是因為它是標準中強制要求必須支持的。而對于舊版本的IE瀏覽器,它們無法識別后面的 filename* ,會自動忽略并使用舊的 filename 。這樣一來就完美解決了多瀏覽器的多語言兼容問題,既不需要 UA 判斷,也符合標準。

P.S.為什么 PHP 要使用rawurlencode()函數(shù)呢?因為這才是真正符合 RFC 3986 的“百分號URL編碼”,只是由于歷史原因,之前先有了一個urlencode()函數(shù)用于實現(xiàn) HTTP POST 中的類似的編碼規(guī)則,故而只好用這么一個奇怪的名字。兩者的區(qū)別在于前者會把空格編碼為%20,而后者則會編碼為+號。如果使用后者,那么IE6在下載帶有空格的文件名時空格會變?yōu)榧犹?。一般情況下,你是不會用到urlencode()這個函數(shù)的( Discuz 某些版本中錯誤地使用它來進行文件名編碼,從而導(dǎo)致空格變加號的BUG)。

到此這篇關(guān)于Java如何正確處理下載文件時HTTP頭的編碼問題的文章就介紹到這了,更多相關(guān)Java下載文件HTTP頭編碼問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • OpenJDK源碼解析之System.out.println詳解

    OpenJDK源碼解析之System.out.println詳解

    這篇文章主要介紹了OpenJDK源碼解析之System.out.println詳解,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 通過weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作

    通過weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作

    這篇文章主要介紹了通過weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java?easyexcel使用教程之導(dǎo)出篇

    Java?easyexcel使用教程之導(dǎo)出篇

    EasyExcel是阿里巴巴開源的一個excel處理框架,以使用簡單,節(jié)省內(nèi)存著稱,下面這篇文章主要給大家介紹了關(guān)于Java?easyexcel使用教程之導(dǎo)出篇的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • Spring @Profile注解實現(xiàn)多環(huán)境配置

    Spring @Profile注解實現(xiàn)多環(huán)境配置

    這篇文章主要介紹了Spring @Profile注解實現(xiàn)多環(huán)境配置,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • 解決springboot啟動失敗的問題('hibernate.dialect'?not?set)

    解決springboot啟動失敗的問題('hibernate.dialect'?not?set)

    這篇文章主要介紹了解決springboot啟動失敗的問題('hibernate.dialect'?not?set),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 華為鴻蒙系統(tǒng)應(yīng)用開發(fā)工具 DevEco Studio的安裝和使用圖文教程

    華為鴻蒙系統(tǒng)應(yīng)用開發(fā)工具 DevEco Studio的安裝和使用圖文教程

    HUAWEI DevEco Studio 是華為消費者業(yè)務(wù)為開發(fā)者提供的集成開發(fā)環(huán)境(IDE),旨在幫助開發(fā)者快捷、方便、高效地使用華為EMUI開放能力。這篇文章主要介紹了華為鴻蒙系統(tǒng)應(yīng)用開發(fā)工具 DevEco Studio的安裝和使用圖文教程,需要的朋友可以參考下
    2021-04-04
  • 5個并發(fā)處理技巧代碼示例

    5個并發(fā)處理技巧代碼示例

    這篇文章主要介紹了5個并發(fā)處理技巧代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10
  • Mybatis結(jié)果生成鍵值對的實例代碼

    Mybatis結(jié)果生成鍵值對的實例代碼

    這篇文章主要介紹了Mybatis結(jié)果生成鍵值對的實例代碼,以及MyBatis返回Map鍵值對數(shù)據(jù)的實現(xiàn)方法,非常不錯,具有參考借鑒價值,需要的的朋友參考下
    2017-02-02
  • Java線程創(chuàng)建的四種方式總結(jié)

    Java線程創(chuàng)建的四種方式總結(jié)

    這篇文章主要介紹了Java線程創(chuàng)建的四種方式,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java中的常用時間日期類總結(jié)(Date、DateFormat)

    Java中的常用時間日期類總結(jié)(Date、DateFormat)

    在Java開發(fā)中處理時間和日期是相當常見的任務(wù),無論是計算日期差異、格式化日期顯示、解析日期字符串還是進行日期計算,都需要一些時間和日期處理的技巧,這篇文章主要給大家介紹了關(guān)于Java中常用時間日期類(Date、DateFormat)的相關(guān)資料,需要的朋友可以參考下
    2024-08-08

最新評論