2007 年 6 月 18 日
http://www.ibm.com/developerworks/cn/xml/x-tipapachexhtml/
本文将向您展示:如何配置 Apache 以便为支持可扩展超文本标记语言(Extensible Hypertext Markup Language,XHTML)的浏览器标记文档的媒体类型为 application/xhtml+xml,同时仍然向不支持该语言的浏览器(如 Microsoft® Internet Explorer®)发送 text/html。
当 Web 服务器向浏览器发送文档时,它会给文档加上一个响应报头作为前缀,如 清单 1 所示。此报头包含了用于告诉浏览器如何解释文档的元数据。元数据的一个最重要的部分是最后一行中的 Content-Type
。它将告诉浏览器如何呈现内容。例如,浏览器用于显示 JPEG 和 GIF 的代码是不同的。最重要的是,很多浏览器用于显示 XHTML 和超文本标记语言(Hypertext Markup Language,HTML)的代码也是不同的。
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
因此,处理 XHTML 时,要获得最大的兼容性,就需要向 Firefox、Safari、Opera 和其他符合标准的浏览器发送 application/xhtml+xml,而向 Internet Explorer 发送 text/html。在这两种情况下发送的是同一个文件。您只需在超文本传输协议(Hypertext Transfer Protocol,HTTP)的报头中更改文件的媒体类型标记即可。使用 Apache Web 服务器时,可在服务器配置文件或个人目录中的 .htaccess 文件中做此更改。
根据默认,Apache 通过检查文件的扩展名来决定与每个文件一起发送的媒体类型。扩展名类型映射存储于 httpd/conf 目录(通常是类似 /usr/httpd/conf 或 /etc/httpd/conf 的目录)下的 mime.types 文件中。比如,清单 2 显示了 Apache 2.0 的 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> |
如果可以的话,您应该多支持一个不能识别 application/xhtml+xml 的浏览器:Lynx。Lynx 是一种文本模式浏览器,主要由自动化脚本和处理 shell 的 UNIX® 爱好者使用。它的市场份额很小,但是其独特的功能使它具有了足够的重要性,颇值得我们关注,但前提是不给其他用户造成不便。
幸运的是,所有 Lynx 的 user-agent 字符串都以词 “Lynx” 开头,而其他的 user-agent 字符串都不包含该词。因此,为支持 Lynx,您所要做的全部工作就是将该字符串添加到重写条件正则表达式中,如 清单 5 所示:
RewriteEngine on RewriteCond %{HTTP_USER_AGENT} ((.*MSIE.*)|(Lynx.*)) RewriteCond %{REQUEST_URI} \.xhtml$ RewriteRule .* - [T=text/html] |
第二行中的新正则表达式匹配任何包含 MSIE
或以 Lynx
开头的字符串。如果发现另一个浏览器不能很好地处理 application/xhtml+xml,则可向其 user-agent 字符串中做类似的添加。
一些更老版本的 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 红皮书。
- developerWorks 技术事件和网络广播:随时关注最新技术。