國內(nèi) 90%以上的 iOS 開發(fā)者除盏,對 APNs 的認(rèn)識都是錯(cuò)的

前言: APNs 協(xié)議在近兩年的 WWDC 上改過兩次叉橱, 15 年 12 月 17 日更是推出了革命性的新特性。但在國內(nèi)傳播的博客者蠕、面試題里關(guān)于 APNs 的答案全都是舊的窃祝、錯(cuò)的。
導(dǎo)航:

  1. 對 APNs 的吐槽
  2. APNs新聞一欄
  3. 新舊 APNs 協(xié)議工作示意圖對比
  4. 反人類的舊APNs協(xié)議設(shè)計(jì)
  5. 基于 HTTP/2 的全新 APNs 協(xié)議
  6. 改進(jìn)了踱侣,但仍需改進(jìn)粪小。還是有坑
  7. 對App開發(fā)的影響
  8. 如何創(chuàng)建 Universal Push Notification Client SSL 證書
  9. 結(jié)束語

對 APNs 的吐槽

APNs 是 Apple Push Notification service 的簡稱(注意 APNs 的大小寫, s不需要大寫)大磺。

以下是我收集的一些關(guān)于 APNs 的吐槽,你先看下哪些吐槽比較“到位”:

-- 被吐槽的內(nèi)容 吐槽
1 使用第三方SDK接入推送服務(wù)探膊,SDK提供商卻告訴我杠愧,他們無法獲知哪條消息成功發(fā)送給了APNs,哪些失敗了逞壁,而且即使APNs接收了流济,APNs是否能保證投遞成功,他們也無能為力腌闯。 我把消息交給你了绳瘟,你告訴什么都保證不了?推送成功與否”基本靠猜“姿骏?
2
為什么我推了多條消息糖声,APNs就只給我最后一條?分瘦!
3 推送內(nèi)容只能是 256 字節(jié) 這也太小了蘸泻,根本不夠用啊嘲玫!
4 生產(chǎn)環(huán)境推送證書悦施、測試環(huán)境推送證書、tvOS推送證書趁冈、watchOS推送證書歼争、VOIP推送證書。渗勘。 證書太多了沐绒,制作、切換證書太麻煩旺坠!

答案會穿插在下文中乔遮。

APNs新聞一欄

時(shí)間 新聞 參考文檔
2014年6月 2014年6月份WWDC搭載iOS8及以上系統(tǒng)的iOS設(shè)備,能夠接收的最大playload大小提升到2KB取刃。低于iOS8的設(shè)備以及OS X設(shè)備維持256字節(jié)蹋肮。 What's New in Notifications - WWDC 2014 - Session 713 - iOS
enter image description here
2015年6月 2015年6月份WWDC宣布將在不久的將來發(fā)布 “基于 HTTP/2 的全新 APNs 協(xié)議”,并在大會上發(fā)布了僅僅支持測試證書的版本璧疗。 What's New in Notifications - WWDC 2015 - Session 720 - iOS, OS X
enter image description here
2015年12月17日 2015年12月17日起坯辩,發(fā)布 “基于 HTTP/2 的全新 APNs 協(xié)議”,iOS 系統(tǒng)以及 OS X 系統(tǒng),統(tǒng)一將最大 playload 大小提升到4KB崩侠。 Apple Push Notification Service Update 12-17 2015

新舊 APNs 協(xié)議工作示意圖對比

基于 HTTP/2 的新 APNs 協(xié)議 基于二進(jìn)制的舊 APNs 協(xié)議
enter image description here
enter image description here

接下來我們分別對新舊協(xié)議進(jìn)行一下介紹:

反人類的舊APNs協(xié)議設(shè)計(jì)

在介紹新版 APNs 前漆魔,讓我們來吐槽下舊的基于二進(jìn)制的 APNs 協(xié)議設(shè)計(jì)是多么反人類:

在理論上,推送分發(fā)的服務(wù)器要打開一個(gè)同 APNs 網(wǎng)關(guān)服務(wù)器的
連接,并保持這個(gè)連接改抡。但在舊的協(xié)議下矢炼,APNs 服務(wù)卻不保證 socket 能維持這個(gè)連接。如果通道上沒有消息往來阿纤,空閑下來到話句灌,socket將被路由掐斷。也就是說:APNs 連接說斷就斷欠拾,而你無能為力胰锌。有意思的是:在舊的協(xié)議下,如果服務(wù)器響應(yīng)成功的話清蚀,你將不會收到任何回應(yīng)匕荸,但是如果服務(wù)器響應(yīng)失敗(例如枷邪,使用了一個(gè)非法的 Push token),服務(wù)器將返回了一個(gè)錯(cuò)誤編碼诺凡,并關(guān)閉這個(gè)socket东揣。最重要的是,你必須重新發(fā)送使用這個(gè)無效 token 以后發(fā)送的所有推送(詳情見示意圖)腹泌。因此嘶卧,你可能一直不能確定你的推送是否成功的被 APNs 服務(wù)器接收。

成功了不響應(yīng)凉袱,失敗了才響應(yīng)芥吟,這個(gè)是最大的反人類。于是許多開發(fā)者想到了一個(gè)很 tricky 的辦法:利用這個(gè)“漏洞”专甩,比如在每發(fā)送10條后故意發(fā)送一個(gè)錯(cuò)誤的token钟鸵,如果APNs有響應(yīng)了,就可以確認(rèn) APNs 是處在可用狀態(tài)的涤躲,進(jìn)而確認(rèn)這10條消息是發(fā)送成功的棺耍。如果沒有響應(yīng)就說明可能連接已經(jīng)中斷,那么這10條消息很可能是丟失的种樱,然后做進(jìn)一步的處理蒙袍。但代價(jià)顯而易見:將導(dǎo)致你們的推送系統(tǒng)性能低下。(本文中所說到“你們的推送系統(tǒng)”嫩挤,如果是使用的第三方的SDK完成的推送服務(wù)害幅,那么就是指SDK提供商所搭建的推送系統(tǒng)。如果是你們公司自己搭建的推送系統(tǒng)岂昭,那么就是指你們自己的推送系統(tǒng)以现。)蘋果有一個(gè)名為"feedback"的服務(wù),我們可以定時(shí)調(diào)用這個(gè)服務(wù)來獲取invalid tokens的列表。這個(gè)服務(wù)你只要調(diào)用一次就可以獲得所有的invalid tokens 列表叼风。所以取董,如果一個(gè)應(yīng)用使用了很多不同公司的推送SDK,他們將會爭奪資源去輪詢查找invalid tokens列表无宿。invalid token越多茵汰,你們的推送系統(tǒng)性能將越低。而且 APNs 只要一發(fā)生錯(cuò)誤就關(guān)閉這個(gè)連接孽鸡,然后重新連接蹂午。也就是“重啟” socket 連接。

示意圖:

enter image description here

圖中的 PN2 去哪里了彬碱?它被放到了 feedback 列表里豆胸,等待下次你調(diào)用 feedback 服務(wù),然后重發(fā)巷疼。

為什么Apple要在舊APNs中設(shè)計(jì)出“重啟”的策略晚胡?

為了效率。

就像PC機(jī)出問題嚼沿,我們總說“重啟能解決90%的問題”估盘。

為了理解“重啟”策略,我們可以類比下骡尽,熟悉 Erlang/OTP 的朋友可能知道遣妥, Erlang/OTP 在處理錯(cuò)誤方面有獨(dú)到之處:監(jiān)督樹(supervision trees)。大致來說攀细,每一個(gè) Erlang 進(jìn)程都由一個(gè)監(jiān)督進(jìn)程發(fā)起并監(jiān)視箫踩。當(dāng)一個(gè)進(jìn)程遇到了問題的時(shí)候,它就會退出谭贪。當(dāng)進(jìn)程退出的時(shí)候境钟,其監(jiān)督進(jìn)程會將其重啟。

(這些監(jiān)督進(jìn)程由一個(gè)引導(dǎo)進(jìn)程(bootstrap process)發(fā)起故河,當(dāng)監(jiān)督進(jìn)程遇到錯(cuò)誤的時(shí)候吱韭,引導(dǎo)進(jìn)程會將其重啟)

其思想是,快速的失敗然后重啟比去處理錯(cuò)誤要快鱼的。像這樣的錯(cuò)誤處理看起來跟直覺相反 —— 當(dāng)錯(cuò)誤發(fā)生的時(shí)候通過放棄處理來獲得可靠性理盆。但是重啟的確是解決暫時(shí)性錯(cuò)誤的靈丹妙藥。

這也可能讓你想到 DNS 服務(wù)發(fā)展史:

DNS 在設(shè)計(jì)之初是基于 UDP 的凑阶,顯然這樣的設(shè)計(jì)不能滿足當(dāng)今社會的準(zhǔn)確性的需求猿规,于是涌現(xiàn)了如 DNSPod 這樣的基于 HTTP 的 DNS 解析服務(wù)。但是當(dāng)時(shí)為什么這樣設(shè)計(jì)宙橱,實(shí)際也很好理解姨俩,UDP 效率高蘸拔,一來一回網(wǎng)絡(luò)上傳輸?shù)闹挥袃蓚€(gè)包,而 HTTP則需要三次握手三個(gè)包环葵,再一拆包调窍,就需要四個(gè)包。這是受限于當(dāng)時(shí)整個(gè)社會的帶寬水平較低张遭,而現(xiàn)在沒人會感激 UDP 所節(jié)省的流量邓萨,所有人都在詬病DNS污染問題。這樣你也許就理解了菊卷,為什么舊的 APNs 設(shè)計(jì)如此反人類缔恳。這個(gè)是必經(jīng)階段。

那么接下來就讓我們看看Apple為解決這些問題而推出的基于 HTTP/2 的全新 APNs 協(xié)議洁闰。

基于 HTTP/2 的全新 APNs 協(xié)議

來看下新版的 APNs 的新特性:

  • Request 和 Response 支持JSON網(wǎng)絡(luò)協(xié)議
  • APNs支持狀態(tài)碼和返回 error 信息
  • APNs推送成功時(shí) Response 將返回狀態(tài)碼200歉甚,遠(yuǎn)程通知是否發(fā)送成功再也不用靠猜了!
  • APNs推送失敗時(shí)扑眉,Response 將返回 JSON 格式的 Error 信息纸泄。
  • 最大推送長度提升到4096字節(jié)(4Kb)
  • 可以通過 “HTTP/2 PING ” 心跳包功能檢測當(dāng)前 APNs 連接是否可用,并能維持當(dāng)前長連接襟雷。
  • 支持為不同的推送類型定義 “topic” 主題
  • 不同推送類型刃滓,只需要一種推送證書 Universal Push Notification Client SSL 證書。

示意圖:

enter image description here

其中最大的變化就是基于了 HTTP/2 協(xié)議耸弄,采用了長連接設(shè)計(jì),并提供 “HTTP/2 PING ” 心跳包功能檢測卓缰、維持當(dāng)前 APNs 連接计呈,解決了老 APNs 無法維持連接的問題。
而且新增的狀態(tài)碼特性征唬,也解決了這個(gè)問題:無法獲知消息是否成功地從你們的推送系統(tǒng)投遞到了 APNs 上捌显。理論上,你們可以保證消息是100%投遞到了APNs的总寒,因?yàn)槟憧梢詼?zhǔn)確的知道哪條消息到達(dá)了APNs扶歪,哪些沒到。重發(fā)特定失敗消息成為可能摄闸。

所以上文開頭的吐槽中第一條善镰,有一句是“不到位的”,因?yàn)楝F(xiàn)在SDK的提供商能夠準(zhǔn)確地告訴你哪些消息推送到APNs了年枕,哪些沒有炫欺。

順便介紹下 HTTP/2:

HTTP/2 是 HTTP 協(xié)議發(fā)布后的首個(gè)更新,于2015年2月17日被批準(zhǔn)熏兄。它采用了一系列優(yōu)化技術(shù)來整體提升 HTTP 協(xié)議的傳輸性能品洛,如異步連接復(fù)用树姨、頭壓縮等等,可謂是當(dāng)前互聯(lián)網(wǎng)應(yīng)用開發(fā)中桥状,網(wǎng)絡(luò)層次架構(gòu)優(yōu)化的首選方案之一帽揪。

Apple 對于 HTTP/2 的態(tài)度也非常積極,2015年5月 HTTP/2 正式發(fā)表后不久辅斟,便在緊接著6月召開的WWDC 2015大會中转晰,向全球開發(fā)者宣布,iOS 9 開始支持HTTP/2砾肺。

而且如果我們要使用 HTTP/2挽霉,那么在網(wǎng)絡(luò)庫的選擇上必然要使用 NSURLSession。

我們都知道 HTTP/2 是復(fù)用 TCP 管道連接的变汪,而且 HTTP/2 也以高復(fù)用著稱侠坎,這也使新的 APNs 協(xié)議更加高性能。(題外話:這點(diǎn)也同樣體現(xiàn)在 NSURLSession 底層對于每個(gè) session 是對多個(gè) task 進(jìn)行連接的復(fù)用裙盾。)

Universal Push Notification Client SSL 證書

在開發(fā)中实胸,往往一條內(nèi)容,需要向多個(gè)終端進(jìn)行推送番官,終端有:iOS庐完、tvOS、 and OS X devices, 和借助iOS來實(shí)現(xiàn)推送的 Apple Watch徘熔。在以往的開發(fā)中门躯,不同的推送,需要配置不同的推送證書:我們需要配置:dev證書酷师、prod證書讶凉、VOIP證書、等等山孔。而從2015年12月17日起懂讯,只使用一種證書就可以了,不再需要那么多證書台颠,這種證書就叫做Universal Push Notification Client SSL 證書(下文統(tǒng)一簡稱:Universal推送證書)褐望。

改進(jìn)了,但仍需改進(jìn)串前。還是有坑

APNs的確改進(jìn)來不少瘫里,但仍有需要改進(jìn)對地方。還是有坑:

除了獲取TLS證書比較復(fù)雜未解決外酪呻,還有一些坑:

文章開頭提到過以下這種情況:

很遺憾的告訴你减宣,你的吐槽是“到位的”:你以后還得忍受這種反人類的設(shè)計(jì)。

這中間發(fā)生了什么玩荠?

當(dāng) APNs 向你發(fā)送了多條推送漆腌,但是你的設(shè)備網(wǎng)絡(luò)狀況不好贼邓,在 APNs 那里下線了,這時(shí) APNs 到你的手機(jī)的鏈路上有多條任務(wù)堆積闷尿,APNs 的處理方式是塑径,只保留最后一條消息推送給你,然后告知你推送數(shù)填具。那么其他三條消息呢统舀?會被APNs丟棄。

有一些 App 的 IM 功能沒有維持長連接劳景,是完全通過推送來實(shí)現(xiàn)到誉简,通常情況下,這些 App 也已經(jīng)考慮到了這種丟推送的情況盟广,這些 App 的做法都是闷串,每次收到推送之后,然后向自己的服務(wù)器查詢當(dāng)前用戶的未讀消息筋量。但是APNs也同樣無法保證這多條推送能至少有一條到達(dá)你的 App烹吵。很遺憾的告訴這些App,這次的更新對你們所遭受對這些坑桨武,沒有改善肋拔。

為什么這么設(shè)計(jì)?APNs的存儲-轉(zhuǎn)發(fā)能力太弱呀酸,大量的消息存儲和轉(zhuǎn)發(fā)將消耗Apple服務(wù)器的資源凉蜂,可能是出于存儲成本考慮,也可能是因?yàn)?Apple 轉(zhuǎn)發(fā)能力太弱性誉≡颈梗總之結(jié)果就是 APNs 從來不保證消息的達(dá)到率。并且設(shè)備上線之后也不會向服務(wù)器上傳信息艾栋。

所以上文開頭的吐槽中第一條,也有一句是“到位的”蛉顽,因?yàn)楝F(xiàn)在SDK的提供商依然無法保證蝗砾,消息推到了 APNs,APNs能推到 App 那里携冤。

但Google Cloud Messaging就有這些特性悼粮。而且 GCM 現(xiàn)在也支持iOS設(shè)備了,那么 APNs 和 GCM 現(xiàn)在就形成了競爭關(guān)系曾棕。讓我共同期待 APNs 在2016年6月的 WWDC 的能有新的改進(jìn)吧扣猫。

對App開發(fā)的影響

想使用新協(xié)議,如果你用的第三方推送翘地,這里最明顯的操作申尤,就是你必須更新到支持新協(xié)議的SDK版本癌幕。因?yàn)樾聟f(xié)議需要 SDK 上傳你 app 的 bundle id ,生成各個(gè)平臺推送用的 topic。如果你們自己搭建的服務(wù)昧穿,則需要你自己上傳勺远。老協(xié)議不用上傳。

新 APNs 支持 iOS6 等全版本推送內(nèi)容達(dá)4096字節(jié)时鸵,舊 APNs 是14年6月之前只支持256字節(jié)胶逢,在此之后支持 iOS8 以上2048字節(jié)。以前受限于推送字節(jié)饰潜,比如推文章 url初坠,開發(fā)者選擇超出256后推送id,甚至不判斷直接推 id彭雾,接收后再請求完整 url碟刺。一旦請求錯(cuò)誤,推送內(nèi)容可能丟失」邗危現(xiàn)在可以避免了南誊。

如何創(chuàng)建 Universal Push Notification Client SSL 證書

現(xiàn)在你知道什么是 Universal Push Notification Client SSL 證書了,那么如何創(chuàng)建它蜜托?

what is Universal Push Notification Client SSL Certificate
what is Universal Push Notification Client SSL Certificate

圖中其他方式抄囚,就叫做非 Universal 方式(下文簡稱:非 Universal 推送證書):

what is not Universal Push Notification Client SSL Certificate

這里也推薦使用 Universal 推送證書來進(jìn)行推送服務(wù)。詳細(xì)的創(chuàng)建步驟如下所示:

  1. 前往蘋果開發(fā)者中心進(jìn)行登錄橄务,并點(diǎn)擊 “Certificates, Identifiers & Profiles”幔托。
    enter Certificates, Identifiers & Profiles
  2. 選擇在 Certificates 欄下的“All”。
  3. 點(diǎn)擊下圖中紅色邊框內(nèi)的加號按鈕蜂挪。


    Create SSL certificate
    Create SSL certificate
  4. 選擇 “Production” 欄下的 “Apple Push Notification service SSL (Sandbox & Production)” 勾選后重挑,點(diǎn)擊下一步。


    Select push certificate
    Select push certificate
  5. 從 App ID 下拉菜單中選擇你需要的 App ID 棠涮,點(diǎn)擊下一步谬哀。


    select App ID
  6. 這時(shí)會出現(xiàn) About Creating a Certificate Signing Request (CSR)
    guide to create a CSR
    guide to create a CSR

根據(jù)它的說明創(chuàng)建 Certificate Signing Request严肪。

how to create a CSR
  1. 點(diǎn)擊下圖中的 “Choose File” 按鈕:


    upload CSR File
    upload CSR File
  2. 上傳剛剛生成的 .certSigningRequest 文件 生成 APNs Push Certificate史煎。
  3. 下載證書。
  4. 雙擊打開證書驳糯,證書打開時(shí)會啟動(dòng)鑰匙串訪問工具篇梭。
    在鑰匙串訪問工具中,你的證書會顯示在 “證書” 中酝枢,注意選擇左下角的 “證書” 和左上角 “登錄”恬偷。
confirm create cer success

結(jié)束語

對于 APNs 而言,iOS9 的這一更新是有劃時(shí)代意義的帘睦,請即刻敦促你們公司的服務(wù)端進(jìn)行升級袍患,或者使用支持新 APNs 協(xié)議的 SDK 進(jìn)行推送服務(wù)坦康。 文中如有錯(cuò)誤,并請幫忙指正协怒,反饋請發(fā)往微博@iOS程序犭袁涝焙。

參考鏈接:

  1. Configuring Push Notifications
  2. APNs Provider API
  3. HTTP/2 Protocol for iOS Push Notification Server(APNS)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孕暇,隨后出現(xiàn)的幾起案子仑撞,更是在濱河造成了極大的恐慌,老刑警劉巖妖滔,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隧哮,死亡現(xiàn)場離奇詭異,居然都是意外死亡座舍,警方通過查閱死者的電腦和手機(jī)沮翔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曲秉,“玉大人采蚀,你說我怎么就攤上這事〕卸” “怎么了榆鼠?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亥鸠。 經(jīng)常有香客問我妆够,道長,這世上最難降的妖魔是什么负蚊? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任神妹,我火速辦了婚禮,結(jié)果婚禮上家妆,老公的妹妹穿的比我還像新娘鸵荠。我一直安慰自己,他們只是感情好伤极,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布腰鬼。 她就那樣靜靜地躺著,像睡著了一般塑荒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姜挺,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天齿税,我揣著相機(jī)與錄音,去河邊找鬼炊豪。 笑死凌箕,一個(gè)胖子當(dāng)著我的面吹牛拧篮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牵舱,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼串绩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芜壁?” 一聲冷哼從身側(cè)響起礁凡,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慧妄,沒想到半個(gè)月后顷牌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塞淹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年窟蓝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饱普。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡运挫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出套耕,到底是詐尸還是另有隱情谁帕,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布箍铲,位于F島的核電站雇卷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颠猴。R本人自食惡果不足惜关划,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翘瓮。 院中可真熱鬧贮折,春花似錦、人聲如沸资盅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呵扛。三九已至每庆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間今穿,已是汗流浹背缤灵。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腮出。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓帖鸦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胚嘲。 傳聞我的和親對象是個(gè)殘疾皇子作儿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容