从URL到文件系统的映射
本文阐述Apache如何根据URL地址定位到文件在文件系统中的位置。
DocumentRoot
Apache根据请求定位文件的默认操作是:取出URL路径(即URL中主机名和端口后面的部分)附加到由DocumentRoot
指定的文件系统路径后面。这样就组成了在网上所看见的基本文件树结构。
如果服务器有多个虚拟主机,则Apache会使用下述两种方法之一:使用每个虚拟主机自己的DocumentRoot
来组成文件系统路径,或者使用由mod_vhost_alias
提供的指令基于IP地址或主机名动态地定位文件。
DocumentRoot以外的文件
实际应用中,经常有必要允许网络对DocumentRoot
以外的文件进行访问。对此,Apache提供了多种方法,在Unix系统中,可以在文件系统的DocumentRoot
目录下放置符号连接以访问其外部文件,考虑到安全问题,这种方法仅在相应目录的Options
指令中设置了FollowSymLinks
或SymLinksIfOwnerMatch
时才有效。
另外,使用Alias
指令可以将文件系统的任何部分映射到网络空间中。例如,这个命令
Alias /docs /var/web
可以把URL http://www.example.com/docs/dir/file.html
映射为/var/web/dir/file.html
。ScriptAlias
指令功能相似,而且使所有目标路径下的所有文件被视为CGI脚本。
AliasMatch
和ScriptAliasMatch
指令可以实现基于正则表达式的匹配和替换,以提供更大的灵活性。例如:
ScriptAliasMatch ^/~([a-zA-Z0-9]+)/cgi-bin/(.+) /home/$1/cgi-bin/$2
上述命令可以将http://example.com/~user/cgi-bin/script.cgi
映射到/home/user/cgi-bin/script.cgi
,并视之为CGI脚本。
用户目录
在Unix系统中,一个特定用户"user"的主目录通常是"~user/
"模块mod_userdir
在网络上沿用了这个概念,允许使用URL访问位于各用户主目录下的文件,例如:
http://www.example.com/~user/file.html
出于安全原因,不应该给予网络用户直接操作主目录的权限,而应该在用户主目录下新建一个目录,把网络文件放在这个新建的目录中,并用UserDir
指令告诉服务器。缺省的用户目录设置是"Userdir public_html
",因此,上述例子中的URL会映射到/home/user/public_html/file.html
,其中/home/user/
是/etc/passwd
指定的用户主目录。
当/etc/passwd
没有指定主目录,那就要用到Userdir
指令的另几种形式。
有些人觉得符号"~"(时常会被编码为%7e
)很别扭,希望用其他形式来表达用户目录。虽然模块mod_userdir
并不支持,但是,如果合理规划服务器上的用户目录,则还是有可能用AliasMatch
指令来达到这个目的。例如,如果希望将http://www.example.com/upages/user/file.html
映射到/home/user/public_html/file.html
,可以这样使用AliasMatch
指令:
AliasMatch ^/upages/([a-zA-Z0-9]+)/?(.*) /home/$1/public_html/$2
URL重定向
上述指令都指示Apache返回给客户文件系统的某个特定内容,但是有时候,需要通知客户其请求的内容位于其他URL,并使客户产生新的对其他URL的请求,这种机制称为重定向(redirection),可以用Redirect
指令实现。例如:如果DocumentRoot
的目录/foo/
被转移到了/bar/
,则可以这样引导客户访问新的位置:
Redirect permanent /foo/ http://www.example.com/bar/
这个命令重定向任何以/foo/
开头的URL路径到位于同一个服务器www.example.com
的/bar/
。当然,可以重定向到任何其它服务器,而不仅仅是原来的那个。
Apache还提供了RedirectMatch
指令来解决复杂的重定向问题。例如,要重定向对站点主页的请求到其他站点,而保留其他所有请求,可以这样配置:
RedirectMatch permanent ^/$ http://www.example.com/startpage.html
另一种方法是,暂时地重定向站点的所有页面到一个特定页面,如:
RedirectMatch temp .* http://othersite.example.com/startpage.html
反向代理
Apache还允许将远程文档纳入本地服务器的网络空间中,因为Web服务器扮演一个代理服务器的角色(从远程服务器取得文档并返回给客户),所以这种机制被称为反向代理(reverse proxying),不同于标准代理的是,在客户看来,他请求的文档似乎原本就位于这个反向代理服务器上。
下例演示了当客户请求位于/foo/
目录下的文档时,服务器从internal.example.com
的/bar/
目录下取回文档并返回给客户,似乎文档原本就在本地服务器上:
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
的请求,使之指向本地服务器上的目录。同样,ProxyPassReverseCookieDomain
和ProxyPassReverseCookieDomain
指令将会改变后端服务器设置的cookie 。
需要注意的很重要的一点是,被取回的文档中的连接是不会被改写的,因此,文档中的所有绝对路径连接会突破代理机制而直接从internal.example.com
取得。一个第三方模块mod_proxy_html可以用于重写HTML和XHTML连接。
URL重写引擎
mod_rewrite
模块提供了更强大的URL重写引擎,可以根据请求中诸如浏览器类型、源IP地址等特征来决定最终提交给客户的内容,还可以使用外部数据库或程序来决定如何处理一个请求,并可以执行上述的所有三种映射:内部重定向(aliases)、外部重定向、代理。许多实用程序都用到了这个模块,详细论述参见:URL重写指南。
URL重定向来引导用户访问新的位置,这样,虽然资源已经转移到新的位置,但是原来的书签和连接仍然有效。
另一种常见的原因是浏览器地址栏或者HTML连接中的URL被拼写错了,Apache提供了mod_speling
模块来帮助解决这个问题,它会接管"File Not Found"错误并查找相似文件,如果找到了唯一的一个,则会重定向到这个文件,如果不止一个,则会列一张表反馈给用户。
mod_speling
的一个很有用的特性是,它可以忽略大小写查找文件,对不注意URL大小写的用户和unix文件系统尤为实用。但是,纠正偶然的URL错误会给服务器带来额外的负担,因为每次"不正确"的请求都将引发URL重定向和来自客户的新请求。
如果所有的努力都失败了,Apache会返回一个出错信息页面,其状态码为"404"(文件没找到),其页面内容取决于ErrorDocument
指令,并可以灵活地自定义其形式,详见:自定义错误响应。