RewriteRule
我正在尝试通过组合一些我之前成功实现的规则来设置通配符子域.htaccess
,相信我可以对我的 Apache vhosts 文件使用相同的规则。
本质上,example.com
转到www.example.com
根路径并查找index.php
。根级别的所有其他(动态)子域请求(例如abc.example.com
)都会重写(对浏览器不可见)为example.com/process.php?p=abc
。
其次,任何来自基础/根级别之外的子域的文件请求都需要重写,以便从没有子域的标准域的根路径获取。因此abc.example.com/css/style.css
需要来自example.com/css/style.css
这是我尝试这样做的。我收到一个 Apache 错误:
您无权访问此服务器上的 /index.php。
对于除 www 之外的任何子域名尝试,其均按预期工作,并且标准example.com
仍可正常工作。
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName other.example.com
ServerAlias *.example.com
DocumentRoot /var/www/example.com/public_html/
<Directory /var/www/example.com/public_html/>
Options FollowSymLinks
AllowOverride all
Require all granted
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC]
RewriteRule ^$ /process.php?p=%2 [QSA,NC]
RewriteCond %{REQUEST_FILENAME} !^$ [NC]
RewriteRule ^(.*) http://www.example.com/$1 [P]
</Directory>
</VirtualHost>
我已成功将不同域的根目录重定向到example.com
使用此.htaccess
文件,该文件合并process.php
并将所有其他请求发送到的根目录example.com
。
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
# Check the request isn't an existing file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^$ http://www.example.com/process.php [P]
RewriteCond %{REQUEST_FILENAME} !^$ [NC]
RewriteRule ^(.*) http://www.example.com/$1 [P]
并且在这个.htaccess
测试中我还成功将子域作为变量重定向到process.php
,尽管它没有捕获其他文件请求,例如上面的 css 示例:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC]
RewriteRule ^$ /process.php?p=%2 [QSA,NC]
更新 1
我使用下面的代码代替我的第二个虚拟主机条目(似乎)取得了一些成功。process.php
如果我使用子域,则会输出页面。虽然模式匹配在这方面似乎有效,但我的实际process.php
接收是一个空变量,而不是预期的子域作为字符串(for:)process.php?p=%2
:
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName other.example.com
ServerAlias *.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options FollowSymLinks
AllowOverride all
Require all granted
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC]
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^$ /process.php?p=%2 [NC,QSA]
</Directory>
</VirtualHost>
更新 2
我已经以一种迂回的方式解决了这个问题,但我不确定这是否是最优雅的方式。
使用上述更新 1代码中,我发现查询字符串仍在附加,但页面中%2
未收到。我可能错误地认为,尽管按照我的代码说明,url 不会将变量显示在浏览器的 url 中,但内部 url 仍会传递它们。尽管如此,我意识到仍然可以使用in将子域确定为字符串,并将其用作页面上的变量,方式与我最初的想法类似。GET
process.php
p=abc
process.php
$_SERVER['HTTP_X_FORWARDED_HOST']
PHP
答案1
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] RewriteCond %{HTTP_HOST} ^(www\.)?([^\.]+)\.example\.com$ [NC] RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^$ /process.php?p=%2 [NC,QSA]
这%2
引用,因为这是指向最后匹配CondPattern(RewriteCond
模式)。最后匹配的 CondPattern^/$
没有任何捕获组,因此%2
始终为空。
无论如何,第三条指令看起来都是多余的。模式RewriteCond
已经检查了这一点(在每个目录上下文中,目录前缀被删除 - 因此这是正确的)。RewriteRule
^$
第一RewriteCond
条指令看起来也是多余的。任何要求www.example.com
都会被第一个 VirtualHost 捕获,因此主机名无论如何,这个 VirtualHost 里面永远不会有www.example.com
,所以这个指令总是计算为真。
我会将其重写为:
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\.example\.com$ [NC]
RewriteRule ^$ process.php?p=%1 [QSA]
我已经做了第一个团体非捕获即(?:www\.)
-?:
使其非捕获。因此,我们只会获取%1
实际的子域。此外,无需在字符类中转义点(以匹配文字点)。这里NC
的标志RewriteRule
是多余的。
我还删除了RewriteRule
代换因为您已经在指令中指定了 URL 路径RewriteBase
。
这仅重写abc.example.com/
,即对文档根目录的请求。
其次,任何来自基础/根级别之外的子域的文件请求都需要重写为从没有子域的标准域的根路径获取。因此
abc.example.com/css/style.css
需要来自example.com/css/style.css
。
由于abc.example.com/
和example.com/
指向文件系统上的同一位置,我认为您不需要在这里做任何事情?example.com/css/style.css
应该指向与相同的文件abc.example.com/css/style.css
。
那么文档根目录中的其他文件呢?例如。abc.example.com/file
目前,这些文件只是像 CSS 文件一样不加改变地通过。