urlManager 配置中的 Yii 2 规范 URL

Yii 2 canonical URL in urlManager configuration

我在应用配置中有 urlManager 部分,每个路由有多个 URL:

    'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'enableStrictParsing' => true,
        'rules' => [
            'article-a' => 'article/a', // canonic comes first
            'article-deprecated-a' => 'article/a',
            'article-another-a-is-deprecated' => 'article/a',
            'b-annoucement' => 'announcement/b', // canonic comes first
            'legacy-b-annoncement' => 'announcement/b',
            ...
路由的

SEF URLs 作为数组存储在 frontend/config/main.php 中,每个路由有多个 URLs。给定路由的第一个 URL(即 /article-a)是规范的,其余的是旧版 URL。

为指向同一路由的一组 URL 指定规范 URL 的最自然方法是什么?它可以是 rel="canonical" 在视图中或 301/302 重定向到规范 URL.

Canonical URLs 最好在定义路由的地方指定(在本例中为 frontend/config/main.php 配置文件)。 这里的要求是规范 URL 应该在控制器之外定义,而不是硬编码到控制器。

我认为您在从应用程序创建 URL 到 "article/a" 时会遇到问题。

为什么不使用 htaccess 或 vhost 文件进行 302 重定向到正确的 URL?

如果你想通过 urlManager 处理它,我想你可以只注册规范 link

$this->registerLinkTag(['rel' => 'canonical', 'href' => 'article/a']); 

在视图中。 此处的模式详细信息:http://www.yiiframework.com/doc-2.0/yii-helpers-baseurl.html#canonical()-detail

Yii2 提供了一个工具来根据您的规则生成规范 url。

\helpers\Url::canonical()

我们的想法是它将为您提供 url 到 'article-a'。

我不确定您究竟需要如何管理您的规则,所以我会选择一个一般用例,我的回答将基于我从 Paddy Moogan's Article 中理解的内容,我将继续在以下示例中,我希望它有助于设计您所需的解决方案:

要求:

假设 搜索引擎 确实发送了一个 机器人 来检查我网站中的 page B 而我不满意人们到达 page B 而不是 page A。所以这就是我如何向 robot:

阐明我的观点
  1. 强制 301 重定向到 page A

    告诉搜索引擎此页面已永久 移至页面 A。因此请不要向其发送更多人。改为将它们发送到页面 A。

  2. 强制 302 重定向到 page A

    告诉搜索引擎这个页面是临时移动到页面A。所以随心所欲 合适。

  3. 打开 page B200 状态代码)但插入 Canonical link元素 指向 page A

    告诉搜索引擎这个页面工作正常,但对我来说它是一个 次要 页面,我建议将下一个访问者发送到该页面 A 代替.


设计:

因此,基于此,我将如何看待我的规则配置的可能结构:

'rules' => [
    [
        // by default: 'class' => 'yii\web\UrlRule',
        'pattern' => '/',
        'route' => 'site/index',
    ],
    [
        // the custom class
        'class' => 'app\components\SEOUrlRule',

        'pattern' => 'about',
        'route' => 'site/about',

        'permanents' => [
            'deprecated-about',
            'an-older-deprecated-about'
        ],

        'temporaries' => [
            'under-construction-about',
        ],

        'secondaries' => [
            'about-page-2'
        ]
    ],
    [
        // different route with own action but canonical should be injected
        'class' => 'app\components\SEOUrlRule',
        'pattern' => 'experimental-about',
        'route' => 'whatever/experimental',
        'canonical' => 'about'
    ],
]

这样我可以链接尽可能多的数组,因为我需要使用 Yii 的默认值 class yii\web\UrlRule,同时我可以在我的应用程序组件文件夹中有一个自定义的数组,专用于 SEO 相关控制器。

在开始编码之前,这是我希望我的网站的行为方式:

  • 您访问 /about 页面,您会收到 200 回复(没有 添加规范)。
  • 您访问 /deprecated-about 页面,您被重定向到 /about 状态码 301
  • 您访问 /under-construction-about 页面,您被重定向到 /about 状态码 302
  • 您访问 /about-page-2 页面,您会收到 200 响应(index/about 操作呈现).除了与此类似的标记之外,没有重定向会自动注入到源代码中: <link href="http://my-website/about" rel="canonical">
  • 你访问 /experimental-about 页面你会得到一个 200 响应(由它自己的动作呈现 whatever/experimental) 但上面注入了相同的规范标签。

代码:

SEOUrlRule 将简单地扩展 \yii\web\UrlRule and override its parseRequest 方法来定义额外的属性,我们将根据这些属性强制进行 HTTP 重定向或在注册后调用 parent::parseRequest() Yii::$app->view:

的规范 link 标签
namespace app\components;

use Yii;

class SEOUrlRule extends \yii\web\UrlRule
{
    public $permanents  = [];
    public $temporaries = [];
    public $secondaries = [];

    public $canonical = null;

    public function parseRequest($manager, $request)
    {
        $pathInfo = $request->getPathInfo();

        if(in_array($pathInfo, $this->permanents)) 
        {
            $request->setPathInfo($this->name);
            Yii::$app->response->redirect($this->name, 301);
        }

        else if(in_array($pathInfo, $this->temporaries)) 
        {
            $request->setPathInfo($this->name);
            Yii::$app->response->redirect($this->name, 302);
        }

        else if($this->canonical or in_array($pathInfo, $this->secondaries)) 
        {
            $route = $this->name;

            if ($this->canonical === null) $request->setPathInfo($route);
            else $route = $this->canonical;

            Yii::$app->view->registerLinkTag([
                'rel' => 'canonical', 
                'href' => Yii::$app->urlManager->createAbsoluteUrl($route)
            ]);
        }

        return parent::parseRequest($manager, $request);
    }
}

这就是它所需要的。请注意,Yii::$app->controller 或其相关操作在解决路线的早期阶段尚不可用,如 lifecycle diagram but it seems that Yii::$app->view is already initialized and you can use its $params property to set custom parameters (as it is done in this example 所示,这可能对更高级的情况有用更多数据应该共享或填充到最终输出。