RQHTTPService.m 48 KB

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