美團的Webview優(yōu)化

在App開發(fā)中直撤,內(nèi)嵌WebView始終占有著一席之地。它能以較低的成本實現(xiàn)Android型豁、iOS和Web的復用,也可以冠冕堂皇的突破蘋果對熱更新的封鎖尚蝌。

然而便利性的同時迎变,WebView的性能體驗卻備受質疑,導致很多客戶端中需要動態(tài)更新等頁面時不得不采用其他方案飘言。

以發(fā)展的眼光來看衣形,功能的動態(tài)加載以及三端的融合將會是大趨勢。那么如何克服WebView固有的問題呢姿鸿?我們將從性能谆吴、內(nèi)存消耗、體驗般妙、安全幾個維度纪铺,來系統(tǒng)的分析客戶端默認WebView的問題,以及對應的優(yōu)化方案碟渺。

對于WebView的性能鲜锚,給人最直觀的莫過于:打開速度比native慢突诬。

是的,當我們打開一個WebView頁面芜繁,頁面往往會慢吞吞的loading很久旺隙,若干秒后才出現(xiàn)你所需要看到的頁面。

這是為什么呢骏令?

對于一個普通用戶來講蔬捷,打開一個WebView通常會經(jīng)歷以下幾個階段:

  1. 交互無反饋
  2. 到達新的頁面,頁面白屏
  3. 頁面基本框架出現(xiàn)榔袋,但是沒有數(shù)據(jù)周拐;頁面處于loading狀態(tài)
  4. 出現(xiàn)所需的數(shù)據(jù)
    如果從程序上觀察,WebView啟動過程大概分為以下幾個階段:


    Webview啟動時間

如何縮短這些過程的時間凰兑,就成了優(yōu)化WebView性能的關鍵妥粟。

接下來我們逐一分析各個階段的耗時情況,以及需要注意的優(yōu)化點吏够。

WebView初始化

當App首次打開時勾给,默認是并不初始化瀏覽器內(nèi)核的;只有當創(chuàng)建WebView實例的時候锅知,才會創(chuàng)建WebView的基礎框架播急。

所以與瀏覽器不同,App中打開WebView的第一步并不是建立連接售睹,而是啟動瀏覽器內(nèi)核桩警。

我們來分析一下這段耗時到底需要多久。

分析

針對WebView的初始化時間侣姆,我們可以定義兩個指標:

測試內(nèi)容:
首次初始化時間:客戶端冷啟動后生真,第一次打開WebView沉噩,從開始創(chuàng)建WebView到開始建立網(wǎng)絡連接之間的時間捺宗。
二次初始化時間:在打開過WebView后,退出WebView川蒙,再重新打開WebView蚜厉,從開始創(chuàng)建WebView到開始建立網(wǎng)絡連接之間的時間。

測試數(shù)據(jù):
測試系統(tǒng)1: iOS模擬器畜眨,Titans 10.0.7
測試系統(tǒng)2: OPPO R829T Android 4.2.2
測試方式:測試10次取平均值
測試App:美團外賣
單位:ms


首次初始化時間 二次初始化時間
iOS(UIWebView) 306.56 76.43
iOS(WKWebView) 763.26 457.25
Android 192.79 * 142.53

注:Android外賣客戶端啟動后會在后臺開啟WebView進程昼牛,故并不是完全新建WebView時間

怎么優(yōu)化

由于這段過程發(fā)生在native的代碼中,單純靠前端代碼是無法優(yōu)化的康聂;大部分的方案都是前端和客戶端協(xié)作完成贰健,以下是幾個業(yè)界采用過的方案。

1. 全局WebView

方法:
在客戶端剛啟動時恬汁,就初始化一個全局的WebView待用伶椿,并隱藏;
當用戶訪問了WebView時,直接使用這個WebView加載對應網(wǎng)頁脊另,并展示导狡。
這種方法可以比較有效的減少WebView在App中的首次打開時間。當用戶訪問頁面時偎痛,不需要初始化WebView的時間旱捧。
參考:https://patents.google.com/patent/CN106250434A/zh

當然這也帶來了一些問題,包括:

  • 額外的內(nèi)存消耗踩麦。
  • 頁面間跳轉需要清空上一個頁面的痕跡枚赡,更容易內(nèi)存泄露。
2. 客戶端代理數(shù)據(jù)請求

方法:
在客戶端初始化WebView的同時谓谦,直接由native開始網(wǎng)絡請求數(shù)據(jù)标锄;
當頁面初始化完成后,向native獲取其代理請求的數(shù)據(jù)茁计。
此方法雖然不能減小WebView初始化時間料皇,但數(shù)據(jù)請求和WebView初始化可以并行進行,總體的頁面加載時間就縮短了星压;縮短總體的頁面加載時間:
參考:https://mp.weixin.qq.com/s/evzDnTsHrAr2b9jcevwBzA?

還有其他各種優(yōu)化的方式践剂,不再一一列舉,總結起來都是圍繞兩點:

  • 在使用前預先初始化好WebView娜膘,從而減小耗時逊脯。
  • 在初始化的同時,通過Native來完成一些網(wǎng)絡請求等過程竣贪,使得WebView初始化不是完全的阻塞后續(xù)過程军洼。

建立連接/服務器處理

在頁面請求的數(shù)據(jù)返回之前,主要有以下過程耗費時間演怎。

  • DNS
  • connection
  • 服務器處理
優(yōu)化

這些時間都是發(fā)生在網(wǎng)頁加載之前匕争,但這并不意味著無法優(yōu)化,有以下幾種方法爷耀。

DNS采用和客戶端API相同的域名

DNS會在系統(tǒng)級別進行緩存甘桑,對于WebView的地址,如果使用的域名與native的API相同歹叮,則可以直接使用緩存的DNS而不用再發(fā)起請求圖片跑杭。

以美團為例,美團的客戶端請求域名主要位于api.meituan.com咆耿,然而內(nèi)嵌的WebView主要位于 i.meituan.com德谅。

當我們初次打開App時:

  • 客戶端首次打開都會請求api.meituan.com,其DNS將會被系統(tǒng)緩存萨螺。
  • 然而當打開WebView的時候窄做,由于請求了不同的域名宅荤,需要重新獲取i.meituan.com的IP。

根據(jù)上面的統(tǒng)計浸策,至少10%的用戶打開WebView時耗費了60ms在DNS上面冯键,如果WebView的域名與App的API域名統(tǒng)一,則可以讓WebView的DNS時間全部達到1.3ms的量級庸汗。

靜態(tài)資源同理惫确,最好與客戶端的資源域名保持一致。

同步渲染采用chunk編碼

同步渲染時如果后端請求時間過長蚯舱,可以考慮采用chunk編碼改化,將數(shù)據(jù)放在最后,并優(yōu)先將靜態(tài)內(nèi)容flush枉昏。對于傳統(tǒng)的后端渲染頁面陈肛,往往都是使用的【瀏覽器】–> 【W(wǎng)eb API】 –> 【業(yè)務 API】的加載模式,其中后端時間就指的是Web API的處理時間了兄裂。在這里Web API一般有兩個作用:

  1. 確定靜態(tài)資源的版本句旱。
  2. 根據(jù)用戶的請求,去業(yè)務API獲取數(shù)據(jù)晰奖。

而一般確定靜態(tài)資源的版本往往是直接讀取代碼版本谈撒,基本無耗時;而主要的后端時間都花費在了業(yè)務API請求上面匾南。

那么怎么優(yōu)化利用這段時間呢啃匿?

在HTTP協(xié)議中,我們可以在header中設置 transfer-encoding:chunked 使得頁面可以分塊輸出蛆楞。如果合理設計頁面溯乒,讓head部分都是確定的靜態(tài)資源版本相關內(nèi)容,而body部分是業(yè)務數(shù)據(jù)相關內(nèi)容豹爹,那么我們可以在用戶請求的時候裆悄,首先將Web API可以確定的部分先輸出給瀏覽器,然后等API完全獲取后帅戒,再將API數(shù)據(jù)傳輸給瀏覽器灯帮。

下圖可以直觀的看出分chunk輸出和一起輸出的區(qū)別:


分chunk加載
  • 如果采用普通方式輸出頁面,則頁面會在服務器請求完所有API并處理完成后開始傳輸逻住。瀏覽器要在后端所有API都加載完成后才能開始解析。
  • 如果采用chunk-encoding: chunked迎献,并優(yōu)先將頁面的靜態(tài)部分輸出瞎访;然后處理API請求,并最終返回頁面吁恍,可以讓后端的API請求和前端的資源加載同時進行扒秸。
  • 兩者的總共后端時間并沒有區(qū)別播演,但是可以提升首字節(jié)速度,從而讓前端加載資源和后端加載API不互相阻塞伴奥。
頁面框架渲染

頁面在解析到足夠多的節(jié)點写烤,且所有CSS都加載完成后進行首屏渲染。在此之前拾徙,頁面保持白屏洲炊;在頁面完全下載并解析完成之前,頁面處于不完整展示狀態(tài)尼啡。

分析

我們以一個美團的活動頁面作為樣例:

測試頁面:http://i.meituan.com/firework/meituanxianshifengqiang
在Mac上面暂衡,模擬4G情況
頁面樣式:

頁面

測試得到的時間耗費如下:
表1

階段 時間 大小 備注
DOM下載 58ms 29.5?KB 4G網(wǎng)絡
DOM解析 12.5ms 198?KB 根據(jù)估算,在手機上慢2~5倍不等
CSS請求+下載 58ms 11.7?KB 4G網(wǎng)絡(包含鏈接時間崖瞭,CDN)
CSS解析 2.89ms 54.1?KB 根據(jù)估算狂巢,在手機上慢2~5倍不等
渲染 23ms 1361節(jié)點 根據(jù)估算,在手機上慢2~5倍不等
繪制 4.1ms 根據(jù)估算书聚,在手機上慢2~5倍不等
合成 0.23ms GPU處理

同時唧领,對HTML的加載時間進行分析,可以得到如下時間點雌续。

表2

指標 時間 計算方法
HTML加載完成時間 218 performance.timing.responseEnd - performance.timing.fetchStart
HTML解析完成時間 330 performance.timing.domInteractive - performance.timing.fetchStart
這意味著什么呢疹吃?

對于表1
可以看到,隨著在網(wǎng)絡優(yōu)良的情況下西雀,Dom的解析所占耗時比例還是不算低的萨驶,對于低端機器更甚。Layout時間也是首屏前耗時的大頭艇肴,據(jù)猜測這與頁面使用了rem作為單位有關(待進一步分析)腔呜。

對于表2,我們可以發(fā)現(xiàn)一個問題
一般來說HTML在開始接收到返回數(shù)據(jù)的時候就開始解析HTML并構建DOM樹再悼。如果沒有JS(JavaScript)阻塞的話一般會相繼完成核畴。然而,在這里時間相差了90ms……也就是說冲九,解析被阻塞了谤草。

進一步分析可以發(fā)現(xiàn),頁面的header部分有這樣的代碼:

.....
<link  rel="stylesheet" onload="MT.pageData.eveTime=Date.now()"/>
<script>
window.fk = function (callback) {
require(['util/native/risk.js'], function (risk) {
    risk.getFk(callback);
});
}
</script>
</head>
....

通常情況下莺奸,上面代碼的link部分和script部分如果單獨出現(xiàn)丑孩,都不會阻塞頁面的解析:

  • CSS不會阻止頁面繼續(xù)向下繼續(xù)。

  • 內(nèi)聯(lián)的JS很快執(zhí)行完成灭贷,然后繼續(xù)解析文檔温学。
    然而,當這兩部分同時出現(xiàn)的時候甚疟,問題就來了仗岖。

  • CSS加載阻塞了下面的一段內(nèi)聯(lián)JS的執(zhí)行逃延,而被阻塞的內(nèi)聯(lián)JS則阻塞了HTML的解析。
    通常情況下轧拄,CSS不會阻塞HTML的解析揽祥,但如果CSS后面有JS,則會阻塞JS的執(zhí)行直到CSS加載完成(即便JS是內(nèi)聯(lián)的腳本)檩电,從而間接阻塞HTML的解析拄丰。

優(yōu)化

在頁面框架加載這一部分,能夠優(yōu)化的點參照雅虎14條就夠了是嗜;但注意不要犯錯愈案,一個小小的內(nèi)聯(lián)JS放錯位置也會讓性能下降很多。

  1. CSS的加載會在HTML解析到CSS的標簽時開始鹅搪,所以CSS的標簽要盡量靠前站绪。
  2. 但是,CSS鏈接下面不能有任何的JS標簽(包括很簡單的內(nèi)聯(lián)JS)丽柿,否則會阻塞HTML的解析恢准。
  3. 如果必須要在頭部增加內(nèi)聯(lián)腳本,一定要放在CSS標簽之前甫题。
CSS帶來的阻塞解析
JS加載

對于大型的網(wǎng)站來說馁筐,在此我們先提出幾個問題:

  • 將全部JS代碼打成一個包,造成首次執(zhí)行代碼過大怎么辦坠非?
  • 將JS以細粒度打包敏沉,造成請求過多怎么辦?
  • 將JS按 “基礎庫” + “頁面代碼” 分別打包炎码,要怎么界定什么是基礎代碼盟迟,什么是頁面代碼;不同頁面用的基礎代碼不一致怎么辦潦闲?
  • 單一文件的少量代碼改的是否會導致緩存失效攒菠?
  • 代碼模塊間有動態(tài)依賴,怎樣合并請求歉闰。

關于這些問題的解決方案數(shù)量可能會比問題還多辖众,而它們也各有優(yōu)劣。
具體分析太過復雜和敬,鑒于篇幅原因在這里不做具體分析了凹炸。您可以期待我們的后續(xù)計劃:BPM(瀏覽器包管理)。

JS解析概龄、編譯还惠、執(zhí)行

在PC互聯(lián)網(wǎng)時代,人們似乎都快忘記了JS的解析和執(zhí)行還需要消耗時間私杜。確實蚕键,在幾年前網(wǎng)速還在用kb衡量的時代里,JS的解析時間在整個頁面的打開時間里只能算是九牛一毛衰粹。

然而锣光,隨著網(wǎng)速越來越快,而CPU的速度反而沒有提升(從PC到手機)铝耻,JS的時間開銷就成為問題了誊爹。那么JS的編譯和解析,在當今的頁面上要消耗多少時間呢瓢捉?

分析

我們用以下方式來檢驗JS代碼的解析/編譯和執(zhí)行時間:

<script>
    window.t1 = performance.now()
</script>
<script>
    window.test = function () {
        // test code
    }
</script>
<script>
    window.t2 = performance.now()
    test();
    window.t3 = performance.now();
     
    alert("編譯耗時:" + (t2 - t1));
    alert("執(zhí)行耗時:" + (t3 - t2));
</script>

將測試代碼放入 【test code】 位置频丘,然后在手機中執(zhí)行;

  • 在t1~t2期間泡态,JS代碼僅僅聲明了一個函數(shù)搂漠,主要時間會集中在解析和編譯過程;
  • 在t2~t3時間段內(nèi)某弦,執(zhí)行test時時間主要為代碼的執(zhí)行時間

在首次啟動客戶端后桐汤,打開WebView的測試頁面,我們可以得到如下的結果:

測試系統(tǒng): iPhone6 iOS 10.2.1
測試系統(tǒng): OPPO R829T Android 4.2.2
內(nèi)容值: 編譯時間(ms)/執(zhí)行時間(ms)

系統(tǒng) Zepto.js Vue.js React.js + ReactDOM.js
iOS 5.2 / 8 12.8 / 16.1 13.7 / 43.3
Android 13 / 40 43 / 127 26 / 353

當保持客戶端進行不關閉情況下靶壮,關閉WebView并重新訪問測試頁面怔毛,再次測試得到如下結果:

系統(tǒng) Zepto.js Vue.js React.js + ReactDom.js
iOS 0.9 / 1.9 5 / 7.4 3.5 / 23
Android 5 / 9 17 / 12 25 / 60

執(zhí)行時間指的是框架代碼加載的頁面的初始化時間,沒有任何業(yè)務的調用腾降。

這意味著什么

經(jīng)過測試可以得出以下結論: * 偏重的框架拣度,例如React,僅僅初始化的時間就會達到50ms ~ 350ms螃壤,這在對性能敏感的業(yè)務中時比較不利的抗果。 * 在App的啟動周期內(nèi),統(tǒng)一域名下的代碼會被緩存編輯和初始化結果映穗,重復調用性能較好窖张。

所以,在移動瀏覽器上蚁滋,JS的解析和執(zhí)行時間并不是不可忽略的宿接。

在低端安卓機上,(框架的初始化+異步數(shù)據(jù)請求+業(yè)務代碼執(zhí)行)會遠高于幾KB網(wǎng)絡請求時間辕录;高性能的Web網(wǎng)站需要仔細斟酌前端渲染帶來的性能問題睦霎。

優(yōu)化

  • 高性能要求頁面還是需要后端渲染。
  • React還是太重了走诞,面向用戶寫系統(tǒng)需要謹慎考慮副女。
  • JS代碼的編譯和執(zhí)行會有緩存,同App中網(wǎng)頁盡量統(tǒng)一框架蚣旱。

WebView性能優(yōu)化總結

一個加載網(wǎng)頁的過程中碑幅,native戴陡、網(wǎng)絡、后端處理沟涨、CPU都會參與恤批,各自都有必要的工作和依賴關系;讓他們相互并行處理而不是相互阻塞才可以讓網(wǎng)頁加載更快:

  • WebView初始化慢裹赴,可以在初始化同時先請求數(shù)據(jù)喜庞,讓后端和網(wǎng)絡不要閑著。
  • 后端處理慢棋返,可以讓服務器分trunk輸出延都,在后端計算的同時前端也加載網(wǎng)絡靜態(tài)資源。
  • 腳本執(zhí)行慢睛竣,就讓腳本在最后運行晰房,不阻塞頁面解析。
  • 同時酵颁,合理的預加載嫉你、預緩存可以讓加載速度的瓶頸更小。
  • WebView初始化慢,就隨時初始化好一個WebView待用。
  • DNS和鏈接慢伸辟,想辦法復用客戶端使用的域名和鏈接。
  • 腳本執(zhí)行慢距误,可以把框架代碼拆分出來,在請求頁面之前就執(zhí)行好扁位。

WebView被運營商劫持准潭、注入問題

由于WebView加載的頁面代碼是從服務器動態(tài)獲取的,這些代碼將會很容易被中間環(huán)節(jié)所竊取或者修改域仇,其中最主要的問題出自地方運營商(浙江尤其明顯)和一些WiFi刑然。

我們監(jiān)測到的問題包括:

  • 無視通信規(guī)則強制緩存頁面。
  • header被篡改暇务。
  • 頁面被注入廣告泼掠。
  • 頁面被重定向。
  • 頁面被重定向并重新iframe到新頁面垦细,框架嵌入廣告择镇。
  • HTTPS請求被攔截。
  • DNS劫持括改。
    這些問題輕則影響用戶體驗腻豌,重則泄露數(shù)據(jù),或影響公司信譽。

針對頁面注入的行為吝梅,有一些解決方案:

使用CSP(Content Security Policy)
CSP可以有效的攔截頁面中的非白名單資源虱疏,而且兼容性較好。在美團移動版的使用中憔涉,能夠阻止大部分的頁面內(nèi)容注入订框。

但在使用中還是存在以下問題:

由于業(yè)務的需要析苫,通常inline腳本還是在白名單中兜叨,會導致完全依賴內(nèi)聯(lián)的頁面代碼注入可以通過檢測。
如果注入的內(nèi)容是純HTML+CSS的內(nèi)容衩侥,則CSP無能為力国旷。
無法解決頁面被劫持的問題。
會帶來額外的一些維護成本茫死。
總體來說CSP是一個行之有效的防注入方案跪但,但是如果對于安全要求更高的網(wǎng)站,這些還不夠峦萎。

HTTPS

HTTPS可以防止頁面被劫持或者注入屡久,然而其副作用也是明顯的,網(wǎng)絡傳輸?shù)男阅芎统晒β识紩陆蛋疲襀TTPS的頁面會要求頁面內(nèi)所有引用的資源也是HTTPS的被环,對于大型網(wǎng)站其遷移成本并不算低。

HTTPS的一個問題在于:一旦底層想要篡改或者劫持详幽,會導致整個鏈接失效筛欢,頁面無法展示。這會帶來一個問題:本來頁面只是會被注入廣告唇聘,而且廣告會被CSP攔截版姑,而采用了HTTPS后,整個網(wǎng)頁由于受到劫持完全無法展示迟郎。

對于安全要求不高的靜態(tài)頁面剥险,就需要權衡HTTPS帶來的利與弊了。

App使用Socket代理請求

如果HTTP請求容易被攔截宪肖,那么讓App將其轉換為一個Socket請求表制,并代理WebView的訪問也是一個辦法。

通常不法運營商或者WiFi都只能攔截HTTP(S)請求匈庭,對于自定義的包內(nèi)容則無法攔截夫凸,因此可以基本解決注入和劫持的問題。

Socket代理請求也存在問題阱持。

  • 首先夭拌,使用客戶端代理的頁面HTML請求將喪失邊下載邊解析的能力;根據(jù)前面所述,瀏覽器在HTML收到部分內(nèi)容后就立刻開始解析鸽扁,并加載解析出來的外鏈蒜绽、圖片等,執(zhí)行內(nèi)聯(lián)的腳本……而目前WebView對外并沒有暴露這種流式的HTML接口桶现,只能由客戶端完全下載好HTML后躲雅,注入到WebView中。因此其性能將會受到影響骡和。
  • 其次相赁,其技術問題也是較多的,例如對跳轉的處理慰于,對緩存的處理钮科,對CDN的處理等等……稍不留神就會埋下若干大坑。

此外還有一些其他的辦法婆赠,例如頁面的MD5檢測绵脯,頁面靜態(tài)頁打包下載等等方式,具體如何選擇還要根據(jù)具體的場景抉擇休里。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛆挫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子妙黍,更是在濱河造成了極大的恐慌悴侵,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件废境,死亡現(xiàn)場離奇詭異畜挨,居然都是意外死亡,警方通過查閱死者的電腦和手機噩凹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門巴元,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驮宴,你說我怎么就攤上這事逮刨。” “怎么了堵泽?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵修己,是天一觀的道長。 經(jīng)常有香客問我迎罗,道長睬愤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任纹安,我火速辦了婚禮尤辱,結果婚禮上砂豌,老公的妹妹穿的比我還像新娘。我一直安慰自己光督,他們只是感情好阳距,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著结借,像睡著了一般筐摘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上船老,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天咖熟,我揣著相機與錄音,去河邊找鬼努隙。 笑死球恤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的荸镊。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼堪置,長吁一口氣:“原來是場噩夢啊……” “哼躬存!你這毒婦竟也來了?” 一聲冷哼從身側響起舀锨,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤岭洲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后坎匿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盾剩,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年替蔬,在試婚紗的時候發(fā)現(xiàn)自己被綠了告私。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡承桥,死狀恐怖驻粟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情凶异,我是刑警寧澤蜀撑,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站剩彬,受9級特大地震影響酷麦,放射性物質發(fā)生泄漏。R本人自食惡果不足惜喉恋,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一沃饶、第九天 我趴在偏房一處隱蔽的房頂上張望粪摘。 院中可真熱鬧,春花似錦绍坝、人聲如沸徘意。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椎咧。三九已至,卻和暖如春把介,著一層夾襖步出監(jiān)牢的瞬間勤讽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工拗踢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脚牍,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓巢墅,卻偏偏與公主長得像诸狭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子君纫,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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