http > https 错误的最终 url(子域重定向)

http > https wrong final url (subdomain redirect)

我有:

目录树:

└───domains
    ├───bar.com
    │   ├───sub (sub.bar.com / www.sub.bar.com)
    │   ├───sub2 (sub2.bar.com / www.sub2.bar.com)
    │   └───www (bar.com / www.bar.com)
    └───foo.com
        ├───sub (sub.foo.com / www.sub.foo.com)
        ├───sub2 (sub2.foo.com / www.sub2.foo.com)
        └───www (foo.com / www.foo.com)
/.htaccess


RewriteEngine On

# remove www from URL
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/ [R=301,DPI,L,NC]

# subdomains (sub.foo.com, sub.bar.com, sub2.foo.com, sub2.bar.com)
RewriteCond %{REQUEST_URI} !^domains/
RewriteCond %{REQUEST_URI} !^/domains/
RewriteCond %{HTTP_HOST} ^([^\.]*)\.([^\.]*\.[^\.]*)$
RewriteCond %{DOCUMENT_ROOT}/domains/%2 -d
RewriteCond %{DOCUMENT_ROOT}/domains/%2/%1 -d
RewriteRule (.*) /domains/%2/%1/ [DPI]

# main domains (foo.com, bar.com)
RewriteCond %{REQUEST_URI} !^domains/
RewriteCond %{REQUEST_URI} !^/domains/
RewriteCond %{HTTP_HOST} ^([^\.]*\.[^\.]*)$
RewriteCond %{DOCUMENT_ROOT}/domains/%1 -d
RewriteRule (.*) /domains/%1/www/ [DPI]

这看起来工作得很好,但是当我需要在 foo.com 上启用 https 时,它并没有按预期工作。

/domains/foo.com/.htaccess

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [DPI,R=301]

因为不是重定向:http://www.sub.foo.com/?query > https://sub.foo.com/?query it redirect to: https://sub.foo.com/domains/foo.com/sub/?query 但它确实不是我所期望的。

/domains/foo.com/.htaccess

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [DPI,R=301]

这在 /domains/foo.com/.htaccess 文件中使用时无法按预期工作,因为它正在处理 URL 已被 /.htaccess 文件在根目录中,到这个阶段 REQUEST_URI 服务器变量已经更新为请求已重写到的完整 URL 路径(不是 URL用户请求),即。 /domains/foo.com/sub/.

(旁白: 你没有说明你是否在使用 PHP, 但为了以防万一... REQUEST_URI PHP 超全局变量,即 $_SERVER['REQUEST_URI']),与 REQUEST_URI Apache 服务器变量不同。 REQUEST_URI PHP 变量包含用户请求的 URL (这似乎是您对 Apache 服务器变量的期望),在这种情况下与 Apache 不同同名的服务器变量。)

简单的解决方案是从匹配 RewriteRule 模式 的 URL 路径中捕获 URL 路径,而不是使用 REQUEST_URI Apache 服务器变量。

例如:

# /domains/foo.com/.htaccess
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{HTTP_HOST}/ [R=301,L]

.htaccess 中,RewriteRule 模式 匹配 URL-path 减去目录前缀 - 所以它总是相对的到包含 .htaccess 文件的目录。

这里似乎不需要 DPI 标志。

替代解决方案是将您的 HTTP 到 HTTPS 重定向移动到根 /.htaccess 文件( 内部重写之前)并且可能检查请求的 hostname 如果需要有选择性的话。例如:

# /.htaccess
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^(www\.)?sub\.foo\.com [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

在根 /.htaccess 文件中,我们可以使用 Apache 变量 REQUEST_URI,前提是将重定向放在 之前 内部重写。

您需要在测试前清除浏览器缓存。最好使用 302(临时)重定向进行测试,以避免潜在的缓存问题。


# remove www from URL
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/ [R=301,DPI,L,NC]

另一个 "problem" 是您的 www 到非 www 重定向总是重定向到 HTTP。因此,对 https://www.sub.foo.com/ 的请求将在(希望)被重定向回 HTTPS 之前被重定向回 HTTP——这是一个不必要的额外重定向。根据您的要求,您可以通过多种方式解决此问题。