【问题标题】:Grouping RewriteRule by RewriteCond with .htaccess通过 RewriteCond 和 .htaccess 对 RewriteRule 进行分组
【发布时间】:2020-07-29 12:57:03
【问题描述】:

我有一个网页模板,用于运行多个登录页面,并且 htaccess 用于将友好 URL 指向 PHP 代码中的 pageid。这一切都有效,但目前我必须在每条规则或重定向冲突之前添加重写条件行。您可以在下面的伪代码中看到这一点:

RewriteEngine On

RewriteCond for domain1
RewriteRule for page 1 on domain 1
RewriteCond for domain1
RewriteRule for page 2 on domain 1

RewriteCond for domain2
RewriteRule for page 1 on domain 2
RewriteCond for domain2
RewriteRule for page 2 on domain 2

这不能很好地扩展,如果我在其他任何语言中这样做,我会像这样对规则进行分组:

RewriteCond for domain1
{
    RewriteRule for page 1 on domain 1  
    RewriteRule for page 2 on domain 1
}

RewriteCond for domain2
{
    RewriteRule for page 1 on domain 2  
    RewriteRule for page 2 on domain 2
}

如果我可以分组,它会使 htaccess 文件更易于管理。有没有办法对规则进行分组?我曾尝试寻找解决方案,但我遇到的每个示例都讨论了 1 个域的 1 个重定向。我的另一个想法是在 PHP / MySQL 中创建一个 htaccess 脚本,我输入我的数据,按下一个按钮并写入 htaccess 文件,这将是复杂的读取但会好的。我确信有一个简单的解决方案。有人可以帮忙吗?

【问题讨论】:

标签: .htaccess mod-rewrite


【解决方案1】:

这是我在生产中工作的最终解决方案:

RewriteEngine On

<If "%{HTTP_HOST} == 'domain1.com'">        

        #main pages
        RewriteRule /members/$    /index.php?pageid=2 [NC,L]
        RewriteRule /contact/$    /index.php?pageid=3 [NC,L]
        RewriteRule /affiliates/$ /index.php?pageid=4 [NC,L]

        #blog articles
        RewriteRule /welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]
</If>


<If "%{HTTP_HOST} == 'domain2.com'">        

        #main pages
        RewriteRule /about/$        /index.php?pageid=2 [NC,L]
        RewriteRule /press-kit/$    /index.php?pageid=3 [NC,L]
        RewriteRule /contact/$   /index.php?pageid=4 [NC,L]
        RewriteRule /affiliates/$   /index.php?pageid=5 [NC,L]

        #blog articles
        RewriteRule /welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]
</If>

【讨论】:

  • 只是好奇这实际上是如何工作的......因为你似乎有冲突,例如。 /index.php?pageid=2domain1 返回/members/ 页面,但domain2/about/ 页面?您是否也在检查index.php 脚本中的HTTP_HOST?或者这些实际上是不同的index.php 文件(因为每个域的文档根可能指向不同的子目录,而这个.htaccess 文件是从一个公共父目录继承的?)
  • @MrWhite 是的,在索引脚本中检测到主机并为每个域调用包含。它目前运行 16 个站点,因此更易于将其拆分并允许每个站点拥有自己的结构。
【解决方案2】:

使用&lt;If&gt; 部分的一些替代方法,因为&lt;If&gt; is not without its caveats

  1. 当条件匹配(或不匹配)时跳过指令
  2. 在 URL 前加上主机名(以匹配)
  3. 为每个主机单独的 .htaccess 配置文件

旁白:你真的想要一个不区分大小写的 - NC - 匹配吗?)

1。当条件匹配(或不匹配)时跳过指令

当规则(或条件)不匹配时,您可以跳过(S 标志)任意数量的指令。 IE。如果您跳过HTTP_HOST 不是domain1.com 时遵循的规则,则仅当HTTP_HOSTdomain1.com 时才会处理以下规则。

例如:

# Skip the following 4 rules when the host is not "domain1.com"
RewriteCond %{HTTP_HOST} !=domain1.com
RewriteRule ^ - [S=4]

# Only processed when the HTTP_HOST is equal to "domain1.com"

#main pages
RewriteRule ^members/$     /index.php?pageid=2 [NC,L]
RewriteRule ^contact/$     /index.php?pageid=3 [NC,L]
RewriteRule ^affiliates/$  /index.php?pageid=4 [NC,L]

#blog articles
RewriteRule ^welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

# --------------------------------------------------------------------

# Skip the following 5 rules when the host is not "domain2.com"
RewriteCond %{HTTP_HOST} !=domain2.com
RewriteRule ^ - [S=5]

# Only processed when the HTTP_HOST is equal to "domain2.com"

#main pages
RewriteRule ^about/$       /index.php?pageid=2 [NC,L]
RewriteRule ^press-kit/$   /index.php?pageid=3 [NC,L]
RewriteRule ^contact/$     /index.php?pageid=4 [NC,L]
RewriteRule ^affiliates/$  /index.php?pageid=5 [NC,L]

#blog articles
RewriteRule ^welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

虽然这种方法的一个明显警告是,在添加或删除任何规则时,您需要小心更新 S=&lt;number&gt; 标志。

您显然可以颠倒逻辑,在顶部放置一个看起来像目录的东西。例如:

RewriteCond %{HTTP_HOST} =domain1.com
RewriteRule ^ - [S=2]
RewriteCond %{HTTP_HOST} =domain2.com
RewriteRule ^ - [S=5]
RewriteCond %{HTTP_HOST} =domain3.com
RewriteRule ^ - [S=9]

# --------------------------------------------------------------------
# domain1.com

#main pages
RewriteRule ^members/$     /index.php?pageid=2 [NC,L]
RewriteRule ^contact/$     /index.php?pageid=3 [NC,L]
RewriteRule ^affiliates/$  /index.php?pageid=4 [NC,L]

#blog articles
RewriteRule ^welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

# --------------------------------------------------------------------
# domain2.com

#main pages
RewriteRule ^about/$       /index.php?pageid=2 [NC,L]
RewriteRule ^press-kit/$   /index.php?pageid=3 [NC,L]
RewriteRule ^contact/$     /index.php?pageid=4 [NC,L]
RewriteRule ^affiliates/$  /index.php?pageid=5 [NC,L]

#blog articles
RewriteRule ^welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

虽然“跳过”规则可能更容易出错,因为您可能需要在添加或删除规则时更新多个规则,具体取决于这些规则所在的位置。

2。用主机名前缀 URL(以匹配)

或者,您可以(临时)在 URL 路径前加上主机名,并在随后的规则中与此匹配。这避免了所有后续规则中的附加 RewriteCond 指令。

例如:

# Prefix URL-path with HTTP_HOST if not already prefixed / No "L" flag
RewriteCond %{HTTP_HOST}@$1 !^([a-z.-]+)@\1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) %{HTTP_HOST}/$1

# --------------------------------------------------------------------
# domain1.com

#main pages
RewriteRule ^domain1\.com/members/$     /index.php?pageid=2 [NC,L]
RewriteRule ^domain1\.com/contact/$     /index.php?pageid=3 [NC,L]
RewriteRule ^domain1\.com/affiliates/$  /index.php?pageid=4 [NC,L]

#blog articles
RewriteRule ^domain1\.com/welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

# --------------------------------------------------------------------
# domain2.com

#main pages
RewriteRule ^domain2\.com/about/$       /index.php?pageid=2 [NC,L]
RewriteRule ^domain2\.com/press-kit/$   /index.php?pageid=3 [NC,L]
RewriteRule ^domain2\.com/contact/$     /index.php?pageid=4 [NC,L]
RewriteRule ^domain2\.com/affiliates/$  /index.php?pageid=5 [NC,L]

#blog articles
RewriteRule ^domain2\.com/welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

这避免了额外的RewriteCond 指令,但是,它要求您在每种情况下都为匹配的 URL 路径加上域的前缀。与上面第一个示例中使用 S 标志相比,出错的可能性更小。

在上面的示例中,对于任何不直接映射到文件或未重写为/index.php?pageid=&lt;number&gt; 的 URL,主机名在请求末尾仍保留在 URL 路径的前缀。这将导致 404。

如果您特别想删除 hostname 前缀(也许您在错误文档中使用 $_SERVER['REDIRECT_URL'] 变量,而不是 $_SERVER['REQUEST_URI']),那么您可以通过引入额外的环境变量(我们称之为FINISHED)并在末尾去掉这个前缀。

例如,修改第一条规则以检查FINISHED env var(最初不存在)并在末尾引入一条新规则,删除前缀并设置 env var。如果没有FINISHED env var,我们将陷入“未知 URL”的重写循环,因为它会重复添加前缀并删除 URL 路径上的主机名。

# Prefix URL-path with HTTP_HOST if not already prefixed and not FINISHED / No "L" flag
RewriteCond %{ENV:FINISHED} ^$
RewriteCond %{HTTP_HOST}@$1 !^([a-z.-]+)@\1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) %{HTTP_HOST}/$1

# :
# : Directives for each domain go here (as above)
# :

# Tidy up - remove the HTTP_HOST prefix and set FINISHED env var
RewriteCond %{HTTP_HOST}@$1 ^([a-z.-]+)@\1/(.*)
RewriteRule (.*) %2 [E=FINISHED:1,L]

3。为每个主机单独的 .htaccess 配置文件

另一种可能更适合单独域和本质上单独的网站(尽管可能是“通用”引擎)的这种特殊情况的替代方法是为每个单独的(单独的).htaccess 文件网站。

具体配置方式可能取决于您配置文件结构的方式,但是,这可以增加站点之间的分离度,甚至可以在两个或多个站点之间共享配置(如果您愿意)。您可能拥有仅与正在访问的网站相关的资源 - 但您可能已经拥有类似的东西。

例如...

  • 您仍将在文档根目录中拥有“master”.htaccess 文件(假设您为所有域共享一个公共根目录)。
  • 为每个主机创建一个子目录。例如。 /domain1.com,在每个子目录中,您只有一个用于该域的 .htaccess 文件。

文件结构:

/
    domain1.com/
        .htaccess
    domain2.com/
        .htaccess
    .htaccess
    index.php

/.htaccess

.htaccess 文件随后会将请求路由到所请求主机的相应子目录。

RewriteEngine On

# If the request is already for index.php in the document root then DONE
RewriteRule ^index\.php$ - [L]

# Rewrite all requests that don't map to files to the appropriate domain subdirectory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) %{HTTP_HOST}/$1 [L]

/domain1.com/.htaccess

然后每个域的 .htaccess 文件只包含该域的指令,并将请求重写回文档根目录中的“通用”/index.php 文件以呈现请求。

重写指令采用与上述相同的“正常”格式。

# domain1.com

RewriteEngine On

# Optional - If this subdirectory is accessed directly then redirect back to the root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) /$1 [R=301,L]

#main pages
RewriteRule ^members/$     /index.php?pageid=2 [NC,L]
RewriteRule ^contact/$     /index.php?pageid=3 [NC,L]
RewriteRule ^affiliates/$  /index.php?pageid=4 [NC,L]

#blog articles
RewriteRule ^welcome-to-our-blog/$ /index.php?pageid=b0001 [NC,L]

无论如何,值得深思。其中一些归结为您如何构建应用程序,而不是严格地“通过 RewriteCond 对 RewriteRule 进行分组”。如果您想进一步解释任何“位”,请直接说。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多