# 過濾器
過濾器是?[控制器 動作](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)