API接口开发

thinkphp实战

哔哩哔哩:https://www.bilibili.com/video/BV1Y3fnYAEbq/

1、云控API接口开发简介


  • 从零开始开发
  • API接口是云控的核心
  • 网络验证
  • 热更新
  • 用户管理
  • 应用管理
  • 卡密管理
  • 等等

2、thinkphp6.0的安装


3、thinkphp6.0的配置


  • 多应用模式composer require topthink/think-multi-app
  • 目录结构1、删除view文件夹 2、创建多应用 app/admin app/api 3、创建(admin,api)应用下的控制器controller,model,view文件夹 4、配置环境变量 .env 5、修改命名空间

4、thinkphp6.0的URL访问


入口文件:index.php
​
单应用URL访问:http://serverName/index.php/控制器/操作/参数/值…
​
多应用URL访问:http://serverName/index.php/应用/控制器/操作/参数/值...

5、创建admin应用


1、手动创建
2、自动创建:php think build admin

6、渲染后台页面


如果你需要使用think-template模板引擎,只需要安装think-view 模板引擎驱动。

composer require topthink/think-view

7、后台模板的引入


后台模板:xadmin http://x.xuebingsi.com/

index.html------>api/app/admin/view/index/index.html
​
静态文件——————> api/public/static/admin
​
theme49.min.css ------>   <link rel="stylesheet" href="/static/admin/css/theme49.min.css">
​
​

8、管理员页面的引入


9、设置路由


10、创建管理员数据表


新建数据库:api    UTF8 Unicode   general-ci

创建管理员数据表

id
username
password
phone
email
role
add_time
status

11、thinkphp连接数据库


APP_DEBUG = true

[APP]
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = api
USERNAME = root
PASSWORD = root
HOSTPORT = 3306
CHARSET = utf8
DEBUG = true

[LANG]
default_lang = zh-cn

12、添加管理员模板引入


admin-add.html

13、添加管理员方法


14、添加管理员模型


15、添加管理员验证器


16、添加管理员的数据处理


17、公共函数的添加和使用


18、删除管理员功能开发


1、删除管理员控制器添加

2、删除管理员模型添加

3、删除管理员数据验证

4、进行数据库操作

5、前端数据提交开发

19、删除管理员添加验证规则


20、编辑管理员模板引入


21、编辑管理员功能开发


22、编辑管理员验证器的使用


23、引入登录页面模板


24、管理员登录功能的开发


25、通过Session管理登录状态


app\middleware.php   

26、管理员后台登录权限验证


27、管理员退出功能开发


28、添加后台权限验证


29、整理后台页面菜单栏


30、设备管理功能的开发


1、创建数据表

2、创建控制器

3、创建模型

4、创建验证器

5、创建视图

6、创建路由

31、设备列表页面的完善


32、设备添加功能的完善


33、设备删除功能的完善


34、设备编辑功能的完善


35、什么是API接口


36、API基本概念:RESTfulAPI


  • RESTful API是一种网络应用程序的设计风格和开发方式,并不是标准,也是目前非常流行的设计方式
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

https://api.example.com/v1/zoos/id
https://api.example.com/v1/animals/id
https://api.example.com/v1/employees/id

37、API基本概念:http请求方法


  • http动词:GET、POST、PUT、DELETEGET 用来获取资源 POST 用来新建资源(也可以用于更新资源) PUT 用来更新资源 DELETE 用来删除资源

38、API基本概念:URI和URL


  • URI,统一资源标志符(Uniform Resource Identifier, URI),表示的是web上每一种可用的资源,如 HTML文档、图像、视频片段、程序等都由一个URI进行标识的。URI通常由三部分组成: ①资源的命名机制; ②存放资源的主机名; ③资源自身的名称。 https://api.example.com/v1/zoos/1
  • URL:统一资源定位符,可以提供找到该资源的路径①第一部分是协议(或称为服务方式)。 ②第二部分是存有该资源的主机IP地址(有时也包括端口号)。 ③第三部分是主机资源的具体地址,如目录和文件名等。 https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png

39、API基本概念:API端点


  • API端点:指用于访问API的URI,不同的功能而拥有不同的端点https://api.example.com/v1/users/me
  • API端点设计短小便与输入的URI 人可以读懂的的URI 没有大小写混用的URI(一般标准的做法是全部使用小写) 修改方便的URI 不会暴露服务器架构的URI 规则统一的URI
  • API端点设计规范使用名词的复数形式 注意所用的单词 不使用空格及需要编码的字符 使用连接符来连接多个单词

40、API基本概念:返回数据


  • 状态码200 - 请求成功 301 - 资源(网页等)被永久转移到其它URL 404 - 请求的资源(网页等)不存在 500 - 内部服务器错误
  • 错误码10001 - 用户名不存在 10002 - 密码不正确
  • 数据体{ "errorCode":"0", "msg":"查询成功!", "data":{ "province":"河北" } }

41、API文档


api端点设计样板一


用户注册接口


1. 端点设计

接口名称端点请求方法备注
用户注册http://api.xxx.com/userspost用户注册

2. 参数

参数名称是否必填类型说明
usernamestring用户名
passwordstring密码
codestring验证码
timestampstring时间戳

3. header

向服务器端发送数据的方式有多种,建议将一些相对固定的数据通过header进行传递,但是这并不是必须的;在这里咱们将签名的数据放到header中传参。

参数名称是否必填类型说明
signstring签名

如果是APP项目,如需传递必要的设计信息,建议放到header中传递,具体传递方式,自己决定

4. 响应

接口无论是执行成功还是失败都有响应数据返回。只有这样,使用者才可以根据响应数据给客户端更好的体验。这里返回的是JSON数据。具体返回的数据结构,要根据项目的需求来顶

  • 响应头
HTTP/1.1 200 OK
Content-Type:application/json
  • 返回数据
{
    "message": "success",
    "data": {},
    "errorcode": 0
}

5.错误码

错误码说明
10000用户名不正确(格式)
10001密码不正确(格式)
10002验证码不正确
19997参数错误
19998请求超时
19999未知错误

api端点设计样板二


管理员登录

post /admin/login

参数必选类型说明
timetrueint时间戳 (用于确定接口的访问时间)
tokentruestring确定访问者身份 (MD5(USER_MD5(time)_USER))
usernametruestring只接受手机号
passwordtruestring用户密码
{
	"ret": 200, // 返回结果状态。200:接口正常请求并返回/40*:服务端的数据有误/500:服务器运行错误
	"data": {
	"user_id": "27", // 用户id
	"user_tag": "1" // 用户身份
	},
	"msg": "" // 401:用户名不存在!/402:手机号不存在!/403:密码不正确!
}

42、API测试工具Postman的安装


43、Postman的使用:接口分组管理


  • New:新建
  • History:历史记录
  • Collections:连接
  • Request:请求
  • Create:创建
  • Save:保存
  • form-data:表单数据
  • Cancel:取消
  • Global:全局

44、Postman的使用:环境变量的使用


  • {{host}}
  • $host
  • var host

45、Postman的使用:自动生成接口文档


  • 需要注册账号

46、创建API接口应用


php think build api

47、配置API接口应用域名


  • 隐藏入口文件<IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] </IfModule> http://api.io/api/demohttp://api.litikj.com/demo
  • 绑定API专用域名

48、用户注册接口开发(一):创建用户数据表


49、用户注册接口开发(二):完成前后端数据基本交互


用户注册接口


1. 端点设计

接口名称端点请求方法备注
用户注册http://api.xxx.com/userspost用户注册

2. 参数

参数名称是否必填类型说明
usernamestring用户名
passwordstring密码
timestampstring时间戳

3. header

向服务器端发送数据的方式有多种,建议将一些相对固定的数据通过header进行传递,但是这并不是必须的;在这里咱们将签名的数据放到header中传参。

参数名称是否必填类型说明
tokenstring签名

如果是APP项目,如需传递必要的设计信息,建议放到header中传递,具体传递方式,自己决定

4. 响应

接口无论是执行成功还是失败都有响应数据返回。只有这样,使用者才可以根据响应数据给客户端更好的体验。这里返回的是JSON数据。具体返回的数据结构,要根据项目的需求来顶

  • 响应头
HTTP/1.1 200 OK
Content-Type:application/json
  • 返回数据
{
    "message": "success",
    "data": [],
    "errorcode": 0
}

5.错误码

错误码说明
10000用户名不正确(格式)
10001密码不正确(格式)
10002验证码不正确
19996时间戳错误
19997参数错误
19998请求超时
19999未知错误

50、用户注册接口开发(三):处理响应数据


51、用户注册接口开发(四):封装统一的数据返回格式


private function return_msg($msg = 'ok',$data = [],$errorCode = 0,$httpCode = 200)
{
        $res_data = [
            'msg' => $msg,
            'data' => $data,
            'errorCode' => $errorCode
        ];

        return json($res_data,$httpCode);
}

52、用户注册接口开发(五):实现参数验证


<?php


namespace app\api\controller;

use app\BaseController;

class Base extends BaseController
{
    protected function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub

        $this->checkTime();
        $this->checkToken();
    }

    /** 检查时间戳 */
    protected function checkTime()
    {
        if(!$this->request->has('timestamp') || strlen($this->request->get('timestamp')) !== 10 || intval($this->request->get('timestamp')) <= 1){
            echo json_encode(['message'=>'时间戳错误','errorCode'=>19999,'data'=>[]]);
            exit;
        }

        if(abs(time() - intval($this->request->get('timestamp'))) > 60){
            echo json_encode(['message'=>'请求超时','errorCode'=>19999,'data'=>[]]);
            exit;
        }
    }
    
    /** 检查token */
    protected function checkToken()
    {
        if($this->request->header('token') == null){
            echo json_encode(['message'=>'token参数错误','errorCode'=>19999,'data'=>[]]);
            exit;
        }
    }

}

53、用户注册接口开发(六):实现数据验证


<?php
declare (strict_types = 1);

namespace app\api\validate;

use app\api\validate\BaseValidate;

class User extends BaseValidate
{
    /**
     * 定义验证规则
     * 格式:'字段名'	=>	['规则1','规则2'...]
     *
     * @var array
     */	
	protected $rule = [
	    'username' => 'require',
        'password' => 'require|min:6|max:20'
    ];
    
    /**
     * 定义错误信息
     * 格式:'字段名.规则名'	=>	'错误信息'
     *
     * @var array
     */	
    protected $message = [
        'username.require' => '用户名不能为空',
        'password.require' => '密码不能为空',
        'password.min' => '密码长度不能少于6位',
        'password.max' => '密码长度不能大于20位'
    ];
}

54、用户注册接口开发(七):异常处理基础知识


55、用户注册接口开发(八):异常处理接管


<?php


namespace app\exception;

use think\exception\Handle;
use think\exception\HttpException;
use think\exception\ValidateException;
use think\Response;
use Throwable;

class ExceptionHandle extends Handle
{
    public function render($request, Throwable $e): Response
    {

//        return json(['message'=>'系统错误','data'=>[],'errorCode'=>123456],500);

        // 参数验证错误
        if ($e instanceof ValidateException) {
            return json($e->getError(), 422);
        }

        // 请求异常
        if ($e instanceof HttpException && $request->isAjax()) {
            return response($e->getMessage(), $e->getStatusCode());
        }

        // 其他错误交给系统处理
        return parent::render($request, $e);
    }
}

56、用户注册接口开发(九):手动抛出异常


<?php


namespace app\exception;

use think\exception\Handle;
use think\exception\HttpException;
use think\exception\ValidateException;
use think\Response;
use Throwable;

class ExceptionHandle extends Handle
{
    private $httpCode = 500;
    private $msg = '未知错误';
    private $errorCode = 19999;

    public function render($request, Throwable $e): Response
    {
        $this->msg = $e->getMessage() ? : $this->msg;
        $this->errorCode = $e->getCode() ? : $this->errorCode;
        if ($e instanceof HttpException) {
            $this->httpCode = $e->getStatusCode() ?: $this->httpCode;
        }
        $res_data = [
            'message' => $this->msg,
            'data' => [],
            'errorCode' => $this->errorCode
        ];
        return json($res_data,$this->httpCode);

        //        $msg = $e->getMessage();
//        // 请求异常
//        if ($e instanceof HttpException) {
//            $httpCode = $e->getStatusCode();
//        }
//        $errorCode = $e->getCode();





        // 其他错误交给系统处理
        return parent::render($request, $e);
    }
}

57、用户注册接口开发(十):完善异常处理


<?php


namespace app\exception;

use think\exception\Handle;
use think\exception\HttpException;
use think\facade\Env;
use think\Response;
use Throwable;

class ExceptionHandle extends Handle
{
    private $httpCode = 500;
    private $msg = '未知错误';
    private $errorCode = 19999;

    public function render($request, Throwable $e): Response
    {
        if(Env::get('APP_DEBUG') == 1){
            // 请求异常
            if ($e instanceof HttpException && $request->isAjax()) {
                return response($e->getMessage(), $e->getStatusCode());
            }

            // 其他错误交给系统处理
            return parent::render($request, $e);
        }

        $this->msg = $e->getMessage() ? : $this->msg;
        $this->errorCode = $e->getCode() ? : $this->errorCode;
        if ($e instanceof HttpException) {
            $this->httpCode = $e->getStatusCode() ?: $this->httpCode;
        }
        $res_data = [
            'message' => $this->msg,
            'data' => [],
            'errorCode' => $this->errorCode
        ];
        return json($res_data,$this->httpCode);
    }
}

58、用户注册接口开发(十一):完善用户注册接口


59、用户登录接口开发(一):用户登录接口设计


用户登录接口


1. 端点设计

接口名称端点请求方法备注
用户登录http://api.xxx.com/loginpost用户登录

2. 参数

参数名称是否必填类型说明
usernamestring用户名
passwordstring密码
timestampstring时间戳

3. header

向服务器端发送数据的方式有多种,建议将一些相对固定的数据通过header进行传递,但是这并不是必须的;在这里咱们将签名的数据放到header中传参。

参数名称是否必填类型说明
tokenstringtoken

如果是APP项目,如需传递必要的设计信息,建议放到header中传递,具体传递方式,自己决定

4. 响应

接口无论是执行成功还是失败都有响应数据返回。只有这样,使用者才可以根据响应数据给客户端更好的体验。这里返回的是JSON数据。具体返回的数据结构,要根据项目的需求来顶

  • 响应头
HTTP/1.1 200 OK
Content-Type:application/json
  • 返回数据
{
    "message": "登录成功",
    "data": [],
    "errorcode": 0
}

5.错误码

错误码说明
10000用户名不正确(格式)
10001密码不正确(格式)
10002验证码不正确
10003无权限
10004登录过期
19996时间戳错误
19997参数错误
19998请求超时
19999未知错误

60、用户登录接口开发(二):完成基本的数据交互


1、匹配路由

2、创建登录控制器

3、参数的验证

4、数据验证

5、数据提交给模型

61、用户登录接口开发(三):完善validate数据验证


<?php
declare (strict_types = 1);

namespace app\api\validate;

use app\api\validate\BaseValidate;

class Login extends BaseValidate
{
    /**
     * 定义验证规则
     * 格式:'字段名'	=>	['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [
        'username' => 'require|max:20',
        'password' => 'require|min:6|max:16'
    ];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名'	=>	'错误信息'
     *
     * @var array
     */
    protected $message = [
        'username.require' => '用户名不能为空',
        'username.max' => '用户名不能超过20个字符',
        'password.require' => '密码不能为空',
        'password.min' => '密码长度不能少于6位',
        'password.max' => '密码长度不能大于16位'
    ];
}

62、用户登录接口开发(四):完善model中的登录验证


public static function login($data)
    {
        //验证用户是否存在
        $user = self::where('username','=',$data['username'])->find();

        if(!$user){
            throw new HttpException(400, '用户不存在',null,[],10000);
        }

        //验证密码是否正确
        if($user->password === md5($data['password'])){
            return true;
        }else{
            throw new HttpException(400, '密码错误',null,[],10001);
        }
    }

63、用户登录接口开发(五):返回响应数据


return $this->return_msg('注册成功!',[],0,200);

64、用户登录接口开发(六):什么token鉴权机制


65、用户登录接口开发(七):生成并返回token


<?php

namespace app\api\libs;


use app\api\model\Users;
use think\facade\Request;

class Auth
{
    private $token = '';
    private $username = '';
    private static $instance = null;

    private function __construct()
    {
        $data = Request::post();
        $this->username = $data['username'];
//        halt($this->username);
    }

    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

    //统一入口
    public static function getInstance()
    {
        if(!self::$instance instanceof self){
            self::$instance = new self();
        }

        return self::$instance;
    }

    //获取token
    public function getToken()
    {
        return $this->token;
    }

    //生成token
    private function createToken()
    {
        $this->token = md5($this->username.time().rand(10000,99999));
    }

    //设置并保存token
    public function setToken()
    {
        $this->createToken();
        $user = (new Users())->where('username','=',$this->username)->find();
        $user->login_code = $this->token;
        $user->expiration_time = time()+1800;
        $user->save();
        return $this;
    }


}

66、用户登录接口开发(八):验证token


<?php


namespace app\api\libs;


use app\api\model\Users as UserModel;
use think\exception\HttpException;
use think\facade\Request;

class Auth
{
    //获取用户数据
    //生成token
    //保存token到数据库
    //返回token

    private $username = '';
    private $token = '';
    private static $instance = null;

    private function __construct()
    {
        $this->username = Request::post('username');
        $this->token = Request::header('token');
    }

    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

    //统一获取对象入口
    public static function getInstance()
    {
        if(!self::$instance instanceof self){
            self::$instance = new self();
        }
        return self::$instance;
    }

    //生成token
    private function createToken()
    {
        $this->token = md5($this->username.time().rand(10000,99999));
    }

    //设置并保存
    public function setToken()
    {
        $this->createToken();
        $user = (new UserModel())->where('username','=',$this->username)->find();
        $user->login_code = $this->token;
        $user->expiration_time = time() + 1800;
        $user->save();
        return $this;
    }

    //获取token
    public function getToken()
    {
        return $this->token;
    }

    //验证token
    public function checkToken()
    {
        //1、验证token是否正确
        $user = (new UserModel())->where('login_code','=',$this->token)->find();
        if(!$user){
            throw new HttpException(400,'无权限',null,[],10003);
        }
        //2、验证token是否过期
        if($user->expiration_time < time()){
            throw new HttpException(400,'登录过期',null,[],10004);
        }

        $user->expiration_time = time() + 1800;
        $user->save();

        return true;
    }
    
}

67、用户登录接口开发(九):使用中间件middleware验证token


<?php
declare (strict_types = 1);

namespace app\middleware;

use app\api\libs\Auth;

class CheckApi
{
    /**
     * 处理请求
     *
     * @param \think\Request $request
     * @param \Closure       $next
     * @return Response
     */
    public function handle($request, \Closure $next)
    {
        //验证token
        Auth::getInstance()->checkToken();
        return $next($request);
    }
}

68、用户登录接口开发(十):token过期时间自动延期优化


//验证token
    public function checkToken()
    {
        //1、验证token是否正确
        $user = (new UserModel())->where('login_code','=',$this->token)->find();
        if(!$user){
            throw new HttpException(400,'无权限',null,[],10003);
        }
        //2、验证token是否过期
        if($user->expiration_time < time()){
            throw new HttpException(400,'登录过期',null,[],10004);
        }
​
        //25分钟不延时,后5分钟延时
        if($user->expiration_time - time() < 5){
            $user->expiration_time = time() + 20;
            $user->save();
        }
        
        return true;
    }
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧