将 URL Map 到文件系统位置

本文档说明了 Apache HTTP Server 如何使用请求的 URL 来确定用于提供文件的文件系统位置。

相关模块和指令

Related Modules Related Directives
mod_actions
mod_alias
mod_autoindex
mod_dir
mod_imagemap
mod_negotiation
mod_proxy
mod_rewrite
mod_speling
mod_userdir
mod_vhost_alias
Alias
AliasMatch
CheckSpelling
DirectoryIndex
DocumentRoot
ErrorDocument
Options
ProxyPass
ProxyPassReverse
ProxyPassReverseCookieDomain
ProxyPassReverseCookiePath
Redirect
RedirectMatch
RewriteCond
RewriteRule
ScriptAlias
ScriptAliasMatch
UserDir

DocumentRoot

在确定为给定请求提供服务的文件时,httpd 的默认行为是获取请求的 URL 路径(主机名和端口后面的 URL 部分)并将其添加到配置文件中指定的DocumentRoot的末尾。因此,DocumentRoot下的文件和目录构成了基本的文档树,这些文档和树将从 Web 上可见。

例如,如果将DocumentRoot设置为/var/www/html,则对http://www.example.com/fish/guppies.html的请求将导致文件/var/www/html/fish/guppies.html被提供给发出请求的 Client 端。

如果请求目录(即以/结尾的路径),则该目录中的文件由DirectoryIndex指令定义。例如,如果DocumentRoot的设置如上,您将设置:

DirectoryIndex index.html index.php

然后,对http://www.example.com/fish/的请求将导致 httpd 尝试提供文件/var/www/html/fish/index.html。如果该文件不存在,它将接下来尝试为文件/var/www/html/fish/index.php提供服务。

如果这两个文件都不存在,则下一步是尝试提供目录索引(如果已加载mod_autoindex并将其配置为允许这样做)。

httpd 还具有Virtual Hosting的功能,其中服务器接收对多个主机的请求。在这种情况下,可以为每个虚拟主机指定不同的DocumentRoot,或者可以使用模块mod_vhost_alias提供的指令根据请求的 IP 地址或主机名动态确定从何处提供内容。

在主服务器配置文件(httpd.conf)中设置了DocumentRoot伪指令,并且可能在创建的每个附加Virtual Host中设置一次。

DocumentRoot 外部的文件

在许多情况下,有必要允许通过 Web 访问文件系统中严格不在DocumentRoot下的部分。 httpd 提供了几种不同的方法来实现此目的。在 Unix 系统上,符号链接可以将文件系统的其他部分置于DocumentRoot下。出于安全原因,仅当相关目录的Options设置包含FollowSymLinksSymLinksIfOwnerMatch时,httpd 才会跟随符号链接。

或者,Alias指令会将文件系统的任何部分 Map 到 Web 空间。例如,

Alias "/docs" "/var/web"

URL http://www.example.com/docs/dir/file.html将通过/var/web/dir/file.html提供。 ScriptAlias指令的工作方式相同,另外的作用是将位于目标路径上的所有内容都视为CGI脚本。

对于需要更多灵 Active 的情况,可以使用AliasMatchScriptAliasMatch指令进行基于regular expression的强大匹配和替换。例如,

ScriptAliasMatch "^/~([a-zA-Z0-9]+)/cgi-bin/(.+)"   "/home/$1/cgi-bin/$2"

会将 Map 到http://example.com/~user/cgi-bin/script.cgi的请求 Map 到路径/home/user/cgi-bin/script.cgi,并将生成的文件视为 CGI 脚本。

User Directories

传统上,在 Unix 系统上,特定* user *的主目录可以称为~user/mod_userdir模块通过允许使用以下 URL 来访问每个用户主目录下的文件,将这一思想扩展到了网络。

http://www.example.com/~user/file.html

出于安全原因,从 Web 直接访问用户的主目录是不合适的。因此,UserDir指令指定了用户主目录下 Web 文件所在的目录。使用默认设置Userdir public_html,上述 URL Map 到/home/user/public_html/file.html之类的目录中的文件,其中/home/user//etc/passwd中指定的用户主目录。

Userdir指令还有其他几种形式,您可以在/etc/passwd不包含主目录位置的系统上使用。

有些人发现“~”符号(通常在网络上编码为%7e)很尴尬,并且更喜欢使用替代字符串来表示用户目录。 mod_userdir 不支持此功能。但是,如果以常规方式构造用户的主目录,则可以使用AliasMatch指令来实现所需的效果。例如,要将http://www.example.com/upages/user/file.htmlMap 到/home/user/public_html/file.html,请使用以下AliasMatch指令:

AliasMatch "^/upages/([a-zA-Z0-9]+)(/(.*))?$"   "/home/$1/public_html/$3"

URL Redirection

上一节中讨论的配置指令告诉 httpd 从文件系统中的特定位置获取内容,并将其返回给 Client 端。有时,最好改为通知 Client 端请求的内容位于其他 URL,并指示 Client 端使用新 URL 发出新请求。这称为* redirection *,并由Redirect指令实现。例如,如果DocumentRoot下的目录/foo/的内容已移动到新目录/bar/,则可以指示 Client 端按以下方式在新位置请求内容:

Redirect permanent "/foo/"   "http://www.example.com/bar/"

这会将所有以/foo/开头的 URL 路径重定向到www.example.com服务器上的同一 URL 路径,并用/bar/代替/foo/。您可以将 Client 端重定向到任何服务器,而不仅仅是原始服务器。

httpd 还为更复杂的重写问题提供了RedirectMatch指令。例如,要将网站主页的请求重定向到其他站点,而又不理会所有其他请求,请使用以下配置:

RedirectMatch permanent "^/$"    "http://www.example.com/startpage.html"

或者,要将一个站点上的所有页面临时重定向到另一站点上的特定页面,请使用以下命令:

RedirectMatch temp ".*"  "http://othersite.example.com/startpage.html"

Reverse Proxy

httpd 还允许您将远程文档带入本地服务器的 URL 空间。这种技术称为“反向代理”,因为 Web 服务器通过从远程服务器获取文档并将它们返回给 Client 端来像代理服务器一样工作。它与常规(正向)代理不同,因为对于 Client 端来说,文档似乎来自反向代理服务器。

在以下示例中,当 Client 端在/foo/目录下请求文档时,服务器从internal.example.com/bar/目录中获取这些文档,然后将它们像从本地服务器一样返回给 Client 端。

ProxyPass "/foo/" "http://internal.example.com/bar/"
ProxyPassReverse "/foo/" "http://internal.example.com/bar/"
ProxyPassReverseCookieDomain internal.example.com public.example.com
ProxyPassReverseCookiePath "/foo/" "/bar/"

ProxyPass配置服务器以获取适当的文档,而ProxyPassReverse伪指令重写源自internal.example.com的重定向,以使它们定位到本地服务器上的适当目录。同样,ProxyPassReverseCookieDomainProxyPassReverseCookiePath重写后端服务器设置的 cookie。

重要的是要注意,但是,文档内部的链接不会被重写。因此,internal.example.com上的任何绝对链接都将导致 Client 端脱离代理服务器并直接向internal.example.com请求。您可以使用mod_substitute修改页面中的这些链接(和其他内容),以便将其提供给 Client 端。

Substitute "s/internal\.example\.com/www.example.com/i"

要更复杂地重写 HTML 和 XHTML 中的链接,还可以使用mod_proxy_html模块。它允许您创建需要重写的 URL Map,以便可以处理复杂的代理方案。

Rewriting Engine

当需要更强大的替换时,mod_rewrite提供的重写引擎可能会很有用。该模块提供的指令可以使用请求的 Feature(例如浏览器类型或源 IP 地址)来决定从何处提供内容。另外,mod_rewrite 可以使用外部数据库文件或程序来确定如何处理请求。重写引擎能够执行上述所有三种类型的 Map:内部重定向(别名),外部重定向和代理。在详细的 mod_rewrite 文档中讨论了许多使用 mod_rewrite 的实际示例。

找不到文件

不可避免地,将请求在文件系统中找不到匹配文件的 URL。发生这种情况有几个原因。在某些情况下,这可能是由于将文档从一个位置移动到另一位置的结果。在这种情况下,最好使用URL redirection通知 Client 端资源的新位置。这样,即使资源位于新位置,您也可以确保旧书签和链接将 continue 起作用。

导致“找不到文件”错误的另一个常见原因是直接在浏览器中或在 HTML 链接中意外误入 URL。 httpd 提供了模块mod_speling(原文如此)来帮助解决此问题。激活此模块后,它将拦截“找不到文件”错误,并寻找具有相似文件名的资源。如果找到一个这样的文件,则 mod_speling 将向 Client 端发送 HTTP 重定向,以通知其正确的位置。如果找到几个“关闭”文件,则将向 Client 端显示可用替代项的列表。

mod_speling 的一个特别有用的功能是,它将比较文件名而不考虑大小写。这可以帮助用户不知道 URL 和 unix 文件系统区分大小写的系统。但是,除了偶尔进行 URL 校正之外,将 mod_speling 用于其他任何事情都可能给服务器带来额外的负担,因为每个“不正确”的请求都将跟随 URL 重定向和来自 Client 端的新请求。

mod_dir提供FallbackResource,可用于将虚拟 URI Map 到真实资源,然后为它们提供服务。在实现“前端控制器”时,这是mod_rewrite的非常有用的替代

如果所有查找内容的尝试均失败,则 httpd 返回带有 HTTP 状态代码 404(找不到文件)的错误页面。该页面的外观由ErrorDocument指令控制,可以按照自定义错误响应文档中讨论的灵活方式自定义。

其他 URL Map 模块

可用于 URL Map 的其他模块包括:

首页