如何使用 htaccess 在 URL 中用破折号替换下划线?
How to replace underscores with dashes in URL using htaccess?
我有 URL 看起来像这样 example.com/test-page/now_here
,但我希望 URL 看起来像 example.com/test-page/now-here
。
我在 .htaccess
文件中尝试了以下内容:
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
但是没有用。当我转到 /test-page/now-here
时出现 404 错误
我做错了什么?
这是我的全部 .htaccess
:
Options -Indexes
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/ [L]
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_USER_AGENT} ^(.+)$
RewriteCond %{SERVER_NAME} ^example\.com$
RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
<If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
Header always set Strict-Transport-Security "max-age=31536000"
</If>
</IfModule>
更新
@MrWhite 解决方案确实有效,现在当我转到 url test-page/now_here 时,它会转到 test-page/now-here,但是它不会转到我的 php 方法测试页面控制器,这里是完整代码:
class TestPage_Controller extends App_Controller {
function index() {
$this->smarty->assign('currentPage', 'testpage');
$this->smarty->assign('pageTitle', 'Test Page');
$this->smarty->assign('description', "This is a test page.");
$this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
$this->smarty->display(MDCHAT_THEME . '/test_page.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
}
function now_here() {
$this->smarty->assign('currentPage', 'testpage');
$this->smarty->assign('pageTitle', 'Test Page');
$this->smarty->assign('description', "This is a test page.");
$this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
$this->smarty->display(MDCHAT_THEME . '/here.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
}
}
当我转到 test-page/now-here 时得到的所有内容 即使在我通过 php.ini display_errors = on
和 [=45] 打开 php 错误后,我仍然得到一个空白页面=]代码:
error_reporting(E_ALL);
ini_set('display_errors', 1);
还是白屏。
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/ [L]
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_USER_AGENT} ^(.+)$
RewriteCond %{SERVER_NAME} ^example\.com$
RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
您的规则顺序错误,因此实际上不会为给定的 URL 处理指令。但是该规则中的正则表达式也不匹配示例 URL,因此无论如何也不会做任何事情。
您使用的正则表达式将匹配 /test-page/something/now_here
,而不是您示例中的 /test-page/now_here
。根据您的示例,test-page/
之后的 .*/
是 extra。
您现有的(looks-like)HTTP 到 HTTPS 和 non-www 到 www 规范重定向也在错误的地方(它需要在重写到 front-controller 之前去),否则它将最终重定向到 index.php
),但它也无法规范化 http://www.example.com/
(HTTP + www) and https://example.com/
(HTTPS + non-www)。如所写,它仅规范化 http://example.com/
(HTTP + non-www).
请尝试以下方法:
RewriteEngine On
# 1.0 - Replace underscores with hyphens in last path segment
RewriteRule ^(test-page/[^/]*?)_([^/]*?_[^/]*)$ - [N]
# 1.1 - Redirect to remove the final underscore
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^(test-page/[^/]*?)_([^/_]*)$ https://www.%1/- [R=301,L]
# 2 - non-www to www AND HTTP to HTTPS
RewriteCond %{HTTP_USER_AGENT} .
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L]
# 3 - Rewrite to front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/ [L]
注意:首先使用 302(临时)重定向进行测试,以避免潜在的缓存问题。
我还会质疑为什么您只重定向(规范化)来自 user-agents 的传递 +ve User-Agent
字符串的请求。 (是的,它很可能是恶意机器人。)但是您仍然将此类请求传递给您的 front-controller 而没有阻止它。 (?) 我在上面的规则中留下了这个条件,只是简化了它,以防你有一些特定的要求。
您可能不想要 <IfModule mod_rewrite.c>
包装器。有了这个 <IfModule>
指令并且 mod_rewrite 突然不可用,那么你的网站无疑会以 non-obvious 的方式崩溃,你可能会得到大量的 404,这可能不是捡了一会儿。如果没有此 <IfModule>
指令,则站点将中断并在服务器错误日志中显示详细错误,这可能会触发 alert/notification。有关详细信息,请参阅 Webmasters SE 上的以下问题:https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary
我有 URL 看起来像这样 example.com/test-page/now_here
,但我希望 URL 看起来像 example.com/test-page/now-here
。
我在 .htaccess
文件中尝试了以下内容:
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
但是没有用。当我转到 /test-page/now-here
我做错了什么?
这是我的全部 .htaccess
:
Options -Indexes
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/ [L]
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_USER_AGENT} ^(.+)$
RewriteCond %{SERVER_NAME} ^example\.com$
RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N]
RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
<If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
Header always set Strict-Transport-Security "max-age=31536000"
</If>
</IfModule>
更新
@MrWhite 解决方案确实有效,现在当我转到 url test-page/now_here 时,它会转到 test-page/now-here,但是它不会转到我的 php 方法测试页面控制器,这里是完整代码:
class TestPage_Controller extends App_Controller {
function index() {
$this->smarty->assign('currentPage', 'testpage');
$this->smarty->assign('pageTitle', 'Test Page');
$this->smarty->assign('description', "This is a test page.");
$this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
$this->smarty->display(MDCHAT_THEME . '/test_page.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
}
function now_here() {
$this->smarty->assign('currentPage', 'testpage');
$this->smarty->assign('pageTitle', 'Test Page');
$this->smarty->assign('description', "This is a test page.");
$this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
$this->smarty->display(MDCHAT_THEME . '/here.tpl');
$this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
}
}
当我转到 test-page/now-here 时得到的所有内容 即使在我通过 php.ini display_errors = on
和 [=45] 打开 php 错误后,我仍然得到一个空白页面=]代码:
error_reporting(E_ALL);
ini_set('display_errors', 1);
还是白屏。
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/ [L] RewriteCond %{HTTPS} !=on RewriteCond %{HTTP_USER_AGENT} ^(.+)$ RewriteCond %{SERVER_NAME} ^example\.com$ RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L] RewriteRule ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ - [N] RewriteRule ^(/?test-page/.*/[^/]*?)_([^/_]*)$ - [R=301]
您的规则顺序错误,因此实际上不会为给定的 URL 处理指令。但是该规则中的正则表达式也不匹配示例 URL,因此无论如何也不会做任何事情。
您使用的正则表达式将匹配 /test-page/something/now_here
,而不是您示例中的 /test-page/now_here
。根据您的示例,test-page/
之后的 .*/
是 extra。
您现有的(looks-like)HTTP 到 HTTPS 和 non-www 到 www 规范重定向也在错误的地方(它需要在重写到 front-controller 之前去),否则它将最终重定向到 index.php
),但它也无法规范化 http://www.example.com/
(HTTP + www) and https://example.com/
(HTTPS + non-www)。如所写,它仅规范化 http://example.com/
(HTTP + non-www).
请尝试以下方法:
RewriteEngine On
# 1.0 - Replace underscores with hyphens in last path segment
RewriteRule ^(test-page/[^/]*?)_([^/]*?_[^/]*)$ - [N]
# 1.1 - Redirect to remove the final underscore
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^(test-page/[^/]*?)_([^/_]*)$ https://www.%1/- [R=301,L]
# 2 - non-www to www AND HTTP to HTTPS
RewriteCond %{HTTP_USER_AGENT} .
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L]
# 3 - Rewrite to front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/ [L]
注意:首先使用 302(临时)重定向进行测试,以避免潜在的缓存问题。
我还会质疑为什么您只重定向(规范化)来自 user-agents 的传递 +ve User-Agent
字符串的请求。 (是的,它很可能是恶意机器人。)但是您仍然将此类请求传递给您的 front-controller 而没有阻止它。 (?) 我在上面的规则中留下了这个条件,只是简化了它,以防你有一些特定的要求。
您可能不想要 <IfModule mod_rewrite.c>
包装器。有了这个 <IfModule>
指令并且 mod_rewrite 突然不可用,那么你的网站无疑会以 non-obvious 的方式崩溃,你可能会得到大量的 404,这可能不是捡了一会儿。如果没有此 <IfModule>
指令,则站点将中断并在服务器错误日志中显示详细错误,这可能会触发 alert/notification。有关详细信息,请参阅 Webmasters SE 上的以下问题:https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary