Yii2 内置强大的 RESTful 支持,本文系统讲解三大核心功能的配置与最佳实践:响应格式化、认证授权、速率限制。基于 Yii 2.0 版本,代码可直接用于生产环境。
frontend/
├── config/
│ └── main.php
├── controllers/
│ └── BookController.php
└── models/
└── Book.php
common/
└── models/
└── User.php
Yii2 通过 yii\filters\ContentNegotiator 支持 JSON、XML 等格式。默认根据 Accept 头自动协商,也可强制指定。
<?php
namespace frontend\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\filters\ContentNegotiator;
class BookController extends ActiveController
{
public $modelClass = 'frontend\models\Book';
public function behaviors()
{
$behaviors = parent::behaviors();
// 重新配置 contentNegotiator
$behaviors['contentNegotiator'] = [
'class' => ContentNegotiator::class,
'formats' => [
'application/json' => Response::FORMAT_JSON,
'application/xml' => Response::FORMAT_XML,
// 强制浏览器访问也返回 JSON(可选)
'text/html' => Response::FORMAT_JSON,
],
];
return $behaviors;
}
}
GET /books → 返回 JSON 数组GET /books?format=xml → 返回 XML(需额外解析 query 参数)Accept: application/xmlRESTful API 无状态,每次请求需携带凭证。Yii2 提供三种内置认证方式:
| 方式 | 类 | 适用场景 |
|---|---|---|
| HTTP Basic Auth | HttpBasicAuth | 服务器间通信,access token 作用户名 |
| OAuth 2 (Bearer Token) | HttpBearerAuth | 标准 OAuth2 流程,Header 传递 Authorization: Bearer <token> |
| Query Param | QueryParamAuth | JSONP 或无法设置 Header 的场景,?access-token=xxx |
// frontend/config/main.php
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => false, // 无状态 API 禁用自动登录
'enableSession' => false, // 禁用 Session,避免 CSRF 等问题
'loginUrl' => null, // 直接返回 403 而非重定向登录页
],
],
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => \yii\filters\auth\CompositeAuth::class,
'authMethods' => [
\yii\filters\auth\HttpBearerAuth::class, // 推荐:Bearer Token
\yii\filters\auth\QueryParamAuth::class, // 兼容:Query 参数
],
'except' => ['options'], // OPTIONS 请求跳过认证(CORS 预检)
];
return $behaviors;
}
findIdentityByAccessToken()// common/models/User.php
namespace common\models;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
// ... 其他方法 ...
public static function findIdentityByAccessToken($token, $type = null)
{
// 简单场景:token 存数据库 user 表的 access_token 字段
return static::findOne(['access_token' => $token, 'status' => 10]);
}
}
CREATE TABLE `user` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(50) NOT NULL UNIQUE, `password_hash` VARCHAR(255) NOT NULL, `access_token` VARCHAR(100) NOT NULL UNIQUE COMMENT 'API 访问令牌', `auth_key` VARCHAR(32) NOT NULL, `status` SMALLINT UNSIGNED DEFAULT 10, `created_at` INT UNSIGNED DEFAULT 0, `updated_at` INT UNSIGNED DEFAULT 0 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
防止滥用,限制单位时间内请求次数。Yii2 通过 yii\filters\RateLimiter 实现,需身份类实现 RateLimitInterface。
use yii\filters\RateLimitInterface;
class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
{
// ... 现有字段需包含 allowance, allowance_updated_at ...
// 返回 [最大请求数, 时间窗口秒数] 例:1分钟内最多60次
public function getRateLimit($request, $action)
{
return [60, 60];
}
// 返回 [剩余配额, 最后更新 Unix 时间戳]
public function loadAllowance($request, $action)
{
return [$this->allowance, $this->allowance_updated_at];
}
// 保存更新后的配额与时间戳
public function saveAllowance($request, $action, $allowance, $timestamp)
{
$this->allowance = $allowance;
$this->allowance_updated_at = $timestamp;
$this->save(false, ['allowance', 'allowance_updated_at']);
}
}
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['rateLimiter'] = [
'class' => \yii\filters\RateLimiter::class,
'enableRateLimitHeaders' => true, // 返回 X-Rate-Limit-* 头
];
// 认证配置...
return $behaviors;
}
X-Rate-Limit-Limit: 60
X-Rate-Limit-Remaining: 59
X-Rate-Limit-Reset: 1699999999
超限时自动抛出 yii\web\TooManyRequestsHttpException (HTTP 429)。
allowance 存 Redis,避免每次请求写数据库。getRateLimit() 中根据用户角色返回不同限额,或直接返回 [INF, 1] 跳过限流。<?php
namespace frontend\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\filters\ContentNegotiator;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
use yii\filters\RateLimiter;
class BookController extends ActiveController
{
public $modelClass = 'frontend\models\Book';
public function behaviors()
{
$behaviors = parent::behaviors();
// 1. 格式化
$behaviors['contentNegotiator'] = [
'class' => ContentNegotiator::class,
'formats' => [
'application/json' => Response::FORMAT_JSON,
'application/xml' => Response::FORMAT_XML,
],
];
// 2. 认证
$behaviors['authenticator'] = [
'class' => CompositeAuth::class,
'authMethods' => [
HttpBearerAuth::class,
QueryParamAuth::class,
],
'except' => ['options'],
];
// 3. 限流
$behaviors['rateLimiter'] = [
'class' => RateLimiter::class,
'enableRateLimitHeaders' => true,
];
return $behaviors;
}
}
通过组合 ContentNegotiator、CompositeAuth、RateLimiter,Yii2 能快速构建生产级 RESTful API。关键点在于:禁用 Session、正确实现 IdentityInterface 与 RateLimitInterface、合理配置限流策略。建议结合 Redis 优化高并发下的限流性能。