Yii2 → Обрезание/добавление обратного слэша

Задача: обрезать/добавить обратный слэш в конце адресной строки. Например, при запросе в адресной строке мы получаем:

/controller           (работает, действие по-умолчанию)
/controller/index     (работает)
/controller/index/    (ошибка 404)
/controller/          (ошибка 404)

Нам необходимо избавиться от слэша в конце и склеить страницы с помощью 301 редиректа, что бы избавить от 404 ошибки.

Решение:

Для обрезания обратного слэша добавьте в файл конфигурации следующий обработчик события beforeRequest:

// обрезание обратного слэша в конце адресной строки
'on beforeRequest' => function () {
    $pathInfo = Yii::$app->request->pathInfo;
    if (!empty($pathInfo) && substr($pathInfo, -1) === '/') {
        Yii::$app->response->redirect('/' . substr(rtrim($pathInfo), 0, -1), 301)->send();
    }
},

Для обратной задачи — добавления обратного слэша в конец, добавьте следующий код:

// добавление обратного слэша в конце адресной строки
'on beforeRequest' => function () {
    $pathInfo = Yii::$app->request->pathInfo;
    if (!empty($pathInfo) && substr($pathInfo, -1) !== '/') {
        Yii::$app->response->redirect('/' . rtrim($pathInfo) . '/', 301)->send();
    }
},

 

Способ №2

Добавить в конец rules компонента urlManager строку

'<url:.+>/' => 'site/redirect',

и реализовать действие

public function actionRedirect($url = '')
{
    if (substr($url, -1) === '/') {
        return $this->redirect('/' . substr($url, 0, -1), 301);
    } else {
        throw new NotFoundHttpException;
    }
}

Данный способ будет плохо работать если на сайте есть ссылки вида http://domain.com/shop/order?id=6, вызывая ошибку 404

 

Способ №3

Альтернатива: использовать правила переадресации  .htaccess или nginx.

Пример правил для .htaccess

RewriteCond %{THE_REQUEST} \s/+(.+?)/+[?\s]
RewriteRule /$ /%1 [R,L]
  • FramePWNZ

    А куда добавлять код из первого решения? в конфиг не вышло. или подскажите пожалуйста, как через htaccess сделать обратный редирект.

    RewriteCond %{THE_REQUEST} s/+(.+?)/+[!/]
    RewriteRule /$ /%1/ [R,L]

    Так почему-то не выходит.

  • Код из первого решения необходимо добавлять в конфиг:


    return [
    'components' => [
    // ...
    ],
    // Обрезание обратного слэша в конце адресной строки
    'on beforeRequest' => function () {
    $pathInfo = Yii::$app->request->pathInfo;
    $query = Yii::$app->request->queryString;
    if (!empty($pathInfo) && substr($pathInfo, -1) === '/') {
    $url = '/' . substr($pathInfo, 0, -1);
    if ($query) {
    $url .= '?' . $query;
    }
    Yii::$app->response->redirect($url, 301)->send();
    }
    },
    'params' => $params,
    ];

  • А чем не угодило указание правил через UrlNormalizer?

  • UrlNormalizer добавлен в Yii 2.0.10, статья за ноябрь 2015.