解耦神器 —— 統跳協議和Rewrite引擎

之前寫過簡單實現APP內各模塊界面跳轉統一使用URL的文章,今天發現一篇手機天貓的同窗寫的統跳方案的文章,寫的很好,轉載和你們分享。正則表達式

------------------------------------分割線------------------------------------瀏覽器

統跳協議是天貓App統一跳轉協議,主要負責天貓App界面之間的串聯,也就是界面跳轉服務。Rewrite引擎是與之配合的一套URL重寫引擎,能夠經過配置實現重寫規則動態化。框架

歷史上的今天

統跳協議的前身是一套叫作internal的協議,internal要重點解決的問題是在WebView和推送通知中如何跳轉到指定的界面,進一步在任何動態場景下如何跳轉到指定界面。在這樣的思路下,internal中定義了多種協議格式,如:
tmall://tmallclient/?{"action":""}
internal:url=
link:url=
tmall://mobile.tmall.com/page/
幾乎每一種場景都有一種格式的協議與之對應。在具體操做過程當中這些協議都以URL表現出來。不難看出,這套協議最大的問題在於協議格式異構化嚴重,且不符合W3C的URL標準。隨着App規模的擴大,場景日趨複雜,界面愈來愈多,這套協議的弊端也日益顯露。編碼

而在天貓App開始從百萬級衝擊千萬級的時候,咱們認識到一套格式統一,符合標準,規則簡潔的協議很是必要。這套協議的任務也毫不是解決固定場景跳轉,而是徹底託管整個App的跳轉工做,從而實現全App界面解耦和跳轉動態化。所以,咱們從新設計了界面協議,造成了當下這套規範——統跳協議。配合統跳協議,爲了解決更多細節問題和跨平臺問題,咱們還設計了Rewrite引擎與之配合。url

統跳協議

統跳協議設計之初就保留了很強的可擴展性,爲接下來更豐富的場景預留了能力。上文講到了統跳協議在界面跳轉中做用,而事實上界面跳轉僅僅是這套方案的一個典型場景,一個最佳實踐。界面跳轉在統跳協議的框架中被認爲成一個服務,而跳轉到哪個界面則是由服務內部實現決定的。spa

統跳協議服務註冊

註冊一個服務

服務經過聲明URL的方式註冊到統跳協議中,這個聲明發生在服務所屬模塊內部的一個配置文件中,而這個配置文件被註冊到統跳協議裏。也就是說,整個App中的每個模塊都要註冊一個配置文件到統跳協議,統跳協議在初始化過程當中會遍歷配置文件列表,逐一加載這些模塊配置,根據配置信息把一個一個的模塊服務註冊到協議中。設計

服務註冊

統跳協議要求調用服務的URL必須是符合W3C URL標準的,服務註冊使用的URL只能包括host和path兩部分,其中host是必須的,path則可選。當統跳協議接收一個跳轉請求的URL後,先根據該URL的host和path兩部分做爲條件查找已註冊的服務,再初始化對應服務,把URL交給服務實例執行後續操做。指針

如何實現服務

統跳協議聲明瞭一個服務接口,這個接口中只有一個方法,服務必須由該接口實現而來。每個服務能夠經過實現接口中聲明的方法,使用參數中傳遞來的完整URL,參數列表和調用發起者指針,執行具體業務邏輯。code

例如分享服務,以iOS爲例:實現了TMShareUrlHandler服務。htm

@interface TMShareUrlHandler : NSObject<AliAppURLHandler>
@end
@implementation TMShareUrlHandler
#pragma mark - URL調用分享組件
- (id)handleUrl:(NSURL *)url withTarget:(id)target withParams:(id)params
{
// 省略代碼詳情
    return nil;
}
@end

在分享模塊的配置文件中聲明該服務的URL爲sharekit.tm/doShare

這份配置文件在分享模塊裏:

聲明分享服務

分享模塊的配置文件sharekit_bundle.plist也註冊到統跳協議中。

這份配置文件在統跳協議模塊裏:

註冊分享模塊

統跳協議如何處理界面跳轉

界面跳轉是統跳協議的初衷,也是統跳協議最重要的任務。所以在統跳協議服務註冊機制中,爲界面服務註冊作了更精細的定製開發。

上文提到跳轉服務是一個單一服務,而界面則成百上千,因此在界面註冊和服務註冊中出現了衝突。本着下降開發成本的原則,咱們又但願把同一個模塊中界面註冊和服務註冊放在一塊兒。因此在統跳協議中作了以下訂製:

  • 默認註冊跳轉服務

    跳轉服務是默認存在的,在統跳協議初始化過程當中這個服務就已經初始化了。

  • 給界面註冊提供特殊的標記

    上文中能夠看到在註冊分享服務的配置中object字段是服務的類名,若界面註冊也按照這個規則,那麼界面的類就會被認爲成一個服務,在調用過程當中必然會出現錯誤。所以咱們約定,界面註冊須要在類名前加#標示。

    界面註冊

如此一來,在統跳協議初始化過程當中,默認加載跳轉服務。當調用發生,解析URL查找到的對應對象帶有#,則認爲這是一個界面,則初始化這個對象,但不對其調用處理URL的方法,而是託管給已註冊的跳轉服務。跳轉服務則根據URL和初始化的界面對象執行跳轉服務。

Rewrite

Rewrite引擎的思路來源於Web容器中的Rewrite機制,主要解決天貓App中URL平臺展示一致性的問題。

天貓App中全部界面都是經過URL來標示的,然而標示Native界面的URL所有都創建在Native規範下,沒法和其餘平臺對應起來,而Rewrite引擎經過重寫URL來實現平臺一致性。

例如:商品詳情頁面在PC Web的URL是https://detail.tmall.com/item.htm,在Mobile Web則是https://detail.m.tmall.com/item.htm,在Native聲明的是tmall://page.tm/itemDetail。三者各不相同。PC Web和Mobile Web能夠經過判斷瀏覽器的UA識別環境,從而經過跳轉實現一致性,也就是說在手機瀏覽器訪問PC Web的URL,會經過一次302轉到Mobile Web的URL。而Native App的環境具備必定的特殊性,Native界面則沒法經過相似302這樣的跳轉來實現無感知切換,而Rewrite引擎就是來解決這個問題的。首先,不管是Native仍是Web,在天貓App中他們兩兩之間的跳轉都被統跳協議託管,而統跳協議在執行跳轉操做以前會把原始URL放入Rewrite引擎中作一次Rewrite操做。這樣一來,Rewrite引擎就根據配置規則,把原始URL轉換成適用於天貓App的目標URL,實現了URL表現平臺一致性。

原理

Rewrite引擎的原理很是簡單,模擬Web容器(Apache/Nginx等)的Rewrite配置,根據配置把傳入的原始URL進行重寫,返回重寫後的目標URL,交給統跳協議處理。

配置是經過正則表達式描述的Rewrite規則列表,這份列表經過貓客的配置中心實現動態更新。

Rewrite規則

  • 每條Rewrite規則中有三個字段:模式串,轉換串和標記位
    • 模式串:即正則表達式,用於匹配原始URL
    • 轉換串:即須要被轉換成目標URL的描述
    • 標記位:以西文逗號分隔的標記位,包括表示匹配則終止的l,須要進行店鋪域名查詢的s
  • Rewrite規則按行整理,並自上而下按順序逐行匹配

轉換模板中的保留字

  • 變量

    變量由變量標示符和變量名組合而成,如:$0,$#1,query,$#fragment等。變量被用在轉換串中描述轉換後的目標URL中的值。

    • 變量標示符:$,$$和$#
      • $:原變量的值
      • $$:對原變量作URL Encode
      • $#:自動識別編碼,對原變量作URL Decode
      • $$$:自動識別編碼,對原變量作URL Decode,再以UTF8作URL Encode
    • 變量名:數字(從0開始),枚舉(scheme,host,port,path,query,fragment,shopid)
      • 數字:0 - 表示整個URL,1~n - 表示正則中使用圓括號取出的參數
      • 枚舉:scheme,host,port,path,query,fragment表示標準URL中的相應部分;shopid表示對個性店鋪域名查詢後獲得的shopid
  • 標記位

    即上述規則中的標記位

Rewrite引擎查詢流程

  1. 取出規則列表中的首條規則
  2. 以模式串爲模板對原始URL作匹配,並獲得模式串定義的參數表
  3. 若匹配成功則繼續進行,不然進入下一條規則,從2開始進行下一輪匹配
  4. 查看該條規則是否包含s標記位,若包含,則使用原始串作一次個性域名的查詢
  5. 使用1的結果和重寫串對原始URL進行重寫操做,獲得目標URL
  6. 查看該條規則是否包含l標記位:
    • 若包含,則結束匹配,返回目標URL
    • 若不包含,則把目標URL賦值給原始URL,並進入下一條規則,從2開始下一輪匹配
  7. 直到最後一條規則結束,返回目標URL

舉例

上述提到過商品詳情頁的例子,在Rewrite配置中就體現爲:

模式串 轉換串 標記位
^(?:https?:)?\/\/detail(?:.m)?.tmall.com\/?item.htm\?(.*) tmall://page.tm/itemDetail?$1 l

在這條規則的保護下,PC Web和Mobile Web下的商品詳情URL在天貓App中都會被攔截到Native商品詳情頁面,能夠帶來最好的用戶體驗。也就是說,在平常的運營工做中,不須要關注一個商品在某個平臺內部須要以什麼樣的URL來投放,只須要投放一個主要的URL格式。這個URL在天貓App內部會被Rewrite引擎重寫爲Native界面聲明的URL,進行展現。

統跳和Rewrite在雙11中的表現

統跳協議和Rewrite引擎在剛剛過去的雙11期間,在全鏈路界面降級方案和會場上下線中發揮了重要做用。

全鏈路界面降級

上文中提到了天貓App中所有界面都聲明瞭本身的一個tmall://協議的Native URL,但在業務邏輯上使用的不是這個Native URL,而是和Web保持一直的http://協議的URL,在統跳協議中會調用Rewrite引擎對這個http:// URL進行重寫後再作展示。

爲了保證整個天貓App的可用性,咱們在配置列表中預先定義了一系列Rewrite規則,用於攔截這些URL。一旦發現Native邏輯出現異常,將快速上線預約義的規則,從而在Rewrite引擎把http:// URL重寫成Native URL以前攔截,直接返回http:// URL,實現Native界面到Mobile Web界面的降級。

Native會場上下線

雙11會場是雙11活動期間曝光率最高的頁面,也是對體驗要求最高的界面。所以,咱們在天貓App雙11版本中對重要會場作了Native化,以提高用戶體驗。而Native會場展示依賴會場數據,且開啓時間嚴格控制在雙11當日的24小時內。

在這樣的要求下,咱們配置了http://協議的會場URL到Native會場URL的Rewrite規則,並在雙11開始時上線,結束時下線,實現了雙11當日天貓App的會場Native化。

結語

統跳協議在設計過程當中預留了很好的擴展能力,因此在界面解耦以外還承擔了更多的服務調用功能。Rewrite引擎爲實現平臺一致性而設計,而在實際應用過程當中又挖掘出更多的場景和功能。

在統跳協議和Rewrite引擎接下來的發展過程當中,將更注重Android和iOS雙平臺的高度一致性,並嘗試開放更多API,讓全部人一塊兒挖掘這套方案的潛力。

相關文章
相關標籤/搜索