HTTP知多少——Content-disposition(文件下
HTTP知多少——Content-disposition(文件下载)
HTTP知多少——Content-Type(内容类型)详解
Content-disposition(内容-部署)是MIME协议类型的扩展,MIME协议指示MIME用户代理如何显示附加的文件。
1. Content-Disposition的作用
Content-disposition是MIME协议的扩展,MIME协议指示MIME用户代理如何显示附加的文件。当Internet Explorer接收到头时,他会激活文件下载
对话框,它的文件名框自动填充headers指定的文件名。
服务器向浏览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt
、jpg
等。如果需要提示用户保存,就要利用Content-Disposition
进行处理,(敲黑板,划重点)关键在于一定要加上attachment
[附件] [əˈtætʃmənt]
。
例如
Response.AppendHeader("ContentDisposition","attachment;filename=FileName.txt");
这样的话,浏览器在打开的时候回提示保存还是打开,即使选择打开,也会使用相关联的程序,比如记事本打开,而不是IE直接打开。
Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名。
具体的定义如下:
//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;"
注意点:
当然filename参数可以包含路径信息,但User-Agnet会忽略这些信息,只会把路径信息的最后一部分作为文件名。当响应类型为application/octet-stream
情况下使用上面的头信息的话,那么就不能直接显示内容,而是弹出一个"文件下载"的对话框,接下来就是用户决定“打开”还是“保存”了。
2. 下载文件中文乱码
Content-Disposition如何适配各个浏览器以及解决中文乱码问题。
IE浏览器下载乱码问题
总体下来就是这么几点:
- 两个IE11在使用第一个方法下载文件时中文文件名都会乱码,而使用第二个方法下载时其中一个IE11中文不会乱码,另一个IE11则会乱码;
- 文件名中存在空格时两个IE11浏览器下载下来文件文件名空格会变成+号,其他浏览器没有这个问题;
- 火狐浏览器下载时遇到文件名中有空格时下载下来的文件的文件名第一个空格后面的文字都会丢失。
-
**老版IE的USER-AGENT参数中含有MISE关键字,但是IE11之后浏览器的USER-AGENT中去掉了MISE关键字。
【IE11:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko;】
** -
IE下载文件名存在+号,是因为URLEncoder函数在对字符串进行转码后将空格替换成了+号,IE直接把+号显示出来。解决办法就是对文件名进行转码之后,使用replace方法将+号替换成%20即可,浏览器会将%20转换成空格输出。
-
对于第三个问题则是因为代码在set响应头时Content-Disposition参数的attachment;filename=等号后面文件名字符串没有使用双引号括起来,火狐浏览器对于遇到文件名有空格时认为空格前的字符是一个完整的字符串。故下载下来文件时文件名就只剩空格前的那几个字了。解决办法就是:在filename两边加上双引号并加反斜杠转义。
编码类
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");// 设定输出文件头
response.setContentType("application/msexcel");// 定义输出类型
//将数据写入输出流
//TODO
}
注意:下载的时候使用的Content-Type大全,一般可以使用application/octet-stream。