# 过滤器
过滤器是 [控制器 动作](http://www.yiichina.com/doc/guide/2.0/structure-controllers#actions) 执行之前或之后执行的对象。 例如访问控制过滤器可在动作执行之前来控制特殊终端用户是否有权限执行动作, 内容压缩过滤器可在动作执行之后发给终端用户之前压缩响应内容。
过滤器可包含 预过滤(过滤逻辑在动作*之前*) 或 后过滤(过滤逻辑在动作*之后*),也可同时包含两者。
## 使用过滤器
过滤器本质上是一类特殊的 [行为](http://www.yiichina.com/doc/guide/2.0/concept-behaviors),所以使用过滤器和 [使用 行为](http://www.yiichina.com/doc/guide/2.0/concept-behaviors#attaching-behaviors)一样。 可以在控制器类中覆盖它的 yii\base\Controller::behaviors() 方法来申明过滤器,如下所示:
~~~
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index', 'view'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('user')->max('updated_at');
},
],
];
}
~~~
控制器类的过滤器默认应用到该类的 *所有* 动作,你可以配置yii\base\ActionFilter::only属性明确指定控制器应用到哪些动作。 在上述例子中,`HttpCache` 过滤器只应用到`index`和`view`动作。 也可以配置yii\base\ActionFilter::except属性使一些动作不执行过滤器。
除了控制器外,可在 [模块](http://www.yiichina.com/doc/guide/2.0/structure-modules)或[应用主体](http://www.yiichina.com/doc/guide/2.0/structure-applications) 中申明过滤器。 申明之后,过滤器会应用到所属该模块或应用主体的 *所有* 控制器动作, 除非像上述一样配置过滤器的 yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 属性。
> 补充: 在模块或应用主体中申明过滤器,在yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 属性中使用[路由](http://www.yiichina.com/doc/guide/2.0/structure-controllers#routes) 代替动作ID, 因为在模块或应用主体中只用动作ID并不能唯一指定到具体动作。.
当一个动作有多个过滤器时,根据以下规则先后执行:
* 预过滤
* 按顺序执行应用主体中`behaviors()`列出的过滤器。
* 按顺序执行模块中`behaviors()`列出的过滤器。
* 按顺序执行控制器中`behaviors()`列出的过滤器。
* 如果任意过滤器终止动作执行,后面的过滤器(包括预过滤和后过滤)不再执行。
* 成功通过预过滤后执行动作。
* 后过滤
* 倒序执行控制器中`behaviors()`列出的过滤器。
* 倒序执行模块中`behaviors()`列出的过滤器。
* 倒序执行应用主体中`behaviors()`列出的过滤器。
## 创建过滤器
继承 yii\base\ActionFilter 类并覆盖 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法来创建动作的过滤器,前者在动作执行之前执行,后者在动作执行之后执行。 yii\base\ActionFilter::beforeAction() 返回值决定动作是否应该执行, 如果为false,之后的过滤器和动作不会继续执行。
下面的例子申明一个记录动作执行时间日志的过滤器。
~~~
namespace app\components;
use Yii;
use yii\base\ActionFilter;
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提供了一组常用过滤器,在`yii\filters`命名空间下,接下来我们简要介绍这些过滤器。
### yii\filters\AccessControl
AccessControl提供基于yii\filters\AccessControl::rules规则的访问控制。 特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则, 来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。
如下示例表示表示允许已认证用户访问`create` 和 `update` 动作,拒绝其他用户访问这两个动作。
~~~
use yii\filters\AccessControl;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update'],
'rules' => [
// 允许认证用户
[
'allow' => true,
'roles' => ['@'],
],
// 默认禁止其他用户
],
],
];
}
~~~
更多关于访问控制的详情请参阅 [授权](http://www.yiichina.com/doc/guide/2.0/security-authorization) 一节。
### 认证方法过滤器
认证方法过滤器通过[HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication)或[OAuth 2](http://oauth.net/2/) 来认证一个用户,认证方法过滤器类在 `yii\filters\auth` 命名空间下。
如下示例表示可使用yii\filters\auth\HttpBasicAuth来认证一个用户,它使用基于HTTP基础认证方法的令牌。 注意为了可运行,yii\web\User::identityClass 类必须 实现 yii\web\IdentityInterface::findIdentityByAccessToken()方法。
~~~
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
return [
'basicAuth' => [
'class' => HttpBasicAuth::className(),
],
];
}
~~~
认证方法过滤器通常在实现RESTful API中使用,更多关于访问控制的详情请参阅 RESTful [认证](http://www.yiichina.com/doc/guide/2.0/rest-authentication) 一节。
### yii\filters\ContentNegotiator
ContentNegotiator支持响应内容格式处理和语言处理。 通过检查 `GET` 参数和 `Accept` HTTP头部来决定响应内容格式和语言。
如下示例,配置ContentNegotiator支持JSON和XML响应格式和英语(美国)和德语。
~~~
use yii\filters\ContentNegotiator;
use yii\web\Response;
public function behaviors()
{
return [
[
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON,
'application/xml' => Response::FORMAT_XML,
],
'languages' => [
'en-US',
'de',
],
],
];
}
~~~
在[应用主体生命周期](http://www.yiichina.com/doc/guide/2.0/structure-applications#application-lifecycle)过程中检测响应格式和语言简单很多, 因此ContentNegotiator设计可被[引导启动组件](http://www.yiichina.com/doc/guide/2.0/structure-applications#bootstrap)调用的过滤器。 如下例所示可以将它配置在[应用主体配置](http://www.yiichina.com/doc/guide/2.0/structure-applications#application-configurations)。
~~~
use yii\filters\ContentNegotiator;
use yii\web\Response;
[
'bootstrap' => [
[
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON,
'application/xml' => Response::FORMAT_XML,
],
'languages' => [
'en-US',
'de',
],
],
],
];
~~~
> 补充: 如果请求中没有检测到内容格式和语言,使用formats和languages第一个配置项。
### yii\filters\HttpCache
HttpCache利用`Last-Modified` 和 `Etag` HTTP头实现客户端缓存。例如:
~~~
use yii\filters\HttpCache;
public function behaviors()
{
return [
[
'class' => HttpCache::className(),
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('user')->max('updated_at');
},
],
];
}
~~~
更多关于使用HttpCache详情请参阅 [HTTP 缓存](http://www.yiichina.com/doc/guide/2.0/caching-http) 一节。
### yii\filters\PageCache
PageCache实现服务器端整个页面的缓存。如下示例所示,PageCache应用在`index`动作, 缓存整个页面60秒或`post`表的记录数发生变化。它也会根据不同应用语言保存不同的页面版本。
~~~
use yii\filters\PageCache;
use yii\caching\DbDependency;
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,
]
],
];
}
~~~
更多关于使用PageCache详情请参阅 [页面缓存](http://www.yiichina.com/doc/guide/2.0/caching-page) 一节。
### yii\filters\RateLimiter
RateLimiter 根据 [漏桶算法](http://en.wikipedia.org/wiki/Leaky_bucket) 来实现速率限制。 主要用在实现RESTful APIs,更多关于该过滤器详情请参阅 [Rate Limiting](http://www.yiichina.com/doc/guide/2.0/rest-rate-limiting) 一节。
### yii\filters\VerbFilter
VerbFilter检查请求动作的HTTP请求方式是否允许执行,如果不允许,会抛出HTTP 405异常。 如下示例,VerbFilter指定CRUD动作所允许的请求方式。
~~~
use yii\filters\VerbFilter;
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index' => ['get'],
'view' => ['get'],
'create' => ['get', 'post'],
'update' => ['get', 'put', 'post'],
'delete' => ['post', 'delete'],
],
],
];
}
~~~
### yii\filters\Cors
跨域资源共享 [CORS](https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS) 机制允许一个网页的许多资源(例如字体、JavaScript等) 这些资源可以通过其他域名访问获取。 特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,由于同源安全策略该跨域请求会被网页浏览器禁止. CORS定义浏览器和服务器交互时哪些跨域请求允许和禁止。
yii\filters\Cors 应在 授权 / 认证 过滤器之前定义,以保证CORS头部被发送。
~~~
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
],
], parent::behaviors());
}
~~~
Cors 可转为使用 `cors` 属性。
* `cors['Origin']`: 定义允许来源的数组,可为`['*']` (任何用户) 或 `['http://www.myserver.net', 'http://www.myotherserver.com']`. 默认为 `['*']`.
* `cors['Access-Control-Request-Method']`: 允许动作数组如 `['GET', 'OPTIONS', 'HEAD']`. 默认为 `['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']`.
* `cors['Access-Control-Request-Headers']`: 允许请求头部数组,可为 `['*']` 所有类型头部 或 `['X-Request-With']` 指定类型头部. 默认为 `['*']`.
* `cors['Access-Control-Allow-Credentials']`: 定义当前请求是否使用证书,可为 `true`, `false` 或 `null` (不设置). 默认为`null`.
* `cors['Access-Control-Max-Age']`: 定义请求的有效时间,默认为 `86400`.
例如,允许来源为 `http://www.myserver.net` 和方式为 `GET`, `HEAD` 和 `OPTIONS` 的CORS如下:
~~~
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
'cors' => [
'Origin' => ['http://www.myserver.net'],
'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
],
],
], parent::behaviors());
}
~~~
可以覆盖默认参数为每个动作调整CORS 头部。例如,为`login`动作增加`Access-Control-Allow-Credentials`参数如下所示:
~~~
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
'cors' => [
'Origin' => ['http://www.myserver.net'],
'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
],
'actions' => [
'login' => [
'Access-Control-Allow-Credentials' => true,
]
]
],
], parent::behaviors());
}
~~~
- 介绍(Introduction)
- 关于 Yii(About Yii)
- 从 Yii 1.1 升级(Upgrading from Version 1.1)
- 入门(Getting Started)
- 安装 Yii(Installing Yii)
- 运行应用(Running Applications)
- 第一次问候(Saying Hello)
- 使用 Forms(Working with Forms)
- 玩转 Databases(Working with Databases)
- 用 Gii 生成代码(Generating Code with Gii)
- 更上一层楼(Looking Ahead)
- 应用结构(Application Structure)
- 结构概述(Overview)
- 入口脚本(Entry Scripts)
- 应用(Applications)
- 应用组件(Application Components)
- 控制器(Controllers)
- 模型(Models)
- 视图(Views)
- 模块(Modules)
- 过滤器(Filters)
- 小部件(Widgets)
- 前端资源(Assets)
- 扩展(Extensions)
- 请求处理(Handling Requests)
- 运行概述(Overview)
- 引导(Bootstrapping)
- 路由引导与创建 URL(Routing and URL Creation)
- 请求(Requests)
- 响应(Responses)
- Sessions and Cookies
- 错误处理(Handling Errors)
- 日志(Logging)
- 关键概念(Key Concepts)
- 组件(Components)
- 属性(Properties)
- 事件(Events)
- 行为(Behaviors)
- 配置(Configurations)
- 别名(Aliases)
- 类自动加载(Class Autoloading)
- 服务定位器(Service Locator)
- 依赖注入容器(Dependency Injection Container)
- 配合数据库工作(Working with Databases)
- 数据库访问(Data Access Objects): 数据库连接、基本查询、事务和模式操作
- 查询生成器(Query Builder): 使用简单抽象层查询数据库
- 活动记录(Active Record): 活动记录对象关系映射(ORM),检索和操作记录、定义关联关系
- 数据库迁移(Migrations): 在团体开发中对你的数据库使用版本控制
- Sphinx
- Redis
- MongoDB
- ElasticSearch
- 接收用户数据(Getting Data from Users)
- 创建表单(Creating Forms)
- 输入验证(Validating Input)
- 文件上传(Uploading Files)
- 收集列表输入(Collecting Tabular Input)
- 多模型同时输入(Getting Data for Multiple Models)
- 显示数据(Displaying Data)
- 格式化输出数据(Data Formatting)
- 分页(Pagination)
- 排序(Sorting)
- 数据提供器(Data Providers)
- 数据小部件(Data Widgets)
- 操作客户端脚本(Working with Client Scripts)
- 主题(Theming)
- 安全(Security)
- 认证(Authentication)
- 授权(Authorization)
- 处理密码(Working with Passwords)
- 客户端认证(Auth Clients)
- 安全领域的最佳实践(Best Practices)
- 缓存(Caching)
- 概述(Overview)
- 数据缓存(Data Caching)
- 片段缓存(Fragment Caching)
- 分页缓存(Page Caching)
- HTTP 缓存(HTTP Caching)
- RESTful Web 服务
- 快速入门(Quick Start)
- 资源(Resources)
- 控制器(Controllers)
- 路由(Routing)
- 格式化响应(Response Formatting)
- 授权验证(Authentication)
- 速率限制(Rate Limiting)
- 版本化(Versioning)
- 错误处理(Error Handling)
- 开发工具(Development Tools)
- 调试工具栏和调试器(Debug Toolbar and Debugger)
- 使用 Gii 生成代码(Generating Code using Gii)
- TBD 生成 API 文档(Generating API Documentation)
- 测试(Testing)
- 概述(Overview)
- 搭建测试环境(Testing environment setup)
- 单元测试(Unit Tests)
- 功能测试(Functional Tests)
- 验收测试(Acceptance Tests)
- 测试夹具(Fixtures)
- 高级专题(Special Topics)
- 高级应用模版(Advanced Project Template)
- 从头构建自定义模版(Building Application from Scratch)
- 控制台命令(Console Commands)
- 核心验证器(Core Validators)
- 国际化(Internationalization)
- 收发邮件(Mailing)
- 性能优化(Performance Tuning)
- 共享主机环境(Shared Hosting Environment)
- 模板引擎(Template Engines)
- 集成第三方代码(Working with Third-Party Code)
- 小部件(Widgets)
- Bootstrap 小部件(Bootstrap Widgets)
- jQuery UI 小部件(jQuery UI Widgets)
- 助手类(Helpers)
- 助手一览(Overview)
- Array 助手(ArrayHelper)
- Html 助手(Html)
- Url 助手(Url)