2006-11-29

在 WEB 开发中指示文件的格式和显示方式

网络上的 WEB 服务器,往往网络地址的扩展名决定下载内容的格式。比如, http://www.google.com/images/logo_sm.gif 表示一个 gif 图片文件,http://www.ietf.org/rfc/rfc0001.txt 表示一个 txt 文本文件。然后,也有少数不是这样的,比如 Gmail ,链接地址都是看不懂的一串字符,可是这也能在浏览器中显示图片,并且对于附件中的图片,提供了直接在浏览器中查看和下载到本地两个按钮。这些功能都很人性化,是在返回的消息头信息中,告诉浏览器本消息格式这样的方式来实现的。
在返回的头信息中, Content-Type 字段指示了消息的类型,消息的类型由 MIME 决定。MIME ,全名 Multipurpose Internet Mail Extensions (多用途网际邮件扩展),是一个描述消息内容的标准,网络浏览器通过此标准解析收到的内容。
在 RFC( Request for Comments) 文档 rfc2045 中,对消息内容的类型作了以下说明:

content := "Content-Type" ":" type "/" subtype
           *(";" parameter)
           ; Matching of media type and subtype
           ; is ALWAYS case-insensitive.

type := discrete-type / composite-type

discrete-type := "text" / "image" / "audio" / "video" /
                 "application" / extension-token

composite-type := "message" / "multipart" / extension-token

extension-token := ietf-token / x-token

ietf-token := <An extension token defined by a
               standards-track RFC and registered
               with IANA.>

x-token := <The two characters "X-" or "x-" followed, with
            no intervening white space, by any token>

subtype := extension-token / iana-token

iana-token := <A publicly-defined extension token. Tokens
               of this form must be registered with IANA
               as specified in RFC 2048.>

parameter := attribute "=" value

attribute := token
             ; Matching of attributes
             ; is ALWAYS case-insensitive.

value := token / quoted-string

token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
            or tspecials>

tspecials := "(" / ")" / "<" / ">" / "@" /
             "," / ";" / ":" / "\" / <">
             "/" / "[" / "]" / "?" / "="
             ; Must be in quoted-string,
             ; to use within parameter values

上面指出,目前独立的内容类型主要有5种,分别是 text(文本),image(图片),audio(音频),video(视频),application(应用程序识别),当浏览器收到此类型定义时,解析器根据此字段调用不同的组件显示收到的消息。所以,修改 Content-Type ,我们可以指定浏览器以何种方式显示收到的消息。
同时,对于没有指定内容类型的消息, rfc 文档指定了默认值,如下:

Content-type: text/plain; charset=us-ascii

另外,在文档 rfc2183 中,补充了接收展现的信息,定义为 Content-Disposition :

disposition := "Content-Disposition" ":"
                disposition-type
                *(";" disposition-parm)

disposition-type := "inline"
                    / "attachment"
                    / extension-token
                    ; values are not case-sensitive

disposition-parm := filename-parm
                    / creation-date-parm
                    / modification-date-parm
                    / read-date-parm
                    / size-parm
                    / parameter

filename-parm := "filename" "=" value

creation-date-parm := "creation-date" "=" quoted-date-time

modification-date-parm := "modification-date" "=" quoted-date-time

read-date-parm := "read-date" "=" quoted-date-time

size-parm := "size" "=" 1*DIGIT

quoted-date-time := quoted-string
                    ; contents MUST be an RFC 822 `date-time'
                    ; numeric timezones (+HHMM or -HHMM) MUST be used

上面指定了展现时主要有两种类型: inline(直接打开)和 attachment(作为附件打开)。通过对 Content-Disposition 的修改,我们可以让浏览器直接显示或弹出保存文件的对话框。常用的附加参数还有文件名,创建日期,修改日期,文件大小,最后读取日期等,浏览器将遵循这些字段保存文件。
可以看到,浏览器通过对 Content-Type 和 Content-Disposition 的读取决定显示消息的类型和方式,与网络地址的扩展名毫无关系。下面分别使用 ASP.NET 和 Servlet 列出在客户端弹出图片下载窗口的方法。
使用 C# 在 ASP.NET 中的实现:

...
Response.ContentType = "image/gif";//指示客户端传输的内容为gif图片
Response.AddHeader("Content-Disposition",
     "attachment;filename=cs.gif");//默认的文件名是cs.gif
//在这里使用 Response.BinaryWrite 方法往客户端写二进制数据
Response.Close();
...

使用 Java 在 Servlet 中的实现:

...
resp.setContentType("image/gif");//指示客户端传输的内容为gif图片
resp.addHeader("Content-Disposition",
      "attachment;filename=java.gif");//默认的文件名是java.gif
//使用 resp.setContentLength 方法设定发送的长度
ServletOutputStream stream = resp.getOutputStream();
//在这里使用 stream.write 方法往客户端写二进制数据
stream.close();
...

0 Comments: