AFNetworking源碼探究(十一) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(二)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.03.01

前言

我們做APP發(fā)起網(wǎng)絡(luò)請(qǐng)求言询,都離不開一個(gè)非常有用的框架AFNetworking,可以說這個(gè)框架的知名度已經(jīng)超過了蘋果的底層網(wǎng)絡(luò)請(qǐng)求部分想际,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請(qǐng)求的庸推,但是一定知道AFNetworking蒜茴,接下來幾篇我們就一起詳細(xì)的解析一下這個(gè)框架。感興趣的可以看上面寫的幾篇疆栏。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請(qǐng)求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)
3. AFNetworking源碼探究(三) —— GET請(qǐng)求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(一)
4. AFNetworking源碼探究(四) —— GET請(qǐng)求實(shí)現(xiàn)之代理轉(zhuǎn)發(fā)思想(一)
5. AFNetworking源碼探究(五) —— AFURLSessionManager中NSURLSessionDelegate詳細(xì)解析(一)
6. AFNetworking源碼探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate詳細(xì)解析(一)
7. AFNetworking源碼探究(七) —— AFURLSessionManager中NSURLSessionDataDelegate詳細(xì)解析(一)
8. AFNetworking源碼探究(八) —— AFURLSessionManager中NSURLSessionDownloadDelegate詳細(xì)解析(一)
9. AFNetworking源碼探究(九) —— AFURLSessionManagerTaskDelegate中三個(gè)轉(zhuǎn)發(fā)代理方法詳細(xì)解析(一)
10. AFNetworking源碼探究(十) —— 數(shù)據(jù)解析之?dāng)?shù)據(jù)解析架構(gòu)的分析(一)

回顧

上一篇我們主要介紹了有關(guān)數(shù)據(jù)解析類和協(xié)議棘街,以及實(shí)現(xiàn)解析的架構(gòu),這一篇就分開講述各個(gè)類是如何實(shí)現(xiàn)對(duì)應(yīng)的數(shù)據(jù)解析的承边。


AFURLResponseSerialization協(xié)議

我們先看一下這個(gè)協(xié)議的接口

/**
 The `AFURLResponseSerialization` protocol is adopted by an object that decodes data into a more useful object representation, according to details in the server response. Response serializers may additionally perform validation on the incoming response and data.

 For example, a JSON response serializer may check for an acceptable status code (`2XX` range) and content type (`application/json`), decoding a valid JSON response into an object.
 */
@protocol AFURLResponseSerialization <NSObject, NSSecureCoding, NSCopying>

/**
 The response object decoded from the data associated with a specified response.

 @param response The response to be processed.
 @param data The response data to be decoded.
 @param error The error that occurred while attempting to decode the response data.

 @return The object decoded from the specified response data.
 */
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;

@end

根據(jù)服務(wù)器響應(yīng)中的細(xì)節(jié)遭殉,AFURLResponseSerialization協(xié)議被一個(gè)對(duì)象采用,該對(duì)象將數(shù)據(jù)解碼為更有用的對(duì)象表示博助。 Response序列化器還可以對(duì)傳入響應(yīng)和數(shù)據(jù)執(zhí)行驗(yàn)證险污。例如,JSON響應(yīng)序列化器可以檢查可接受的狀態(tài)碼(2XX范圍)和內(nèi)容類型(application / json)富岳,將有效的JSON響應(yīng)解碼成對(duì)象


AFHTTPResponseSerializer

這個(gè)是所有其他解析類的父類蛔糯,他遵守上面的AFURLResponseSerialization協(xié)議。

我們看一下協(xié)議在這個(gè)類中的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];

    return data;
}

這里調(diào)用了一個(gè)方法窖式,進(jìn)行了指定response和數(shù)據(jù)的驗(yàn)證蚁飒。

/**
 Validates the specified response and data.

 In its base implementation, this method checks for an acceptable status code and content type. Subclasses may wish to add other domain-specific checks.

 @param response The response to be validated.
 @param data The data associated with the response.
 @param error The error that occurred while attempting to validate the response.

 @return `YES` if the response is valid, otherwise `NO`.
 */
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
                    data:(nullable NSData *)data
                   error:(NSError * _Nullable __autoreleasing *)error;

在其基本實(shí)現(xiàn)中,此方法檢查可接受的狀態(tài)碼和內(nèi)容類型萝喘。 子類可能希望添加其他域特定的檢查淮逻。

下面我們看一下驗(yàn)證過程琼懊,主要對(duì)應(yīng)下面這段代碼

- (BOOL)validateResponse:(NSHTTPURLResponse *)response
                    data:(NSData *)data
                   error:(NSError * __autoreleasing *)error
{
    BOOL responseIsValid = YES;
    NSError *validationError = nil;

    if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
        if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
            !([response MIMEType] == nil && [data length] == 0)) {

            if ([data length] > 0 && [response URL]) {
                NSMutableDictionary *mutableUserInfo = [@{
                                                          NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
                                                          NSURLErrorFailingURLErrorKey:[response URL],
                                                          AFNetworkingOperationFailingURLResponseErrorKey: response,
                                                        } mutableCopy];
                if (data) {
                    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
                }

                validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
            }

            responseIsValid = NO;
        }

        if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
            NSMutableDictionary *mutableUserInfo = [@{
                                               NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
                                               NSURLErrorFailingURLErrorKey:[response URL],
                                               AFNetworkingOperationFailingURLResponseErrorKey: response,
                                       } mutableCopy];

            if (data) {
                mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
            }

            validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);

            responseIsValid = NO;
        }
    }

    if (error && !responseIsValid) {
        *error = validationError;
    }

    return responseIsValid;
}

這是一個(gè)具有返回值類型為BOOL的方法,但是這里對(duì)于返回值并沒有使用爬早。

(a) 最外層的判斷

最外層的判斷主要是

if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) 

就是如果response不是nil哼丈,并且response的類型是NSHTTPURLResponse

(b) 第一個(gè)if判斷

在上面最外層判斷的內(nèi)部是兩個(gè)if判斷筛严,根據(jù)不同的條件判斷數(shù)據(jù)是否有效以及在無效時(shí)應(yīng)該拋出怎樣的異常醉旦。

主要對(duì)應(yīng)下面這段代碼

if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
    !([response MIMEType] == nil && [data length] == 0)) {

    if ([data length] > 0 && [response URL]) {
        NSMutableDictionary *mutableUserInfo = [@{
                                                  NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
                                                  NSURLErrorFailingURLErrorKey:[response URL],
                                                  AFNetworkingOperationFailingURLResponseErrorKey: response,
                                                } mutableCopy];
        if (data) {
            mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
        }

        validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
    }

    responseIsValid = NO;
}

responseIsValid = NO,我們可以看出來桨啃,這一定是拋出異常车胡,沒有驗(yàn)證通過的,但是為什么拋出異常呢照瘾?我們看一下匈棘。

如果有接受數(shù)據(jù)類型,如果不匹配response网杆,而且響應(yīng)類型不為空羹饰,數(shù)據(jù)長度不為0伊滋。接著進(jìn)行判斷碳却,如果數(shù)據(jù)長度大于0,而且有響應(yīng)URL笑旺,那么就生成mutableUserInfo信息昼浦,調(diào)用下面的方法生成錯(cuò)誤信息。

static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
    if (!error) {
        return underlyingError;
    }

    if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) {
        return error;
    }

    NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy];
    mutableUserInfo[NSUnderlyingErrorKey] = underlyingError;

    return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];
}

這里要注意筒主,NSURLResponse中這個(gè)MIMEType屬性关噪。

/*! 
    @abstract Returns the MIME type of the receiver.
    @discussion The MIME type is based on the information provided
    from an origin source. However, that value may be changed or
    corrected by a protocol implementation if it can be determined
    that the origin server or source reported the information
    incorrectly or imprecisely. An attempt to guess the MIME type may
    be made if the origin source did not report any such information.
    @result The MIME type of the receiver.

     @abstract返回接收者的MIME類型。
     @討論MIME類型基于提供的信息
     來源乌妙。 但是使兔,該值可能會(huì)改變或
     如果可以確定原始服務(wù)器或來源報(bào)告了信息
     不正確或不準(zhǔn)確,則由協(xié)議實(shí)施糾正
     藤韵。如果原始資料來源未報(bào)告任何此類信息虐沥, 
     可以嘗試猜測MIME類型
     @result接收者的MIME類型。
*/
@property (nullable, readonly, copy) NSString *MIMEType;

(c) 第二個(gè)if判斷

主要對(duì)應(yīng)下邊這段代碼

if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
    NSMutableDictionary *mutableUserInfo = [@{
                                       NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
                                       NSURLErrorFailingURLErrorKey:[response URL],
                                       AFNetworkingOperationFailingURLResponseErrorKey: response,
                               } mutableCopy];

    if (data) {
        mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
    }

    validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);

    responseIsValid = NO;
}

判斷自己可接受的狀態(tài)碼泽艘,如果和response的狀態(tài)碼不匹配欲险,則進(jìn)入if塊,生成錯(cuò)誤和標(biāo)識(shí)匹涮。

(d) error和responseIsValid判斷

主要是下面一段代碼

if (error && !responseIsValid) {
    *error = validationError;
}

這里天试,如果error不為空,并且responseIsValid == NO然低,也就是說上面兩個(gè)if判斷至少走過了一個(gè)喜每,這時(shí)候給error進(jìn)行了賦值务唐。

*error = validationError;

這個(gè)方法就是來判斷返回?cái)?shù)據(jù)與咱們使用的解析器是否匹配,需要解析的狀態(tài)碼是否匹配灼卢。

兩個(gè)屬性值绍哎,一個(gè)acceptableContentTypes,一個(gè)acceptableStatusCodes鞋真,兩者在初始化的時(shí)候有給默認(rèn)值崇堰,如果給acceptableContentTypes定義了不匹配的類型,那么數(shù)據(jù)仍舊會(huì)解析錯(cuò)誤涩咖。


AFJSONResponseSerializer

AFJSONResponseSerializerAFHTTPResponseSerializer的一個(gè)子類海诲,用于驗(yàn)證和解碼JSON響應(yīng)。

默認(rèn)情況下檩互,AFJSONResponseSerializer接受以下MIME類型特幔,其中包括官方標(biāo)準(zhǔn),application / json以及其他常用類型:

  • application / json
  • text / json
  • text / javascript

我們看一下協(xié)議在這個(gè)類中的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

    id responseObject = nil;
    NSError *serializationError = nil;
    // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
    // See https://github.com/rails/rails/issues/1742
    BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
    if (data.length > 0 && !isSpace) {
        responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
    } else {
        return nil;
    }

    if (self.removesKeysWithNullValues && responseObject) {
        responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
    }

    if (error) {
        *error = AFErrorWithUnderlyingError(serializationError, *error);
    }

    return responseObject;
}

下面就看一下闸昨,這里都做了a什么

(a) 有效性的驗(yàn)證

我們看一下如何進(jìn)行有效性的驗(yàn)證的蚯斯。

if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
    if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
        return nil;
    }
}

就是調(diào)用我們上面解析的,驗(yàn)證有效性的方法饵较。如果無效拍嵌,進(jìn)入判斷,接著if判斷循诉,如果error為空横辆,或者有錯(cuò)誤,去函數(shù)里判斷茄猫。

static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {
    if ([error.domain isEqualToString:domain] && error.code == code) {
        return YES;
    } else if (error.userInfo[NSUnderlyingErrorKey]) {
        return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);
    }

    return NO;
}

數(shù)據(jù)無效后狈蚤,返回nil。

(b) 幾個(gè)條件判斷

下面就是幾個(gè)條件判斷划纽,滿足的話直接序列化對(duì)應(yīng)的JSON數(shù)據(jù)脆侮,不滿足的話返回nil。

id responseObject = nil;
NSError *serializationError = nil;
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length > 0 && !isSpace) {
    responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
    return nil;
}

if (self.removesKeysWithNullValues && responseObject) {
    responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}

if (error) {
    *error = AFErrorWithUnderlyingError(serializationError, *error);
}
  • 第一組條件判斷
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length > 0 && !isSpace) {
    responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
    return nil;
}

這里首先判斷數(shù)據(jù)是否為空勇劣,利用isEqualToData:方法進(jìn)行判斷靖避,如果不為空,并且數(shù)據(jù)長度大于0芭毙,那么就進(jìn)行JSON數(shù)據(jù)的序列化筋蓖。

responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];

如果不滿足上面條件就返nil。

  • 第二組條件判斷
if (self.removesKeysWithNullValues && responseObject) {
    responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}

這里有一個(gè)屬性

/**
 Whether to remove keys with `NSNull` values from response JSON. Defaults to `NO`.
 */
@property (nonatomic, assign) BOOL removesKeysWithNullValues;

是否從響應(yīng)JSON中刪除具有NSNull值的鍵退敦。 默認(rèn)為NO粘咖。如果需要移除這個(gè)鍵并且上面的responseObject已經(jīng)序列化成功,那么就要調(diào)用下面的函數(shù)移除具有NSNull值的鍵侈百。

static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {
    if ([JSONObject isKindOfClass:[NSArray class]]) {
        NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];
        for (id value in (NSArray *)JSONObject) {
            [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)];
        }

        return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];
    } else if ([JSONObject isKindOfClass:[NSDictionary class]]) {
        NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];
        for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {
            id value = (NSDictionary *)JSONObject[key];
            if (!value || [value isEqual:[NSNull null]]) {
                [mutableDictionary removeObjectForKey:key];
            } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
                mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions);
            }
        }

        return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];
    }

    return JSONObject;
}

這里有一個(gè)屬性和枚舉瓮下,一起來看一下

/**
 Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default.
 */
用于讀取響應(yīng)JSON數(shù)據(jù)并創(chuàng)建Foundation對(duì)象的選項(xiàng)翰铡。 有關(guān)可能的值,請(qǐng)參閱“NSJSONSerialization”文檔部分“NSJSONReadingOptions”讽坏。 默認(rèn)為'0'

@property (nonatomic, assign) NSJSONReadingOptions readingOptions;

typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
    NSJSONReadingMutableContainers = (1UL << 0),
    NSJSONReadingMutableLeaves = (1UL << 1),
    NSJSONReadingAllowFragments = (1UL << 2)
} API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
  • 第三組條件判斷
if (error) {
    *error = AFErrorWithUnderlyingError(serializationError, *error);
}

如果error不為空锭魔,那么就利用函數(shù)AFErrorWithUnderlyingError生成NSError對(duì)象并賦值。

后記

本篇講述了一個(gè)AFURLResponseSerialization協(xié)議以及AFHTTPResponseSerializerAFJSONResponseSerializer類中父類那個(gè)協(xié)議方法的實(shí)現(xiàn)路呜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末迷捧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子胀葱,更是在濱河造成了極大的恐慌漠秋,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抵屿,死亡現(xiàn)場離奇詭異庆锦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)轧葛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門搂抒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尿扯,你說我怎么就攤上這事求晶。” “怎么了姜胖?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵誉帅,是天一觀的道長淀散。 經(jīng)常有香客問我右莱,道長,這世上最難降的妖魔是什么档插? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任慢蜓,我火速辦了婚禮,結(jié)果婚禮上郭膛,老公的妹妹穿的比我還像新娘晨抡。我一直安慰自己,他們只是感情好则剃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布耘柱。 她就那樣靜靜地躺著,像睡著了一般棍现。 火紅的嫁衣襯著肌膚如雪调煎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天己肮,我揣著相機(jī)與錄音士袄,去河邊找鬼悲关。 笑死,一個(gè)胖子當(dāng)著我的面吹牛娄柳,可吹牛的內(nèi)容都是我干的寓辱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼赤拒,長吁一口氣:“原來是場噩夢啊……” “哼秫筏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挎挖,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤跳昼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后肋乍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹅颊,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年墓造,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堪伍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡觅闽,死狀恐怖帝雇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛉拙,我是刑警寧澤尸闸,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站孕锄,受9級(jí)特大地震影響吮廉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畸肆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一宦芦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轴脐,春花似錦调卑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碴巾,卻和暖如春溯捆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背餐抢。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工现使, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留低匙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓碳锈,卻偏偏與公主長得像顽冶,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子售碳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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