欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

URL重写指南 有大用 有大用

URL重写指南

可用的语言:EN|让开

原来写的
Ralf S. Engelschall <rse@apache.org>
December 1997

本文件的补充mod_rewrite参考文档。它描述了如何使用Apache的mod_rewrite针对典型的基于URL的问题,很多站长都commonony面临。我们给予详细的说明如何通过配置URL重写规则解决每一个问题。

top

介绍mod_rewrite

Apache模块mod_rewrite是一个杀手之一,即它是一个非常复杂的模块,做一个强大的方式提供URL的处理。有了它你可以做几乎所有类型的URL处理你曾经想过。你要付出的代价是接受的复杂性,因为mod_rewrite的主要缺点是,它是不容易理解和使用的初学者。甚至有时专家发现新的方面,Apachemod_rewrite可以帮助

换句话说:有mod_rewrite你可以拍摄自己的脚第一次没有再次使用它或爱它其余的你的生活因为它的力量。本文试图给你一些初步的成功事件,避免第一例通过已经发明了解你。

top

实用的解决方案

很多实用的解决方案,我也发明了自己的或从过去其他人的解决方案收集来的。随时了解URL重写从这些例子中的魔法。

注意:根据您的服务器配置可以稍微改变的例子,对于你的情况,例如添加[PT]此外,使用时的旗帜对_别名mod_userdir,等或重写规则集以适应htaccess而每个服务器的上下文语境。总是试图了解一个特定的规则集是否真在你使用它。它避免问题。
top

URL布局

规范网址

描述

在一些Web服务器有多个URL资源。通常有典型的URL(应该是实际使用和分布)和那些仅仅是快捷方式,内部的,等独立的URL的用户提供他应该最后只看到规范的要求。

解决方案:

我们做的所有非规范网址固定在浏览器的位置和所有后续的请求外部HTTP重定向。在下面的例子我们替换规则/~user用规范U /用户固定失踪的斜线为/u/user

RewriteRule   ^/~([^/]+)/?(.*)    /u/$1/$2  [R]
RewriteRule   ^/([uge])/([^/]+)$  /$1/$2/   [R]

主机名称

描述
这个规则的目标是迫使某个主机名的使用,更可达到相同的其他网站的主机名。例如,如果你想使用武力www.而不是example.com,你可以使用下面的食谱的一个变种。
解决方案:
# For sites running on a port other than 80
RewriteCond %{HTTP_HOST}   !^www\.example\.com [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteCond %{SERVER_PORT} !^80$
RewriteRule ^/(.*)         http://www.example.com:%{SERVER_PORT}/$1 [L,R]

# And for a site running on port 80
RewriteCond %{HTTP_HOST}   !^www\.example\.com [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteRule ^/(.*)         http://www.example.com/$1 [L,R]

感动DocumentRoot

描述

通常DocumentRoot该Web服务器直接涉及的URL”/“。但是通常这种数据是不是真的顶级优先,这也许只是一个实体的大量数据池。例如,在我们的内部网站有/e/www/(WWW网页),南西/ E / /(对于内网主页)等,因为现在的数据DocumentRoot呆在/ E /网络/我们必须确保所有的内联图像和其他的东西在这个数据池工作后续请求。

解决方案:

我们重定向的URL// E /网络/

RewriteEngine on
RewriteRule   ^/$  /e/www/  [R]

请注意,这也可以使用RedirectMatch指令:

RedirectMatch ^/$ http://example.com/e/www/

斜线的问题

描述

每一个站长可以唱关于URL引用的目录的斜线问题的歌。如果他们不见了,服务器将错误,因为如果你说/~quux/foo而不是quux foo / / / ~然后一个服务器搜索文件命名foo。由于该文件是一个目录,它抱怨。其实它试图修复它本身在大多数情况下,但有时这种机制需要模仿你。例如,在你做了很多复杂的URL重写CGI脚本等。

解决方案:

这个微妙的问题,解决的办法是让服务器自动添加斜线。这样做的正确我们必须使用外部重定向,所以浏览器正确要求后续图像等如果我们只做了一个内部重写,这只会为目录页,但会出错时,任何图像都包含在这页的相对URL,因为浏览器会要求一个排列对象。例如,一个请求image.gif进入/ / / ~ quux foo。将成为/~quux/image.gif没有外部重定向!

所以,要做到这一点我们写的:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo$  foo/  [R]

疯狂和懒惰甚至可以在顶层做以下.htaccess他们是否文件。但是请注意,这造成了一些处理开销。

RewriteEngine  on
RewriteBase    /~quux/
RewriteCond    %{REQUEST_FILENAME}  -d
RewriteRule    ^(.+[^/])$           $1/  [R]

通过均匀的URL布局Webcluster

描述

我们要创建一个均匀和一致的URL布局在Intranet webcluster所有的WWW服务器,即所有的URL(每定义服务器的地方从而服务器依赖!)成为真正的服务器无党派!我们要的是给WWW服务器命名空间一致独立布局:没有URL应该包括任何物理正确的目标服务器。集群本身应该促使我们自动的物理目标主机。

解决方案:

首先,对目标服务器的知识来自(分布式)外部地图包含的信息,我们的用户、组和实体保持。有形式

user1  server_of_user1
user2  server_of_user2
:      :

我们把它们放进文件map.xxx-to-host。二要指导所有服务器重定向的URL

/u/user/anypath
/g/group/anypath
/e/entity/anypath

http://physical-host/u/user/anypath
http://physical-host/g/group/anypath
http://physical-host/e/entity/anypath

当URL不是一个本地服务器有效。下面的规则是我们的地图文件的帮助(假设服务器是一个默认的服务器将用户如果在地图没有进入使用):

RewriteEngine on

RewriteMap      user-to-host   txt:/path/to/map.user-to-host
RewriteMap     group-to-host   txt:/path/to/map.group-to-host
RewriteMap    entity-to-host   txt:/path/to/map.entity-to-host

RewriteRule   ^/u/([^/]+)/?(.*)   http://${user-to-host:$1|server0}/u/$1/$2
RewriteRule   ^/g/([^/]+)/?(.*)  http://${group-to-host:$1|server0}/g/$1/$2
RewriteRule   ^/e/([^/]+)/?(.*) http://${entity-to-host:$1|server0}/e/$1/$2

RewriteRule   ^/([uge])/([^/]+)/?$          /$1/$2/.www/
RewriteRule   ^/([uge])/([^/]+)/([^.]+.+)   /$1/$2/.www/$3\

移动到不同的服务器homedirs

描述

很多站长要解决以下情况:他们想重定向都homedirs在Web服务器的Web服务器。他们通常需要建立一个新的服务器之类的东西,以取代旧的时候。

解决方案:

解决的办法是平凡的mod_rewrite。在旧的服务器只是将所有的~ /用户/ anypath网址http://newserver/~user/anypath

RewriteEngine on
RewriteRule   ^/~(.+)  http://newserver/~$1  [R,L]

结构化homedirs

描述

成千上万的用户通常使用一个结构化的布局是否有些网站,即每个子目录是否是开始,例如对用户名的第一个字符。所以,/~foo/anypath/家/F/ / www / anypath foo。虽然/~bar/anypath/家/B/酒吧/网络/ anypath。

解决方案:

我们使用以下规则扩展的URL到完全上述布局。

RewriteEngine on
RewriteRule   ^/~(([a-z])[a-z0-9]+)(.*)  /home/$2/$1/.www$3

文件系统重组

描述

这真的是一个铁杆的例子:一个严重使用每个目录的杀手级应用RewriteRules得到一个光滑的外观和感觉的网站,其数据结构是从未接触过或调整。背景net.sw是我的免费的UNIX软件档案,我开始收集1992。这是我的爱好和工作于此,因为我在学习计算机科学的我也做了很多年的一个系统和网络管理员在我的业余时间。每星期我需要一些软件,所以我创造了我在哪里存储包目录深层次:

drwxrwxr-x   2 netsw  users    512 Aug  3 18:39 Audio/
drwxrwxr-x   2 netsw  users    512 Jul  9 14:37 Benchmark/
drwxrwxr-x  12 netsw  users    512 Jul  9 00:34 Crypto/
drwxrwxr-x   5 netsw  users    512 Jul  9 00:41 Database/
drwxrwxr-x   4 netsw  users    512 Jul 30 19:25 Dicts/
drwxrwxr-x  10 netsw  users    512 Jul  9 01:54 Graphic/
drwxrwxr-x   5 netsw  users    512 Jul  9 01:58 Hackers/
drwxrwxr-x   8 netsw  users    512 Jul  9 03:19 InfoSys/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:21 Math/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:24 Misc/
drwxrwxr-x   9 netsw  users    512 Aug  1 16:33 Network/
drwxrwxr-x   2 netsw  users    512 Jul  9 05:53 Office/
drwxrwxr-x   7 netsw  users    512 Jul  9 09:24 SoftEng/
drwxrwxr-x   7 netsw  users    512 Jul  9 12:17 System/
drwxrwxr-x  12 netsw  users    512 Aug  3 20:15 Typesetting/
drwxrwxr-x  10 netsw  users    512 Jul  9 14:08 X11/

在1996年7月,我决定把这个档案通过一个漂亮的Web界面世界公开。”好的”的意思是,我想提供一个接口,你可以直接浏览通过档案法。“好”意味着,我不想在这个层次的任何变化甚至把一些CGI脚本在上面。为什么?由于上述结构应该是以后可以通过FTP为好,我不想让任何Web或CGI的东西在那里。

解决方案:

解决的办法有两个部分:首先是一套CGI脚本创建的所有页面在所有目录层次上飞。我把它们放在/e/netsw/.www/如下:

-rw-r--r--   1 netsw  users    1318 Aug  1 18:10 .wwwacl
drwxr-xr-x  18 netsw  users     512 Aug  5 15:51 DATA/
-rw-rw-rw-   1 netsw  users  372982 Aug  5 16:35 LOGFILE
-rw-r--r--   1 netsw  users     659 Aug  4 09:27 TODO
-rw-r--r--   1 netsw  users    5697 Aug  1 18:01 netsw-about.html
-rwxr-xr-x   1 netsw  users     579 Aug  2 10:33 netsw-access.pl
-rwxr-xr-x   1 netsw  users    1532 Aug  1 17:35 netsw-changes.cgi
-rwxr-xr-x   1 netsw  users    2866 Aug  5 14:49 netsw-home.cgi
drwxr-xr-x   2 netsw  users     512 Jul  8 23:47 netsw-img/
-rwxr-xr-x   1 netsw  users   24050 Aug  5 15:49 netsw-lsdir.cgi
-rwxr-xr-x   1 netsw  users    1589 Aug  3 18:43 netsw-search.cgi
-rwxr-xr-x   1 netsw  users    1885 Aug  1 17:41 netsw-tree.cgi
-rw-r--r--   1 netsw  users     234 Jul 30 16:35 netsw-unlimit.lst

这个DATA/子目录包含上述目录结构,即房net.sw的东西,会自动更新,通过rdist不时地.问题的第二部分是:如何将这两种结构组合成一个顺利的URL的树吗?我们想隐藏日期/目录从用户对各种运行相应的CGI脚本的URL。这是解决方法:首先我把下面的每个目录的配置文件中DocumentRoot服务器的URL重写宣布/ net.sw/的内部路径/e/netsw

RewriteRule  ^net.sw$       net.sw/        [R]
RewriteRule  ^net.sw/(.*)$  e/netsw/$1

第一个规则是要求错过斜线!第二规则是真实的东西。然后是杀手配置停留在每个目录中的配置文件/e/netsw/.www/.wwwacl

Options       ExecCGI FollowSymLinks Includes MultiViews

RewriteEngine on

#  we are reached via /net.sw/ prefix
RewriteBase   /net.sw/

#  first we rewrite the root dir to
#  the handling cgi script
RewriteRule   ^$                       netsw-home.cgi     [L]
RewriteRule   ^index\.html$            netsw-home.cgi     [L]

#  strip out the subdirs when
#  the browser requests us from perdir pages
RewriteRule   ^.+/(netsw-[^/]+/.+)$    $1                 [L]

#  and now break the rewriting for local files
RewriteRule   ^netsw-home\.cgi.*       -                  [L]
RewriteRule   ^netsw-changes\.cgi.*    -                  [L]
RewriteRule   ^netsw-search\.cgi.*     -                  [L]
RewriteRule   ^netsw-tree\.cgi$        -                  [L]
RewriteRule   ^netsw-about\.html$      -                  [L]
RewriteRule   ^netsw-img/.*$           -                  [L]

#  anything else is a subdir which gets handled
#  by another cgi script
RewriteRule   !^netsw-lsdir\.cgi.*     -                  [C]
RewriteRule   (.*)                     netsw-lsdir.cgi/$1

为了解释一些提示:

  1. 通知L(一)标志和没有替代领域(&#39;在第四部分)
  2. 通知!(不)特征和C(链)在最后一部分的第一条规则的旗帜
  3. 注意抓住在过去的统治模式

NCSA图像映射到Apachemod_imap

描述

从NCSA服务器切换到更现代的Apache Web服务器很多人想要顺利过渡时。所以他们希望用他们的老校的页面imagemap程序工作在Apache与现代mod_imap。问题是,有很多超链接,参考imagemap程序通过的CGI斌/影像/路径/到/ page.map。在Apache这才读/path/to/page.map

解决方案:

我们使用一个全局规则删除所有请求的飞的前缀:

RewriteEngine  on
RewriteRule    ^/cgi-bin/imagemap(.*)  $1  [PT]

在多个目录搜索页面

描述

有时有必要让多个目录服务器搜索页面。这下或其他技术不能帮助。

解决方案:

我们计划一个明确的规则搜索目录中的文件。

RewriteEngine on

#   first try to find it in custom/...
#   ...and if found stop and be happy:
RewriteCond         /your/docroot/dir1/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/dir1/$1  [L]

#   second try to find it in pub/...
#   ...and if found stop and be happy:
RewriteCond         /your/docroot/dir2/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/dir2/$1  [L]

#   else go on for other Alias or ScriptAlias directives,
#   etc.
RewriteRule   ^(.+)  -  [PT]

根据URL部分设置环境变量

描述

也许你想保持请求和使用URL编码之间的状态信息。但你不想用CGI包装所有的页面只是带出了这样的信息。

解决方案:

我们使用重写规则剥离出的状态信息并记住它通过环境变量以后可以引用在xssi或CGI。这样一个URL/foo/S=java/bar/被翻译成/食品/酒吧/与环境变量命名STATUS的值设置为“java”。

RewriteEngine on
RewriteRule   ^(.*)/S=([^/]+)/(.*)    $1/$3 [E=STATUS:$2]

虚拟用户的主机

描述

假设你想提供www.username.host.domain.com对于用户名主页通过DNS记录是一样的机器,在这台计算机上没有任何virtualhosts。

解决方案:

HTTP请求/ 1有没有解决的办法,但是HTTP / 1.1请求包含主机:HTTP头,我们可以使用下面的规则重写http://www.username.host.com/anypath内部/家/用户名/ anypath

RewriteEngine on
RewriteCond   %{HTTP_HOST}                 ^www\.[^.]+\.host\.com$
RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
RewriteRule   ^www\.([^.]+)\.host\.com(.*) /home/$1$2

重定向homedirs外国人

描述

我们要到另一个服务器的URL重定向是否www.somewhere.com当请求的用户不在本地域ourdomain.com。这是有时用于虚拟主机环境。

解决方案:

只是一个重写条件:

RewriteEngine on
RewriteCond   %{REMOTE_HOST}  !^.+\.ourdomain\.com$
RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]

没有其他的服务器URL重定向

描述

关于URL重写一个典型的问题是如何重定向请求到Web服务器失败,通常这是通过BErrorDocument在Perl的CGI脚本,但也有一个mod_rewrite解决方案但是请注意,这种表现更差,比使用ErrorDocumentCGI脚本

解决方案:

第一个解决方案具有最好的性能,但缺乏灵活性,和更少的错误的安全:

RewriteEngine on
RewriteCond   /your/docroot/%{REQUEST_FILENAME} !-f
RewriteRule   ^(.+)                             http://webserverB.dom/$1

在这里,这只会对页面内工作的问题DocumentRoot。虽然你可以添加更多的条件(例如也处理的homedirs,等)有更好的变异:

RewriteEngine on
RewriteCond   %{REQUEST_URI} !-U
RewriteRule   ^(.+)          http://webserverB.dom/$1

使用URL向前看的特征mod_rewrite。结果是,这将为所有类型的URL的工作,是一种安全的方式。但它对服务器性能的影响,因为每一个请求都有一个内部子请求。所以,如果你的服务器运行在一个强大的CPU,用这一个。如果这是一个缓慢的机器,使用第一种方法或更好错误的文件CGI脚本

扩展的重定向

描述

有时候,我们需要更多的控制(关于字符转义机制)的URL重定向。通常Apache内核URL逃逸函数也逃锚,即URL”url#anchor“。你不能用这个直接重定向mod_rewrite因为uri_escape()功能的Apache也逃脱哈希。我们怎么可以重定向到一个URL?

解决方案:

We have to use a kludge by the use of a NPH-CGI script which does the redirect itself. Because here no escaping is done (NPH=non-parseable headers). First we introduce a new URL schemexredirect:每服务器配置线以下(应该是最后一个重写规则):

RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
            [T=application/x-httpd-cgi,L]

在本组urls prefixed withxredirect:要通过管道输送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{'PATH_INFO'};

print "HTTP/1.0 302 Moved Temporarily\n";
print "Server: $ENV{'SERVER_SOFTWARE'}\n";
print "Location: $url\n";
print "Content-type: text/html\n";
print "\n";
print "<html>\n";
print "<head>\n";
print "<title>302 Moved Temporarily (EXTENDED)</title>\n";
print "</head>\n";
print "<body>\n";
print "<h1>Moved Temporarily (EXTENDED)</h1>\n";
print "The document has moved <a HREF=\"$url\">here</a>.<p>\n";
print "</body>\n";
print "</html>\n";

##EOF##

这为你提供了做重定向到URL方案的功能,即包括不直接受理的mod_rewrite。比如你现在也可以重定向到新闻:新闻组通过

RewriteRule ^anyurl  xredirect:news:newsgroup
注意:你不放[R][ R ]上述规则,因为xredirect:需要扩展后,通过特殊的“管子”以上规则。

档案接入复用器

描述

你知道大CPAN(归档网络)下www.perl.com http:/ / /。?这是一个重定向到一个FTP的周围携带的CPAN镜像服务器和世界大约是在发出请求的客户端的位置。其实这可以称为一个FTP访问复用服务。而通过CPAN运行CGI脚本,如何能通过类似的方法实现mod_rewrite

解决方案:

首先我们注意到,从版本3.0.0mod_rewrite也可以使用“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

这提供了内容foo.day.html在URLfoo.html07:00-19:00在剩余的时间内容foo.night.html。一个网页只是一个不错的功能…

为YYYY XXXX迁移的向后兼容性

描述

我们怎样才能使URL的向后兼容(仍然存在几乎)后迁移document.YYYYdocument.xxxx翻译后,如一束.html文件PHTML

解决方案:

我们只是改写名字的basename和拓新的存在性检验。如果它存在,我们把这个名字,否则我们重写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
top

内容处理

从旧到新的(实习)

描述

假设我们最近更名为页foo.htmlbar.html现在想提供向后兼容旧的URL。其实我们要的,用户甚至不承认旧的URL页面更名。

解决方案:

我们重写旧的URL到新的内部通过以下规则:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  bar.html

从旧到新的(外部)

描述

假设我们最近更名为页foo.htmlbar.html现在想提供向后兼容旧的URL。但这一次我们想把旧URL的用户得到暗示新的一个,即浏览器定位领域应该改变,太。

解决方案:

我们强迫一个HTTP重定向导致改变浏览器,用户查看新的URL:

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  bar.html  [R]

浏览器相关的内容

描述

至少对于重要的顶层页面有时需要提供浏览器相关内容的优化,即有最新的Netscape变体提供最大的版本,为天猫浏览器和其他所有人的平均特征版本的最低版本。

解决方案:

我们不能使用内容协商因为浏览器不在形式提供的类型。相反,我们必须按照HTTP头的“用户代理”。以下condig做如下工作:如果HTTP头的“用户代理”开始与“Mozilla / 3”页面foo.html改写foo.ns.html而重写停止。如果浏览器是“山猫”或“Mozilla”版本1或2的网址是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程序实际上保持着一个明确的本地机器上的远程数据备份。一个Web服务器,我们可以使用程序webcopy它的作用类似通过HTTP。但这两种技术都有一个主要的缺点:本地副本是最新的我们总是经常运行程序。如果镜子是不是一个静态的我们必须建立明确的会更好。我们想要一个数据会自动更新,当有需要的时候动态镜像(更新数据在远程主机上)。

解决方案:

提供这个功能我们地图远程网页甚至完整的远程webarea我们命名空间的使用代理吞吐特征(标志[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

检索从内网数据缺失

描述

这是一种微妙的方式实际上是运行一个公司(外部)网络服务器(www.quux-corp.dom),而实际上是保持和维护其数据在内网服务器((内部)www2.quux-corp.dom)这是由防火墙保护。诀窍是,在外部Web服务器检索请求的数据从内部一飞。

解决方案:

首先,我们必须确保我们的防火墙保护的内部网络服务器仍然只有与外部服务器允许从中检索数据。一个包过滤防火墙我们可以配置防火墙规则如下:

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的变体,那么特殊的一个mod_rewrite

  1. DNS轮循

    负载平衡的最简单的方法是使用DNS轮询功能BIND。在这里,你只需要配置WWW foo.com [0-9]。像往常一样,在你的DNS记录,例如一个(地址)

    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,所有后续的请求也去这个名字wwwN.foo.com。但最终的结果是好的,因为要求的总和是遍布各种网络服务器。

  2. DNS负载均衡

    一个复杂的基于DNS的负载均衡方法是使用程序lbnamed它可以发现在HTTP:/ / www.stanford .edu / ~阴谋家/文档/ lbnamed / lbnamed.html。这是一个5程序与辅助工具,提供了一个真正的负载均衡DNS连接Perl。

  3. 代理吞吐循环

    这种变异的利用mod_rewrite其代理的吞吐量特性。首先我们奉献www0.foo.com是真的www.foo.com通过使用一个单一的

    www    IN  CNAME   www0.foo.com.
    

    in the DNS条目。然后我们把www0.foo.com一个代理服务器,即我们配置本机所有到达的网址只是推动内部代理的另外5台服务器(www1 - www5)。要做到这一点我们首先建立一个规则集与负载平衡的脚本lb.pl所有的URL

    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,等处理是完全做对其他机器。这是很重要的一点。
  4. 硬件/ TCP圆知更鸟

    有一个硬件的解决方案,也。思科有叫兽localdirector哪一个负载均衡在TCP/IP层次。其实这是一种在一个webcluster前端电路级网关。如果你有足够的钱,真的需要一个解决方案的高性能,用这一个。

新的MIME类型,新的服务

描述

在网上有很多漂亮的CGI程序。但是,它们的使用通常是无聊的,所以很多站长不使用它们。即使是Apache的操作处理程序特征的MIME类型是只适合当CGI程序不需要特殊的URL(实际上PATH_INFO查询_丁字裤)作为输入。首先,让我们用扩展配置一个新的文件类型.scgi(安全网关)将受处理cgiwrap程序这里的问题是,比如我们用均匀的URL布局(见上图)在用户homedirs文件的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子树一瞥)。我们要为这些项目提供URL区,他们知道在哪个区域他们必须采取行动。但通常这丑陋的,因为他们都是时代的要求,还是从地区,即通常我们会跑swwidx计划内/u/user/foo/通过超链接

/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

Now the hyperlink to search at/u/user/foo/只读取

HREF="*"

其内部会自动转化为

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

同样的方法导致的访问日志的CGI程序调用时的超链接:log习惯

从静态到动态

描述

如何将一个静态页面foo.html为一个动态变foo.cgi在一个无缝的方式,即不通过浏览器/用户的通知。

解决方案:

我们只是重写URL的CGI脚本和力的正确的MIME类型,所以它真正作为一个CGI脚本运行。这种方式要求/~quux/foo.html内部导致调用quux / foo.cgi / ~

RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.html$  foo.cgi  [T=application/x-httpd-cgi]

在飞的内容更新

描述

这里是一个很深奥的特征:动态生成静态页面,但送达,即页面应该是纯静态页面传递(从文件系统读取和刚刚通过了),但他们必须生成服务器动态如果失踪。这样你可以有CGI生成的页面是静态的服务除非(或任务)将静态内容。然后,内容得到刷新。

解决方案:
这是通过以下规则:
RewriteCond %{REQUEST_FILENAME}   !-s
RewriteRule ^page\.html$          page.cgi   [T=application/x-httpd-cgi,L]

这一要求page.html导致内部运行的相应page.cgi如果page.html仍然是丢失或有文件大小的空。这里的诀窍是page.cgi是一种常见的CGI脚本(另外的STDOUT)将其输出到文件page.html。一旦被运行,服务器发送数据page.html。当站长想强制刷新的内容,他只是删除page.html(通过任务通常所做的那样)。

文件与自动刷新

描述

那岂不是很好,而如果浏览器会自动刷新页面,我们写一个新的版本在我们编辑每次创建一个复杂的网页?不可能吗?

解决方案:

不!我们只是把MIME多部分功能,服务器NPH特征和URL处理能力mod_rewrite。首先,我们建立了一个新的URL特征:添加:刷新任何URL导致这被刷新,每一次被文件系统的更新。

RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1

现在,当我们参考the URL

/u/foo/bar/page.html:refresh

这导致内部调用的URL

/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html

唯一缺少的部分是nph-cgi脚本。虽然一个通常会说“留给读者作为练习”;-)我会提供这个,太。

#!/sw/bin/perl
##
##  nph-refresh -- NPH/CGI script for auto refreshing pages
##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##
$| = 1;

#   split the QUERY_STRING variable
@pairs = split(/&/, $ENV{'QUERY_STRING'});
foreach $pair (@pairs) {
    ($name, $value) = split(/=/, $pair);
    $name =~ tr/A-Z/a-z/;
    $name = 'QS_' . $name;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
    eval "\$$name = \"$value\"";
}
$QS_s = 1 if ($QS_s eq '');
$QS_n = 3600 if ($QS_n eq '');
if ($QS_f eq '') {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
    exit(0);
}
if (! -f $QS_f) {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
    exit(0);
}

sub print_http_headers_multipart_begin {
    print "HTTP/1.0 200 OK\n";
    $bound = "ThisRandomString12345";
    print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
    &print_http_headers_multipart_next;
}

sub print_http_headers_multipart_next {
    print "\n--$bound\n";
}

sub print_http_headers_multipart_end {
    print "\n--$bound--\n";
}

sub displayhtml {
    local($buffer) = @_;
    $len = length($buffer);
    print "Content-type: text/html\n";
    print "Content-length: $len\n\n";
    print $buffer;
}

sub readfile {
    local($file) = @_;
    local(*FP, $size, $buffer, $bytes);
    ($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
    $size = sprintf("%d", $size);
    open(FP, "&lt;$file");
    $bytes = sysread(FP, $buffer, $size);
    close(FP);
    return $buffer;
}

$buffer = &readfile($QS_f);
&print_http_headers_multipart_begin;
&displayhtml($buffer);

sub mystat {
    local($file) = $_[0];
    local($time);

    ($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
    return $mtime;
}

$mtimeL = &mystat($QS_f);
$mtime = $mtime;
for ($n = 0; $n &lt; $QS_n; $n++) {
    while (1) {
        $mtime = &mystat($QS_f);
        if ($mtime ne $mtimeL) {
            $mtimeL = $mtime;
            sleep(2);
            $buffer = &readfile($QS_f);
            &print_http_headers_multipart_next;
            &displayhtml($buffer);
            sleep(5);
            $mtimeL = &mystat($QS_f);
            last;
        }
        sleep($QS_s);
    }
}

&print_http_headers_multipart_end;

exit(0);

##EOF##

大规模虚拟主机

描述

这个<VirtualHost>特征的Apache是好的,当你有几十家虚拟主机的伟大作品。但当你是一个ISP和虚拟主机提供此功能上是不是最好的选择。

解决方案:

提供这个功能我们地图远程网页甚至完整的远程webarea我们命名空间的使用代理吞吐特征(旗[P]):

##
##  vhost.map
##
www.vhost1.dom:80  /path/to/docroot/vhost1
www.vhost2.dom:80  /path/to/docroot/vhost2
     :
www.vhostN.dom:80  /path/to/docroot/vhostN
##
##  httpd.conf
##
    :
#   use the canonical hostname on redirects, etc.
UseCanonicalName on

    :
#   add the virtual host in front of the CLF-format
CustomLog  /path/to/access_log  "%{VHOST}e %h %l %u %t \"%r\" %>s %b"
    :

#   enable the rewriting engine in the main server
RewriteEngine on

#   define two maps: one for fixing the URL and one which defines
#   the available virtual hosts with their corresponding
#   DocumentRoot.
RewriteMap    lowercase    int:tolower
RewriteMap    vhost        txt:/path/to/vhost.map

#   Now do the actual virtual host mapping
#   via a huge and complicated single rule:
#
#   1. make sure we don't map for common locations
RewriteCond   %{REQUEST_URI}  !^/commonurl1/.*
RewriteCond   %{REQUEST_URI}  !^/commonurl2/.*
    :
RewriteCond   %{REQUEST_URI}  !^/commonurlN/.*
#
#   2. make sure we have a Host header, because
#      currently our approach only supports
#      virtual hosting through this header
RewriteCond   %{HTTP_HOST}  !^$
#
#   3. lowercase the hostname
RewriteCond   ${lowercase:%{HTTP_HOST}|NONE}  ^(.+)$
#
#   4. lookup this hostname in vhost.map and
#      remember it only when it is a path
#      (and not "NONE" from above)
RewriteCond   ${vhost:%1}  ^(/.*)$
#
#   5. finally we can map the URL to its docroot location
#      and remember the virtual host for logging puposes
RewriteRule   ^/(.*)$   %1/$1  [E=VHOST:${lowercase:%{HTTP_HOST}}]
    :
top

访问限制

阻断机器人

描述

我们怎样才能阻止讨厌的机器人从检索特定的webarea页?一/robots.txt含有“机器人排除协议”项通常不足以摆脱这种机器人文件。

解决方案:

我们使用一个规则禁止的webarea URL/~quux/foo/arc/(也许是一个很深的目录索引区,机器人遍历会创造大的服务器负载)。我们必须确保我们禁止访问仅限于特定的机器人,即禁止在机器人运行的主机是不够的。这将阻止用户从该主机,太。我们通过同时匹配用户代理的HTTP头信息。

RewriteCond %{HTTP_USER_AGENT}   ^NameOfBadRobot.*
RewriteCond %{REMOTE_ADDR}       ^123\.45\.67\.[8-9]$
RewriteRule ^/~quux/foo/arc/.+   -   [F]

封锁内联图像

描述

假设我们有下http://www.quux-corp.de/~quux/与内联GIF图形的一些网页。这些图形很好,所以其他人直接将其通过超链接到自己的网页。我们不喜欢这种做法,因为这会增加服务器的无用流量。

解决方案:

虽然我们不能100%的保护内部图片,我们至少可以限制在浏览器发送的HTTP Referer报头例。

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
RewriteRule .*\.gif$        -                                    [F]
RewriteCond %{HTTP_REFERER}         !^$
RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$
RewriteRule ^inlined-in-foo\.gif$   -                        [F]

主持人否认

描述

我们怎么能禁止列表中的外部配置的主机使用我们的服务器?

解决方案:

For Apache >= 1.3b6:

RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteCond   ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
RewriteCond   ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
RewriteRule   ^/.*  -  [F]

For Apache <= 1.3b6:

RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteRule   ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ /$1
##
##  hosts.deny
##
##  ATTENTION! This is a map, not a list, even when we treat it as such.
##             mod_rewrite parses it for key/value pairs, so at least a
##             dummy value "-" must be present for each entry.
##

193.102.180.41 -
bsdti1.sdm.de  -
192.76.162.40  -

代理否认

描述

我们怎么能禁止某个主机或者用户的一个特殊的主机使用Apache的代理?

解决方案:

我们首先要确定mod_rewrite低于(!)_代理模型在配置文件中编译Apache WebServer时。这种方式被称为之前mod_proxy。那么我们配置以下一系列相关的否认…

RewriteCond %{REMOTE_HOST} ^badhost\.mydomain\.com$
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]

…这一个用户名@主机相关的否认:

RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST}  ^badguy@badhost\.mydomain\.com$
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]

特殊认证的变体

描述

有时一个非常特殊的认证是必要的,例如一个认证检查一组显式配置的用户。只有这些应该接受访问,没有明确的提示(会使用基本身份验证时,通过mod_auth

解决方案:

我们用一个列表重写条件排除所有的除了我们的朋友:

RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend1@client1.quux-corp\.com$
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend2@client2.quux-corp\.com$
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend3@client3.quux-corp\.com$
RewriteRule ^/~quux/only-for-friends/      -                                 [F]

参考基础板

描述

我们如何计划灵活的URL导流作用于“引荐”HTTP标头,可以配置不同的页面,我们喜欢吗?

解决方案:

使用下面的真正复杂的规则集…

RewriteMap  deflector txt:/path/to/deflector.map

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
RewriteRule ^.* %{HTTP_REFERER} [R,L]

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]

…在相应改写地图连接:

##
##  deflector.map
##

http://www.badguys.com/bad/index.html    -
http://www.badguys.com/bad/index2.html   -
http://www.badguys.com/bad/index3.html   http://somewhere.com/

这种自动重定向请求到相关页面(当”-“作为地图的价值)或一个特定的URL(当一个URL映射中指定的作为第二个参数)。

top

其他

外部重写引擎

描述

一个问题:我们如何解决FOO /酒吧/ quux等问题?似乎没有利用的解决方案mod_rewrite

解决方案:

使用一个外部RewriteMap,即它的行为像一个程序rewritemap。它是在启动Apache运行一次接收请求的URLSTDIN并把所得(通常重写URL上)标准输出(一阶)。

RewriteEngine on
RewriteMap    quux-map       prg:/path/to/map.quux.pl
RewriteRule   ^/~quux/(.*)$  /~quux/${quux-map:$1}
#!/path/to/perl

#   disable buffered I/O which would lead
#   to deadloops for the Apache server
$| = 1;

#   read URLs one per line from stdin and
#   generate substitution URL on stdout
while (<>) {
    s|^foo/|bar/|;
    print $_;
}

这是一个演示例子只是重写所有URL只/~quux/foo/.../ / / quux吧~…。其实你可以任何你喜欢的。但是请注意,虽然这样的地图可以用过的通过一个普通用户,只有系统管理员可以定义IT

来自 http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
普通分类: