天天看點

HTTP協定header中Content-Disposition中文檔案名亂碼

在做檔案下載下傳時當檔案名為中文時經常會出現亂碼現象。 

參考文章 http://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/ 

本文就詳細給出案例來解決這一亂碼問題以及還一直未解決的一個疑問歡迎大家一起來探讨。 

大體的原因就是header中隻支援ascii是以我們傳輸的檔案名必須是ascii當檔案名為中文時必須要将該中文轉換成ascii。 

轉換方式有很多 

方式一将中文檔案名用iso-8859-1進行重新編碼如headers.add("content-disposition","attachment;filename="+new string("中國".getbytes("utf-8"),"iso-8859-1")+".txt"); 

方式二可以對中文檔案名使用url編碼如headers.add("content-disposition","attachment;filename="+urlencoder.encode("中國","utf-8")+".txt"); 

疑問中文檔案名轉換成ascii後傳給浏覽器浏覽器遇到一堆ascii如何能正确的還原出來我們原來的中文檔案名的呢 

實驗案例 

亂碼現象如下 

<a href="http://my.oschina.net/pingpangkuangmo/blog/376332#">?</a>

1

2

3

4

5

6

7

8

<code>@requestmapping</code><code>(value=</code><code>"/test/httpentity1"</code><code>,method=requestmethod.get)</code>

<code>    </code><code>public</code> <code>httpentity&lt;string&gt; testhttpentity1()</code><code>throws</code> <code>unsupportedencodingexception{</code>

<code>        </code><code>string body=</code><code>"abc"</code><code>;</code>

<code>        </code><code>httpheaders headers=</code><code>new</code> <code>httpheaders();</code>

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename=中國.txt"</code><code>);</code>

<code>        </code><code>httpentity&lt;string&gt; ret=</code><code>new</code> <code>httpentity&lt;string&gt;(body,headers);</code>

<code>        </code><code>return</code> <code>ret;</code>

<code>    </code><code>}</code>

這裡的filename直接使用中文檔案然後就造成了下面的亂碼現象 

HTTP協定header中Content-Disposition中文檔案名亂碼

檔案名字尾也完全變了。 

原因就是header隻支援ascii是以我們要把"中國"轉換成ascii。 

解決方案一将中文檔案名用iso-8859-1進行重新編碼 

<code>@requestmapping</code><code>(value=</code><code>"/test/httpentity"</code><code>,method=requestmethod.get)</code>

<code>    </code><code>public</code> <code>httpentity&lt;string&gt; testhttpentity()</code><code>throws</code> <code>unsupportedencodingexception{</code>

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename="</code><code>+</code><code>new</code> <code>string(</code><code>"中國"</code><code>.getbytes(</code><code>"utf-8"</code><code>),</code><code>"iso-8859-1"</code><code>)+</code><code>".txt"</code><code>);</code>

chrome為 

HTTP協定header中Content-Disposition中文檔案名亂碼

ie11為 

HTTP協定header中Content-Disposition中文檔案名亂碼

chrome解決了亂碼現象但ie沒有。但是你是否想過浏覽器面對一堆content-disposition:attachment;filename=中å½.txt它又是如何來正确顯示的中文檔案名"中國.txt"的呢它肯定要對中å½重新進行utf-8編碼才能正确顯示出"中國"即必須進行類似如下的操作new string("中å½".getbytes("iso-8859-1"),"utf-8")才能正常顯示出"中國.txt"。而ie11進行的類似操作為new string("中å½".getbytes("iso-8859-1"),"gbk")。 

同樣的實驗隻是把utf-8改成gbk 

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename="</code><code>+</code><code>new</code> <code>string(</code><code>"中國"</code><code>.getbytes(</code><code>"gbk"</code><code>),</code><code>"iso-8859-1"</code><code>)+</code><code>".txt"</code><code>);</code>

HTTP協定header中Content-Disposition中文檔案名亂碼
HTTP協定header中Content-Disposition中文檔案名亂碼

ie11和chrmoe都能正确顯示面對content-disposition:attachment;filename=Öйú.txt浏覽器也必須進行如下類似的操作才能正确還原出"中國"new string("Öйú".getbytes("iso-8859-1"),"gbk")。 

這裡就可以提出我們的疑問了浏覽器面對中å½、Öйú都能正确還原出"中國"選擇utf-8還是gbk它到底是怎麼做到的呢依據又是什麼呢難道它是要計算出機率這便是我的疑問還請大家一起探讨和研究。 

接下來說說其他的解決方案 

解決方案二可以對中文檔案名使用url編碼 

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename="</code><code>+urlencoder.encode(</code><code>"中國"</code><code>,</code><code>"utf-8"</code><code>)+</code><code>".txt"</code><code>);</code>

HTTP協定header中Content-Disposition中文檔案名亂碼
HTTP協定header中Content-Disposition中文檔案名亂碼

也能正常顯示出"中國.txt"。 

然而将該方案的utf-8換成gbk浏覽器卻不支援了。 

如下 

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename="</code><code>+urlencoder.encode(</code><code>"中國"</code><code>,</code><code>"gbk"</code><code>)+</code><code>".txt"</code><code>);</code>

HTTP協定header中Content-Disposition中文檔案名亂碼

檔案名也全變了。 

HTTP協定header中Content-Disposition中文檔案名亂碼

這裡就是說對于url編碼支援utf-8其他的好像還不支援。 

解決方案三 

使用最新的解決方案即filename*=charset'lang'value。charset則是給浏覽器指明以什麼編碼方式來還原中文檔案名。 

如filename*=utf-8''value其中value為原始資料的utf-8形式的url編碼。 

<code>@requestmapping</code><code>(value=</code><code>"/httpentity"</code><code>,method=requestmethod.get)         </code>

<code>        </code><code>httpheaders headers=</code><code>new</code> <code>httpheaders();</code><code>//filename="+urlencoder.encode("中國","utf-8")+";</code>

<code>        </code><code>headers.add(</code><code>"content-disposition"</code><code>,</code><code>"attachment;filename*=utf-8''"</code><code>+urlencoder.encode(</code><code>"中國"</code><code>,</code><code>"utf-8"</code><code>)+</code><code>".txt"</code><code>);</code>

<code>        </code><code>httpentity&lt;string&gt; ret=</code><code>new</code> <code>httpentity&lt;string&gt;(body, headers);</code>

HTTP協定header中Content-Disposition中文檔案名亂碼
HTTP協定header中Content-Disposition中文檔案名亂碼

都能夠正确顯示。 

若使用headers.add("content-disposition","attachment;filename*=gbk''"+urlencoder.encode("中國","utf-8")+".txt"),對此chrome則是按照gbk方式來還原中文檔案名的是以就會變成 

HTTP協定header中Content-Disposition中文檔案名亂碼

造成亂碼。而ie11則直接是 

HTTP協定header中Content-Disposition中文檔案名亂碼

若使用headers.add("content-disposition","attachment;filename*=gbk''"+urlencoder.encode("中國","gbk")+".txt") 

HTTP協定header中Content-Disposition中文檔案名亂碼
HTTP協定header中Content-Disposition中文檔案名亂碼

即ie11僅支援filename*=utf-8編碼形式的。 

然後就是headers.add("content-disposition","attachment;filename="+urlencoder.encode("中國","utf-8")+".txt;filename*=utf-8''"+urlencoder.encode("中國","utf-8")+".txt");filename和filename*可以組合使用來解決跨浏覽器的問題。 

對于上面提出的疑問還請網友們解答。

繼續閱讀