![]() |
|
|||||||
| 服务器环境搭建 Windows,Linux,IIS,Apache等服务器配置、安全维护以及PHP和MYSQL运行环境讨论。 |
![]() |
|
|
Thread Tools | Display Modes |
|
#1
IP: 218.2.67.48
|
|||
|
|||
|
重定向失败的URL到其他网站服务器
说明: 如何重写URL以重定向对网站服务器A的失败请求到服务器B,是一个常见的问题。一般,可以用Perl写的CGI脚本通过ErrorDocument来解决,此外,还有mod_rewrite方案。但是须注意,这种方法的执行效率不如用ErrorDocument的CGI脚本! 方案: 第一种方案,有最好的性能而灵活性欠佳,出错概率小所以安全: 代码: RewriteEngine on RewriteCond /your/docroot/% !-f RewriteRule ^(.+) http://webserverB.dom/$1 但是其问题在于,它只对位于DocumentRoot中的页面有效。虽然可以增加更多的条件(比如同时还处理宿主目录,等等),但是还有一个更好的方法: 代码: RewriteEngine on RewriteCond % !-U RewriteRule ^(.+) http://webserverB.dom/$1 这种方法使用了mod_rewrite提供的“向前参照(look-ahead)”的功能,是一种对所有URL类型都有效而且安全的方法。但是,对网站服务器的性能会有影响,所以如果网站服务器有一个强大的CPU,那就用这个方法。而在慢速机器上,可以用第一种方法,或者用性能更好的ErrorDocument CGI脚本。 扩展的重定向 说明: 有时候,我们会需要更多的对重定向URL的(有关字符转义机制方面的)控制。通常,Apache内核中的URL转义函数uri_escape()同时还会对anchor转义,即,类似"url#anchor"的URL,因此,你不能用mod_rewrite对此类URL直接重定向。那么如何实现呢? 方案: 必须用NPH-CGI脚本使它自己重定向,因为对NPH(non-parseable headers [无须解析的HTTP头])不会发生转义操作。首先,在针对服务器的配置中(应该位于所有重写规则的最后),引入一种新的URL类型xredirect:: 代码: RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 [T=application/x-httpd-cgi,L] 以强制所有带xredirect:前缀的URL被传送到如下的nph-xredirect.cgi程序: 代码: #!/path/to/perl ## ## nph-xredirect.cgi -- NPH/CGI script for extended redirects ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## $| = 1; $url = $ENV; print "HTTP/1.0 302 Moved Temporarilyn"; print "Server: $ENVn"; print "Location: $urln"; print "Content-type: text/htmln"; print "n"; print "n"; print "n"; print "n"; print "n"; print "n"; print " Moved Temporarily (EXTENDED) n"; print "The document has moved here. n"; print "n"; print "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/(.*) %::$1 [C] RewriteRule ^.+.([a-zA-Z]+)::(.*)$ $$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的类型比较,并加以连接,就可以实现依赖于时间的重写: 代码: RewriteEngine on RewriteCond %% >0700 RewriteCond %% <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 %.phtml -f RewriteRule ^(.*)$ $1.phtml [S=1] # else reverse the previous basename cutout RewriteCond % ^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 % ^Mozilla/3.* RewriteRule ^foo.html$ foo.NS.html [L] RewriteCond % ^Lynx/.* [OR] RewriteCond % ^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 % !-f RewriteCond % !-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,则其后继请求都将被送往www.foo.com。但是最终结果是正确的,因为请求的总量的确被分散到各个服务器了 DNS 负载均衡 一种成熟的基于DNS的负载均衡方法是使用http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html的lbnamed程序,它是一个Perl 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 ^/(.+)$ $ [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 () { $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 "%t %h -> %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 Options -FollowSymLinks -SymLinksIfOwnerMatch AllowOverride None # the status page for monitoring the reverse proxy SetHandler server-status # 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://$/$1 [S=1] RewriteRule ^/(.*)$ to://$/$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] Last edited by sunshine : 2006-02-18 at 10:07 PM |
![]() |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
|
|