原文网址:https://www.ibm.com/developerworks/cn/xml/x-tipapachexhtml/
当 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](https://i-blog.csdnimg.cn/blog_migrate/c26133b98aad199f21ca2172f43b51ad.png)
因此,处理 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 所能采用的惟一途径,但它却是往正确方向上迈出的一大步。