【问题标题】:mod_rewrite aliasing a subdirectorymod_rewrite 给子目录起别名
【发布时间】:2011-10-10 07:18:01
【问题描述】:

我一直在为 mod_rewrite 苦苦挣扎。我们有许多通过 WordPress 多站点运行的客户端门户,所有这些门户都通过一个子目录访问:portal

例如:http://www.mydomain.com/portal/clientA/

我希望只需输入 http://www.mydomain.com/clientA/ 即可到达那里,它会将我重定向到 http://www.mydomain.com/portal/clientA/

这是我目前所拥有的,我可以说它并没有产生任何重写:

RewriteCond %{REQUEST_URI} /portal/
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule . - [S=1]

RewriteRule /clientA(/?) /portal/clientA/

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

第二部分我无法触及,因为 WordPress 需要它。我的模式还试图预测有人不输入斜杠,因此(/?)

编辑:我还应该注意,我不想创建更通用的规则 - 我很乐意为每个新客户添加重写规则并增加 S=x 数字每次。

编辑(8 月 11 日),所以经过一番推敲之后,这就是我的 .htaccess 所在的位置:

RewriteEngine On
RewriteRule ^clientA(/?) /portal/clientA/ [R]

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

不用说它不起作用。但是,如果我删除整个 WordPress 部分,则第一部分有效。我需要它们同时工作。导致第一部分失败的 WordPress 作品是什么?我想这是 RewriteBase 和最后一条规则的组合,它将其他任何东西都别名为 /index.php,坦率地说,这有点令人失望。事实上,我并不真正了解该规则如何在多站点环境中发挥作用,但似乎可以。

最终解决方案 感谢 LazyOne 的正确答案!供其他人参考,我使用的最终解决方案是:

RewriteEngine On
RewriteRule ^clientA(/.+)? /portal/clientA$1 [R,L]
RewriteRule ^clientB(/.+)? /portal/clientB$1 [R,L]


# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

【问题讨论】:

    标签: mod-rewrite


    【解决方案1】:

    就这么简单:

    RewriteCond %{REQUEST_URI} !^/portal/
    RewriteRule (.*) /portal/$1 [L]
    

    它将所有请求重写(内部重定向)到/portal/ 文件夹(例如/clientA/something => /portal/clientA/something)。

    如果您只需要为某些客户端执行此操作(或者,更好的说法是,仅作为客户端的特定文件夹,同时仍保留一些常规/通用文件夹),您可以对每个客户端使用此规则:

    RewriteRule ^clientA(.*) /portal/clientA$1 [L]
    

    这样 .htaccess 将如下所示:

    RewriteRule ^clientA(.*) /portal/clientA$1 [L]
    RewriteRule ^clientB(.*) /portal/clientB$1 [L]
    
    # BEGIN WordPress
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    # END WordPress
    

    【讨论】:

    • 感谢您的建议。唯一的问题是,使用 [L]ast 指令,WordPress 重写不会发生,它们需要发生(即使对于客户端文件夹)才能在 WP 中启用漂亮的永久链接
    • @Tom 为什么“不会发生”?在看到[L] 标志重写后进入下一次迭代(这就是它的工作方式——L 并不意味着“停止重写并立即离开”)......并且仍然会达到 WordPress 重写规则。但是是的——你可以通过删除L 标志来加快它的速度。如果它可以处理/portal/clientA/something 链接,其余的取决于WordPress。 关于[L]标志stackoverflow.com/questions/6797998/…。如果您在服务器配置中有重写规则,那么最好确实跳过 [L] 标志。
    • 啊!感谢您澄清 [L]。我确实认为它在那之后立即停止处理 .htaccess 。现在,如果您查看我更新的帖子,您会发现它仍然无法正常工作。是因为 RewriteBase 吗?
    • @Tom 什么不起作用,哪个 URL?它应该如何工作(根据您创建的规则)?
    • @fishman 你有名为def 的实际文件夹(或任何真实名称)吗?也许你有一些其他的重写规则(在那个文件夹中的 .htaccess 文件中)阻止你进一步重写。目前的规则对我来说似乎很好。
    【解决方案2】:

    我将其中的一部分作为评论发布,但认为对于来到这里的人来说,这样做可能更清楚作为答案。就 OP 而言,他找到了一种使用 [R](重定向)行来执行此操作的方法,但这消除了您创建的子目录 URL 结构,这在大多数 URL 重写中会更可取。因此,之前发布的答案是正确的,我不对此提出异议,但根据您的实施,您可能仍然会收到 WordPress 404 错误。这是我的情况的解决方案,我认为这可能更常见。

    就我而言,我需要这样的 URL 结构:

    http://mysite.com/p/profile_name/
    

    每个注册的用户都可以即时创建自己的个人资料,除了对内容进行一些修改外,大部分情况下,根目录下的所有 WordPress 内容都是将显示的内容。本质上,我需要这个:

    http://mysite.com/p/profile_name/(.*)
    

    改写成这样:

    http://mysite.com/$1
    

    这是另一个答案中发布的 .htaccess 代码,它将正确处理该规则:

    RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [L]
    

    问题在于 WordPress 并不关心你的重写,因为 WordPress 使用 $_SERVER['REQUEST_URI'],无论你重写什么,它始终是用户浏览器窗口中的内容. OP 通过使用 [R] 选项找到了解决此问题的方法,但这会导致您丢失 URL:

    RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [R,L]
    

    重定向

    http://mysite.com/p/profile/(.*)
    

    收件人:

    http://mysite.com/$1
    

    但是,用户以这种方式丢失了他的唯一 URL。充其量您可以添加一个查询字符串以至少保留数据,但这样您就失去了开头漂亮 URL 的意义。

    我确实想出了一个解决方案;但是,它涉及黑客 WordPress 包含文件 :( 如果有人有更好的方法,请更新。我们开始吧:

    解决方案

    我将我的 .htaccess 文件设置为:

    # BEGIN WordPress
    <IfModule mod_rewrite.c>
    RewriteEngine On
    #My addition:
    RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [L]
    
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    # END WordPress
    

    然后,我知道 WordPress 使用了 REQUEST_URI 变量,所以我进行了递归搜索,并在 /wp-includes/class-wp.php(第 147 行 v3.4.2)中找到了这行代码:

    $req_uri = $_SERVER['REQUEST_URI'];
    

    我改成这样了:

    $req_uri = preg_replace(@'/^\/?p\/([-a-zA-Z0-9_]+)\//', '', $_SERVER['REQUEST_URI']);
    

    这基本上只是通过过滤掉 URI 开头的配置文件来欺骗 WordPress。

    最后,我还需要网站内链接的解决方案。为此,我添加了这个过滤器:

    注意:其中一些正则表达式可能有点疯狂;我正在过滤掉特定于网站的内容,因此请将此用作概念,而不是复制/粘贴。

    function mysite_wp_make_link_relative( $link ) {
        $sBaseUrl = (preg_match('/^\/(p\/[-a-zA-Z0-9_]+\/)(.*)/', $_SERVER['REQUEST_URI'], $matches)) ? $matches[1] : '';
        return preg_replace( '|https?://[^/]+/(.*)|i', '/' . $sBaseUrl . '$1', $link );
    }
    function rw_relative_urls() {
        $filters = array(
            'page_link', // Page link
            'home_url',
            'site_url',
            'get_site_url',
            'home_link',
        );
        foreach ( $filters as $filter ) {
            add_filter( $filter, 'mysite_wp_make_link_relative' );
        }
    }
    

    其中一些过滤器可能不相关;我很确定 page_link 和 home_url 是唯一重要的。无论如何,您需要该代码才能使您的内部链接正常工作。

    希望对您有所帮助,如果有人有任何改进的 cmets 建议,我将不胜感激。

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 2015-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      相关资源
      最近更新 更多