關(guān)于 node.js 在公司基礎(chǔ)框架中的應(yīng)用

項(xiàng)目名稱:關(guān)于 node.js 在公司基礎(chǔ)框架中的應(yīng)用

修訂歷史

版本號(hào) 作者 時(shí)間
1.0 廖石榮(0027011057),林飛鵬(0027011438) 2019-01-11

1 概述

1.1 術(shù)語

Node.js 是一個(gè) Javascript 運(yùn)行環(huán)境(runtime environment),發(fā)布于 2009 年 5 月,由 Ryan Dahl 開發(fā)娃磺,實(shí)質(zhì)是對(duì) Chrome V8 引擎進(jìn)行了封裝粘拾。Node.js 不是一個(gè) JavaScript 框架菠赚,不同于CakePHP荣病、Django舟茶、Rails柿冲。Node.js 更不是瀏覽器端的庫(kù)茬高,不能與 jQuery、ExtJS 相提并論假抄。Node.js 是一個(gè)讓 JavaScript 運(yùn)行在服務(wù)端的開發(fā)平臺(tái)怎栽,它讓 JavaScript 成為與PHPPython宿饱、Perl熏瞄、Ruby 等服務(wù)端語言平起平坐的腳本語言

1.2 需求背景

最近部門某個(gè)項(xiàng)目在開發(fā)完成初次上線之后谬以,由于接口復(fù)雜强饮,數(shù)據(jù)庫(kù)設(shè)計(jì)等原因?qū)е陆涌诜祷爻瑫r(shí),特別是多人同時(shí)使用這個(gè)系統(tǒng)为黎,并發(fā)性存在問題邮丰,后來通過后端將接口由串行改為并行方式返回?cái)?shù)據(jù),數(shù)據(jù)庫(kù)增加索引等方式雖然解決了問題铭乾,但是花費(fèi)的時(shí)間比較多而且復(fù)雜剪廉,所以后來在想有沒有一個(gè)好的架構(gòu)可以避免這種問題,由于畢業(yè)設(shè)計(jì)的時(shí)候接觸過 node.js片橡,我知道 node.js 可以解決高并發(fā)妈经,它是單線程,當(dāng)訪問量很多時(shí)捧书,將訪問者分配到不同的內(nèi)存中吹泡,不同的內(nèi)存區(qū)做不同的事,以快速解決這個(gè)線程经瓷。就像醫(yī)院的分科室看病人爆哑。效率快,但消耗內(nèi)存大舆吮、異步和事件驅(qū)動(dòng)揭朝。概擴(kuò)起來就三點(diǎn):?jiǎn)尉€程队贱、異步 I/O、事件驅(qū)動(dòng)潭袱。nodejs 離不開 ChormeV8 引擎柱嫌,也就是 V8 引擎是來解釋 javascript。用 nodejs 來搭建高性能的 Web 服務(wù)器屯换,因此 node.js 是基于服務(wù)器端的 javascript编丘。
由于項(xiàng)目規(guī)模越來越大,前后端分離必然是個(gè)趨勢(shì)彤悔,當(dāng)前的分離模式如下圖:

后端 前端
提供數(shù)據(jù) 接收數(shù)據(jù)嘉抓,返回?cái)?shù)據(jù)
處理業(yè)務(wù)邏輯 處理渲染邏輯
Server-side MVC 架構(gòu) Client-side MV* 架構(gòu)
代碼跑在服務(wù)器上 代碼跑在瀏覽器上

這里分離干凈了,分工也很明確了晕窑,看似一切都那么美好抑片,but...我們也很容易發(fā)現(xiàn)問題的所在:

  1. Client-side Model 是 Server-side Model 的加工
  2. Client-side View 跟 Server-side 是 不同層次的東西
  3. Client-side 的 Controller 跟 Sever-side 的 Controller 各搞各的
  4. Client-side 的 Route 但是 Server-side 可能沒有

也就是說服務(wù)端和客戶端各層職責(zé)重疊,大家各搞各的杨赤,很難統(tǒng)一具體要做的事情敞斋。并且可能會(huì)伴隨著一些性能上的問題。最具體的表現(xiàn)就是我們常用的 SPA 應(yīng)用:

  1. 渲染望拖,取值都在客戶端進(jìn)行渺尘,有性能的問題
  2. 需要等待資源到齊才能進(jìn)行,會(huì)有短暫白屏與閃動(dòng)
  3. 在移動(dòng)設(shè)備低速網(wǎng)路的體驗(yàn)奇差無比
  4. 渲染都在客戶端说敏,模版無法重用鸥跟,SEO 實(shí)現(xiàn) 麻煩

緊接著,我們代碼量越來越大盔沫,我們需要校驗(yàn)的表單也會(huì)越來越多医咨,有時(shí)候,前端提交需要校驗(yàn)一次表單架诞。
服務(wù)端任需要進(jìn)行校驗(yàn)來達(dá)到數(shù)據(jù)的可靠性拟淮;前端的路由可能在服務(wù)端并不存在....等等這一系列重用性的問題。所以我們之前的重構(gòu)可能需要更深層次的思考谴忧。

1.3 目標(biāo)

高可用很泊,高并發(fā),穩(wěn)定性沾谓,速度快

2 系統(tǒng)構(gòu)架重構(gòu)

在開始重構(gòu)之前委造,我們需要對(duì)前后端界線做一個(gè)劃分,也就是說什么是屬于前端的范疇均驶,什么是屬于后端的范疇昏兆,最傳統(tǒng)的前后端劃分可能是這樣的:


8.png
8.png

那么問題來了:我們前后端劃分的接線,是依照工作職責(zé)來劃分的前后端妇穴;還是依照硬體環(huán)境劃分的前后端爬虱?自從了 nodejs 之后隶债,我們可以從工作職能上重新定義前后端的范疇:


9.png
9.png

可以看到,這里的前端比之前多了個(gè) nodejs跑筝,也就是在前后端之間我們構(gòu)建了一個(gè) nodejs 服務(wù)作為中間層死讹!
為什么我們選擇的中間層是 nodejs 呢?因?yàn)槲覀儼阎虚g層歸在了前端的范疇曲梗,那么對(duì)前端小伙伴來說回俐,nodejs 畢竟還是個(gè) js,那么從語法角度來說稀并,上收起來應(yīng)該沒有什么問題。其次開發(fā)轉(zhuǎn)移成本也想對(duì)較低单默,不必來回切換語言的邏輯和語法:
  1. 前端熟悉的語言碘举,學(xué)習(xí)成本低
  2. 都是 JS,可以前后端復(fù)用
  3. 體質(zhì)適合:事件驅(qū)動(dòng)搁廓、非阻塞 I/O
  4. 適合 IO 密集型業(yè)務(wù)
  5. 執(zhí)行速度也不差

好了引颈,提前說了這么多東西,那么這個(gè)中間層能給我們帶來什么了境蜕?要知道引入 nodejs 的開發(fā)成本也是很大的蝙场,首先就是多了一層服務(wù),多的不說粱年,單憑傳輸時(shí)間售滤,就多了一層的傳輸時(shí)間啊台诗!下面我們來研究一下什么應(yīng)用場(chǎng)景下的 nodejs 能給我們帶來利大于弊的東西完箩。

3 中間層應(yīng)用場(chǎng)景以及性能問題

引入 nodejs 之后,我們來重新劃分一下前后端的職能:


10.png
10.png

11.png
11.png

這個(gè)就是中間層 nodejs 的主要思路拉队,下面我們來看一下常見的業(yè)務(wù)場(chǎng)景:

3.1 常見業(yè)務(wù)場(chǎng)景

3.1.1 接口數(shù)據(jù)可靠性修復(fù)

有的時(shí)候服務(wù)端返回給我們的數(shù)據(jù)可能并不是前端想要的結(jié)構(gòu)弊知,所有用到的展現(xiàn)數(shù)據(jù)都是后端通過異步接口(AJAX/JSONP)的方式提供的,前端只管展現(xiàn)粱快。但是后端經(jīng)常提供后端的數(shù)據(jù)邏輯秩彤,在前端還需要去處理這些數(shù)據(jù)邏輯。比如我再開發(fā)一個(gè)功能的時(shí)候事哭,有時(shí)候會(huì)碰到這樣的問題:


12.png
12.png
13.png
13.png

服務(wù)端返回的某個(gè)字段為 null 或者服務(wù)端返回的數(shù)據(jù)結(jié)構(gòu)太深漫雷,前端需要不斷寫這樣的代碼去判斷數(shù)據(jù)結(jié)構(gòu)是否真的返回了正確的東西,而不是個(gè) null 或者 undefined:

if (params.items && params.items.type && ...) {
   // todo
}

對(duì)于這種情況慷蠕,我們前端其實(shí)不應(yīng)該去重復(fù)校驗(yàn)數(shù)據(jù)的格式珊拼,這也本不應(yīng)該是瀏覽器端 js 需要做的事情。我們可以在中間層做接口轉(zhuǎn)發(fā)流炕,在轉(zhuǎn)發(fā)的過程中做數(shù)據(jù)處理澎现。而不用擔(dān)心數(shù)據(jù)返回的問題:

router.get("/buyer/product/detail", (req, res, next) => {
  httpRequest.get("/buyer/product/detail", (data) => {
    // todo 處理數(shù)據(jù)
    res.send(data);
  });
});

3.1.2 頁面性能優(yōu)化 和 SEO

有點(diǎn)時(shí)候我們做單頁面應(yīng)用仅胞,經(jīng)常會(huì)碰到首屏加載性能問題,這個(gè)時(shí)候如果我們接了中間層 nodejs 的話剑辫,那么我們可以把首屏渲染的任務(wù)交給 nodejs 去做干旧,次屏的渲染依然走之前的瀏覽器渲染。(前端換頁妹蔽,瀏覽器端渲染椎眯,直接輸入網(wǎng)址,服務(wù)器渲染)服務(wù)端渲染對(duì)頁面進(jìn)行拼接直出 html 字符串胳岂,可以大幅提高首屏渲染的時(shí)間编整,減少用戶的等待時(shí)間。這種形式應(yīng)用最廣的比如 Vue 的服務(wù)端渲染乳丰,里面也有相關(guān)的介紹掌测。
其次對(duì)于單頁面的 SEO 優(yōu)化也是很好地處理方式,由于目前的 ajax 并不被搜索百度等搜索引擎支持产园,所以如果想要得到爬蟲的支持汞斧,那么服務(wù)端渲染也是一種解決方法。

3.2 中間層性能問題

多加了一層通訊什燕,肯定會(huì)有一定的性能損耗粘勒。但分層帶來的損失,一定能在其他方面的收益彌補(bǔ)回來屎即,而且合理的分層能讓職責(zé)清晰庙睡、方便協(xié)作,大大提升開發(fā)效率技俐。也可以通過優(yōu)化通訊方式和協(xié)議埃撵,盡可能把損耗降到最低。

一個(gè)靜態(tài)化的詳情頁面上有很多(動(dòng)態(tài))的數(shù)據(jù)虽另,用戶資料暂刘、評(píng)論信息、訂單等等捂刺,需要 5谣拣、6 個(gè)異步請(qǐng)求,node 中間層可以代理這些請(qǐng)求族展,輕松實(shí)現(xiàn) Bigpipe森缠。
在 PC 上你覺得發(fā) 5,6 個(gè)異步請(qǐng)求也沒什么,但是在無線端仪缸,在客戶手機(jī)上建立一個(gè) HTTP 請(qǐng)求開銷很大贵涵,有了這個(gè)優(yōu)化,性能一下提升好幾倍。

3.3 容易拓展多種語言接口

目前 Node.js 可以支持調(diào)用 python , c++ 等其它語言接口宾茂,這樣可以每個(gè)模塊選擇最優(yōu)技術(shù)語言解決方案瓷马,不用局限于 Java 一種語言了,技術(shù)壁壘也可以打破跨晴。

3.4 淘寶常見的需求解決方案

需求:在淘寶欧聘,單日四億 PV,頁面數(shù)據(jù)來自各個(gè)不同接口端盆,為了不影響體驗(yàn)怀骤,先產(chǎn)生頁面框架后,在發(fā)起多個(gè)異步請(qǐng)求取數(shù)據(jù)更新頁面焕妙,這些多出來的請(qǐng)求帶來的影響不小蒋伦,尤其在無線端。
解決方案:在 NodeJS 端使用 Bigpiper 技術(shù)焚鹊,合并請(qǐng)求凉敲,降低負(fù)擔(dān),分批輸出寺旺,不影響體驗(yàn)。同時(shí)可以拆分大接口為獨(dú)立小接口势决,并發(fā)請(qǐng)求阻塑。串行 => 并行,大幅縮短請(qǐng)求時(shí)間果复。

3.5 開源的成熟方案

目前 Node.js 業(yè)界比較成熟的方案很多陈莽,如:

  • express
  • koa
  • sails
  • loopback
  • thinkjs
  • egg

express
這個(gè)是使用最多的框架,也是各個(gè)推薦新手入門的框架虽抄。
Express 不對(duì) Node.js 已有的特性進(jìn)行二次抽象走搁,只是在它之上擴(kuò)展了 Web 應(yīng)用所需的基本功能(個(gè)人感覺相當(dāng)于 node 中的 jquery)

  • 封裝了路由
  • 靜態(tài)資源托管
  • 中間件的概念
  • 內(nèi)置了 jade,ejs 模板引擎

個(gè)人評(píng)價(jià)迈窟,express 適合小型項(xiàng)目私植,不適合大型企業(yè)級(jí)項(xiàng)目,個(gè)人用用還可以车酣,做為快速入門是個(gè)很好的選擇曲稼,用過之后就可以考慮進(jìn)入 koa 框架的道路

koa2

koa 是比 express 思想更先進(jìn)的框架,是 express 原班人馬打造
koa 解決的最大問題湖员,利用 async await 的新語法特性贫悄,解決回調(diào)地獄的問題
koa 與 express 最大的不同,個(gè)人覺得有 3 點(diǎn): 1.在于 handler 的處理方法娘摔,express 是普通的回調(diào)函數(shù)窄坦, koa 是利用 ES7 中 Async/Await 的特性,沒有回調(diào),沒有回調(diào)鸭津,就大大加速了開發(fā)速度這一點(diǎn)而言彤侍,已經(jīng)足以讓我們跪舔了
2.koa 是洋蔥中間件模式,執(zhí)行到 next 的時(shí)候曙博,會(huì)去調(diào)用下一個(gè)中間件拥刻,下個(gè)中間件執(zhí)行完再接著執(zhí)行上個(gè)中間件 next 下面的代碼
3.koa 把 request, response 封裝到了同一個(gè)上下文對(duì)象 content
最為 express 的進(jìn)化,確實(shí)帶來更好的開發(fā)效率父泳,成本只需要學(xué)西一下 async await 的新語法特性般哼。可以說作為 express 框架的進(jìn)階框架是非常好的了

后面的這幾個(gè)都是企業(yè)級(jí)框架

express =》koa 之后惠窄,最大的問題就是開發(fā)項(xiàng)目的時(shí)候缺少約束蒸眠,單人開發(fā)還好,多人的時(shí)候杆融,各種目錄結(jié)構(gòu)楞卡,各種包的選擇,百花齊放的代碼風(fēng)格脾歇。都是團(tuán)隊(duì)開發(fā)頭疼的事情蒋腮。
因?yàn)楸救酥白鲞^ php 開發(fā),laravel 框架的使用起來很舒服(優(yōu)雅E焊鳌)池摧,還有配套的 laravel-admin。所以一直想找一個(gè)能像 laravel 這樣的 node 框架提高開發(fā)效率
回到正題激况,sails , loopback, thinkjs, egg 都是企業(yè)級(jí)框架作彤,我們又該如何選擇
Sails 是基于 exrpess 的大而全的框架,MVC 框架乌逐,旨在模擬熟悉的 Ruby on Rails 框架的 MVC 模式竭讳,但支持現(xiàn)代應(yīng)用程序的需求。捆綁了一個(gè)強(qiáng)大的 ORM浙踢,即 Waterline绢慢。自動(dòng)生成的 REST API
LoopBack 是建立在 Express 基礎(chǔ)上的企業(yè)級(jí) Node.js 框架,只需編寫少量代碼就能創(chuàng)建動(dòng)態(tài)端到端的 REST API洛波,一致化的模型關(guān)系和對(duì) API 訪問的權(quán)限控制等
ThinkJS 是國(guó)內(nèi) 360 團(tuán)隊(duì)推出的一款面向未來開發(fā)的 Node.js 框架呐芥,整合了大量的項(xiàng)目最佳實(shí)踐,讓企業(yè)級(jí)開發(fā)變得如此簡(jiǎn)單奋岁、高效思瘟。框架底層基于 Koa 2.x 實(shí)現(xiàn)闻伶,兼容 Koa 的所有功能
Egg.js 是《阿里旗下產(chǎn)品》基于 Node.js 和 Koa 的一個(gè) Nodejs 的企業(yè)級(jí)應(yīng)用開發(fā)框架滨攻,它可以幫助開發(fā)團(tuán)隊(duì)及開發(fā)人員降低開發(fā)和維護(hù)成本。Egg.js 則是按照約定進(jìn)行開發(fā),奉行『約定優(yōu)于配置』光绕,具備提供基于 Egg 定制上層框架的能力女嘲、

高度可擴(kuò)展的插件機(jī)制、內(nèi)置多進(jìn)程管理诞帐、基于 Koa 開發(fā)欣尼,性能優(yōu)異、框架穩(wěn)定停蕉,測(cè)試覆蓋率高愕鼓、漸進(jìn)式開發(fā)、開發(fā)成本和維護(hù)成本低等特點(diǎn)慧起。

4 總結(jié)

4.1 對(duì)現(xiàn)有團(tuán)隊(duì)的影響

常見的前后端分離的開發(fā)模式中菇晃,后端為前端提供了路由結(jié)構(gòu)和頁面的數(shù)據(jù)綁定,前端只需要切頁面和少量的邏輯蚓挤。
在 node 中間層中磺送,前端不僅僅要切頁面和做頁面邏輯,還要做 url design灿意、頁面數(shù)據(jù)綁定估灿、聯(lián)調(diào)與溝通,還要考慮 SEO 的問題缤剧,偽靜態(tài)頁面馅袁、title/keyword 設(shè)置、網(wǎng)站地圖鞭执,甚至包括錯(cuò)誤日志等等。雖然前端的工作量增加了不少芒粹,但是基于模塊化的開發(fā)兄纺,讓總體的效率提升了。
對(duì)于后端程序員化漆,接口整合的工作交給了前端服務(wù)器進(jìn)行處理估脆,同時(shí)和前端耦合度大大降低,工作量和工作效率都減少了座云。
另外疙赠,由于前后端分離,測(cè)試都可以分開來了朦拖,專門測(cè)試接口的和專門測(cè)試 ui 層圃阳。分析項(xiàng)目對(duì)本系統(tǒng)的影響,例如:

  • 新加的業(yè)務(wù)璧帝,功能有沒有影響原有的功能
  • 系統(tǒng)的改造對(duì)原有業(yè)務(wù)有什么影響
  • 有沒有影響系統(tǒng)對(duì)外提供的服務(wù)的約定捍岳,這非常重要

4.1 個(gè)人期望

我覺得,以后基于 NodeJs 的全棧式開發(fā)的模式將會(huì)越來越流行,這也會(huì)引領(lǐng)前端步入工程化時(shí)代锣夹。但是要把 Node 全棧開發(fā)變成一個(gè)穩(wěn)定的页徐、方便的開發(fā)工具,還有很多路要走银萍。公司也可以一步一步慢慢往這個(gè)方向上靠攏变勇,打造高可用的框架平臺(tái)產(chǎn)品。

本文部分圖片段落參考文章: 淘寶前后端分離實(shí)踐

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贴唇,一起剝皮案震驚了整個(gè)濱河市搀绣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滤蝠,老刑警劉巖豌熄,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異物咳,居然都是意外死亡锣险,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門览闰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芯肤,“玉大人,你說我怎么就攤上這事压鉴⊙伦桑” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵油吭,是天一觀的道長(zhǎng)击蹲。 經(jīng)常有香客問我,道長(zhǎng)婉宰,這世上最難降的妖魔是什么歌豺? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮心包,結(jié)果婚禮上类咧,老公的妹妹穿的比我還像新娘。我一直安慰自己蟹腾,他們只是感情好痕惋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娃殖,像睡著了一般值戳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炉爆,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天述寡,我揣著相機(jī)與錄音柿隙,去河邊找鬼。 笑死鲫凶,一個(gè)胖子當(dāng)著我的面吹牛禀崖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播螟炫,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼波附,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了昼钻?” 一聲冷哼從身側(cè)響起掸屡,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎然评,沒想到半個(gè)月后仅财,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碗淌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年盏求,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亿眠。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碎罚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纳像,到底是詐尸還是另有隱情荆烈,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布竟趾,位于F島的核電站憔购,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岔帽。R本人自食惡果不足惜玫鸟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望山卦。 院中可真熱鬧鞋邑,春花似錦诵次、人聲如沸账蓉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铸本。三九已至,卻和暖如春遵堵,著一層夾襖步出監(jiān)牢的瞬間箱玷,已是汗流浹背怨规。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锡足,地道東北人波丰。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像舶得,于是被迫代替她去往敵國(guó)和親掰烟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355