HTTP知多少——Content-disposition(文件下載)
HTTP知多少——Content-Type(內(nèi)容類型)詳解
Content-disposition(內(nèi)容-部署)是MIME協(xié)議類型的擴(kuò)展,MIME協(xié)議指示MIME用戶代理如何顯示附加的文件。
1. Content-Disposition的作用
Content-disposition是MIME協(xié)議的擴(kuò)展,MIME協(xié)議指示MIME用戶代理如何顯示附加的文件。當(dāng)Internet Explorer接收到頭時(shí),他會(huì)激活文件下載對(duì)話框,它的文件名框自動(dòng)填充headers指定的文件名。
服務(wù)器向?yàn)g覽器發(fā)送文件時(shí),如果是瀏覽器支持的文件類型,一般會(huì)默認(rèn)使用瀏覽器打開(kāi),比如txt、jpg等。如果需要提示用戶保存,就要利用Content-Disposition進(jìn)行處理,(敲黑板,劃重點(diǎn))關(guān)鍵在于一定要加上attachment [附件] [??t?t?m?nt]。
例如
Response.AppendHeader("ContentDisposition","attachment;filename=FileName.txt");
這樣的話,瀏覽器在打開(kāi)的時(shí)候回提示保存還是打開(kāi),即使選擇打開(kāi),也會(huì)使用相關(guān)聯(lián)的程序,比如記事本打開(kāi),而不是IE直接打開(kāi)。
Content-Disposition就是當(dāng)用戶想把請(qǐng)求所得的內(nèi)容存為一個(gè)文件的時(shí)候提供一個(gè)默認(rèn)的文件名。
具體的定義如下:
//content-disposition的定義
content-disposition ="Content-Disposition" ":"
disposition-type
*(";" disposition-param)
//disposition-type的定義
disposition-type="attachment"|disp-extension-token
//disposition-param的定義
disposition-param=filename-param|disp-extension-parm
//filename-param的定義
filename-param= "filename" "=" quoted-string
//disp-extension-token的定義
disp-extension-token = token
//disp-extension-parm
token "=" ( token | quoted-string )
例如:
Content-Disposition:attachment;filename="filename.xlsx;"
注意點(diǎn):
當(dāng)然filename參數(shù)可以包含路徑信息,但User-Agnet會(huì)忽略這些信息,只會(huì)把路徑信息的最后一部分作為文件名。當(dāng)響應(yīng)類型為application/octet-stream情況下使用上面的頭信息的話,那么就不能直接顯示內(nèi)容,而是彈出一個(gè)"文件下載"的對(duì)話框,接下來(lái)就是用戶決定“打開(kāi)”還是“保存”了。
2. 下載文件中文亂碼
Content-Disposition如何適配各個(gè)瀏覽器以及解決中文亂碼問(wèn)題。
IE瀏覽器下載亂碼問(wèn)題
總體下來(lái)就是這么幾點(diǎn):
- 兩個(gè)IE11在使用第一個(gè)方法下載文件時(shí)中文文件名都會(huì)亂碼,而使用第二個(gè)方法下載時(shí)其中一個(gè)IE11中文不會(huì)亂碼,另一個(gè)IE11則會(huì)亂碼;
- 文件名中存在空格時(shí)兩個(gè)IE11瀏覽器下載下來(lái)文件文件名空格會(huì)變成+號(hào),其他瀏覽器沒(méi)有這個(gè)問(wèn)題;
- 火狐瀏覽器下載時(shí)遇到文件名中有空格時(shí)下載下來(lái)的文件的文件名第一個(gè)空格后面的文字都會(huì)丟失。
**老版IE的USER-AGENT參數(shù)中含有MISE關(guān)鍵字,但是IE11之后瀏覽器的USER-AGENT中去掉了MISE關(guān)鍵字。
【IE11:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko;】**IE下載文件名存在+號(hào),是因?yàn)閁RLEncoder函數(shù)在對(duì)字符串進(jìn)行轉(zhuǎn)碼后將空格替換成了+號(hào),IE直接把+號(hào)顯示出來(lái)。解決辦法就是對(duì)文件名進(jìn)行轉(zhuǎn)碼之后,使用replace方法將+號(hào)替換成%20即可,瀏覽器會(huì)將%20轉(zhuǎn)換成空格輸出。
對(duì)于第三個(gè)問(wèn)題則是因?yàn)榇a在set響應(yīng)頭時(shí)Content-Disposition參數(shù)的attachment;filename=等號(hào)后面文件名字符串沒(méi)有使用雙引號(hào)括起來(lái),火狐瀏覽器對(duì)于遇到文件名有空格時(shí)認(rèn)為空格前的字符是一個(gè)完整的字符串。故下載下來(lái)文件時(shí)文件名就只剩空格前的那幾個(gè)字了。解決辦法就是:在filename兩邊加上雙引號(hào)并加反斜杠轉(zhuǎn)義。
編碼類
public static String toUtf8String(String fileName, HttpServletRequest request) throws Exception {
final String userAgent = request.getHeader("USER-AGENT");
String finalFileName = null;
if (StringUtils.contains(userAgent, "MSIE")||StringUtils.contains(userAgent, "Trident")) {// IE瀏覽器(舊版/新版)
finalFileName = URLEncoder.encode(fileName, "UTF8");
} else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐瀏覽器
finalFileName = new String(fileName.getBytes(), "ISO8859-1");
} else {
finalFileName = URLEncoder.encode(fileName, "UTF8");// 其他瀏覽器
}
return finalFileName;
}
@RequestMapping("/downExcel")
public void downExcel(HttpServletRequest request, HttpServletResponse response) {
out = response.getOutputStream();// 取得輸出流
response.reset();// 清空輸出流
response.setHeader("Content-disposition",
"attachment; filename=" + ExcelUtil.toUtf8String(fileName, request) + ".xlsx");// 設(shè)定輸出文件頭
response.setContentType("application/msexcel");// 定義輸出類型
//將數(shù)據(jù)寫(xiě)入輸出流
//TODO
}
注意:下載的時(shí)候使用的Content-Type大全,一般可以使用application/octet-stream。