Yii过滤器写在控制器的behaviors()方法中,通过返回配置数组声明AccessControl等内置或自定义行为,核心拦截逻辑在beforeAction()中实现并必须显式return false终止请求。

Yii 过滤器写在哪?控制器里直接定义 behaviors()
Yii 的请求拦截逻辑不是靠单独的“过滤器类”文件驱动,而是通过控制器的 behaviors() 方法返回配置数组来声明。你不需要新建一个“Filter.php”,直接在控制器里写就行。
常见错误是试图继承 yii\base\ActionFilter 后手动挂载——这可行但绕远路;官方推荐路径就是行为(Behavior)方式,更轻量、更贴近实际权限/日志等场景。
-
behaviors()必须是 public 方法,返回关联数组,键是行为名(如'access'),值是配置(数组或对象) - 内置常用过滤器如
AccessControl、VerbFilter、ContentNegotiator都走这条路 - 自定义逻辑可写成匿名函数(适合简单判断),或独立类(需继承
ActionFilter并实现beforeAction())
beforeAction() 里 return false 就能中断请求
所有 ActionFilter 类型的行为,核心拦截点都在 beforeAction()。只要它返回 false,后续 action 就不会执行,且默认不抛异常、不自动跳转——这点和 Laravel 的 middleware 逻辑不同,容易误以为“没生效”。
典型场景:登录态校验失败时想跳转到登录页,得手动写 $this->redirect()->send() 再 return false;否则只是静默终止,浏览器可能卡在空白页或 404。
- 必须显式
return false,仅 throw Exception 不会阻止 action 执行(除非全局异常处理器介入) -
beforeAction()接收$action参数,可用于判断当前路由、方法名、是否是 AJAX 请求等 - 如果用了多个行为,它们按
behaviors()数组顺序依次执行beforeAction(),任一返回false即终止链
用 AccessControl 做权限控制,别手写 if 判断
90% 的登录/角色/IP 拦截需求,直接配 AccessControl 就够了,不用自己写 beforeAction() 逻辑。它底层也是 ActionFilter,但封装了规则匹配、用户状态检查、跳转逻辑。
容易踩的坑是规则顺序写反:规则按数组下标从前到后匹配,'allow' => true 的规则一旦命中就结束匹配,后面规则失效。所以通常要把精确规则(如特定 action ID)放前面,宽泛规则(如 'actions' => ['*'])放后面。
- 配置中
'rules'是数组,每项含allow、actions、roles、ips等键 -
roles用['?']表示游客,['@']表示登录用户,['admin']对应authManager中的角色名 - 没匹配到任何规则时,默认拒绝(
deny),无需额外写兜底
自定义过滤器类要继承 ActionFilter,且注意作用域
真需要复用复杂逻辑(比如统一埋点、请求体解密、灰度路由),才值得写独立类。这时必须继承 yii\base\ActionFilter,并在 beforeAction() 里写核心逻辑。
关键细节:过滤器实例在每次请求中只创建一次,但 beforeAction() 会被每个匹配的 action 调用一次。如果你在里面做单例缓存或静态变量累加,要注意作用域是否跨 action —— 大多数时候不该跨。
- 类文件放在
@app/filters/下,命名如RequestLoggerFilter.php - 在
behaviors()中引用时,用完整命名空间:app\filters\RequestLoggerFilter::class - 若需传参(如指定日志级别),在 behaviors 配置里加
'level' => 'info',然后在构造函数或init()中读取
最常被忽略的是:过滤器只对 controller 中定义的 action 生效,对模块内嵌的 widget、REST API 的 ActiveController 子类、或者 console 应用完全无效——这些地方要用各自机制(如 beforeAction 重写、beforeValidate、console Bootstrap 类)。


















