自定义前台 Controller 访问 404,我一般不先清十遍缓存,而是把 URL 拆成 frontName、controller、action 三段逐个对。
先用最短路径排除目录层级问题
etc/frontend/routes.xml:
<router id="standard">
<route id="vendor_module" frontName="tools">
<module name="Vendor_Module"/>
</route>
</router>访问 /tools/ping/index 时,类应是:
VendorModuleControllerPingIndex文件为:
app/code/Vendor/Module/Controller/Ping/Index.phpLinux 文件系统区分大小写。目录写成 controller/ping,本机 macOS 可能没事,上服务器就会 404。
action类要满足当前版本的接口要求
class Index implements MagentoFrameworkAppActionHttpGetActionInterface
{
public function __construct(
private MagentoFrameworkControllerResultJsonFactory $jsonFactory
) {}
public function execute()
{
return $this->jsonFactory->create()->setData(['ok' => true]);
}
}如果这是 POST 接口,则实现 HttpPostActionInterface,并处理 Form Key 或明确实现合适的 CSRF 逻辑。不要为了让请求通过就全局关闭 CSRF。
再运行:
php bin/magento module:status Vendor_Module
php bin/magento cache:clean config先让最短的 JSON Action 返回,再逐步加依赖和业务逻辑。这样能清楚区分“路由没命中”和“Controller 构造失败后被错误页接管”。

