過濾器(Filters)

2018-02-24 15:40 更新

過濾器

過濾器是?控制器 動作?執(zhí)行之前或之后執(zhí)行的對象。 例如訪問控制過濾器可在動作執(zhí)行之前來控制特殊終端用戶是否有權(quán)限執(zhí)行動作, 內(nèi)容壓縮過濾器可在動作執(zhí)行之后發(fā)給終端用戶之前壓縮響應(yīng)內(nèi)容。

過濾器可包含 預(yù)過濾(過濾邏輯在動作之前) 或 后過濾(過濾邏輯在動作之后),也可同時包含兩者。

使用過濾器

過濾器本質(zhì)上是一類特殊的?行為,所以使用過濾器和?使用 行為一樣。 可以在控制器類中覆蓋它的 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');
            },
        ],
    ];
}

控制器類的過濾器默認應(yīng)用到該類的?所有?動作,你可以配置yii\base\ActionFilter::only屬性明確指定控制器應(yīng)用到哪些動作。 在上述例子中,HttpCache?過濾器只應(yīng)用到indexview動作。 也可以配置yii\base\ActionFilter::except屬性使一些動作不執(zhí)行過濾器。

除了控制器外,可在?模塊應(yīng)用主體?中申明過濾器。 申明之后,過濾器會應(yīng)用到所屬該模塊或應(yīng)用主體的?所有?控制器動作, 除非像上述一樣配置過濾器的 yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性。

補充: 在模塊或應(yīng)用主體中申明過濾器,在yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性中使用路由?代替動作ID, 因為在模塊或應(yīng)用主體中只用動作ID并不能唯一指定到具體動作。.

當一個動作有多個過濾器時,根據(jù)以下規(guī)則先后執(zhí)行:

  • 預(yù)過濾
    • 按順序執(zhí)行應(yīng)用主體中behaviors()列出的過濾器。
    • 按順序執(zhí)行模塊中behaviors()列出的過濾器。
    • 按順序執(zhí)行控制器中behaviors()列出的過濾器。
    • 如果任意過濾器終止動作執(zhí)行,后面的過濾器(包括預(yù)過濾和后過濾)不再執(zhí)行。
  • 成功通過預(yù)過濾后執(zhí)行動作。
  • 后過濾
    • 倒序執(zhí)行控制器中behaviors()列出的過濾器。
    • 倒序執(zhí)行模塊中behaviors()列出的過濾器。
    • 倒序執(zhí)行應(yīng)用主體中behaviors()列出的過濾器。

創(chuàng)建過濾器

繼承 yii\base\ActionFilter 類并覆蓋 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法來創(chuàng)建動作的過濾器,前者在動作執(zhí)行之前執(zhí)行,后者在動作執(zhí)行之后執(zhí)行。 yii\base\ActionFilter::beforeAction() 返回值決定動作是否應(yīng)該執(zhí)行, 如果為false,之后的過濾器和動作不會繼續(xù)執(zhí)行。

下面的例子申明一個記錄動作執(zhí)行時間日志的過濾器。

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規(guī)則的訪問控制。 特別是在動作執(zhí)行之前,訪問控制會檢測所有規(guī)則并找到第一個符合上下文的變量(比如用戶IP地址、登錄狀態(tài)等等)的規(guī)則, 來決定允許還是拒絕請求動作的執(zhí)行,如果沒有規(guī)則符合,訪問就會被拒絕。

如下示例表示表示允許已認證用戶訪問create?和?update?動作,拒絕其他用戶訪問這兩個動作。

use yii\filters\AccessControl;

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['create', 'update'],
            'rules' => [
                // 允許認證用戶
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // 默認禁止其他用戶
            ],
        ],
    ];
}

更多關(guān)于訪問控制的詳情請參閱?授權(quán)?一節(jié)。

認證方法過濾器

認證方法過濾器通過HTTP Basic AuthOAuth 2?來認證一個用戶,認證方法過濾器類在?yii\filters\auth?命名空間下。

如下示例表示可使用yii\filters\auth\HttpBasicAuth來認證一個用戶,它使用基于HTTP基礎(chǔ)認證方法的令牌。 注意為了可運行,yii\web\User::identityClass 類必須 實現(xiàn) yii\web\IdentityInterface::findIdentityByAccessToken()方法。

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    return [
        'basicAuth' => [
            'class' => HttpBasicAuth::className(),
        ],
    ];
}

認證方法過濾器通常在實現(xiàn)RESTful API中使用,更多關(guān)于訪問控制的詳情請參閱 RESTful?認證?一節(jié)。

yii\filters\ContentNegotiator

ContentNegotiator支持響應(yīng)內(nèi)容格式處理和語言處理。 通過檢查?GET?參數(shù)和?Accept?HTTP頭部來決定響應(yīng)內(nèi)容格式和語言。

如下示例,配置ContentNegotiator支持JSON和XML響應(yīng)格式和英語(美國)和德語。

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',
            ],
        ],
    ];
}

應(yīng)用主體生命周期過程中檢測響應(yīng)格式和語言簡單很多, 因此ContentNegotiator設(shè)計可被引導(dǎo)啟動組件調(diào)用的過濾器。 如下例所示可以將它配置在應(yīng)用主體配置

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',
            ],
        ],
    ],
];

補充: 如果請求中沒有檢測到內(nèi)容格式和語言,使用formats和languages第一個配置項。

yii\filters\HttpCache

HttpCache利用Last-Modified?和?Etag?HTTP頭實現(xiàn)客戶端緩存。例如:

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');
            },
        ],
    ];
}

更多關(guān)于使用HttpCache詳情請參閱?HTTP 緩存?一節(jié)。

yii\filters\PageCache

PageCache實現(xiàn)服務(wù)器端整個頁面的緩存。如下示例所示,PageCache應(yīng)用在index動作, 緩存整個頁面60秒或post表的記錄數(shù)發(fā)生變化。它也會根據(jù)不同應(yīng)用語言保存不同的頁面版本。

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,
            ]
        ],
    ];
}

更多關(guān)于使用PageCache詳情請參閱?頁面緩存?一節(jié)。

yii\filters\RateLimiter

RateLimiter 根據(jù)?漏桶算法?來實現(xiàn)速率限制。 主要用在實現(xiàn)RESTful APIs,更多關(guān)于該過濾器詳情請參閱?Rate Limiting?一節(jié)。

yii\filters\VerbFilter

VerbFilter檢查請求動作的HTTP請求方式是否允許執(zhí)行,如果不允許,會拋出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?機制允許一個網(wǎng)頁的許多資源(例如字體、JavaScript等) 這些資源可以通過其他域名訪問獲取。 特別是JavaScript's AJAX 調(diào)用可使用 XMLHttpRequest 機制,由于同源安全策略該跨域請求會被網(wǎng)頁瀏覽器禁止. CORS定義瀏覽器和服務(wù)器交互時哪些跨域請求允許和禁止。

yii\filters\Cors 應(yīng)在 授權(quán) / 認證 過濾器之前定義,以保證CORS頭部被發(fā)送。

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::className(),
        ],
    ], parent::behaviors());
}

Cors 可轉(zhuǎn)為使用?cors?屬性。

  • cors['Origin']: 定義允許來源的數(shù)組,可為['*']?(任何用戶) 或?['http://www.myserver.net', 'http://www.myotherserver.com']. 默認為?['*'].
  • cors['Access-Control-Request-Method']: 允許動作數(shù)組如?['GET', 'OPTIONS', 'HEAD']. 默認為?['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].
  • cors['Access-Control-Request-Headers']: 允許請求頭部數(shù)組,可為?['*']?所有類型頭部 或?['X-Request-With']?指定類型頭部. 默認為?['*'].
  • cors['Access-Control-Allow-Credentials']: 定義當前請求是否使用證書,可為?true,?false?或?null?(不設(shè)置). 默認為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());
}

可以覆蓋默認參數(shù)為每個動作調(diào)整CORS 頭部。例如,為login動作增加Access-Control-Allow-Credentials參數(shù)如下所示:

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());
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號