将子域和 URL 路径重写为 URL 参数,但允许访问文件
我正在努力处理我的 .htaccess 文件并按照我想要的方式设置它。主要功能是一个从子域获取语言和从子文件夹获取当前页面的网站。
要求
我需要 .htaccess
文件来满足三个要求;
- 通配符子域重定向到 lang 变量
- 子文件夹重定向到 page 变量
- 尊重本地文件(这是我陷入困境的地方)
- (奖励) 将页面变量拆分为每个斜杠的段; page、sub1、sub2 等
示例
en.example.com/hello
->/index.php?lang=en&page=hello
es.example.com/hola
->/index.php?lang=es&page=hola
- (奖励)
en.example.com/hello/there/sir
->index.php?lang=en&page=hello&sub1=there&sub2=sir
我当前的 .htaccess
这是我当前的设置,如果我不这样做的话,它实际上可以有点不需要任何本地文件(笑)。这意味着当我的 .htaccess 下面
处于活动状态时,找不到本地图像。我尝试添加 RewriteCond %{REQUEST_FILENAME} !-f
来尊重本地文件,但这似乎破坏了整个文件 - 我不知道为什么。
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^$ /index.php?lang=%1 [L]
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^(.+)$ /index.php?lang=%1&page=$1 [L]
RewriteRule ^index\.php$ - [L]
RewriteRule ^(.*)$ /index.php?page=$1 [L,QSA]
I'm struggling with my .htaccess
file and setting it up the way I want it. The main function is a website that gets the language from the subdomain and the current page from the subfolders.
Requirements
I have three requirements that I need my .htaccess
file to do;
- Wildcard subdomain redirected to lang variable
- Subfolder(s) redirected to page variable
- Local files respected (this is where I'm stuck)
- (Bonus) Split up the page variable into segments for each slash; page, sub1, sub2, etc
Examples
en.example.com/hello
->/index.php?lang=en&page=hello
es.example.com/hola
->/index.php?lang=es&page=hola
- (Bonus)
en.example.com/hello/there/sir
->index.php?lang=en&page=hello&sub1=there&sub2=sir
My current .htaccess
This is my current setup which actually kinda works, if I don't need any local files (lol). This means local images aren't found when my .htaccess below
is active. I tried adding RewriteCond %{REQUEST_FILENAME} !-f
to respect local files but that breaks the whole file it seems - and I don't know why.
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^$ /index.php?lang=%1 [L]
RewriteCond %{HTTP_HOST} ((?!www).+)\.example\.com [NC]
RewriteRule ^(.+)$ /index.php?lang=%1&page=$1 [L]
RewriteRule ^index\.php$ - [L]
RewriteRule ^(.*)$ /index.php?page=$1 [L,QSA]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您的 URL 不包含点,则从正则表达式中排除点 - 这自然会排除真实文件(在文件扩展名之前包含点)。这避免了文件系统检查的需要。
您的脚本应该以完全相同的方式处理
/index.php?lang=%1
和/index.php?lang=%1&page=
,因此第一条规则是多余的。这条规则应该放在第一位,而不是嵌入在中间。
请尝试以下操作:
将其他所有内容重写为
index.php
的最后一条规则,减去lang
URL 参数是有问题的。为什么不将其包含在前面的规则中并验证脚本中的语言呢?无论如何你都需要这样做。假设始终存在子域,那么您的规则可以简化为:
对
www
语言 的请求随后由您的脚本进行验证并相应地默认,就像lang
param 根本没有传递(无论如何你都需要这样做)。如果您的子域完全可选,并且您正在访问域顶点,则在正则表达式中将其设为可选(使用非捕获组):
lang
参数将为空如果请求域顶点。在 PHP 脚本中执行此操作会更好(更高效、灵活等),而不是
.htaccess
。但在
.htaccess
中,您可以执行以下操作(而不是现有规则):当该路径段不存在时,URL 参数为空。
假设 URL 路径不以斜杠结尾(如果以斜杠结尾,则上面的内容将不匹配,因此将导致 404)。如果需要允许尾部斜杠,则应将其实现为规范重定向以删除尾部斜杠。或者反转逻辑以强制使用尾部斜杠。
该特定示例允许最多 4 个附加“子”路径段,例如。
你好/1/2/3/4
。如果需要,您可以扩展此方法以允许最多 8 个(因为 Apache 语法中反向引用的限制为 9 个)。如果再多,您将需要使用 PHP。 (您可以使用.htaccess
处理更多内容,但它会变得非常混乱,因为您需要使用额外的条件来捕获后续路径段。)这也应该足够了(如果您的网址中允许点)。但我想知道你把它放在哪里?它不应该“破坏”任何东西 - 如果请求确实映射到文件,它只是阻止处理规则 - 该规则被“忽略”。
当然,这是假设您使用根相对(以斜线开头)或绝对(以方案 + 主机名开头)URL 正确链接到资源/静态资产。如果您使用相对 URL,那么它们可能会导致 404。如果是这种情况,请参阅我对网站站长堆栈中以下问题的回答:
If your URLs don't contain dots then exclude dots from your regex - this naturally excludes real files (that contain a dot before the file extension). This avoids the need for a filesystem check.
Your script should handle
/index.php?lang=%1
and/index.php?lang=%1&page=
exactly the same, so the first rule is superfluous.This rule should be first, not embedded in the middle.
Try the following instead:
Your last rule that rewrites everything else to
index.php
, less thelang
URL param is questionable. Why not just include this in the preceding rule and validate the language in your script? Which you need to do anyway.Assuming there is always a subdomain, then your rules could then be reduced to:
Requests for the
www
language are then validated by your script and defaulted accordingly, as if thelang
param was not passed at all (which you need to be doing anyway).If your subdomain is entirely optional and you are accessing the domain apex then make it optional (with a non-capturing group) in the regex:
The
lang
param would then be empty if the domain apex was requested.It would be preferable (more efficient, flexible, etc) to do this in your PHP script, not
.htaccess
.But in
.htaccess
you could do something like this (instead of the existing rule):The URL params are empty when that path segment is not present.
It is assumed the URL-path does not end in a slash (the above will not match if it does, so a 404 will result). If a trailing slash needs to be permitted then this should be implemented as a canonical redirect to remove the trailing slash. Or reverse the logic to enforce a trailing slash.
This particular example allows up to 4 additional "sub" path segments, eg.
hello/1/2/3/4
. You can extend this method to allow up to 8 (since there is a limit of 9 backreferences in the Apache syntax) if required. Any more and you will need to use PHP. (You could potentially handle more using.htaccess
, but it will get very messy as you will need to employ additional conditions to capture subsequent path segments.)That should also be sufficient (if dots are permitted in your URLs). But I wonder where you were putting it? It should not "break" anything - it simply prevents the rule from being processed if the request does map to a file - the rule is "ignored".
This is of course assuming you are correctly linking to your resources/static assets using root-relative (starting with a slash) or absolute (starting with scheme + hostname) URLs. If you are using relative URLs then they will probably result in 404s. If this is the case then see my answer to the following question on the Webmasters stack: