0 关注者

过滤器

过滤器是在 控制器操作 前后运行的对象。例如,访问控制过滤器可以在操作之前运行,以确保允许特定最终用户访问这些操作;内容压缩过滤器可以在操作之后运行,以在将响应内容发送给最终用户之前压缩响应内容。

过滤器可能包含一个预过滤器(在操作之前 应用的过滤逻辑)和/或一个后过滤器(在操作之后 应用的逻辑)。

使用过滤器

过滤器本质上是一种特殊类型的 行为。因此,使用过滤器与 使用行为 相同。您可以在控制器类中通过重写其 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 过滤器仅应用于 indexview 操作。您还可以配置 except 属性以防止某些操作被过滤。

除了控制器之外,您还可以在 模块应用程序 中声明过滤器。当您这样做时,过滤器将应用于属于该模块或应用程序的所有控制器操作,除非您配置过滤器的 onlyexcept 属性,如上面所述。

注意:当在模块或应用程序中声明过滤器时,您应该使用 路由 而不是操作 ID 在 onlyexcept 属性中。这是因为操作 ID 无法完全指定模块或应用程序范围内的操作。

当为单个操作配置多个过滤器时,它们将根据下面描述的规则应用

  • 预过滤
    • 按照在behaviors()中列出的顺序应用在应用程序中声明的过滤器。
    • 按照在behaviors()中列出的顺序应用在模块中声明的过滤器。
    • 按照在behaviors()中列出的顺序应用在控制器中声明的过滤器。
    • 如果任何过滤器取消了操作执行,则其后的过滤器(包括预过滤器和后过滤器)将不会被应用。
  • 如果通过预过滤,则运行操作。
  • 后过滤
    • 按照在behaviors()中列出的反向顺序应用在控制器中声明的过滤器。
    • 按照在behaviors()中列出的反向顺序应用在模块中声明的过滤器。
    • 按照在behaviors()中列出的反向顺序应用在应用程序中声明的过滤器。

创建过滤器

要创建一个新的操作过滤器,请从 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::debug("Action '{$action->uniqueId}' spent $time second.");
        return parent::afterAction($action, $result);
    }
}

核心过滤器

Yii 提供了一组常用的过滤器,主要位于yii\filters命名空间下。在下面,我们将简要介绍这些过滤器。

AccessControl

AccessControl 基于一组 规则 提供简单的访问控制。特别地,在执行操作之前,AccessControl 将检查列出的规则,并找到第一个与当前上下文变量(如用户 IP 地址、用户登录状态等)匹配的规则。匹配的规则将决定是否允许或拒绝执行请求的操作。如果没有规则匹配,则将拒绝访问。

以下示例显示了如何允许经过身份验证的用户访问createupdate操作,同时禁止所有其他用户访问这两个操作。

use yii\filters\AccessControl;

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::class,
            'only' => ['create', 'update'],
            'rules' => [
                // allow authenticated users
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // everything else is denied by default
            ],
        ],
    ];
}

有关一般访问控制的更多详细信息,请参阅 授权 部分。

身份验证方法过滤器

身份验证方法过滤器用于使用各种方法对用户进行身份验证,例如 HTTP Basic AuthOAuth 2。这些过滤器类都在yii\filters\auth命名空间下。

以下示例显示了如何使用 yii\filters\auth\HttpBasicAuth 使用基于 HTTP Basic Auth 方法的访问令牌对用户进行身份验证。请注意,为了使此方法正常工作,您的 用户身份类 必须实现 findIdentityByAccessToken() 方法。

use yii\filters\auth\HttpBasicAuth;

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

身份验证方法过滤器通常用于实现 RESTful API。有关更多详细信息,请参阅 RESTful 身份验证 部分。

ContentNegotiator

ContentNegotiator 支持响应格式协商和应用程序语言协商。它将尝试通过检查GET参数和Accept HTTP 头来确定响应格式和/或语言。

在以下示例中,ContentNegotiator 配置为支持 JSON 和 XML 响应格式,以及英语(美国)和德语。

use yii\filters\ContentNegotiator;
use yii\web\Response;

public function behaviors()
{
    return [
        [
            'class' => ContentNegotiator::class,
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ];
}

响应格式和语言通常需要在 应用程序生命周期 中的更早阶段确定。出于这个原因,ContentNegotiator 的设计方式使其既可以用作过滤器,也可以用作 引导组件。例如,您可以在 应用程序配置 中对其进行配置,如下所示

use yii\filters\ContentNegotiator;
use yii\web\Response;

[
    'bootstrap' => [
        [
            'class' => ContentNegotiator::class,
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ],
];

信息:如果无法从请求中确定首选内容类型和语言,则将使用 formatslanguages 中列出的第一个格式和语言。

HttpCache

HttpCache 通过使用Last-ModifiedEtagHTTP 头来实现客户端缓存。例如,

use yii\filters\HttpCache;

public function behaviors()
{
    return [
        [
            'class' => HttpCache::class,
            'only' => ['index'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('user')->max('updated_at');
            },
        ],
    ];
}

有关使用 HttpCache 的更多详细信息,请参阅 HTTP 缓存 部分。

PageCache

PageCache 实现整个页面的服务器端缓存。在以下示例中,PageCache 应用于index操作,以将整个页面缓存最多 60 秒,或者直到post表中的条目数量发生变化。它还根据选择的应用程序语言存储页面的不同版本。

use yii\filters\PageCache;
use yii\caching\DbDependency;

public function behaviors()
{
    return [
        'pageCache' => [
            'class' => PageCache::class,
            'only' => ['index'],
            'duration' => 60,
            'dependency' => [
                'class' => DbDependency::class,
                'sql' => 'SELECT COUNT(*) FROM post',
            ],
            'variations' => [
                \Yii::$app->language,
            ]
        ],
    ];
}

有关使用 PageCache 的更多详细信息,请参阅 页面缓存 部分。

RateLimiter

RateLimiter 基于 漏桶算法 实现速率限制算法。它主要用于实现 RESTful API。有关使用此过滤器的详细信息,请参阅 速率限制 部分。

VerbFilter

VerbFilter 检查 HTTP 请求方法是否被请求的操作允许。如果不允许,它将抛出一个 HTTP 405 异常。在以下示例中,VerbFilter 声明为指定 CRUD 操作的典型允许请求方法集。

use yii\filters\VerbFilter;

public function behaviors()
{
    return [
        'verbs' => [
            'class' => VerbFilter::class,
            'actions' => [
                'index'  => ['get'],
                'view'   => ['get'],
                'create' => ['get', 'post'],
                'update' => ['get', 'put', 'post'],
                'delete' => ['post', 'delete'],
            ],
        ],
    ];
}

Cors

跨域资源共享 CORS 是一种机制,允许网页上的许多资源(例如字体、JavaScript 等)从资源来源域之外的另一个域进行请求。特别是,JavaScript 的 AJAX 调用可以使用 XMLHttpRequest 机制。否则,根据同源策略,此类“跨域”请求将被 Web 浏览器禁止。CORS 定义了一种浏览器和服务器可以交互的方式,以确定是否允许跨域请求。

Cors 过滤器 应该在身份验证/授权过滤器之前定义,以确保 CORS 头部始终被发送。

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

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

如果您想将 CORS 过滤器添加到 API 中的 yii\rest\ActiveController 类,请查看有关 REST 控制器 的部分。

可以使用 $cors 属性调整 CORS 过滤。

  • cors['Origin']:用于定义允许来源的数组。可以是['*'](所有人)或['https://www.myserver.net', 'https://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']:定义当前请求是否可以使用凭据。可以是truefalsenull(未设置)。默认值为null
  • cors['Access-Control-Max-Age']:定义预检请求的生存期。默认值为86400

例如,允许源为 https://www.myserver.net 的 CORS,方法为GETHEADOPTIONS

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

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::class,
            'cors' => [
                'Origin' => ['https://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::class,
            'cors' => [
                'Origin' => ['https://www.myserver.net'],
                'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
            ],
            'actions' => [
                'login' => [
                    'Access-Control-Allow-Credentials' => true,
                ]
            ]
        ],
    ], parent::behaviors());
}

发现错别字或您认为此页面需要改进?
在 github 上编辑它 !