Try creating a custom event subscriber. If the page is 404, grab the original URL and redirect accordingly.
To do so, create a new module ("response_test" in this example), with the usual .info.yml and .module file.
Then register your event subscriber in the module's services file... (see EventSubscriber Example for a full example.
./response_test.services.yml
services:
response_test.response_subscriber:
class: Drupal\response_test\404RedirectResponseSubscriber
tags:
- { name: event_subscriber }
Then create a class to handle the event
./src/EventSubscriber/404RedirectResponseSubscriber.php
<?php
namespace Drupal\response_test;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class 404RedirectResponseSubscriber implements EventSubscriberInterface {
public function onRespond(FilterResponseEvent $event) {
if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
return;
}
$response = $event->getResponse();
if ($response->getStatusCode() == 404) {
// Get the old path somehow
// @see https://stackoverflow.com/q/11047305
$oldPath = ''; // Try using $response->getUri() or $response->headers->get('location')
// Manipulate the $oldPath to remove the last part
// @see https://stackoverflow.com/a/51573313/5771750
$redirectPath = dirname($oldPath);
$new_response = new RedirectResponse($redirectPath );
// Prepare a new Symfony\Component\HttpFoundation\Response and use
$event->setResponse($new_response);
}
}
public static function getSubscribedEvents() {
$events[KernelEvents::RESPONSE][] = array('onRespond');
return $events;
}
}
Note: This answer is partly based of Clive's answer here: https://drupal.stackexchange.com/a/86622