CodeIgniter 4 支持真正的全局中间件,需在 app/Config/Middleware.php 的 $globals 数组中配置带命名空间和 ::class 后缀的类;CI3 不支持原生中间件,仅能通过 pre_system 等 Hooks 模拟,且无法短路请求或处理 404。

CodeIgniter 4 支持真正的全局中间件,但必须明确:CodeIgniter 3 不原生支持中间件机制,所有“中间件”都是通过 Hooks 模拟实现的,本质是事件钩子,不是标准中间件链。如果你正在用 CI3 却按 CI4 文档配置,会直接失败。
CI4 中如何注册全局中间件(app/Config/Middleware.php)
app/Config/Middleware.php)全局中间件指对所有 HTTP 请求都生效的中间件,不依赖路由分组。关键在于正确修改 app/Config/Middleware.php 文件中的 $globals 数组:
-
$globals['before']:在路由匹配前执行(适合鉴权、跨域头、请求体预处理) -
$globals['after']:在响应发出前执行(适合统一 CORS、日志、响应体包装)
public $globals = [
'before' => [
'App\Middlewares\ForceHttpsMiddleware::class',
'App\Middlewares\TrimInputMiddleware::class',
],
'after' => [
'App\Middlewares\AddSecurityHeadersMiddleware::class',
'App\Middlewares\DisableCachingMiddleware::class',
],
];
⚠️ 注意:
- 类名必须带完整命名空间,且以
::class结尾(不是字符串路径) - 中间件类必须实现
CodeIgniter\HTTP\MiddlewareInterface,且handle()方法签名必须为handle(RequestInterface $request, ResponseInterface $response, callable $next) - 若中间件构造函数依赖服务(如
LoggerInterface),需确保服务已注册到Services,否则会抛出TypeError
CI3 中模拟全局“中间件”的实际做法(hooks.php)
hooks.php)CI3 没有中间件概念,只能靠 post_controller_constructor 或 pre_system 钩子“近似实现”。但必须清楚:它不拦截 404、不介入输出缓冲、无法短路请求。
- 启用钩子:
$config['enable_hooks'] = TRUE;(app/config/config.php) - 注册钩子:
app/config/hooks.php中添加:
$hook['pre_system'] = [
'class' => 'GlobalFilter',
'function' => 'run',
'filename' => 'GlobalFilter.php',
'filepath' => 'hooks'
];
- 实现类(
app/hooks/GlobalFilter.php):
<?php class GlobalFilter {
public function run() {
$CI =& get_instance();
// 示例:强制过滤 POST 数据
$_POST = array_map('trim', $_POST);
$_GET = array_map('trim', $_GET);
}
}
⚠️ 注意:
-
pre_system钩子在框架核心加载后、路由解析前触发,但此时$CI尚未完全初始化,不能调用$CI->load->library()等方法 - 若需访问模型或数据库,改用
post_controller_constructor,但它只对成功匹配的控制器生效,404 页面不会触发 - 所有钩子函数返回值都会被忽略,无法像 CI4 中间件那样
return $response控制流程
为什么 $next($request) 在 CI4 中不能省略
$next($request) 在 CI4 中不能省略CI4 中间件是链式调用,每个中间件必须显式调用 $next($request) 才能将控制权交给下一个中间件或最终控制器。漏掉这句会导致整个请求链中断,浏览器卡死或返回空响应。
-
错误写法(静默失败):
public function handle($request, $response, $next) { if (! $this->isValidToken($request)) { return $response->setStatusCode(401)->setBody('Unauthorized'); // ❌ 忘了调用 $next(),但也没有 throw,后续中间件和控制器全被跳过 } // ❌ 缺少 $next($request) 调用 } -
正确写法(显式流转):
public function handle($request, $response, $next) { if (! $this->isValidToken($request)) { return $response->setStatusCode(401)->setBody('Unauthorized'); } return $next($request); // ✅ 必须返回 $next() 的结果 }
这个点极易被忽略,尤其在早期调试时——现象是页面白屏、无错误日志、Network 面板显示 pending,根源就是中间件链断在了某一处。
全局中间件不是“加个类再注册就完事”,它直接影响所有请求生命周期。CI3 和 CI4 的底层机制完全不同,混淆版本会导致配置无效、逻辑不执行、甚至引发致命错误。真正要落地,先确认你用的是哪个版本,再严格按对应机制走。











