• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 使用 mod_rewrite 重定向和重新映射 URL

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

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

    从旧到新(内部)

    描述:

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

    解:

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

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

    从旧到新的重写(外部)

    描述:

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

    解:

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

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

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

    Redirect "/foo" "/bar"
    

    资源已移至另一台服务器

    描述:

    如果资源已移至另一台服务器,您可能希望在人们更新其书签的同时,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" !-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"          [L]
    
    RewriteCond "%{HTTP_USER_AGENT}"  "^Lynx/" [OR]
    RewriteCond "%{HTTP_USER_AGENT}"  "^Mozilla/[12]"
    RewriteRule "^foo\.html$"         "foo.20"          [L]
    
    RewriteRule "^foo\.html$"         "foo.32"          [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]