# RestFul接口設計
# 一、接口編程
## 1、背景
隨著互聯網的發展, 尤其是移動互聯為代表的Web3.0時代. 客戶端層出不窮, 以APP、微信、PC瀏覽器為代表, 服務端業務邏輯是基本一致的。那么有沒有一種方式可以做到”服務端一次編寫, 客戶端隨時接入”呢?
流行的方案就是"**接口編程**"
## 2、接口編程
API(Application Programming Interface,應用程序編程接口),程序之間交互數據的一種方式。
以 瀏覽器和服務器之間的數據交互(ajax請求) 為例:
請求方式:get方式 post方式
請求協議:http協議 https協議
返回參數格式:普通字符串、json格式、xml格式,現在通用的是**json格式**
這里的接口,不是面向對象中的interface接口。
數據交互中的接口:實際上,就是通過url請求到的地址中的代碼(框架中就是一個控制器的方法)
# 二、RESTFul設計風格
## 1、Rest與RestFul
REST(英文:Representational State Transfer,簡稱REST),表述性狀態轉移,指的是一組架構原則。
Restful: 遵守了rest 原則 的web服務或web應用。
## 2、API設計六要素
資源路徑(URI)、HTTP動詞(Method)、過濾信息(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://](http://api.local.com/movies)www.tpshop.com/users
[https://www.tpshop.com:8080/users?id=100](https://api.local.com:8080/articles?id=100)
### 2)HTTP動詞(請求方式)
對于資源, 一般有4個操作, 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 Unavailable)- 服務端當前無法處理請求
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 Unavailable)- 服務當前無法處理請求
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 Unavailable)- 服務當前無法處理請求
DELETE
200 (OK)- 資源已被刪除
301 (Moved Permanently)- 資源的URI已更改
303 (See Other)- 其他,如負載均衡
400 (bad request)- 指代壞請求
404 (not found)- 資源不存在
409 (conflict)- 通用沖突
500 (internal server error)- 通用錯誤響應
503 (Service Unavailable)- 服務端當前無法處理請求
### 5)錯誤信息
如果狀態碼是4xx或者5xx, 需要告訴客戶端對應的錯誤信息. 通常以Json格式返回:
{
“error”: “錯誤信息”,
}
### 6)返回結果
針對不同的操作, 服務需要返回的結果應該符合這樣的規范
GET /collections -- 返回資源列表(數組)
GET /collections/:id -- 返回單個資源 eg. /collections/1
POST /collections -- 返回新生成的資源
PUT /collections/:id -- 返回資源的完整屬性
DELETE /collections/:id -- 返回204狀態碼+空文檔
實際開發中,通常會將 狀態碼、錯誤信息、返回數據,都放到返回結果中。
比如
```
{"code":200, 'msg':'success', "data":{"id":1,"goods_name":"tp"}}
```
## 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框架中的資源路由
手冊-路由-資源路由、手冊-控制器-資源控制器
①創建api模塊
```php
php think build --module api
```
②創建news控制器
```php
php think make:controller api/News
```
③設置路由(application/route.php)
```php
\think\Route::resource('news','api/news');
```
相當于分別設置了以下路由:
```php
\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 |
④修改News控制器,返回json格式數據
```php
<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
class News extends Controller
{
/**
* 顯示資源列表
*
* @return \think\Response
*/
public function index()
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'index']);
}
/**
* 顯示創建資源表單頁.
*
* @return \think\Response
*/
public function create()
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'create']);
}
/**
* 保存新建的資源
*
* @param \think\Request $request
* @return \think\Response
*/
public function save(Request $request)
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'save']);
}
/**
* 顯示指定的資源
*
* @param int $id
* @return \think\Response
*/
public function read($id)
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'read']);
}
/**
* 顯示編輯資源表單頁.
*
* @param int $id
* @return \think\Response
*/
public function edit($id)
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'edit']);
}
/**
* 保存更新的資源
*
* @param \think\Request $request
* @param int $id
* @return \think\Response
*/
public function update(Request $request, $id)
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'update']);
}
/**
* 刪除指定資源
*
* @param int $id
* @return \think\Response
*/
public function delete($id)
{
return json(['code' => 200, 'msg' => 'success', 'data'=>'delete']);
}
}
```
通過postman 分別訪問以下七個地址:
```php
請求方式 請求地址
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
```php
<!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中 添加以下代碼
```html
<input type="button" id="post_to_put" value="偽裝put">
<input type="button" id="post_to_delete" value="偽裝delete">
<script>
$(function(){
$('#post_to_put').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":"get",
"data":"_method=delete",
"dataType":"json",
"success":function(res){
console.log(res);
}
});
});
})
</script>
```
## 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中發送請求
①file_get_contents函數 :傳遞完整的url參數 通常是get請求,有返回值(地址中的輸出)
②curl請求方式(PHP的curl函數庫):php中比較規范的一種發送請求方式。
## 2、CURL函數庫
Curl函數庫的使用流程:
①使用curl_init初始化請求會話
②使用curl_setopt設置請求一些選項
③使用curl_exec執行,發送請求
④使用curl_close關閉請求會話
## 3、封裝請求函數
封裝一個函數用來發送curl請求
在application/common.php中封裝一個函數curl_request
使用curl函數庫的前提:
①在php.ini中開啟php_curl擴展(必須開啟)

②建議在php.ini中開啟php_openssl擴展(本身不是curl必須的,是調用一些第三方接口需要的)

③如果以上操作重啟apache后,curl還是不能使用,需要將php安裝目錄設置到環境變量。
代碼封裝:application/common.php


## 4、本地模擬測試
先準備好一個接口地址:用于請求調用

再寫一個方法,發送請求,調用之前準備好的接口

測試結果:
訪問:http://www.tpshop.com/index.php/api/index/testrequest

## 5、curl請求錯誤調試
curl_errno函數 返回錯誤碼
curl_error函數 返回錯誤信息


# 五、快遞查詢
## 1、接口說明
提供快遞查詢的第三方平臺很多,比如快遞100、聚合數據、百度云apistore、阿里云、騰訊云、京東萬象等等。
這里以聚合數據平臺為例:接口頁面:<https://www.juhe.cn/docs/api/id/43>
**接口地址:**http://v.juhe.cn/exp/index
**返回格式:**json/xml
**請求方式:**http post/get
必傳請求參數: com 快遞公司編號; no 快遞單號; key 授權key
**請求示例:**http://v.juhe.cn/exp/index?com=zto&no=73115984252335&key=ac2dde994cc76d4f15738f7f97af7ca4

## 2、項目使用
api模塊index控制器kuaidi方法
```php
public function kuaidi()
{
//接口地址
$url = "http://v.juhe.cn/exp/index?com=zto&no=73115984252335&key=ac2dde994cc76d4f15738f7f97af7ca4";
//請求方式 get post
//請求參數
$params = [
'com' => 'zto',
'no' => '73115984252335',
'key' => 'ac2dde994cc76d4f15738f7f97af7ca4'
];
//發送請求
$res = curl_request($url, true, $params);
if(!$res){
echo '請求失敗';die;
}
//解析結果
$arr = json_decode($res, true);
//查詢失敗
if($arr['resultcode'] != 200){
echo $arr['reason'];die;
}
//查詢成功,展示信息
$list = $arr['result']['list'];
echo '時間 ------------------------ 物流信息<br>';
foreach($list as $v){
echo $v['datetime'], '------------------------', $v['remark'], '<br>';
}
}
```
展示效果:

# 六、接口文檔
## 1、接口內容
**接口名稱**
場景說明
**接口說明**
**請求參數**
**響應參數**
錯誤碼
## 2、請求參數內容
字段名
是否必填
類型
示例值
描述
## 3、響應參數內容
字段名稱
描述
返回示例
## 4、錯誤碼內容
名稱
描述
原因
解決方案
## 5、示例
## 

## 6、練習(接口文檔)
將admin/controller/Goods.php中 save方法 改為 接口方式
① 將Base控制器中的登錄驗證,注釋。
② 將save方法代碼 復制到 save2方法
③將save2方法中的參數驗證規則修改(刪除 token規則, 添加 goods_logo字段的驗證)
④將\$this->error 和\$this->success部分代碼,修改為 return json()這種代碼。
⑤將文件上傳的方法調用 注釋
⑥通過postman測試save2接口
⑦ 寫接口文檔
## 7、練習(項目搭建)
1、安裝部署tp框架(解壓壓縮包、配置虛擬站點)(主域名、子域名,比如 www.pyg.com 和 adminapi.pyg.com)
2、模塊劃分(后臺模塊admin、前臺模塊home、后臺接口模塊adminapi、公共模塊common)
3、admin模塊、home模塊、adminapi模塊 有默認的控制器方法,可以訪問。 common模塊下只需要model模型目錄
4、路由配置: adminapi模塊 配置域名路由
5、嘗試,對adminapi模塊,創建一個Base控制器,定義ok方法和fail方法,用于快捷返回結果數據
比如:
```
失敗時,以下兩行代碼 效果一樣
return json(['code' => 401, 'msg' => '參數錯誤', 'data' => []]);
//$this->fail(401, '參數錯誤');
成功時,以下兩行代碼 效果一樣
return json(['code' => 200, 'msg' => 'success', 'data' => $data]);
//$this->ok($data);
```
- 辦公器材
- 辦公用品清單
- 辦公購材料
- 文檔
- 銷售文檔
- 需求確認合同
- ui合同
- 需求文檔
- 技術文檔
- 開發類文檔
- 代碼規范
- php代碼規范
- 數據字典規范
- 類庫說明
- 封裝規范
- 代碼注釋規范
- 接口文檔書寫
- 狀態碼說明
- 接口書寫規范文檔
- 工具類文檔
- 環境搭建文檔
- 常用工具使用說明
- 版本控制協同開發
- 系統鏡像
- 接口測試工具
- 雇傭文檔
- 雇傭合同
- 人力資源文檔
- 會議管理文檔
- 發文規范文檔
- 檔案管理文檔
- 車輛管理文檔
- 電腦規范文檔
- 電話使用文檔
- 交接文檔
- 崗位職責文檔
- 入職流程文檔
- 入職培訓文檔
- 員工培訓文檔
- 情報文檔
- 財務
- 質量管理文檔
- 規章制度
- 第一章:總則
- 第二章:員工日常行為規范
- 第三章 聘任管理制度
- 第四章 作息與考勤制度
- 第五章 請假制度
- 第六章 離職制度
- 第七章 ?移交制度
- 第八章 晉升制度
- 第九章 薪資制度
- 第十章 獎懲制度
- 獎勵
- 工齡獎
- 考勤獎
- 內推獎
- 年度貢獻獎
- 年度人氣獎
- 培訓獎
- 績效獎
- 部門獎
- 懲罰
- 失職
- 投訴
- 其他
- 運營途徑
- 市場調研
- seo
- 軟文
- 抖音
- 活動
- 開源代碼
- 微信qq
- 地推
- 電銷
- 第三方外包平臺
- 水軍
- 接口平臺
- 品牌
- 品牌故事
- pinpoint符號
- 吉祥物
- 品牌詞
- 廣告語
- 產品
- 工具
- 企劃書
- 企業環境
- 啟動資金
- 企業規劃書