HTTPDNS在iOS端的實(shí)踐

DNS解析本質(zhì)上是localDNS的解析想鹰,說白了,你給它一個域名购披,它返回給你一個IPlist

DNS(Domain Name System)域名解析系統(tǒng)杖挣,這個東西說對于開發(fā)者來說,應(yīng)該是沒有不知道的刚陡。說簡單點(diǎn)惩妇,這個系統(tǒng)的作用就是將域名解析成IP地址。我們的每一次網(wǎng)絡(luò)請求筐乳,如果是使用域名歌殃,那么就是進(jìn)行域名解析。
一個優(yōu)秀的域名服務(wù)應(yīng)該能夠滿足兩點(diǎn)要求

  • 能夠正確的返回IP地址蝙云,
  • 就是能夠根據(jù)網(wǎng)絡(luò)情況返回所請求的域名最近的服務(wù)器IP氓皱。

一: DNS解析路線

DNS劫持和故障.png

LocalDNS
一個DNS查詢,會先從本地緩存查找勃刨,如果沒有或者已經(jīng)過期波材,就從DNS服務(wù)器查詢,如果客戶端沒有主動設(shè)置DNS服務(wù)器身隐,一般是從服務(wù)商DNS服務(wù)器上查找廷区。這就出現(xiàn)了不可控。因?yàn)槿绻褂昧薎PS的LocalDNS域名服務(wù)器贾铝,那么基本都會或多或少地?zé)o法避免在有中國特色的互聯(lián)網(wǎng)環(huán)境中遭遇到各種域名被緩存隙轻、用戶跨網(wǎng)訪問緩慢等問題。
我們先來看看普通域名服務(wù)會有什么問題:

  • 1. 域名劫持
    一些小服務(wù)商以及小地方的服務(wù)商非常喜歡干這個事情垢揩。根據(jù)騰訊給出的數(shù)據(jù)玖绿,DNS劫持率7%,惡意劫持率2%叁巨。網(wǎng)速給的劫持率是10-15%斑匪。

    • 把你的域名解析到競爭對手那里,然后哭死都不知道俘种,為什么流量下降了秤标。
    • 在你的代碼當(dāng)中绝淡,插入廣告或者追蹤代碼。這就是為什么在淘寶或者百度搜索一下東西苍姜,很快就有人聯(lián)系你牢酵。
    • 下載APK文件的時候,替換你的文件衙猪,下載一個其他應(yīng)用或者山寨應(yīng)用馍乙。
    • 打開一個頁面,先跳轉(zhuǎn)到廣告聯(lián)盟垫释,然后跳轉(zhuǎn)到這個頁面丝格。無緣無故多花廣告錢,以及對運(yùn)營的誤導(dǎo)棵譬。
  • 2.智能DNS策略失效

智能DNS显蝌,就是為了調(diào)度用戶訪問策略,但是這些因素會導(dǎo)致智能DNS策略失效订咸。

  • 小運(yùn)營商曼尊,沒有DNS服務(wù)器,直接調(diào)用別的服務(wù)商脏嚷,導(dǎo)致服務(wù)商識別錯誤骆撇,直接跨網(wǎng)傳輸,速度大大下降父叙。
  • 服務(wù)商多長NAT恋腕,實(shí)際IP莺掠,獲得不了,結(jié)果沒有就近訪問宇植。
  • 一些運(yùn)營商將IP設(shè)置到開卡地布疼,即使漫游到其他地方城豁,結(jié)果也是沒有就近訪問逗抑。

目前國內(nèi)大多數(shù)企業(yè)對于域名解析這塊問題沒有進(jìn)行特殊處理镊绪,這導(dǎo)致了上述說的那些問題,其中域名劫持的問題相當(dāng)普遍带欢。那么有沒有一種方法能夠避免上述的情況呢?有烤惊,當(dāng)然有乔煞。那就是使用HTTPDNS
HttpDNS其實(shí)也是對DNS解析的另一種實(shí)現(xiàn)方式柒室,只是將域名解析的協(xié)議由DNS協(xié)議換成了Http協(xié)議渡贾,并不復(fù)雜。使用HTTP協(xié)議向D+服務(wù)器的80端口進(jìn)行請求雄右,代替?zhèn)鹘y(tǒng)的DNS協(xié)議向DNS服務(wù)器的53端口進(jìn)行請求空骚,繞開了運(yùn)營商的Local DNS纺讲,從而避免了使用運(yùn)營商Local DNS造成的劫持和跨網(wǎng)問題。
接入HttpDNS也是很簡單的囤屹,使用普通DNS時熬甚,客戶端發(fā)送網(wǎng)絡(luò)請求時,就直接發(fā)送出去了肋坚,有底層網(wǎng)絡(luò)框架進(jìn)行域名解析乡括。當(dāng)接入HttpDNS時,就需要自己發(fā)送域名解析的HTTP請求智厌,當(dāng)客戶端拿到域名對應(yīng)的IP之后诲泌,就向直接往此IP發(fā)送業(yè)務(wù)協(xié)議請求。
這樣铣鹏,就再也不用再考慮傳統(tǒng)DNS解析會帶來的那些問題了敷扫,因?yàn)槭鞘褂肏TTP協(xié)議,所以不用擔(dān)心域名劫持問題了诚卸;而且葵第,如果選擇好的DNS服務(wù)器提供商,還保證將用戶引導(dǎo)的訪問速度最快的IDC節(jié)點(diǎn)上惨险。
HTTPDNS是使用http請求替換域名解析的過程羹幸,但一般這個http請求都是基于https的,且是IP直連的辫愉,這樣我們就保證了栅受,這個解析域名的http請求不會被劫持并且內(nèi)容安全.

二:HTTPDNS服務(wù)

我們一般在客戶端上做HTTPDNS服務(wù)的解決方案的時候,策略可簡單可復(fù)雜恭朗,但大體要圍繞以下幾個問題:

  • 1.數(shù)據(jù)要預(yù)先獲取屏镊,
  • 2.運(yùn)營商變化的時候要更新數(shù)據(jù)
  • 3.為了提升獲取ip的成功率要有過期數(shù)據(jù)的預(yù)取策略痰腮,
  • 4.當(dāng)由于種種原因而芥,獲取不到HTTPDNSIP時,要降級為獲取localDNSIP

iOS網(wǎng)絡(luò)庫沒有Android的網(wǎng)絡(luò)庫訂制的那么深度膀值,其實(shí)就是AFNetworkingokhttp的差距棍丐,所以針對HTTPDNS的網(wǎng)路庫適配(才是今天的最佳實(shí)踐)iOS會更加原始一些,它處理的問題大致有以下幾類

  • 域名替換IP沧踏,防止劫持的關(guān)鍵就是不采用域名請求歌逢,取而代之的是IP直連

  • ** https的處理,由于替換了IP翘狱,https可信任域名檢驗(yàn)機(jī)制獲取不到域名**

  • HTTP Proxy的處理秘案,當(dāng)iOS網(wǎng)絡(luò)切換成HTTP代理后,由于替換了IP會導(dǎo)致連接失敗,一般的處理方式是關(guān)閉HTTPDNS服務(wù)

  • Cookie的處理阱高,由于替換了IP赚导,導(dǎo)致Cookiedomain獲取不到,從而使Cookie失效

  • IPV6的處理赤惊,蘋果在2016年強(qiáng)制推行的IPV6吼旧,由于我們切換成IP直連的方式,所以會在iOS8.4以下的版本荐捻,IPV6-only的網(wǎng)絡(luò)環(huán)境下連接失敗黍少,蘋果官方的建議采用getAddressInfo方法解決這個問題,但這個方法在iOS9.2后才支持將一個IPV4的IP轉(zhuǎn)成一個IPV6的IP处面,所以我們一般會在這種情況下降級

  • UIWebView/WKWebView的處理厂置,不管是哪種WebView,我們都可以采用蘋果的黑科技NSURLProtocol進(jìn)行網(wǎng)絡(luò)層面的攔截魂角,從而接管WebView的網(wǎng)絡(luò)能力昵济,從而支持WebViewDNS反劫持

HTTPDNS解析.png

iOS端的網(wǎng)絡(luò)層是基于AFNetworking進(jìn)行封裝實(shí)現(xiàn)的,iOS端的網(wǎng)絡(luò)框架NSURLSession沒有提供DNS解析相關(guān)的接口供使用者進(jìn)行自定義修改DNS解析結(jié)果野揪,因此在iOS端接入HTTPDNS有幾個通用的問題需要處理访忿,如請求的URL的域名替換為IP地址、請求頭中設(shè)置原始HOST斯稳、SSL證書校驗(yàn)處理海铆、Cookie問題處理、重定向挣惰、SNI場景下的問題處理卧斟,以及對應(yīng)的SNI場景下的數(shù)據(jù)編解碼和鏈接復(fù)用等問題,上述這些問題都需要有一個統(tǒng)一的解決方案憎茂。

因此珍语,我們在騰訊云HTTPDNS的SDK作為提供HTTPDNS的基礎(chǔ)能力之上,單獨(dú)封裝了iOS端HTTPDNS的接入層SDK竖幔,主要用來實(shí)現(xiàn)一些定制的策略和解決上述問題板乙,同時也方便后續(xù)更換SDK或者接入自部署的HTTPDNS方案,讓上層各業(yè)務(wù)方能夠無感知底層HTTPDNS服務(wù)的存在拳氢,減少業(yè)務(wù)入侵性募逞。

iOS端接入層SDK架構(gòu)圖如下圖所示:


SDK.png
接口層

接口層提供的部分接口:

// 開啟HTTPDNS服務(wù)
- (void)startHTTPDNS;

// 白名單列表,如果設(shè)置了白名單馋评,則只有在白名單內(nèi)域名走h(yuǎn)ttpdns服務(wù)
@property (nonatomic, copy) NSArray *whiteDomainList;

// 黑名單列表凡辱,如果設(shè)置了黑名單,黑名單內(nèi)域名都不走h(yuǎn)ttpdns栗恩,黑名單的優(yōu)先級最高
@property (nonatomic, copy) NSArray *blackDomainList;

// 是否允許緩存ip,允許緩存的情況下,在通過第三方服務(wù)無法獲取ip的情況下磕秤,允許使用上次解析成功的ip進(jìn)行請求乳乌,默認(rèn)YES
@property (nonatomic, assign) BOOL enableCachedIP;
策略層

策略層主要提供不同的策略組合和配置,能夠使得SDK能夠穩(wěn)定的對外提供HTTPDNS服務(wù)市咆,下面簡單介紹一下每個策略的內(nèi)容:
容災(zāi)策略SDK內(nèi)部優(yōu)先使用HTTPDNS服務(wù)汉操,當(dāng)HTTPDNS服務(wù)不可用時,即無法獲得有效ip時蒙兰,服務(wù)自動降級為運(yùn)營商的LocalDNS服務(wù)磷瘤,確保不受HTTPDNS服務(wù)不可用時導(dǎo)致系統(tǒng)故障無法發(fā)出網(wǎng)絡(luò)請求。注:目前階段沒有接入內(nèi)置ip策略搜变,后續(xù)會考慮采缚。
黑白名單策略:APP內(nèi)的網(wǎng)絡(luò)請求域名眾多,目前并不是所有的網(wǎng)絡(luò)請求都走HTTPDNS服務(wù)挠他,設(shè)置了白名單或者黑名單后扳抽,會根據(jù)黑白名單中的域名去執(zhí)行HTTPDNS,如果設(shè)置了白名單殖侵,則只有白名單內(nèi)的域名走HTTPDNS服務(wù)贸呢;如果設(shè)置了黑名單,黑名單內(nèi)的域名不走HTTPDNS服務(wù)拢军,黑名單的優(yōu)先級高于白名單楞陷。
緩存策略緩存策略除了基礎(chǔ)服務(wù)層中騰訊云HTTPDNS SDK提供的基于TTL的緩存策略外,我們自己封裝的接入層SDK中還存在一份內(nèi)存緩存和本地化持久緩存茉唉,持久化緩存主要用來解決啟動APP時無法獲取HTTPDNS中的IP的問題固蛾,內(nèi)存緩存主要為查詢策略提供服務(wù)。當(dāng)某個基于HTTPDNS的IP地址導(dǎo)致請求失敗后赌渣,會清除當(dāng)前域名和IP的緩存數(shù)據(jù)魏铅。同時外部可控制是否使用緩存。
查詢策略查詢策略主要是為了解決坚芜,短時間內(nèi)同一個域名多次調(diào)用基礎(chǔ)服務(wù)層的域名查詢服務(wù)览芳,當(dāng)狀態(tài)是正在查詢中時,后來者不再調(diào)用查詢服務(wù)鸿竖,直接從緩存策略中的內(nèi)存緩存中讀取可用的IP沧竟,如果緩存內(nèi)也無可用的IP,則直接降級為運(yùn)營商的LocalDNS查詢缚忧。查詢策略可在確保服務(wù)可用的同時悟泵,有效減少和HTTPDNS服務(wù)器交互的次數(shù)。

注入層

注入層在iOS端是依賴NSURLProtocol進(jìn)行攔截網(wǎng)絡(luò)請求闪水,在這里不再具體介紹NSURLProtocol的用法糕非。基于NSURLProtocol攔截網(wǎng)絡(luò)請求,我們分別實(shí)現(xiàn)了兩套方案朽肥,在不需要處理SNI場景的情況下禁筏,基于NSURLSession實(shí)現(xiàn);在需要處理SNIServer Name Indication衡招,單IP多HTTPS證書)場景的情況下篱昔,基于CFNetwork實(shí)現(xiàn)。下面我們看一下兩種方案:

  • (1)SNI場景下基于CFNetwork的實(shí)現(xiàn)方案
    SNI(Server Name Indication)是為了解決一個服務(wù)器使用多個域名和證書的SSL/TLS擴(kuò)展始腾。它的工作原理如下:
  • 在連接到服務(wù)器建立SSL鏈接之前先發(fā)送要訪問站點(diǎn)的域名(Hostname)州刽。

  • 服務(wù)器根據(jù)這個域名返回一個合適的證書。

上述過程中浪箭,當(dāng)客戶端使用HTTPDNS解析域名時穗椅,請求URL中的host會被替換成HTTPDNS解析出來的IP,導(dǎo)致服務(wù)器獲取到的域名為解析后的IP山林,無法找到匹配的證書房待,只能返回默認(rèn)的證書或者不返回,所以會出現(xiàn)SSL/TLS握手不成功的錯誤驼抹。

由于iOS上層網(wǎng)絡(luò)庫NSURLSession沒有提供接口進(jìn)行SNI字段的配置桑孩,因此可以考慮使用NSURLProtocol攔截網(wǎng)絡(luò)請求,然后使用CFHTTPMessageRef創(chuàng)建NSInputStream實(shí)例進(jìn)行Socket通信框冀,并設(shè)置其kCFStreamSSLPeerName的值流椒。

注:上述文字來自于騰訊HTTPDNS官方文檔

基于CFHTTPMessageRefNSInputStream設(shè)置SNI關(guān)鍵代碼如下:


 // 設(shè)置SNI host信息
NSString *host = [self.sniRequest.allHTTPHeaderFields objectForKey:@"Host"];
if (!host) {
    host = self.originalRequest.URL.host;
}
[self.inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey];
NSDictionary *sslProperties = @{ (__bridge id) kCFStreamSSLPeerName : host };
[self.inputStream setProperty:sslProperties forKey:(__bridge_transfer NSString *) kCFStreamPropertySSLSettings];

基于CFNetwork的實(shí)現(xiàn)方案明也,除了設(shè)置SNI信息外宣虾,還需要考慮的數(shù)據(jù)編解碼的問題,在我們看到的眾多的開源代碼和文章中很少有人提及這一點(diǎn)温数,因此我們在處理響應(yīng)數(shù)據(jù)時需要添加類似如下代碼進(jìn)行響應(yīng)數(shù)據(jù)的解碼操作:

//檢查`Content-Encoding`绣硝,返回數(shù)據(jù)是否需要進(jìn)行解碼操作;
//此處僅做了gzip解碼的處理撑刺,業(yè)務(wù)場景若確定有其他編碼格式鹉胖,需自行完成擴(kuò)展。
NSString *contentEncoding = [self.response.headerFields objectForKey:@"Content-Encoding"];
if (contentEncoding && [contentEncoding isEqualToString:@"gzip"]) {
    [self.delegate task:self didReceiveData:[self ungzipData:self.resultData]];
} else {
    [self.delegate task:self didReceiveData:self.resultData];
}

此外還有非常重要的一點(diǎn)够傍,基于CFNetwork的實(shí)現(xiàn)方案甫菠,需要考慮連接復(fù)用的問題,不能每次請求都重新創(chuàng)建冕屯,重新連接的成本非常高寂诱。這也是我們在看開源代碼和文章從來不會提及的部分,如果此處不處理安聘,性能消耗非常嚴(yán)重痰洒。

尤其我們目前大部分請求都已經(jīng)是HTTP2.0(也就是H2)了瓢棒,性能對比會更加明顯。但由于蘋果的CFNetwork框架是不支持HTTP2.0的丘喻,也就是我們很難基于CFNetwork實(shí)現(xiàn)到HTTP2.0的相關(guān)特性音羞。我們目前是實(shí)現(xiàn)了HTTP1.1協(xié)議中連接復(fù)用這一部分功能,不需要每次請求都重新建立連接仓犬。

基本原理為相同host、port舍肠、scheme的請求搀继,在請求發(fā)起時如果有可用的沒過期的連接可以復(fù)用,就不需要重新建立連接翠语,直接復(fù)用連接即可叽躯,如果連接在本地過期,或者服務(wù)端通過響應(yīng)頭主動關(guān)閉連接肌括,則連接不復(fù)用点骑,進(jìn)行連接關(guān)閉。判斷服務(wù)端是否連接復(fù)用谍夭,可通過響應(yīng)頭的Connectionkeep-alive還是close進(jìn)行判斷黑滴。

  • (2)非SNI場景下基于CFNetwork的實(shí)現(xiàn)方案
    基于NSURLSession的實(shí)現(xiàn)比較簡單,在通過NSURLProtocol進(jìn)行攔截請求后紧索,只需要將Request中的域名替換成IP袁辈,在請求頭中設(shè)置原始Host字段和Cookie字段,重新構(gòu)建dataTask任務(wù)珠漂,發(fā)起請求即可晚缩,簡單的示例代碼如下:
//處理url和host dnsResultURL為替換ip后的URL
NSMutableURLRequest *ipRequest = [originRequest mutableCopy];
ipRequest.URL = [NSURL URLWithString:dnsResultURL];
[ipRequest setValue:url.host forHTTPHeaderField:@"Host"];
            
//處理cookie,由于url變了媳危,系統(tǒng)并不會攜帶原域名下的cookie
NSString *cookieString = [[MFSNICookieManager sharedManager] requestCookieHeaderForURL:url];
[ipRequest setValue:cookieString forHTTPHeaderField:@"Cookie"];
            
self.ipRequest = ipRequest;
self.clientThread = [NSThread currentThread];
self.ipTask = [[[self class] sharedDemux] dataTaskWithRequest:ipRequest delegate:self modes:self.modes];
                        
if(self.ipTask){
    [self.ipTask resume];
}

HTTPS的證書校驗(yàn)流程中荞彼,由于我們修改了請求URL中的Host為IP地址,因此證書驗(yàn)證流程無法通過待笑,因此需要修改證書的驗(yàn)證流程鸣皂,在證書驗(yàn)證時,將IP替換為原來的域名滋觉,再進(jìn)行證書驗(yàn)證签夭。示例代碼如下:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *_Nullable))completionHandler {
    if (!challenge) {
        return;
    }
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    NSURLCredential *credential = nil;
    
    //獲取原始域名host,用原始請求即可獲取
    NSString *host = [[self.originRequest allHTTPHeaderFields] objectForKey:@"Host"];
    if (!host) {
        host = self.originRequest.URL.host;
    }
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:host]) {
            disposition = NSURLSessionAuthChallengeUseCredential;
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    } else {
        disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    }
    // 對于其他的challenges直接使用默認(rèn)的驗(yàn)證方案
    completionHandler(disposition, credential);
}


- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
    //創(chuàng)建證書策略
    NSMutableArray *policies = [NSMutableArray array];
    if (domain) {
        [policies addObject:(__bridge_transfer id) SecPolicyCreateSSL(true, (__bridge CFStringRef) domain)];
    } else {
        [policies addObject:(__bridge_transfer id) SecPolicyCreateBasicX509()];
    }
    //綁定校驗(yàn)策略到服務(wù)端的證書上
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef) policies);
    /*
     * 評估當(dāng)前serverTrust是否可信任椎侠,
     * 官方建議在result = kSecTrustResultUnspecified 或 kSecTrustResultProceed
     * 的情況下serverTrust可以被驗(yàn)證通過第租,https://developer.apple.com/library/ios/technotes/tn2232/_index.html
     * 關(guān)于SecTrustResultType的詳細(xì)信息請參考SecTrust.h
     */
    SecTrustResultType result;
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
    SecTrustEvaluate(serverTrust, &result);
    #pragma clang diagnostic pop
    return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
}

基礎(chǔ)服務(wù)層

基礎(chǔ)服務(wù)層目前階段主要依賴騰訊云HTTPDNS SDK提供基礎(chǔ)查詢服務(wù),主要提供基于TTL的緩存存儲和過期處理邏輯我纪,同時這一層還提供SDK內(nèi)部緩存存儲以及日志和基礎(chǔ)校驗(yàn)等功能;

? ? ? ? ? ?如果你對性能有這很高的要求慎宾,同時又需要處理SNI場景的問題丐吓,我建議不要直接主動使用HTTPDNS,而是在運(yùn)營商LocalDNS獲取的IP請求失敗的情況下趟据,可以在底層直接使用基于CFNetwork的網(wǎng)絡(luò)請求進(jìn)行重試券犁,這樣就能在請求DNS劫持性能中間得到一個平衡,既能保證在運(yùn)營商的LocalDNS解析出現(xiàn)問題時能夠走HTTPDNS汹碱,保證成功率和可用性粘衬;同時又能夠在運(yùn)營商的LocalDNS可用時,使用基于NSURLSession的請求咳促,享受系統(tǒng)實(shí)現(xiàn)的HTTP2.0特性帶來的性能提升稚新。如果,不需要處理SNI的問題跪腹,就老老實(shí)實(shí)使用基于NSURLSession的實(shí)現(xiàn)方案

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載褂删,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末冲茸,一起剝皮案震驚了整個濱河市屯阀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轴术,老刑警劉巖难衰,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膳音,居然都是意外死亡召衔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門祭陷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苍凛,“玉大人,你說我怎么就攤上這事兵志〈己” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵想罕,是天一觀的道長悠栓。 經(jīng)常有香客問我,道長按价,這世上最難降的妖魔是什么惭适? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮楼镐,結(jié)果婚禮上癞志,老公的妹妹穿的比我還像新娘。我一直安慰自己框产,他們只是感情好凄杯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布错洁。 她就那樣靜靜地躺著,像睡著了一般戒突。 火紅的嫁衣襯著肌膚如雪屯碴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天膊存,我揣著相機(jī)與錄音导而,去河邊找鬼。 笑死隔崎,一個胖子當(dāng)著我的面吹牛嗡载,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仍稀,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼埂息!你這毒婦竟也來了技潘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤千康,失蹤者是張志新(化名)和其女友劉穎享幽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拾弃,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡值桩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了豪椿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奔坟。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖搭盾,靈堂內(nèi)的尸體忽然破棺而出咳秉,到底是詐尸還是另有隱情,我是刑警寧澤鸯隅,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布澜建,位于F島的核電站,受9級特大地震影響蝌以,放射性物質(zhì)發(fā)生泄漏炕舵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一跟畅、第九天 我趴在偏房一處隱蔽的房頂上張望咽筋。 院中可真熱鬧,春花似錦碍彭、人聲如沸晤硕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舞箍。三九已至舰褪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疏橄,已是汗流浹背占拍。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捎迫,地道東北人晃酒。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像窄绒,于是被迫代替她去往敵國和親贝次。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

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

  • ******科普片** 1彰导、DNS劫持的危害 不知道大家有沒有發(fā)現(xiàn)這樣一個現(xiàn)象蛔翅,在打開一些網(wǎng)頁的時候會彈出一些與所...
    茉莉兒閱讀 31,053評論 84 217
  • 移動互聯(lián)網(wǎng)的網(wǎng)絡(luò)狀況是十分復(fù)雜的,三大運(yùn)營商位谋、3G山析、4G、Wi-Fi掏父、地點(diǎn)等任何一個狀態(tài)的改變都會導(dǎo)致網(wǎng)絡(luò)狀況的變...
    Joy___閱讀 10,259評論 4 89
  • DY_Monster閱讀 234評論 0 0
  • 親愛的老公笋轨,今天幫我去辦理車輛年檢,還發(fā)現(xiàn)我的車子有點(diǎn)問題赊淑,并立即送維修爵政。感覺有你真好。雖然你不會說甜言蜜語陶缺,但你...
    湖南zy閱讀 133評論 0 1
  • 焦點(diǎn)中級13期杜金玲茂卦,堅(jiān)持分享第209天《尋覓希望之旅》,許維素教授组哩。生活中的辛苦與創(chuàng)傷成為自己去奮斗的動力等龙。解決...
    渡小滿6閱讀 282評論 0 2