vivo 低代碼平臺【后羿】的探索與實踐

作者:vivo 互聯(lián)網前端團隊- Wang Ning

本文根據王寧老師在“2022 vivo開發(fā)者大會"現場演講內容整理而成秋泄。公眾號回復【2022 VDC】獲取互聯(lián)網技術分會場議題相關資料。

本文主要從前后端分離的低代碼方案热某、自研高性能渲染引擎脂新、高效的可視化配置方案哨啃、千億級內容投放号阿、低代碼如何與傳統(tǒng)開發(fā)共存等五個維度vivo在低代碼平臺方面的實踐經驗迁沫,其中也會涉及到動態(tài)交互如何運用低代碼來編排和我們在提高配置效率方面的全面探索芦瘾。

一、前言

青春才幾年集畅,疫情占三年近弟,后疫情時代,究竟需要什么樣的新技術挺智,才能真正解放IT生產力祷愉,我認為是低代碼,一種可視化的應用開發(fā)方法赦颇,即“用較少的代碼二鳄、以較快的速度來交付應用程序”。


低代碼如果從表現形式來說確實不是新技術媒怯,1980年就有了订讼,但隨著前端各種新技術的出現及云原生時代的到來,低代碼讓我們看到了積極向上的一面扇苞;對用戶來說:圖形化操作欺殿,容易上手;內置各種模板杨拐、組件祈餐,降低開發(fā)難度;可視化拖拽哄陶,開發(fā)效率高帆阳。對企業(yè)來說:能夠縮短產品周期;節(jié)省成本,提高效率蜒谤;而且維護便利山宾,即改即用。低代碼的優(yōu)勢這么的顯而易見鳍徽,自然也會在 vivo 發(fā)揮它的價值资锰。

隨著vivo互聯(lián)網用戶量級不斷增加,傳統(tǒng)開發(fā)已經不能夠滿足井噴式的運營需求阶祭,而后羿绷杜,正是我們探索解決方案過程中誕生的用于支撐運營后臺業(yè)務高效高質量落地的低代碼平臺,目前已是vivo后臺業(yè)務首選的在線可視化開發(fā)平臺濒募,我們在平臺建設的過程中也沉淀了大量的經驗鞭盟,后面的內容將會以后羿為背景來詳細展開。

接下來我們將從以下五個方面分別展開我們在低代碼方面的實踐:

  1. 前后端分離的低代碼方案

  2. 自研高性能渲染引擎

  3. 高效的可視化配置方案

  4. 千億級內容投放

  5. 低代碼如何與傳統(tǒng)開發(fā)共存

二瑰剃、前后端分離的低代碼方案

低代碼平臺常常前端部分要占據重頭戲齿诉,所以在早期,我們采用的是前端大包大攬的技術方案晌姚,但隨著業(yè)務量的劇增粤剧,我們遇到了各種各樣的訴求,比如后羿側是否可以輸出獨立頁面挥唠,或者支持純粹的服務端低代碼能力抵恋、產出獨立的接口服務等。為了解決問題及時響應業(yè)務訴求宝磨,我們大刀闊斧的進行了重構馋记,在后續(xù)的版本,我們采用了前后端分離的低代碼方案懊烤,當然,這種分離包括了“前后端開發(fā)分離"和“低代碼服務能力分離”宽堆,如下圖腌紧,我們能夠直觀的看到web開發(fā)兩種最基本的方式。

前后端分離較不分離的方式畜隶,分工更加明確壁肋,真正實現解耦;前端可以專注于頁面交互籽慢、用戶體驗和兼容性浸遗,而后端則主要負責高并發(fā)、高可用箱亿、高性能跛锌、安全、存儲和業(yè)務邏輯届惋,前后端分離的開發(fā)方式也是時下行業(yè)的主流選擇髓帽。我們再來看一下低代碼方式開發(fā)應用的不同之處菠赚。


一種方式是產品視角,或者說是非開發(fā)的視角郑藏,當我們在低代碼平臺搭建衡查、開發(fā)業(yè)務時,無需關心整個制品的具體分層和實現細節(jié)必盖,只需要使用平臺提供的能力來搭建我們所需的端側應用即可拌牲,這種方式下用戶甚至無需具備專業(yè)的開發(fā)知識便可搭建出簡單的應用,這種平臺往往也是無代碼平臺歌粥。

另一種則是開發(fā)視角塌忽,這種思維模式下,用戶至少會看到前端和后端兩種服務阁吝,這兩種服務通常來說可能是頁面和接口砚婆,這種模式更加適合程序員,與日常開發(fā)思維保持一致突勇,所以平臺學習成本也就很低装盯,能夠簡單、快速的開發(fā)出更加復雜的應用甲馋;后羿主要面向開發(fā)者埂奈,自然而然的采用了這種分層開發(fā)的模式。

低代碼平臺本身也需要開發(fā)者投入大量的開發(fā)精力定躏,一個好的開發(fā)模式往往能夠事半功倍账磺,目前流行的低代碼產品,大多是下圖所示兩大類實現方式痊远。

前后端不分離實現會導致平臺的靈活性差垮抗、拓展性差、可集成度較低碧聪;反觀前后端分離實現的方式冒版,我們可以設計簡單易懂的DSL,下發(fā)到開發(fā)側編譯轉換逞姿,發(fā)揮各自的優(yōu)勢辞嗡;前后端版本迭代和優(yōu)化升級也可以做到互不干擾。

正如上圖滞造,得益于前后端分離的分層架構续室,我們在前端服務層又分離出開發(fā)者平臺和運營平臺;開發(fā)者平臺專注于可視化搭建谒养,運營平臺面向最終的業(yè)務運營挺狰;一個負責開發(fā)體驗,一個負責用戶體驗;后端則通過微服務架構拆分出不同功能模塊她渴,實現了平臺邏輯與業(yè)務邏輯的解耦达址。

前后端分離的方案,分層明確趁耗,解除耦合沉唠,而且前后端各自的服務也實現了邏輯分層,得益于這種架構苛败,我們很輕松就實現了前后端低代碼能力的分離满葛,來滿足更加復雜的業(yè)務訴求。

前文我們提到罢屈,前后端分離中還包括了前后端低代碼服務能力的分離嘀韧。

如上圖所示,開發(fā)者平臺產出的DSL缠捌,傳遞到端側锄贷,經過各自的運行時解析,便可以針對不同用戶提供不同的低代碼能力曼月;這樣谊却,用戶就可以使用平臺搭建頁面來連接自己的服務,或者編排接口來為自己的頁面提供存儲服務哑芹;既可以單獨配置頁面炎辨,也可以獨立使用接口服務,這就是前后端低代碼能力的分離聪姿,前后端分別配置碴萧,也與傳統(tǒng)開發(fā)邏輯、思維方式一致末购,對開發(fā)者十分友好破喻。

除此之外,前后端分離的方案盟榴,也帶來了其他的一些利好:前端側通過引入BFF層可輕松實現動態(tài)接口代理低缩、鑒權、日志曹货;服務端也可以做接口的微服務化;通過功能拆分讳推、組件懶加載等方式可以提升性能顶籽;也能夠更好的與傳統(tǒng)開發(fā)兼容,各施所長银觅;前后端獨立部署更加靈活礼饱、高效;也更易被第三方應用集成。

三镊绪、自研高性能渲染引擎

渲染引擎是由動態(tài)表單渲染器匀伏、列表渲染器和動態(tài)交互解釋器三部分組成的,他們能夠各司其職也可以相互配合蝴韭,渲染引擎的主要作用就是將可視化操作生成的DSL翻譯成具有功能邏輯和交互的頁面够颠、模板或組件。

先來看看表單渲染器榄鉴,

眾所周知履磨,表單場景一直都是前端中后臺領域最復雜的場景,通過自研的表單渲染引擎我們提供了表單數據管理庆尘、表單狀態(tài)管理剃诅、動態(tài)渲染、組件聯(lián)動等功能驶忌;基于JSONSchema驅動的分層架構矛辕,實現了邏輯與UI框架解耦;通常付魔,用戶只需要稍微了解幾個膠水層的API便可以快速上手聊品;復雜的場景下,用戶還可以通過拓展組件屬性或開發(fā)自定義組件的方式來滿足需求抒抬;另外杨刨,我們還將表單實例掛載到了動態(tài)交互的上下文,這樣我們就可以很輕松的實現各塊級組件聯(lián)動和數據交互擦剑。

特別說明的是妖胀,自研完全是為了更加貼合業(yè)務需要,開源社區(qū)有很多優(yōu)秀的動態(tài)解決方案惠勒,如formily2赚抡、x-render、formast纠屋,他們都有各自的優(yōu)缺點涂臣,我們也是權衡了利弊之后選擇的自研,當然我們也借鑒了x-render的api設計與formast的動態(tài)語法表達式售担,我們追求的是簡單赁遗、好用、高性能及完全可控族铆。

再來看看列表渲染器岩四,

列表是前端中后臺領域又一個非常重要的場景,為了滿足各種各樣的列表需求哥攘,我們二次開發(fā)了vxe-table這個功能豐富的開源列表庫剖煌,各種工具材鹦,復雜表格、樹形表格耕姊、編輯表格桶唐、虛擬滾動(ps:自定義渲染器的場景大數據的性能表現不佳)都是天然支持,我們額外內置了圖片茉兰、視頻等15種常用的渲染場景尤泽;與表單渲染器相同,列表渲染器依然是基于json-schema驅動的分層架構邦邦,學習成本極低安吁,拓展簡單,也支持用戶自定義渲染器燃辖;同樣鬼店,我們也將列表實例掛載到了動態(tài)交互的上下文,實現與其他塊級組件的聯(lián)動和數據交互黔龟。

說到列表妇智,我們提一下圖表,圖表你也可以理解為列表的另一種展現形式氏身,有了列表的開發(fā)經驗巍棱,圖表實現起來也十分輕松,只需要設計合理的DSL編譯后下發(fā)給第三方庫即可(如Echart)蛋欣,主要的思路還是和表單進行聯(lián)動航徙,由表單來驅動查詢條件,執(zhí)行異步查詢陷虎,得到的數據經過格式化后綁定到圖表即可到踏。

有了表單和列表,已經能夠搭出簡單頁面了尚猿,但是彈窗窝稿、按鈕交互、接口請求如何實現呢凿掂?動態(tài)交互是前端低代碼最復雜也是最有趣的部分伴榔,下面就來揭開它的神秘面紗。

如上圖所示庄萎,由用戶點擊按鈕發(fā)起踪少,彈出表單彈窗,填寫表單糠涛,發(fā)起接口請求秉馏,根據響應結果提示和列表刷新,其中有的是用戶交互脱羡,有的則是程序在驅動萝究;我們通過對這樣的動態(tài)交互流程建模,可以抽象出流程源和一個個流程節(jié)點;當用戶觸發(fā)交互,一個個交互節(jié)點組成了動態(tài)交互隊列筒饰,有序執(zhí)行珍策,雖然實際情況可能會更復雜,有異步腊嗡、有分支,但我們也僅僅通過不到30行的代碼便實現了整個動態(tài)交互的驅動,我們把這個核心解決方案稱之為動態(tài)交互解釋器秒紧,如下圖所示偽代碼。

同樣挨下,動態(tài)交互解釋器也是基于JSONSchema驅動的分層架構熔恢,解釋器僅僅是一層膠水和內置的交互流程節(jié)點;執(zhí)行器主要的功能就是貯藏動態(tài)節(jié)點臭笆、傳遞動態(tài)上下文叙淌、解釋執(zhí)行動態(tài)交互、流轉或終止流程愁铺。

前文我們多次提到了“將實例掛載到動態(tài)交互上下文”鹰霍,正如偽代碼中的ctx,這是一個響應式的上下文茵乱,我們會根據不同的業(yè)務場景有選擇性的掛載表單茂洒、列表、圖表的實例及相關方法和諸如路由信息瓶竭、全局狀態(tài)督勺、應用信息等其他用戶可能會需要的重要數據,以便各流程節(jié)點可以實時的訪問實例和動態(tài)修改對應的實例在验,這樣就實現了各區(qū)塊間的聯(lián)動交互玷氏。

動態(tài)交互解釋器也支持自定義,在極其復雜的場景下我們可以通過添加自定義流程節(jié)點的方式來拓展功能腋舌,滿足需求盏触。

四、高效的可視化配置方案

不同于其他低代碼平臺块饺,在后羿中赞辩,我們將頁面視為資源,按照資源級別來管理授艰、發(fā)布我們的配置辨嗽,這樣做的好處有兩個:

  • 第一、 我們可以根據資源的層級關系設計不同的導航風格淮腾,可以是tab-history模式糟需,也可以是面包屑模式屉佳,以及你能想到的任何菜單管理模式。

  • 第二洲押、 資源的管理與頁面的可視化配置解耦武花,管理更加高效;如上圖所示杈帐,除了可以隨時拖拽調整菜單結構体箕,還可以一目了然的看到資源的詳細信息;得益于這種設計挑童,我們提供了針對資源級別的版本發(fā)布功能累铅,可以實現一鍵迭代及線上熱更新;基于V消息的工單版本管理站叼,安全高效可追溯娃兽,還能夠實現秒級回退。

如上圖大年,我們還提供了模板换薄、代碼片段功能,模板專注于同類型頁面的復用翔试,代碼片段則專注于組件轻要、功能邏輯的復用;通過復用垦缅,可以極大的降低開發(fā)時間冲泥,5分鐘搭建頁面不再是紙上談兵。

系統(tǒng)功能上我們提供了一鍵開啟常用的水印壁涎、菜單搜索凡恍、消息通知等功能,還可以配置多種類型客服信息怔球,方便系統(tǒng)級的版本發(fā)布通知及日常的值班人員維護嚼酝。

頁面內容的配置我們采用了大家最習慣的從左到右的拖拽配置方式,可視化的配置方式便捷竟坛、高效闽巩,而且實時拖拽,即刻預覽担汤。

動態(tài)交互同樣支持可視化配置涎跨,流程的運轉邏輯清晰的展示在畫布上,直觀又容易維護崭歧。

此外隅很,我們還提供了一些貼心的功能:內置動態(tài)接口代理,一鍵開啟后率碾,即可連接本地或mock服務叔营,開發(fā)調試非常方便屋彪;統(tǒng)一的服務配置入口,除了符合開發(fā)直覺绒尊, 也方便了系統(tǒng)層面的接口管理及復用撼班,系統(tǒng)還會根據不同環(huán)境自動執(zhí)行接口匹配。

我們提供了頁面結構大綱視圖垒酬,只需點擊icon,便可以快速定位到組件件炉,解決了復雜頁面查找組件的痛苦勘究;

開發(fā)或迭代時,對頁面的改動無法追溯也是一個痛點斟冕,于是我們內置了版本比對口糕,只需拖拽任意兩個版本到比對框,就可以實現兩者的精確比對磕蛇,方便排查問題景描;每個版本也提供了版本快速回退,點擊即可一鍵回退秀撇。

右鍵功能也是提高配置效率的法寶超棺,基于右鍵,我們提供了組件的復制粘貼呵燕,并且可以跨區(qū)塊棠绘、跨頁面、跨應用的復制粘貼再扭;右鍵也可以快速定位到組件的schema氧苍,修改schema也會實時同步到視圖;代碼片段的保存復用也是基于右鍵來提供泛范。

得益于開發(fā)者平臺的分層設計让虐,只需按照編輯器協(xié)議配置,自定義組件同樣可以享受可視化的配置能力罢荡。

多層嵌套配置赡突,是可視化中相當痛苦的場景,于是我們提供了扁平化配置方案柠傍,比起層層堆疊的彈窗配置麸俘,配置更加方便,切換成本更低惧笛。

另外我們對新手用戶也十分友好从媚,除了引導式配置,我們還提供了字段級功能說明及文檔指引患整,以降低配置門檻拜效。

說到文檔(如上圖)喷众,這可能是很多低代碼平臺都會遇到的問題,我們認為一個好的文檔必須要能夠指引用戶由淺入深的學習平臺的使用姿勢紧憾,否則會直接勸退一大批用戶到千,我們的用戶主要面向開發(fā)者,這里面還分離出前端赴穗、后端憔四、應用、AI般眉、大數據等等了赵,如何讓各崗位的同學都能夠找到想要的解決方案真的是很棘手,于是我們由淺入深甸赃,層層展開柿汛,簡單到手把手教學,深入到整個核心庫的原理及實現埠对,并且還提供了海量的示例络断,包括數據聯(lián)動、動態(tài)交互项玛、布局等等貌笨。

五、千億級內容投放

內容投放是否高效會直接影響用戶的選擇稍计,后羿通過通用的 CURD 接口及可動態(tài)插拔的業(yè)務模塊來實現數據的存儲和處理躁绸。在用戶完成操作后統(tǒng)一執(zhí)行數據處理和入庫,并使用獨立的投放服務來快速分發(fā)到各業(yè)務系統(tǒng)臣嚣。

對于五花八門的運營數據我們會無差別的存放在MongoDB中净刮;通過自定義的分倉策略來保證業(yè)務隔離和可擴展;當然也會涉及到數據的多級關聯(lián)硅则,自定義檢索等淹父,多種手段的加持下才達到最后的精確分發(fā)。

后羿平臺承載了海量的業(yè)務數據怎虫,面對巨大的用戶流量暑认,我們必須保證投放的高可用。

如圖所示大审,我們在架構上采用獨立鏡像服務來承載各個大流量業(yè)務蘸际,各獨立服務又有本地緩存、磁盤緩存和獨立Redis集群來保證單體服務的高可用徒扶。

除了高可用粮彤,還要能夠支持高并發(fā),目前我們的QPS在百萬級別,每次請求可能會關聯(lián)查詢上百個表單导坟,最終就會放大到千屿良、萬億級別的表單查詢量。

我們通過異步加并發(fā)的方式提升服務的吞吐量惫周,結合異步監(jiān)聽尘惧、動態(tài)更新、定時重新加載等方式來提升系統(tǒng)的性能递递;多種手段的加持最終保證了服務的高并發(fā)喷橙。

對于個性化的業(yè)務訴求,我們還支持在后羿提供的SDK 上二次拓展登舞,這部分與傳統(tǒng)的開發(fā)幾乎沒有區(qū)別重慢。

六、低代碼如何與傳統(tǒng)開發(fā)共存

說到傳統(tǒng)開發(fā)逊躁,那我們就來聊聊這個老生常談的話題:

  • 低代碼如何與傳統(tǒng)開發(fā)共存?

  • 低代碼會取代程序員嗎隅熙?

  • 低代碼會不會干掉傳統(tǒng)開發(fā)稽煤?

  • 首先我們要明確的是,兩者并不沖突囚戚!

低代碼也不是銀彈酵熙,而傳統(tǒng)開發(fā)有著天然的定制化優(yōu)勢,靈活且沒有限制驰坊,配套的技術也相當成熟匾二;所以我們認為兩者共存,優(yōu)勢互補才能發(fā)揮更大的價值拳芙。

那后羿是如何實踐的呢察藐?

一方面我們不斷的豐富場景模型,提高拓展能力和配置效率舟扎;另一方面則從底層架構設計上兼容了傳統(tǒng)的定制化開發(fā)分飞;我們雙向支持iframe及微應用,雙向意味著后羿產出的頁面可以嵌入到第三方應用中睹限,也接受第三方應用嵌入到后羿中譬猫;并且支持頁面級、區(qū)塊級和組件級的嵌入羡疗。

這種設計除了可以發(fā)揮傳統(tǒng)開發(fā)優(yōu)勢染服,還能讓現存的老、舊應用發(fā)揮余熱叨恨,簡單改造柳刮,就可以將他們集成到后羿,然后在此基礎上使用低代碼能力繼續(xù)維護;得益于后羿將菜單與頁面內容隔離設計的方案诚亚,我們可以輕松的實現與第三方應用的兼容晕换,不破換其自有的菜單管理體系。

傳統(tǒng)開發(fā)場景站宗,為了讓大家專注于業(yè)務邏輯闸准,我們打通了樹懶的資源快速部署能力,并且提供了多種類型的工程腳手架梢灭,支持腳本命令一鍵發(fā)布迭代夷家;另外還支持素材托管,擁有獨立的業(yè)務空間敏释,安全又便捷库快。

以上就是后羿的低代碼實踐經驗,這么短的篇幅不足以揭開后羿的全貌钥顽,對于低代碼來說也只是杯水車薪义屏,我們利用現有的資源、服務蜂大、基建(基建真的很重要)以最小的成本孵化出來了后羿低代碼平臺闽铐,其實能做的還很多,我們也會持續(xù)探索奶浦,讓每個人都能享受到低代碼的樂趣兄墅。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市澳叉,隨后出現的幾起案子隙咸,更是在濱河造成了極大的恐慌,老刑警劉巖成洗,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件五督,死亡現場離奇詭異,居然都是意外死亡瓶殃,警方通過查閱死者的電腦和手機概荷,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碌燕,“玉大人误证,你說我怎么就攤上這事⌒藓荆” “怎么了愈捅?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長慈鸠。 經常有香客問我蓝谨,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任譬巫,我火速辦了婚禮咖楣,結果婚禮上,老公的妹妹穿的比我還像新娘芦昔。我一直安慰自己诱贿,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布咕缎。 她就那樣靜靜地躺著珠十,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凭豪。 梳的紋絲不亂的頭發(fā)上焙蹭,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音嫂伞,去河邊找鬼孔厉。 笑死,一個胖子當著我的面吹牛帖努,可吹牛的內容都是我干的烟馅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼然磷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刊驴?” 一聲冷哼從身側響起姿搜,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捆憎,沒想到半個月后舅柜,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡躲惰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年致份,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片础拨。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡氮块,死狀恐怖,靈堂內的尸體忽然破棺而出诡宗,到底是詐尸還是另有隱情滔蝉,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布塔沃,位于F島的核電站蝠引,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜螃概,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一矫夯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吊洼,春花似錦训貌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至超燃,卻和暖如春区拳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背意乓。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工樱调, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人届良。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓笆凌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親士葫。 傳聞我的和親對象是個殘疾皇子乞而,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容