成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

我所理解的接口設(shè)計(jì)

taoszu / 2689人閱讀

摘要:前言自己做接口開發(fā)的時(shí)間也算不短了三年,想寫這篇文章其實(shí)差不多已經(jīng)有一年多的時(shí)間了。

前言

自己做接口開發(fā)的時(shí)間也算不短了(三年),想寫這篇文章其實(shí)差不多已經(jīng)有一年多的時(shí)間了。我將從下面的方向來對我所理解的接口設(shè)計(jì)做個(gè)總結(jié):

接口參數(shù)定義 -> 接口版本化的問題 -> 接口的安全性 -> 接口的代碼設(shè)計(jì) -> 接口的可讀性 -> 接口文檔 -> 我遇到的坑
接口參數(shù)定義

接口設(shè)計(jì)中往可以抽象出一些新的公共參數(shù),從事了近三年的接口開發(fā)工作中,我目前能想到了一些較為常見的公共接口參數(shù)如下:

公共參數(shù) 含意 定義該參數(shù)的意義
timestamp 毫秒級時(shí)間戳 1.客戶端的請求時(shí)間標(biāo)示 2.后端可以做請求過期驗(yàn)證 3.該參數(shù)參與簽名算法增加簽名的唯一性
app_key 簽名公鑰 簽名算法的公鑰,后端通過公鑰可以得到對應(yīng)的私鑰
sign 接口簽名 通過請求的參數(shù)和定義好的簽名算法生成接口簽名,作用防止中間人篡改請求參數(shù)
did 設(shè)備ID 設(shè)備的唯一標(biāo)示,生成規(guī)則例如android的mac地址的md5和ios曾今udid(目前無法獲取)的md5, 1:數(shù)據(jù)收集 2.便于問題追蹤 3.消息推送標(biāo)示
接口版本化的問題

接口設(shè)計(jì)中有個(gè)算是歷史上的難題 -> 接口版本化。曾經(jīng)也去調(diào)研了很多關(guān)于接口版本化的資料和設(shè)計(jì),最后我得到的結(jié)論大致如下:

接口的版本區(qū)分為

大版本

原則:大版本的數(shù)量最多控制到5個(gè)以內(nèi)(我個(gè)人跟傾向于3個(gè)),超過版本限制的版本提示升級到新版本

方案

uri攜帶版本號(hào),例如:v1/user/get

請求參數(shù),例如:user/get?v=1.0

小版本

原則:自己把控吧?

方案

uri攜帶版本號(hào),例如:v1/user/get_01

請求參數(shù),小數(shù)點(diǎn)右邊就是小版本,例如:user/get?v=1.1

接口的安全性

接口的設(shè)計(jì)肯定繞不開安全這兩個(gè)字,為了達(dá)到盡可能的安全,我們需要盡可能的增加被攻擊的難度,以下是我了解和使用到的一些常見的手段去增加接口的安全性(https這里就不討論了):

過期驗(yàn)證/簽名驗(yàn)證/重放攻擊/限流/轉(zhuǎn)義

偽代碼如下:

// 過期驗(yàn)證
if (microtime(true)*1000 - $_REQUEST["timestamp"] > 5000) {
    throw new Exception(401, "Expired request");
}
// 簽名驗(yàn)證(公鑰校驗(yàn)省略)
$params = ksort($_REQUEST);
unset($params["sign"]);
$sign = md5(sha1(implode("-", $params) . $_REQUEST["app_key"]));
if ($sign !== $_REQUEST["sign"]) {
    throw new Exception(401, "Invalid sign");
}
/**
 * 重放攻擊
 * @params noise string 隨機(jī)字符串或隨機(jī)正整數(shù),與 Timestamp 聯(lián)合起來, 用于防止重放攻擊 例如騰訊云是6位隨機(jī)正整數(shù)
 */
$key = md5("{$_REQUEST["REQUEST_URI"]}-{$_REQUEST["timestamp"]}-{$_REQUEST["noise"]}-{$_REQUEST["did"]}");
if ($redisInstance->exists($key)) {
    throw new Exception(401, "Repeated request");
}
// 限流
$key = md5("{$_REQUEST["REQUEST_URI"]}-{$_REQUEST["REMOTE_ADDR"]}-{$_REQUEST["did"]}");
if ($redisInstance->get($key) > 60) {
    throw new Exception(401, "Request limit");
}
$redisInstance->incre($key);
// 轉(zhuǎn)義
$username = htmlspecialchars($_REQUEST["username"]);
接口的代碼設(shè)計(jì) -> 解耦業(yè)務(wù) 即插即用
這個(gè)過程的關(guān)鍵字:抽象成類 前置中間件 注入

接著就是我們代碼設(shè)計(jì)的層面了,如何抽象公共的部分與業(yè)務(wù)代碼解耦。

一般寫法, 定義個(gè)全局函數(shù),然后每個(gè)接口開始時(shí)調(diào)用該函數(shù):

// 全局定義一個(gè)函數(shù)
function check () {
    // 校驗(yàn)公共參數(shù)
    # code ...
    // 校驗(yàn)簽名
    # code ...
    // 校驗(yàn)頻率
    # code ...
    // 等等...
}

二般寫法, 定義個(gè)父類方法,然后每個(gè)接口類繼承該接口,構(gòu)造函數(shù)調(diào)用改方法,其實(shí)和上面的換湯不換藥:

// 父類方法

class father
{
    public function __construct()
    {
        $this->check();
    }

    public function check () {
        // 校驗(yàn)公共參數(shù)
        # code ...
        // 校驗(yàn)簽名
        # code ...
        // 校驗(yàn)頻率
        # code ...
        // 等等...
    }
}

重點(diǎn)來了,我提倡的第三般寫法,對象鏈和前置中間件:

/**
 * 檢驗(yàn)抽象類
 */
abstract class Check
{
    /**
     * 下一個(gè)check實(shí)體
     *
     * @var object
     */
    private $nextCheckInstance;
    
    /**
     * 校驗(yàn)方法
     *
     * @param Request $request 請求對象
     */
    abstract public function operate(Request $request);

    /**
     * 設(shè)置責(zé)任鏈上的下一個(gè)對象
     *
     * @param Check $check
     */
    public function setNext(Check $check)
    {
        $this->nextCheckInstance = $check;
        return $check;
    }

    /**
     * 啟動(dòng)
     *
     * @param Request $request 請求對象
     */
    public function start(Request $request)
    {
        $this->operate($request);
        // 調(diào)用下一個(gè)對象
        if (! empty($this->nextCheckInstance)) {
            $this->nextCheckInstance->start($request);
        }
    }
}

// 校驗(yàn)公共參數(shù)類
class ParamsCheck extends Check
{
    public function operate()
    {
       // 校驗(yàn)公共參數(shù)
        # code ... 
    }
}

// 校驗(yàn)簽名類
class SignCheck extends Check
{
    public function operate()
    {
       // 校驗(yàn)簽名
        # code ... 
    }
}

// 等等...

// 前置中間件類
class FrontMiddleware
{
    public function run()
    {
        // 初始化一個(gè):必傳參數(shù)校驗(yàn)的check
        $checkParams   =  new ParamsCheck();
        // 初始化一個(gè):簽名check
        $checkSign     =  new SignCheck();
        // 初始化一個(gè):頻率check
        $checkFrequent =  new FrequentCheck();
        // 等等...

        // 構(gòu)成對象鏈
        $checkParams->setNext($checkSign)
                    ->setNext($checkFrequent)
                    ...
        // 啟動(dòng)
        $checkParams->start();
    }
}
接口的可讀性

關(guān)于可讀性的不得不提到的就是RESTFUL,這里我就不討論RESTFUL,大家可以自行補(bǔ)充相關(guān)知識(shí)。關(guān)于接口設(shè)計(jì)可讀性的我的一些思考:

url

非RESTFUL: 資源/資源/操作(動(dòng)詞), 例如 content/article/get -> 獲取內(nèi)容資源下的一篇文章資源

RESTFUL: 資源/資源/資源, 例如 get content/article/1 -> 獲取內(nèi)容資源下文章ID為1的文章資源

method

非RESTFUL: get便于查nginx日志,上傳資源post, 沒啥硬性要求

RESTFUL: 符合RESTFUL的思想

request params: 個(gè)人更青睞于下劃線命名,適當(dāng)?shù)膯卧~縮寫

response params: 響應(yīng)的code要符合http status

200 -> 正常

400 -> 缺少公共必傳參數(shù)或者業(yè)務(wù)必傳參數(shù)

401 -> 接口校驗(yàn)失敗 例如簽名

403 -> 沒有該接口的訪問權(quán)限

499 -> 上游服務(wù)響應(yīng)時(shí)間超過接口設(shè)置的超時(shí)時(shí)間

500 -> 代碼錯(cuò)誤

501 -> 不支持的接口method

502 -> 上游服務(wù)返回的數(shù)據(jù)格式不正確

503 -> 上游服務(wù)超時(shí)

504 -> 上游服務(wù)不可用

// 響應(yīng)的格式
{
    "code": 200,
    "msg": "ok",
    "data": {

    }
}
接口文檔

好的接口文檔就是生產(chǎn)力, swagger + api blueprint 自行g(shù)oogle吧?

我遇到的坑

這里遇到的一個(gè)比較大的坑就是http協(xié)議歷史遺留的bug:

不區(qū)分url里的空格 和加號(hào)?

帶來的問題就是urldecode會(huì)把參數(shù)里的+號(hào)轉(zhuǎn)為空格,所以這種場景的就得使用rawurldecode防止+轉(zhuǎn)成空格。比如做接口的參數(shù)校驗(yàn)的時(shí)候~

掃面下方二維碼關(guān)注我的技術(shù)公眾號(hào),及時(shí)為大家推送我的原創(chuàng)技術(shù)分享

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/28399.html

相關(guān)文章

  • 談?wù)?em>我所理解面向?qū)ο?/b>

    摘要:眾多面向?qū)ο蟮木幊趟枷腚m不盡一致,但是無論哪種面向?qū)ο缶幊陶Z言都具有以下的共通功能。原型編程以類為中心的傳統(tǒng)面向?qū)ο缶幊?,是以類為基礎(chǔ)生成新對象。而原型模式的面向?qū)ο缶幊陶Z言沒有類這樣一個(gè)概念。 什么是面向?qū)ο螅窟@個(gè)問題往往會(huì)問到剛畢業(yè)的新手or實(shí)習(xí)生上,也是往往作為一個(gè)技術(shù)面試的開頭題。在這里我們不去談如何答(fu)好(yan)問(guo)題(qu),僅談?wù)勎宜斫獾拿嫦驅(qū)ο蟆?從歷...

    avwu 評論0 收藏0
  • 我所理解簡單項(xiàng)目結(jié)構(gòu)

    摘要:將圖片都放入文件夾下指定公共的名字。匹配刪除的文件根目錄開啟在控制臺(tái)輸出信息啟用刪除文件插入開關(guān)說一些可能沒用的站在前端角度不懂的很多很多時(shí)候一個(gè)項(xiàng)目都是由一個(gè)小組完成的,小組成員可能包括產(chǎn)品,前端,后端,測試,運(yùn)營等等。 不急,先聽我嘮會(huì)嗑~ 隨著js發(fā)展的如此迅速,市場上越來越多的前端框架可以方便開發(fā)者使用。 本人大四渣渣一名,先后實(shí)習(xí)了兩個(gè)地方,第一家公司用vuejs,實(shí)話...

    _DangJin 評論0 收藏0
  • RESTful實(shí)踐(具體應(yīng)用)思考

    摘要:其他交互一般會(huì)遵循一些數(shù)據(jù)結(jié)構(gòu)協(xié)議或者狀態(tài)值,比如不同的操作結(jié)果對應(yīng)不同的狀態(tài)值,且出錯(cuò)會(huì)返回指定的錯(cuò)誤信息方便前端進(jìn)行提示等。 RESTful這種架構(gòu)已經(jīng)具有很長的時(shí)間和歷程了,但似乎最近restful這個(gè)詞出現(xiàn)的頻率特別高,目前不是很清楚是因?yàn)槲易詡€(gè)兒現(xiàn)在是以restful風(fēng)格寫程序產(chǎn)生的孕婦效應(yīng),還是單頁面程序開發(fā)的流行造成的。 其實(shí)一開始我也是不想寫這篇文章的,因?yàn)榫W(wǎng)絡(luò)上與re...

    myshell 評論0 收藏0
  • 簡述我所理解 PHP Trait

    摘要:和組合的語義定義了一種減少復(fù)雜性的方式,避免傳統(tǒng)多繼承和類相關(guān)典型問題。隊(duì)列的目的是將耗時(shí)的任務(wù)延時(shí)處理,比如發(fā)送郵件,從而大幅度縮短請求和相應(yīng)的時(shí)間。同樣的道理,根據(jù)引入不同的來完成對應(yīng)的功能。 showImg(https://segmentfault.com/img/remote/1460000010868178); Trait 概念 在常規(guī)的 PHP 開發(fā)中,我們都習(xí)慣于先編寫一...

    gecko23 評論0 收藏0
  • 我所理解模板方法模式

    摘要:定義在父類中定義處理流程的框架,在子類中實(shí)現(xiàn)具體處理的模式就稱為模板方法模式參與角色抽象類抽象類不僅負(fù)責(zé)實(shí)現(xiàn)模板方法,還負(fù)責(zé)聲明在模板方法中所使用到的抽象方法。 定義 在父類中定義處理流程的框架,在子類中實(shí)現(xiàn)具體處理的模式就稱為模板方法模式 參與角色 抽象類(AbstractClass) 抽象類不僅負(fù)責(zé)實(shí)現(xiàn)模板方法,還負(fù)責(zé)聲明在模板方法中所使用到的抽象方法。 具體類(子類) 該角色負(fù)責(zé)...

    Y3G 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<