Scheme & Rewrite

原文地址

蘋果核 - 解耦神器 —— 統跳協議和Rewrite引擎

題記:天貓App長大了,已經長成了流量以千萬計規模的App,當下至少有10個團隊在直接維護天貓App。在App長大,團隊擴充的過程中解耦是一個永恒的話題,而界面解耦又是App架構的重中之重。

統跳協議是天貓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引擎與之配合。

統跳協議

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

統跳協議.png

注冊一個服務

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

注冊服務.png

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

如何實現服務

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

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

@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

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

分享模塊.png

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

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

配置文件.png

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

界面跳轉是統跳協議的初衷,也是統跳協議最重要的任務。因此在統跳協議服務注冊機制中,為界面服務注冊做了更精細的定制開發。

上文提到跳轉服務是一個單一服務,而界面則成百上千,所以在界面注冊和服務注冊中出現了沖突。本著降低開發成本的原則,我們又希望把同一個模塊中界面注冊和服務注冊放在一起。所以在統跳協議中做了如下訂制:

  • 默認注冊跳轉服務

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

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

上文中可以看到在注冊分享服務的配置中object字段是服務的類名,若界面注冊也按照這個規則,那么界面的類就會被認為成一個服務,在調用過程中必然會出現錯誤。因此我們約定,界面注冊需要在類名前加#標示。

###.png

如此一來,在統跳協議初始化過程中,默認加載跳轉服務。當調用發生,解析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$#1query$#fragment等。變量被用在轉換串中描述轉換后的目標URL中的值。

    • 變量標示符:$$$$#
      • $原變量的值
      • $$對原變量做URL Encode
      • $#自動識別編碼,對原變量做URL Decode
      • $$$自動識別編碼,對原變量做URL Decode,再以UTF8URL Encode
    • 變量名:數字(從0開始),枚舉(schemehostportpathqueryfragmentshopid
      • 數字:0 -表示整個URL1~n - 表示正則中使用圓括號取出的參數
      • 枚舉:schemehostportpathqueryfragment表示標準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,進行展示。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容