QNHttpRegionRequest.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // QNHttpRequest.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2020/4/29.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNDefine.h"
  9. #import "QNLogUtil.h"
  10. #import "QNAsyncRun.h"
  11. #import "QNUploadRequestState.h"
  12. #import "QNHttpRegionRequest.h"
  13. #import "QNConfiguration.h"
  14. #import "QNUploadOption.h"
  15. #import "NSURLRequest+QNRequest.h"
  16. #import "QNUploadRequestMetrics.h"
  17. #import "QNResponseInfo.h"
  18. @interface QNHttpRegionRequest()
  19. @property(nonatomic, strong)QNConfiguration *config;
  20. @property(nonatomic, strong)QNUploadOption *uploadOption;
  21. @property(nonatomic, strong)QNUploadRequestInfo *requestInfo;
  22. @property(nonatomic, strong)QNUploadRequestState *requestState;
  23. @property(nonatomic, strong)QNUploadRegionRequestMetrics *requestMetrics;
  24. @property(nonatomic, strong)QNHttpSingleRequest *singleRequest;
  25. @property(nonatomic, strong)id <QNUploadServer> currentServer;
  26. @property(nonatomic, strong)id <QNUploadRegion> region;
  27. @end
  28. @implementation QNHttpRegionRequest
  29. - (instancetype)initWithConfig:(QNConfiguration *)config
  30. uploadOption:(QNUploadOption *)uploadOption
  31. token:(QNUpToken *)token
  32. region:(id <QNUploadRegion>)region
  33. requestInfo:(QNUploadRequestInfo *)requestInfo
  34. requestState:(QNUploadRequestState *)requestState {
  35. if (self = [super init]) {
  36. _config = config;
  37. _uploadOption = uploadOption;
  38. _region = region;
  39. _requestInfo = requestInfo;
  40. _requestState = requestState;
  41. _singleRequest = [[QNHttpSingleRequest alloc] initWithConfig:config
  42. uploadOption:uploadOption
  43. token:token
  44. requestInfo:requestInfo
  45. requestState:requestState];
  46. }
  47. return self;
  48. }
  49. - (void)get:(NSString *)action
  50. headers:(NSDictionary *)headers
  51. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  52. complete:(QNRegionRequestCompleteHandler)complete{
  53. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  54. [self performRequest:[self getNextServer:nil]
  55. action:action
  56. headers:headers
  57. method:@"GET"
  58. body:nil
  59. shouldRetry:shouldRetry
  60. progress:nil
  61. complete:complete];
  62. }
  63. - (void)post:(NSString *)action
  64. headers:(NSDictionary *)headers
  65. body:(NSData *)body
  66. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  67. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  68. complete:(QNRegionRequestCompleteHandler)complete{
  69. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  70. [self performRequest:[self getNextServer:nil]
  71. action:action
  72. headers:headers
  73. method:@"POST"
  74. body:body
  75. shouldRetry:shouldRetry
  76. progress:progress
  77. complete:complete];
  78. }
  79. - (void)put:(NSString *)action
  80. headers:(NSDictionary *)headers
  81. body:(NSData *)body
  82. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  83. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  84. complete:(QNRegionRequestCompleteHandler)complete{
  85. self.requestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:self.region];
  86. [self performRequest:[self getNextServer:nil]
  87. action:action
  88. headers:headers
  89. method:@"PUT"
  90. body:body
  91. shouldRetry:shouldRetry
  92. progress:progress
  93. complete:complete];
  94. }
  95. - (void)performRequest:(id <QNUploadServer>)server
  96. action:(NSString *)action
  97. headers:(NSDictionary *)headers
  98. method:(NSString *)method
  99. body:(NSData *)body
  100. shouldRetry:(BOOL(^)(QNResponseInfo *responseInfo, NSDictionary *response))shouldRetry
  101. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  102. complete:(QNRegionRequestCompleteHandler)complete{
  103. if (!server.host || server.host.length == 0) {
  104. QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"server error"];
  105. [self complete:responseInfo response:nil complete:complete];
  106. return;
  107. }
  108. NSString *serverHost = server.host;
  109. NSString *serverIP = server.ip;
  110. if (self.config.converter) {
  111. serverHost = self.config.converter(serverHost);
  112. serverIP = nil;
  113. }
  114. self.currentServer = server;
  115. BOOL toSkipDns = NO;
  116. NSString *scheme = self.config.useHttps ? @"https://" : @"http://";
  117. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  118. if (serverIP && serverIP.length > 0) {
  119. NSString *urlString = [NSString stringWithFormat:@"%@%@%@", scheme, serverIP, action ?: @""];
  120. request.URL = [NSURL URLWithString:urlString];
  121. request.qn_domain = serverHost;
  122. request.qn_ip = serverIP;
  123. toSkipDns = YES;
  124. } else {
  125. NSString *urlString = [NSString stringWithFormat:@"%@%@%@", scheme, serverHost, action ?: @""];
  126. request.URL = [NSURL URLWithString:urlString];
  127. request.qn_domain = serverHost;
  128. request.qn_ip = nil;
  129. toSkipDns = NO;
  130. }
  131. request.HTTPMethod = method;
  132. [request setAllHTTPHeaderFields:headers];
  133. [request setTimeoutInterval:self.config.timeoutInterval];
  134. request.HTTPBody = body;
  135. QNLogInfo(@"key:%@ url:%@", self.requestInfo.key, request.URL);
  136. QNLogInfo(@"key:%@ headers:%@", self.requestInfo.key, headers);
  137. kQNWeakSelf;
  138. [self.singleRequest request:request
  139. server:server
  140. shouldRetry:shouldRetry
  141. progress:progress
  142. complete:^(QNResponseInfo * _Nullable responseInfo, NSArray<QNUploadSingleRequestMetrics *> * _Nullable metrics, NSDictionary * _Nullable response) {
  143. kQNStrongSelf;
  144. [self.requestMetrics addMetricsList:metrics];
  145. if (shouldRetry(responseInfo, response)
  146. && self.config.allowBackupHost
  147. && responseInfo.couldRegionRetry) {
  148. id <QNUploadServer> newServer = [self getNextServer:responseInfo];
  149. if (newServer) {
  150. QNAsyncRunAfter(self.config.retryInterval, kQNBackgroundQueue, ^{
  151. [self performRequest:newServer
  152. action:action
  153. headers:headers
  154. method:method
  155. body:body
  156. shouldRetry:shouldRetry
  157. progress:progress
  158. complete:complete];
  159. });
  160. } else if (complete) {
  161. [self complete:responseInfo response:response complete:complete];
  162. }
  163. } else if (complete) {
  164. [self complete:responseInfo response:response complete:complete];
  165. }
  166. }];
  167. }
  168. - (void)complete:(QNResponseInfo *)responseInfo
  169. response:(NSDictionary *)response
  170. complete:(QNRegionRequestCompleteHandler)completionHandler {
  171. if (completionHandler) {
  172. completionHandler(responseInfo, self.requestMetrics, response);
  173. }
  174. self.singleRequest = nil;
  175. }
  176. //MARK: --
  177. - (id <QNUploadServer>)getNextServer:(QNResponseInfo *)responseInfo{
  178. if (responseInfo.isTlsError) {
  179. self.requestState.isUseOldServer = YES;
  180. }
  181. return [self.region getNextServer:[self.requestState copy] responseInfo:responseInfo freezeServer:self.currentServer];
  182. }
  183. @end