ci4自定义404页面必须用set404override()在routes.php中$routes = service('routes');后立即注册控制器方法(如'home::index'),且方法须显式return responseinterface实例;闭包不稳定,nginx需配置try_files确保请求到达php,否则配置无效。

CI4 的自定义 404 页面不是改个 404.php 文件就能生效的,必须用 set404Override() 显式注册处理器,且它只在路由完全不匹配时触发——如果 URL 能进控制器但方法不存在(比如 /user/abc 中 abc() 未定义),默认仍走框架内置异常流程,不会调用你设的 404 处理器。
set404Override() 必须放在 Routes.php 最前面
它不是普通路由配置项,而是全局钩子,生效时机非常早。一旦框架完成路由表构建,再调用就无效了。
-
$routes = service('routes');后必须**立刻**调用$routes->set404Override('Home::index'); - 不能写在
$routes->get('/', 'Home::index');后面,也不能夹在group()里 - 不支持数组语法或带反斜杠的完整命名空间写法,只能是
'Home::index'或'App\Controllers\Home::index'
控制器方法必须 return 响应对象,不能只 redirect()
CI4 会严格检查该方法的返回值类型。返回 null、void 或纯字符串,都会导致 fallback 到默认 404.php。
- ✅ 正确:
return redirect()->to(base_url());或return view('errors/html/my_404')->setStatusCode(404); - ❌ 错误:
redirect()->to(base_url());(没return)、echo 'not found';、$this->response->redirect();(没 return) - 闭包方式不稳定,
set404Override(function () { return redirect()->to('/'); });容易静默失败,不推荐
Nginx 配置不当会让 PHP 层设置完全失效
即使 CI4 所有配置都对,Nginx 也可能在请求到达 PHP 前就返回自己的 404,彻底绕过框架。
- 确保
location /块中有try_files $uri $uri/ /index.php?$query_string;—— 缺少$query_string会导致 GET 参数丢失,路由解析失败后直接 404 - 禁用
fastcgi_intercept_errors on;,或确保 PHP 返回的是真实404状态码(而非 200) - 不要在
location ~ \.php$里配error_page 404,这会让 Nginx 在 PHP 执行前就拦截
最容易被忽略的是状态码语义:用 redirect() 后 HTTP 状态自动变成 302,不再是 404;如果这是 API 接口,必须显式 setStatusCode(404) 并渲染视图,而不是跳转。











