yii2yii restful api 跨域web api fields方法覆盖怎么不行

拒绝访问 | www. | 百度云加速
请打开cookies.
此网站 (www.) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(38f3e87b932b43b3-ua98).
重新安装浏览器,或使用别的浏览器拒绝访问 |
| 百度云加速
请打开cookies.
此网站 () 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(38f3e87c510543dd-ua98).
重新安装浏览器,或使用别的浏览器前不久做一个项目,是用Yii2框架写一套RESTful风格的API,就去查了下《Yii 2.0 权威指南 》,发现上面写得比较简略。所以就在这里写一篇教程贴,希望帮助刚接触Yii2框架RESTful的小伙伴快速入门。
一、目录结构
实现一个简单地RESTful API只需用到三个文件。目录如下:
├─ config
└ main.php
├─ controllers
└ BookController.php
└─ models
└ Book.php
二、配置URL规则
1.修改服务器的rewrite规则,将所有URL全部指向index.php上,使其支持 /books/1 格式。如果是Apache服务器,在frontend/web/ 目录中新建.htaccess文件。文件内容如下:
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
如果是Nginx服务器,修改nginx/conf/nginx.conf,在当前"server{}"的"location / {}"中添加下面红色标记内容:
location / {
  try_files $uri $uri/ /index.php$is_args$
2.修改frontend/config/main.php文件,为book控制器增加一个 URL 规则。这样,就能通过美化的 URL 和有意义的 http 动词进行访问和操作数据。配置如下:
'components' =& [
'urlManager' =& [
'enablePrettyUrl' =& true,
'enableStrictParsing' =& true,
'showScriptName' =& false,
'rules' =& [
['class' =& 'yii\rest\UrlRule', 'controller' =& 'book'],
三、创建一个model
1.在数据库中创建一张book表。book表的内容如下:
-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` char(50) NOT NULL DEFAULT '',
`num` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('1', 'toefl', '10');
INSERT INTO `book` VALUES ('2', 'ielts', '20');
INSERT INTO `book` VALUES ('3', 'sat', '30');
INSERT INTO `book` VALUES ('4', 'gre', '40');
INSERT INTO `book` VALUES ('5', 'gmat', '50');
2.在frontend/models/目录中新建Book.php。文件内容如下:
namespace frontend\
use yii\db\ActiveR
class Book extends ActiveRecord
public static function tableName()
return 'book';
四、创建一个控制器
在frontend/controllers/目录中新建BookController.php。控制器类扩展自 yii\rest\ActiveController。通过指定 yii\rest\ActiveController::modelClass 作为 frontend\models\Book, 控制器就能知道使用哪个模型去获取和处理数据。文件内容如下:
namespace frontend\
use yii\rest\ActiveC
class BookController extends ActiveController
public $modelClass = 'frontend\models\Book';
到这里,我们就已经完成了创建用于访问用户数据 的 RESTful 风格的 API。创建的 API 包括:
GET /books: 列出所有的书
HEAD /books: 显示书的列表的概要信息
POST /books: 新增1本书
GET /books/1: 返回 书ID=<span style="color: #的详细信息
HEAD /books/1: 显示 书ID=<span style="color: #的概述信息
PATCH /books/1 and PUT /books/1: 更新书ID=<span style="color: #的信息
DELETE /books/1: 删除书ID=<span style="color: #的信息
OPTIONS /books: 显示关于末端 /books 支持的动词
OPTIONS /books/1: 显示有关末端 /books/1 支持的动词
可以通过Web浏览器中输入 URL http://{frontend的域名}/books 来访问API,或者使用一些浏览器插件来发送特定的 headers 请求,比如Firefox的RestClient、Chrome的Advanced Rest Client、postman等。
1.Yii 将在末端使用的控制器的名称自动变为复数。这是因为 yii\rest\UrlRule 能够为他们使用的末端全自动复数化控制器。可以通过设置yii\rest\UrlRule::pluralize为false来禁用此行为:
'rules' =& [
['class' =& 'yii\rest\UrlRule', 'controller' =& 'book', 'pluralize' =& false],
2.可以使用fields和expand参数指定哪些字段应该包含在结果内。例如:URL http://{frontend的域名}/books?fields=name,num 将只返回 name 和 num 字段。
阅读(...) 评论()Yii2 RESTful中api的使用及开发实例详解
作者:白狼
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Yii2 RESTful中api的使用及开发实例详解的相关资料,需要的朋友可以参考下
什么是RESTful风格的API
对于各种客户端设备与服务端的通信,我们往往都通过API为客户端提供数据,提供某种资源。关于RESTful的概念,一查一大推,一两句也解释不清,姑且先按照我们通俗的理解:在众多风格、众多原则的API中,RESTful就是一套比较优秀的接口调用方式。
Yii2如何实现RESTful风格的API
1、建立单独的应用程序
为了增加程序的可维护性,易操作性,我们选择新建一套应用程序,这也是为了和前台应用、后台应用区分开操作。有些人要嚷嚷了,为啥非得单独搞一套呢?如果你就单纯的提供个别的几个h5页面的话,那就没有必要了,但事实往往是客户端要升级啊,要增加不同的版本啊,这就需要我们不但要后端不仅要增加一套单独的应用程序,我们还要增加各种版本去控制。
在WEB前端(frontend)和后端(backend)的同级目录,新建一个文件夹,命名api,其目录结构如下所示:
├─assets
│ AppAsset.php
├─config
│ bootstrap.php
│ main-local.php
│ main.php
│ params-local.php
│ params.php
├─runtime
│ index.php
├─assets
可以看出其目录结构基本上同backend没有其他差异,因为我们就是拷贝backend项目,只是做了部分优化。
2、为新建的api应用程序美化路由
首先保证你的web服务器开启rewrite规则,细节我们就不说了,不过这是前提。
接着配置api/config/main.php文件
'components' =& [
// other config
'urlManager' =& [
'enablePrettyUrl' =& true,
'showScriptName' =& false,
'enableStrictParsing' =&true,
'rules' =& [],
最后只需要在应用入口同级增加.htaccess文件就好,我们以apache为例
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
RewriteRule \.svn\/ /404.html
RewriteRule \.git\/ /404.html
3、利用gii生成测试modules
用了便于演示说明,我们新建一张数据表goods表,并向其中插入几条数据。
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `goods` VALUES ('1', '11111');
INSERT INTO `goods` VALUES ('2', '22222');
INSERT INTO `goods` VALUES ('3', '333');
INSERT INTO `goods` VALUES ('4', '444');
INSERT INTO `goods` VALUES ('5', '555');
接着我们先利用gii生成modules后,再利用gii模块,按照下图中生成goods信息
现在,我们的api目录结构应该多个下面这几个目录
├─models
│ Goods.php
├─modules
│ │ Module.php
│ ├─controllers
│ │ DefaultController.php
│ │ GoodsController.php
│ └─views
│ └─default
│ index.php
4、重新配置控制器
为了实现restful风格的api,在yii2中,我们需要对控制器进行一下改写
namespace api\modules\v1\
use yii\rest\ActiveC
class GoodsController extends ActiveController
public $modelClass = 'api\models\Goods';
5、为Goods配置Url规则
'rules' =& [
'class' =& 'yii\rest\UrlRule',
'controller' =& ['v1/goods']
6、模拟请求操作
经过上面几个步骤,到此我们已经为goods成功创建了满足restful风格的api了。为了更好更方便的演示,我们借助工具postman进行模拟请求。
为了见证一下我们的操作,我们用postman请求一下GET /v1/goods看看结果如何:
从上面截图中可以清楚的看到,GET /v1/goods 已经能够很方便的获取我们表中的数据了。
当然,yii2还对该api封装了如下操作:
GET /users: 逐页列出所有用户
HEAD /users: 显示用户列表的概要信息
POST /users: 创建一个新用户
GET /users/123: 返回用户 123 的详细信息
HEAD /users/123: 显示用户 123 的概述信息
PATCH /users/123 and PUT /users/123: 更新用户123
DELETE /users/123: 删除用户123
OPTIONS /users: 显示关于末端 /users 支持的动词
OPTIONS /users/123: 显示有关末端 /users/123 支持的动词
不信的话我们可以利用postman发送一个post请求到/v1/goods,我们会发现成功创建了一个新的商品。
需要提醒的是,操作中还请细心且注意:
如果你的控制器末端不是复数(比如是blog非blogs)请保证请求的时候是复数!这是因为在RESTful架构中,网址中只能有名词而不能包含动词,名词又往往与数据表相对应,数据表呢又是一个“集合”,因此该名词往往是复数的形式。
7、关于授权认证
为什么需要授权认证?这在一般的操作中是需要的。比如说用户要设置自己的信息。
为了对yii2 restful授权认证说的更清楚,我们将会以两个两种不同的方法进行说明。
首先需要开启认证:
假设我们已经按照第3步创建了包含字段access-token的数据表user,而且利用gii上生成了相应的model和controller
配置main.php文件
'components' =& [
'user' =& [
'identityClass' =& 'common\models\User',
'enableAutoLogin' =& true,
'enableSession'=&false
为控制器配置authenticator行为指定认证方式
namespace api\modules\v1\
use yii\rest\ActiveC
use yii\helpers\ArrayH
use yii\filters\auth\QueryParamA
class UserController extends ActiveController
public $modelClass = 'api\models\User';
public function behaviors() {
return ArrayHelper::merge (parent::behaviors(), [
'authenticator' =& [
'class' =& QueryParamAuth::className()
最后我们还需要在identityClass中实现findIdentityByAccessToken方法
public static function findIdentityByAccessToken($token, $type = null)
return static::findOne(['access_token' =& $token, 'status' =& self::STATUS_ACTIVE]);
如此一来,我们先通过postman模拟不带access-token请求看结果
"name": "Unauthorized",
"message": "You are requesting with an invalid credential.",
"code": 0,
"status": 401,
"type": "yii\\web\\UnauthorizedHttpException"
提示401 我们没有权限访问!
我们在请求的链接上携带正确的access-token,认证通过后,控制器会再继续执行其他检查(频率限制、操作权限等),才可以返回正确的用户信息。
需要提醒的是:通过url的形式对access-token传递存在一定的风险,有可能会造成数据的泄漏!一般而言,access-token需要放到HTTP头中进行传递!除非客户端的请求是jsonp格式的!
8、速率限制
速率限制,该操作完全也是出于安全考虑,我们需要限制同一接口某时间段过多的请求。
速率限制默认不启用,用启用速率限制,yii\web\User::identityClass 应该实现yii\filters\RateLimitInterface,也就是说我们的common\models\User.php需要实现yii\filters\RateLimitInterface接口的三个方法,具体代码可参考:
use yii\filters\RateLimitI
use yii\web\IdentityI
class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
// other code ......
// 返回某一时间允许请求的最大数量,比如设置10秒内最多5次请求(小数量方便我们模拟测试)
public function getRateLimit($request, $action){
return [5, 10];
// 回剩余的允许的请求和相应的UNIX时间戳数 当最后一次速率限制检查时
public function loadAllowance($request, $action){
return [$this-&allowance, $this-&allowance_updated_at];
// 保存允许剩余的请求数和当前的UNIX时间戳
public function saveAllowance($request, $action, $allowance, $timestamp){
$this-&allowance = $
$this-&allowance_updated_at = $
$this-&save();
需要注意的是,你仍然需要在数据表User中新增加两个字段
allowance:剩余的允许的请求数量
allowance_updated_at:相应的UNIX时间戳数
在我们启用了速率限制后,Yii 会自动使用 yii\filters\RateLimiter 为 yii\rest\Controller 配置一个行为过滤器来执行速率限制检查。
现在我们通过postman请求v1/users再看看结果,会发现在10秒内调用超过5次API接口,我们会得到状态为429太多请求的异常信息。
"name": "Too Many Requests",
"message": "Rate limit exceeded.",
"code": 0,
"status": 429,
"type": "yii\\web\\TooManyRequestsHttpException"
9、关于版本
为了兼容历史版本而且考虑向后兼容性,我们在一开始操作的时候就以URL的方式实现了版本话,这里就不再进行阐述了。
10、错误处理
Yii的REST框架的HTTP状态代码可参考如下就好,没啥好说的
200: OK。一切正常。
201: 响应 POST 请求时成功创建一个资源。Location header 包含的URL指向新创建的资源。
204: 该请求被成功处理,响应不包含正文内容 (类似 DELETE 请求)。
304: 资源没有被修改。可以使用缓存的版本。
400: 错误的请求。可能通过用户方面的多种原因引起的,例如在请求体内有无效的JSON 数据,无效的操作参数,等等。
401: 验证失败。
403: 已经经过身份验证的用户不允许访问指定的 API 末端。
404: 所请求的资源不存在。
405: 不被允许的方法。 请检查 Allow header 允许的HTTP方法。
415: 不支持的媒体类型。 所请求的内容类型或版本号是无效的。
422: 数据验证失败 (例如,响应一个 POST 请求)。 请检查响应体内详细的错误消息。
429: 请求过多。 由于限速请求被拒绝。
500: 内部服务器错误。 这可能是由于内部程序错误引起的。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具CREATE TABLE IF NOT EXISTS `user` (
`id` int(20) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL COMMENT '用户名',
`password_hash` varchar(80) DEFAULT NULL COMMENT '密码',
`password_reset_token` varchar(60) DEFAULT NULL COMMENT '密码token',
`email` varchar(60) DEFAULT NULL COMMENT '邮箱',
`auth_key` varchar(60) DEFAULT NULL,
`status` int(5) DEFAULT NULL COMMENT '状态',
`created_at` int(18) DEFAULT NULL COMMENT '创建时间',
`updated_at` int(18) DEFAULT NULL COMMENT '更新时间',
`password` varchar(50) DEFAULT NULL COMMENT '密码',
`role` varchar(50) DEFAULT NULL COMMENT 'role',
`access_token` varchar(60) DEFAULT NULL,
`allowance` int(20) NOT NULL,
`allowance_updated_at` int(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `access_token` (`access_token`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
-- 转存表中的数据 `user`
INSERT INTO `user` (`id`, `username`, `password_hash`, `password_reset_token`, `email`, `auth_key`, `status`, `created_at`, `updated_at`, `password`, `role`, `access_token`, `allowance`, `allowance_updated_at`) VALUES
(1, 'terry', '$2y$13$EyK1HyJtv4A/19Jb8gB5y.4SQm5y93eMeHjUf35ryLyd2dWPJlh8y', NULL, '', 'pBJi3hyFsLsTuvUM9paFpWjYRatn3qwS', 10, , , NULL, NULL, 'xxxxxxxxxxxxxxxxxxxx', 0, ),
(2, 'terry1', '$2y$13$B0P2T4wEFrxeecSEClo5g.wrapMqG0RmsSL0cJluHJ747M3R0vkMG', NULL, '', 'wIvJk7dMm6PQ1dJFz8iUqJ1RfH6rsDTW', 10, , , NULL, NULL, NULL, 0, 0),
(3, 'zqy', '$2y$13$kcczJRoLGqSWHo7AZloCyeJiMYeM5SA1uXhyUZCNkFirWJuWeC3gO', NULL, '', 'K-76pcy7gxceemxRI2IeN5g1EhLMaCj8', 10, , , NULL, 'moderator', NULL, 0, 0),
(4, 'admin', '$2y$13$w4/PWXvwRUKNSrDTSMhPhOnvxw4v4WWt7GVl2siozPDlmEjP04vJC', NULL, '', 'hZWOaamjHEsPtuJJVghFRdE2oTj7Qv8P', 10, , , NULL, NULL, NULL, 0, 0);
设置用户组件 yii\web\U
'user' =& [
'identityClass' =& 'myapp\code\core\Erp\User\models\User',
'enableAutoLogin' =& true,
3.创建User模块,在模块中加入
'class' =& 'myapp\code\core\Erp\User\Module',
4.编辑 myapp\code\core\Erp\User\Module.php
namespace myapp\code\core\Erp\U
class Module extends \yii\base\Module
public $controllerNamespace = 'myapp\code\core\Erp\User\controllers';
public function init()
parent::init();
# session 设置无效
\Yii::$app-&user-&enableSession =
\Yii::$app-&user-&loginUrl =
# 加载配置文件
if(file_exists(__DIR__ . '/etc/config.php')){
Yii::configure($this, ['params'=&(require(__DIR__ . '/etc/config.php'))]);
$this-&params['blockDir'] = str_replace("\\controllers","",$this-&controllerNamespace);
主要是 设置:
\Yii::$app-&user-&enableSession =
\Yii::$app-&user-&loginUrl =
myapp\code\core\Erp\User\models\User 实现 yii\web\IdentityInterface 接口。
代码如下:
namespace myapp\code\core\Erp\User\
use yii\base\NotSupportedE
use yii\behaviors\TimestampB
use yii\db\ActiveR
use yii\web\IdentityI
use yii\filters\RateLimitI
* User model
* @property integer $id
* @property string $username
* @property string $password_hash
* @property string $password_reset_token
* @property string $email
* @property string $auth_key
* @property integer $status
* @property integer $created_at
* @property integer $updated_at
* @property string $password write-only password
class User extends ActiveRecord implements IdentityInterface ,RateLimitInterface
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
# 速度控制
6秒内访问3次,注意,数组的第一个不要设置1,设置1会出问题,一定要
#大于2,譬如下面
6秒内只能访问三次
# 文档标注:返回允许的请求的最大数目及时间,例如,[100, 600] 表示在600秒内最多100次的API调用。
function getRateLimit($request, $action){
return [3, 6];
# 文档标注: 返回剩余的允许的请求和相应的UNIX时间戳数 当最后一次速率限制检查时。
function loadAllowance($request, $action){
//return [1,strtotime(date("Y-m-d H:i:s"))];
//echo $this-&
return [$this-&allowance, $this-&allowance_updated_at];
# allowance 对应user 表的allowance字段
# allowance_updated_at 对应user allowance_updated_at
# 文档标注:保存允许剩余的请求数和当前的UNIX时间戳。
function saveAllowance($request, $action, $allowance, $timestamp){
$this-&allowance = $
$this-&allowance_updated_at = $
$this-&save();
* @inheritdoc
# 设置table
public static function tableName()
return 'user';
* @inheritdoc
public function behaviors()
TimestampBehavior::className(),
* @inheritdoc
# 设置 status
,以及取值的区间
public function rules()
['status', 'default', 'value' =& self::STATUS_ACTIVE],
['status', 'in', 'range' =& [self::STATUS_ACTIVE, self::STATUS_DELETED]],
* @inheritdoc
# 通过id 找到identity
public static function findIdentity($id)
return static::findOne(['id' =& $id, 'status' =& self::STATUS_ACTIVE]);
* @inheritdoc
# 通过access_token 找到identity
public static function findIdentityByAccessToken($token, $type = null)
return static::findOne(['access_token' =& $token, 'status' =& self::STATUS_ACTIVE]);
# 生成access_token
public function generateAccessToken()
$this-&access_token = Yii::$app-&security-&generateRandomString();
* Finds user by username
* @param string $username
* @return static|null
public static function findByUsername($username)
return static::findOne(['username' =& $username, 'status' =& self::STATUS_ACTIVE]);
* Finds user by password reset token
* @param string $token password reset token
* @return static|null
# 此处是忘记密码所使用的
public static function findByPasswordResetToken($token)
if (!static::isPasswordResetTokenValid($token)) {
return static::findOne([
'password_reset_token' =& $token,
'status' =& self::STATUS_ACTIVE,
* Finds out if password reset token is valid
* @param string $token password reset token
* @return boolean
public static function isPasswordResetTokenValid($token)
if (empty($token)) {
$timestamp = (int) substr($token, strrpos($token, '_') + 1);
$expire = Yii::$app-&params['user.passwordResetTokenExpire'];
return $timestamp + $expire &= time();
* @inheritdoc
public function getId()
return $this-&getPrimaryKey();
* @inheritdoc
public function getAuthKey()
return $this-&auth_
* @inheritdoc
public function validateAuthKey($authKey)
return $this-&getAuthKey() === $authK
* Validates password
* @param string $password password to validate
* @return boolean if password provided is valid for current user
public function validatePassword($password)
return Yii::$app-&security-&validatePassword($password, $this-&password_hash);
* Generates password hash from password and sets it to the model
* @param string $password
public function setPassword($password)
$this-&password_hash = Yii::$app-&security-&generatePasswordHash($password);
* Generates "remember me" authentication key
public function generateAuthKey()
$this-&auth_key = Yii::$app-&security-&generateRandomString();
* Generates new password reset token
public function generatePasswordResetToken()
$this-&password_reset_token = Yii::$app-&security-&generateRandomString() . '_' . time();
* Removes password reset token
public function removePasswordResetToken()
$this-&password_reset_token =
6.控制器:
namespace myapp\code\core\Erp\User\
use yii\web\C
use myapp\code\core\Erp\User\models\U
use yii\filters\auth\CompositeA
use yii\filters\auth\HttpBasicA
use yii\filters\auth\HttpBearerA
use yii\filters\auth\QueryParamA
use yii\filters\RateL
class IndexController extends Controller
public function init(){
parent::init();
# 行为 添加
验证 :authenticator
速度控制:rateLimiter
public function behaviors()
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' =& CompositeAuth::className(),
'authMethods' =& [
# 下面是三种验证access_token方式
//HttpBasicAuth::className(),
//HttpBearerAuth::className(),
# 这是GET参数验证的方式
# http://10.10.10.252:600/user/index/index?access-token=xxxxxxxxxxxxxxxxxxxx
QueryParamAuth::className(),
# rate limit部分,速度的设置是在
\myapp\code\core\Erp\User\models\User::getRateLimit($request, $action){
官方文档:
当速率限制被激活,默认情况下每个响应将包含以下HTTP头发送 目前的速率限制信息:
X-Rate-Limit-Limit: 同一个时间段所允许的请求的最大数目;
X-Rate-Limit-Remaining: 在当前时间段内剩余的请求的数量;
X-Rate-Limit-Reset: 为了得到最大请求数所等待的秒数。
你可以禁用这些头信息通过配置 yii\filters\RateLimiter::enableRateLimitHeaders 为false, 就像在上面的代码示例所示。
$behaviors['rateLimiter'] = [
'class' =& RateLimiter::className(),
'enableRateLimitHeaders' =& true,
public function actionIndex()
echo Yii::$app-&user-&
然后通过访问:
http://10.10.10.252:900/user/index/index?access-token=nnnnnnnnnnnnnn
就可以访问了,由于我设置的是6秒内访问3次,正常访问,查看head消息头:如下
我设置的是:6秒内最多访问3次的返回结果
X-Rate-Limit-Limit : 3
总次数还剩余3次
X-Rate-Limit-Remaining:2

我要回帖

更多关于 yii2 restful api实例 的文章

 

随机推荐