一、接口编程
1、背景
随着互联网的发展,尤其是移动互联网为代表的Web3.0时代,客户端层出不穷,以APP、微信、PC浏览器为代表,服务端业务逻辑基本一致的,那么有没有一种方式可以做到“服务端一次编写,客户端随时接入”呢 流行的方案就是“接口编程”
2、接口编程
API(Application Programming Interface,应用程序编程接口),程序之间交互数据的一种方式。 以浏览器和服务器之间的数据交互(ajax请求)为例:
请求方式:get方式 post方式 请求协议:http协议 https协议 返回参数:普通字符串、json格式、xml格式,现在通用的是json格式。
二、RESTFul设计风格
1、Rest与RestFul
REST(英文:Representational State Transfer,简称REST),表述性状态转移,指的是一组架构原则。 Restful:遵守了rest原则的web服务或web应用。
2、API设计六要素
资源路径(URI)、HTTP动词(Mrthod)、过滤信息(query-string)、状态码(Status-code)、错误信息(Error)、返回结果(Result)
1、资源路径URI
资源:所有在服务器保存的数据(如:音乐/视频/文章/个人信息。。。)都是服务器资源。 URI(Uniform Resource Identifier)/统一资源标志符,包括URL和URN。 URL(Uniform Resource Locator):统一资源定位符。 URN(Uniform Resource Name):统一资源命名
在HTTP协议中,URI的组成如下 Schema://host[:port]/path[?query-string] Schema:使用的协议类型,如http/https/ftp等 host:主机域名或IP port:端口号(可选) path:路径 query-string:查询参数(可选) 例子: http://www.tpshop.com/users https://www.tpshop.com:8080/users?id=100
2、HTTP动词(请求方式)
对于资源,一般有四个操作,CURD(增、删、改、查) GET:从服务器获取资源(一项或多项) POST:在服务器新建一个资源 PUT:在服务器更新资源,服务器返回完整的属性 DELETE:从服务器删除资源
3、过滤信息
通常也叫做请求参数或查询字符串
4、响应状态码
服务端返回的信息,用来告诉客户端操作结果 常见状态码:
状态码 | 含义 | 说明 |
---|
200 | OK | 操作成功,并返回数据 | 201 | CREATED | 新建成功 | 204 | No CONTENT | 删除成功 | 400 | BAD REQUEST | 请求语法错误 | 403 | Forbidden | 请求没有权限的资源 | 404 | NOT FOUND | 没有找到请求的资源 |
GET 200(ok)-表示已在响应中发出 204(无内容)-资源有空表示 301(Moved Permanently)-资源的URI已被更新 303 (See Other)-其他(如,负载均衡) 304 (not Modified)-资源未更改(缓存) 400 (bad request)-指代坏请求(如,参数错误) 404 (not found)-资源不存在 406(not acceptable)-服务端不支持所需展示 500 (internal server error) -通用错误响应 503 (Service Unavaifable) -服务端当前无法处理请求
POST 200(ok)-如果现有资源已被更改 201(created)-如果新资源被创建 202 ( accepted)-已接受处理请求但尚未完成(异步处理) 301(Moved Permanently)-资源的URI被更新 303 (See Other)-其他(如,负载均衡) 400 (bad request)-指代坏请求(如,参数错误) 404 (not found)-资源不存在 406(not acceptable)-服务端不支持所需展示 409(conflict)-通用冲突 412 (Precondition Failed)-前置条件失败(如执行条件更新时的冲突) 415(unsupported media type)-接收到的表示不受支持 500 (internal server error) -通用错误响应 503 (Service Unavaifable) -服务端当前无法处理请求
PUT 200(ok)-如果现有资源已被更改 201(created)-如果新资源被创建 301(Moved Permanently)-资源的URI被更新 303 (See Other)-其他(如,负载均衡) 400 (bad request)-指代坏请求(如,参数错误) 404 (not found)-资源不存在 406(not acceptable)-服务端不支持所需展示 409(conflict)-通用冲突 412 (Precondition Failed)-前置条件失败(如执行条件更新时的冲突) 415(unsupported media type)-接收到的表示不受支持 500 (internal server error) -通用错误响应 503 (Service Unavaifable) -服务端当前无法处理请求
DELETE 200(ok)-资源已被删除 301(Moved Permanently)-资源的URI被更新 303 (See Other)-其他(如,负载均衡) 400 (bad request)-指代坏请求(如,参数错误) 404 (not found)-资源不存在 409(conflict)-通用冲突 500 (internal server error) -通用错误响应 503 (Service Unavaifable) -服务端当前无法处理请求
5、错误信息
如果状态码是4xx或者5xx,需要告诉客户端对应的错误信息,通常以json格式返回:{“error”:“错误信息”;}
6、返回结果
针对不同的操作,服务端需要返回的结果应该符合这样的规范 GET/collections–返回资源列表(数组) GET/collections/:id --返回单个资源 eg./collections/1 POST/collections --返回新的资源 PUT/collections/:id --返回资源的完整属性 DELETE/collections/:id --返回204状态码+空文档
3、RestFul接口设计风格
RESTFul是一种软件设计风格,主要用于有客户端与服务端交互的软件 RESTFul是目前最流行的API设计规范,用于web数据接口的设计
RESTFul风格的数据接口示例: 以新闻资源为例:URI及HTTP动词设计如下
HTTP动词 | URI路径 | 说明 |
---|
GET | http://域名/news | 获取列表数据 | GET | http://域名/news/:id | 根据id获取一条数据 | POST | http://域名/news | 添加一条数据 | PUT | http://域名/news/:id | 根据id修改一条数据 | DELETE | http://域名/news/:id | 根据id删除一条数据 |
三、RestFul实战
1、TP框架中的资源路由
手册-路由-资源路由 手册-控制器-资源控制器 1、创建api模块
php think build --module api
2、创建news控制器
php think make:controller api/News
3、设置路由(application/route.php)’
\think\Route::resource('news','api/news');
相当于设置了以下路由
\think\Route::get('news','api/news/index');
\think\Route::get('news/create','api/news/create');
\think\Route::post('news','api/news/save');
\think\Route::get('news/:id','api/news/read');
\think\Route::get('news/:id/edit','api/news/edit');
\think\Route::put('news/:id','api/news/update');
\think\Route::delete('news/:id','api/news/delete');
设置后会自动注册7个路由规则,如下:
标识 | 请求类型 | 生成路由规则 | 对应操作方法(默认) |
---|
index | GET | news | index | create | GET | news/create | create | save | POST | news | save | read | GET | news /:id | read | edit | GET | news/:id/edit | edit | update | PUT | news/:id | update | delete | DELETE | news/:id | delete |
4、修改News控制器,返回json格式数据
<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
class News extends Controller
{
public function index()
{
$res=['code'=>200,'msg'=>'success','data'=>'index'];
return json($res);
}
public function create()
{
$res=['code'=>200,'msg'=>'success','data'=>'create'];
return json($res);
}
public function save(Request $request)
{
$res=['code'=>200,'msg'=>'success','data'=>'save'];
return json($res);
}
public function read($id)
{
$res=['code'=>200,'msg'=>'success','data'=>'read'];
return json($res);
}
public function edit($id)
{
$res=['code'=>200,'msg'=>'success','data'=>'edit'];
return json($res);
}
public function update(Request $request, $id)
{
$res=['code'=>200,'msg'=>'success','data'=>'update'];
return json($res);
}
public function delete($id)
{
$res=['code'=>200,'msg'=>'success','data'=>'delete'];
return json($res);
}
}
通过postman分别访问以下七个地址:
请求方式 请求地址
get http://www.tpshop.com/news
get http://www.tpshop.com/news/create
post http://www.tpshop.com/news
get http://www.tpshop.com/news/33
get http://www.tpshop.com/news/33/edit
put http://www.tpshop.com/news/33
delete http://www.tpshop.com/news/33
2、ajax请求restful接口
public目录下,创建测试文件api.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax请求restful接口</title>
<script src="/static/admin/js/jquery-1.8.1.min.js"></script>
</head>
<body>
<input type="button" id="index" value="index">
<input type="button" id="create" value="create">
<input type="button" id="save" value="save">
<input type="button" id="read" value="read">
<input type="button" id="edit" value="edit">
<input type="button" id="update" value="update">
<input type="button" id="delete" value="delete">
<script>
$(function(){
$('#index').click(function(){
$.ajax({
"url":"/news",
"type":"get",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
});
$('#create').click(function(){
$.ajax({
"url":"/news/create",
"type":"get",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
$('#save').click(function(){
$.ajax({
"url":"/news",
"type":"post",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
$('#read').click(function(){
$.ajax({
"url":"/news/33",
"type":"get",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
$('#edit').click(function(){
$.ajax({
"url":"/news/33/edit",
"type":"get",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
});
$('#update').click(function(){
$.ajax({
"url":"news/33",
"type":"put",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
$('#delete').click(function(){
$.ajax({
"url":"news/33",
"type":"delete",
"data":"",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
})
</script>
</body>
</html>
3、请求伪装
部分客户端(比如低版本浏览器)可能仅支持get请求、post请求、不支持delete请求和put请求。 TP框架提供了对“请求伪装”的支持,可以使用post请求携带_method参数,伪装成其他请求。 比如 使用ajax的post请求伪装put请求 public/api.html中添加以下代码
$('#post-to-update').click(function(){
$.ajax({
"url":"news/33",
"type":"post",
"data":"_method=put",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
$('#post-to-delete').click(function(){
$.ajax({
"url":"news/33",
"type":"post",
"data":"_method=delete",
"dataType":"json",
"success":function(res){
console.log(res);
}
})
})
4、Restful常用的资源路由
新增页面展示create方法和修改页面edit方法一般可以不用。
标识 | 请求类型 | 生成路由规则 | 对应操作方法(默认) | 备注 |
---|
index | GET | news | index | 查询多条数据(列表) | read | GET | news/:id | read | 查询一条数据(详情、修改页面展示) | save | POST | news | save | 新增一条数据 | update | PUT | news/:id | update | 修改一条数据 | delete | DELETE | news/:id | delete | 删除一条数据 |
5、实际开发中的Restful
Restful接口通常返回的是完整的数据模型,粒度过于粗,对客户端不友好(客户端可能只需要其中一小部分字段)。
Restful典型使用场景:开放API(各种开放平台的数据api)。开放API之所以开放,就是因为不知道也不关心客户端需要什么返回结果。直接返回完整的数据,好处是通用。
实际开发中,通常都是内部接口开发,需求非常明确,所以一般都是灵活借鉴Restful中的优点,结合自己的实际情况,来设计自己的内部api,在基本的增删改查接口之外,通常会设计一些业务接口(根据业务逻辑需要,一个接口中对多个资源的数据进行整合再返回。)
四、服务端CURL请求
服务端与服务端之间,也存在接口编程 比如我们网站服务端,需要发送短信、发送邮件、查询快递等,都需要调用第三方平台的接口。
1、php中发送请求
1、file_get_contents函数:传递完整的url参数 通常是get请求,有返回值(地址中的输出)。 2、curl请求方式(PHP的curl函数库):php中比较规范的一种发送请求方式。
2、CURL函数库
Curl函数库的使用流程: 1、使用curl_init初始化请求会话 2、使用curl_setopt设置请求一些选项 3、使用curl_exec执行,发送请求 4、使用curl_close关闭请求会话
3、封装请求函数
封装一个函数用来发送curl请求 在application/common.php中封装一个函数curl_request 使用curl函数库的前提: 1、在php.ini中开启php_curl扩展(必须开启)
2、建议在php.ini中开启php_openssl扩展(本身不是curl必须的,是调用一些第三方接口需要的)
3、如果以上操作重启apache后,curl还是不能用,需要将php安装目录设置到环境变量。
代码封装:application/common.php
if(!function_exists('curl_request')){
function curl_request($url,$type=false,$params=[],$https=false){
$ch= curl_init($url);
if($type){
curl_setopt($ch,CURLOPT_POST,true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$params);
}
if($https){
curl_setopt($ch,CURLOPT_PROXY_SSL_VERIFYPEER,true);
}
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$res=curl_exec($ch);
curl_close($ch);
return $res;
}
}
测试结果:
5、curl请求错误调试
curl_errno函数返回错误码 curl_error函数返回错误信息
public function testrequest(){
$url="http://www.tpshop.com/api/index/testapi";
$params=['id'=>100,'page'=>10];
$res=curl_request($url,true,$params);
if(!$res){
echo '请求错误';die;
}
$arr=json_decode($res,true);
dump($arr['data']);
dump($res);die;
}
五、快递查询
1、接口说明
提供快递查询的第三方平台很多,比如快递100、聚合数据、百度云、阿里云、腾讯云等等。
2、项目使用
public function kuaidi(){
$url='http://www.kuaidi.com/index-ajaxselectcourierinfo--.html';
$res=curl_request($url);
if(!$res){
echo '请求错误';die;
}
$arr=json_decode($res,true);
if($arr['success']==false){
echo $arr['reason'];die;
}
$list=$arr['data'];
echo '时间-------------进度<br>';
foreach ($list as $v){
echo $v['time'],'----------',$v['context'],'<br>';
}
die;
}
六、接口文档
1、接口内容
接口名称 场景说明 接口说明 请求参数 响应参数 错误码
2、请求参数内容
字段名 是否必填 类型 示例值 描述
3、响应参数内容
字段名称 描述 返回示例
4、错误码内容
名称 描述 原因 解决方案
5、示例
1.2、登录接口
1、请求地址
post/login 用于根据用户名,密码进行登录 示例:http://api.baidu.com/login
2、请求参数
名称 | 类型 | 必填 | 备注 |
---|
username | string | 是 | 用户名:admin | password | string | 是 | 密码:123456 | code | string | 是 | 验证码 | uniqid | string | 是 | 验证码标识 |
3、返回数据
名称 | 备注 |
---|
token | token令牌 | user_id | 用户id | username | 用户名 | nickname | 用户昵称 | email | 用户邮箱 |
4、返回示例
{
"code":200,
"msg":"success",
"data":{
"token":"admslkfnlskawjrqwwiepfe",
"user_id":"54866",
"username":"admin",
"nickname":"麦克",
"email":"674684@qq.com"
}
}
5、改造之前的商品保存方法
public function save2(Request $request)
{
$params = $request->param();
$rule = [
'goods_name' => 'require',
'goods_price' => 'require|float|gt:0',
'goods_number' => 'require|integer|gt:0'
];
$msg = [
'goods_name.require' => '商品名称不能为空',
'goods_price.require' => '商品价格不能为空',
'goods_price.float' => '商品价格格式不正确',
'goods_price.gt' => '商品价格必须大于0',
'goods_number.require' => '商品数量不能为空',
'goods_number.gt' => '商品数量必须大于0',
];
$validate = $this->validate($params, $rule, $msg);
if ($validate !== true) {
return json(['code'=>401,'msg'=>$validate,'data'=>[]]);
}
$params['goods_logo']=$this->upload_logo();
$data=\app\admin\model\Goods::create($params, true);
return json(['code'=>200,'msg'=>'success','data'=>$data]);
}
项目搭建流程
1、安装部署tp框架(解压压缩包、配置虚拟站点)(主域名、子域名,比如www.pyg.com和adminapi.pyg.com) 2、模块划分(后台模块admin、前台模块home、后台接口模块adminapi、公共模块common) 3、admin模块、home模块、adminapi模块、有默认的控制器方法,可以访问。common模块下只需要mode模型目录 4、路由配置:adminapi模块 配置域名路由 5、尝试,对adminapi模块,创建一个Base控制器,定义ok方法和fail方法,用于快捷返回结果数据 比如:
失败时,以下两行代码 效果一样
return json(['code'=>401,'msg'=>'参数错误','data'=>[]]);
成功时,以下两行代码 效果一样
return json(['code'=>200,'msg'=>'success','data'=>$data]);
|