gpt4 book ai didi

mod-rewrite - 如何在使用通配符的 Directory 指令中使用 apache2 mod_rewrite?

转载 作者:行者123 更新时间:2023-12-04 02:16:00 24 4
gpt4 key购买 nike

我编写了一个 Web 应用程序,我在专用服务器下运行该应用程序以托管 Web 应用程序。此 Web 应用程序的实例可在不同的域中使用,每个域都有自己的 Web 应用程序文件副本,允许根据需要进行自定义。

我在 Debian Squeeze 下运行 Apache/2.2.16。

我在 VirtualHost 指令下进行所有配置,不使用 .htaccess 文件。

为了简化 apache 配置,我想维护一个像这样的目录指令:

<Directory "/srv/www/*/public/">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>

但是,RewriteRule 会产生错误的结果,因为在使用通配符 Directory 值时,它无法剥离每个目录的前缀。这是重写日志的输出:
[rid#b9832078/initial] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/login'
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9832078/initial] (4) [perdir /srv/www/*/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9832078/initial] (2) [perdir /srv/www/*/public/] rewrite '/srv/www/domain1/public/login' -> '/index.php?q=/srv/www/domain1/public/login'
[rid#b9832078/initial] (3) split uri=/index.php?q=/srv/www/domain1/public/login -> uri=/index.php, args=q=/srv/www/domain1/public/login
[rid#b9832078/initial] (1) [perdir /srv/www/*/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b9847440/initial/redir#1] (3) [perdir /srv/www/*/public/] applying pattern '^(.+)$' to uri '/srv/www/domain1/public/index.php'
[rid#b9847440/initial/redir#1] (4) [perdir /srv/www/*/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b9847440/initial/redir#1] (1) [perdir /srv/www/*/public/] pass through /srv/www/domain1/public/index.php

问题是RewriteRule 'uri'是文件系统路径而不是url路径,导致查询字符串不正确:q=/srv/www/domain1/public/login

显式指定目录路径,如下所示:
<Directory "/srv/www/domain1/public/">
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]
</Directory>

工作得很好,这里是重写日志的输出,显示了正确的行为(不同之处在于新的第一行为重写的其余部分提供了正确的输入,从而产生了正确的查询字符串:q=login):
[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/login -> login
[rid#b9868048/initial] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'login'
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-f' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/login' pattern='!-d' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b9868048/initial] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b9868048/initial] (2) [perdir /srv/www/domain1/public/] rewrite 'login' -> '/index.php?q=login'
[rid#b9868048/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b9868048/initial] (1) [perdir /srv/www/domain1/public/] internal redirect with /index.php [INTERNAL REDIRECT]
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] strip per-dir prefix: /srv/www/domain1/public/index.php -> index.php
[rid#b987d5f8/initial/redir#1] (3) [perdir /srv/www/domain1/public/] applying pattern '^(.+)$' to uri 'index.php'
[rid#b987d5f8/initial/redir#1] (4) [perdir /srv/www/domain1/public/] RewriteCond: input='/srv/www/domain1/public/index.php' pattern='!-f' => not-matched
[rid#b987d5f8/initial/redir#1] (1) [perdir /srv/www/domain1/public/] pass through /srv/www/domain1/public/index.php

我希望我遇到了 Apache 的错误,但如果不是这样,我做错了什么?

虽然我很欣赏将方法更改为另一种可行解决方案的意见,但我会接受以我采用的方法(例如不使用 .htaccess)解决它的答案,除非可以证明这种方法无法解决。

那么在通配符目录中使用时,是否必须更改 RewriteCond/Rules ?

好奇的旁注:为了进一步简化,我使用 VirtualDocumentRoot 使用单个 VirtualHost - 但是这无关紧要,因为使用“DocumentRoot”并在单个域下测试可以复制此问题。

编辑

好的,我已经根据 regilero 的回答重新审视了这个,这就是发生的事情 - 将重写原样移出目录会导致查询字符串从“登录”更改为“/登录”的轻微初始问题,这通过修改 RewriteRule 来修复: RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]这修复了我之前的“莫名其妙地失败”的评论。

之后,所有静态文件都无法加载,这是显示此问题的重写日志:
[rid#b7bc7fa0/initial] (2) init rewrite engine with requested uri /login
[rid#b7bc7fa0/initial] (3) applying pattern '^/(.+)$' to uri '/login'
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-f' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!-d' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/favicon.ico' => matched
[rid#b7bc7fa0/initial] (4) RewriteCond: input='/login' pattern='!=/robots.txt' => matched
[rid#b7bc7fa0/initial] (2) rewrite '/login' -> '/index.php?q=login'
[rid#b7bc7fa0/initial] (3) split uri=/index.php?q=login -> uri=/index.php, args=q=login
[rid#b7bc7fa0/initial] (2) local path result: /index.php
[rid#b7bc7fa0/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7bc7fa0/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]
[rid#b7be6b80/initial] (2) init rewrite engine with requested uri /static/css/common.css
[rid#b7be6b80/initial] (3) applying pattern '^/(.+)$' to uri '/static/css/common.css'
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-f' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!-d' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/favicon.ico' => matched
[rid#b7be6b80/initial] (4) RewriteCond: input='/static/css/common.css' pattern='!=/robots.txt' => matched
[rid#b7be6b80/initial] (2) rewrite '/static/css/common.css' -> '/index.php?q=static/css/common.css'
[rid#b7be6b80/initial] (3) split uri=/index.php?q=static/css/common.css -> uri=/index.php, args=q=static/css/common.css
[rid#b7be6b80/initial] (2) local path result: /index.php
[rid#b7be6b80/initial] (2) prefixed with document_root to /srv/www/domain1/public/index.php
[rid#b7be6b80/initial] (1) go-ahead with /srv/www/domain1/public/index.php [OK]

但是就像我在对 regilero 的回答的评论中所说的那样,这是通过在 RewriteCond 指令 TestString 前面加上 %{DOCUMENT_ROOT} 来解决的。但是,在使用 VirtualDocumentRoot 时,使用 %{DOCUMENT_ROOT} 不起作用。

%{DOCUMENT_ROOT} 前缀对我来说似乎是必要的。

编辑

REQUEST_FILENAME

The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI.



这解释了需要 DOCUMENT_ROOT 前缀。

我已将重写规则更新为:
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{REQUEST_URI} !^/static/
RewriteRule ^/(.+)$ /index.php?q=$1 [PT,L,QSA]

哪个工作正常(注意:PT 标志是必要的,以避免在使用 VirutalDocumentRoot 时过早地将 url 路径转换为文件系统路径)。此处行为的主要变化是,应用程序的所有入口点都需要 RewriteCond - 类似于/static 行。

编辑

这是我在任何目录指令之外的 VirtualHost 中重写指令的最终化身:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/static/
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteRule ^/(.+)$ /index.php?q=$1 [NS,PT,L,QSA]
RewriteRule ^/$ /index.php [NS,PT,L,QSA]

我添加了 NS标志以避免额外的内部评估并添加了第二个 RewriteRule支持使用 mod_dir 和 DirectoryIndex 的指令.我的应用程序不希望根 url 有 q= 参数,否则只有一个 RewriteRuleRewriteRule ^/(.*)$ /index.php?q=$1 [NS,PT,L,QSA]如果应用程序更新为接受空 q= 就足够了根 url 的参数。我将来可能会这样做。

最佳答案

非常好的和详细的问题。

您肯定遇到了错误,或者至少遇到了未记录的 rewriteRule 域。文档指出:

  • The rewrite engine may be used in .htaccess files and in sections, with some additional complexity.
  • To enable the rewrite engine in this context, you need to set "RewriteEngine On" and "Options FollowSymLinks" must be enabled. If your administrator has disabled override of FollowSymLinks for a user's directory, then you cannot use the rewrite engine. This restriction is required for security reasons.
  • When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substutions.


所以没有提到这个事实 <Directory>带有通配符的指令将无法去除每个目录的前缀。使用 RewriteBase 对您没有帮助,它已完成重建最终 Url 而不改变 perdir 工作。

但是正如您在开头看到的那样,有“具有一些额外的复杂性”的句子。 由 mod-rewrite 完成的目录操作比一般的目录外重写规则更慢、更复杂 .这在 documentation 中也有说明,主要是因为 perdir 条操作。这意味着你也可以从 <Directory> 中写出你的 rewriteRule部分,在您的 VirtualHost 中。
  • 会更快
  • 不会被这个bug击中
  • 如果某些不存在的文件不应该映射到您的 index.php?q=$1,它可能会产生一些副作用。规则在其他一些目录中。但我很确定这在你的情况下不是问题。

  • 所以简单地写(没有通配符目录):
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !=/favicon.ico
    RewriteCond %{REQUEST_URI} !=/robots.txt
    RewriteRule ^(.+)$ /index.php?q=$1 [L,QSA]

    它应该可以工作,如果这会导致新问题,请告诉我。

    编辑:

    好吧,忘记了 REQUEST_FILENAME 尚未在 VirtualHost 上下文中完全定义的事实,它已记录在案,这是“正常的”,当应用条件时,实际路径上的文件搜索尚未完成,这就是您必须添加文档根目录的原因。所以实际上你的最终解决方案应该是:
    RewriteEngine on
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !=/favicon.ico
    RewriteCond %{REQUEST_URI} !=/robots.txt
    RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

    我尝试了第二个,避免使用 DOCUMENT_ROOT,使用 REQUEST_FILENAME 的延迟评估 ( %{LA-U:REQUEST_FILENAME} 包含最终路径,如果文件不存在,它实际上是 index.php 的完整路径),但我让它工作的唯一方法是添加第二个规则和一个或条件在第二个,不太简单,所以第一个解决方案肯定更好(KISS)。
      RewriteCond %{LA-U:REQUEST_FILENAME} !-f [OR]
    RewriteCond %{LA-U:REQUEST_FILENAME} !/index.php
    RewriteCond %{LA-U:REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !=/favicon.ico
    RewriteCond %{REQUEST_URI} !=/robots.txt
    RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

    RewriteCond %{LA-U:REQUEST_FILENAME} /index.php
    RewriteRule ^/(.+)$ /index.php?q=$1 [L,QSA]

    关于mod-rewrite - 如何在使用通配符的 Directory 指令中使用 apache2 mod_rewrite?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6358913/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com