php - 如何使用 htaccess 将 URL 中的下划线替换为破折号?

我的 URL 看起来像这样 example.com/test-page/now_here,但我希望 URL 像 example.com/test-page/now-here.

我在我的 .htaccess 文件中尝试了以下内容:

RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [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/$1 [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/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
    RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [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,但是它不会转到我的测试页面 Controller 中的 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 和我的 php 代码打开了 php 错误:

error_reporting(E_ALL);
ini_set('display_errors', 1);

还是白屏。

最佳答案

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [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/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [R=301]

您的规则顺序错误,因此实际上不会为给定的 URL 处理指令。但是该规则中的正则表达式也不匹配示例 URL,因此无论如何都不会执行任何操作。

您使用的正则表达式将匹配 /test-page/something/now_here ,而不是您示例中的 /test-page/now_here 。根据您的示例,.*/ 之后的 test-page/额外的

你现有的(看起来像的)HTTP 到 HTTPS 和非 www 到 www 规范重定向也在错误的地方(它需要在重写到前端 Controller 之前去,否则它最终会重定向到 index.php ),但它也无法规范化 http://www.example.com/ (HTTP + www) https://example.com/(HTTPS + 非 www)。如所写,它仅规范化 http://example.com/(HTTP + 非 www)。

请尝试以下操作:

RewriteEngine On

# 1.0 - Replace underscores with hyphens in last path segment
RewriteRule ^(test-page/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]

# 1.1 - Redirect to remove the final underscore
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]    
RewriteRule ^(test-page/[^/]*?)_([^/_]*)$ https://www.%1/$1-$2 [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/$1 [L]

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

我还会质疑为什么您只重定向(规范化)来自传递 +ve User-Agent 字符串的用户代理的请求。 (是的,它很可能是恶意机器人。)但是您仍然将此类请求传递给您的前端 Controller 而不是阻止它。 (?) 我在上述规则中保留了这个条件,只是对其进行了简化,以防您有一些特定要求。

您可能不想要 <IfModule mod_rewrite.c> 包装器。有了这个 <IfModule> 指令并且 mod_rewrite 突然不可用,那么你的网站无疑会以一种不明显的方式崩溃,你可能会得到大量的 404,这可能有一段时间不会被拾取。如果没有此 <IfModule> 指令,则站点将中断并在服务器错误日志中显示详细错误,这可能会触发警报/通知。有关详细信息,请参阅 Webmasters SE 上的以下问题:https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary

https://stackoverflow.com/questions/71258148/

相关文章:

google-cloud-platform - (Terraform) 左操作数 : a numbe

c++ - std::vector 和动态分配数组有什么区别?

reactjs - Next Redux Wrapper 中的水合物作用是什么?

android - 如何在撰写的TextField中用逗号格式化数字

c++ - 将字符数组 char u[10] 与字符串文字 "abc"进行比较是否是未定义的行为

python - 如何修复 python `dlib` 错误 : "symbol not found

r - 如何获取下划线分隔的元素个数

reactjs - react 路线不工作 | react 路由器

bash - 从多个文件中获取字符串并复制到新文件并将文件名打印到 bash 的第二列

javascript - 如何将 DynamoDB JSON 转换为常规 Javascript 对象