一個主系統和若干其餘團隊(或公司)開發的子系統(主系統和每一個子系統都有先後端)須要對外展示爲一個系統(實際上沒有主系統和子系統之分,這裏是由於主系統研發團隊須要對整個系統負責,而子系統研發團隊只對自身系統負責)。因時間關係,主系統研發團隊再也不從新開發界面,而是直接跳轉到子系統界面。這樣的話,就至關於一個系統有多個界面和多個後端。通常校驗用戶是否登陸都是在各自的後端完成的,而多個子系統的話就會有多個帳號體系,這對於系統融合就很麻煩了。這裏爲了簡單,要求各子系統自己不作用戶登陸態校驗,統一由主系統研發團隊負責用戶登陸態校驗工做。html
所謂web端的融合,就是要經過同一個域名(也能夠是同一個IP地址)去訪問不一樣的子系統的web端。用戶登陸只在其中一個子系統(這個項目是在主系統中)實現,若是使用同一個域名訪問不一樣的子系統,瀏覽器會自動攜帶cookie(跨域的話,瀏覽器不會自動攜帶cookie),這樣訪問每一個子系統時都會攜帶cookie,後端服務才能利用cookie進一步判斷用戶是否登陸。
首先,要能經過同一個域名訪問全部子系統web端,就須要全部子系統的web端靜態文件都放置在同一個web服務器的下,爲了不衝突,這些子系統的靜態文件不能都放在web服務器的根目錄下,而須要在web服務器的根目錄下爲每一個子系統都單獨新建一個目錄來存放各自的靜態文件。而後,爲了區分來自同一個域名的請求是要訪問哪一個子系統,就須要在URL裏爲不一樣的子系統指定不一樣的前綴
。
下面給出使用nginx作web服務器,web端融合的nginx配置:前端
# 指定靜態文件的根目錄 root /opt/www; # 若是訪問根目錄,直接重定向至主系統 location = / { rewrite / /mainsubprefix; } # 主系統前綴爲 /mainsubprefix # 主系統靜態文件放置在根目錄下的 manisubstatic 裏,當前配置就是位於 /opt/www/manisubstatic 下 location /mainsubprefix { try_files $uri $uri/ /manisubstatic/index.html; } # 子系統一前綴爲 /suboneprefix # 子系統一靜態文件放置在根目錄下的 subonestatic 裏,當前配置就是位於 /opt/www/subonestatic 下 location /suboneprefix { try_files $uri $uri/ /subonestatic/index.html; } # 子系統二前綴爲 /subtwoprefix # 子系統二靜態文件放置在根目錄下的 subtwostatic 裏,當前配置就是位於 /opt/www/subtwostatic 下 location /subtwoprefix { try_files $uri $uri/ /subtwostatic/index.html; }
上面咱們已經肯定了不一樣子系統web端融合的方案,各子系統的web端融合後,對外展示就是一個web端了,因此接下來的討論中都是基於一個web端(內部能夠是多個子系統的web端的融合)進行的。
根據上一節的需求分析,整個系統由多個子系統組合而成,這實際上能夠理解爲就是很常見的分佈式系統,所不一樣的就是分佈式系統通常只有一個前端界面,並且分佈式系統內部的各服務通常都容許互相通訊。但這裏咱們能夠先用一個簡單的分佈式系統權限認證方案作入手分析,以下圖所示爲一個簡單分佈式系統權限認證方案,提供一個獨立的權限認證服務,而後各子系統後端經過調用權限認證服務判斷用戶是否登陸。nginx
如今來分析一下上面的方案,優缺點以下:web
爲了解決上面的方案中各子系統後端和認證服務器緊耦合的問題,這裏在web端和各子系統後端服務之間增長一層代理層,這樣全部的請求都會先到代理層,代理層負責驗證用戶是否登陸,並返回失敗(用戶未登陸),或轉發請求至對應的子系統後端(用戶以登陸)。以下圖所示。數據庫
增長代理層方案優缺點以下:後端
方案 | 簡單分佈式權限認證方案 | 增長代理層方案 |
---|---|---|
優勢 | 簡單、已理解、已實現 | 各子系統後端與認證服務器緊耦合 |
缺點 | 對各子系統後端透明,各子系統研發團隊只需保證自身系統運行正常 | 增長了新服務、引入了不穩定性;各子系統的web端在解析每一個請求的響應時,須要處理代理層用戶未登陸的響應,並跳轉至登陸頁 |
根據目前項目相關的信息,系統暫沒有可擴展性要求,併發量也不大。穩定性方面,前面也提到了簡單分佈式權限認證方案相對穩定。接下來咱們從業務場景和研發團隊兩個方面進一步分析兩個方案。
業務場景方面,認證服務器是徹底跟業務緊耦合的,它須要訪問業務數據庫的用戶表;代理層服務器是業務鬆耦合的,它跟業務惟一的耦合就是須要調用認證服務器去驗證用戶是否登陸。衆所周知,與業務緊耦合的服務確定比與業務鬆耦合的服務改變機率要大的多。但僅就目前的用戶登陸態驗證接口,彷佛都是經過cookie去校驗,因此無論認證服務器內部怎麼驗證方案怎麼變,只要保證接口不變,其餘調用端都不用改變。因此從業務場景方面,兩個方案差很少,由於當前方案要解決的用戶登陸驗證場景幾乎不會變化。
研發團隊方面,每一個子系統都是由不一樣地區的公司負責,很明顯若是每一個公司只負責各子的子系統正常運行是最簡單的了。參與過異地多團隊項目的人應該都知道,跨地域團隊的溝通效率是很是底的,若是須要常常聯調,效率就更低了。從這個方面來說,增長代理層方案要勝出一點。跨域
沒有最好的方案,只有最合適的方案。咱們結合了項目背景和研發人員的安排,選擇了增長代理層的方案。瀏覽器
通過上面的分析,最終整個系統的方案以下圖所示,這裏特地將nginx放進來是由於涉及到一個跨域的問題,web端不能直接調用代理層服務器,不然瀏覽器認爲跨域,不會自動攜帶cookie,因此這裏使用nginx作了一層反向代理,先後端都經過一個nginx代理就不存在跨域的問題了。也就是說全部後端服務器都要通過同一個域名訪問,那麼每一個子系統的後端服務也就須要提供不一樣前綴以區分請求
。服務器
上圖中,代理層服務須要能接收指定前綴的請求,而後驗證登陸態,並返回失敗響應或轉發請求至對應後端服務。
這裏給出系統總體方案後端服務的nginx配置(web配置前面已經給出):cookie
# /mainsubbackend 爲主系統後端服務API前綴,proxy_pass 後是主系統後端服務地址 location /mainsubbackend { proxy_pass http://127.0.0.1:15001; } # /sub1backend 爲子系統一後端服務API前綴,proxy_pass 後是子系統一後端服務地址 location /sub1backend { proxy_pass http://127.0.0.1:15003; } # /sub2backend 爲子系統二後端服務API前綴,proxy_pass 後是子系統二後端服務地址 location /sub2backend { proxy_pass http://127.0.0.1:15003; }
代理層服務須要能接收指定前綴的請求,而後驗證登陸態,若是用戶已登陸,將請求轉發至對應後端服務,否正返回失敗響應。實現方面沒有什麼難度,主要是如何實現轉發功能,由於我用的是Go語言實現的,因此這裏指出Go語言是如何實現轉發功能的。Go語言net/http/httputil
包裏的ReverseProxy
自帶了轉發功能,這裏給個簡單的例子:
// 用帶轉發的目標地址建立一個 ReverseProxy 對象指針 proxy := httputil.NewSingleHostReverseProxy(dstAddress) // 將請求 c.Request 發送至 dstAddress, 響應寫會 c.Writer。實際上就是實現了轉發 proxy.ServeHTTP(c.Writer, c.Request)
當把整個系統完成後,再來回顧下系統架構,發現其實代理層就是一個網關,只是代理層只實現了用戶登陸驗證。這個項目只須要統一的用戶登陸校驗,因而最開始就把精力放在瞭如何去校驗用戶登陸態的微觀層,忘了從宏觀層面來梳理下整個系統,以致於最開始老是出於混亂中,直到實現了整個系統纔看清整個系統的架構實際上是業界成熟通用的架構。固然,還一個很重要的緣由就是對網關的不熟悉。
因此說,看事物仍是要看到其根本。最後以一個禪語故事結束本文:
無名禪師拿起筆來,在紙上寫了一個「我」字,但這個「我」倒是反方向寫出來的,就像是印章上的文字。禪師寫完後問道:「這是什麼?」 小沙彌回答說:「這是一個字,只不過寫反了。」 禪師又問:「那你能看出這是個什麼字嗎?」 小沙彌回答說:「是個‘我’字。」 禪師又說:「那麼寫反的‘我’字算不算字呢?」 小沙彌說:「寫反的字怎麼還能算字呢?」 禪師說道:「既然不算,那你爲什麼會說這是個‘我’呢?」 小沙彌馬上改口說:「算。」 禪師又說:「既然算個字,那你爲何又說這個字反了呢?」 小沙彌無言以對。 無名禪師微笑着說道:「正寫是字,反寫也是字,你既然說它是個反寫的‘我’字,就說明在你內心是真正識得‘我’的原字的;相反,若是你不知道原來的字是什麼模樣,就算我寫反了,你也無從知曉,只怕當人告訴你這是的‘我’字後,遇到正寫的‘我’,你倒要說是反寫的了。」 小沙彌如有所悟地點點頭,禪師接着說道:「一樣的道理,好人是人,壞人也是人,你只需明瞭人的本性,能一眼辨出善惡,那麼度化壞人又有何難呢?」 小沙彌所以頓悟。 其實無名禪師旨在告訴咱們,世間萬物皆有其本相,只要明悉本相,那麼心中就不會有迷惘疑惑。任其正反,均可不失其道,不亂其規,心如明鏡,本相可照。