首页 > 解决方案 > 将子域重写到现有文件夹

问题描述

我有一个这样的文件夹结构:

public_html
...images
...v2020
...v2021

使用 mod_rewrite,我重定向到文件夹 v2021 并强制到https://www.example.com。现在我很难添加子域。当我转到 images.example.com 时,我希望重定向到文件夹 images,而 images.example.com 在地址字段中保持不变。我分别对代码进行了两部分测试,首先是对 https://www 的转发,包括子域。它可以在没有子域的情况下工作,但如果我添加任何子域,它就会无处可去。

RewriteEngine on
# "example.com" to "www.example.com" (and HTTPS)
RewriteCond %{HTTP_HOST} ^(example\.com) [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,R=301,L]

# HTTP to HTTPS (same host) - preserve subdomain
RewriteCond %{HTTPS} off 
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [NE,R=301,L]

作为最小工作示例的第二部分是标准域(无子域)的前言和子域转发到调试脚本。

RewriteCond %{HTTP_HOST} ^www\.example\.com
RewriteRule ^((?!v2021/).*)$ v2021/$1 [L]

RewriteCond %{HTTP_HOST} ^(.+?)\.example\.com
RewriteRule (.*) echo.php\?a=%1\&b=$1 [L]

该脚本工作正常,并在与上限条件一起使用时输出 a="www",但不与下限一起执行。我被转发到无处。谢谢你的帮助!

标签: .htaccessmod-rewrite

解决方案


这里似乎有几个问题......

RewriteCond %{HTTP_HOST} !^www\. [OR,NC]
RewriteCond %{HTTPS} off 
RewriteRule ^ https://www.example.com%{REQUEST_URI} [NE,R=301,L]

您的第一条规则将您的所有子域(每个未启动的主机名www.)重定向到www.example.com,因此子域丢失。您可能需要更改第一个条件,以便它仅将example.com(域顶点)的请求重定向到www.example.com. 但是您还需要将 HTTP 拆分为 HTTPS 重定向以保留子域(images 等)

例如:

# "example.com" to "www.example.com" (and HTTPS)
RewriteCond %{HTTP_HOST} ^(example\.com) [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,R=301,L]

# HTTP to HTTPS (same host) - preserve subdomain
RewriteCond %{HTTPS} off 
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [NE,R=301,L]
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com
RewriteRule ^(.*)$ %1/$1 [L,NC,QSA]

这将导致内部重写循环(500 错误),因为它反复重写subdomain/url-path导致subdomain/subdomain/subdomain/url-path等等。

您需要一个条件来仅重写直接/初始请求(而不是重写请求),或者检查子域是否尚未被重写到同名的子目录。

但是,这也会重写www子域,我认为这不是意图,因此需要另一个条件来排除它。

例如,仅重写初始请求并排除 www 子域:

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com
RewriteRule (.*) %1/$1 [L]

通过始终重写初始请求并且不明确检查子目录是否与子域不匹配,这意味着您可以拥有与子域同名的子子目录(如果需要)。例如。/images/images/foo.jpg不是问题。

NC和上的QSA标志RewriteRule不是必需的。(因为它已经不区分大小写,并且您没有要附加的查询字符串。)

REDIRECT_STATUS环境变量在初始请求时为空,并在第一次成功重写后设置为(200如 200 OK 状态),因此通过检查它是否为空,可以避免重写循环。

如果您配置了通配符子域,那么您可能需要在重写之前检查该子目录是否存在。(虽然文件系统检查相对昂贵,所以如果可能的话最好避免这样做。特别是在服务资产时。)

RewriteRule ^((?!v2021/).*)$ /v2021/$1 [L]

这似乎与上述规则相冲突。这不应该只适用于www子域(与上述重写相反)吗?例如:

RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^((?!v2021/).*)$ v2021/$1 [L]

推荐阅读