.htaccess 使用Apache将所有请求发送到子文件夹

deyfvvtc  于 2022-11-16  发布在  Apache
关注(0)|答案(1)|浏览(148)

我正在尝试将对我的网站的所有请求传递到我的webroot中的子文件夹。
以下是我的文件夹结构:

/webroot
    current
    releases
        release1
            index.html
            en
                index.html
        release2
            index.html
            en
                index.html
        ...
    .htaccess

current文件夹是指向releases文件夹中的一个文件夹的符号链接。其思想是当我制作一个新版本时,在releases文件夹中创建一个新文件夹,然后current符号链接指向这个新文件夹。
在我的.htaccess中,我尝试将所有请求传递给current符号链接。
现在,只要请求以尾随斜杠结束,例如https://example.com/en/,这种方法就能很好地工作,但如果我删除尾随斜杠,路由就能工作,但浏览器中的URL将是https://example.com/current/en
下面是我在我的.htaccess中所做的重写:

Options +FollowSymlinks -MultiViews -Indexes

DirectorySlash On

RewriteEngine on
RewriteBase /

RewriteCond %{REQUEST_URI} !^/current/
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ current/$1 [L]

这是日志文件

[perdir /path/to/webroot/] applying pattern '^(.*)$' to uri 'en'
[perdir /path/to/webroot/] RewriteCond: input='/en' pattern='!^/current/' => matched
[perdir /path/to/webroot/] RewriteCond: input='' pattern='^$' => matched
[perdir /path/to/webroot/] rewrite 'en' -> 'current/en'
[perdir /path/to/webroot/] add per-dir prefix: current/en -> /path/to/webroot/current/en
[perdir /path/to/webroot/] trying to replace prefix /path/to/webroot/ with /
strip matching prefix: /path/to/webroot/current/en -> current/en
add subst prefix: current/en -> /current/en
[perdir /path/to/webroot/] internal redirect with /current/en [INTERNAL REDIRECT]
[perdir /path/to/webroot/] strip per-dir prefix: /path/to/webroot/current/en -> current/en
[perdir /path/to/webroot/] applying pattern '^(.*)$' to uri 'current/en'
[perdir /path/to/webroot/] RewriteCond: input='/current/en' pattern='!^/current/' => not-matched
[perdir /path/to/webroot/] pass through /path/to/webroot/current/en
[perdir /path/to/webroot/] strip per-dir prefix: /path/to/webroot/current/en/ -> current/en/
[perdir /path/to/webroot/] applying pattern '^(.*)$' to uri 'current/en/'
[perdir /path/to/webroot/] RewriteCond: input='/current/en/' pattern='!^/current/' => not-matched
[perdir /path/to/webroot/] pass through /path/to/webroot/current/en/
[perdir /path/to/webroot/] strip per-dir prefix: /path/to/webroot/current/en/index.php -> current/en/index.php
[perdir /path/to/webroot/] applying pattern '^(.*)$' to uri 'current/en/index.php'
[perdir /path/to/webroot/] RewriteCond: input='/current/en/index.php' pattern='!^/current/' => not-matched
[perdir /path/to/webroot/] pass through /path/to/webroot/current/en/index.php
[perdir /path/to/webroot/] strip per-dir prefix: /path/to/webroot/current/en/index.html -> current/en/index.html
[perdir /path/to/webroot/] applying pattern '^(.*)$' to uri 'current/en/index.html'
[perdir /path/to/webroot/] RewriteCond: input='/current/en/index.html' pattern='!^/current/' => not-matched
[perdir /path/to/webroot/] pass through /path/to/webroot/current/en/index.html
oyxsuwqo

oyxsuwqo1#

但如果我删除尾部斜杠,路由工作,但在浏览器中的URL将是https://example.com/current/en
我假设您指的是https://example.com/current/en/(后面有一个斜杠)。
这是因为mod_dir试图通过在物理目录中添加一个斜杠来“修复”(使用301重定向)URL(这是目录索引正常工作所必需的)。此“修复”发生在URL被重写到子目录之后(因为URL路径/en最初没有Map到子目录)。
您可以禁用mod_dir的这一行为,以便不附加尾随斜杠;但是这样做会很麻烦(然后需要根据需要手动添加尾部斜杠),并且可能会引发安全问题。
相反,您需要确保链接到的URL * 始终带有 * 尾随斜杠,并在 * mod_dir执行此操作之前手动更正任何在.htaccess * 中省略尾随斜杠的URL。
重写到/current子目录的现有重写看起来没问题,尽管您不需要检查请求是否已经开始/current/(第一个 * 条件 )。(通过检查请求是否已经开始/current/,您就允许直接请求实际的符号链接的文件系统位置-尽管这可能是一个要求?)
因此,
在 * 现有重写之前,添加以下重定向:

# Fix any requests for directories that omit the trailing slash
RewriteCond %{DOCUMENT_ROOT}/current/$1 -d
RewriteRule ^(.+[^/])$ /$1/ [R=301,L]

给定一个/example的请求,上面的代码首先检查/current/example是否作为一个目录存在(尽管是一个符号链接的目录)。如果存在,那么它发出一个301重定向,将尾部斜杠附加到原始URL,而不是重写的URL。例如,/example被重定向到/example/,然后被重写为/current/example/
首先测试302(临时)重定向,以避免潜在的缓存问题。
您需要清除浏览器缓存,因为错误的301(永久)mod_dir重定向将被浏览器缓存。

更新日期:

它应该不可能直接访问“当前”文件夹中的任何文件或文件夹。目前,这是可能的...
正如上面所暗示的,您可以简单地删除第一个 condition,它检查REQUEST_URI是否已经以/current/开始。因此,所有直接请求都将无条件地重写为/current/。因此,对/current/en/的请求将被重写为/current/current/en,从而导致404。
然而,用户仍然可能直接请求文件系统位置,完全绕过符号链接。例如/releases/release1/en/
要阻止直接访问这两个位置,您可以添加以下规则作为第一条规则:

# Block direct access to "/current/" and "/releases/"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(current|releases)($|/) - [F]

直接请求/current/.../releases/...将导致“403禁止”。或者将F更改为R=404以提供“404未找到”服务(尽管使用了R标志,但不会发生 redirect)。
REDIRECT_STATUS环境变量的检查(如原始规则中所述)确保请求仍然可以在内部重写到这些位置。(REDIRECT_STATUS env var在来自客户端的初始请求中为空,但在第一次重写后设置为HTTP响应状态(例如“200”)。

相关问题