我們在項目中引入網關做了這些事情
我們用網關做了這些事情:
- 1.實現路由功能;
- 2.整合Swagger API文檔;
- 3.文件URI的全局修改;
- 4.統一校驗Token;
- 5.統一校驗資源訪問權限;
- 6.對外開放API統一簽名校驗。
實現路由功能
實現路由功能的目的是統一流量入口,為前端屏蔽后端多個微服務的存在,無需為后端每個微服務都通過域名將接口暴露于外網。
之前我們項目是通過nginx實現請求路由功能,但我們需要的不僅僅是路由功能,路由功能只是網關的最基礎功能。
整合Swagger API文檔
項目微服務化后接口文檔也隨之分散,前期由于我們是使用nginx做路由,配置swagger路由又太過麻煩,前端同事也需要記住路由規則,因此我們放棄通過配置路由訪問接口文檔。
在沒有網關之前,前端同事無法訪問測試環境的接口文檔,我們只能在本地啟動微服務讓前端同事通過局域網訪問API接口文檔。
引入網關后我們希望能統一API文檔入口。詳細的整合步驟筆者已單獨整理出一篇教程《在網關實現合并多個微服務Swagger接口文檔的詳細步驟》,最終實現的效果如下圖所示。
文件URI的全局修改
由于域名、路由前綴都有修改的可能,一般圖片上傳后我們只存儲圖片的相對路徑到數據庫,但響應給前端的必須是完整的url,否則圖片無法訪問,因此我們必須要在響應前為所有圖片url拼接上域名與路由。
以修改用戶頭像為例,前端需要先調用文件上傳接口上傳圖片并獲取到圖片上傳后的url,再攜帶圖片url調用修改用戶頭像的接口。由于前端可能需要實現上傳后回顯,因此文件上傳接口響應的圖片url也必須是完整的,這樣就導致前端調用修改用戶頭像接口傳的圖片url也是完整的,我們不得不在修改用戶頭像的接口實現去掉頭像url的域名和路由。
一個接口可以這樣,很多個接口呢?如果不怕麻煩,那確實每個接口都可以這樣寫。
對于這類重復性操作,我們選擇將其移至網關統一實現,并且當路由、域名修改后其它微服務也不需要做任何的改動。
想要實現為圖片url去掉或拼接域名與路由并不難,難的是我們如何從請求body以及從響應body中識別出哪些字段是文件url。
首先是如何從請求body識別出哪個字段傳的是文件url。由于前端傳的文件url是完整的,因此可根據域名、路由和文件名后綴使用正則匹配替換。域名、路由、文件名后綴這三個條件缺一不可。匹配域名和路由是避免匹配到第三方網站的圖片鏈接或是以前上傳的圖片(向后兼容),匹配文件名后綴是確保這是一個文件鏈接,而不是接口鏈接。
其次是如何從響應body識別出哪個字段傳的是文件鏈接。我們只能通過后綴名去匹配,當匹配上后綴名后還需要判斷鏈接是否已經是完整的鏈接,對于完整的鏈接就無需做拼接。
在實現過程中需要注意的地方:當我們修改請求或響應body時,其長度可能會發生變化,因此必須要記得修改請求或響應頭的ContentLength。
如果是基于Spring Cloud Gateway實現的網關,由于是異步響應式的,對于請求數據包,先是請求頭被寫入InputStream流,再是body,而不是一起寫入,所以當我們修改body后再修改請求頭的ContentLength已是無意義。在無法預知修改后body的長度情況下,解決方案可以是將請求頭的ContentLength移除,取而代之的是Transfer-Encoding: chunked。
統一校驗Token有效性
在還是使用nginx做請求轉發的時候,每個微服務都需要寫一套token校驗邏輯,如通過攔截器校驗請求是否攜帶token,以及token是否有效。而獲取用戶信息需要先從請求頭獲取token,再查redis獲取用戶身份信息。
在引入網關后,我們就只需要在網關做token校驗,校驗通過后從redis獲取用戶信息,并寫到請求頭中,同時將Token從請求頭移除。userId由網關傳遞給后臺微服務,后臺微服務不需要再一次根據Token獲取用戶ID。
統一校驗資源訪問權限
在引入網關后,除了登錄(Token)校驗,用戶訪問資源的權限校驗都可以在網關實現,每個微服務都不再關心權限校驗的問題。
具體的用戶資源訪問權限校驗依然由用戶中心完成,網關只負責調用用戶中心提供的權限校驗接口完成用戶資源訪問權限校驗。這可能會影響接口的性能,盡量讓用戶中心在實現權限校驗接口時數據來源全部讀緩存。
對外開放api統一簽名校驗
我們對外開放API采用基于簽名機制實現身份認證,可以控制簽名的有限時間。筆者之前寫過一篇關于簽名機制的文章:《一種基于簽名算法且簡單安全的API授權機制》。
在沒有引入網關之前,我們通過AOP實現,只需要在開放API方法上添加一個注解。其中key和私鑰、簽名有效期在配置文件中配置。而在引入網關后,就可以統一在網關實現簽名校驗。
如果API需要提供給多個不同主體使用,也就是會有多個合作客戶的系統使用,那么key和密鑰是要在后臺提供配置功能的,且配置持久化到數據庫,網關也需要支持根據key查詢密鑰再校驗簽名。網關可將key、密鑰字典緩存在內存中,定時刷新。或者緩存到redis,當有賬號的密鑰更新時同步刷新緩存。
總結
網關一般用于統一流量入口、統一認證鑒權、流量控制,除此之外,一些與業務無關的重復操作也都可以在網關統一實現,如本篇介紹的統一SwaggerAPI文檔入口,為文件url自動去掉或拼接域名與路由。內部對外提供的接口也都可以通過網關做簽名校驗、訪問頻率限制等。
本文轉載自微信公眾號「Java藝術」,可以通過以下二維碼關注。轉載本文請聯系Java藝術公眾號。