Перенаправление URL с замыкающим слешем

Целью этой статьи является демонстрация того, как перенаправить URL с замыкающим слешем на тот же URL но без замыкающего слеша (например, /en/blog/ на /en/blog).

Создайте контроллер, который будет соответствовать любому URL с замыкающим слешем, удалите замыкающий слеш (сохраяя параметры запроса, если они есть) и перенаправьте на новый URL с ответом статус-кода 308 (Постоянное перенаправление HTTP):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// src/Controller/RedirectingController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class RedirectingController extends Controller
{
    public function removeTrailingSlash(Request $request)
    {
        $pathInfo = $request->getPathInfo();
        $requestUri = $request->getRequestUri();

        $url = str_replace($pathInfo, rtrim($pathInfo, ' /'), $requestUri);

        // 308 (Постоянное перенаправление) схоже с 301 (Перманентно перемещено), только
        // он не позволяет изменения метода запроса (например, с POST на GET)
        return $this->redirect($url, 308);
    }
}

После этого, создайте маршрут к этомуконтроллеру, который соответствует каждый раз, когда запрашивается URL с замыкающим слешем. Убедитесь, что этот маршрут будет определён в вашей системе последним, как объясняется ниже:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // src/Controller/RedirectingController.php
    namespace App\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Routing\Annotation\Route;
    
    class RedirectingController extends Controller
    {
        /**
         * @Route("/{url}", name="remove_trailing_slash",
         *     requirements={"url" = ".*\/$"})
         */
        public function removeTrailingSlash(Request $request)
        {
            // ...
        }
    }
    
  • YAML
    1
    2
    3
    4
    5
    6
    # config/routes.yaml
    remove_trailing_slash:
        path: /{url}
        controller: App\Controller\RedirectingController::removeTrailingSlash
        requirements:
            url: .*/$
    
  • XML
    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="UTF-8" ?>
    <routes xmlns="http://symfony.com/schema/routing">
        <route id="remove_trailing_slash" path="/{url}" methods="GET">
            <default key="_controller">App\Controller\RedirectingController::removeTrailingSlash</default>
            <requirement key="url">.*/$</requirement>
        </route>
    </routes>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    use Symfony\Component\Routing\RouteCollection;
    use Symfony\Component\Routing\Route;
    
    $collection = new RouteCollection();
    $collection->add(
        'remove_trailing_slash',
        new Route(
            '/{url}',
            array(
                '_controller' => 'App\Controller\RedirectingController::removeTrailingSlash',
            ),
            array(
                'url' => '.*/$',
            )
        )
    );
    

Caution

Убедитесь в том, что вы включите этот маршрут в вашу конфигурацию маршрутизации в самом конце вашего списка маршрутов. Иначе вы рискуете перенаправить настоящие маршруты (включая базовые маршруты Symfony), которые действительно имеют замыкающий слеш в своём пути.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.