技巧

配置 Apache 为 XHTML 发送正确的 MIME 类型

使用 mod_rewrite 浏览器嗅探

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 技巧

敬请期待该系列的后续内容。

此内容是该系列的一部分:技巧

敬请期待该系列的后续内容。

当 Web 服务器向浏览器发送文档时,它会给文档加上一个响应报头作为前缀,如 清单 1 所示。此报头包含了用于告诉浏览器如何解释文档的元数据。元数据的一个最重要的部分是最后一行中的 Content-Type。它将告诉浏览器如何呈现内容。例如,浏览器用于显示 JPEG 和 GIF 的代码是不同的。最重要的是,很多浏览器用于显示 XHTML 和超文本标记语言(Hypertext Markup Language,HTML)的代码也是不同的。

清单 1. 一个典型的 HTTP 响应报头
HTTP/1.1 200 OK
Date: Thu, 04 Jan 2007 19:39:13 GMT
Server: Apache/2
Last-Modified: Wed, 06 Sep 2006 11:19:37 GMT
ETag: "4dfce0-c4aa-26828440"
Accept-Ranges: bytes
Content-Length: 50346
Content-Style-Type: text/css
Content-Type: application/xhtml+xml

Web 服务器应该给 XHTML 文档加上媒体类型标记 application/xhtml+xml。识别此媒体类型的 Web 浏览器就会相应地将其以 strict 模式而不是 tag soup 模式运行。这使浏览器能更可靠地进行显示,对于级联样式表(Cascading Style Sheets,CSS)布局和基于文档的对象模型的 JavaScript ™ 程序,这一点尤为重要。事实上,在一些情况下同一文档能以两种不同的方式显示,取决于其处理模式是 tag soup 还是 strict。如果想要生成格式良好甚或是有效的 XHTML,则 strict 模式将会是您计划使用并希望使用的模式。

不支持 XHTML 的浏览器也能以 tag soup 模式处理格式良好的文档。结果并不完美,但可以满足一小部分使用很老的浏览器的用户需要。对于大部分使用不符合标准的 Internet Explorer 的用户来说,结果也还可以接受。但是,当前版本的 Internet Explorer(包括 6 和 7)无法识别 application/xhtml+xml 媒体类型。如果向 Internet Explorer 发送 application/xhtml+xml 文档,它将会反过来要求您保存文件,如 图 1 所示。

图 1. Internet Explorer 不知道如何处理 application/xhtml+xml
某些文件可能会损害您的计算机。如果下面的文件信息看起来可疑,或者您不完全信任其来源,请不要打开或保存此文件。文件名:a.xhtml
某些文件可能会损害您的计算机。如果下面的文件信息看起来可疑,或者您不完全信任其来源,请不要打开或保存此文件。文件名:a.xhtml

因此,处理 XHTML 时,要获得最大的兼容性,就需要向 Firefox、Safari、Opera 和其他符合标准的浏览器发送 application/xhtml+xml,而向 Internet Explorer 发送 text/html。在这两种情况下发送的是同一个文件。您只需在超文本传输协议(Hypertext Transfer Protocol,HTTP)的报头中更改文件的媒体类型标记即可。使用 Apache Web 服务器时,可在服务器配置文件或个人目录中的 .htaccess 文件中做此更改。

Apache 配置指令

根据默认,Apache 通过检查文件的扩展名来决定与每个文件一起发送的媒体类型。扩展名类型映射存储于 httpd/conf 目录(通常是类似 /usr/httpd/conf 或 /etc/httpd/conf 的目录)下的 mime.types 文件中。比如,清单 2 显示了 Apache 2.0 的 mime.types 文件的部分内容。

清单 2. Apache 的 mime.types
# This file controls what Internet media types are sent to the client for
# given file extension(s).  Sending the correct media type to the client
# is important so they know how to handle the content of the file.
# Extra types can either be added here or by using an AddType directive
# in your config files. For more information about Internet media types,
# please read RFC 2045, 2046, 2047, 2048, and 2077.  The Internet media type
# registry is at <http://www.iana.org/assignments/media-types/>.

# MIME type                     Extensions
application/atom+xml            atom
application/mathematica
application/mathml+xml          mathml
application/msword              doc
application/octet-stream        bin dms lha lzh exe class so dll dmg
application/postscript          ai eps ps
application/rdf+xml             rdf
application/reginfo+xml
application/xhtml+xml           xhtml xht
application/xslt+xml            xslt
application/xml                 xml xsl
application/xml-dtd             dtd
application/xml-external-parsed-entity
application/zip                 zip
audio/mpeg                      mpga mp2 mp3
image/jpeg                      jpeg jpg jpe
image/naplps
image/png                       png
image/svg+xml                   svg
image/tiff                      tiff tif
text/html                       html htm
text/plain                      asc txt
text/sgml                       sgml sgm
text/xml
text/xml-external-parsed-entity
video/mpeg                      mpeg mpg mpe

一些更老的版本没有根据默认安装所有这些映射,并且可能事实上使用了一些十分有害的映射。尤其应该注意,对于原始 XML 文件使用 text/xml 而不是 application/xml 是一个常见的问题。

具有了这些默认的映射后,您所需要做的全部工作就是为 XHTML 文件加上 .xhtml 或 .xht 后缀,而不是 .html 后缀,之后,所有这类文件都将被作为 application/xhtml+xml 处理。这对于 Firefox、Opera 和 Safari 效果很好,但对于 Internet Explorer 却并非如此。您所需要的是一种方法,通过它可向 Internet Explorer 发送一种媒体类型而向所有其他浏览器发送另一种媒体类型。

浏览器嗅探

2007 年,可以放心假设所有非 Internet Explorer 的浏览器都能识别 application/xhtml+xml。(如果您确实希望支持很老的浏览器,则破解我下面提出的规则也很容易。)因此您就需要识别 Internet Explorer 的所有版本并将媒体类型更改为 text/html。幸运的是,Internet Explorer 在发送 HTTP 请求时可告知服务器浏览器的类型,如 清单 3 所示。

清单 3. Internet Explorer 的 HTTP 请求报头
GET /test/a.xhtml HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, 
        application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)
Host: www.xom.nu
Connection: Keep-Alive

关键在于 User-Agent 字段。虽然由于传统原因 Internet Explorer 在开始时感觉像是 Netscape,但 MSIE 字符串可将其识别为 Internet Explorer。所有版本的 Internet Explorer 在 User-Agent 字段中都包含了此字符串,而所有其他现代的浏览器都不具备此特征。

您需要配置服务器以便查看报头中的 User-Agent 字段,并向 Internet Explorer 发送 text/html,向所有其他浏览器发送 application/xhtml+xml。mod-rewrite 模块并不局限于重写 URL。它还能根据 User-Agent 更改 HTTP 响应报头。清单 4 展示了配置文件中需要放入的代码。

清单 4. 向 Internet Explorer 发送 text.html
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} .*MSIE.*
RewriteCond %{REQUEST_URI} \.xhtml$
RewriteRule .* - [T=text/html]

第一行会打开重写引擎。

第二行的第一个重写条件表明:下面的规则仅适用于 HTTP 请求报头中的 user-agent 字符串包含子字符串 MSIE 的情形。正则表达式 .*MSIE.* 实现了此功能。

第三行的第二个重写条件表明:下面的规则仅适用于浏览器请求的文件具有 .xhtml 扩展名的情形。常规的 .html 文件被作为普通的 text/html 提供给所有浏览器。

最后一行是实际的重写规则。此规则有点不太常见,因为重写并未真正更改 URL 中的任何东西。接下来,匹配整个 URL (.*) 但接着将其替换成它自己 (-)。然而,最后的 [T=text/html] 字段会把 Content-Type 报头更改为 text/html。如果同时匹配上述两个条件,则使用此规则。反之则不然。

安装规则

根据服务器设置的不同,此代码可能位于以下几个位置之一:

  • 主 httpd.conf 文件
  • httpd.conf 文件中的 VirtualHost 部分或单独的虚拟主机配置文件
  • XHTML 文件所在目录中的 .htaccess 文件

这些指导说明在 Apache 1.3 和 2.0 中应该都有效。如果您在 .htaccess 文件中使用这些规则,则似乎没什么作用,这时,确保对目录做出了如下设置以允许在主 httpd.conf 文件中进行覆盖:

<Directory /var/www/foo>
  AllowOverride FileInfo
</Directory>

Lynx

如果可以的话,您应该多支持一个不能识别 application/xhtml+xml 的浏览器:Lynx。Lynx 是一种文本模式浏览器,主要由自动化脚本和处理 shell 的 UNIX® 爱好者使用。它的市场份额很小,但是其独特的功能使它具有了足够的重要性,颇值得我们关注,但前提是不给其他用户造成不便。

幸运的是,所有 Lynx 的 user-agent 字符串都以词 “Lynx” 开头,而其他的 user-agent 字符串都不包含该词。因此,为支持 Lynx,您所要做的全部工作就是将该字符串添加到重写条件正则表达式中,如 清单 5 所示:

清单 5. 向 Lynx 发送 text.html
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ((.*MSIE.*)|(Lynx.*))
RewriteCond %{REQUEST_URI} \.xhtml$
RewriteRule .* - [T=text/html]

第二行中的新正则表达式匹配任何包含 MSIE 或以 Lynx 开头的字符串。如果发现另一个浏览器不能很好地处理 application/xhtml+xml,则可向其 user-agent 字符串中做类似的添加。

伪装成 Internet Explorer

一些更老版本的 Opera 和 Safari 通过在其 user-agent 字符串中包含 MSIE 将自己伪装成 Internet Explorer。但是您无需为此忧虑,原因如下:

  • 几乎已经没什么人使用那些版本了。
  • 与一些更新版本的 Safari 和 Opera 不同,那些较老的版本总的说来处理 text/html 比处理 application/xhtml+xml 的效果好。

要了解更精确的目标信息,请参阅 参考资料 中到 user-agent 字符串完整列表的链接和可供您参考的 application/xhtml+xml 浏览器支持。

结束语

XHTML 是 Web 的未来。但是,像很多其他重要的技术一样,它的采用由于得不到 Microsoft 浏览器的有力支持而受到阻碍。如本文所展示的那样,没有理由等待 Microsoft。您可以轻松地向非 Microsoft 的浏览器提供 XHTML,同时仍然告诉 Internet Explorer 将它作为 tag soup 处理。现代浏览器的访客和页面作者将完全受益于 XHTML,而受 Internet Explorer 牵制的访客则仍然可获得大部分内容。适当地设置 Multipurpose Internet Mail Extensions(MIME)媒体类型并不是向旧的浏览器提供 XHTML 所能采用的惟一途径,但它却是往正确方向上迈出的一大步。


相关主题

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • XHTML 1.0: Marking up a new dawn(Molly Holzschlag,developerWorks,2005 年 2 月):在这篇对 XHTML 及其功能的介绍中了解 XHTML 1.0 是什么和它能给 Web 开发人员带来什么。
  • mod_rewrite 文档:探索这种功能非常强大(常常有些晦涩难懂)的模块的能力并动态地重写请求的 URL。
  • Sending XHTML as text/html Considered Harmful(Ian Hickson):了解为何将所有 XHTML 作为 text/html 发送不是个好主意以及为何应该将 XHTML 标记作为 application/xhtml+xml 发送。
  • XHTML 媒体类型:查阅万维网联盟(World Wide Web Consortium,W3C)有关 XHTML 内容的媒体类型的正式定义,了解更多针对服务于 XHTML 家族文档的 Internet 媒体类型的最佳当前实践。
  • Apache 2.0 中的内容协商支持:了解如何将不同文件发送到不同的客户机。如果您希望维护每个文档的单独的 XHTML 和 HTML 副本,则可能会发现这种功能很有用。
  • XHTML 1.0 规范中的兼容性指导原则:更轻松地将文档作为 XHTML 和 tag soup 处理。
  • User-agent strings topic(Wikipedia):查看作者所见过的 user-agent 字符串的最完整集合。
  • XHTML 媒体类型测试 - 结果:学习这个由 W3C 维持的列表的细节,了解不同版本的各种浏览器支持 application/xhtml+xml 的情况。
  • IBM XML 认证:了解如何才能成为一名 IBM 认证的 XML 和相关技术的开发人员。
  • 访问 developerWorks 中国网站 XML 专区,查看广泛的技术文章和提示、教程、标准以及 IBM 红皮书。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source
ArticleID=231757
ArticleTitle=技巧: 配置 Apache 为 XHTML 发送正确的 MIME 类型
publish-date=06182007