快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

Apache的ReWrite的应用(2)


print "The document has moved <a HREF="$url">here</a>.<p>n";
print "</body>n";
print "</html>n";
##EOF##

  这是一种可以重定向所有URL类型的方法,包括不被mod_rewrite直接支持的类型。所以,还可以这样重定向news:newsgroup:

  代码:

  RewriteRule ^anyurl xredirect:news:newsgroup

  注意:无须对上述规则加[R]或[R,L],因为xredirect:会在稍后被其特殊的传送规则扩展。

  文档访问的多路复用

  说明:

  你知道http://www.perl.com/CPAN的CPAN(Comprehensive Perl Archive Network)吗?它实现了一个重定向以提供,全世界的CPAN镜像中离访问者最近的一个FTP站点,也可以称之为FTP访问多路复用服务。CPAN是通过CGI脚本实现的,那么用mod_rewrite如何实现呢?

  方案:

  首先,我们注意到mod_rewrite从3.0.0版本开始,还可以重写"ftp:"类型。其次,对客户端顶级域名的路径最近的求取可以用RewriteMap实现。利用链式规则集,并用顶级域名作为查找多路复用地图的键,可以这样做:

  代码:

  RewriteEngine on

  RewriteMap multiplex txt:/path/to/map.cxan

  RewriteRule ^/CxAN/(.*) %{REMOTE_HOST}::$1 [C]

  RewriteRule ^.+.([a-zA-Z]+):.*)$ ${multiplex:$1|ftp.default.dom}$2 [R,L]

  ##

  ## map.cxan -- Multiplexing Map for CxAN

  ##

  de ftp://ftp.cxan.de/CxAN/

  uk ftp://ftp.cxan.uk/CxAN/

  com ftp://ftp.cxan.com/CxAN/

  :

  ##EOF##

  依赖于时间的重写

  说明:

  在页面内容依时间不同而变化的场合,比如重定向特定页面,许多网管仍然采用CGI脚本的方法,如何用mod_rewrite来实现呢?

  方案:

  有许多类似TIME_xxx的变量可以用在重写条件中,利用<STRING,>STRING和=STRING的类型比较,并加以连接,就可以实现依赖于时间的重写:

  代码:

  RewriteEngine on

  RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700

  RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900

  RewriteRule ^foo.html$ foo.day.html

  RewriteRule ^foo.html$ foo.night.html

  此例使URL foo.html在07:00-19:00时指向foo.day.html,而在其余时间,则指向foo.night.html,对主页是一个不错的功能...

  对YYYY过渡为XXXX的向前兼容

  说明:

  在转变了大批.html文件为.phtml,使文档.YYYY过渡成为文档.XXXX后,如何保持URL的向前兼容(仍然虚拟地存在)?

  方案:

  只须按基准文件名重写,并测试带有新的扩展名的文件是否存在,如果存在,则用新的,否则,仍然用原来的。

  代码:

  # backward compatibility ruleset for

  # rewriting document.html to document.phtml

  # when and only when document.phtml exists

  # but no longer document.html

  RewriteEngine on

  RewriteBase /~quux/

  # parse out basename, but remember the fact

  RewriteRule ^(.*).html$ $1 [C,E=WasHTML:yes]

  # rewrite to document.phtml if exists

  RewriteCond %{REQUEST_FILENAME}.phtml -f

  RewriteRule ^(.*)$ $1.phtml [S=1]

  # else reverse the previous basename cutout

  RewriteCond %{ENV:WasHTML} ^yes$

  RewriteRule ^(.*)$ $1.html

  内容的处理

  新旧URL(内部的)

  说明:

  假定已经把文件bar.html改名为foo.html,需要对老的URL向前兼容,即让用户仍然可以使用老的URL,而感觉不到文件被改名了。

  方案:

  通过以下规则内部地重写老的URL为新的:

  代码:

  RewriteEngine on

  RewriteBase /~quux/

  RewriteRule ^foo.html$ bar.html

  新旧URL(外部的)

  说明:

  仍然假定已经把文件bar.html改名为foo.html,需要对老的URL向前兼容,但是要让用户得到文件被改名的暗示,即,其浏览器的地址栏中显示的是新的URL。

  方案:

  作一个HTTP的强制重定向以改变浏览器和用户界面上的显示:

  代码:

  RewriteEngine on

  RewriteBase /~quux/

  RewriteRule ^foo.html$ bar.html [R]

  依赖于浏览器的内容

  说明:

  至少对重要的顶级页面,有时候有必要提供依赖于浏览器的最佳的内容,即对最新的Netscape提供最大化的版本,对Lynx提供最小化的版本,而对其他的浏览器则提供一个功能一般的版本。

  方案:

  对此,内容协商无能为力,因为浏览器不提供其那种形式的类型,所以只能在HTTP头"User-Agent"上想办法。以下规则集可以完成这个操作:如果HTTP头"User-Agent"以"Mozilla/3"开头,则页面foo.html被重写为foo.NS.html,而后重写操作终止;如果是"Lynx"或者版本号为1和2的"Mozilla",则重写为foo.20.html;而其他所有的浏览器收到的页面则是foo.32.html:

  代码:

  RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*

  RewriteRule ^foo.html$ foo.NS.html [L]

  RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]

  RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*

  RewriteRule ^foo.html$ foo.20.html [L]

  RewriteRule ^foo.html$ foo.32.html [L]

  动态镜像

  说明:

  假定,需要在我们的名称空间里加入其他远程主机的页面。对FTP服务器,可以用mirror程序以在本地机器上维持一个对远程数据的最新的拷贝;对网站服务器,可以用类似的用于HTTP的webcopy程序。但这两种技术都有一个主要的缺点:此本地拷贝必须通过这个程序的执行来更新。所以,比较好的方法是,不采用静态镜像,而采用动态镜像,即,在有数据请求时自动更新(远程主机上更新的数据)。

  方案:

  为此,使用Proxy Throughput功能(flag [P]),以映射远程页面甚至整个远程网络区域到我们的名称空间:

  代码:

  RewriteEngine on

  RewriteBase /~quux/

  RewriteRule ^hotsheet/(.*)$ http://www.tstimpreso.com/hotsheet/$1 [P]

  RewriteEngine on

  RewriteBase /~quux/

  RewriteRule ^usa-news.html$ http://www.quux-corp.com/news/index.html [P]

  反向动态镜像

  说明:

  ...

  方案:

  代码:

  RewriteEngine on

  RewriteCond /mirror/of/remotesite/$1 -U

  RewriteRule ^http://www.remotesite.com/(.*)$ /mirror/of/remotesite/$1

  通过Intranet取得丢失的数据

  说明:

  这是一种在受防火墙保护的(内部的)Intranet(www2.quux-corp.dom)上保存和维护实际数据,而虚拟地运行企业级(外部的)Internet网站服务器(www.quux-corp.dom)的巧妙的方法。这种方法是外部服务器在空闲时间从内部服务器取得被请求的数据。

  方案:

  首先,必须确保防火墙对内部服务器的保护,并只允许此外部服务器取得数据。对包过滤(packet-filtering)防火墙,可以如下制定防火墙规则:

  代码:

  ALLOW Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port 80

  DENY Host * Port * --> Host www2.quux-corp.dom Port 80

  按你的实际配置,只要对上例稍作调整即可。接着,建立通过代理后台获取丢失数据的mod_rewrite规则:

  代码:

  RewriteRule ^/~([^/]+)/?(.*) /home/$1/.www/$2

  RewriteCond %{REQUEST_FILENAME} !-f

  RewriteCond %{REQUEST_FILENAME} !-d

  RewriteRule ^/home/([^/]+)/.www/?(.*) http://www2.quux-corp.dom/~$1/pub/$2 [P]

  负载的均衡

  说明:

  如何均衡www.foo.com的负载到www[0-5].foo.com(一共是6个服务器)?

  方案:

  这个问题有许多可能的解决方案,在此,我们讨论通称为“基于DNS(DNS-based)的”方案,和特殊的使用mod_rewrite的方案:

  DNS循环(DNS Round-Robin)

  最简单的方法是用BIND的DNS循环特性,只要按惯例设置www[0-9].foo.com的DNS的A(地址)记录,如:

  代码:

  www0 IN A 1.2.3.1

  www1 IN A 1.2.3.2

  www2 IN A 1.2.3.3

  www3 IN A 1.2.3.4

  www4 IN A 1.2.3.5

  www5 IN A 1.2.3.6

  然后,增加以下各项:

  代码:

  www IN CNAME www0.foo.com.

  IN CNAME www1.foo.com.

  IN CNAME www2.foo.com.

  IN CNAME www3.foo.com.

  IN CNAME www4.foo.com.

  IN CNAME www5.foo.com.

  IN CNAME www6.foo.com.

  注意,上述看起来似乎是错误的,但事实上,它的确是BIND中的一个预期的特性,而且也可以这样用。无论如何,现在www.foo.com已经被解析,BIND可以给出www0-www6 - 虽然每次在次序上会有轻微的置换/循环,客户端的请求可以被分散到各个服务器。可是,这并不是一个优秀的负载均衡方案,因为,DNS解析信息可以被网络中其他名称服务器缓冲,而一旦www.foo.com被解析为wwwN.foo.com,则...⒌礁鞲龇?衿髁?/a>

  DNS 负载均衡

  一种成熟的基于DNS的负载均衡方法是使用http://www.stanford.edu/~schemers/d...颍??且桓鯬erl 5程序,带有若干辅助工具,实现了真正的基于DNS的负载均衡。

  代理吞吐循环(Proxy Throughput Round-Robin)

  这是一个使用mod_rewrite及其代理吞吐特性的方法。首先,在DNS记录中,将www0.foo.com固定为www.foo.com,如下:

  代码:

  www IN CNAME www0.foo.com.

  其次,将www0.foo.com转换为一个专职代理服务器,即,由这个机器把所有到来的URL通过内部代理分散到另外5个服务器(www1-www5)。为此,必须建立一个规则集,对所有URL调用一个负载均衡脚本lb.pl。

  代码:

  RewriteEngine on

  RewriteMap lb prg:/path/to/lb.pl

  RewriteRule ^/(.+)$ ${lb:$1} [P,L]

  以下是lb.pl:

  代码:

#!/path/to/perl
##
## lb.pl -- load balancing script
##
$| = 1;
$name = "www"; # the hostname base
$first = 1; # the first server (not 0 here, because 0 is myself)
$last = 5; # the last server in the round-robin
$domain = "foo.dom"; # the domainname
$cnt = 0;
while (<STDIN> ) {
$cnt = (($cnt+1) % ($last+1-$first));
$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
print "http://$server/$_";
}
##EOF##

  最后的说明:这样有用吗?www0.foo.com似乎也会超载呀?答案是:没错,它的确会超载,但是它超载的仅仅是简单的代理吞吐请求!所有诸如SSI、CGI、ePerl等等的处理完全是由其他机器完成的,这个才是要点。

  硬件/TCP循环

  还有一个硬件解决方案。Cisco有一个叫LocalDirector的东西,实现了TCP/IP层的负载均衡,事实上,它是一个位于网站集群前端的电路级网关。如果你有足够资金而且的确需要高性能的解决方案,那么可以用这个。

  反向代理

  说明:

  ...

  方案:

  代码:

##
## apache-rproxy.conf -- Apache configuration for Reverse Proxy Usage
##
# server type
ServerType standalone
Listen 8000
MinSpareServers 16
StartServers 16
MaxSpareServers 16
MaxClients 16
MaxRequestsPerChild 100
# server operation parameters
KeepAlive on
MaxKeepAliveRequests 100
KeepAliveTimeout 15
Timeout 400
IdentityCheck off
HostnameLookups off
# paths to runtime files
PidFile /path/to/apache-rproxy.pid
LockFile /path/to/apache-rproxy.lock
ErrorLog /path/to/apache-rproxy.elog
CustomLog /path/to/apache-rproxy.dlog "%{%v/%T}t %h -> %{SERVER}e URL: %U"
# unused paths
ServerRoot /tmp
DocumentRoot /tmp
CacheRoot /tmp
RewriteLog /dev/null
TransferLog /dev/null
TypesConfig /dev/null
AccessConfig /dev/null
ResourceConfig /dev/null
# speed up and secure processing
<Directory />
Options -FollowSymLinks -SymLinksIfOwnerMatch
AllowOverride None
</Directory>
# the status page for monitoring the reverse proxy
<Location /apache-rproxy-status>
SetHandler server-status
</Location>
# enable the URL rewriting engine
RewriteEngine on
RewriteLogLevel 0
# define a rewriting map with value-lists where
# mod_rewrite randomly chooses a particular value
RewriteMap server rnd:/path/to/apache-rproxy.conf-servers
# make sure the status page is handled locally
# and make sure no one uses our proxy except ourself
RewriteRule ^/apache-rproxy-status.* - [L]
RewriteRule ^(http|ftp)://.* - [F]
# now choose the possible servers for particular URL types
RewriteRule ^/(.*.(cgi|shtml))$ to://${server:dynamic}/$1 [S=1]
RewriteRule ^/(.*)$ to://${server:static}/$1
# and delegate the generated URL by passing it
# through the proxy module
RewriteRule ^to://([^/]+)/(.*) http://$1/$2 [E=SERVER:$1,P,L]
# and make really sure all other stuff is forbidden
# when it should survive the above rules...
RewriteRule .* - [F]
# enable the Proxy module without caching
ProxyRequests on
NoCache *
# setup URL reverse mapping for redirect reponses
ProxyPassReverse / http://www1.foo.dom/
ProxyPassReverse / http://www2.foo.dom/
ProxyPassReverse / http://www3.foo.dom/
ProxyPassReverse / http://www4.foo.dom/
ProxyPassReverse / http://www5.foo.dom/
ProxyPassReverse / http://www6.foo.dom/
##
## apache-rproxy.conf-servers -- Apache/mod_rewrite selection table
##
# list of backend servers which serve static
# pages (HTML files and Images, etc.)
static www1.foo.dom|www2.foo.dom|www3.foo.dom|www4.foo.dom
# list of backend servers which serve dynamically
# generated page (CGI programs or mod_perl scripts)
dynamic www5.foo.dom|www6.foo.dom

  新的MIME类型,新的服务

  说明:

  网上有许多很技巧的CGI程序,但是用法晦涩,许多网管弃之不用。即使是Apache的MEME类型的动作处理器,也仅仅在CGI程序不需要在其输入中包含特殊URL(PATH_INFO和QUERY_STRINGS)时才很好用。首先,配置一种新的后缀为.scgi(for secure CGI)文件类型,其处理器是很常见的cgiwrap程序。问题是:如果使用同类URL规划(见上述),而用户宿主目录中的一个文件的URL是/u/user/foo/bar.scgi,可是cgiwrap要求的URL的格式是/~user/foo/bar.scgi/,以下规则解决了这个问题:

  代码:

  RewriteRule ^/[uge]/([^/]+)/.www/(.+).scgi(.*) ...

  ... /internal/cgi/user/cgiwrap/~$1/$2.scgi$3 [NS,T=application/x-http-cgi]

  另外,假设需要使用其他程序:wwwlog(显示access.log中的一个URL子树)和wwwidx(对一个URL子树运行Glimpse),则必须对这些程序提供URL区域作为其操作对象。比如,对/u/user/foo/执行swwidx程序的超链是这样的:

  代码:

  /internal/cgi/user/swwidx?i=/u/user/foo/

  其缺点是,必须同时硬编码超链中的区域和CGI的路径,如果重组了这个区域,就需要花费大量时间来修改各个超链。

  方案:

  方案是用一个特殊的新的URL格式,自动拼装CGI参数:

  代码:

  RewriteRule ^/([uge])/([^/]+)(/?.*)/* /internal/cgi/user/wwwidx?i=/$1/$2$3/

  RewriteRule ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3

  现在,这个搜索到/u/user/foo/的超链简化成了:

  代码:

  HREF="*"

  它会被内部地自动转换为

  代码:

  /internal/cgi/user/wwwidx?i=/u/user/foo/

  如此,可以为使用:log的超链,拼装出调用CGI程序的参数。

  从静态到动态

  说明:

  如何无缝转换静态页面foo.html为动态的foo.cgi,而不为浏览器/用户所察觉。

  方案:

  只须重写此URL为CGI-script,以强制为可以作为CGI-script运行的正确的MIME类型。如此,对/~quux/foo.html的请求其实会执行/~quux/foo.cgi。

  代码:

  RewriteEngine on

  RewriteBase /~quux/

  RewriteRule ^foo.html$ foo.cgi [T=application/x-httpd-cgi]

  空闲时间内的内容协商

  说明:

  这是一个很难解的功能:动态生成的静态页面,即,它应该作为静态页面发送(从文件系统中读出,然后直接发出去),但是如果它丢失了,则由服务器动态生成。如此,可以静态地提供CGI生成的页面,除非有人(或者是一个cronjob)删除了这些静态页面,而且其内容可以得到更新。

  方案:

  以下规则集实现这个功能:

  代码:

  RewriteCond %{REQUEST_FILENAME} !-s

  RewriteRule ^page.html$ page.cgi [T=application/x-httpd-cgi,L]

  这样,如果page.html不存在或者文件大小为null,则对page.html的请求会导致page.cgi的运行。其中奥妙在于,page.cgi是一个将输出写入page.html的(同时也写入STDOUT)的常规的CGI脚本,执行完毕,服务器则将page.html的内容发出。如果网管需要强制更新其内容,只须删除page.html即可(通常由一个cronjob完成)。

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论