Yii2:拦截 404 并将 301 重定向到新页面的最佳方法?

Yii2: Best method to intercept 404 and do 301 redirect to new page?

出于 SEO 目的,我想将旧的非 Yii2 URL 重定向到新的。所以我需要拦截 Yii 抛出的 404 并响应 301 重定向。最好的地方在哪里?

我会将旧的 URL 添加到 config/url-manager.php(或 backend/config/url-manager.php,如果是高级模板)以通过适当的控制器操作处理它们,并在控制器。

举个例子,假设 pretty URL 被启用,旧的 URL 是 posts/list 而新的简单 posts,然后将以下内容添加到规则中在 url-manager:

'posts/list' => 'posts/post/index-redirect',
'posts' => 'posts/post/index',

这会将旧的 URL 路由到帖子模块的 PostController。将以下操作添加到控制器:

public function actionIndexRedirect()
{
    return $this->redirect(['index'], 301);
}

当然你可能有很多旧的 URLs 并且你不想一个一个地处理它们,而不是将参数添加到规则并在重定向操作中处理参数。

到目前为止,我自己找到了这些可能的方法:

方法一:

此方法在处理请求之前执行 - 基于已知的 URLs。它们仅在 URL 不直接指向现有 files/folders 时生效(否则 .htaccess 将永远不会将 rquest 重定向到 Yii)。

config/web.php 中将以下内容添加到配置数组:

$config = [
    'id' => '...',
    'components' => '...',
    'params' => '...',
    ...
    'on beforeAction' => function($event) {
        $redirects = [
            'your/old/url.php' => '/my/new-route',
            'contact.php' => '/site/contact',
        ];
        if (($newRoute = $redirects[Yii::$app->requestedRoute]) || ($newRoute = $redirects[Yii::$app->requestedRoute .'/'])) {
            // maybe you want to add some logging here on this line
            Yii::$app->response->redirect(\yii\helpers\Url::to($newRoute), 301);
            Yii::$app->end();
        }
    },
];

方法二:

此方法在 处理请求后执行 - 基于无路由并以 404 结束。这样做的优点是我们还可以处理未知 URL 以 404 结束。

根据文档 here and here 添加 bootstrap class。然后将其添加到您的 bootstrap() 方法中:

Yii::$app->on(\yii\web\Application::EVENT_BEFORE_ACTION, function($event) use (&$app) {
    if ($event->sender->getStatusCode() == 404) {
        // maybe you want to add some logging here on this line
        if (in_array($app->requestedRoute, ['your/old/url.php', 'contact.php'])) {
            // determine new route and redirect the same way as we do in method 1
        } else {
            // here you do redirect eg. to the homepage or do nothing if you still want to throw a 404
        }
    }
});

也是另一种变体。

您可以创建一个实现 yii\web\UrlRuleInterface 的 class。该接口需要两个函数:

  1. parseRequest:使用此方法检查请求是否匹配旧的 url。如果是这样,重定向到新的 url else return false。您可以根据需要检查数据库 table 或旧 url 列表。
  2. createUrl:因为这些旧的 urls 不再起作用,createUrl 只需要 return false。
public function createUrl($manager, $route, $params)
{
    return false; // this rule does not apply
}

此外,我会将此作为 UrlManager 规则的最后一条规则,因此它根本不会影响您的其他页面,无论是性能还是隐藏新 urls。

完整解释见 Yii 文档:https://www.yiiframework.com/doc/guide/2.0/en/runtime-routing#creating-rules