NSURLSession相关代理

相关枚举

typedef NS_ENUM(NSInteger, NSURLSessionAuthChallengeDisposition) {
    NSURLSessionAuthChallengeUseCredential = 0,  使用指定的凭据,它可以是nil。                                     
    NSURLSessionAuthChallengePerformDefaultHandling = 1,  对挑战使用默认处理,就像未实现此委托方法一样。所提供的凭据参数将被忽略。                            
    NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 取消整个请求。所提供的凭据参数将被忽略。
    NSURLSessionAuthChallengeRejectProtectionSpace = 3,  拒绝此挑战,并使用下一个身份验证保护空间再次调用身份验证委托方法。所提供的凭据参数将被忽略。
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
typedef NS_ENUM(NSInteger, NSURLSessionDelayedRequestDisposition) {
    NSURLSessionDelayedRequestContinueLoading = 0,  指示任务应继续处理原始请求的配置。
    NSURLSessionDelayedRequestUseNewRequest = 1, 指示任务应该使用新请求来执行网络负载的配置。
    NSURLSessionDelayedRequestCancel = 2, 指示任务应被取消的配置。
} NS_SWIFT_NAME(URLSession.DelayedRequestDisposition) API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
    NSURLSessionResponseCancel = 0,  使用此配置相当于对任务调用cancel。
    NSURLSessionResponseAllow = 1, 允许继续加载操作。
    NSURLSessionResponseBecomeDownload = 2,  将此请求的响应转换为使用NSURLSessionDownloadTask。                              
    NSURLSessionResponseBecomeStream API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)) = 3,  将此请求的响应转换为使用NSURLSessionStreamTask。
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);

NSURLSessionDelegate 相关

定义URL会话实例调用其委托来处理会话级事件(如会话生命周期更改)的方法的协议。

除了在此协议中定义的方法之外,大多数委托还应该实现NSURLSessionTaskDelegate、NSURLSessionDataDelegate和NSURLSessionDownloadDelegate协议中的一些或所有方法,以处理任务级事件。

这些事件包括单个任务的开始和结束,以及来自数据或下载任务的定期进度更新。

注意: 您的NSURLSession对象不需要委托。如果没有分配委托,则使用系统提供的委托,并且必须提供一个completion回调函数来获取数据。

NSURLSessionDelegate 相关方法

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;
告诉URL会话会话已无效。
如果通过调用会话的finishtaskandinvalidate方法使会话无效,则会话将等到会话中的最后一个任务完成或失败后才调用此委托方法。如果您调用invalidateAndCancel方法,会话将立即调用此委托方法。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
                                             completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
请求来自委托的凭据,以响应来自远程服务器的会话级身份验证请求。
这种方法在两种情况下调用:
当远程服务器请求客户端证书或Windows NT LAN Manager (NTLM)身份验证时,允许您的应用程序提供适当的凭据
当会话首次建立到使用SSL或TLS的远程服务器的连接时,允许应用程序验证服务器的证书链
如果不实现此方法,则会话将调用其委托的URLSession:task:didReceiveChallenge:completionHandler:方法。
注意:该方法只处理NSURLAuthenticationMethodNTLM、NSURLAuthenticationMethodNegotiate、NSURLAuthenticationMethodClientCertificate和NSURLAuthenticationMethodServerTrust身份验证类型。对于所有其他身份验证方案,会话只调用URLSession:task:didReceiveChallenge:completionHandler:方法。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
告诉委托,为会话排队的所有消息都已交付。
在iOS中,当后台传输完成或需要凭证时,如果你的应用程序不再运行,你的应用程序会自动在后台重启,应用的UIApplicationDelegate被发送一个应用:handleEventsForBackgroundURLSession:completionHandler: message。此调用包含导致应用程序启动的会话的标识符。然后,您应该在创建具有相同标识符的后台配置对象和使用该配置创建会话之前存储该完成处理程序。新创建的会话与正在进行的后台活动自动重新关联。
当您的应用程序稍后接收到URLSessionDidFinishEventsForBackgroundURLSession: message时,这表示之前为该会话排队的所有消息都已发送,现在可以安全地调用以前存储的完成处理程序,或者启动任何可能导致调用完成处理程序的内部更新。
重要:因为所提供的完成处理程序是UIKit的一部分,所以必须在主线程上调用它。

NSURLSessionTaskDelegate 相关

完全继承 NSURLSessionDelegate 协议

定义URL会话实例调用其委托来处理任务级事件的方法的协议。

如果您正在使用下载任务,还可以实现NSURLSessionDownloadDelegate协议中的方法。

如果您正在使用数据或上载任务,还可以实现NSURLSessionDataDelegate协议中的方法。

注意:您的NSURLSession对象不需要委托。如果没有分配委托,则使用系统提供的委托,并且必须提供一个completion回调函数来获取数据。

NSURLSessionTaskDelegate 相关方法

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                        willBeginDelayedRequest:(NSURLRequest *)request
                              completionHandler:(void (^)(NSURLSessionDelayedRequestDisposition disposition, NSURLRequest * _Nullable newRequest))completionHandler
    API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
告诉委托,延迟的URL会话任务现在将开始加载。
当具有延迟启动时间的后台会话任务(如使用earliestBeginDate属性设置的)准备启动时,将调用此方法。只有当请求在等待网络负载并需要被新请求替换时变得过时,才应该实现此委托方法。
要继续加载,委托必须调用完成处理程序,并传入指示任务应如何进行的配置。
传递NSURLSessionDelayedRequestCancel配置相当于直接调用任务上的cancel。
- (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task
    API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
告诉委托任务正在等待合适的连接可用后才开始网络加载。
如果NSURLSessionConfiguration的waitsForConnectivity属性为true,且没有足够的连接性,则调用此方法。委托可以利用此机会更新用户界面;例如,通过显示脱机模式或只显示蜂窝模式。
对于每个任务,最多只调用一次此方法,且仅当连接最初不可用时才调用。它从不为后台会话调用,因为这些会话会忽略waitsForConnectivity。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                     willPerformHTTPRedirection:(NSHTTPURLResponse *)response
                                     newRequest:(NSURLRequest *)request
                              completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;
告诉委托远程服务器请求HTTP重定向。
此方法仅对默认会话和临时会话中的任务调用。后台会话中的任务自动跟随重定向。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                            didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
                              completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
从委托请求凭据,以响应来自远程服务器的身份验证请求。
此方法处理任务级身份验证挑战。
NSURLSessionDelegate协议还提供了会话级身份验证委托方法。所调用的方法取决于身份验证挑战的类型:
对于会话级的挑战——nsurlauthenticationmethodntlm、NSURLAuthenticationMethodNegotiate、NSURLAuthenticationMethodClientCertificate或nsurlauthenticationmethodservertrust——NSURLSession对象调用会话委托的URLSession:didReceiveChallenge:completionHandler:方法。如果应用程序没有提供会话委托方法,NSURLSession对象将调用任务委托的URLSession:task:didReceiveChallenge:completionHandler:方法来处理挑战。
对于非会话级别的挑战(所有其他挑战),NSURLSession对象调用会话委托的URLSession:task:didReceiveChallenge:completionHandler:方法来处理该挑战。
如果您的应用程序提供了一个会话委托,并且您需要处理身份验证,那么您必须在任务级处理身份验证,或者提供一个显式调用每个会话处理程序的任务级处理程序。对于非会话级别的挑战,不调用会话委托的URLSession:didReceiveChallenge:completionHandler:方法。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                              needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler;
当任务需要向远程服务器发送新的请求主体流时,通知委托。
任务在两种情况下调用这个委托方法:
如果任务是用uploadTaskWithStreamedRequest创建的,则提供初始请求体流:
如果任务因身份验证挑战或其他可恢复服务器错误而需要重新发送具有主体流的请求,则提供替换请求主体流。
注意:如果代码使用文件URL或数据对象提供请求体,则不需要实现此方法。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                                didSendBodyData:(int64_t)bytesSent
                                 totalBytesSent:(int64_t)totalBytesSent
                       totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
定期通知委托将主体内容发送到服务器的过程。
totalBytesSent和totalBytesExpectedToSend参数也可以作为NSURLSessionTask属性countOfBytesSent和countOfBytesExpectedToSend使用。或者,由于NSURLSessionTask支持NSProgressReporting,您可以使用任务的progress属性,这可能更方便。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
当为任务收集完整的统计信息时发送。
告诉委托,会话已完成收集任务的指标。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                           didCompleteWithError:(nullable NSError *)error;
告诉委托任务已完成数据传输。
服务器错误不通过错误参数报告。委托通过错误参数接收到的唯一错误是客户端错误,例如无法解析主机名或连接到主机。

NSURLSessionDataDelegate 相关

与直接向委托交付数据的任务的操作相关的消息。

定义方法的协议,URL会话实例调用这些方法的委托来处理特定于数据和上载任务的任务级事件。

完全继承 NSURLSessionTaskDelegate

您的会话委托还应该实现NSURLSessionTaskDelegate协议中的方法来处理所有任务类型共有的任务级事件,以及NSURLSessionDelegate协议中的方法来处理会话级事件。

NSURLSession对象不需要委托。如果没有分配委托,则在该会话中创建任务时,必须提供一个completion handler块来获取数据。

完成处理程序块主要用于替代使用自定义委托。如果使用接受完成处理程序块的方法创建任务,则不会调用用于响应和数据交付的委托方法。

NSURLSessionDataDelegate 相关方法

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
告诉委托,数据任务从服务器接收到初始回复(头)。
实现此方法是可选的,除非您需要在第一次接收响应头时取消传输或将其转换为下载任务。如果不提供此委托方法,则会话始终允许任务继续。
如果需要支持相当模糊的多部分/x-混合替换内容类型,还可以实现此方法。使用该内容类型,服务器发送一系列部件,每个部件都用于替换前一部分。会话在每个部分的开头调用这个方法,然后用该部分的内容调用一个或多个URLSession:dataTask:didReceiveData:。
每当为某个部分调用URLSession:dataTask:didReceiveResponse:completionHandler:方法时,收集前一部分接收到的数据(如果有的话),并根据应用程序的需要处理数据。这种处理可以包括将数据存储到文件系统,将其解析为自定义类型,或者显示给用户。接下来,通过使用NSURLSessionResponseAllow常量调用完成处理程序,开始接收下一部分。最后,如果您还实现了URLSession:task:didCompleteWithError:,会话将在发送完最后一部分的所有数据后调用它。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                              didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
告诉委托数据任务已更改为下载任务。
当您的URLSession:dataTask:didReceiveResponse:completionHandler: delegate方法使用NSURLSessionResponseBecomeDownload配置将请求转换为使用下载时,会话调用此委托方法来为您提供新的下载任务。在此调用之后,会话委托将不再接收与原始数据任务相关的委托方法调用。
数据任务已成为下载任务的通知。将来不会向数据任务发送任何消息。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;
告诉委托数据任务已更改为流任务。
当您的URLSession:dataTask:didReceiveResponse:completionHandler: delegate方法使用NSURLSessionResponseBecomeStream配置将请求转换为使用流时,会话调用此委托方法来为您提供新的流任务。在此调用之后,会话委托将不再接收与原始数据任务相关的委托方法调用。
对于已管道化的请求,流任务只允许读取,对象立即发送委托消息URLSession:writeClosedForStreamTask:。通过在它的NSURLSessionConfiguration对象上设置HTTPShouldUsePipelining属性,或者通过在NSURLRequest对象上设置HTTPShouldUsePipelining属性来处理单个请求。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                     didReceiveData:(NSData *)data;
告诉委托,数据任务已接收到一些预期的数据。
因为数据对象参数通常是由许多不同的数据对象拼凑而成的,只要有可能,使用enumerateByteRangesUsingBlock:方法遍历数据,而不是使用bytes方法(它将数据对象压扁为单个内存块)。
此委托方法可以被多次调用,并且每个调用只提供自上次调用以来接收到的数据。如果需要,应用程序负责积累这些数据。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                  willCacheResponse:(NSCachedURLResponse *)proposedResponse 
                                  completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
询问委托数据(或上载)任务是否应将响应存储在缓存中。
会话在任务接收完所有预期数据后调用此委托方法。如果不实现此方法,默认行为是使用会话配置对象中指定的缓存策略。此方法的主要目的是防止缓存特定URL或修改与URL响应关联的userInfo字典。只有在处理请求的NSURLProtocol决定缓存响应时才调用此方法。一般来说,只有当下列各项都为真时,才会缓存响应:
请求是针对HTTP或HTTPS URL(或支持缓存的自定义网络协议)。
请求成功(状态码在200-299范围内)。
所提供的响应来自服务器,而不是缓存。
会话配置的缓存策略允许缓存。
提供的URLRequest对象的缓存策略(如果适用)允许缓存。
服务器响应中的缓存相关头(如果存在)允许缓存。
响应大小足够小,可以合理地放入缓存中。(例如,如果提供磁盘缓存,响应必须不大于磁盘缓存大小的5%左右。)

NSURLSessionDownloadDelegate

定义方法的协议,URL会话实例调用这些方法的委托来处理特定于下载任务的任务级事件。

除了本协议中的方法外,请确保在NSURLSessionTaskDelegate和NSURLSessionDelegate协议中实现方法,分别处理所有任务类型和会话级事件的公共事件。

注意: NSURLSession对象不需要委托。如果没有分配委托,则使用系统提供的委托,并且必须提供一个completion回调函数来获取数据。

与将数据写入文件并在完成时通知委托的任务的操作相关的消息。

完全继承 NSURLSessionTaskDelegate

NSURLSessionDownloadDelegate 相关方法

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;
告诉委托下载任务已完成下载。
如果选择打开文件进行读取,应该在另一个线程中执行实际读取,以避免阻塞委托队列。
当下载任务完成下载后发送
委托应该复制或移动指定位置的文件到新位置,因为当委托消息返回时,将删除该文件。URLSession:task:didCompleteWithError:仍然会被调用。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
定期通知委托下载的进度。
定期发送,通知委托下载进度。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;
告诉委托下载任务已恢复下载。
如果可恢复的下载任务被取消或失败,您可以请求一个resumeData对象,该对象提供足够的信息,以便将来重新启动下载。稍后,您可以使用该数据调用downloadTaskWithResumeData:或downloadTaskWithResumeData:completionHandler:。
当您调用这些方法时,您将获得一个新的下载任务。一旦您恢复该任务,会话就会用该新任务调用该方法,以指示下载已恢复。

NSURLSessionStreamDelegate 相关

定义方法的协议,URL会话实例调用这些方法的委托来处理特定于流任务的任务级事件。

除了这些方法之外,请确保在NSURLSessionTaskDelegate和NSURLSessionDelegate协议中实现方法,分别处理所有任务类型和会话级事件的公共事件。

NSURLSession对象不需要委托。如果没有分配委托,则使用系统提供的委托,并且必须提供一个completion回调函数来获取数据。

完全继承 NSURLSessionTaskDelegate

NSURLSessionStreamDelegate 相关方法

- (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;
告诉委托基础套接字的读端已关闭。
即使当前没有进行读取,也可以调用此方法。此方法不表示流已到达文件末尾(EOF),因此无法读取更多数据。
确定连接的读端已关闭。
任何未完成的读取都将完成,但是将来的读取将立即失败。
即使没有读取正在进行中,也可以发送此消息。
然而,当接收到此委托消息时,可能仍然有字节可用。
您只需要知道,当您能够读取EOF之前,没有更多的字节可用。
- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;
告诉委托基础套接字的写端已关闭。
即使当前没有进行写操作,也可以调用此方法。
确定连接的写端已关闭。
任何未完成的写操作都已完成,但是将来的写操作将立即失败。
- (void)URLSession:(NSURLSession *)session betterRouteDiscoveredForStreamTask:(NSURLSessionStreamTask *)streamTask;
告诉委托,已为流检测到更好的到主机的路由。
当URL加载系统确定到端点主机的更好路由可用时,将调用此方法。例如,当Wi-Fi接口可用时,可以调用此方法。
您应该考虑完成挂起的工作并创建一个新的流任务,以便在它们可用时利用更好的路由。
一个通知,系统已经确定到主机的更好的路由已被检测到(例如,一个wi-fi接口可用)。
这是给委托的一个提示,说明可能需要为后续工作创建一个新任务。
注意,不能保证将来的任务能够连接到主机,因此调用者应该为任何新接口上的读写失败做好准备。
- (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask
                                 didBecomeInputStream:(NSInputStream *)inputStream
                                         outputStream:(NSOutputStream *)outputStream;
告诉委托,流任务已作为调用captureStreams方法的流任务的结果完成。
此委托方法仅在流任务的所有入队列读写完成后调用。
给定的任务已经完成,并且从底层网络连接创建了未打开的NSInputStream和NSOutputStream对象。
这只会在所有入队IO完成后调用(包括任何必要的握手)。
streamTask将不再接收任何其他委托消息。

涉及相关类(未深度研究的)

NSURLAuthenticationChallenge
NSCachedURLResponse
NSOutputStream
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342