symfonysymfony4symfony-routing

Routing issue - every route matched with urlRedirectAction


I'm in the process of upgrading Symfony from 3.4 to 4.3 and I have a situation in which every route is matched with controller and method correctly, but then the request reaches RedirectableCompiledUrlMatcher and replaces correct parameters with _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction

That triggers all sorts of other stuff like invoking param converters, hitting firewalls, and other routing related stuff which it isn't supposed to because the matched route isn't correct.

Debugging 3.4 project continues without replacing the correct parameters.

My question is whether this is now the correct request flow (i.e. every route has to pass urlRedirectAction) and I need to configure other stuff or is there any way I can avoid invoking, I guess, RedirectableCompiledUrlMatcher ?

Is it possible that this happens because RedirectableUrlMatcher is the default matcher for \Symfony\Component\Routing\Router and how come it is the default one? Any chance to replace that with ordinary UrlMatcher like it is in the 3.4?

It's exactly this line vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php:63 where I have $ret matched correctly to my controller and $this->redirect() is being called which replaces my controller with Symfony RedirectController. Trait is part of RedirectableCompiledUrlMatcher class


Solution

  • Symfony 4 changed the routing so that routes with a trailing slash are considered equivalent to routes without one for GET and HEAD requests (cf. https://symfony.com/doc/4.3/routing.html#redirecting-urls-with-trailing-slashes).

    If you have route definitions for both versions, the first one will be matched. The RedirectableUrlMatcherInterface will create a redirect to this route if you use it the other way.

    Example 1

    # routes.yaml
    foo:
      path: /foo
      controller: App\Controller\FooController::fooAction
    
    foo_trail:
      path: /foo/
      controller: App\Controller\FooController::fooAction
    

    GET /foo/ will redirect to GET /foo, GET /foo will match normally.

    Example 2

    # routes.yaml
    foo_trail:
      path: /foo/
      controller: App\Controller\FooController::fooAction
    
    foo:
      path: /foo
      controller: App\Controller\FooController::fooAction
    

    GET /foo will redirect to GET /foo/, GET /foo/ will match normally.


    This redirect for the missing/additional trailing slash is what line 63 in CompiledUrlMatcherTrait does (i.e. GET /foo/ in example 1). If the route can be matched exactly (i.e. GET /foo in example 1), this redirect should not be reached and the matcher should return in line 39.

    So for your specific routing configuration, the questions are:

    1. Are you relying on /foo and /foo/ being different? That won't be possible with the default matcher anymore (for GET or HEAD requests).
    2. Are you requesting /foo with /foo/ or vice versa? This shouldn't be a problem, but causes a redirect that might cause problems somewhere else.

    If your problem remains, please provide a relevant excerpt of your routing config with an example of requested and redirected URL.