📄 rewriteguide.html
字号:
RewriteRule ^foo\.html$ foo.day.html
RewriteRule ^foo\.html$ foo.night.html
</pre></div>
<p>此例使URLfoo.html在07:00-19:00时指向foo.day.html ,而在其余时间,则指向foo.night.html ,对主页是一个不错的功能...</p>
</dd>
</dl>
<h3>对YYYY过渡为XXXX的向前兼容</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>在转变了大批.html文件为.phtml ,使文档.YYYY过渡成为文档.XXXX后,如何保持URL的向前兼容(仍然虚拟地存在)?</p>
</dd>
<dt>方案:</dt>
<dd>
<p>只须按基准文件名重写,并测试带有新的扩展名的文件是否存在,如果存在,则用新的,否则,仍然用原来的。</p>
<div class="example"><pre>
# 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
</pre></div>
</dd>
</dl>
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="content" id="content">内容的处理</a></h2>
<h3>新旧URL(内部的)</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>假定已经把文件<code>bar.html</code>改名为<code>foo.html</code> ,需要对老的URL向前兼容,即让用户仍然可以使用老的URL,而感觉不到文件被改名了。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>通过以下规则内部地重写老的URL为新的:</p>
<div class="example"><pre>
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html
</pre></div>
</dd>
</dl>
<h3>新旧URL(外部的)</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>仍然假定已经把文件<code>bar.html</code>改名为<code>foo.html</code> ,需要对老的URL向前兼容,但是要让用户得到文件被改名的暗示,即浏览器的地址栏中显示的是新的URL。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>作一个HTTP的强制重定向以改变浏览器和用户界面上的显示:</p>
<div class="example"><pre>
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html [<strong>R</strong>]
</pre></div>
</dd>
</dl>
<h3>依赖于浏览器的内容</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>至少对重要的顶级页面,有时候有必要提供依赖于浏览器的最佳的内容,即对最新的Netscape提供最大化的版本,对Lynx提供最小化的版本,而对其他的浏览器则提供一个功能一般的版本。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>对此,内容协商无能为力,因为浏览器不提供那种形式的类型,所以只能在HTTP头"User-Agent"上想办法。以下规则集可以完成这个操作:如果HTTP头"User-Agent"以"Mozilla/3"开头,则页面<code>foo.html</code>被重写为<code>foo.NS.html</code> ,而后重写操作终止;如果是"Lynx"或者版本号为1和2的"Mozilla",则重写为<code>foo.20.html</code> ;而其他所有的浏览器收到的页面则是<code>foo.32.html</code></p>
<div class="example"><pre>
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/3</strong>.*
RewriteRule ^foo\.html$ foo.<strong>NS</strong>.html [<strong>L</strong>]
RewriteCond %{HTTP_USER_AGENT} ^<strong>Lynx/</strong>.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/[12]</strong>.*
RewriteRule ^foo\.html$ foo.<strong>20</strong>.html [<strong>L</strong>]
RewriteRule ^foo\.html$ foo.<strong>32</strong>.html [<strong>L</strong>]
</pre></div>
</dd>
</dl>
<h3>动态镜像</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>假定,需要在我们的名称空间里加入其他远程主机的页面。对FTP服务器,可以用<code>mirror</code>程序以在本地机器上维持一个对远程数据的最新的拷贝;对web服务器,可以用类似的用于HTTP的<code>webcopy</code>程序。但这两种技术都有一个主要的缺点:此本地拷贝必须通过这个程序的执行来更新。所以,比较好的方法是,不采用静态镜像,而采用动态镜像,即在有数据请求时自动更新(远程主机上更新的数据)。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>为此,使用代理吞吐(<dfn>Proxy Throughput</dfn>)功能(flag <code>[P]</code>),以映射远程页面甚至整个远程网络区域到我们的名称空间:</p>
<div class="example"><pre>
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^<strong>hotsheet/</strong>(.*)$ <strong>http://www.tstimpreso.com/hotsheet/</strong>$1 [<strong>P</strong>]
</pre></div>
<div class="example"><pre>
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^<strong>usa-news\.html</strong>$ <strong>http://www.quux-corp.com/news/index.html</strong> [<strong>P</strong>]
</pre></div>
</dd>
</dl>
<h3>反向动态镜像</h3>
<dl>
<dt>说明:</dt>
<dd>...</dd>
<dt>方案:</dt>
<dd>
<div class="example"><pre>
RewriteEngine on
RewriteCond /mirror/of/remotesite/$1 -U
RewriteRule ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
</pre></div>
</dd>
</dl>
<h3>通过Intranet取得丢失的数据</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>这是一种在受防火墙保护的(内部)Intranet(<code>www2.quux-corp.dom</code>)上保存和维护实际数据,而虚拟地运行企业级(外部)Internet web服务器(<code>www.quux-corp.dom</code>)的巧妙的方法。这种方法是外部服务器在空闲时间从内部服务器取得被请求的数据。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>首先,必须确保防火墙对内部服务器的保护,并只允许此外部服务器取得数据。对包过滤(packet-filtering)防火墙,可以如下制定防火墙规则:</p>
<div class="example"><pre>
<strong>ALLOW</strong> Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port <strong>80</strong>
<strong>DENY</strong> Host * Port * --> Host www2.quux-corp.dom Port <strong>80</strong>
</pre></div>
<p>按你的实际配置,只要对上例稍作调整即可。接着,建立通过代理后台获取丢失数据的<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>规则:</p>
<div class="example"><pre>
RewriteRule ^/~([^/]+)/?(.*) /home/$1/.www/$2
RewriteCond %{REQUEST_FILENAME} <strong>!-f</strong>
RewriteCond %{REQUEST_FILENAME} <strong>!-d</strong>
RewriteRule ^/home/([^/]+)/.www/?(.*) http://<strong>www2</strong>.quux-corp.dom/~$1/pub/$2 [<strong>P</strong>]
</pre></div>
</dd>
</dl>
<h3>负载的均衡</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>如何均衡<code>www.foo.com</code>的负载到<code>www[0-5].foo.com</code>(一共是6个服务器)?</p>
</dd>
<dt>方案:</dt>
<dd>
<p>这个问题有许多可能的解决方案,在此,我们讨论通称为“基于DNS”的方案,和特殊的使用<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>的方案:</p>
<ol>
<li>
<strong>DNS循环(DNS Round-Robin)</strong>
<p>最简单的方法是用<code>BIND</code>的DNS循环特性,只要按惯例设置<code>www[0-9].foo.com</code>的DNS的A(地址)记录,如:</p>
<div class="example"><pre>
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
</pre></div>
<p>然后,增加以下各项:</p>
<div class="example"><pre>
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.
</pre></div>
<p>注意,上述看起来似乎是错误的,但事实上,它的确是<code>BIND</code>中的一个预期的特性,而且也可以这样用。无论如何,现在<code>www.foo.com</code>已经被解析,<code>BIND</code>可以给出<code>www0-www6</code> ,虽然每次在次序上会有轻微的置换/循环,客户端的请求可以被分散到各个服务器。但这并不是一个优秀的负载均衡方案,因为DNS解析信息可以被网络中其他名称服务器缓冲,而一旦<code>www.foo.com</code>被解析为<code>wwwN.foo.com</code>,则其后继请求都将被送往<code>www.foo.com</code>。但是最终结果是正确的,因为请求的总量的确被分散到各个服务器了</p>
</li>
<li>
<strong>DNS 负载均衡</strong>
<p>一种成熟的基于DNS的负载均衡方法是使用<a href="http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html">http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html</a>的<code>lbnamed</code>程序,它是一个Perl5程序,带有若干辅助工具,实现了真正的基于DNS的负载均衡。</p>
</li>
<li>
<strong>代理吞吐循环(Proxy Throughput Round-Robin)</strong>
<p>这是一个使用<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>及其代理吞吐特性的方法。首先,在DNS记录中将<code>www0.foo.com</code>固定为<code>www.foo.com</code> ,如下:</p>
<div class="example"><pre>
www IN CNAME www0.foo.com.
</pre></div>
<p>其次,将<code>www0.foo.com</code>转换为一个专职代理服务器,即由这个机器把所有到来的URL通过内部代理分散到另外5个服务器(<code>www1-www5</code>)。为此,必须建立一个规则集,对所有URL调用一个负载均衡脚本<code>lb.pl</code> 。</p>
<div class="example"><pre>
RewriteEngine on
RewriteMap lb prg:/path/to/lb.pl
RewriteRule ^/(.+)$ ${lb:$1} [P,L]
</pre></div>
<p>以下是<code>lb.pl</code> :</p>
<div class="example"><pre>
#!/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##
</pre></div>
<div class="note">最后的说明:这样有用吗?<code>www0.foo.com</code>似乎也会超载呀?答案是:没错,它的确会超载,但是它超载的仅仅是简单的代理吞吐请求!所有诸如SSI、CGI、ePerl等等的处理完全是由其他机器完成的,这个才是要点。</div>
</li>
<li>
<strong>硬件/TCP循环</strong>
<p>还有一个硬件解决方案。Cisco有一个叫LocalDirector的东西,实现了TCP/IP层的负载均衡,事实上,它是一个位于网站集群前端的电路级网关。如果你有足够资金而且的确需要高性能的解决方案,那么可以用这个。</p>
</li>
</ol>
</dd>
</dl>
<h3>反向代理</h3>
<dl>
<dt>说明:</dt>
<dd>...</dd>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -