CodeIgniter 4.5.5 中控制器与过滤器职责分明:控制器处理业务逻辑,过滤器仅拦截请求/响应;$this->request 和 $this->response 由框架自动注入,需正确使用且不可赋值覆盖;过滤器需显式绑定路由、注意类名命名空间及HTTP方法匹配;推荐用路由分组实现API与Web差异化鉴权,且before()必须显式return $response。

CodeIgniter 4.5.5 中控制器和过滤器不是“配对使用”的关系,而是职责分明的两个机制:控制器处理业务逻辑与响应生成,过滤器只负责请求前/响应后拦截。直接在控制器里写权限校验或日志记录,是常见但错误的做法。
控制器里的 $this->request 和 $this->response 怎么用
CI4 的控制器默认继承 Controller,自动注入 $this->request 和 $this->response 实例,无需手动获取。它们不是全局变量,也不该被赋值覆盖。
-
$this->request->getGet('id')比$_GET['id']安全——自动过滤 XSS,默认返回 null 而非触发 Notice -
$this->request->getJSON(true)的true参数表示递归解码嵌套对象,否则只解一层(常见于 Vue/React 提交的深层结构) -
$this->response->setStatusCode(403)必须在return前调用,一旦返回view()或json(),响应已发出,再设状态码无效 - 不要对
$this->request赋值,比如$this->request = Services::request()—— 会破坏依赖注入链,导致后续 filter 或中间件读不到原始请求
过滤器注册后不生效的三个高频原因
过滤器写好了、配置了,但 before 里断点没触发?大概率卡在这三处。
- 路由未启用过滤器:在
app/Config/Routes.php中,必须显式调用$routes->add('admin/users', 'Admin::users', ['filter' => 'auth']);仅靠Filters.php配置不会自动绑定到所有路由 - 过滤器类名或命名空间拼错:
app/Filters/Auth.php的类必须是class Auth extends Filter,且命名空间为App\Filters;CI4 不支持短名自动解析,'filter' => 'auth'对应的是类名小写形式,不是文件名 - HTTP 方法限制冲突:若过滤器
before()方法里写了if ($request->getMethod() !== 'POST') return $response;,却用 GET 访问受保护路由,就会静默跳过——没有报错,但也不执行后续逻辑
如何让一个过滤器只对 API 路由生效
Web 页面和 API 接口常需不同鉴权策略,比如 Session 登录 vs Token 验证。不能靠“在控制器里 if 判断”,而应利用 CI4 的路由分组 + 过滤器组合能力。
- 在
app/Config/Filters.php中定义两个过滤器:一个'jwt-auth'(用于 API),一个'session-auth'(用于后台) - 在
Routes.php中用分组隔离:$routes->group('api', ['namespace' => 'App\Controllers\Api', 'filter' => 'jwt-auth'], function($routes) { $routes->post('login', 'Auth::login'); $routes->get('users', 'User::index'); }); - 注意:分组的
filter键值会覆盖全局globals设置,但不会影响其他分组——这是实现差异鉴权最干净的方式 - 避免在过滤器里硬编码路径前缀(如
str_starts_with($request->getUri(), '/api/')),CI4 的路由分组机制就是为此设计的
真正容易被忽略的点是:过滤器的 before() 返回 $response 时,CI4 会立即终止流程并输出响应;但如果你忘了 return,比如只写了 $response->setStatusCode(401) 却没 return $response,控制器仍会继续执行——这种漏掉 return 的 bug 很难 debug,因为 HTTP 状态码看似变了,但页面还是正常渲染了。


















