过滤器是 控制器 动作 执行之前或之后执行的对象。 例如访问控制过滤器可在动作执行之前来控制特殊终端用户是否有权限执行动作, 内容压缩过滤器可在动作执行之后发给终端用户之前压缩响应内容。
过滤器可包含 预过滤(过滤逻辑在动作之前) 或 后过滤(过滤逻辑在动作之后),也可同时包含两者。
使用过滤器:
在控制管理器里覆盖 behaviors 方法就可以了。
public function behaviors(){ return [ [ 'class' => 'yiifiltersHttpCache', 'only' => ['index', 'view'], 'lastModified' => function ($action, $params) { $q = new yiidbQuery(); return $q->from('user')->max('updated_at'); }, ], ]; }
behavior默认应用到所有的操作,但是可以通过 only 属性设置只对那些操作起作用,也可以通过 except 属性说明哪些操作不经过过滤器。除了控制器外,可在 模块或应用主体 中申明过滤器。 申明之后,过滤器会应用到所属该模块或应用主体的 所有 控制器动作, 除非像上述一样配置过滤器的 [[yiiaseActionFilter::only|only]] 和 [[yiiaseActionFilter::except|except]] 属性。
当一个动作有多个过滤器时,根据以下规则先后执行:
预过滤
- 按顺序执行应用主体中behaviors()列出的过滤器。
- 按顺序执行模块中behaviors()列出的过滤器。
- 按顺序执行控制器中behaviors()列出的过滤器。
如果任意过滤器终止动作执行,后面的过滤器(包括预过滤和后过滤)不再执行。
成功通过预过滤后执行动作。后过滤器和预过滤的顺序正好是相反的,这就和html的标签一样,总是成对出现,并相互对应。
后过滤
- 倒序执行控制器中behaviors()列出的过滤器。
- 倒序执行模块中behaviors()列出的过滤器。
- 倒序执行应用主体中behaviors()列出的过滤器。
创建过滤器:
继承 [[yiiaseActionFilter]] 类并覆盖 [[yiiaseActionFilter::beforeAction()|beforeAction()]] 和/或 [[yiiaseActionFilter::afterAction()|afterAction()]] 方法来创建动作的过滤器,前者在动作执行之前执行,后者在动作执行之后执行。 [[yiiaseActionFilter::beforeAction()|beforeAction()]] 返回值决定动作是否应该执行, 如果为false,之后的过滤器和动作不会继续执行。
namespace appcomponents; use Yii; use yiiaseActionFilter; class ActionTimeFilter extends ActionFilter { private $_startTime; public function beforeAction($action) { $this->_startTime = microtime(true); return parent::beforeAction($action); } public function afterAction($action, $result) { $time = microtime(true) - $this->_startTime; Yii::trace("Action '{$action->uniqueId}' spent $time second."); return parent::afterAction($action, $result); } }
核心过滤器:
Yii提供了一组常用过滤器,在yiifilters命名空间下,接下来我们简要介绍这些过滤器。
1、[[yiifiltersAccessControl|AccessControl]]: 提供基于[[yiifiltersAccessControl::rules|rules]]规则的访问控制。 特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则, 来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。如下示例表示表示允许已认证用户访问create 和 update 动作,拒绝其他用户访问这两个动作。
use yiifiltersAccessControl; public function behaviors(){ return [ 'access' => [ 'class' => AccessControl::className(), 'only' => ['create', 'update'], 'rules' => [ // 允许认证用户 [ 'allow' => true, 'roles' => ['@'], ], // 默认禁止其他用户 ], ], ]; }
2、认证方法过滤器: 通过HTTP Basic Auth或OAuth 2 来认证一个用户,认证方法过滤器类在 yiifiltersauth 命名空间下。
如下示例表示可使用[[yiifiltersauthHttpBasicAuth]]来认证一个用户,它使用基于HTTP基础认证方法的令牌。 注意为了可运行,[[yiiwebUser::identityClass|user identity class]] 类必须 实现 [[yiiwebIdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]方法。
use yiifiltersauthHttpBasicAuth; public function behaviors(){ return [ 'basicAuth' => [ 'class' => HttpBasicAuth::className(), ], ]; }
3、[[yiifiltersContentNegotiator|ContentNegotiator]]:支持响应内容格式处理和语言处理。 通过检查 GET 参数和 Accept HTTP头部来决定响应内容格式和语言。如下示例,配置ContentNegotiator支持JSON和XML响应格式和英语(美国)和德语。
use yiifiltersContentNegotiator; use yiiwebResponse; public function behaviors(){ return [ [ 'class' => ContentNegotiator::className(), 'formats' => [ 'application/json' => Response::FORMAT_JSON, 'application/xml' => Response::FORMAT_XML, ], 'languages' => [ 'en-US', 'de', ], ], ]; }
4、[[yiifiltersHttpCache|HttpCache]]:利用Last-Modified 和 Etag HTTP头实现客户端缓存。例如:
use yiifiltersHttpCache; public function behaviors(){ return [ [ 'class' => HttpCache::className(), 'only' => ['index'], 'lastModified' => function ($action, $params) { $q = new yiidbQuery(); return $q->from('user')->max('updated_at'); }, ], ]; }
5、[[yiifiltersPageCache|PageCache]]:实现服务器端整个页面的缓存。如下示例所示,PageCache应用在index动作, 缓存整个页面60秒或post表的记录数发生变化。它也会根据不同应用语言保存不同的页面版本。
use yiifiltersPageCache; use yiicachingDbDependency; public function behaviors(){ return [ 'pageCache' => [ 'class' => PageCache::className(), 'only' => ['index'], 'duration' => 60, 'dependency' => [ 'class' => DbDependency::className(), 'sql' => 'SELECT COUNT(*) FROM post', ], 'variations' => [ Yii::$app->language, ] ], ]; }
6、[[yiifiltersRateLimiter|RateLimiter]]:根据 漏桶算法 来实现速率限制。 主要用在实现RESTful APIs
7、[[yiifiltersVerbFilter|VerbFilter]]:检查请求动作的HTTP请求方式是否允许执行,如果不允许,会抛出HTTP 405异常。 如下示例,VerbFilter指定CRUD动作所允许的请求方式。
use yiifiltersVerbFilter; public function behaviors(){ return [ 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'index' => ['get'], 'view' => ['get'], 'create' => ['get', 'post'], 'update' => ['get', 'put', 'post'], 'delete' => ['post', 'delete'], ], ], ]; }