yii2的behaviors()方法是对父类行为做增量调整,必须基于parent::behaviors()操作;直接return新数组会丢失verbfilter、contentnegotiator等关键内置行为,导致动词校验失效、内容协商崩溃、认证链断裂。

直接说结论:Yii2 的 behaviors() 方法不是“写死配置”,而是对父类默认行为做**增量调整**——删掉不需要的、替换不合适的、插入新逻辑,关键在“基于 parent::behaviors() 操作”,不是重写整个数组。
为什么不能直接 return 新数组?
因为 Yii2 内置控制器(如 yii\rest\ActiveController)的默认 behaviors() 已预置了 contentNegotiator、verbFilter、authenticator 等关键过滤器。全量覆盖会丢失这些,导致:
- HTTP 动词校验失效(比如 PUT /users/123 被允许,违反 REST 语义)
- 内容协商崩溃(
Accept: application/xml请求返回 HTML 或 500) - 认证链断裂(
Authorization头被忽略)
正确做法永远是先取父类结果,再修改:
public function behaviors()
{
$behaviors = parent::behaviors();
// 后续增删改都在 $behaviors 上操作
}
怎么安全禁用 CSRF 和强制 JSON?
REST 接口无 session,CSRF 验证不仅多余,还会拦截 POST/PUT 请求体为 JSON 的合法请求;同时必须拒绝非 JSON 输入和输出,否则前端收不到结构化错误。
常见错误现象:400 Bad Request 但响应体为空、Content-Type: application/json 请求被拒、错误提示是 HTML 页面而非 JSON。
实操要点:
- 用
unset($behaviors['csrf'])彻底移除 CSRF 行为(别只设'enableCsrfValidation' => false,那只是关校验,不删行为) - 重写
contentNegotiator,显式限定'formats' => ['application/json' => \yii\web\Response::FORMAT_JSON] - 保留
verbFilter(别 unset 它),它是保障POST /users、GET /users/123语义的关键
如何插入自定义 JWT 认证?
默认 authenticator 是空的或只支持 HTTP Basic,JWT 必须自己配。但顺序和例外规则极易出错。
关键点:
- 键名必须是
'authenticator',否则框架不识别为认证入口 -
'except' => ['options']是硬性要求,否则 CORS 预检(OPTIONS)因认证失败而卡住 - 不要用
'only'列白名单,容易漏掉HEAD或未来新增 action;except更安全 - 确保你的 JWT 类(如
\api\filters\JwtAuth)已注册为应用组件,且能从Authorization头正确提取 token
自定义行为类怎么挂到控制器?
行为类本身要继承 yii\base\Behavior,但挂载方式分静态和动态两种,生产环境只推荐静态(即重写 behaviors())。
例如日志行为 LogActionBehavior:
- 类里必须实现
events()方法,返回[Controller::EVENT_BEFORE_ACTION => 'beforeAction']这样的映射 - 在控制器中加一条:
$behaviors['log'] = LogActionBehavior::className();(注意键名别用数字索引,否则会被覆盖) - 如果行为需传参(如指定日志级别),写成数组:
['class' => LogActionBehavior::className(), 'level' => 'info']
最容易被忽略的是:行为类中的 $this->owner 在 beforeAction 时可能还未初始化完整模型,访问 $this->owner->id 之类属性前务必判空。











