<-
Apache HTTP 服务器 2.4 > 使用mod_rewrite进行URL重定向和重新映射

使用mod_rewrite重定向和重新映射

本文档是mod_rewrite 参考文档的补充。它描述了如何使用mod_rewrite重定向和重新映射请求。这包括mod_rewrite常用用法的许多示例,包括每种用法的详细说明。

请注意,这些示例中的许多示例在您的特定服务器配置中都不会起作用,因此,理解它们,而不只是将示例剪切并粘贴到您的配置中,这一点很重要。
支持Apache!

也可以看看

最佳

从旧到新(内部)

描述:

假设我们最近将页面重命名 foo.htmlbar.html,现在想提供旧的URL以实现向后兼容。但是,我们希望旧URL的用户甚至无法识别页面已被重命名-也就是说,我们不希望在其浏览器中更改地址。

解:

我们通过以下规则在内部将旧网址重写为新网址:

RewriteEngine  on
RewriteRule    "^/foo\.html$"  "/bar.html" [PT]
最佳

从旧到新的重写(外部)

描述:

再次假设我们最近将页面重命名 foo.htmlbar.html,现在想提供旧的URL以实现向后兼容。但是这一次,我们希望旧URL的用户得到新的提示,即他们的浏览器的“位置”字段也应更改。

解:

我们强制HTTP重定向到新URL,从而导致浏览器发生更改,因此用户可以查看:

RewriteEngine  on
RewriteRule    "^/foo\.html$"  "bar.html"  [R]
讨论区

与上面的内部示例相比,在此示例中,我们可以简单地使用Redirect指令。在较早的示例中使用了mod_rewrite,以便从客户端隐藏重定向:

Redirect "/foo.html" "/bar.html"
最佳

资源已移至另一台服务器

描述:

如果资源已移至另一台服务器,则您可能希望在人们更新其书签的同时,URL在旧服务器上继续工作一段时间。

解:

您可以mod_rewrite用来将这些URL重定向到新服务器,但也可以考虑使用Redirect或RedirectMatch指令。

#With mod_rewrite
RewriteEngine on
RewriteRule   "^/docs/(.+)"  "http://new.example.com/docs/$1"  [R,L]
#With RedirectMatch
RedirectMatch "^/docs/(.*)" "http://new.example.com/docs/$1"
#With Redirect
Redirect "/docs/" "http://new.example.com/docs/"
最佳

从静态到动态

描述:

我们如何无缝地将静态页面 foo.html转换为动态变体 foo.cgi,即浏览器/用户无需通知。

解:

我们只是将URL重写为CGI脚本,然后将处理程序强制为cgi-script,以便将其作为CGI程序执行。这样,对/~quux/foo.html 内部的请求会导致的调用 /~quux/foo.cgi

RewriteEngine  on
RewriteBase    "/~quux/"
RewriteRule    "^foo\.html$"  "foo.cgi"  [H=cgi-script]
最佳

向后兼容文件扩展名更改

描述:

在迁移document.YYYYdocument.XXXX(例如将一堆.html文件转换为)后,如何使URL向后兼容(实际上仍然存在).php

解:

我们将该名称重写为其基名称,并测试是否存在新扩展名。如果存在,则使用该名称,否则将URL重写为其原始状态。

#   backward compatibility ruleset for
#   rewriting document.html to document.php
#   when and only when document.php exists
<Directory "/var/www/htdocs">
    RewriteEngine on
    RewriteBase "/var/www/htdocs"

    RewriteCond "$1.php" -f
    RewriteCond "$1.html" !-f
    RewriteRule "^(.*).html$" "$1.php"
</Directory>
讨论区

本示例通过利用规则集的执行顺序,使用了mod_rewrite经常被忽略的功能。特别是,mod_rewrite在评估RewriteCond指令之前先评估RewriteRule的左侧。因此,在评估RewriteCond指令时已经定义了$ 1。这使我们能够使用相同的基本文件名测试原始文件(document.html)和目标document.php文件()的存在。

此规则集旨在用于每个目录的上下文(在<Directory>块中或.htaccess文件中),以便 -f检查使用正确的目录路径。您可能需要设置一个RewriteBase指令来指定您正在使用的目录库。

最佳

规范主机名

描述:
该规则的目标是强制使用特定主机名,而不是可能用于访问同一站点的其他主机名。例如,如果您希望强制使用www.example.com而不是 example.com,则可以使用以下配方的变体。
解:

解决此问题的最佳方法完全不涉及mod_rewrite,而是Redirect 将虚拟主机中的指令用于非规范主机名。

<VirtualHost *:80>
  ServerName undesired.example.com
  ServerAlias example.com notthis.example.com

  Redirect "/" "http://www.example.com/"
</VirtualHost>

<VirtualHost *:80>
  ServerName www.example.com
</VirtualHost>

您也可以使用<If> 指令完成此操作 :

<If "%{HTTP_HOST} != 'www.example.com'">
    Redirect "/" "http://www.example.com/"
</If>

或者,例如,要将您的网站的一部分重定向到HTTPS,您可以执行以下操作:

<If "%{SERVER_PROTOCOL} != 'HTTPS'">
    Redirect "/admin/" "https://www.example.com/admin/"
</If>

如果出于某种原因仍要使用mod_rewrite -例如,如果需要此功能以使用更大的RewriteRules集,则可以使用以下配方之一。

对于运行在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,NE]

对于在端口80上运行的站点

RewriteCond "%{HTTP_HOST}"   "!^www\.example\.com" [NC]
RewriteCond "%{HTTP_HOST}"   "!^$"
RewriteRule "^/?(.*)"        "http://www.example.com/$1" [L,R,NE]

如果您想为所有域名一般做到这一点-那就是,如果你想重定向example.comwww.example.com的所有可能的值 example.com,你可以使用下面的方法:

RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule "^/?(.*)"      "http://www.%{HTTP_HOST}/$1" [L,R,NE]

这些规则集将在您的主服务器配置文件中或在服务器的.htaccess放置文件中工作DocumentRoot

最佳

在多个目录中搜索页面

描述:

特定资源可能存在于多个位置之一,我们希望在请求资源时在这些位置中查找该资源。也许我们最近已经重新排列了目录结构,将内容分为几个位置。

解:

以下规则集在两个目录中搜索以找到资源,并且,如果在两个位置均未找到资源,则将尝试仅在请求的位置之外提供资源。

RewriteEngine on

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

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

#   else go on for other Alias or ScriptAlias directives,
#   etc.
RewriteRule   "^"  "-"  [PT]
最佳

重定向到地理位置分布式服务器

描述:

我们的网站有很多镜像,并希望将人们重定向到他们所所在的国家/地区。

解:

查看发出请求的客户的主机名,我们确定他们来自哪个国家。如果我们无法在其IP地址上进行查找,我们将退回到默认服务器。

我们将使用一条RewriteMap 指令来构建我们希望使用的服务器列表。

HostnameLookups on
RewriteEngine on
RewriteMap    multiplex         "txt:/path/to/map.mirrors"
RewriteCond   "%{REMOTE_HOST}"  "([a-z]+)$" [NC]
RewriteRule   "^/(.*)$"  "${multiplex:%1|http://www.example.com/}$1"  [R,L]

## map.mirrors -- Multiplexing Map

de http://www.example.de/
uk http://www.example.uk/
com http://www.example.com/
##EOF##

讨论区
此规则集依赖于 HostNameLookups set on,这可能会严重影响性能。

RewriteCond 指令捕获请求客户端的主机名的最后一部分-国家/地区代码-并且以下RewriteRule使用该值在映射文件中查找适当的镜像主机。

最佳

浏览器相关内容

描述:

我们希望基于请求内容的浏览器或用户代理提供不同的内容。

解:

我们必须根据HTTP标头“ User-Agent”确定要提供的内容。以下配置执行以下操作:如果HTTP标头“ User-Agent”包含“ Mozilla / 3”,则页面将foo.html 被重写到foo.NS.html该位置,并且重写将停止。如果浏览器是版本1或2的“ Lynx”或“ Mozilla”,则URL变为foo.20.html。所有其他浏览器都会收到page 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]
最佳

规范网址

描述:

在某些Web服务器上,一个资源有多个URL。通常,存在规范的URL(实际使用和分发的URL)以及只是快捷方式,内部的URL等。无论用户随请求提供了哪个URL,最终他们应该在浏览器地址栏中看到规范的URL。

解:

我们对所有非规范URL进行外部HTTP重定向,以在浏览器的位置视图以及所有后续请求中修复它们。在这个例子中的规则集下面我们替换/puppies,并/canines 通过规范/dogs

RewriteRule   "^/(puppies|canines)/(.*)"    "/dogs/$2"  [R]
讨论:
这实际上应该使用Redirect或RedirectMatch指令完成:
RedirectMatch "^/(puppies|canines)/(.*)" "/dogs/$2"
最佳

感动 DocumentRoot

描述:

通常DocumentRoot ,网络服务器的都直接与URL“ /”相关。但是通常这些数据并不是真正的最高优先级。例如,您可能希望访问者在首次进入站点时进入特定的子目录/about/。这可以使用以下规则集来完成:

解:

我们将网址重定向//about/

RewriteEngine on
RewriteRule   "^/$"  "/about/"  [R]

请注意,这也可以使用RedirectMatch指令进行处理:

RedirectMatch "^/$" "http://example.com/about/"

另请注意,该示例仅重写根URL。也就是说,它会重写的请求http://example.com/,而不是的请求http://example.com/page.html。如果实际上已经更改了文档根目录-也就是说,如果实际上所有内容都位于该子目录中,则最好只更改DocumentRoot 指令或将所有内容上移到一个目录中,而不是重写URL。

最佳

后备资源

描述:
您希望一个资源(例如,某个文件,例如index.php)来处理到达特定目录的所有请求,但那些应该进入现有资源(例如图像或css文件)的请求除外。
解:

从2.2.16版开始,您应该FallbackResource为此使用指令:

<Directory "/var/www/my_blog">
  FallbackResource "index.php"
</Directory>

但是,在Apache的早期版本中,或者如果您的需求比这更复杂,则可以使用以下重写集的变体来完成同一件事:

<Directory "/var/www/my_blog">
  RewriteBase "/my_blog"

  RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-f
  RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-d
  RewriteRule "^" "index.php" [PT]
</Directory>

另一方面,如果您希望将请求的URI作为查询字符串参数传递给index.php,则可以将该RewriteRule替换为:

RewriteRule "(.*)" "index.php?$1" [PT,QSA]

请注意,这些规则集可以在.htaccess 文件以及<Directory>块中使用。

最佳

重写查询字符串

描述:
您想从查询字符串中捕获特定值,然后替换它或将其合并到URL的另一个组件中。
解决方案:

本节中的许多解决方案都将使用相同的条件,这会将匹配的值保留在%2反向引用中。%1是查询字符串的开头(取决于兴趣关键字),而%3是其余部分。对于灵活性和避免替换中使用双'&&'而言,此条件有点复杂。

  • 此解决方案删除匹配的键和值:
    # Remove mykey=???
    RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
    RewriteRule "(.*)" "$1?%1%3"
  • 此解决方案在URL替换中使用捕获的值,并通过附加“?”来丢弃原始查询的其余部分:
    # Copy from query string to PATH_INFO
    RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
    RewriteRule "(.*)" "$1/products/%2/?" [PT]
  • 此解决方案在随后的条件下检查捕获的值:
    # Capture the value of mykey in the query string
    RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
    RewriteCond "%2" !=not-so-secret-value 
    RewriteRule "(.*)" - [F]
  • 此解决方案与前面的解决方案相反,将路径部分(也许是PATH_INFO)从URL复制到查询字符串中。
    # The desired URL might be /products/kitchen-sink, and the script expects
    # /path?products=kitchen-sink.
    RewriteRule "^/?path/([^/]+)/([^/]+)" "/path?$1=$2" [PT]

可用语言: zh  |  fr 

最佳

注释

注意:
这不是“问答”部分。此处放置的评论应指向有关改进文档或服务器的建议,如果实施或被认为无效/偏离主题,我们的主持人可以将其删除。有关如何管理Apache HTTP Server的问题,应直接指向我们的IRC频道#httpd(位于Freenode上),或发送至我们的邮件列表
目前,此页面已禁用评论。