如何更改我的 mod_rewrite 规则以在父目录中工作?
How can I change my mod_rewrite rules to work in the parent directory?
我有一个 MVC 应用程序 index.php 位于 /public 子文件夹中。目前,我将 Apache 指向 /public 文件夹并在其中使用 .htaccess 将 MVC 请求重写为 index.php.
当前的 Apache 配置:
<VirtualHost>
DocumentRoot /var/www/html/public
</VirtualHost>
/public中的当前 .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php? [L,QSA]
目标 Apache 配置:
<VirtualHost>
DocumentRoot /var/www/html
</VirtualHost>
目标 .htaccess,但我无法正确重写 MVC 和资产 URL:
DirectoryIndex index.php
RewriteEngine On
RewriteBase /public
# If it's a file/directory/symlink, serve it.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]
# Otherwise let's go MVC
RewriteRule ^.*$ index.php [NC,L]
示例网址:
domain.com/login (MVC URL, rewritten to public/index.php)
domain.com/assets/styles.css (non-MVC URL, rewritten to public/assets folder)
除非您正在设置本地开发环境来模拟限制性更强的实时服务器环境,否则...
Not sure why you want to do this, as your current config (setting the DocumentRoot
to /public
) would seem to be the most desirable (and simple) setup.
Setting the DocumentRoot
to the parent directory and rewriting to the /public
subdirectory instead is often a workaround when you are unable to change the DocumentRoot
. This is ultimately more work and exposes the /public
subdirectory, which now has to be blocked/redirected to prevent direct access.
无论如何,移动到 public HTML space...
中的 /public
子目录
将 DocumentRoot
设置为 /var/www/html
后,有两种方法可以完成此操作,使用 1 个或 2 个 .htaccess
文件。 (虽然,这也引发了另一个问题......当您有权访问服务器配置时,为什么要使用 .htaccess
?尽管这可能有完全正当的理由。)
方法#1 - 两个 .htaccess
文件
使用两个 .htaccess
文件可以说更容易做到这一点。一个在文档根目录中,将所有请求重写到 /public
子目录中,另一个在 /public
子目录中,将请求重写到您的 MVC 应用程序中,其方式与您已经在做的大致相同。 /public/.htaccess
文件的存在也用于防止重写循环。
例如:
# (1) /.htaccess
RewriteEngine On
# (OPTIONAL) If you need to allow access to files/directories/symlinks
# outside of the "public" directory
#RewriteCond %{REQUEST_FILENAME} -f [OR]
#RewriteCond %{REQUEST_FILENAME} -d [OR]
#RewriteCond %{REQUEST_FILENAME} -l
#RewriteRule ^ - [L]
# Rewrite all requests to the "/public" subdirectory
RewriteRule (.*) public/ [L]
# (2) /public/.htaccess
RewriteEngine On
# If "public" directory is requested directly then redirect to remove it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) / [R=301,L]
# Stop early if already rewritten to MVC
RewriteRule ^index\.php$ - [L]
# Rewrite to MVC app, otherwise serve assets
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule (.*) index.php? [QSA,L]
方法#2 - 文档根目录中的一个 .htaccess
文件
或者,您在文档根目录中只有一个 .htaccess
文件。
例如:
# /.htaccess (only)
RewriteEngine On
# If "public" directory is requested directly then redirect to remove it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^public(?:/(.*))?$ / [R=301,L]
# Stop early if already rewritten to "public" directory
RewriteRule ^public/ - [L]
# If it's a file/directory/symlink, serve it.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
# Rewrite to assets in "public" directory if they exist
RewriteCond %{REQUEST_URI} \.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f
RewriteRule !^public/ public%{REQUEST_URI} [L]
# Otherwise rewrite request to the MVC app in "public" directory
RewriteRule (.*) public/index.php? [QSA,L]
我假设您所有的“资产”的文件扩展名都在 2 到 4 个字符之间。对上述内容的优化是,如果您的所有“资产”都被 /assets/...
引用,那么您可以简单地将所有这些请求重写为 /public/assets/...
- 无需文件系统检查。例如:
# Rewrite to assets in "public" directory (unconditionally)
RewriteRule ^assets/ public%{REQUEST_URI} [L]
尽管这意味着您不能在 MVC 应用程序中包含以 /assets/
开头的路由。但你可能不应该这样做。
旁白: 如果您不直接提供目录服务(现在这样做很不常见),那么您不需要检查请求是否映射到目录重写规则。只需让它传递到您的 MVC 应用程序并触发 404(而不是 403)- 这可能更可取。
我有一个 MVC 应用程序 index.php 位于 /public 子文件夹中。目前,我将 Apache 指向 /public 文件夹并在其中使用 .htaccess 将 MVC 请求重写为 index.php.
当前的 Apache 配置:
<VirtualHost>
DocumentRoot /var/www/html/public
</VirtualHost>
/public中的当前 .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php? [L,QSA]
目标 Apache 配置:
<VirtualHost>
DocumentRoot /var/www/html
</VirtualHost>
目标 .htaccess,但我无法正确重写 MVC 和资产 URL:
DirectoryIndex index.php
RewriteEngine On
RewriteBase /public
# If it's a file/directory/symlink, serve it.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]
# Otherwise let's go MVC
RewriteRule ^.*$ index.php [NC,L]
示例网址:
domain.com/login (MVC URL, rewritten to public/index.php)
domain.com/assets/styles.css (non-MVC URL, rewritten to public/assets folder)
除非您正在设置本地开发环境来模拟限制性更强的实时服务器环境,否则...
Not sure why you want to do this, as your current config (setting the
DocumentRoot
to/public
) would seem to be the most desirable (and simple) setup.Setting the
DocumentRoot
to the parent directory and rewriting to the/public
subdirectory instead is often a workaround when you are unable to change theDocumentRoot
. This is ultimately more work and exposes the/public
subdirectory, which now has to be blocked/redirected to prevent direct access.
无论如何,移动到 public HTML space...
中的/public
子目录
将 DocumentRoot
设置为 /var/www/html
后,有两种方法可以完成此操作,使用 1 个或 2 个 .htaccess
文件。 (虽然,这也引发了另一个问题......当您有权访问服务器配置时,为什么要使用 .htaccess
?尽管这可能有完全正当的理由。)
方法#1 - 两个 .htaccess
文件
使用两个 .htaccess
文件可以说更容易做到这一点。一个在文档根目录中,将所有请求重写到 /public
子目录中,另一个在 /public
子目录中,将请求重写到您的 MVC 应用程序中,其方式与您已经在做的大致相同。 /public/.htaccess
文件的存在也用于防止重写循环。
例如:
# (1) /.htaccess
RewriteEngine On
# (OPTIONAL) If you need to allow access to files/directories/symlinks
# outside of the "public" directory
#RewriteCond %{REQUEST_FILENAME} -f [OR]
#RewriteCond %{REQUEST_FILENAME} -d [OR]
#RewriteCond %{REQUEST_FILENAME} -l
#RewriteRule ^ - [L]
# Rewrite all requests to the "/public" subdirectory
RewriteRule (.*) public/ [L]
# (2) /public/.htaccess
RewriteEngine On
# If "public" directory is requested directly then redirect to remove it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) / [R=301,L]
# Stop early if already rewritten to MVC
RewriteRule ^index\.php$ - [L]
# Rewrite to MVC app, otherwise serve assets
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule (.*) index.php? [QSA,L]
方法#2 - 文档根目录中的一个 .htaccess
文件
或者,您在文档根目录中只有一个 .htaccess
文件。
例如:
# /.htaccess (only)
RewriteEngine On
# If "public" directory is requested directly then redirect to remove it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^public(?:/(.*))?$ / [R=301,L]
# Stop early if already rewritten to "public" directory
RewriteRule ^public/ - [L]
# If it's a file/directory/symlink, serve it.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^ - [L]
# Rewrite to assets in "public" directory if they exist
RewriteCond %{REQUEST_URI} \.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f
RewriteRule !^public/ public%{REQUEST_URI} [L]
# Otherwise rewrite request to the MVC app in "public" directory
RewriteRule (.*) public/index.php? [QSA,L]
我假设您所有的“资产”的文件扩展名都在 2 到 4 个字符之间。对上述内容的优化是,如果您的所有“资产”都被 /assets/...
引用,那么您可以简单地将所有这些请求重写为 /public/assets/...
- 无需文件系统检查。例如:
# Rewrite to assets in "public" directory (unconditionally)
RewriteRule ^assets/ public%{REQUEST_URI} [L]
尽管这意味着您不能在 MVC 应用程序中包含以 /assets/
开头的路由。但你可能不应该这样做。
旁白: 如果您不直接提供目录服务(现在这样做很不常见),那么您不需要检查请求是否映射到目录重写规则。只需让它传递到您的 MVC 应用程序并触发 404(而不是 403)- 这可能更可取。