yii\rest\Controller提供的大多數RESTful API功能通過過濾器實現. 特別是以下過濾器會按順序執行:
- yii\filters\ContentNegotiator: 支持內容協商。
- yii\filters\VerbFilter: 支持HTTP 方法驗證;
- yii\filters\AuthMethod: 支持用戶認證;
- yii\filters\RateLimiter: 支持頻率限制.
這些過濾器都在yii\rest\Controller::behaviors()方法中聲明。原本的聲明如下:
/**
* @inheritdoc
*/
public function behaviors()
{
return [
'contentNegotiator' => [
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON,
'application/xml' => Response::FORMAT_XML,
],
],
'verbFilter' => [
'class' => VerbFilter::className(),
'actions' => $this->verbs(),
],
'authenticator' => [
'class' => CompositeAuth::className(),
],
'rateLimiter' => [
'class' => RateLimiter::className(),
],
];
}
首先是yii\filters\ContentNegotiator過濾器,該過濾器是用於內容協商的,例如,
如果一個 RESTful API 請求中包含以下 header,
Accept: application/json; q=1.0, */*; q=0.1
將會得到JSON格式的響應,幕後,執行一個 RESTful API 控制器動作之前,yii\filters\ContentNegotiator filter 將檢查 HTTP header 在請求時和配置 yii\web\Response::format 爲 json。 之後的動作被執行並返回得到的資源對象或集合, yii\rest\Serializer 將結果轉換成一個數組。最後,yii\web\JsonResponseFormatter 該數組將序列化爲JSON字符串,並將其包括在響應主體。
之後將會執行yii\filters\VerbFilter,這一步是對動詞的過濾,參考yii\rest\ActiveController中的聲明:
/**
* @inheritdoc
*/
protected function verbs()
{
return [
'index' => ['GET', 'HEAD'],
'view' => ['GET', 'HEAD'],
'create' => ['POST'],
'update' => ['PUT', 'PATCH'],
'delete' => ['DELETE'],
];
}
所謂的動詞即是用戶發出的請求的類型,由此對應不同的操作。
然後是yii\filters\AuthMethod和Web應用不同,RESTful
APIs 通常是無狀態的,也就意味着不應使用sessions 或 cookies, 因此每個請求應附帶某種授權憑證,因爲用戶授權狀態可能沒通過sessions 或 cookies維護, 常用的做法是每個請求都發送一個祕密的access token來認證用戶,由於access token可以唯一識別和認證用戶。
最後是yii\filters\RateLimiter爲防止濫用,你應該考慮增加速率限制到您的API。 例如,您可以限制每個用戶的API的使用是在10分鐘內最多100次的API調用。 如果一個用戶同一個時間段內太多的請求被接收, 將返回響應狀態代碼 429 (這意味着過多的請求)。
要啓用速率限制, yii\web\User::identityClass 應該實現 yii\filters\RateLimitInterface. 這個接口需要實現以下三個方法:
getRateLimit()
: 返回允許的請求的最大數目及時間,例如,[100, 600]
表示在600秒內最多100次的API調用。loadAllowance()
: 返回剩餘的允許的請求和相應的UNIX時間戳數 當最後一次速率限制檢查時。saveAllowance()
: 保存允許剩餘的請求數和當前的UNIX時間戳。
你可以在user表中使用兩列來記錄容差和時間戳信息。 loadAllowance()
和 saveAllowance()
可以通過實現對符合當前身份驗證的用戶
的這兩列值的讀和保存。爲了提高性能,你也可以 考慮使用緩存或NoSQL存儲這些信息。
一旦 identity 實現所需的接口, Yii 會自動使用 yii\filters\RateLimiter 爲 yii\rest\Controller 配置一個行爲過濾器來執行速率限制檢查。 如果速度超出限制 該速率限制器將拋出一個 yii\web\TooManyRequestsHttpException。 你可以在你的 REST 控制器類裏配置速率限制,
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['rateLimiter']['enableRateLimitHeaders'] = false;
return $behaviors;
}
當速率限制被激活,默認情況下每個響應將包含以下HTTP頭髮送 目前的速率限制信息:
X-Rate-Limit-Limit
: 同一個時間段所允許的請求的最大數目;X-Rate-Limit-Remaining
: 在當前時間段內剩餘的請求的數量;X-Rate-Limit-Reset
: 爲了得到最大請求數所等待的秒數。
你可以禁用這些頭信息通過配置 yii\filters\RateLimiter::enableRateLimitHeaders 爲false, 就像在上面的代碼示例所示。
yii\rest\ActiveController繼承了yii\rest\Controller,在這個基礎上,封裝了基本的RESTful API: /**
* @inheritdoc
*/
public function actions()
{
return [
'index' => [
'class' => 'yii\rest\IndexAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'view' => [
'class' => 'yii\rest\ViewAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'create' => [
'class' => 'yii\rest\CreateAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->createScenario,
],
'update' => [
'class' => 'yii\rest\UpdateAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->updateScenario,
],
'delete' => [
'class' => 'yii\rest\DeleteAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
'options' => [
'class' => 'yii\rest\OptionsAction',
],
];
}
在創建自己的RESTful API時可以通過對yii\rest\ActiveController::actions()的重載來對對應的方法進行禁用和允許的設置。同時要對yii\rest\ActiveController::verbs()進行重載:
/**
* @inheritdoc
*/
protected function verbs()
{
return [
'index' => ['GET', 'HEAD'],
'view' => ['GET', 'HEAD'],
'create' => ['POST'],
'update' => ['PUT', 'PATCH'],
'delete' => ['DELETE'],
];
}
用於處理不同的動作對應的HTTP請求方式。
最後yii\rest\ActiveController提供了一個yii\rest\ActiveController::checkAccess()方法。該方法用於檢驗當前發起請求的用戶是否有權限使用某數據層進行某個操作。