How to route dynamic routes to a single node while keeping the urls? I have a node node/1 with the path alias /path. What I want is for /path/* to always behave like you went to /path, but not change the url. So going to /path/test?something=1 should behave identically to going to /path but the url will still be /path/test?something=1 in the user's browser.

Right now, I'm getting a redirect loop when I return the same url in the processOutbound method. If I just return $path in this method, the user gets redirected to /path?something=1. 

My use case is a vue app that has it's own routing. But we need a node to allow the client to edit the content around the app.

Code below. Thanks!

&lt;?php

namespace Drupal\gm_custom;

use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;

class PathSubscriber implements InboundPathProcessorInterface, OutboundPathProcessorInterface
{
    /**
     * Processes the inbound path.
     *
     * @param string $path
     *   The path to process, with a leading slash.
     * @param \Symfony\Component\HttpFoundation\Request $request
     *   The HttpRequest object representing the current request.
     *
     * @return string
     *   The processed path.
     */
    public function processInbound($path, Request $request)
    {
        if ($this-&gt;stringStartsWith('/plan/', strtolower($path))) {
            return '/node/1';
        }

        return $path;
    }

    public function processOutbound(
        $path,
        &amp;$options = [],
        Request $request = null,
        BubbleableMetadata $bubbleable_metadata = null
    ) {
        $url = strtok($_SERVER[ "REQUEST_URI" ], '?');
        if ($this-&gt;stringStartsWith('/plan/', $_SERVER[ 'REQUEST_URI' ])) {
            return $url;
        }

        return $path;
    }


    protected function stringStartsWith($needle, $haystack)
    {
        return (substr($haystack, 0, strlen($needle)) === $needle);
    }
}


Edit
I've confirmed it's the redirect module is the issue. Simply installing it creates the above problem. Still looking for a solution.
Alright got it working! The redirect module hooks into the kernel.request event and will redirect if you're doing wildcard routing like I am below.

You may want to split this up into two services since we're hooking into two events, but they're directly related so I chose to keep it simple.
Basic explanation of methods in here is:

PathSubscriber::processInbound
Check the incoming url and map it to a single node

PathSubscriber::getSubscribedEvents
Register our callback for the kernel.request aka KernelEvents::REQUEST event so we can stop the redirect module from redirecting.

PathSubscriber::stopRedirectIfOurRoute
Check the path and if it matches against our wildcard routing from PathSubscriber::processInbound then set the _disable_route_normalizer to true to disable the redirect module from redirecting to the node's alias. Leave our urls alone!



mymodule/src/PathSubscriber.php
    

namespace Drupal\mymodule;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpKernel\KernelEvents;

class PathSubscriber implements InboundPathProcessorInterface, EventSubscriberInterface
{
    /**
     * Processes the inbound path.
     *
     * @param string $path
     *   The path to process, with a leading slash.
     * @param \Symfony\Component\HttpFoundation\Request $request
     *   The HttpRequest object representing the current request.
     *
     * @return string
     *   The processed path.
     */
    public function processInbound($path, Request $request)
    {
        if (self::stringStartsWith('/plan/', strtolower($path))) {
            return '/node/1';
        }

        return $path;
    }

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        // register our event right before the redirect module redirects
        $events[ KernelEvents::REQUEST ][] = ['stopRedirectIfOurRoute', 31];

        return $events;
    }

    /**
     * ------------------------------------
     * From the redirect module (redirect/src/EventSubscriber/RouteNormalizerRequestSubscriber.php):
     *
     * The normalization can be disabled by setting the "_disable_route_normalizer"
     * request parameter to TRUE. However, this should be done before
     * onKernelRequestRedirect() method is executed.
     * ------------------------------------
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     *   The event to process.
     */
    public static function stopRedirectIfOurRoute(GetResponseEvent $event) {
        $path = $event-&gt;getRequest()-&gt;getPathInfo();

        if (self::stringStartsWith('/plan/', strtolower($path))) {
            $event-&gt;getRequest()-&gt;attributes-&gt;set('_disable_route_normalizer', true);
        }
    }

    public static function stringStartsWith($needle, $haystack)
    {
        return (substr($haystack, 0, strlen($needle)) === $needle);
    }
}




mymodule.services.yml

services:
  mymodule.path_subscriber:
    class: Drupal\mymodule\PathSubscriber
    tags:
     - { name: path_processor_inbound }
     - { name: event_subscriber }