当前位置:网站首页>接口設計時的一些建議

接口設計時的一些建議

2022-07-04 20:49:00 碼拉松

1. 參數校驗

參數的合法性校驗應該是每個接口必備的,無論是前端發起的請求,還是後端的其他調用都必須對參數做校驗,比如:參數的長度、類型、格式,必傳參數是否有傳,是否符合約定的業務規則等等。

推薦使用SpringBoot Validation來快速實現一些基本的參數校驗。

參考如下示例:

@Data
@ToString
public class DemoEntity {
    
	
	// 不能為空,比較時會除去空格
    @NotBlank(message = "名稱不能為空")
    private String name;
	
	// amount必須是一個大於等於5,小於等於10的數字
    @DecimalMax(value = "10")
    @DecimalMin(value = "5")
    private BigDecimal amount;

	// 必須符合email格式
    @Email
    private String email;
	
	// size長度必須在5到10之間
    @Size(max = 10, min = 5)
    private String size;
	
	// age大小必須在18到35之間
    @Min(value = 18)
    @Max(value = 35)
    private int age;
	
	// user不能為null
    @NotNull
    private User user;
	
	// 限制必須為小數,且整數比特integer最多2比特,小數比特fraction最多為4比特
    @Digits(integer = 2, fraction = 4)
    private BigDecimal digits;
	
	// 限制必須為未來的日期
    @Future
    private Date future;

	// 限制必須為過期的日期
    @Past
    private Date past;
	
	// 限制必須是一個未來或現在的時間
    @FutureOrPresent
    private Date futureOrPast;
	
	// 支持正則錶達式
	@Pattern(regexp = "^\\d+$")
	private String digit;
}

@RestController
@Slf4j
@RequestMapping("/valid")
public class TestValidController {
    

    @RequestMapping("/demo1")
    public String demo12(@Validated @RequestBody DemoEntity demoEntity) {
    
        try {
    
            return "SUCCESS";
        } catch (Exception e) {
    
            log.error(e.getMessage(), e);
            return "FAIL";
        }
    }
}

2. 接口限流

在設計接口時,我們應當對接口的負載能力做出評估,尤其是提供給第三方使用時,這樣當實際請求流量超過預期流量時,我們便可采取相應的預防策略,以免服務器崩潰。

一般來說限流主要是為了防止惡意的Dos攻擊或者爬蟲等非正常的業務訪問,因此一般來說采取的方式都是直接丟弃超出閾值的部分。

限流的具體實現有多種,單機版可以使用Guava的RateLimiter,分布式可以使用Redis+Lua,想要更加完善的成套解决方案則可以使用阿裏開源的sentinel。

3. 接口降級、熔斷、隔離

在如今這個微服務時代,一次後臺請求可能都會經過好幾次RPC調用的過程,因此服務與服務之間的正常通信就顯得非常重要,我們不能因為某個服務不可用,導致整條鏈路上節點都受到影響,慢慢的導致整個服務都不可用,這也就是我們所說的雪崩效應。

在這裏插入圖片描述
如果此時B服務發生故障,導致A服務到B服務的所有請求都沒有及時響應,那麼最終造成的結果就是A服務的所有連接被耗盡。

要知道,實際上我們服務與服務之間一定是以網狀的形式存在,我們當然還會有從其他鏈路發起的到A服務的請求。

比如有C直接請求A的,有D請求C,然後C再請求A的,有E直接請求A的,所以一旦A的連接被耗盡,也就意味著C/D/E的連接也會被耗盡,就這樣越滾越多,最終導致整個網狀中的節點連接資源全部被耗盡。
在這裏插入圖片描述

可以看出,服務雪崩問題帶來的影響是非常嚴重的,我們必須要有所防範,而熔斷、降級則是一種非常有效的方式。

首先我們需要做到快速失敗,請求響應一旦超過一定的時間,就自動返回,提示客戶端請求超時或是其他什麼,總之,我們需要在服務能接受的範圍內快速給出響應。

熔斷可以幫助我們對於多次請求響應都超時的請求,給出一定解决措施,比如一定時間範圍內就不再請求了,除此之外,還可以做到資源隔離,比如對於X接口的調用,就只分配M個資源(這裏的資源一般指的就是線程)。

而降級可以理解為Plan B,也就是當請求響應超過了你設置的閾值後,你的後備方案是什麼,接下來會怎麼辦?通常比較簡單的方式就是給客戶端一個友好的響應,比如服務開小差之類的,在保證服務穩定的前提下,也能够給客戶端良好的體驗性。

其中netlfix開源的hystrix組件,可以輕松與spring cloud生態結合,其對於資源隔離、服務熔斷、降級等都有了成熟的解决方案,可以嘗試使用。

4. 超時重試

使用重試機制,是相信請求還是可以成功的,有些情况下一次請求失敗可能僅僅是因為網絡不穩定造成的,也許再重新請求一次就好了,此時如果直接返回客戶端失敗就不是最佳的選擇。

重試的策略也有很多種,比如重試的次數、頻率,當目標節點是集群部署時,還可以采用切換節點重試等方式,比如:如果請求A節點失敗,那就自動切換到請求B節點。

超時重試可以使用spring-retry,這是spring封裝好的API,直接通過注解的方式就可以設定各種重試策略,實現重試機制。

netifix開源的ribbon,作為客戶端的負載均衡,也封裝了重試機制,其底層也是基於spring-retry實現的。

5. 幂等性

既然有重試就一定要考慮幂等性的問題,所謂幂等性,簡單來說,就是對一個接口執行多次的重複請求,與一次請求所產生的結果是相同的,概念聽起來非常容易理解,但要真正的在系統中要始終保持這個目標,是需要很嚴謹的設計的。

除了重試、像基於异步回調通知、MQ等方面的設計也决定了接口一定要保證幂等性,當然並不是說只要沒有這些設計就不用考慮幂等性問題了,前面在講重試時提到,網絡本身也存在重試機制,我們知道TCP是可靠的傳輸層協議,既然要保證數據包一定能够到達,那就一定會有重試的機制。

保證幂等性的方式也有很多,比如:加鎖、數據庫唯一鍵、狀態機等。

6. 接口性能

性能是一個非常廣的話題,此文中沒法完全展開,但可以提供一些方向,之後讀者可再沿著每一條方向深思鑽研。

6.1 並行

並行是充分利用CPU資源的一種方式,JDK中也有非常多的並行工具類,比如:CompletableFuture,如果一次請求鏈路中存在多次IO請求,而這些請求也沒有先後依賴關系,那麼則可以嘗試並行處理。

並行需要我們控制好並行度的問題。

6.2 异步

我相信關於异步、響應式編程等概念一定也是耳熟能詳,异步可以輕松獲得遠遠超出同步請求的吞吐量,有很多的業務場景也特別適合使用异步來處理,比如新用戶注册後的短信通知、郵件通知。

6.3 緩存

提到性能提昇,那一定少不了對於緩存的使用,這本身就是由計算機的設計所决定的。

在這裏插入圖片描述
如果你對各個層面的訪問延遲有所了解,你就可以針對性的采取措施,比如在CPU緩存,就是操作系統級別的緩存,一般我們能控制的就是訪問的類型,我們需要的數據是從磁盤獲取還是從內存獲取,或者是通過一次TCP請求獲取。

當然,緩存雖好,但也不能亂用,畢竟資源有限,內存可比磁盤貴的多,還有空間與時間的局部性原理,你也應該所有了解,緩存的命中率如果不高,那麼最終將適得其反。

6.4 算法

我們說得到同樣的結果,實現過程可以各有不同,O(n^2)的時間複雜度與O(n)甚至是O(logn)的時間複雜度差距還是很明顯的,這一點在數據量較小時感知不出來,不過一旦數據量比較多,就非常明顯了。

除此之外,對於空間的使用也是必須要考慮到的,否則可能會導致頻繁的GC,帶來的結果就是CPU消耗過高,甚至最後內部不足,導致OOM

7. 安全

最後,還有另外一個繞不開的話題,就是接口安全方面,如果你的接口僅僅是在內部網絡中使用,那到還不必過於擔心,但如果是暴露在公網環境中的接口,那就一定要考慮安全方面的問題。

接口安全需要考慮的地方非常多,還是一樣,本編文章只能提點一些,沒辦法逐一展開。

7.1 敏感數據

敏感信息一般包含,身份證、手機號、銀行卡號、車牌號、姓名等等,應該按照脫敏規則進行處理。

7.2 漏洞攻擊

一般包含,CSRF、XSS、SQL注入、文件上傳漏洞等。

CSRF

跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。跟跨網站脚本(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。

在這裏插入圖片描述

XSS

跨站脚本攻擊 (Cross Site Scripting, XSS) 發生在客戶端,可被用於進行竊取隱私、釣魚欺騙、偷取密碼、傳播惡意代碼等攻擊行為。 惡意的攻擊者將對客戶端有危害的代碼放到服務器上作為一個網頁內容, 使得其它網站用戶在觀看此網頁時,這些代碼注入到了用戶的瀏覽器中執行,使用戶受到攻擊。一般而言,利用跨站脚本攻擊,攻擊者可竊會話 Cookie 從而竊取網站用戶的隱私。

SQL注入

SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情况下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。

文件上傳漏洞

Web 應用程序在處理文件下載時,接受用戶指定的路徑和文件名進行下載,攻擊者利用此漏洞來下載服務器的其它文件甚至任意文件(源代碼、數據庫甚至 passwd 等)。

7.3 Token、 加密、簽名

Token機制主要是用來做身份認證的,在對外提供的接口中,用來鑒別接口請求方的身份。

簽名可以用來防止數據篡改、加密可以用來防止數據被偷窺。

7.4 黑、 白名單機制

使用白名單機制可以進一步加强接口的安全性,一旦服務與服務交互可以使用,接口提供方可以限制只有白名單內的IP才能訪問,這樣接口請求方只要把其出口IP提供出來即可。

與之對應的黑名單機制,則是應用在服務端與客戶端的交互,由於客戶端IP都是不固定的,所以無法使用白名單機制,不過我們依然可以使用黑名單攔截一些已經被識別為非法請求的IP。

原网站

版权声明
本文为[碼拉松]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207041914512039.html