QNHttpResponseInfo.m 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // QNHttpResponseInfo.m
  3. // QiniuSDK
  4. //
  5. // Created by WorkSpace_Sun on 2020/4/19.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNHttpResponseInfo.h"
  9. #import "QNSystemTool.h"
  10. #import "QNUploadInfoCollector.h"
  11. #import "QNUserAgent.h"
  12. #import "QNVersion.h"
  13. #import "QNSessionManager.h"
  14. @interface QNHttpResponseInfo ()
  15. @property (nonatomic, strong) NSDictionary *responseBody;
  16. @end
  17. @implementation QNHttpResponseInfo
  18. + (QNHttpResponseInfo *)buildResponseInfoHost:(NSString *)host
  19. response:(NSHTTPURLResponse *)response
  20. body:(NSData *)body
  21. error:(NSError *)error
  22. sessionStatistics:(QNSessionStatistics *)sessionStatistics {
  23. return [[[self class] alloc] initWithResponseInfoHost:host response:response body:body error:error sessionStatistics:sessionStatistics];
  24. }
  25. - (instancetype)initWithResponseInfoHost:(NSString *)host
  26. response:(NSHTTPURLResponse *)response
  27. body:(NSData *)body
  28. error:(NSError *)error
  29. sessionStatistics:(QNSessionStatistics *)sessionStatistics {
  30. self = [super init];
  31. if (self) {
  32. _statusCode = QN_IntNotSet;
  33. _signalStrength = QN_IntNotSet;
  34. _proxyConnection = NO;
  35. _hasHttpResponse = NO;
  36. _host = host;
  37. _pid = [QNSystemTool getCurrentProcessID];
  38. _tid = [QNSystemTool getCurrentThreadID];
  39. _timeStamp = [[NSDate date] timeIntervalSince1970];
  40. _bytesSent = sessionStatistics.bytesSent;
  41. _bytesTotal = sessionStatistics.bytesTotal;
  42. _remoteIp = sessionStatistics.remoteIp;
  43. _port = sessionStatistics.port;
  44. _totalElapsedTime = sessionStatistics.totalElapsedTime;
  45. _dnsElapsedTime = sessionStatistics.dnsElapsedTime;
  46. _connectElapsedTime = sessionStatistics.connectElapsedTime;
  47. _tlsConnectElapsedTime = sessionStatistics.tlsConnectElapsedTime;
  48. _requestElapsedTime = sessionStatistics.requestElapsedTime;
  49. _waitElapsedTime = sessionStatistics.waitElapsedTime;
  50. _responseElapsedTime = sessionStatistics.responseElapsedTime;
  51. _proxyConnection = sessionStatistics.isProxyConnection;
  52. if (response) {
  53. _hasHttpResponse = YES;
  54. int statusCode = (int)[response statusCode];
  55. NSDictionary *headers = [response allHeaderFields];
  56. _statusCode = statusCode;
  57. _reqId = headers[@"X-Reqid"];
  58. _xlog = headers[@"X-Log"];
  59. _xvia = !headers[@"X-Via"] ? (!headers[@"X-Px"] ? headers[@"Fw-Via"] : headers[@"X-Px"]) : headers[@"X-Via"];
  60. if (statusCode != 200) {
  61. if (response.statusCode / 100 == 4) {
  62. _errorType = bad_request;
  63. } else {
  64. _errorType = response_error;
  65. }
  66. if (body == nil) {
  67. _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:nil];
  68. } else {
  69. NSError *tmp;
  70. NSDictionary *uInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
  71. if (tmp != nil) {
  72. // 出现错误时,如果信息是非UTF8编码会失败,返回nil
  73. NSString *str = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
  74. if (str == nil) {
  75. str = @"";
  76. }
  77. uInfo = @{ @"error" : str };
  78. }
  79. _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
  80. }
  81. } else if (body == nil || body.length == 0) {
  82. NSDictionary *uInfo = @{ @"error" : @"no response json" };
  83. _errorType = unknown_error;
  84. _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
  85. } else {
  86. NSError *tmp;
  87. NSDictionary *responseBody = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
  88. if (!error) {
  89. _responseBody = responseBody;
  90. } else {
  91. NSDictionary *uInfo = @{ @"error" : @"JSON serialization failed" };
  92. _errorType = parse_error;
  93. _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
  94. }
  95. }
  96. } else {
  97. _hasHttpResponse = NO;
  98. if (error) {
  99. _error = error;
  100. _statusCode = (int)error.code;
  101. _errorDescription = _error.localizedDescription;
  102. if (self.isProxyConnection) {
  103. _errorType = proxy_error;
  104. } else {
  105. if (error.code == -1 || error.code == -1009) {
  106. _errorType = network_error;
  107. } else if (error.code == -1001) {
  108. _errorType = network_timeout;
  109. } else if (error.code == -1003 || error.code == -1006) {
  110. _errorType = unknown_host;
  111. } else if (error.code == -1004) {
  112. _errorType = cannot_connect_to_host;
  113. } else if (error.code == -1005 || error.code == -1011) {
  114. _errorType = transmission_error;
  115. } else if (error.code > -2001 && error.code < -1199) {
  116. _errorType = ssl_error;
  117. } else if (error.code == -1007 || error.code == -1010) {
  118. _errorType = malicious_response;
  119. } else if (error.code == -1015 || error.code == -1016 || error.code == -1017) {
  120. _errorType = parse_error;
  121. } else if (error.code == -999) {
  122. _errorType = user_canceled;
  123. } else if (error.code == 100) {
  124. _errorType = protocol_error;
  125. } else {
  126. _errorType = unknown_error;
  127. }
  128. }
  129. }
  130. }
  131. }
  132. return self;
  133. }
  134. - (BOOL)isOK {
  135. return _statusCode == 200 && _error == nil && _reqId != nil;
  136. }
  137. - (BOOL)couldRetry {
  138. return (_statusCode >= 500 && _statusCode < 600 && _statusCode != 579) || _statusCode == 996 || _statusCode == 406 || (_statusCode == 200 && _error != nil) || _statusCode < -1000 || self.isNotQiniu;
  139. }
  140. - (BOOL)isNotQiniu {
  141. return (_statusCode >= 200 && _statusCode < 500) && _reqId == nil;
  142. }
  143. - (NSDictionary *)getResponseBody {
  144. return self.isOK ? self.responseBody : nil;
  145. }
  146. - (int64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
  147. if (!startDate || !endDate) return 0;
  148. NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
  149. return interval * 1000;
  150. }
  151. - (NSString *)description {
  152. return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %lld, requestId: %@, xlog: %@, xvia: %@, host: %@ duration: %.3f s time: %llu error: %@>", NSStringFromClass([self class]), [QNUserAgent sharedInstance].id, kQiniuVersion, _statusCode, _reqId, _xlog, _xvia, _host, _totalElapsedTime / 1000.0, _timeStamp, _error];
  153. }
  154. @end