App下載

如何設計一個看起來很牛逼的API接口

猿友 2020-09-22 11:56:03 瀏覽數 (2522)
反饋

文章來源于各種:Java旅途 作者:周明堯

在平時工作中,總會接觸到多種接口。前后端數據傳輸接口,第三方業(yè)務平臺接口。一個平臺的前后端數據傳輸接口一般都會在內網環(huán)境下通信,而且會使用安全框架,所以安全性可以得到很好的保護。這篇文章重點討論一下提供給第三方平臺的業(yè)務接口應當如何設計?我們應該考慮哪些問題?

API接口設計規(guī)范

主要從以上三個方面來設計一個安全的API接口。

一 安全性問題

安全性問題是一個接口必須要保證的規(guī)范。如果接口保證不了安全性,那么你的接口相當于直接暴露在公網環(huán)境中任人蹂躪。

1.1 調用接口的先決條件-token

獲取 token 一般會涉及到幾個參數appid,appkey,timestampnonce,sign。我們通過以上幾個參數來獲取調用系統(tǒng)的憑證。

appidappkey可以直接通過平臺線上申請,也可以線下直接頒發(fā)。appid是全局唯一的,每個appid將對應一個客戶,appkey需要高度保密。

timestamp是時間戳,使用系統(tǒng)當前的 unix 時間戳。時間戳的目的就是為了減輕 DOS 攻擊。防止請求被攔截后一直嘗試請求接口。服務器端設置時間戳閥值,如果請求時間戳和服務器時間超過閥值,則響應失敗。

nonce是隨機值。隨機值主要是為了增加sign的多變性,也可以保護接口的冪等性,相鄰的兩次請求nonce不允許重復,如果重復則認為是重復提交,響應失敗。

sign是參數簽名,將appkey,timestampnonce拼接起來進行md5加密(當然使用其他方式進行不可逆加密也沒問題)。

token,使用參數appid,timestamp,nonce,sign來獲取token,作為系統(tǒng)調用的唯一憑證。token可以設置一次有效(這樣安全性更高),也可以設置時效性,這里推薦設置時效性。如果一次有效的話這個接口的請求頻率可能會很高。token推薦加到請求頭上,這樣可以跟業(yè)務參數完全區(qū)分開來。

1.2 使用POST作為接口請求方式

一般調用接口最常用的兩種方式就是 GET 和 POST 。兩者的區(qū)別也很明顯,GET 請求會將參數暴露在瀏覽器 URL 中,而且對長度也有限制。為了更高的安全性,所有接口都采用 POST 方式請求。

1.3 客戶端IP白名單

ip 白名單是指將接口的訪問權限對部分 ip 進行開放。這樣就能避免其他 ip 進行訪問攻擊,設置 ip 白名單比較麻煩的一點就是當你的客戶端進行遷移后,就需要重新聯(lián)系服務提供者添加新的 ip 白名單。設置 ip 白名單的方式很多,除了傳統(tǒng)的防火墻之外,spring cloud alibaba 提供的組件 sentinel 也支持白名單設置。為了降低 api 的復雜度,推薦使用防火墻規(guī)則進行白名單設置。

1.4 單個接口針對ip限流

限流是為了更好的維護系統(tǒng)穩(wěn)定性。使用 redis 進行接口調用次數統(tǒng)計,ip+接口地址作為 key,訪問次數作為 value ,每次請求 value+1,設置過期時長來限制接口的調用頻率。

1.5 記錄接口請求日志

使用 aop 全局記錄請求日志,快速定位異常請求位置,排查問題原因。

1.6 敏感數據脫敏

在接口調用過程中,可能會涉及到訂單號等敏感數據,這類數據通常需要脫敏處理,最常用的方式就是加密。加密方式使用安全性比較高的RSA非對稱加密。非對稱加密算法有兩個密鑰,這兩個密鑰完全不同但又完全匹配。只有使用匹配的一對公鑰和私鑰,才能完成對明文的加密和解密過程。

二 冪等性問題

冪等性是指任意多次請求的執(zhí)行結果和一次請求的執(zhí)行結果所產生的影響相同。說的直白一點就是查詢操作無論查詢多少次都不會影響數據本身,因此查詢操作本身就是冪等的。但是新增操作,每執(zhí)行一次數據庫就會發(fā)生變化,所以它是非冪等的。

冪等問題的解決有很多思路,這里講一種比較嚴謹的。提供一個生成隨機數的接口,隨機數全局唯一。調用接口的時候帶入隨機數。第一次調用,業(yè)務處理成功后,將隨機數作為key,操作結果作為 value,存入 redis,同時設置過期時長。第二次調用,查詢 redis,如果 key 存在,則證明是重復提交,直接返回錯誤。

三 數據規(guī)范問題

3.1 版本控制

一套成熟的 API 文檔,一旦發(fā)布是不允許隨意修改接口的。這時候如果想新增或者修改接口,就需要加入版本控制,版本號可以是整數類型,也可以是浮點數類型。一般接口地址都會帶上版本號,http://ip:port//v1/list

3.2 響應狀態(tài)碼規(guī)范

一個牛逼的 API,還需要提供簡單明了的響應值,根據狀態(tài)碼就可以大概知道問題所在。我們采用 http 的狀態(tài)碼進行數據封裝,例如200表示請求成功,4xx表示客戶端錯誤,5xx表示服務器內部發(fā)生錯誤。狀態(tài)碼設計參考如下:

分類 描述
1xx 信息,服務器收到請求,需要請求者繼續(xù)執(zhí)行操作
2xx 成功
3xx 重定向,需要進一步的操作以完成請求
4xx 客戶端錯誤,請求包含語法錯誤或無法完成請求
5xx 服務端錯誤

狀態(tài)碼枚舉類:

public enum CodeEnum {


    // 根據業(yè)務需求進行添加
    SUCCESS(200,"處理成功"),
    ERROR_PATH(404,"請求地址錯誤"),
    ERROR_SERVER(505,"服務器內部發(fā)生錯誤");

    
    private int code;
    private String message;

    
    CodeEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }


    public int getCode() {
        return code;
    }


    public void setCode(int code) {
        this.code = code;
    }


    public String getMessage() {
        return message;
    }


    public void setMessage(String message) {
        this.message = message;
    }
}

3.3 統(tǒng)一響應數據格式

為了方便給客戶端響應,響應數據會包含三個屬性,狀態(tài)碼(code),信息描述(message),響應數據(data)??蛻舳烁鶕顟B(tài)碼及信息描述可快速知道接口,如果狀態(tài)碼返回成功,再開始處理數據。

響應結果定義及常用方法:

public class R implements Serializable {


    private static final long serialVersionUID = 793034041048451317L;


    private int code;
    private String message;
    private Object data = null;


    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }


    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }


    public Object getData() {
        return data;
    }


    /**
     * 放入響應枚舉
     */
    public R fillCode(CodeEnum codeEnum){
        this.setCode(codeEnum.getCode());
        this.setMessage(codeEnum.getMessage());
        return this;
    }


    /**
     * 放入響應碼及信息
     */
    public R fillCode(int code, String message){
        this.setCode(code);
        this.setMessage(message);
        return this;
    }


    /**
     * 處理成功,放入自定義業(yè)務數據集合
     */
    public R fillData(Object data) {
        this.setCode(CodeEnum.SUCCESS.getCode());
        this.setMessage(CodeEnum.SUCCESS.getMessage());
        this.data = data;
        return this;
    }
}

總結

本篇文章從安全性、冪等性、數據規(guī)范等方面討論了 API 設計規(guī)范。除此之外,一個好的 API 還少不了一個優(yōu)秀的接口文檔。接口文檔的可讀性非常重要,雖然很多程序員都不喜歡寫文檔,而且不喜歡別人不寫文檔。為了不增加程序員的壓力,推薦使用 swagger 或其他接口管理工具,通過簡單配置,就可以在開發(fā)中測試接口的連通性,上線后也可以生成離線文檔用于管理API。

以上就是W3Cschool編程獅關于如何設計一個看起來很牛逼的API接口的相關介紹了,希望對大家有所幫助。

0 人點贊