http://www.qihangnet.com/blog/PermaLink-db65d50a-ba90-4229-a3a2-71b4f1b407b9
最近不少Web技术圈内的朋友在讨论协议方面的事情,有的说web开发者应该熟悉web相关的协议,有的则说不用很了解。个人认为这要分层次来看待这个问题,对于一个新手或者刚入门的web开发人员而言,研究协议方面的东西可能会使得web开发失去趣味性、抹煞学习积极性,这类人应该更多的了解基本的Web技术使用。而对于在该行业工作多年的老鸟来说,协议相关的内容、标准相关内容应该尽量多些的了解,因为只有这样才能使得经手的web系统更加优秀(安全、漂亮、快速、兼容性好、体验好……)。本文我们来说一下MIME 协议的一个扩展Content-disposition。
我们在开发web系统时有时会有以下需求:
- 希望某类或者某已知MIME 类型的文件(比如:*.gif;*.txt;*.htm)能够在访问时弹出“文件下载”对话框
- 希望以原始文件名(上传时的文件名,例如:山东省政府1024号文件.doc)提供下载,但服务器上保存的地址却是其他文件名(如:12519810948091234_asdf.doc)
- 希望某文件直接在浏览器上显示而不是弹出文件下载对话框
- ……………………
要解决上述需求就可以使用Content-disposition来解决。第一个需求的解决办法是
Response.AddHeader "content-disposition","attachment; filename=fname.ext"
public static void ToDownload(string serverfilpath,string filename)
{
FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
long fileSize = fileStream.Length;
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + UTF_FileName(filename) + "\";");
attachment --- 作为附件下载
inline --- 在线打开
HttpContext.Current.Response.AddHeader("Content-Length", fileSize.ToString());
byte[] fileBuffer = new byte[fileSize];
fileStream.Read(fileBuffer, 0, (int)fileSize);
HttpContext.Current.Response.BinaryWrite(fileBuffer);
fileStream.Close();
HttpContext.Current.Response.End();
}
public static void ToOpen(string serverfilpath, string filename)
{
FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
long fileSize = fileStream.Length;
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=\"" + UTF_FileName(filename) + "\";");
HttpContext.Current.Response.AddHeader("Content-Length", fileSize.ToString());
byte[] fileBuffer = new byte[fileSize];
fileStream.Read(fileBuffer, 0, (int)fileSize);
HttpContext.Current.Response.BinaryWrite(fileBuffer);
fileStream.Close();
HttpContext.Current.Response.End();
}
private static string UTF_FileName(string filename)
{
return HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8);
}
简单的对上述代码做一下解析,ToDownload方法为将一个服务器上的文件(serverfilpath为服务器上的物理地址),以某文件名(filename)在浏览器上弹出“文件下载”对话框,而ToOpen是将服务器上的某文件以某文件名在浏览器中显示/打开的。注意其中我使用了UTF_FileName方法,该方法很简单,主要为了解决包含非英文/数字名称的问题,比如说文件名为“衣明志.doc”,使用该方法客户端就不会出现乱码了。
需要注意以下几个问题:
- Content-disposition是MIME协议的扩展,由于多方面的安全性考虑没有被标准化,所以可能某些浏览器不支持,比如说IE4.01
- 我们可以使用程序来使用它,也可以在web服务器(比如IIS)上使用它,只需要在http header上做相应的设置即可
如何为已知的 MIME 类型激活“文件下载”对话框
参见:http://support.microsoft.com/kb/260519
--------------------------------
泪总结一个关于Content-Disposition的教训
来自:
http://cymoft.blog.51cto.com/324099/92412
当代码里面使用Content-Disposition来确保浏览器弹出下载对话框的时候。
response.addHeader(
"Content-Disposition",
"attachment");
一定要保证
没有做过关于
禁止浏览器缓存的操作。
response.setHeader(
"Pragma",
"No-cache");
response.setHeader(
"Cache-Control",
"No-cache");
response.setDateHeader(
"Expires", 0);
不然你会像我一样,发现下载功能在
opera和
firefox里面好好的没问题,在
IE下面就是不行,就是找不到文件。
HTTP报头信息:
来自:http://blog.youkuaiyun.com/xiemk2005/article/details/6111614
response.setHeader( "Cache-Control", "No-cache");
response.setDateHeader( "Expires", 0);
MIME
多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions )是一个互联网标准 ,它扩展了电子邮件 标准,使其能够支持非ASCII 字符、二进制 格式附件等多种格式的邮件消息。这个标准被定义在RFC 2045 、RFC 2046 、RFC 2047 、RFC 2048 、RFC 2049 等RFC 中。 由RFC 822 转变而来的RFC 2822 ,规定电子邮件 标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息都不能在电子邮件中传输。MIME规定了用于表示各种各样的数据类型的符号化方法。 此外,在万维网 中使用的HTTP协议 中也使用了MIME的框架。
MIME是通过标准化电子邮件报文的头部的附加领域(fields)而实现的;这些头部的附加领域,描述新的报文类型的内容和组织形式。
内容类型(Content-Type),这个头部领域用于指定消息的类型。一般以下面的形式出现。
Content-Type: [type]/[subtype]; parameter
type有下面的形式。
Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;
Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据;
Application:用于传输应用程序数据或者二进制数据;
Message:用于包装一个E-mail消息;
Image:用于传输静态图片数据;
Audio:用于传输音频或者音声数据;
Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。
subtype用于指定type的详细形式。content-type/subtype配对的集合和与此相关的参数,将随着时间而增长。为了确保这 些值在一个有序而且公开的状态下开发,MIME使用Internet Assigned Numbers Authority (IANA)作为中心的注册机制来管理这些值。常用的subtype值如下所示:
text/plain(纯文本 )
text/html(HTML文档)
application/xhtml+xml(XHTML文档)
image/gif(GIF图像)
image/jpeg(JPEG图像)【PHP中为:image/pjpeg】
image/png(PNG图像)【PHP中为:image/x-png】
video/mpeg(MPEG动画)
application/octet-stream(任意的二进制数据)
application/pdf(PDF文档)
application/msword(Microsoft Word文件)
message/rfc822(RFC 822 形式)
multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示)
application/x-www-form-urlencoded(使用HTTP的POST方法提交的表单)
multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)
此外,尚未被接受为正式数据类型的subtype,可以使用x-开始的独立名称(例如application/x-gzip)。vnd-开始的固有名称也可以使用(例:application/vnd.ms-excel)。
parameter可以用来指定附加的信息,更多情况下是用于指定text/plain和text/htm等的文字编码方式的charset参数。 MIME根据type制定了默认的subtype,当客户端不能确定消息的subtype的情况下,消息被看作默认的subtype进行处理。Text默 认是text/plain,Application默认是application/octet-stream而Multipart默认情况下被看作 multipart/mixed。
以上出现的“消息”翻译自message
如:HTTP/1.1中
Response = Status-Line
*(( general-header
| response-header
| entity-header ) CRLF)
CRLF
[ message-body ]
Content-Disposition
在进行Web开发时,可能遇到遇到以下几种需求:
l 希望某类或者某已知MIME 类型的文件(比如:*.gif;*.txt;*.htm)能够在访问时弹出“文件下载”对话框。
l 希望客户端下载时以指定文件名显示。
l 希望某文件直接在浏览器上显示而不是弹出文件下载对话框。
对于上面的需求,使用Content-Disposition属性就可以解决。下面是代码示例:
response.setHeader("Content-disposition", "attachment;filename=" + fileName)。
//Content-disposition为属性名。
//attachment表示以附件方式下载。如果要在页面中打开,则改为inline。
//filename如果为中文,则会出现乱码。解决办法有两种:
//1、使用fileName = new String(fileName.getBytes(), "ISO8859-1")语句
//2、使用fileName = HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8)语句
参考文档:
HTTP/1.1 附录:http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19
维基百科:http://zh.wikipedia.org/zh-cn/MIME
-----------------------
关于文件名:
关键在于UrlEncode这个东东,在下面不同情况下的结果是不一样的
1。web.config 里responseEncoding= "gb2312 "
2。web.config 里responseEncoding= "utf-8 "
使用Server.UrlEncode的话必须responseEncoding= "utf-8 "才会正确
所以不要用Server.UrlEncode,换HttpUtility.UrlEncode
string s=HttpUtility.UrlEncode(System.Text.UTF8Encoding.UTF8.GetBytes( "中文.txt "));
Response.AppendHeader( "Content-Disposition ", "attachment; filename= " + s);