圖解AFNetworking

一、AFN架構(gòu)的最上層是AFHTTPSessionManager

AFHTTPSessionManager繼承于AFURLSessionManager抒钱,它所做的主要工作是收集HTTP請(qǐng)求的URL翘魄、Parameters鼎天、成功的回調(diào)、失敗的回調(diào)四個(gè)參數(shù)暑竟。然后自己的屬性requestSerializer根據(jù)前兩個(gè)參數(shù)URL和Parameter生成一個(gè)NSMutableURLRequest類的對(duì)象斋射。然后把它交個(gè)父類處理,父類會(huì)返回一個(gè)NSURLSessionDataTask類的對(duì)象task光羞,然后調(diào)用[task resume]發(fā)起請(qǐng)求绩鸣。

AFHTTPSessionManager中的處理過(guò)程

該過(guò)程對(duì)應(yīng)的源碼:

// AFHTTPSessionManager就是拿到這個(gè)方法產(chǎn)生的對(duì)象發(fā)起請(qǐng)求的
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    NSError *serializationError = nil;
    // #1:URL&Parameters --> [requestSerializer] --> Request
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }
    __block NSURLSessionDataTask *dataTask = nil;
    // #2:Request --> [AFURLSessionManager.session] --> DataTask
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];
    return dataTask;
}

二、AFN架構(gòu)的核心類AFURLSessionManager

AFURLSessionManager就像一個(gè)“工廠”纱兑,NSURLSessionDelegate一系列代理方法就是“流水線”呀闻,task是“原料”,responseObject是產(chǎn)出的“產(chǎn)品”潜慎。#2這一流程就是由AFURLSessionManager完成的捡多。

它的核心屬性有

  1. sessionConfiguration:會(huì)話對(duì)象的配置信息類,默認(rèn)使用的是default模式铐炫;
  2. session:會(huì)話對(duì)象垒手,用于產(chǎn)生任務(wù)對(duì)象task;
  3. operationQueue:創(chuàng)建session會(huì)話對(duì)象的指定的隊(duì)列倒信,這是一個(gè)串行隊(duì)列(最大并發(fā)數(shù)是1)科贬;
  4. responseSerializer:返回對(duì)象的序列化,主要負(fù)責(zé)狀態(tài)判斷、解析等任務(wù)榜掌;
  5. 四個(gè)xxxTasks數(shù)組:只讀屬性优妙,存放的是請(qǐng)求任務(wù);
  6. mutableTaskDelegatesKeyedByTaskIdentifier:以鍵值對(duì)的形式向task關(guān)聯(lián)一些回調(diào)函數(shù)憎账,key是taskIdentifier套硼,value是回調(diào)組成的AFURLSessionManagerTaskDelegate類的對(duì)象;
  7. reachabilityManager:監(jiān)管網(wǎng)絡(luò)狀態(tài)的對(duì)象胞皱;
  8. completionQueue:請(qǐng)求并解析完成后將在該隊(duì)列中交付數(shù)據(jù)(調(diào)用請(qǐng)求的completionHandler)邪意,默認(rèn)是主串行隊(duì)列;
  9. completionGroup:交付數(shù)據(jù)(調(diào)用請(qǐng)求的completionHandler)時(shí)指定的任務(wù)組反砌,AFN默認(rèn)是一個(gè)靜態(tài)的dispatch_group_t雾鬼。該分組允許用戶創(chuàng)建task1、task2...于颖,當(dāng)他們都完成時(shí)通過(guò)dispatch_group_notify()再進(jìn)行后續(xù)操作呆贿。

創(chuàng)建的靜態(tài)對(duì)象有:

  1. af_url_session_manager_creation_queue:串行隊(duì)列,將session創(chuàng)建task的任務(wù)交付到該隊(duì)列森渐;注:此隊(duì)列是修復(fù)在iOS8.0之前并行創(chuàng)建task時(shí)得到的taskIdentifier異常的情況做入,iOS8.0系統(tǒng)已經(jīng)修復(fù)了該bug。
  2. af_url_session_manager_processing_queue:專門(mén)對(duì)返回?cái)?shù)據(jù)進(jìn)行解析的隊(duì)列同衣。這是一個(gè)并行隊(duì)列竟块,能夠更高效的完成數(shù)據(jù)解析任務(wù);
  3. af_url_session_manager_completion_group:將completionHandler歸為該任務(wù)組耐齐,上述9中默認(rèn)的靜態(tài)任務(wù)組就是它浪秘。

#2流程細(xì)分:

step_1:創(chuàng)建會(huì)話session,將會(huì)話的代理指定為自己(AFURLSessionManager有相當(dāng)一部分代碼是session對(duì)象的代理方法)埠况,創(chuàng)建串行隊(duì)列耸携,指定session回調(diào)在該隊(duì)列中處理;
step_2:根據(jù)Request創(chuàng)建任務(wù)task辕翰,同時(shí)創(chuàng)建AFURLSessionManagerTaskDelegate類的對(duì)象(它和task一一對(duì)應(yīng))夺衍。這個(gè)對(duì)象包含了Request對(duì)應(yīng)的回調(diào)方法,它還有一個(gè)重要的任務(wù)就是存儲(chǔ)和拼接服務(wù)器返回的數(shù)據(jù)喜命,保存在mutableData中沟沙;
step_3:根據(jù)task的標(biāo)識(shí)taskIdentifier存儲(chǔ)step_2產(chǎn)生的對(duì)象,保存在字典中壁榕;
step_4:當(dāng)請(qǐng)求任務(wù)發(fā)起后矛紫,會(huì)有觸發(fā)session的一系列代理方法,其中就附帶了標(biāo)識(shí)是哪個(gè)task的信息牌里。當(dāng)請(qǐng)求返回?cái)?shù)據(jù)時(shí)根據(jù)task的taskIdentifier在step_3產(chǎn)生的字典中找到對(duì)應(yīng)的代理颊咬,讓代理拼接數(shù)據(jù);
step_5:當(dāng)請(qǐng)求完成時(shí)讓任務(wù)的代理根據(jù)session的responseSerializer完成數(shù)據(jù)解析任務(wù)(該代理有一個(gè)對(duì)創(chuàng)建任務(wù)的會(huì)話的弱引用);
step_6:執(zhí)行completionHandler向外拋出數(shù)據(jù)贪染。

#2流程示意圖

task和回調(diào)的存儲(chǔ)關(guān)系

核心代碼:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {

    __block NSURLSessionDataTask *dataTask = nil;
    //step_2:生成task
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });
    //step_3:生成task關(guān)聯(lián)的對(duì)象缓呛,將upload/downloadProgressBlock、completionHandler讓關(guān)聯(lián)對(duì)象管理
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
    return dataTask;
}
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
              downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
             completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;//反向的弱引用杭隙,指向存儲(chǔ)自己的類
    delegate.completionHandler = completionHandler;
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];//用字典構(gòu)建dataTask與delegate的對(duì)應(yīng)關(guān)系
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

step_1在NSURLSessionManager對(duì)象的初始化中完成。step_4是一個(gè)“循環(huán)”因妙,不斷的產(chǎn)生數(shù)據(jù)痰憎,它以及step_5step_6下文有詳細(xì)描述攀涵。

三铣耘、NSURLSessionDelegate方法的執(zhí)行以及后續(xù)任務(wù)的輪轉(zhuǎn)

任務(wù)在隊(duì)列中的輪轉(zhuǎn)

接收數(shù)據(jù)的代理方法

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    [delegate URLSession:session dataTask:dataTask didReceiveData:data];
    if (self.dataTaskDidReceiveData) {
        self.dataTaskDidReceiveData(session, dataTask, data);
    }
}

[self delegateForTask:dataTask]就是根據(jù)dataTask的任務(wù)標(biāo)識(shí)找到與它對(duì)用的代理對(duì)象,代理對(duì)象將data拼接到mutableData中保存以故。

請(qǐng)求完成時(shí)的代理方法

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    if (delegate) {
        [delegate URLSession:session task:task didCompleteWithError:error];
        [self removeDelegateForTask:task];
    }
    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}

請(qǐng)求完成后task的代理會(huì)對(duì)mutableData做異步的解析操作蜗细,[self removeDelegateForTask:task]會(huì)移除與代理的一切通知,然后從字典中移除怒详。

四炉媒、數(shù)據(jù)的解析和交付responseObject

先從源碼看起:

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
    __strong AFURLSessionManager *manager = self.manager;
    __block id responseObject = nil;
    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];//將NSMutableData拷貝以備解析之用
        self.mutableData = nil;//釋放內(nèi)存空間
    }
    /* 構(gòu)建通知的userInfo */
    if (!error) {
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
            /* 構(gòu)建通知的userInfo */
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{// 交付數(shù)據(jù)
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                dispatch_async(dispatch_get_main_queue(), ^{//發(fā)通知
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
}

貼出的源碼刪去了構(gòu)建通知userInfo和請(qǐng)求異常分支的處理流程(比成功時(shí)少了一個(gè)解析操作)。第一個(gè)dispatch_async()包含了解析操作昆烁,解析完成后在主串行隊(duì)列(解析完成后吊骤,用戶拿到數(shù)據(jù)一般就要顯示了)執(zhí)行block把數(shù)據(jù)交付出去,然后在主隊(duì)列發(fā)出任務(wù)完成的通知静尼,通知的userInfo信息中AFNetworkingTaskDidCompleteSerializedResponseKey對(duì)應(yīng)也是解析后的數(shù)據(jù)白粉。

五、其他

5.1 關(guān)于AFURLSessionManagerTaskDelegate
它是NSURLSessionManager中的一個(gè)私有類鼠渺,里面有兩個(gè)關(guān)于上傳和下載進(jìn)度的屬性:uploadProgress鸭巴、downloadProgress,它通過(guò)把自己添加為對(duì)用task的觀察者來(lái)實(shí)現(xiàn)自己的progress的值改變拦盹。

[task addObserver:self//自己(taskDelegate)將觀察task的countOfBytesSent屬性的變化情況
           forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
              options:NSKeyValueObservingOptionNew
              context:NULL];
[self.uploadProgress addObserver:self//自己觀察 進(jìn)度(Progress)的“完成比例屬性”的變化情況
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                             options:NSKeyValueObservingOptionNew
                             context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    // 當(dāng)被觀察對(duì)象是任務(wù)時(shí)鹃祖,更新自己的progress值
    if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
            self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        }
    } else //當(dāng)被觀察對(duì)象是自己的progress時(shí),執(zhí)行上傳下載的進(jìn)度有更新的代理掌敬,并發(fā)進(jìn)度以NSProgress對(duì)象的方式傳遞出去
    if ([object isEqual:self.downloadProgress]) {
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }
}

變化過(guò)程

新數(shù)據(jù)下載/上傳 --> task的屬性發(fā)生變化 --> taskDelegate的progress同步該變化 --> progress的完成百分比就發(fā)生變化 --> taskDelegate發(fā)出通知

5.2 關(guān)系梳理:NSURLSessionManager惯豆、NSURLSession、AFURLSessionManagerTaskDelegate奔害、NSURLSessionTask

四者的關(guān)系

持有1:屬性持有楷兽;
持有2:通過(guò)集合屬性持有;
持有3:雖然NSURLSession的.h文件沒(méi)有給出存儲(chǔ)它創(chuàng)建的task的集合屬性华临,但有理由相信它也是采用持有2的形式存儲(chǔ)的芯杀。
代理1:通過(guò)直接設(shè)置代理對(duì)象的方式實(shí)現(xiàn);
代理2:通過(guò)key-value的方式建立聯(lián)系,然后task有一些任務(wù)(數(shù)據(jù)拼接揭厚、進(jìn)度管理)要處理的時(shí)候通過(guò)該聯(lián)系找打taskDelegate却特,讓它負(fù)責(zé)完成。
5.3獲取Session創(chuàng)建的Task
方法:- (void)getTasksWithCompletionHandler:(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler筛圆,這是一個(gè)異步的方法裂明,通過(guò)在Session的代理隊(duì)列中執(zhí)行回調(diào)的方式交付處理的結(jié)果。3個(gè)數(shù)組中包含的是有效的(未開(kāi)始和進(jìn)行中)task太援。
大膽猜測(cè)一下它的實(shí)現(xiàn):

- (void)getTasksWithCompletionHandler:(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler {
    dispatch_barrier_async(self.workQueue, ^{
        NSMutableArray *dataTasks = [NSMutableArray array];
        NSMutableArray *uploadTasks = [NSMutableArray array];
        NSMutableArray *downloadTasks = [NSMutableArray array];
        for (NSURLSessionTask *task in self.allTasks) {
            if (task.state == NSURLSessionTaskStateRunning || task.state == NSURLSessionTaskStateSuspended) {
                if ([task isKindOfClass:[NSURLSessionDataTask class]]) {
                    [dataTasks addObject:task];
                } else if ([task isKindOfClass:[NSURLSessionUploadTask class]]) {
                    [uploadTasks addObject:task];
                } else if ([task isKindOfClass:[NSURLSessionDownloadTask class]]) {
                    [downloadTasks addObject:task];
                }
            }
        }
        dispatch_async(self.delegateQueue, ^{
            if (completionHandler) {
                completionHandler(dataTasks, uploadTasks, downloadTasks);
            }
        })
    })
}

當(dāng)用戶通過(guò)屬性獲取task的時(shí)候闽晦,NSURLSessionManager用了一個(gè)信號(hào)量,等待該異步操作操作的完成提岔,然后返回給用戶仙蛉。

- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);//令牌數(shù)為0
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
            tasks = dataTasks;
        }/* 刪減了其他分支 */
        dispatch_semaphore_signal(semaphore);//放入一個(gè)令牌
    }];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//令牌>0時(shí)向下執(zhí)行,否者等待
    return tasks;
}

六碱蒙、總結(jié)

AFNetworking框架UIKit模塊提供了View層的擴(kuò)展荠瘪,方便使用。Serialization模塊負(fù)責(zé)請(qǐng)求和返回?cái)?shù)據(jù)的序列化赛惩,Security模塊負(fù)責(zé)網(wǎng)絡(luò)安全哀墓,Reachability模塊負(fù)責(zé)網(wǎng)絡(luò)環(huán)境監(jiān)測(cè),NSURLSession模塊將其他模塊有機(jī)的組織在一起協(xié)同工作坊秸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末麸祷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子褒搔,更是在濱河造成了極大的恐慌阶牍,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件星瘾,死亡現(xiàn)場(chǎng)離奇詭異走孽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)琳状,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)磕瓷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人念逞,你說(shuō)我怎么就攤上這事困食。” “怎么了翎承?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵硕盹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叨咖,道長(zhǎng)瘩例,這世上最難降的妖魔是什么啊胶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮垛贤,結(jié)果婚禮上焰坪,老公的妹妹穿的比我還像新娘。我一直安慰自己聘惦,他們只是感情好某饰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著善绎,像睡著了一般露乏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涂邀,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音箱锐,去河邊找鬼比勉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驹止,可吹牛的內(nèi)容都是我干的浩聋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼臊恋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼衣洁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抖仅,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坊夫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后撤卢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體环凿,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年放吩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了智听。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渡紫,死狀恐怖到推,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惕澎,我是刑警寧澤莉测,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站集灌,受9級(jí)特大地震影響悔雹,放射性物質(zhì)發(fā)生泄漏复哆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一腌零、第九天 我趴在偏房一處隱蔽的房頂上張望梯找。 院中可真熱鬧,春花似錦益涧、人聲如沸锈锤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)久免。三九已至,卻和暖如春扭弧,著一層夾襖步出監(jiān)牢的瞬間阎姥,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工鸽捻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呼巴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓御蒲,卻偏偏與公主長(zhǎng)得像衣赶,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厚满,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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