【问题标题】:Dynamically pointing multiple domains to a single domain's subfolder with .htaccess使用 .htaccess 将多个域动态指向单个域的子文件夹
【发布时间】:2021-10-29 23:13:08
【问题描述】:

在本例中,我管理 domain.com。在其中,我在 php 中有一个商店模板,可以动态加载所选商店:

  • domain.com/store1
  • domain.com/store2
  • domain.com/store3

下面的.htaccess 正在生成漂亮的网址。后面真正加载的是这样的:

  • domain.com/store/index.php?store=store1
  • domain.com/store/index.php?store=store2
  • domain.com/store/index.php?store=store3

每个商店都有内部链接,例如:

  • domain.com/store1/catalogue
  • domain.com/store1/catalogue/instruments
  • domain.com/store1/catalogue/instruments/guitars
  • domain.com/store1/electric-guitar/1337

它完全按预期工作。这些是在 domain.com 中使用的 .htaccess 规则。每个RewriteRule 中的store 查询字符串(store1store2store3)确定正在加载哪个商店:

# permalinks
RewriteEngine on

# errors
ErrorDocument 404 /error.php?error=404

# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]

#################################################

# store
RewriteRule ^([0-9a-zA-Z-]{2,50})/?$ store/index.php?store=$1 [QSA,L]

# store: catalogue
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/?$ store/catalogue.php?store=$1 [QSA,L]
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/([0-9a-zA-Z-]{1,75})/?$ store/catalogue.php?store=$1&cat=$2 [QSA,L]
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/([0-9a-zA-Z-]{1,75})/([0-9a-zA-Z-]{1,75})/?$ store/catalogue.php?store=$1&cat=$2&subcat=$3 [QSA,L]

# store: products
RewriteRule ^([0-9a-zA-Z-]{2,50})/([0-9a-zA-Z-]{1,150})/([0-9]+)$ store/product.php?store=$1&slug=$2&id_product=$3 [QSA,L]

现在,棘手的部分来了。一些客户想要使用自己的域,以便store1.com/* 加载与domain.com/store1/* 相同的内容(不使用重定向)。

例子:

  • store1.com => domain.com/store1/
  • store1.com/catalogue => domain.com/store1/catalogue
  • store1.com/catalogue/instruments => domain.com/store1/catalogue/instruments
  • store1.com/catalogue/instruments/guitars => domain.com/store1/catalogue/instruments/guitars
  • store1.com/electric-guitar/1337 => domain.com/store1/electric-guitar/1337

你明白了。

所有域(domain.comstore1.comstore2.comstore3.com)都配置在同一个 Apache Web Server 环境中(使用虚拟主机)。

问题是:这可以在每个商店的域根路径中的.htaccess 文件中动态实现还是在虚拟主机.conf 文件中实现?如果有,怎么做?

【问题讨论】:

  • 这很可能是可行的,但具体的实现细节可能会有所不同。域名和商店名称之间的关系是什么(总是只是附加.com,如果是.co.uk,如果在store1.com之前有www.,如果有未知域的请求到达怎么办.. .)。此外,如果您有权访问 apache 配置 (.conf) 文件,则根本不应该使用 .htaccess。最后,您最好只在 Web 应用代码中处理所有这些逻辑。
  • @DusanBajic 感谢您的反馈。他们永远不会使用 www.。域类型可以是任何类型:.com.co.uk.ec 等。可能无法从 domain.com 根目录切换 .htaccess 逻辑,因为一切都在那里,解决方案应该-也许-在其他域的.conf文件中(?)关于从哪里开始寻找的任何想法?
  • 我假设域名,即。 store1 in store1.com 将是 store URL 参数的必需值,就像现在的“虚拟目录”/store1/ 一样?
  • @MrWhite 没错。如果没有 store=store1 值,domain.com 中的模板将不知道要加载哪个存储。

标签: apache .htaccess mod-rewrite


【解决方案1】:

确保在domain.com vHost 中将所有自定义“存储”域(例如store1.comstore2.com 等)定义为ServerAlias,因此解析到与domain.com 相同的位置。

然后,您可以重写自定义商店域的请求,以 store-id(域名)作为 URL 路径的前缀,然后使用现有规则不变。

例如,store1.com/catalogue/instruments 的请求被内部重写/store1/catalogue/instruments,然后像往常一样由现有规则处理。

以下指令应该在现有的# store 规则之前

# Internally rewrite the request when a custom domain is used
#  - the URL-path is prefixed with the domain name
RewriteCond %{HTTP_HOST} !^(www\.)?domain\. [NC]
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}@%1 !^/([^/]+)/.*@\1
RewriteRule (.*) %1/$1

基本上就是这样,尽管您也可能决定实施规范重定向 - 见下文。

上述指令的解释:

  • 第一个 条件 只是排除对主要domain.com 的请求(应该已经将相关的 store-id 作为 URL 路径的前缀)。

  • %{REQUEST_URI} !\.\w{2,4}$ - 第二个条件 避免重写对静态资源(图像、JS、CSS 等)的请求。具体来说,它不包括任何以文件扩展名结尾的请求。

  • %{HTTP_HOST} ^([^.]+) - 第三个条件 在 TLD 之前捕获请求的域名,然后可以使用 %1 反向引用访问该域名,并用于作为 URL 路径的前缀。这假设没有 www 子域(如 cmets 中所述)。例如。给定对store1.comstore2.co.uk 的请求,分别捕获store1store2

  • %{REQUEST_URI}@%1 !^/([^/]+)/.*@\1 - 第四个条件 检查 URL 路径是否尚未以域名为前缀(如上所示)。这主要是为了确保重写的请求不会再次被重写,从而导致重写循环。这是使用内部反向引用 (\1) 实现的,该反向引用将 URL 路径中的第一个路径段与之前捕获的域名 (%1) 进行比较。

  • (.*) %1/$1 - 最后,请求在内部被重写,将域名作为请求的 URL 路径的前缀。


忽略现有文件(可能不是必需的)

# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]

您尚未说明如何引用静态资源(图像、JS、CSS 等),但您可能需要修改此规则以匹配对现有文件的请求。 (虽然我在上面的规则中添加的条件可能已经足以排除这些请求。)例如:

# ignore existing directories or files
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

规范重定向(可选)

您还应该考虑将store1.com/store1/catalogue/instruments 形式的任何直接请求重定向回规范 URL store1.com/catalogue/instruments - 如果这些 URL 曾经暴露/被发现。 store1.com/store2/catalogue/instruments 形式的请求自然会导致 404,因此不是问题。

例如,以下内容将紧跟在现有规则中的 ErrorDocument 指令之后:

# Redirect to remove the "/store1" URL-prefix when the "store1.com" domain is requested.
# - Only applies to direct requests.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} !^domain\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}@%1 ^/([^/]+)/.*@\1
RewriteRule ^(?:[^/]+)(/.*) $1 [R=301,L]

首先使用 302(临时)重定向进行测试以避免潜在的缓存问题。

这基本上与上述重写相反,但仅适用于直接请求。对REDIRECT_STATUS env var 的检查确保只处理来自客户端的直接请求,而不是稍后重写的重写请求。


总结

两个规则块就位...

# permalinks
RewriteEngine on

# errors
ErrorDocument 404 /error.php?error=404

# Redirect to remove the "/store1" URL-prefix when the "store1.com" domain is requested.
# - Only applies to direct requests.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} !^domain\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}@%1 ^/([^/]+)/.*@\1
RewriteRule ^(?:[^/]+)(/.*) $1 [R=301,L]

# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Internally rewrite the request when a custom domain is used
#  - the URL-path is prefixed with the domain name
RewriteCond %{HTTP_HOST} !^(www\.)?domain\. [NC]
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}@%1 !^/([^/]+)/.*@\1
RewriteRule (.*) %1/$1

#################################################

# store

:
: existing directives follow
:

【讨论】:

  • 这是最全面的答案。谢谢!
猜你喜欢
  • 2013-11-22
  • 2010-12-07
  • 2014-03-17
  • 1970-01-01
  • 2023-03-16
  • 2018-01-22
  • 1970-01-01
  • 1970-01-01
  • 2014-06-19
相关资源
最近更新 更多