RQHTTPService.m 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. //
  2. // RQHTTPService.m
  3. // RQCommon
  4. //
  5. // Created by 张嵘 on 2018/11/16.
  6. // Copyright © 2018 张嵘. All rights reserved.
  7. //
  8. #import "RQHTTPService.h"
  9. #import <AFNetworking/AFNetworkActivityIndicatorManager.h>
  10. #import <CocoaSecurity/CocoaSecurity.h>
  11. #import <MJExtension/MJExtension.h>
  12. #import <JDStatusBarNotification/JDStatusBarNotification.h>
  13. #import <CoreTelephony/CTCellularData.h>
  14. /**
  15. * 知识点
  16. //- (RACSignal *)replayLast 就是用Capacity为1的RACReplaySubject来替换- (RACSignal *)replay的`subject。
  17. 其作用是使后来订阅者只收到最后的历史值。
  18. //- (RACSignal *)replayLazily和- (RACSignal *)replay的区别就是replayLazily会在第一次订阅的时候才订阅sourceSignal。
  19. // replay、replayLast、replayLazily的区别 ReactiveCocoa提供了这三个简便的方法允许多个订阅者订阅一个信号,却不会重复执行订阅代码,并且能给新加的订阅者提供订阅前的值。
  20. replay和replayLast使信号变成热信号,且会提供所有值(-replay) 或者最新的值(-replayLast) 给订阅者。
  21. replayLazily 会提供所有的值给订阅者 replayLazily还是冷信号 避免了冷信号的副作用
  22. *
  23. */
  24. /// The Http request error domain
  25. NSString *const RQHTTPServiceErrorDomain = @"RQHTTPServiceErrorDomain";
  26. /// 请求成功,但statusCode != 0
  27. NSString *const RQHTTPServiceErrorResponseCodeKey = @"RQHTTPServiceErrorResponseCodeKey";
  28. NSString * const RQHTTPServiceErrorRequestURLKey = @"RQHTTPServiceErrorRequestURLKey";
  29. NSString * const RQHTTPServiceErrorHTTPStatusCodeKey = @"RQHTTPServiceErrorHTTPStatusCodeKey";
  30. NSString * const RQHTTPServiceErrorDescriptionKey = @"RQHTTPServiceErrorDescriptionKey";
  31. NSString * const RQHTTPServiceErrorMessagesKey = @"RQHTTPServiceErrorMessagesKey";
  32. NSString * const RQNetworkingReachabilityDidChangeNotification = @"RQNetworkingReachabilityDidChangeNotification";
  33. /// 连接服务器失败 default
  34. NSInteger const RQHTTPServiceErrorConnectionFailed = 668;
  35. NSInteger const RQHTTPServiceErrorJSONParsingFailed = 669;
  36. NSInteger const RQHTTPServiceErrorBadRequest = 670;
  37. NSInteger const RQHTTPServiceErrorRequestForbidden = 671;
  38. /// 服务器请求失败
  39. NSInteger const RQHTTPServiceErrorServiceRequestFailed = 672;
  40. NSInteger const RQHTTPServiceErrorSecureConnectionFailed = 673;
  41. /// 微信登录相关
  42. NSString * const RQWeChatOnRespNotification = @"RQWeChatOnRespNotification";
  43. /// 抖音登录相关
  44. NSString * const RQDouYinOnRespNotification = @"RQDouYinOnRespNotification";
  45. @interface RQHTTPService ()
  46. @property (nonatomic, assign, readwrite) AFNetworkReachabilityStatus networkReachabilityStatus;
  47. @property (nonatomic, readwrite, assign) BOOL isShowNetWorkAuth;
  48. @end
  49. @implementation RQHTTPService
  50. static id service_ = nil;
  51. #pragma mark - HTTPService
  52. +(instancetype) sharedInstance {
  53. static dispatch_once_t onceToken;
  54. dispatch_once(&onceToken, ^{
  55. service_ = [[self alloc] initWithBaseURL:[NSURL URLWithString:[RQConfigureManager requestBaseUrl]] sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
  56. });
  57. return service_;
  58. }
  59. + (id)allocWithZone:(struct _NSZone *)zone{
  60. static dispatch_once_t onceToken;
  61. dispatch_once(&onceToken, ^{
  62. service_ = [super allocWithZone:zone];
  63. });
  64. return service_;
  65. }
  66. - (id)copyWithZone:(NSZone *)zone {
  67. return service_;
  68. }
  69. - (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration{
  70. if (self = [super initWithBaseURL:url sessionConfiguration:configuration]) {
  71. /// 配置
  72. [self _configHTTPService];
  73. [self wechatOnRespNotification];
  74. [self douYinOnRespNotification];
  75. }
  76. return self;
  77. }
  78. /// config service
  79. - (void)_configHTTPService{
  80. AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializer];
  81. #if DEBUG
  82. responseSerializer.removesKeysWithNullValues = NO;
  83. #else
  84. responseSerializer.removesKeysWithNullValues = YES;
  85. #endif
  86. responseSerializer.readingOptions = NSJSONReadingAllowFragments;
  87. /// config
  88. self.responseSerializer = responseSerializer;
  89. self.requestSerializer = [AFJSONRequestSerializer serializer];
  90. /// 安全策略
  91. AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
  92. //allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
  93. //如果是需要验证自建证书,需要设置为YES
  94. securityPolicy.allowInvalidCertificates = YES;
  95. //validatesDomainName 是否需要验证域名,默认为YES;
  96. //假如证书的域名与你请求的域名不一致,需把该项设置为NO
  97. //主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
  98. securityPolicy.validatesDomainName = NO;
  99. self.securityPolicy = securityPolicy;
  100. /// 支持解析
  101. self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
  102. @"text/json",
  103. @"text/javascript",
  104. @"text/html",
  105. @"text/plain",
  106. @"text/html; charset=UTF-8",
  107. nil];
  108. /// 开启网络监测
  109. [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
  110. [self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
  111. switch (status) {
  112. case AFNetworkReachabilityStatusUnknown:
  113. // 未知网络
  114. NSLog(@"当前网络:未知网络");
  115. break;
  116. case AFNetworkReachabilityStatusNotReachable:
  117. // 无网络
  118. NSLog(@"当前网络:无网络");
  119. break;
  120. case AFNetworkReachabilityStatusReachableViaWWAN:
  121. // 蜂窝数据
  122. NSLog(@"当前网络:蜂窝数据");
  123. break;
  124. case AFNetworkReachabilityStatusReachableViaWiFi:
  125. // 无线网络
  126. NSLog(@"当前网络:无线网络");
  127. break;
  128. default:
  129. break;
  130. }
  131. if (_networkReachabilityStatus != status) {
  132. _networkReachabilityStatus = status;
  133. // 网络改变通知
  134. [[NSNotificationCenter defaultCenter] postNotificationName:RQNetworkingReachabilityDidChangeNotification object:[NSNumber numberWithInteger:status]];
  135. }
  136. }];
  137. [self.reachabilityManager startMonitoring];
  138. }
  139. #pragma mark - Request
  140. - (RACSignal *)enqueueRequest:(RQHTTPRequest *) request resultClass:(Class /*subclass of RQObject*/) resultClass{
  141. /// request 必须的有值
  142. if (!request) return [RACSignal error:[NSError errorWithDomain:RQHTTPServiceErrorDomain code:-1 userInfo:nil]];
  143. @weakify(self);
  144. if ([request.urlParameters.method isEqualToString:RQ_HTTTP_METHOD_GET] || [request.urlParameters.path isEqualToString:RQ_POST_Code] || [request.urlParameters.path isEqualToString:RQ_POST_Code_IOS] || [request.urlParameters.path isEqualToString:RQ_POST_Code_DouYin]) {
  145. /// 覆盖manager请求序列化
  146. self.requestSerializer = [self _requestSerializerWithRequest:request];
  147. } else if ([request.urlParameters.method isEqualToString:RQ_HTTTP_METHOD_POST] && ![request.urlParameters.path isEqualToString:RQ_POST_Code] && ![request.urlParameters.path isEqualToString:RQ_POST_Code_IOS] && ![request.urlParameters.path isEqualToString:RQ_POST_PrepareOrder]) {
  148. self.requestSerializer = [self _requestJSONSerializerWithRequest:request];
  149. } else if ([request.urlParameters.method isEqualToString:RQ_HTTTP_METHOD_DELETE]) {
  150. if (request.urlParameters.parameters.allValues.count > 1) {
  151. self.requestSerializer = [self _requestJSONSerializerWithRequest:request];
  152. } else {
  153. NSString *deletePath = [NSString stringWithFormat:@"%@/%@",request.urlParameters.path,request.urlParameters.parameters.allValues.firstObject];
  154. request.urlParameters.path = deletePath;
  155. request.urlParameters.parameters = @{};
  156. self.requestSerializer = [self _requestSerializerWithRequest:request];
  157. }
  158. } else {
  159. self.requestSerializer = [self _requestSerializerWithRequest:request];
  160. }
  161. // self.requestSerializer.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", nil];
  162. if (RQ_USER_MANAGER.isLogin) {
  163. [self.requestSerializer setValue:RQ_USER_MANAGER.currentUser.token forHTTPHeaderField:@"Authorization"];
  164. }
  165. /// @RQ-MARK:请求参数
  166. // request.urlParameters.path = [NSString stringWithFormat:@"%@?%@",request.urlParameters.path, [self _signWithParameters:request.urlParameters.parameters]];
  167. // request.urlParameters.path = [NSString stringWithFormat:@"%@",request.urlParameters.path];
  168. /// 发起请求
  169. /// concat:按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。 这里传进去的参数,不是parameters而是之前通过
  170. /// urlParametersWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters;穿进去的参数
  171. return [[[self enqueueRequestWithPath:request.urlParameters.path parameters:request.urlParameters.parameters method:request.urlParameters.method]
  172. reduceEach:^RACStream *(NSURLResponse *response, NSDictionary * responseObject){
  173. @strongify(self);
  174. /// 请求成功 这里解析数据
  175. return [[self parsedResponseOfClass:resultClass fromJSON:responseObject]
  176. map:^(id parsedResult) {
  177. RQHTTPResponse *parsedResponse = [[RQHTTPResponse alloc] initWithResponseObject:responseObject parsedResult:parsedResult];
  178. NSAssert(parsedResponse != nil, @"Could not create RQHTTPResponse with response %@ and parsedResult %@", response, parsedResult);
  179. return parsedResponse;
  180. }];
  181. }]
  182. concat];
  183. }
  184. /// 请求数据
  185. - (RACSignal *)enqueueRequestWithPath:(NSString *)path parameters:(id)parameters method:(NSString *)method{
  186. @weakify(self);
  187. /// 创建信号
  188. RACSignal *signal = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
  189. @strongify(self);
  190. /// 获取request
  191. NSError *serializationError = nil;
  192. NSMutableURLRequest *request;
  193. // NSDictionary *dic = parameters;
  194. // YYCache *cache = [[YYCache alloc] initWithName:@"getTeachingVideoByTypeId"];
  195. // NSString *cacheResponseKeyName = [NSString stringWithFormat:@"Response-getTeachingVideoByTypeId=%@",dic[@"videoTypeId"]];
  196. // NSString *cacheResponseObjectKeyName = [NSString stringWithFormat:@"ResponseObject-getTeachingVideoByTypeId=%@",dic[@"videoTypeId"]];
  197. if ([RQ_CACHE_MANAGER isNeedCacheWithPath:path]) {
  198. // if ([cache objectForKey:cacheResponseObjectKeyName] && [cache objectForKey:cacheResponseKeyName]) {
  199. // /// 打包成元祖 回调数据
  200. // NSURLResponse *response = (NSURLResponse *)[cache objectForKey:cacheResponseKeyName];
  201. // NSDictionary *responseObject = (NSDictionary *)[cache objectForKey:cacheResponseObjectKeyName];
  202. // dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
  203. // [subscriber sendNext:RACTuplePack(response , responseObject)];
  204. // [subscriber sendCompleted];
  205. // });
  206. // return [RACDisposable disposableWithBlock:^{
  207. //
  208. // }];
  209. // }
  210. NSDictionary *dic = [RQ_CACHE_MANAGER getCacheWithPath:path parameters:parameters];
  211. if (!RQObjectIsNil(dic)) {
  212. NSURLResponse *response = (NSURLResponse *)dic[@"response"];
  213. NSDictionary *responseObject = (NSDictionary *)dic[@"responseObject"];
  214. dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
  215. [subscriber sendNext:RACTuplePack(response , responseObject)];
  216. [subscriber sendCompleted];
  217. });
  218. return [RACDisposable disposableWithBlock:^{
  219. }];
  220. }
  221. }
  222. if ([path containsString:@"api.weixin.qq.com"] || [path containsString:@"zzjs.zzxcx.net"] || [path containsString:@"192.168.8.213:8080"]) {
  223. request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:[NSURL URLWithString:@""]] absoluteString] parameters:parameters error:&serializationError];
  224. } else {
  225. if ([path isEqualToString:RQ_POST_AddCollections]) {
  226. NSDictionary *dic = parameters;
  227. request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString] parameters:dic[@"list"] error:&serializationError];
  228. } else if ([path isEqualToString:RQ_DELETE_Collection_All] || [path isEqualToString:RQ_DELETE_Wrong_All]) {
  229. request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
  230. [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
  231. NSString *dataStr = [parameters mj_JSONString];
  232. NSData * bodyData = [dataStr mj_JSONData];
  233. [request setHTTPBody:bodyData];
  234. } else {
  235. request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
  236. }
  237. }
  238. if (serializationError) {
  239. #pragma clang diagnostic push
  240. #pragma clang diagnostic ignored "-Wgnu"
  241. dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
  242. [subscriber sendError:serializationError];
  243. });
  244. #pragma clang diagnostic pop
  245. return [RACDisposable disposableWithBlock:^{
  246. }];
  247. }
  248. /// 获取请求任务
  249. __block NSURLSessionDataTask *task = nil;
  250. task = [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse *response, NSDictionary * responseObject, NSError *error) {
  251. NSDictionary *erroInfo = error.userInfo;
  252. NSData *data = [erroInfo valueForKey:@"com.alamofire.serialization.response.error.data"];
  253. NSString *errorString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  254. if (error) {
  255. NSError *parseError = [self _errorFromRequestWithTask:task httpResponse:(NSHTTPURLResponse *)response responseObject:responseObject error:error];
  256. [self HTTPRequestLog:task body:parameters error:parseError];
  257. [subscriber sendError:parseError];
  258. } else {
  259. /// 断言
  260. NSAssert([responseObject isKindOfClass:NSDictionary.class], @"responseObject is not an NSDictionary: %@", responseObject);
  261. /// 在这里判断数据是否正确
  262. /// 判断
  263. NSInteger statusCode = [responseObject[RQHTTPServiceResponseCodeKey] integerValue];
  264. if (statusCode == RQHTTPResponseCodeSuccess) {
  265. // NSHTTPURLResponse *httpUrlResponse = (NSHTTPURLResponse *)response;
  266. // /// 存储token
  267. // NSString *token = [[[httpUrlResponse allHeaderFields] valueForKey:RQHTTPRequestTokenKey] rq_stringValueExtension];
  268. // [self saveToken:token];
  269. [self HTTPRequestLog:task body:parameters error:nil];
  270. /// 打包成元祖 回调数据
  271. [subscriber sendNext:RACTuplePack(response , responseObject)];
  272. if ([RQ_CACHE_MANAGER isNeedCacheWithPath:path]) {
  273. // [cache setObject:response forKey:cacheResponseKeyName];
  274. // [cache setObject:responseObject forKey:cacheResponseObjectKeyName];
  275. [RQ_CACHE_MANAGER saveCacheWithPath:path parameters:parameters response:response responseObject:responseObject];
  276. }
  277. [subscriber sendCompleted];
  278. }else{
  279. if (([path isEqualToString:RQ_GET_Userinfo] || [path isEqualToString:RQ_GET_Refresh_token]) && statusCode == 0) {
  280. /// 打包成元祖 回调数据
  281. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:responseObject];
  282. [dic setValue:path forKey:@"path"];
  283. [subscriber sendNext:RACTuplePack(response , dic.copy)];
  284. [subscriber sendCompleted];
  285. }
  286. if (statusCode == RQHTTPResponseCodeNotLogin && ![RQControllerHelper.currentViewController isKindOfClass:[RQLoginViewController class]]) {
  287. RACSignal *signalA = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  288. /// 删除账号
  289. [SAMKeychain deleteRawLogin];
  290. /// 先退出用户
  291. [RQ_USER_MANAGER logoutUser];
  292. [subscriber sendNext:@1];
  293. [subscriber sendCompleted];
  294. return nil;
  295. }] delay:1] deliverOnMainThread];
  296. RACSignal *signalB = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  297. /// 这里切换 主页面
  298. [RQNotificationCenter postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogout)}];
  299. [subscriber sendNext:@2];
  300. return nil;
  301. }] delay:1] deliverOnMainThread];
  302. // 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。
  303. RACSignal *concatSignal = [signalA concat:signalB];
  304. // 以后只需要面对拼接信号开发。
  305. // 订阅拼接的信号,不需要单独订阅signalA,signalB
  306. // 内部会自动订阅。
  307. // 注意:第一个信号必须发送完成,第二个信号才会被激活
  308. [concatSignal subscribeNext:^(id x) {
  309. NSLog(@"%@",x);
  310. if ([x integerValue] == 2) {
  311. RQ_USER_MANAGER.isShouldLogin;
  312. }
  313. }];
  314. // [[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  315. //
  316. // /// 延迟一段时间
  317. // [subscriber sendNext:@1];
  318. // return nil;
  319. // }] delay:1] deliverOnMainThread] then:^RACSignal * _Nonnull{
  320. // return [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  321. // /// 这里切换 主页面
  322. // [RQNotificationCenter postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogout)}];
  323. // /// 延迟一段时间
  324. // [subscriber sendNext:@2];
  325. // return nil;
  326. // }] delay:1] deliverOnMainThread];
  327. // }] subscribeNext:^(id x) {
  328. // /// 这里切换 到账号登录的界面
  329. // NSLog(@"%@",x);
  330. // RQ_USER_MANAGER.isShouldLogin;
  331. // }];
  332. // [self login:^{
  333. // /// 这里需要重新配置序列化
  334. // self.requestSerializer = [self _requestSerializerWithRequest:[RQHTTPRequest requestWithParameters:[RQURLParameters urlParametersWithMethod:method path:path parameters:parameters]]];
  335. // /// 重新发起请求
  336. // [[self enqueueRequestWithPath:path parameters:parameters method:method] subscribe:subscriber];
  337. // } cancel:^{
  338. // NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  339. // userInfo[RQHTTPServiceErrorResponseCodeKey] = @(statusCode);
  340. // NSString *msgTips = responseObject[RQHTTPServiceResponseMsgKey];
  341. //#if defined(DEBUG)||defined(_DEBUG)
  342. // msgTips = RQStringIsNotEmpty(msgTips)?[NSString stringWithFormat:@"%@(%zd)",msgTips,statusCode]:[NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode]; /// 调试模式
  343. //#else
  344. // msgTips = RQStringIsNotEmpty(msgTips)?msgTips:@"服务器出错了,请稍后重试~"; /// 发布模式
  345. //#endif
  346. // userInfo[RQHTTPServiceErrorMessagesKey] = msgTips;
  347. // if (task.currentRequest.URL != nil) userInfo[RQHTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;
  348. // if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;
  349. // NSError *requestError = [NSError errorWithDomain:RQHTTPServiceErrorDomain code:statusCode userInfo:userInfo];
  350. // [self HTTPRequestLog:task body:parameters error:requestError];
  351. // [subscriber sendError:requestError];
  352. // }];
  353. } else if (statusCode == RQHTTPResponseInsufficientRequestPermissionCode) {
  354. NSString *savePath = path;
  355. NSString *saveParameters = parameters;
  356. NSString *saveMethod = method;
  357. /// token过期 请求权限不足
  358. [[RQ_HTTP_Service wechatRefreshToken] subscribeNext:^(RQWechatRefreshTokenModel *wechatRefreshTokenModel) {
  359. RQ_USER_MANAGER.currentUser.thirdResult.access_token = wechatRefreshTokenModel.access_token;
  360. RQ_USER_MANAGER.currentUser.thirdResult.refresh_token = wechatRefreshTokenModel.refresh_token;
  361. RQ_USER_MANAGER.currentUser.thirdResult.scope = wechatRefreshTokenModel.scope;
  362. RQ_USER_MANAGER.currentUser.thirdResult.openid = wechatRefreshTokenModel.openid;
  363. [self enqueueRequestWithPath:savePath parameters:saveParameters method:saveMethod];
  364. }];
  365. } else {
  366. NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  367. userInfo[RQHTTPServiceErrorResponseCodeKey] = @(statusCode);
  368. NSString *msgTips = responseObject[RQHTTPServiceResponseMsgKey];
  369. if ([responseObject[RQHTTPServiceResponseDataKey] isKindOfClass:[NSString class]] && RQStringIsEmpty(msgTips)) {
  370. msgTips = responseObject[RQHTTPServiceResponseDataKey];
  371. #if defined(DEBUG)||defined(_DEBUG)
  372. msgTips = RQStringIsNotEmpty(msgTips)?[NSString stringWithFormat:@"%@(%zd)",msgTips,statusCode]:[NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode]; /// 调试模式
  373. #else
  374. msgTips = RQStringIsNotEmpty(msgTips)?msgTips:@"服务器出错了,请稍后重试~";/// 发布模式
  375. #endif
  376. } else {
  377. #if defined(DEBUG)||defined(_DEBUG)
  378. msgTips = RQObjectIsNil(msgTips)? [NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode] : (RQStringIsNotEmpty(msgTips)?[NSString stringWithFormat:@"%@(%zd)",msgTips,statusCode]:[NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode]); /// 调试模式
  379. #else
  380. msgTips = RQStringIsNotEmpty(msgTips)?msgTips:@"服务器出错了,请稍后重试~";/// 发布模式
  381. #endif
  382. }
  383. userInfo[RQHTTPServiceErrorMessagesKey] = msgTips;
  384. if (task.currentRequest.URL != nil) userInfo[RQHTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;
  385. if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;
  386. NSError *requestError = [NSError errorWithDomain:RQHTTPServiceErrorDomain code:statusCode userInfo:userInfo];
  387. [self HTTPRequestLog:task body:parameters error:requestError];
  388. [subscriber sendError:requestError];
  389. }
  390. }
  391. }
  392. }];
  393. /// 开启请求任务
  394. [task resume];
  395. return [RACDisposable disposableWithBlock:^{
  396. [task cancel];
  397. }];
  398. }];
  399. /// replayLazily:replayLazily会在第一次订阅的时候才订阅sourceSignal
  400. /// 会提供所有的值给订阅者 replayLazily还是冷信号 避免了冷信号的副作用
  401. return [[signal
  402. replayLazily]
  403. setNameWithFormat:@"-enqueueRequestWithPath: %@ parameters: %@ method: %@", path, parameters , method];
  404. }
  405. #pragma mark - Upload
  406. - (RACSignal *)enqueueUploadRequest:(RQHTTPRequest *)request resultClass:(Class)resultClass fileDatas:(NSArray<NSData *> *)fileDatas name:(NSString *)name mimeType:(NSString *)mimeType{
  407. /// request 必须的有值
  408. if (!request) return [RACSignal error:[NSError errorWithDomain:RQHTTPServiceErrorDomain code:-1 userInfo:nil]];
  409. /// 断言
  410. NSAssert(RQStringIsNotEmpty(name), @"name is empty: %@", name);
  411. @weakify(self);
  412. /// 覆盖manager 请求序列化
  413. self.requestSerializer = [self _requestSerializerWithRequest:request];
  414. /// 发起请求
  415. /// concat:按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。 这里传进去的参数,不是parameters而是之前通过
  416. /// urlParametersWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters;穿进去的参数
  417. return [[[self enqueueUploadRequestWithPath:request.urlParameters.path parameters:request.urlParameters.parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
  418. NSInteger count = fileDatas.count;
  419. for (int i = 0; i< count; i++) {
  420. /// 取出fileData
  421. NSData *fileData = fileDatas[i];
  422. /// 断言
  423. NSAssert([fileData isKindOfClass:NSData.class], @"fileData is not an NSData class: %@", fileData);
  424. // 在网络开发中,上传文件时,是文件不允许被覆盖,文件重名
  425. // 要解决此问题,
  426. // 可以在上传时使用当前的系统事件作为文件名
  427. static NSDateFormatter *formatter = nil;
  428. static dispatch_once_t onceToken;
  429. dispatch_once(&onceToken, ^{
  430. formatter = [[NSDateFormatter alloc] init];
  431. });
  432. // 设置时间格式
  433. [formatter setDateFormat:@"yyyyMMddHHmmss"];
  434. NSString *dateString = [formatter stringFromDate:[NSDate date]];
  435. NSString *fileName = [NSString stringWithFormat:@"senba_empty_%@_%d.jpg", dateString , i];
  436. [formData appendPartWithFileData:fileData name:name fileName:fileName mimeType:RQStringIsNotEmpty(mimeType)?mimeType:@"application/octet-stream"];
  437. }
  438. }]
  439. reduceEach:^RACStream *(NSURLResponse *response, NSDictionary * responseObject){
  440. @strongify(self);
  441. /// 请求成功 这里解析数据
  442. return [[self parsedResponseOfClass:resultClass fromJSON:responseObject]
  443. map:^(id parsedResult) {
  444. RQHTTPResponse *parsedResponse = [[RQHTTPResponse alloc] initWithResponseObject:responseObject parsedResult:parsedResult];
  445. NSAssert(parsedResponse != nil, @"Could not create RQHTTPResponse with response %@ and parsedResult %@", response, parsedResult);
  446. return parsedResponse;
  447. }];
  448. }]
  449. concat];;
  450. }
  451. - (RACSignal *)enqueueUploadRequestWithPath:(NSString *)path parameters:(id)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block{
  452. @weakify(self);
  453. /// 创建信号
  454. RACSignal *signal = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
  455. @strongify(self);
  456. /// 获取request
  457. NSError *serializationError = nil;
  458. NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
  459. if (serializationError) {
  460. #pragma clang diagnostic push
  461. #pragma clang diagnostic ignored "-Wgnu"
  462. dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
  463. [subscriber sendError:serializationError];
  464. });
  465. #pragma clang diagnostic pop
  466. return [RACDisposable disposableWithBlock:^{
  467. }];
  468. }
  469. __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
  470. if (error) {
  471. NSError *parseError = [self _errorFromRequestWithTask:task httpResponse:(NSHTTPURLResponse *)response responseObject:responseObject error:error];
  472. [self HTTPRequestLog:task body:parameters error:parseError];
  473. [subscriber sendError:parseError];
  474. } else {
  475. /// 断言
  476. NSAssert([responseObject isKindOfClass:NSDictionary.class], @"responseObject is not an NSDictionary: %@", responseObject);
  477. /// 在这里判断数据是否正确
  478. /// 判断
  479. NSInteger statusCode = [responseObject[RQHTTPServiceResponseCodeKey] integerValue];
  480. if (statusCode == RQHTTPResponseCodeSuccess) {
  481. /// 打包成元祖 回调数据
  482. [subscriber sendNext:RACTuplePack(response , responseObject)];
  483. [subscriber sendCompleted];
  484. }else{
  485. if (statusCode == RQHTTPResponseCodeNotLogin && ![RQControllerHelper.currentViewController isKindOfClass:[RQLoginViewController class]]) {
  486. RACSignal *signalA = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  487. /// 删除账号
  488. [SAMKeychain deleteRawLogin];
  489. /// 先退出用户
  490. [RQ_USER_MANAGER logoutUser];
  491. [subscriber sendNext:@1];
  492. [subscriber sendCompleted];
  493. return nil;
  494. }] delay:1] deliverOnMainThread];
  495. RACSignal *signalB = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
  496. /// 这里切换 主页面
  497. [RQNotificationCenter postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogout)}];
  498. [subscriber sendNext:@2];
  499. return nil;
  500. }] delay:1] deliverOnMainThread];
  501. // 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。
  502. RACSignal *concatSignal = [signalA concat:signalB];
  503. // 以后只需要面对拼接信号开发。
  504. // 订阅拼接的信号,不需要单独订阅signalA,signalB
  505. // 内部会自动订阅。
  506. // 注意:第一个信号必须发送完成,第二个信号才会被激活
  507. [concatSignal subscribeNext:^(id x) {
  508. NSLog(@"%@",x);
  509. if ([x integerValue] == 2) {
  510. RQ_USER_MANAGER.isShouldLogin;
  511. }
  512. }];
  513. /// 需要登录
  514. // [self login:^{
  515. // /// 这里需要重新配置序列化
  516. // self.requestSerializer = [self _requestSerializerWithRequest:[RQHTTPRequest requestWithParameters:[RQURLParameters urlParametersWithMethod:@"POST" path:path parameters:parameters]]];
  517. // /// 重新发起请求
  518. // [self enqueueUploadRequestWithPath:path parameters:parameters constructingBodyWithBlock:block];
  519. // } cancel:^{
  520. // NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  521. // userInfo[RQHTTPServiceErrorResponseCodeKey] = @(statusCode);
  522. // NSString *msgTips = responseObject[RQHTTPServiceResponseMsgKey];
  523. //#if defined(DEBUG)||defined(_DEBUG)
  524. // msgTips = RQStringIsNotEmpty(msgTips)?[NSString stringWithFormat:@"%@(%zd)",msgTips,statusCode]:[NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode]; /// 调试模式
  525. //#else
  526. // msgTips = RQStringIsNotEmpty(msgTips)?msgTips:@"服务器出错了,请稍后重试~"; /// 发布模式
  527. //#endif
  528. // userInfo[RQHTTPServiceErrorMessagesKey] = msgTips;
  529. // if (task.currentRequest.URL != nil) userInfo[RQHTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;
  530. // if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;
  531. // [subscriber sendError:[NSError errorWithDomain:RQHTTPServiceErrorDomain code:statusCode userInfo:userInfo]];
  532. // }];
  533. }else{
  534. NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  535. userInfo[RQHTTPServiceErrorResponseCodeKey] = @(statusCode);
  536. NSString *msgTips = responseObject[RQHTTPServiceResponseMsgKey];
  537. #if defined(DEBUG)||defined(_DEBUG)
  538. msgTips = RQStringIsNotEmpty(msgTips)?[NSString stringWithFormat:@"%@(%zd)",msgTips,statusCode]:[NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",statusCode]; /// 调试模式
  539. #else
  540. msgTips = RQStringIsNotEmpty(msgTips)?msgTips:@"服务器出错了,请稍后重试~"; /// 发布模式
  541. #endif
  542. userInfo[RQHTTPServiceErrorMessagesKey] = msgTips;
  543. if (task.currentRequest.URL != nil) userInfo[RQHTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;
  544. if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;
  545. [subscriber sendError:[NSError errorWithDomain:RQHTTPServiceErrorDomain code:statusCode userInfo:userInfo]];
  546. }
  547. }
  548. }
  549. }];
  550. [task resume];
  551. return [RACDisposable disposableWithBlock:^{
  552. [task cancel];
  553. }];
  554. }];
  555. /// replayLazily:replayLazily会在第一次订阅的时候才订阅sourceSignal
  556. /// 会提供所有的值给订阅者 replayLazily还是冷信号 避免了冷信号的副作用
  557. return [[signal
  558. replayLazily]
  559. setNameWithFormat:@"-enqueueUploadRequestWithPath: %@ parameters: %@", path, parameters];
  560. }
  561. #pragma mark Parsing (数据解析)
  562. - (NSError *)parsingErrorWithFailureReason:(NSString *)localizedFailureReason {
  563. NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  564. userInfo[NSLocalizedDescriptionKey] = NSLocalizedString(@"Could not parse the service response.", @"");
  565. if (localizedFailureReason != nil) userInfo[NSLocalizedFailureReasonErrorKey] = localizedFailureReason;
  566. return [NSError errorWithDomain:RQHTTPServiceErrorDomain code:RQHTTPServiceErrorJSONParsingFailed userInfo:userInfo];
  567. }
  568. /// 解析数据
  569. - (RACSignal *)parsedResponseOfClass:(Class)resultClass fromJSON:(NSDictionary *)responseObject {
  570. /// 必须是RQBaseModel的子类 且 最外层responseObject必须是字典
  571. NSParameterAssert((resultClass == nil || [resultClass isSubclassOfClass:RQBaseModel.class]));
  572. /// 这里主要解析的是 data:对应的数据
  573. if ([responseObject.allKeys containsObject:RQHTTPServiceResponseDataKey]) {
  574. responseObject = responseObject[RQHTTPServiceResponseDataKey];
  575. }
  576. /// 解析
  577. return [RACSignal createSignal:^ id (id<RACSubscriber> subscriber) {
  578. /// 解析字典
  579. void (^parseJSONDictionary)(NSDictionary *) = ^(NSDictionary *JSONDictionary) {
  580. if (resultClass == nil) {
  581. [subscriber sendNext:JSONDictionary];
  582. return;
  583. }
  584. /// 这里继续取出数据 data{"list":[]}
  585. NSArray * JSONArray = JSONDictionary[RQHTTPServiceResponseDataListKey];
  586. if ([JSONArray isKindOfClass:[NSArray class]]) {
  587. /// 字典数组 转对应的模型
  588. NSArray *parsedObjects = [NSArray yy_modelArrayWithClass:resultClass.class json:JSONArray];
  589. /// 这里还需要解析是否是RQObject的子类
  590. for (id parsedObject in parsedObjects) {
  591. /// 确保解析出来的类 也是 RQObject
  592. ((RQBaseModel *)parsedObject).total = [JSONDictionary[RQHTTPServiceResponseDataTotalKey] integerValue];
  593. NSAssert([parsedObject isKindOfClass:RQBaseModel.class], @"Parsed model object is not an RQObject: %@", parsedObject);
  594. }
  595. [subscriber sendNext:parsedObjects];
  596. }else{
  597. /// 字典转模型
  598. RQBaseModel *parsedObject = [resultClass yy_modelWithDictionary:JSONDictionary];
  599. if (parsedObject == nil) {
  600. // Don't treat "no class found" errors as real parsing failures.
  601. // In theory, this makes parsing code forward-compatible with
  602. // API additions.
  603. // 模型解析失败
  604. NSError *error = [NSError errorWithDomain:@"" code:2222 userInfo:@{}];
  605. [subscriber sendError:error];
  606. return;
  607. }
  608. /// 确保解析出来的类 也是 BaseModel
  609. NSAssert([parsedObject isKindOfClass:RQBaseModel.class], @"Parsed model object is not an BaseModel: %@", parsedObject);
  610. /// 发送数据
  611. [subscriber sendNext:parsedObject];
  612. }
  613. };
  614. if ([responseObject isKindOfClass:NSArray.class]) {
  615. if (resultClass == nil) {
  616. [subscriber sendNext:responseObject];
  617. }else{
  618. /// 数组 保证数组里面装的是同一种 NSDcitionary
  619. for (NSDictionary *JSONDictionary in responseObject) {
  620. if (![JSONDictionary isKindOfClass:NSDictionary.class]) {
  621. NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Invalid JSON array element: %@", @""), JSONDictionary];
  622. [subscriber sendError:[self parsingErrorWithFailureReason:failureReason]];
  623. return nil;
  624. }
  625. }
  626. /// 字典数组 转对应的模型
  627. NSArray *parsedObjects = [NSArray yy_modelArrayWithClass:resultClass.class json:responseObject];
  628. /// 这里还需要解析是否是RQObject的子类
  629. for (id parsedObject in parsedObjects) {
  630. /// 确保解析出来的类 也是 BaseModel
  631. NSAssert([parsedObject isKindOfClass:RQBaseModel.class], @"Parsed model object is not an BaseModel: %@", parsedObject);
  632. }
  633. [subscriber sendNext:parsedObjects];
  634. }
  635. [subscriber sendCompleted];
  636. } else if ([responseObject isKindOfClass:NSDictionary.class]) {
  637. /// 解析字典
  638. parseJSONDictionary(responseObject);
  639. [subscriber sendCompleted];
  640. } else if (responseObject == nil || [responseObject isKindOfClass:[NSNull class]]) {
  641. [subscriber sendNext:nil];
  642. [subscriber sendCompleted];
  643. } else if ([responseObject isKindOfClass:[NSString class]]) {
  644. /// RQ-MARK: 如果responseObject是NSString类型进入该条件
  645. [subscriber sendNext:responseObject];
  646. [subscriber sendCompleted];
  647. } else if ([responseObject isKindOfClass:[NSNumber class]]) {
  648. /// RQ-MARK: 如果responseObject是NSNumber类型进入该条件
  649. [subscriber sendNext:responseObject];
  650. [subscriber sendCompleted];
  651. } else {
  652. NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Response wasn't an array or dictionary (%@): %@", @""), [responseObject class], responseObject];
  653. [subscriber sendError:[self parsingErrorWithFailureReason:failureReason]];
  654. }
  655. return nil;
  656. }];
  657. }
  658. #pragma mark - Error Handling
  659. /// 请求错误解析
  660. - (NSError *)_errorFromRequestWithTask:(NSURLSessionTask *)task httpResponse:(NSHTTPURLResponse *)httpResponse responseObject:(NSDictionary *)responseObject error:(NSError *)error {
  661. /// 不一定有值,则HttpCode = 0;
  662. NSInteger HTTPCode = httpResponse.statusCode;
  663. NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
  664. /// default errorCode is RQHTTPServiceErrorConnectionFailed,意味着连接不上服务器
  665. NSInteger errorCode = RQHTTPServiceErrorConnectionFailed;
  666. NSString *errorDesc = @"服务器出错了,请稍后重试~";
  667. /// 其实这里需要处理后台数据错误,一般包在 responseObject
  668. /// HttpCode错误码解析 https://www.guhei.net/post/jb1153
  669. /// 1xx : 请求消息 [100 102]
  670. /// 2xx : 请求成功 [200 206]
  671. /// 3xx : 请求重定向[300 307]
  672. /// 4xx : 请求错误 [400 417] 、[422 426] 、449、451
  673. /// 5xx 、600: 服务器错误 [500 510] 、600
  674. NSInteger httpFirstCode = HTTPCode/100;
  675. if (httpFirstCode>0) {
  676. if (httpFirstCode==4) {
  677. /// 请求出错了,请稍后重试
  678. if (HTTPCode == 408) {
  679. #if defined(DEBUG)||defined(_DEBUG)
  680. errorDesc = @"请求超时,请稍后再试(408)~"; /// 调试模式
  681. #else
  682. errorDesc = @"请求超时,请稍后再试~"; /// 发布模式
  683. #endif
  684. }else{
  685. #if defined(DEBUG)||defined(_DEBUG)
  686. errorDesc = [NSString stringWithFormat:@"请求出错了,请稍后重试(%zd)~",HTTPCode]; /// 调试模式
  687. #else
  688. errorDesc = @"请求出错了,请稍后重试~"; /// 发布模式
  689. #endif
  690. }
  691. }else if (httpFirstCode == 5 || httpFirstCode == 6){
  692. /// 服务器出错了,请稍后重试
  693. #if defined(DEBUG)||defined(_DEBUG)
  694. errorDesc = [NSString stringWithFormat:@"服务器出错了,请稍后重试(%zd)~",HTTPCode]; /// 调试模式
  695. #else
  696. errorDesc = @"服务器出错了,请稍后重试~"; /// 发布模式
  697. #endif
  698. }else if (!self.reachabilityManager.isReachable){
  699. /// 网络不给力,请检查网络
  700. errorDesc = @"网络开小差了,请稍后重试~";
  701. }
  702. }else{
  703. if (!self.reachabilityManager.isReachable){
  704. /// 网络不给力,请检查网络
  705. errorDesc = @"网络开小差了,请稍后重试~";
  706. }
  707. }
  708. switch (HTTPCode) {
  709. case 400:{
  710. errorCode = RQHTTPServiceErrorBadRequest; /// 请求失败
  711. break;
  712. }
  713. case 403:{
  714. errorCode = RQHTTPServiceErrorRequestForbidden; /// 服务器拒绝请求
  715. break;
  716. }
  717. case 422:{
  718. errorCode = RQHTTPServiceErrorServiceRequestFailed; /// 请求出错
  719. break;
  720. }
  721. default:
  722. /// 从error中解析
  723. if ([error.domain isEqual:NSURLErrorDomain]) {
  724. #if defined(DEBUG)||defined(_DEBUG)
  725. errorDesc = [NSString stringWithFormat:@"请求出错了,请稍后重试(%zd)~",error.code]; /// 调试模式
  726. #else
  727. errorDesc = @"请求出错了,请稍后重试~"; /// 发布模式
  728. #endif
  729. switch (error.code) {
  730. case NSURLErrorSecureConnectionFailed:
  731. case NSURLErrorServerCertificateHasBadDate:
  732. case NSURLErrorServerCertificateHasUnknownRoot:
  733. case NSURLErrorServerCertificateUntrusted:
  734. case NSURLErrorServerCertificateNotYetValid:
  735. case NSURLErrorClientCertificateRejected:
  736. case NSURLErrorClientCertificateRequired:
  737. errorCode = RQHTTPServiceErrorSecureConnectionFailed; /// 建立安全连接出错了
  738. break;
  739. case NSURLErrorTimedOut:{
  740. #if defined(DEBUG)||defined(_DEBUG)
  741. errorDesc = @"请求超时,请稍后再试(-1001)~"; /// 调试模式
  742. #else
  743. errorDesc = @"请求超时,请稍后再试~"; /// 发布模式
  744. #endif
  745. break;
  746. }
  747. case NSURLErrorNotConnectedToInternet:{
  748. #if defined(DEBUG)||defined(_DEBUG)
  749. errorDesc = @"网络开小差了,请稍后重试(-1009)~"; /// 调试模式
  750. #else
  751. errorDesc = @"网络开小差了,请稍后重试~"; /// 发布模式
  752. #endif
  753. break;
  754. }
  755. }
  756. }
  757. }
  758. userInfo[RQHTTPServiceErrorHTTPStatusCodeKey] = @(HTTPCode);
  759. userInfo[RQHTTPServiceErrorDescriptionKey] = errorDesc;
  760. if (task.currentRequest.URL != nil) userInfo[RQHTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;
  761. if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;
  762. return [NSError errorWithDomain:RQHTTPServiceErrorDomain code:errorCode userInfo:userInfo];
  763. }
  764. #pragma mark - 打印请求日志
  765. - (void)HTTPRequestLog:(NSURLSessionTask *)task body:params error:(NSError *)error {
  766. NSLog(@">>>>>>>>>>>>>>>>>>>>>👇 REQUEST FINISH 👇>>>>>>>>>>>>>>>>>>>>>>>>>>");
  767. NSLog(@"Request%@=======>:%@", error?@"失败":@"成功", task.currentRequest.URL.absoluteString);
  768. NSLog(@"requestBody======>:%@", params);
  769. NSLog(@"requstHeader=====>:%@", task.currentRequest.allHTTPHeaderFields);
  770. NSLog(@"response=========>:%@", task.response);
  771. NSLog(@"error============>:%@", error);
  772. NSLog(@"<<<<<<<<<<<<<<<<<<<<<👆 REQUEST FINISH 👆<<<<<<<<<<<<<<<<<<<<<<<<<<");
  773. }
  774. #pragma mark - Parameter 签名 MD5 生成一个 sign ,这里请根据实际项目来定
  775. /// 基础的请求参数
  776. -(NSMutableDictionary *)_parametersWithRequest:(RQHTTPRequest *)request{
  777. NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
  778. /// 模型转字典
  779. NSDictionary *extendsUrlParams = [request.urlParameters.extendsParameters mj_keyValues].copy;
  780. if ([extendsUrlParams count]) {
  781. [parameters addEntriesFromDictionary:extendsUrlParams];
  782. }
  783. if ([request.urlParameters.parameters count]) {
  784. [parameters addEntriesFromDictionary:request.urlParameters.parameters];
  785. }
  786. return parameters;
  787. }
  788. /// 带签名的请求参数
  789. - (NSString *)_signWithParameters:(NSDictionary *) parameters {
  790. /// 按照ASCII码排序
  791. NSArray *sortedKeys = [[parameters allKeys] sortedArrayUsingSelector:@selector(compare:)];
  792. NSMutableArray *kvs = [NSMutableArray array];
  793. for (id key in sortedKeys) {
  794. /// value 为 empty 跳过
  795. if(RQObjectIsNil(parameters[key])) continue;
  796. NSString * value = [parameters[key] rq_stringValueExtension];
  797. // if (RQObjectIsNil(value)||!RQStringIsNotEmpty(value)) continue;
  798. value = [value rq_removeBothEndsWhitespaceAndNewline];
  799. // value = [value rq_URLEncoding];
  800. [kvs addObject:[NSString stringWithFormat:@"%@=%@",key,value]];
  801. }
  802. NSString *paramString = [kvs componentsJoinedByString:@"&"];
  803. /// 拼接私钥
  804. // NSString *keyValue = RQHTTPServiceKeyValue;
  805. // NSString *signedString = [NSString stringWithFormat:@"%@&%@=%@",paramString,RQHTTPServiceKey,keyValue];
  806. /// 拼接时间戳
  807. NSString *ts = [NSString stringWithFormat:@"%.f", [NSDate date].timeIntervalSince1970 * 1000];
  808. NSString *sign = [NSString stringWithFormat:@"%@&key=%@",paramString ,ts];
  809. /// md5
  810. sign = [CocoaSecurity md5:sign].hex;
  811. NSString *signedStr = [NSString stringWithFormat:@"ts=%@&sign=%@&user=ios&v=jsjp",ts ,sign];
  812. return signedStr;
  813. }
  814. /// 序列化
  815. - (AFHTTPRequestSerializer *)_requestSerializerWithRequest:(RQHTTPRequest *) request {
  816. /// 获取基础参数(参数+拓展参数)
  817. NSMutableDictionary *parameters = [self _parametersWithRequest:request];
  818. /// 获取带签名的参数
  819. NSString *sign = [self _signWithParameters:parameters];
  820. /// 赋值
  821. parameters[RQHTTPServiceSignKey] = [sign length]?sign:@"";
  822. /// 请求序列化
  823. AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
  824. /// 配置请求头
  825. for (NSString *key in parameters) {
  826. NSString *value = [[parameters[key] rq_stringValueExtension] copy];
  827. if (value.length==0) continue;
  828. /// value只能是字符串,否则崩溃
  829. [requestSerializer setValue:value forHTTPHeaderField:key];
  830. }
  831. return requestSerializer;
  832. }
  833. - (AFJSONRequestSerializer *)_requestJSONSerializerWithRequest:(RQHTTPRequest *) request {
  834. /// 获取基础参数(参数+拓展参数)
  835. NSMutableDictionary *parameters = [self _parametersWithRequest:request];
  836. /// 获取带签名的参数
  837. NSString *sign = [self _signWithParameters:parameters];
  838. /// 赋值
  839. parameters[RQHTTPServiceSignKey] = [sign length]?sign:@"";
  840. /// 请求序列化
  841. AFJSONRequestSerializer *requestSerializer = [AFJSONRequestSerializer serializer];
  842. /// 配置请求头
  843. for (NSString *key in parameters) {
  844. NSString *value = [[parameters[key] rq_stringValueExtension] copy];
  845. if (value.length==0) continue;
  846. /// value只能是字符串,否则崩溃
  847. [requestSerializer setValue:value forHTTPHeaderField:key];
  848. }
  849. return requestSerializer;
  850. }
  851. - (AFHTTPRequestSerializer *)_requestRawSerializerWithRequest:(RQHTTPRequest *) request {
  852. /// 获取基础参数(参数+拓展参数)
  853. NSMutableDictionary *parameters = [self _parametersWithRequest:request];
  854. /// 获取带签名的参数
  855. NSString *sign = [self _signWithParameters:parameters];
  856. /// 赋值
  857. parameters[RQHTTPServiceSignKey] = [sign length]?sign:@"";
  858. /// 请求序列化
  859. AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
  860. /// 配置请求头
  861. for (NSString *key in parameters) {
  862. NSString *value = [[parameters[key] rq_stringValueExtension] copy];
  863. if (value.length==0) continue;
  864. /// value只能是字符串,否则崩溃
  865. [requestSerializer setValue:value forHTTPHeaderField:key];
  866. }
  867. return requestSerializer;
  868. }
  869. #pragma mark - LoginMethod
  870. - (void)wechatOnRespNotification {
  871. /// 监听微信回调的通知
  872. [[[RQNotificationCenter rac_addObserverForName:RQWeChatOnRespNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSNotification * note) {
  873. [MBProgressHUD rq_showProgressHUD:@"正在登录..." addedToView:RQControllerHelper.currentViewController.view];
  874. [[RQ_HTTP_Service studentThirdLoginWithAuthorizationCode:note.object] subscribeNext:^(RQThirdLoginModel *thirdLoginModel) {
  875. [MBProgressHUD rq_hideHUD];
  876. /// 存储用户数据
  877. [MBProgressHUD rq_showTips:@"登录成功"];
  878. RQUserModel *userModel = [[RQUserModel alloc] init];
  879. userModel.channel = RQUserLoginChannelTypeWeChatId;
  880. userModel.token = thirdLoginModel.token;
  881. userModel.thirdResult = thirdLoginModel.thirdResult;
  882. // userModel.wechatUserInfoModel = wechatUserInfoModel;
  883. [RQ_USER_MANAGER loginUser:userModel];
  884. /// 切换更控制器
  885. dispatch_async(dispatch_get_main_queue(), ^{
  886. /// 发通知
  887. [[NSNotificationCenter defaultCenter] postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogin)}];
  888. });
  889. // [[RQ_HTTP_Service wechatGetUserInfoWithAccess_token:thirdLoginModel.thirdResult.access_token openid:thirdLoginModel.thirdResult.openid lang:@"c"] subscribeNext:^(RQWechatUserInfoModel *wechatUserInfoModel) {
  890. // [MBProgressHUD rq_hideHUD];
  891. // /// 存储用户数据
  892. // [MBProgressHUD rq_showTips:@"登录成功"];
  893. // RQUserModel *userModel = [[RQUserModel alloc] init];
  894. // userModel.channel = RQUserLoginChannelTypeWeChatId;
  895. // userModel.token = thirdLoginModel.token;
  896. // userModel.thirdResult = thirdLoginModel.thirdResult;
  897. // userModel.wechatUserInfoModel = wechatUserInfoModel;
  898. // [RQ_USER_MANAGER loginUser:userModel];
  899. // /// 切换更控制器
  900. // dispatch_async(dispatch_get_main_queue(), ^{
  901. // /// 发通知
  902. // [[NSNotificationCenter defaultCenter] postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogin)}];
  903. // });
  904. // }];
  905. } error:^(NSError * _Nullable error) {
  906. [MBProgressHUD rq_hideHUD];
  907. [MBProgressHUD rq_showErrorTips:error];
  908. }];
  909. }];
  910. }
  911. /// studentDouYinThirdLoginWithAuthorizationCode
  912. - (void)douYinOnRespNotification {
  913. /// 监听抖音回调的通知
  914. [[[RQNotificationCenter rac_addObserverForName:RQDouYinOnRespNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSNotification * note) {
  915. [MBProgressHUD rq_showProgressHUD:@"正在登录..." addedToView:RQControllerHelper.currentViewController.view];
  916. [[RQ_HTTP_Service studentDouYinThirdLoginWithAuthorizationCode:note.object] subscribeNext:^(RQThirdLoginModel *thirdLoginModel) {
  917. [MBProgressHUD rq_hideHUD];
  918. /// 存储用户数据
  919. [MBProgressHUD rq_showTips:@"登录成功"];
  920. RQUserModel *userModel = [[RQUserModel alloc] init];
  921. userModel.channel = RQUserLoginChannelTypeDouYin;
  922. userModel.token = thirdLoginModel.token;
  923. userModel.thirdResult = thirdLoginModel.thirdResult;
  924. [RQ_USER_MANAGER loginUser:userModel];
  925. /// 切换更控制器
  926. dispatch_async(dispatch_get_main_queue(), ^{
  927. /// 发通知
  928. [[NSNotificationCenter defaultCenter] postNotificationName:RQSwitchRootViewControllerNotification object:nil userInfo:@{RQSwitchRootViewControllerUserInfoKey:@(RQSwitchRootViewControllerFromTypeLogin)}];
  929. });
  930. } error:^(NSError * _Nullable error) {
  931. [MBProgressHUD rq_showErrorTips:error];
  932. }];
  933. }];
  934. }
  935. /// 获取网络权限
  936. - (void)networkAuthStatus {
  937. CTCellularData *cellularData = [[CTCellularData alloc]init];
  938. cellularData.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state) {
  939. if (state == kCTCellularDataRestricted) {
  940. //拒绝
  941. [self networkSettingAlert];
  942. } else if (state == kCTCellularDataNotRestricted) {
  943. //允许
  944. } else {
  945. //未知
  946. [self unknownNetwork];
  947. }
  948. };
  949. }
  950. - (void)networkSettingAlert {
  951. dispatch_async(dispatch_get_main_queue(), ^{
  952. NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
  953. NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
  954. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:[NSString stringWithFormat:@"您尚未授权“%@”访问网络的权限,请前往设置开启网络授权", app_Name] preferredStyle:UIAlertControllerStyleAlert];
  955. [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
  956. _isShowNetWorkAuth = NO;
  957. }]];
  958. [alertController addAction:[UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  959. _isShowNetWorkAuth = NO;
  960. if (@available(iOS 10.0, *)) {
  961. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
  962. } else {
  963. // Fallback on earlier versions
  964. }
  965. }]];
  966. if (!_isShowNetWorkAuth) {
  967. _isShowNetWorkAuth = YES;
  968. [RQControllerHelper.topViewController presentViewController:alertController animated:YES completion:nil];
  969. }
  970. });
  971. }
  972. - (void)unknownNetwork {
  973. dispatch_async(dispatch_get_main_queue(), ^{
  974. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"未知网络" preferredStyle:UIAlertControllerStyleAlert];
  975. [alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  976. }]];
  977. [RQControllerHelper.topViewController presentViewController:alertController animated:YES completion:nil];
  978. });
  979. }
  980. @end