Yii2框架写一套RESTful风格的API,对照魏曦教你学

一,入门

一、目录结构

实现一个简单地RESTful API只需用到三个文件。目录如下:

  1. frontend
  2. ├─ config
  3. main.php
  4. ├─ controllers
  5. BookController.php
  6. └─ models
  7. Book.php

二、配置URL规则

1.修改服务器的rewrite规则,将所有URL全部指向index.php上,使其支持 /books/1 格式。
如果是Apache服务器,在frontend/web/ 目录中新建.htaccess文件。文件内容如下:

  1. RewriteEngine on
  2. # If a directory or a file exists, use the request directly
  3. RewriteCond %{REQUEST_FILENAME} !-f
  4. RewriteCond %{REQUEST_FILENAME} !-d
  5. # Otherwise forward the request to index.php
  6. RewriteRule . index.php

如果是Nginx服务器,修改nginx/conf/nginx.conf,在当前"server{}"的"location / {}"中添加下面红色标记内容:

  1. location / {
  2.   try_files $uri $uri/ /index.php$is_args$args;
  3. }

2.修改frontend/config/main.php文件,为book控制器增加一个 URL 规则。这样,就能通过美化的 URL 和有意义的 http 动词进行访问和操作数据。配置如下:

  1. 'components' => [
  2. 'urlManager' => [
  3. 'enablePrettyUrl' => true,
  4. 'enableStrictParsing' => true,
  5. 'showScriptName' => false,
  6. 'rules' => [
  7. ['class' => 'yii\rest\UrlRule', 'controller' => 'book'],
  8. ],
  9. ],
  10. ],

三、创建一个model

1.在数据库中创建一张book表。book表的内容如下:

  1. -- ----------------------------
  2. -- Table structure for book
  3. -- ----------------------------
  4. DROP TABLE IF EXISTS `book`;
  5. CREATE TABLE `book` (
  6. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  7. `name` char(50) NOT NULL DEFAULT '',
  8. `num` tinyint(3) unsigned NOT NULL DEFAULT '0',
  9. PRIMARY KEY (`id`)
  10. ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
  11.  
  12. -- ----------------------------
  13. -- Records of book
  14. -- ----------------------------
  15. INSERT INTO `book` VALUES ('1', 'toefl', '10');
  16. INSERT INTO `book` VALUES ('2', 'ielts', '20');
  17. INSERT INTO `book` VALUES ('3', 'sat', '30');
  18. INSERT INTO `book` VALUES ('4', 'gre', '40');
  19. INSERT INTO `book` VALUES ('5', 'gmat', '50');

2.在frontend/models/目录中新建Book.php。文件内容如下:

  1. namespace frontend\models;
  2.  
  3. use yii\db\ActiveRecord;
  4.  
  5. class Book extends ActiveRecord
  6. {
  7. public static function tableName()
  8. {
  9. return 'book';
  10. }
  11. }

四、创建一个控制器

在frontend/controllers/目录中新建BookController.php。控制器类扩展自 yii\rest\ActiveController。通过指定 yii\rest\ActiveController::modelClass 作为 frontend\models\Book, 控制器就能知道使用哪个模型去获取和处理数据。文件内容如下:

  1. namespace frontend\controllers;
  2.  
  3. use yii\rest\ActiveController;
  4.  
  5. class BookController extends ActiveController
  6. {
  7. public $modelClass = 'frontend\models\Book';
  8. }

五、测试

到这里,我们就已经完成了创建用于访问用户数据 的 RESTful 风格的 API。创建的 API 包括:

  1. GET /books: 列出所有的书
  2. HEAD /books: 显示书的列表的概要信息
  3. POST /books: 新增1本书
  4. GET /books/1: 返回 ID=1的详细信息
  5. HEAD /books/1: 显示 ID=1的概述信息
  6. PATCH /books/1 and PUT /books/1: 更新书ID=1的信息
  7. DELETE /books/1: 删除书ID=1的信息
  8. OPTIONS /books: 显示关于末端 /books 支持的动词
  9. 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来禁用此行为:

  1. 'rules' => [
  2. ['class' => 'yii\rest\UrlRule', 'controller' => 'book', 'pluralize' => false],
  3. ],

2.可以使用fields和expand参数指定哪些字段应该包含在结果内。例如:URL http://{frontend的域名}/books?fields=name,num 将只返回 name 和 num 字段。

二,格式化响应,授权认证和速率限制

一、目录结构

先列出需要改动的文件。目录如下:

  1. web
  2. ├─ common
  3. └─ models
  4. User.php
  5. └─ frontend
  6. ├─ config
  7. main.php
  8. └─ controllers
  9. BookController.php

二、格式化响应

Yii2 RESTful支持JSON和XML格式,如果想指定返回数据的格式,需要配置yii\filters\ContentNegotiator::formats属性。例如,要返回JSON格式,修改frontend/controllers/BookController.php,加入红色标记代码:

  1. namespace frontend\controllers;
  2.  
  3. use yii\rest\ActiveController;
  4. use yii\web\Response;
  5.  
  6. class BookController extends ActiveController
  7. {
  8. public $modelClass = 'frontend\models\Book';
  9.  
  10. public function behaviors() {
  11. $behaviors = parent::behaviors();
  12. $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
  13. return $behaviors;
  14. }
  15. }

返回XML格式:FORMAT_XML。formats属性的keys支持MIME类型,而values必须在yii\web\Response::formatters中支持被响应格式名称。

三、授权认证

RESTful APIs通常是无状态的,因此每个请求应附带某种授权凭证,即每个请求都发送一个access token来认证用户。

1.配置user应用组件(不是必要的,但是推荐配置):
  设置yii\web\User::enableSession属性为false(因为RESTful APIs为无状态的,当yii\web\User::enableSession为false,请求中的用户认证状态就不能通过session来保持)
  设置yii\web\User::loginUrl属性为null(显示一个HTTP 403 错误而不是跳转到登录界面)
具体方法,修改frontend/config/main.php,加入红色标记代码:

  1. 'components' => [
  2. ...
  3. 'user' => [
  4. 'identityClass' => 'common\models\User',
  5. 'enableAutoLogin' => true,
  6.  
  7. 'enableSession' => false,
  8. 'loginUrl' => null,
  9.  
  10. ],
  11. ...
  12. ]

2.在控制器类中配置authenticator行为来指定使用哪种认证方式,修改frontend/controllers/BookController.php,加入红色标记代码:

  1. namespace frontend\controllers;
  2.  
  3. use yii\rest\ActiveController;
  4. use yii\web\Response;
  5.  
  6. use yii\filters\auth\CompositeAuth;
  7. use yii\filters\auth\QueryParamAuth;
  8.  
  9. class BookController extends ActiveController
  10. {
  11. public $modelClass = 'frontend\models\Book';
  12.  
  13. public function behaviors() {
  14. $behaviors = parent::behaviors();
  15.  
  16. $behaviors['authenticator'] = [
  17. 'class' => CompositeAuth::className(),
  18. 'authMethods' => [
  19. /*下面是三种验证access_token方式*/
  20. //1.HTTP 基本认证: access token 当作用户名发送,应用在access token可安全存在API使用端的场景,例如,API使用端是运行在一台服务器上的程序。
  21. //HttpBasicAuth::className(),
  22. //2.OAuth 2: 使用者从认证服务器上获取基于OAuth2协议的access token,然后通过 HTTP Bearer Tokens 发送到API 服务器。
  23. //HttpBearerAuth::className(),
  24. //3.请求参数: access token 当作API URL请求参数发送,这种方式应主要用于JSONP请求,因为它不能使用HTTP头来发送access token
  25. //http://localhost/user/index/index?access-token=123
  26. QueryParamAuth::className(),
  27. ],
  28. ];
  29.  
  30. $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
  31. return $behaviors;
  32. }
  33. }

3.创建一张user表

  1. -- ----------------------------
  2. -- Table structure for user
  3. -- ----------------------------
  4. DROP TABLE IF EXISTS `user`;
  5. CREATE TABLE `user` (
  6. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  7. `username` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  8. `password_hash` varchar(100) NOT NULL DEFAULT '' COMMENT '密码',
  9. `password_reset_token` varchar(50) NOT NULL DEFAULT '' COMMENT '密码token',
  10. `email` varchar(20) NOT NULL DEFAULT '' COMMENT '邮箱',
  11. `auth_key` varchar(50) NOT NULL DEFAULT '',
  12. `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态',
  13. `created_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
  14. `updated_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
  15. `access_token` varchar(50) NOT NULL DEFAULT '' COMMENT 'restful请求token',
  16. `allowance` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'restful剩余的允许的请求数',
  17. `allowance_updated_at` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'restful请求的UNIX时间戳数',
  18. PRIMARY KEY (`id`),
  19. UNIQUE KEY `username` (`username`),
  20. UNIQUE KEY `access_token` (`access_token`)
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  22.  
  23. -- ----------------------------
  24. -- Records of user
  25. -- ----------------------------
  26. INSERT INTO `user` VALUES ('1', 'admin', '$2y$13$1KWwchqGvxDeORDt5pRW.OJarf06PjNYxe2vEGVs7e5amD3wnEX.i', '', '', 'z3sM2KZvXdk6mNXXrz25D3JoZlGXoJMC', '10', '1478686493', '1478686493', '123', '4', '1478686493');

在common/models/User.php类中实现 yii\web\IdentityInterface::findIdentityByAccessToken()方法。修改common/models/User.php,加入红色标记代码::

  1. public static function findIdentityByAccessToken($token, $type = null)
  2. {
  3. //findIdentityByAccessToken()方法的实现是系统定义的
  4. //例如,一个简单的场景,当每个用户只有一个access token, 可存储access token 到user表的access_token列中, 方法可在User类中简单实现,如下所示:
  5. return static::findOne(['access_token' => $token]);
  6. //throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
  7. }

四、速率限制

为防止滥用,可以增加速率限制。例如,限制每个用户的API的使用是在60秒内最多10次的API调用,如果一个用户同一个时间段内太多的请求被接收,将返回响应状态代码 429 (这意味着过多的请求)。

1.Yii会自动使用yii\filters\RateLimiter为yii\rest\Controller配置一个行为过滤器来执行速率限制检查。如果速度超出限制,该速率限制器将抛出一个yii\web\TooManyRequestsHttpException。
修改frontend/controllers/BookController.php,加入红色标记代码:

  1. namespace frontend\controllers;
  2.  
  3. use yii\rest\ActiveController;
  4. use yii\web\Response;
  5. use yii\filters\auth\CompositeAuth;
  6. use yii\filters\auth\QueryParamAuth;
  7.  
  8. use yii\filters\RateLimiter;
  9.  
  10. class BookController extends ActiveController
  11. {
  12. public $modelClass = 'frontend\models\Book';
  13.  
  14. public function behaviors() {
  15. $behaviors = parent::behaviors();
  16.  
  17. $behaviors['rateLimiter'] = [
  18. 'class' => RateLimiter::className(),
  19. 'enableRateLimitHeaders' => true,
  20. ];
  21.  
  22. $behaviors['authenticator'] = [
  23. 'class' => CompositeAuth::className(),
  24. 'authMethods' => [
  25. /*下面是三种验证access_token方式*/
  26. //1.HTTP 基本认证: access token 当作用户名发送,应用在access token可安全存在API使用端的场景,例如,API使用端是运行在一台服务器上的程序。
  27. //HttpBasicAuth::className(),
  28. //2.OAuth 2: 使用者从认证服务器上获取基于OAuth2协议的access token,然后通过 HTTP Bearer Tokens 发送到API 服务器。
  29. //HttpBearerAuth::className(),
  30. //3.请求参数: access token 当作API URL请求参数发送,这种方式应主要用于JSONP请求,因为它不能使用HTTP头来发送access token
  31. //http://localhost/user/index/index?access-token=123
  32. QueryParamAuth::className(),
  33. ],
  34. ];
  35. $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
  36. return $behaviors;
  37. }
  38. }

2.在user表中使用两列来记录容差和时间戳信息。为了提高性能,可以考虑使用缓存或NoSQL存储这些信息。
修改common/models/User.php,加入红色标记代码:

  1. namespace common\models;
  2.  
  3. use Yii;
  4. use yii\base\NotSupportedException;
  5. use yii\behaviors\TimestampBehavior;
  6. use yii\db\ActiveRecord;
  7. use yii\web\IdentityInterface;
  8.  
  9. use yii\filters\RateLimitInterface;
  10.  
  11. class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
  12. {
  13.  
  14. ....
  15.  
  16. // 返回在单位时间内允许的请求的最大数目,例如,[10, 60] 表示在60秒内最多请求10次。
  17. public function getRateLimit($request, $action)
  18. {
  19. return [5, 10];
  20. }
  21.  
  22. // 返回剩余的允许的请求数。
  23. public function loadAllowance($request, $action)
  24. {
  25. return [$this->allowance, $this->allowance_updated_at];
  26. }
  27.  
  28. // 保存请求时的UNIX时间戳。
  29. public function saveAllowance($request, $action, $allowance, $timestamp)
  30. {
  31. $this->allowance = $allowance;
  32. $this->allowance_updated_at = $timestamp;
  33. $this->save();
  34. }
  35.  
  36. ....
  37.  
  38. public static function findIdentityByAccessToken($token, $type = null)
  39. {
  40. //throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
  41. //findIdentityByAccessToken()方法的实现是系统定义的
  42. //例如,一个简单的场景,当每个用户只有一个access token, 可存储access token 到user表的access_token列中, 方法可在User类中简单实现,如下所示:
  43. return static::findOne(['access_token' => $token]);
  44. }
  45.  
  46. ....
  47. }

Yii2 Restful api设计--App接口编程的更多相关文章

  1. 我是如何根据豆瓣api来理解Restful API设计的

    1.什么是REST REST全称是Representational State Transfer,表述状态转移的意思.它是在Roy Fielding博士论文首次提出.REST本身没有创造新的技术.组件 ...

  2. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(二)RESTful API实战笔记(接口设计及Java后端实现)

    写在前面的话 原计划这部分代码的更新也是上传到ssm-demo仓库中,因为如下原因并没有这么做: 有些使用了该项目的朋友建议重新创建一个仓库,因为原来仓库中的项目太多,结构多少有些乱糟糟的. 而且这次 ...

  3. RESTful API实战笔记(接口设计及Java后端实现)

    写在前面的话 原计划这部分代码的更新也是上传到ssm-demo仓库中,因为如下原因并没有这么做: 有些使用了该项目的朋友建议重新创建一个仓库,因为原来仓库中的项目太多,结构多少有些乱糟糟的. 而且这次 ...

  4. Yii2 Restful Api 401

    采用Yii2 Restful Api方式为APP提供数据,默认你已经做好了所有的编码和配置工作.采用Postman测试接口: 出现这个画面的一个可能原因是:access_token的写法有误,如果你使 ...

  5. Rest Framework简介 和 RESTful API 设计指南

    使用Django Rest Framework之前我们要先知道,它是什么,能干什么用? Django Rest Framework 是一个强大且灵活的工具包,用以构建Web API 为什么要使用Res ...

  6. 微服务指南走北(三):Restful API 设计简述

    API的定义取决于选择的IPC通信方式,假设是消息机制(如 AMQP 或者 STOMP).API则由消息频道(channel)和消息类型.假设是使用HTTP机制,则是基于请求/响应(调用http的ur ...

  7. RESTful API设计原则与规范

    RESTful API设计原则与规范 一.背景与基础概念 2 二.RESTful API应遵循的原则 3 1.协议(Protocol) 3 2.域名(ROOT URL) 3 3.版本(Versioni ...

  8. 从英文变形规则计算到Restful Api设计

    ➠更多技术干货请戳:听云博客 一天在研究Restful API设计,命名的时候我总是很纠结,我相信大多数人也有这种感觉,不是说想不出来某个单词怎么写的问题,像我这种没事背单词背到13000词量的人也要 ...

  9. Yii2 restful api创建,认证授权以及速率控制

    Yii2 restful api创建,认证授权以及速率控制 下面是对restful从创建到速率控制的一个详细流程介绍,里面的步骤以及截图尽可能详细,熟悉restful的盆友可能觉得过于繁琐,新手不妨耐 ...

随机推荐

  1. 添加图片后xcode报错:resource fork, Finder information, or similar detritus not allowed

    /Users/songximing/Library/Developer/Xcode/DerivedData/Children-cvqgzlzddltkfndhdmzedxbnoxwx/Build/Pr ...

  2. 嵌套表用法详解(PLSQL)

    嵌套表 嵌套表是一种类似于索引表的结构,也可以用于保存多个数据,而且也可以保存复合类型的数据 嵌套表指的是一个数据表定义事同时加入了其他内部表的定义,这一概念是在oracle 8中引入的,它们可以使用 ...

  3. Python内置模块:random,os,sys,和加密模块hashlib

    random import random    # 导入模块 随机数 import random # 内置的 print(random.random()) #0-1 之间随机小数(18位有效数字) p ...

  4. 洛谷P3311 [SDOI2014]数数 AC自动机+dp

    正解:AC自动机+dp 解题报告: 传送门! 首先看到多串匹配balabala显然想到建个AC自动机? 然后可以用一点儿数位dp的思想地想下(,,,其实并不算QAQ 幸运数可以分为两类:位数<n ...

  5. vue监听路由的变化,跳转到同一个页面时,Url改变但视图未重新加载问题

    引入:https://q.cnblogs.com/q/88214/ 解决方法: 添加路由监听,路由改变时执行监听方法 methods:{ fetchData(){ console.log('路由发送变 ...

  6. 链接服务器XXX的OLE DB提供程序“SQLNCLI”无法启动分布式事务“

    错误消息msg 7391 16级状态1行1表示 “Msg 7391,Level 16,State 2,Line 1 无法执行该操作,因为链接服务器XXX的OLE DB提供程序“SQLNCLI”无法启动 ...

  7. zabbix基础知识

    zabbix监控 初级 1.识别监控对象(分级) 2.理解监控对象(理论知识) 3.细分监控对象的指标 4.确定报警的基准线 预中级 1.工具化和监控分离 2.监控对象的分类 2.1硬件监控(方法:机 ...

  8. oracle-安装-init.sh

    !#/bin/bashgroupadd -g 1001 oinstallgroupadd -g 1002 dbagroupadd -g 1003 opergroupadd -g 1004 asmadm ...

  9. 001-dubbo基础-001-服务化最佳实践、异常处理逻辑

    1.参看地址 http://dubbo.apache.org/zh-cn/ 2.服务化最佳实践 分包 建议将服务接口.服务模型.服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分 ...

  10. PowerTCP FTP for .NET 在线e文文档

    http://www.dart.com/help/ptftpnet/webframe.html