php返回接口不要路径.php,1.项目文档.md · hdlz/thinkphp5-weixin - Gitee.com

## 环境与工具

### 框架

* ThinkPHP5

* 小程序web开发者工具

### 基础语言、环境

* PHP 5.6

* Mysql

* Apache

### 开发工具

* PHPStorm

* 微信web开发者工具(VS code)

* PostMan:接口测试

* Navicat:数据库管理

* phpstudy/XAMPP: 集成开发环境

> https://www.apachefriends.org/download.html

查看端口占用的进程,

1.cmd中输入

netstat -ano

2.找到80端口或3306端口对应的进程PID的数字

3.打开windows 任务管理器-》详细信息中找到该pid对应的进程关闭

### ThinkPHP5

* Composer安装:

* Git安装:

应用项目

https://github.com/top-think/think/tree/v5.0.7

核心框架

https://github.com/top-think/framework

* 直接下载:

### 三端分离项目命名

* 服务器端程序: Server

* 客户端小程序: Shop

* CMS: Cms

thinkphp -》 server

framework -> thinkphp

thinkphp -> 拖入到Server目录中

访问

http://localhost/personal/jiyun_classware/thinkphp5-weixin/server/public/

### ThinkPHP5目录层次结构

* 入口文件:public/index.php

* 应用: application

* 模块: application/模块名

* 控制器: application/模块名/controller/index.php

* action: application/模块名/controller/index.php中的方法

* 模型: application/模块名/model

* 服务: application/模块名/service

* vendor: composer安装目录

* thinkphp:核心类库

* runtime:缓存、日志文件

* public:外部站点的目录,可以被直接访问到的

* extend: 团队自定义的一些类库。可以被think自动加载的

> 详见 https://www.kancloud.cn/manual/thinkphp5/118008

### ThinkPHP5自带的webserver

* cd public

* php -S localhost:8080 router.php

### URL路径格式(默认不区分大小写)

#### PATH_INFO模式

* http://serverName/index.php/module/controller/action/[param/value/param2/value2...]

* http://localhost/server/public/index.php/index/index/index

#### 兼容模式 ?s=index/index/index/p/v

http://localhost:8080/index.php?s=index/index/index

> 缺点:1.太长 2.URL路径暴露了服务器文件结构 3.不能实现URL语义化

### 新建一个模块及命名空间

* 自动补全命名空间

1. settings

2. 搜索 Directories

3. 选中server/applications

4. 点source是选项卡

5. 点右侧小p 向下箭头

6. 输入app

### 安装Postman

### 动态注册式路由

> 原有的path_info模式就会失效

* 修改 application/route.php

use think\Route;

Route::rule('hello','test/Test/hello');

地址栏访问 localhost:8080/hello

### 定义路由

* Route::rule('路由表达式','路由地址','请求类型','路由参数(数组)','变量规则(数组)')

//GET\POST\DELETE\PUT

* 支持多种请求方式:

Route::rule('hello','test/Test/hello','GET|POST',['https'=>false]);

* 简写方式:

Route::get('hello','test/Test/hello');

Route::get('hello','test/Test/hello');

Route::any();

### 路由传参

* get

1.

Route::get('hello/:id','test/Test/hello');

2.不定义在地址栏里,使用?直接传,在方法参数中直接接收

Route::get('hello','test/Test/hello');

* 方法中获取参数

1. application/route.php

Route::get('hello/:id','test/Test/hello');

2. application/test/controller/Test.php/hello

public function hello($id,$name){

echo $id;

echo '|';

echo $name;

}

3.访问

http://localhost:8080/hello/123?name=yuonly

* 使用request获取参数

1. 使用

use think\Request

2.

$id = Request::instance()->param('id');

$name = Request::instance()->param('name');

$age = Request::instance()->param('age');

3. 一次性获取所有参数

$all = Request::instance()->param();

var_dump($all);

Request::instance()->get(); ? 后面的参数

Request::instance()->route(); 地址栏中的参数

Request::instance()->post(); 只获取post参数

* 助手函数获取参数

$all = input('param.');

$all = input('get.');

$all = input('post.');

* 使用依赖注入的方式获取

1. application/test/controller/Test.php/req

use think\Request;

public function hello(Request $request){

$all = $request->param();

}

2. application/route.php

Route::get('req/:id','test/Test/req');

3. 访问

http://localhost:8080/req/222?name=123&age=19

### 功能开发

---

### Banner表设计分析

SET NAMES utf8;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for `y1611_banner`

-- ----------------------------

DROP TABLE IF EXISTS `y1611_banner`;

CREATE TABLE `y1611_banner` (

`bid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'banner主键',

`name` varchar(50) NOT NULL DEFAULT '' COMMENT 'banner名称,作为标识',

`description` varchar(255) NOT NULL DEFAULT '' COMMENT 'Banner描述',

`delete_time` int(11) NOT NULL COMMENT '删除时间',

`update_time` int(11) NOT NULL COMMENT '更新时间',

PRIMARY KEY (`bid`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------

-- Records of `y1611_banner`

-- ----------------------------

BEGIN;

INSERT INTO `y1611_banner` VALUES ('1', '首页', '首页轮播图', '0', '0');

COMMIT;

-- ----------------------------

-- Table structure for `y1611_banner_item`

-- ----------------------------

DROP TABLE IF EXISTS `y1611_banner_item`;

CREATE TABLE `y1611_banner_item` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`img_id` int(10) unsigned NOT NULL COMMENT '图片表的主键',

`keyword` varchar(120) NOT NULL DEFAULT '' COMMENT '关键字,根据不同的type跳转到不同的页面',

`type` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '跳转类型,可能跳转到商品页,也可能跳转到专题页',

`delete_time` int(10) unsigned NOT NULL,

`update_time` int(10) unsigned NOT NULL,

`banner_id` int(10) unsigned NOT NULL COMMENT '关联banner表',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------

-- Records of `y1611_banner_item`

-- ----------------------------

BEGIN;

INSERT INTO `y1611_banner_item` VALUES ('1', '1', '', '1', '0', '0', '1'), ('2', '2', '', '1', '0', '0', '1'), ('3', '3', '', '1', '0', '0', '1'), ('4', '4', '', '1', '0', '0', '1');

COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

### Banner接口定义及自定义控制器多级目录

* 创建Banner.php控制器 application/api/controller/v1/Banner.php

/**

* 获取指定id的banner数据

* @param $id 那个地方的banner,目前只有首页

* @url /banner/:id

* @http GET

*/

public function getBanner($id){

}

* 定义路由 application/router.php

Route::get('banner/:id','api/v1.Banner/getBanner');

### Validate:验证机制

#### 方式一:独立验证

* 控制器中引入 use think\Validate

* 代码

//定义验证规则

$validate = new Validate(([

'name'=>'require|max:10',

'email'=>'email'

]));

//执行验证

$result = $validate->check($data);

var_dump($result);

//获取验证错误信息

echo $validate->getError();

//批量验证

$result = $validate->batch()->check($data);

var_dump($result);

var_dump($validate->getError());

#### 方式二:验证器

* 创建文件夹:application/api/validate

* 创建文件: application/api/validate/TestValidate.php

* TestValiate 需要继承 Validate类

use think\Validate;

class TestValidate extends Validate

{

protected $rule = [

'name'=>'require|max:10',

'email'=>'email'

];

}

* 在控制器 Banner/valid 中使用

//2 验证器的使用

$validate = new TestValidate();

$result = $validate->batch()->check($data);

var_dump($result);

var_dump($validate->getError());

#### 自定义验证规则

* 新建 application/api/validate/IntCheck.php

use think\Validate;

class IntCheck extends Validate

{

protected $rule = [

'id'=>'require|intPositive'

];

protected function intPositive($value,$rule,$data,$field=''){

if(is_numeric($value)&& is_int($value+0)&&($value+0)>0){

return true;

}else{

return $field.'必须是正整数';

}

}

}

* 使用 application/api/controller/v1/Banner.php/valid

public function valid(Request $request){

//3 自定义校验规则

$validate = new IntCheck();

$data = [

'id'=>$request->param('id')

];

$result = $validate->batch()->check($data);

var_dump($result);

var_dump($validate->getError());

}

### 构建接口参数校验

* 创建 application/api/validate/BaseValidate.php

namespace app\api\validate;

use think\Exception;

use think\Request;

use think\Validate;

class BaseValidate extends Validate

{

public function goCheck(){

//1.获取http请求参数

$params = Request::instance()->param();

//2. 执行校验

$result = $this->check($params);

//3. 抛出异常或通过

if(!$result){

$error = $this->error;

throw new Exception($error);

}else{

return true;

}

}

}

* IntCheck 类去继承 BaseValidate

class IntCheck extends BaseValidate

{

protected $rule = [

'id'=>'require|intPositive'

];

protected function intPositive($value,$rule,$data,$field=''){

if(is_numeric($value)&& is_int($value+0)&&($value+0)>0){

return true;

}else{

return $field.'必须是正整数';

}

}

}

* 在控制器Banner中使用

//4. 验证层

(new IntCheck())->goCheck();

$cid = 123;

echo $cid;

---

### REST 与 RESTFul api的设计

> Representational State Transfer: 表述性状态转移

> SOAP Simple Object Access Protocol: 简单对象访问协议,使用XML描述数据

* RESTFul api:基于REST的API设计理念,通常使用JSON描述数据,无状态

* 基于资源,增删改查都只是对于资源状态的改变

* 使用HTTP动词来操作资源

* RESTFul API规范示例

/getGoods/:gid 错

GET: /goods/:gid 对

---

### RESTFul API最佳实践

* POST:创建

* PUT: 更新

* GET: 查询

* DELETE: 删除

#### 状态码:404、400、200、201、202、401(未授权)、403、500(服务器未知错误)

#### 错误码:自定义的错误ID号

#### 统一描述错误:错误码、错误信息、当前URL

return ['code'=>200,'error_code'=>10000,'msg'=>'服务器错误',url:'localhost']

#### 使用Token令牌来授权和验证用户身份

#### 版本控制

#### 测试与生产环境开发:

api.xxx.com

dev.api.xxx.com

#### URL语义要明确,最好可以"望文知意"

#### 最好有一份比较标准的文档

---

#### 学习RESTFul API的最佳方式

* 模仿: 比如豆瓣开放API\Github开发者API

---

### 正确处理异常处理流程

* 创建模型: application/api/model/Banner.php

namespace app\api\model;

class Banner

{

public static function getBannerById($id){

//TODO 根据id获取banner信息

return 'banner info';

}

}

### 传统方式的异常处理,一层一层抛出

* api/model/Banner.php

namespace app\api\model;

use think\Exception;

class Banner

{

public static function getBannerById($id){

//TODO 根据id获取banner信息

try{

1/0;

}catch(Exception $e){

throw $e;

return 'banner info';

}

}

}

* api/controller/v1/Banner.php

public function getBanner($id){

(new IntCheck())->goCheck();

try{

$banner = BannerModel::getBannerById($id);

}catch(Exception $e){

$errors = [

'code'=>500,

'error_code'=>10000,

'msg'=>$e->getMessage()

];

return json($errors,500);

}

return $banner;

}

#### 异常分类

* 由于用户行为导致的异常(没有通过验证、没有查询到结果):需要向用户返回具体信息,不需要记录日志

* 服务器自身异常(代码错误、调用外部接口错误):记录日志,不向客户端返回具体信息

#### 全局异常处理

* application/lib/exception/ExceptionHandler.php :自定义的全局异常处理类,到时让thinkphp的异常处理类从默认的变为这个类

> 修改 config.php

'exception_handle' => 'app\lib\exception\ExceptionHandler'

namespace app\lib\exception;

use think\Exception;

use think\exception\Handle;

use think\Request;

class ExceptionHandler extends Handle

{

private $code;

private $error_code;

private $msg;

//还需要返回客户端当前请求的url路径

//覆盖默认的异常处理的方法。所有的异常都通过它来处理

public function render(Exception $e){

//如果是BaseException 那么需要返回具体错误信息给客户端

if($e instanceof BaseException){

//处理自定义异常

$this->code = $e->code;

$this->msg = $e->msg;

$this->error_code = $e->error_code;

}else{

$this->code = 500;

$this->msg = '服务端错误';

$this->error_code = 999;

}

$request = Request::instance();

$res = [

'error_code'=>$this->error_code,

'msg'=>$this->msg,

'url'=>$request->url()

];

return json($res,$this->code);

}

}

* application/lib/exception/BaseException.php

namespace app\lib\exception;

use think\Exception;

class BaseException extends Exception

{

//http 状态码 404 200

public $code=400;

//错误信息

public $msg='参数错误';

//自定义的错误码

public $error_code=10000;

//请求的api路径

public $url;

}

* application/lib/exception/BannerMissException.php banner未找到异常类

namespace app\lib\exception;

class BannerMissException extends BaseException

{

public $code = 404;

public $msg = '请求的banner不存在';

public $error_code = 40000;

}

* 执行自定义异常: controller/v1/Banner.php

public function getBanner($id){

(new IntCheck())->goCheck();

$banner = BannerModel::getBannerById($id);//当$banner = null 时,未找到。则抛出 BannerMissException异常

if(!$banner){

throw new BannerMissException();

}

return $banner;

}

#### error_code

* 999 未知错误

* 1 开头为通用错误

* 2 商品类错误

* 3 主题类错误

* 4 Banner类错误

* 5 类目类错误

* 6 用户类错误

* 7 订单类错误

---

* 10000 通用参数错误

* 10001 资源未找到

* 10002 未授权(令牌不合法)

* 10003 尝试非法操作(自己的令牌尝试操作其他人的数据)

* 10004 授权失败(第三方应用账号登录失败)

* 10005 授权失败(服务器缓存异常)

---

* 20000 请求商品不存在

* 30000 请求主题不存在

* 40000 banner不存在

* 50000 类目不存在

* 60000 用户不存在

* 60001 用户地址不存在

* 80000 订单不存在

* 80001 订单中的商品不存在,可能被删除

* 80002 订单还未支付,却尝试发货

* 80003 订单已支付过

#### 在服务器异常中加入 记录日志功能

* 关闭系统默认的记录日志功能 config.php type=> File 改为 test

'log' => [

// 日志记录方式,内置 file socket 支持扩展

'type' => 'test',

// 日志保存目录

'path' => LOG_PATH,

// 日志记录级别

'level' => [],

],

* 在入口文件 index.php 中指定日志记录的目录

define('LOG_PATH',__DIR__.'');

* 在ExceptionHandler类中定义私有方法,用来记录日志

private function logRecord($e){

//重新开启记录日志功能

Log::init([

'type' => 'File',

// 日志保存目录

'path' => LOG_PATH,

// 日志记录级别

'level' => ['error']

]);

Log::record($e->getMessage(),'error');

}

* 在render方法中调用

else{

$this->code = 500;

$this->msg = '服务端错误';

$this->error_code = 999;

//调用记录日志方法

$this->logRecord($e);

}

#### 加入开关,当上线时使用自定义的异常处理,当调试时使用tp默认的异常处理

* 由于tp5 app_debug 配置项上线时会关闭,所以使用他作为开关变量即可

* 修改ExceptionHandler

public function render(Exception $e){

//如果是BaseException 那么需要返回具体错误信息给客户端

if($e instanceof BaseException){

//处理自定义异常

$this->code = $e->code;

$this->msg = $e->msg;

$this->error_code = $e->error_code;

}else{

if(config('app_debug')){

return parent::render($e);

}else{

$this->code = 500;

$this->msg = '服务端错误';

$this->error_code = 999;

$this->logRecord($e);

}

}

$request = Request::instance();

$res = [

'error_code'=>$this->error_code,

'msg'=>$this->msg,

'url'=>$request->url()

];

return json($res,$this->code);

}

#### 增加参数异常处理类 lib/exception/ParamException.php

namespace app\lib\exception;

use think\Exception;

class ParamException extends Exception

{

public $code = 400;

public $error_code = '10000';

public $msg = '参数错误';

}

#### 修改BaseValidate中的 goCheck方法

public function goCheck(){

//1.获取http请求参数

$params = Request::instance()->param();

//2. 执行校验

$result = $this->check($params);

//3. 抛出异常或通过

if(!$result){

$e = new ParamException();

$e->msg = $this->error;

throw $e;

//$error = $this->error;

//throw new Exception($error);

}else{

return true;

}

}

一键复制

编辑

Web IDE

原始数据

按行查看

历史

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值