htaccess规则配置问题:无硬编码转发及地址栏URL保留实现
先来说你遇到的第一个问题:为什么跳转后的URL会莫名带上api前缀?
出现这个情况,十有八九是因为你的api子域名和主域名共用了同一个文档根目录(DocumentRoot),而且api子域名的请求被映射到了主域名下的api子目录里。举个实际例子:假设主域名example.com的根目录是/var/www/html,你把api.example.com的根目录也设成了/var/www/html,那当你访问api.example.com/index.html时,Apache其实会去找/var/www/html/api/index.html,这时候你的.htaccess里的RewriteRule ^(.*)$就会捕获到api/index.html,最终拼接出来的URL自然就变成了example.com/dashboard/api/index.html。
解决跳转URL带api的问题
你可以通过两种方式修正这个问题:
方式1:调整虚拟主机配置(推荐)
给api子域名单独设置一个独立的文档根目录,比如/var/www/api。这样当你访问api.example.com/index.html时,请求的URI就是纯index.html,你原来的规则就能正常工作了:
RewriteCond %{HTTP_HOST} ^api\.(.+)$ [NC] RewriteRule ^(.*)$ https://%1/dashboard/$1 [R=302,L]
方式2:在.htaccess里精准捕获路径
如果没法修改虚拟主机配置,那就用REQUEST_URI来抓取真正的请求路径:
RewriteCond %{HTTP_HOST} ^api\.(.+)$ [NC] # 捕获去掉开头斜杠的请求路径 RewriteCond %{REQUEST_URI} ^/(.*)$ # 用%2引用上一条规则捕获到的路径 RewriteRule ^ https://%1/dashboard/%2 [R=302,L]
第二个问题:让地址栏保持原URL,内部转发内容
如果你想让用户看到的地址始终是api.example.com/index.html,但实际返回的是example.com/dashboard/index.html的内容,这需要用到内部重写或者反向代理,分两种场景处理:
场景1:主域名和子域名在同一服务器
如果两个域名指向同一台服务器,且共用文档根目录,直接用内部重写就可以,完全不会改变地址栏:
RewriteCond %{HTTP_HOST} ^api\.(.+)$ [NC] RewriteRule ^(.*)$ /dashboard/$1 [L]
这个规则会把api.example.com下的所有请求,偷偷重写到主域名的dashboard目录下,用户完全感知不到。
场景2:跨服务器或需要代理请求
如果两个域名不在同一台服务器,那得先开启Apache的mod_proxy和mod_proxy_http模块,然后用P标志实现反向代理:
RewriteCond %{HTTP_HOST} ^api\.(.+)$ [NC] RewriteRule ^(.*)$ https://%1/dashboard/$1 [P,L]
P标志会让Apache把请求代理到目标URL,同时保持地址栏显示原来的请求地址。注意:使用前要确保你的服务器允许代理请求,而且目标服务器能正常响应。
内容的提问来源于stack exchange,提问作者drmrbrewer

