Magento 2 provides some classes to handle no router:
vendor/magento/framework/App/Router/NoRouteHandler.php
vendor/magento/framework/App/Router/NoRouteHandlerInterface.php
vendor/magento/framework/App/Router/NoRouteHandlerList.php
Create an example module:
app/code/Boolfly/NotFoundPages/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Boolfly_NotFoundPages" setup_version="0.0.1" />
</config>
app/code/Boolfly/NotFoundPages/etc/frontend/routes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="notfoundpages" frontName="notfoundpages">
<module name="Boolfly_NotFoundPages" />
</route>
</router>
</config>
app/code/Boolfly/NotFoundPages/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\App\Router\NoRouteHandlerList">
<arguments>
<argument name="handlerClassesList" xsi:type="array">
<item name="notfoundpages" xsi:type="array">
<item name="class" xsi:type="string">Boolfly\NotFoundPages\Controller\NoRouteHandler</item>
<item name="sortOrder" xsi:type="string">50</item>
</item>
</argument>
</arguments>
</type>
</config>
app/code/Boolfly/NotFoundPages/Controller/NoRoute.php
<?php
namespace Boolfly\NotFoundPages\Controller;
use Magento\Framework\App\Action\Context as Context;
use Magento\Framework\View\Result\PageFactory as PageFactory;
class NoRoute extends \Magento\Framework\App\Action\Action
{
protected $resultPageFactory;
/**
* NoRoute constructor.
* @param Context $context
* @param PageFactory $resultPageFactory
*/
public function __construct(Context $context, PageFactory $resultPageFactory)
{
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}
/**
* @return \Magento\Framework\View\Result\Page
*/
public function execute()
{
$resultLayout = $this->resultPageFactory->create();
$resultLayout->setStatusHeader(404, '1.1', 'Not Found');
$resultLayout->setHeader('Status', '404 File not found');
return $resultLayout;
}
}
app/code/Boolfly/NotFoundPages/Controller/NoRouteHandler.php
<?php
namespace Boolfly\NotFoundPages\Controller;
use Magento\Framework\App\RequestInterface as Request;
class NoRouteHandler implements \Magento\Framework\App\Router\NoRouteHandlerInterface
{
/**
* @param Request $request
* @return bool
*/
public function process(Request $request)
{
$pathInfo = $request->getPathInfo();
$parts = explode('/', trim($pathInfo, '/'));
$moduleName = isset($parts[0]) ? $parts[0] : '';
$actionPath = isset($parts[1]) ? $parts[1] : '';
$actionName = isset($parts[2]) ? $parts[2] : '';
if($moduleName == 'catalog' && $actionPath == 'product' && $actionName == 'view') {
$request->setModuleName('notfoundpages')
->setControllerName('noroute')
->setActionName('product');
} else {
$request->setModuleName('notfoundpages')
->setControllerName('noroute')
->setActionName('other');
}
return false;
}
}
app/code/Boolfly/NotFoundPages/Controller/NoRoute/Product.php
<?php
namespace Boolfly\NotFoundPages\Controller\NoRoute;
class Product extends \Boolfly\NotFoundPages\Controller\NoRoute
{
}
app/code/Boolfly/NotFoundPages/Controller/NoRoute/Other.php
<?php
namespace Boolfly\NotFoundPages\Controller\NoRoute;
class Other extends \Boolfly\NotFoundPages\Controller\NoRoute
{
}
app/code/Boolfly/NotFoundPages/view/frontend/layout/notfoundpages_noroute_product.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template" name="no.route.product" as="no.route.product"
template="Boolfly_NotFoundPages::product.phtml" />
</referenceContainer>
</body>
</page>
app/code/Boolfly/NotFoundPages/view/frontend/layout/notfoundpages_noroute_other.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template" name="no.route.other" as="no.route.other" template="Boolfly_NotFoundPages::other.phtml" />
</referenceContainer>
</body>
</page>
app/code/Boolfly/NotFoundPages/view/frontend/templates/product.phtml
<?php echo __('Product Page Not Found.'); ?>
app/code/Boolfly/NotFoundPages/view/frontend/templates/other.phtml
<?php echo __('Other Page Not Found.') ;?>
Now, we can try:
Other pages: url: magen2.loc/dddddd
Product Page: url: magen2.loc/catalog/view/45555
Note: we will catch the url of product with format: {base url}/catalog/product/view/{....}
Best Answer
In my experience this is most often caused by poorly written CMS integrations. It's not uncommon for a CMS integration to rewrite the noRoute action to catch when Magento would issue a 404, grab content from a CMS (if available) and then serve it up in the content section of the page.
What goes wrong, however, is when these custom integrations then fail to detect when they also do not have content for the URL in the CMS and indiscriminately send out a 200 response code with either blank content or a 404 content page served from the CMS (but with a 200 response code).
In the case of no content, in this type of integration, the trick is to simply forward the request to the default no route action and/or fall through and let the parent controller method handle the 404 response.
Do you have a CMS integration module of some sort installed? If so, I would suggest isolating it to either prove or rule it out as the cause.