小嘗YTKNetwork

一鲤遥、什么是YTKNetwork

YTKNetwork是一個(gè)基于AFNetworking的網(wǎng)絡(luò)層封裝验烧。

二虐拓、包括那幾個(gè)類

○? YTKBaseRequest

○? YTKRequest

○? YTKNetworkAgent

○? YTKNetworkConfig

△YTKNetwork的基本用法:基本用法沼沈,YTKNetwork 的基本的思想是把每一個(gè)網(wǎng)絡(luò)請(qǐng)求封裝成對(duì)象丈冬。所以使用 YTKNetwork尸折,你的每一種請(qǐng)求都需要繼承 YTKRequest類,通過覆蓋父類的一些方法來構(gòu)造指定的網(wǎng)絡(luò)請(qǐng)求殷蛇。

下面會(huì)分別講解這幾個(gè)類。

YTKNetworkAgent

網(wǎng)絡(luò)請(qǐng)求的總代理類橄浓,是對(duì)AFNetworking的封裝粒梦。此類是一個(gè)單例。

內(nèi)部包含的三個(gè)成員變量:

AFHTTPRequestOperationManager *_manager;

AFHTTPRequestOperationManagerd的單例網(wǎng)路請(qǐng)求manager對(duì)象

YTKNetworkConfig *_config;

負(fù)責(zé)配置一個(gè)相關(guān)的設(shè)置

NSMutableDictionary *_requestsRecord;

請(qǐng)求隊(duì)列

對(duì)外的接口有以下方法:

-(void)addRequest:(YTKBaseRequest *)request;

// 這里詳細(xì)分析一下addRequest的內(nèi)部實(shí)現(xiàn)

- (void)addRequest:(YTKBaseRequest *)request {

YTKRequestMethod method = [request requestMethod];

NSString *url = [self buildRequestUrl:request];

id param = request.requestArgument;

AFConstructingBlock constructingBlock = [request constructingBodyBlock];

// 設(shè)置返回對(duì)象的格式荸实,YTKRequestSerializerTypeHTTP代表返回二進(jìn)制格式匀们,YTKRequestSerializerTypeJSON代表返回一個(gè)json的根對(duì)象(NSDictionary或者NSArray)

if (request.requestSerializerType == YTKRequestSerializerTypeHTTP) {

_manager.requestSerializer = [AFHTTPRequestSerializer serializer];

} else if (request.requestSerializerType == YTKRequestSerializerTypeJSON) {

_manager.requestSerializer = [AFJSONRequestSerializer serializer];

}

_manager.requestSerializer.timeoutInterval = [request requestTimeoutInterval];

// 如果請(qǐng)求需要授權(quán)證書,這里設(shè)置用戶名和密碼

NSArray *authorizationHeaderFieldArray = [request requestAuthorizationHeaderFieldArray];

if (authorizationHeaderFieldArray != nil) {

[_manager.requestSerializer setAuthorizationHeaderFieldWithUsername:(NSString *)authorizationHeaderFieldArray.firstObject

password:(NSString *)authorizationHeaderFieldArray.lastObject];

}

// 設(shè)置其他HTTP header

NSDictionary *headerFieldValueDictionary = [request requestHeaderFieldValueDictionary];

if (headerFieldValueDictionary != nil) {

for (id httpHeaderField in headerFieldValueDictionary.allKeys) {

id value = headerFieldValueDictionary[httpHeaderField];

if ([httpHeaderField isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) {

[_manager.requestSerializer setValue:(NSString *)value forHTTPHeaderField:(NSString *)httpHeaderField];

} else {

YTKLog(@"Error, class of key/value in headerFieldValueDictionary should be NSString.");

}}}

// 如果創(chuàng)建了自定義的NSURLRequest對(duì)象准给,就使用自定的對(duì)象

NSURLRequest *customUrlRequest= [request buildCustomUrlRequest];

if (customUrlRequest) {

// 創(chuàng)建 AFHTTPRequestOperation 對(duì)象

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:customUrlRequest];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *op, id responseObject) {

// 處理結(jié)果

[self handleRequestResult:op];

} failure:^(AFHTTPRequestOperation *op, NSError *error) {

[self handleRequestResult:op];

}];

request.requestOperation = operation;

operation.responseSerializer = _manager.responseSerializer;

// 添加到請(qǐng)求隊(duì)列

[_manager.operationQueue addOperation:operation];

} else {

// 沒有自定義NSURLRequest泄朴,需要手動(dòng)創(chuàng)建

if (method == YTKRequestMethodGet) {

// 如果需要斷點(diǎn)續(xù)傳下載文件

if (request.resumableDownloadPath) {

// 拼接參數(shù)到url

NSString *filteredUrl = [YTKNetworkPrivate urlStringWithOriginUrlString:url appendParameters:param];

NSURLRequest *requestUrl = [NSURLRequest requestWithURL:[NSURL URLWithString:filteredUrl]];

AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:requestUrl targetPath:request.resumableDownloadPath shouldResume:YES];

// 設(shè)置斷點(diǎn)續(xù)傳的進(jìn)度回調(diào)block

[operation setProgressiveDownloadProgressBlock:request.resumableDownloadProgressBlock];

// 整個(gè)請(qǐng)求完成的回調(diào)block

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *op, id responseObject) {

[self handleRequestResult:op];

} failure:^(AFHTTPRequestOperation *op, NSError *error) {

[self handleRequestResult:op];

}];

request.requestOperation = operation;

[_manager.operationQueue addOperation:operation];

} else {

request.requestOperation = [_manager GET:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

}

} else if (method == YTKRequestMethodPost) {

if (constructingBlock != nil) {

// constructingBlock是一個(gè)返回實(shí)現(xiàn)AFMultipartFormData協(xié)議的對(duì)象,該對(duì)象主要作用是實(shí)現(xiàn)文件上傳

// 我們通常會(huì)上傳圖片或者文件需要用到multipart/form-data露氮,實(shí)現(xiàn)以下即可:? ? ? ? ? ? ? ? /*? ? ? ? ? ? ? ? ? - (AFConstructingBlock)constructingBodyBlock {? ? ? ? ? ? ? ? ? return ^(idformData) {

NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"currentPageDot"], 0.9);

NSString *name = @"image";

NSString *formKey = @"image";

NSString *type = @"image/jpeg";

[formData appendPartWithFileData:data name:formKey fileName:name mimeType:type];

};

}*/

request.requestOperation = [_manager POST:url parameters:param constructingBodyWithBlock:constructingBlock success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

} else {

request.requestOperation = [_manager POST:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

}

} else if (method == YTKRequestMethodHead) {

// 只返回head的請(qǐng)求

request.requestOperation = [_manager HEAD:url parameters:param success:^(AFHTTPRequestOperation *operation) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

} else if (method == YTKRequestMethodPut) {

// 更新資源的請(qǐng)求

request.requestOperation = [_manager PUT:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

} else if (method == YTKRequestMethodDelete) {

// 刪除資源

request.requestOperation = [_manager DELETE:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

} else if (method == YTKRequestMethodPatch) {

// 對(duì)PUT請(qǐng)求的補(bǔ)充祖灰,更新部分資源

request.requestOperation = [_manager PATCH:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self handleRequestResult:operation];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self handleRequestResult:operation];

}];

} else {

YTKLog(@"Error, unsupport method type");

return;}}


// 添加一個(gè)請(qǐng)求到_requestsRecord字典中,key是AFHTTPRequestOperation的hash值畔规,value是YTKBaseRequest對(duì)象

// _requestsRecord的作用:當(dāng)請(qǐng)求完成時(shí)局扶,AFN返回operation,通過_requestsRecord可以反射出它所屬的YTKBaseRequest對(duì)象

[self addOperation:request];

}

-(void)cancelRequest:(YTKBaseRequest *)request;

- (void)cancelRequest:(YTKBaseRequest *)request {

[request.requestOperation cancel];

[self removeOperation:request.requestOperation];

[request clearCompletionBlock];

}

-(void)cancelAllRequests;

- (void)cancelAllRequests {

NSDictionary *copyRecord = [_requestsRecord copy];

for (NSString *key in copyRecord) {

YTKBaseRequest *request = copyRecord[key];

[request stop];

}

}

-(NSString )buildRequestUrl:(YTKBaseRequest )request;

YTKBaseRequest

YTKRequest的父類叁扫,先介紹它幾個(gè)重要的屬性和方法三妈。

需要子類來重寫的方法

/// 請(qǐng)求成功的回調(diào)

-(void)requestCompleteFilter;

/// 請(qǐng)求失敗的回調(diào)

-(void)requestFailedFilter;

/// 請(qǐng)求的URL

-(NSString *)requestUrl;

/// 請(qǐng)求的CdnURL

-(NSString *)cdnUrl;

/// 請(qǐng)求的BaseURL

(NSString *)baseUrl;

/// 請(qǐng)求的連接超時(shí)時(shí)間,默認(rèn)為60秒

-(NSTimeInterval)requestTimeoutInterval;

/// 請(qǐng)求的參數(shù)列表

-(id)requestArgument;

/// 用于在cache結(jié)果莫绣,計(jì)算cache文件名時(shí)畴蒲,忽略掉一些指定的參數(shù)

-(id)cacheFileNameFilterForRequestArgument:(id)argument;

/// Http請(qǐng)求的方法

-(YTKRequestMethod)requestMethod;

/// 請(qǐng)求的SerializerType

-(YTKRequestSerializerType)requestSerializerType;

/// 請(qǐng)求的Server用戶名和密碼

-(NSArray *)requestAuthorizationHeaderFieldArray;

/// 在HTTP報(bào)頭添加的自定義參數(shù)? ??

? -(NSDictionary *)requestHeaderFieldValueDictionary;

? ? /// 構(gòu)建自定義的UrlRequest,

? /// 若這個(gè)方法返回非nil對(duì)象对室,會(huì)忽略requestUrl, requestArgument, requestMethod, requestSerializerType? ? ? ? -(NSURLRequest *)buildCustomUrlRequest;??

/// 是否使用CDN的host地址? ? ? ? -(BOOL)useCDN;? ? /// 用于檢查JSON是否合法的對(duì)象? ? ? ? -(id)jsonValidator;??

/// 用于檢查Status Code是否正常的方法? ? ? ? -(BOOL)statusCodeValidator;? ? /// 當(dāng)POST的內(nèi)容帶有文件等富文本時(shí)使用? ? ? ? -(AFConstructingBlock)constructingBodyBlock;?

? /// 當(dāng)需要斷點(diǎn)續(xù)傳時(shí)模燥,指定續(xù)傳的地址? ? ? ? -(NSString*)resumableDownloadPath;?

? /// 當(dāng)需要斷點(diǎn)續(xù)傳時(shí)咖祭,獲得下載進(jìn)度的回調(diào)? ? ? ? -(AFDownloadProgressBlock)resumableDownloadProgressBlock;里面重要的兩個(gè)方法:- (void)start {? ?

// 調(diào)用即將開始請(qǐng)求的hook??

[self toggleAccessoriesWillStartCallBack];? ? [[YTKNetworkAgent sharedInstance] addRequest:self];}

/// remove self from request queue- (void)stop {?

? // 即將結(jié)束的hook?

? [self toggleAccessoriesWillStopCallBack];??

self.delegate = nil;?

? [[YTKNetworkAgent sharedInstance] cancelRequest:self];??

[self toggleAccessoriesDidStopCallBack];}

還有一個(gè)比較重要的增加hook的方法,需要自定義個(gè)對(duì)象涧窒,實(shí)現(xiàn)YTKRequestAccessory協(xié)議定義的一些方法來hook一些動(dòng)作- (void)addAccessory:(id)accessory {

// 因?yàn)榭赡苡卸鄠€(gè)hook對(duì)象心肪,所以添加到一個(gè)數(shù)組中,調(diào)用的時(shí)候也是遍歷數(shù)組調(diào)用

if (!self.requestAccessories) {

self.requestAccessories = [NSMutableArray array];

}

[self.requestAccessories addObject:accessory];

}

YTKRequest

這里主要實(shí)現(xiàn)了一些緩存策略纠吴,重寫了父類的start方法

- (void)start {

if (self.ignoreCache) {

[super start];

return;

}

// 查看緩存時(shí)間是否過期

if ([self cacheTimeInSeconds] < 0) {

[super start];

return;

}

// 查看本地的緩存版本號(hào)和當(dāng)前緩存判斷是否匹配

long long cacheVersionFileContent = [self cacheVersionFileContent];

if (cacheVersionFileContent != [self cacheVersion]) {

[super start];

return;

}

// 查看緩存文件是否存在

NSString *path = [self cacheFilePath];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:path isDirectory:nil]) {

[super start];

return;

}

// 查看緩存時(shí)間是否過期

int seconds = [self cacheFileDuration:path];

if (seconds < 0 || seconds > [self cacheTimeInSeconds]) {

[super start];

return;

}

// 加載緩存數(shù)據(jù)

_cacheJson = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

if (_cacheJson == nil) {

[super start];

return;

}

_dataFromCache = YES;

// 調(diào)用緩存結(jié)束回調(diào)

[self requestCompleteFilter];

YTKRequest *strongSelf = self;

[strongSelf.delegate requestFinished:strongSelf];

if (strongSelf.successCompletionBlock) {

strongSelf.successCompletionBlock(strongSelf);

}

[strongSelf clearCompletionBlock];

}

緩存是存放在本地文件中的硬鞍,文件名用一些關(guān)鍵字的字符串拼接并md5來表示:

- (NSString *)cacheFileName {

NSString *requestUrl = [self requestUrl];

NSString *baseUrl = [YTKNetworkConfig sharedInstance].baseUrl;

id argument = [self cacheFileNameFilterForRequestArgument:[self requestArgument]];

NSString *requestInfo = [NSString stringWithFormat:@"Method:%ld Host:%@ Url:%@ Argument:%@ AppVersion:%@ Sensitive:%@", (long)[self requestMethod], baseUrl, requestUrl,

argument, [YTKNetworkPrivate appVersionString], [self cacheSensitiveData]];

NSString *cacheFileName = [YTKNetworkPrivate md5StringFromString:requestInfo];

return cacheFileName;

}

YTKNetworkConfig

這個(gè)類主要負(fù)責(zé)一些配置的工作,配置baseUrl戴已,cdnUrl等工作固该,內(nèi)部沒有什么具體的實(shí)現(xiàn),在其他類中獲取這個(gè)類的配置信息

YTKBatchRequestAgent糖儡、YTKBatchRequest

用于方便地發(fā)送批量的網(wǎng)絡(luò)請(qǐng)求伐坏,YTKBatchRequest是一個(gè)容器類,它可以放置多個(gè) YTKRequest 子類握联,并統(tǒng)一處理這多個(gè)網(wǎng)絡(luò)請(qǐng)求的成功和失敗桦沉。

在如下的示例中,我們發(fā)送了4個(gè)批量的請(qǐng)求金闽,并統(tǒng)一處理這4個(gè)請(qǐng)求同時(shí)成功的回調(diào)纯露。

- (void)sendBatchRequest {

GetImageApi *a = [[GetImageApi alloc] initWithImageId:@"1.jpg"];

GetImageApi *b = [[GetImageApi alloc] initWithImageId:@"2.jpg"];

GetImageApi *c = [[GetImageApi alloc] initWithImageId:@"3.jpg"];

GetUserInfoApi *d = [[GetUserInfoApi alloc] initWithUserId:@"123"];

YTKBatchRequest *batchRequest = [[YTKBatchRequest alloc] initWithRequestArray:@[a, b, c, d]];

[batchRequest startWithCompletionBlockWithSuccess:^(YTKBatchRequest *batchRequest) {

NSLog(@"succeed");

NSArray *requests = batchRequest.requestArray;

GetImageApi *a = (GetImageApi *)requests[0];

GetImageApi *b = (GetImageApi *)requests[1];

GetImageApi *c = (GetImageApi *)requests[2];

GetUserInfoApi *user = (GetUserInfoApi *)requests[3];

// deal with requests result ...

} failure:^(YTKBatchRequest *batchRequest) {

NSLog(@"failed");

}];

}

內(nèi)部實(shí)現(xiàn),start方法遍歷所有request代芜,并調(diào)用start方法

- (void)start {

if (_finishedCount > 0) {

YTKLog(@"Error! Batch request has already started.");

return;

}

[[YTKBatchRequestAgent sharedInstance] addBatchRequest:self];

[self toggleAccessoriesWillStartCallBack];

for (YTKRequest * req in _requestArray) {

req.delegate = self;

[req start];

}

}

在成功回調(diào)中埠褪,有一個(gè)計(jì)數(shù)器,判斷所有請(qǐng)求是否都已經(jīng)完成

- (void)requestFinished:(YTKRequest *)request {

_finishedCount++;

if (_finishedCount == _requestArray.count) {

[self toggleAccessoriesWillStopCallBack];

if ([_delegate respondsToSelector:@selector(batchRequestFinished:)]) {

[_delegate batchRequestFinished:self];

}

if (_successCompletionBlock) {

_successCompletionBlock(self);

}

[self clearCompletionBlock];

[self toggleAccessoriesDidStopCallBack];

}

}

YTKChainRequestAgent挤庇、YTKChainRequest

用于管理有相互依賴的網(wǎng)絡(luò)請(qǐng)求钞速,它實(shí)際上最終可以用來管理多個(gè)拓?fù)渑判蚝蟮木W(wǎng)絡(luò)請(qǐng)求。

以下是具體的代碼示例嫡秕,在示例中渴语,我們?cè)趕endChainRequest方法中設(shè)置好了Api相互的依賴,然后昆咽。 我們就可以通過chainRequestFinished回調(diào)來處理所有網(wǎng)絡(luò)請(qǐng)求都發(fā)送成功的邏輯了遵班。如果有任何其中一個(gè)網(wǎng)絡(luò)請(qǐng)求失敗了,則會(huì)觸發(fā)chainRequestFailed回調(diào)潮改。

- (void)sendChainRequest {

RegisterApi *reg = [[RegisterApi alloc] initWithUsername:@"username" password:@"password"];

YTKChainRequest *chainReq = [[YTKChainRequest alloc] init];

[chainReq addRequest:reg callback:^(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest) {

RegisterApi *result = (RegisterApi *)baseRequest;

NSString *userId = [result userId];

GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId];

[chainRequest addRequest:api callback:nil];

}];

chainReq.delegate = self;

// start to send request

[chainReq start];

}

- (void)chainRequestFinished:(YTKChainRequest *)chainRequest {

// all requests are done

}

- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest*)request {

// some one of request is failed

}

內(nèi)部實(shí)現(xiàn)狭郑,定義一個(gè)_nextRequestIndex,初始化為0汇在,_requestArray請(qǐng)求數(shù)組翰萨,_requestCallbackArray請(qǐng)求回調(diào)數(shù)組

- (void)start {

if (_nextRequestIndex > 0) {

YTKLog(@"Error! Chain request has already started.");

return;

}

if ([_requestArray count] > 0) {

[self toggleAccessoriesWillStartCallBack];

[self startNextRequest];

[[YTKChainRequestAgent sharedInstance] addChainRequest:self];

} else {

YTKLog(@"Error! Chain request array is empty.");

}}

// 順序執(zhí)行請(qǐng)求,_nextRequestIndex++

- (BOOL)startNextRequest {

if (_nextRequestIndex < [_requestArray count]) {

YTKBaseRequest *request = _requestArray[_nextRequestIndex];

_nextRequestIndex++;

request.delegate = self;

[request start];

return YES;

} else {

return NO;}}

// 請(qǐng)求成功回調(diào)

- (void)requestFinished:(YTKBaseRequest *)request {

// 獲取當(dāng)前請(qǐng)求的回調(diào)糕殉,并調(diào)用其回調(diào)亩鬼,回調(diào)中需要用戶自己去再次去add一個(gè)新的request

NSUInteger currentRequestIndex = _nextRequestIndex - 1;

ChainCallback callback = _requestCallbackArray[currentRequestIndex];

callback(self, request);

// 當(dāng)不能繼續(xù)執(zhí)行請(qǐng)求時(shí)殖告,結(jié)束本次chain請(qǐng)求,調(diào)用完成回調(diào)

if (![self startNextRequest]) {

[self toggleAccessoriesWillStopCallBack];

if ([_delegate respondsToSelector:@selector(chainRequestFinished:)]) {

[_delegate chainRequestFinished:self];

[[YTKChainRequestAgent sharedInstance] removeChainRequest:self];

}

[self toggleAccessoriesDidStopCallBack];}}

YTKNetworkPrivate

定義一些內(nèi)部使用的工具方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雳锋,一起剝皮案震驚了整個(gè)濱河市黄绩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玷过,老刑警劉巖爽丹,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辛蚊,居然都是意外死亡粤蝎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門袋马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來初澎,“玉大人,你說我怎么就攤上這事虑凛”纾” “怎么了?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵桑谍,是天一觀的道長(zhǎng)墓懂。 經(jīng)常有香客問我,道長(zhǎng)霉囚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任匕积,我火速辦了婚禮盈罐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闪唆。我一直安慰自己盅粪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布悄蕾。 她就那樣靜靜地躺著票顾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帆调。 梳的紋絲不亂的頭發(fā)上奠骄,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音番刊,去河邊找鬼含鳞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芹务,可吹牛的內(nèi)容都是我干的蝉绷。 我是一名探鬼主播鸭廷,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼熔吗!你這毒婦竟也來了辆床?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤桅狠,失蹤者是張志新(化名)和其女友劉穎讼载,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體垂攘,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡维雇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晒他。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吱型。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖陨仅,靈堂內(nèi)的尸體忽然破棺而出津滞,到底是詐尸還是另有隱情,我是刑警寧澤灼伤,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布触徐,位于F島的核電站,受9級(jí)特大地震影響狐赡,放射性物質(zhì)發(fā)生泄漏撞鹉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一颖侄、第九天 我趴在偏房一處隱蔽的房頂上張望鸟雏。 院中可真熱鬧,春花似錦览祖、人聲如沸孝鹊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)又活。三九已至,卻和暖如春锰悼,著一層夾襖步出監(jiān)牢的瞬間柳骄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工箕般, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夹界,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像可柿,于是被迫代替她去往敵國(guó)和親鸠踪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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