阿江 2017-10-08 17:04:29 3898次浏览 3条回复 3 0 0

说明

学习Yii Framework 2易2框架的过程是漫长的也是充满乐趣的以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现提供了较完整的代码供你参考不妥之处请多多指正

原文网址:

http://www.yiiframework.com/doc-2.0/guide-structure-filters.html

本文主题:过滤器(Filters)

过滤器是在控制器动作之前或之后运行的对象。举例来说,一个权限控制器可以在动作运行之前执行,以确保该动作可以被允许的用户所访问;一个内容压缩过滤器可以在动作运行之后运行,这样可以在发送到终端用户之前将内容进行压缩操作。 一个过滤器可以同时由pre-filter(前置过滤器,过滤逻辑应用于动作之前)和post-filter(后置过滤器,过滤逻辑应用于动作之后)共同组成。

1、Using Filters(使用过滤器)

过滤器本质上是一种特殊的behaviors。所以,使用过滤器和使用行为的方法是相同的,你可以在一个控制器类中重写它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');
            },
        ],
    ];
}

默认情况下,过滤器在控制器类中定义,它将应用到该控制器的所有动作。你也可以使用only属性显式定义某个过滤器仅适用于哪些动作。在上例中,HttpCache过滤器只适用于index和view动作。你也可以配置except属性列出不适用此过滤器的动作。

除了在控制器中,你还可以在模块或应用中声明过滤器。当你这样做时,此过滤器将应用于模块或应用下的所有控制器的所有动作,除非你为其配置了only和except属性。

注意:当在模块或应用中声明过滤器时,你应在only和except属性中使用routes,而不是动作ID。这是因为在模块或应用范围内,动作ID描述的不完整。

当为一个动作配置了多个过滤器时,它们的应用规则如下: 1、Pre-filtering(前置过滤器): 1)执行在应用的behaviors()中定义的过滤器,列出顺序就是它们的执行顺序。 2)执行在模块的behaviors()中定义的过滤器,列出顺序就是它们的执行顺序。 3)执行在控制器的behaviors()中定义的过滤器,列出顺序就是它们的执行顺序。 4)如果任何一个过滤器取消了动作的执行,它之后的过滤器(包括前置和后置)将不再被执行。 2、如果通过前置过滤器,则运行此动作 3、Post-filtering(后置过滤器) 1)执行在控制器的behaviors()中定义的过滤器,列出顺序的反序就是它们的执行顺序。 2)执行在模块的behaviors()中定义的过滤器,列出顺序的反序就是它们的执行顺序。 3)执行在应用的behaviors()中定义的过滤器,列出顺序的反序就是它们的执行顺序。

2、Creating Filters(创建过滤器)

要创建一个新的动作过滤器,应继承自yii\base\ActionFilter,并重写beforeAction()和afterAction()方法。前者将在动作运行之前被执行,而后者将在动作运行之后被执行。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);
	}
}
3、Core Filters(核心过滤器)

Yii提供了一系列通用过滤器,主要构建在yii\filters命名空间下,接下来,我们将主要介绍这些过滤器。

AccessControl Authentication Method Filters ContentNegotiator HttpCache PageCache RateLimiter VerbFilter Cors

AccessControl(访问控制)

AccessControl提供了基于一套规则的简单访问控制,实际上,在一个动作执行之前,AccessControl将检查列出的规则,以查找出符合当前环境变量的(如用户IP地址、用户登录状态等),匹配的规则将决定是放行或拒绝请求动作的执行。如果没有规则匹配,则访问将被拒绝。

下例将展示如何允许认证用户访问create和update动作,但对其他用户拒绝访问这两个方法:

use yii\filters\AccessControl;
public function behaviors(){
	return [
		'access'=>[
			'class'=>AccessControl::className(),
			'only'=>['access','update'],
			'rules'=>[
				//允许认证用户访问
				[
					'allow'=>true,
					'roles'=>['@'],
				],
				//默认情况下其他人都将被拒绝访问
			],
		],
	];
}

关于访问控制的详细信息,请参考Authorization章节: http://www.yiiframework.com/doc-2.0/guide-security-authorization.html

Authentication Method Filters(授权方法过滤器)

授权方法过滤器用于使用不同的方法授权一个用户,例如HTTP Basic Auth,OAuth2 。此过滤器类在yii\filters\auth命名空间下。

下例展示了如何使用yii\filters\auth\HttpBasicAuth授权一个用户使用基于HTTP Basic Auth方法获取访问令牌。注意要让这段代码正常工作,需要在user标识类中实现findIdentityByAccessToken()方法。

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

授权方法过滤器通常用于实现RESTful API,更多细节请参考RESTful的Authentication章节: http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html

ContentNegotiator(内容协商)

ContentNegotiator支持响应格式协商和语言协商。它将通过检查GET参数和Accept HTTP头令牌去决定响应格式和语言。 在下例中,配置的内容协商将支持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'=>FORMAT_XML,
			],
			'language'=>[
				'en-US',
				'de',
			],
		],
	];
}

响应格式和语言通常需要在应用生命周期中更早的被决定下来,因为这个原因,ContentNegotiator更应被设计为一个启动组件(bootstrapping component)而不是一个过滤器,你可以在应用配置中如下设置:

[
	'bootstrap'	=>[
		[
			'class'=>'yii\filters\ContentNegotiator',
			'formats'=>[
				'application/json'=>yii\web\Response::FORMAT_JSON,
				'application/xml'=>yii\web\Response::FOMAT_XML,
			],
			'language'=>[
				'en-US',
				'de',
			],
		],
	],
];

信息:首选的内容类型和语言如果不能从请求中确定,那么在格式和语言设置中的第一项将被使用。

HttpCache(Http缓存)

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 Caching章节: http://www.yiiframework.com/doc-2.0/guide-caching-http.html

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的使用详情请参考Page Caching章节: http://www.yiiframework.com/doc-2.0/guide-caching-page.html

RateLimiter(频率限制器)

频率限制器基于Leaky bucket算法(漏桶算法)实现了频率限制。它主要用于实现RESTful API,关于这个过滤器的使用详情请参考Rate Limiting章节: http://www.yiiframework.com/doc-2.0/guide-rest-rate-limiting.html

VerbFilter(动词过滤器)

VerbFilter检查HTTP请求方法是否使用的是允许的动作。如果是非允许的,它将抛出一个HTTP405异常,在下例中,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'],
			],
		],
	];	
}
Cors(跨站资源共享)

Cors(Cross-origin resource sharing,跨域资源共享)是允许外域访问资源域网页资源的一种机制。特别是JavaScript的AJAX调用可以使用XMLHttpRequest的机制。根据同源安装策略,这样的跨域(cross-domain)请求将被浏览器禁止。CORS在浏览器与服务器之间定义了一个方法,交互决定是否允许此跨域请求。

Cors过滤器将在Authentication/Authorization过滤器之前定义,以确保CORS头信息会始终被发送出去:

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

在你的API中如果你想要添加CORS过滤器到yii\rest\ActiveController类中,请参阅REST Controllers章节: http://www.yiiframework.com/doc-2.0/guide-rest-controllers.html#cors

Cors过滤器可以使用$cors 属性进行调节: 1、cors['Origin']:定义允许源的数组,可以是'*'或['http://www.myserver.net','http://www.myotherserver.com'],默认值为['*'] 2、cors['Access-Control-Request-Method']:允许动词的数组,如['GET','OPTIONS','HEAD']。默认值是['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']。 3、cors['Access-Control-Request-Headers']:允许头信息的数组。可以是['*'](所有头)或定义一个['X-Request-With'],默认值是['*']。 4、cors['Access-Control-Allow-Credentials']:定义当前请求是否使用了证书,可以是true,false或null(没有设置),默认值为 null。 5、cors['Access-Control-Max-Age']:定义请求准备的时长,默认值是86400。

例如,允许CORS使用GET,HEAD和OPTIONS方法调用http://www.myserver.net:

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-Reuqest-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());
}

(全文完)

  • 回复于 2017-10-19 14:18 举报

    写的很好,谢谢

  • 回复于 2018-01-27 13:47 举报

    阿瓦达无多

  • 回复于 2018-08-30 21:18 举报

    过滤器的afterAction怎么接受controller里action执行完的某个值。

    1 条回复
    回复于 2018-08-31 06:57 回复

    在controller定义一个公共属性就可以啊,public $value='',在action中将某个值放到$value中,在afterAction中使用$this->value调用即可。

您需要登录后才可以回复。登录 | 立即注册