iOS 에서 개발 한 NSURLProtocol 의 구 덩이 를 자세히 알 아 보 세 요.

6018 단어 iOSNSURLProtocol
NSURLProtocol
NSURLProtocol 은 애플 의 URL 로 딩 시스템(URL Loading System)의 행동 을 새롭게 정의 할 수 있 습 니 다.URL Loading System 에는 URL 요청 을 처리 하 는 데 사용 되 는 여러 가지 종류 가 있 습 니 다.예 를 들 어 NSURL,NSURLRequest,NSURLConnection 과 NSURLSession 등 입 니 다.URL Loading System 이 NSURLRequest 를 사용 하여 자원 을 가 져 올 때 NSURLProtocol 하위 클래스 의 인 스 턴 스 를 만 듭 니 다.NSURLProtocol 을 직접 예화 해 서 는 안 됩 니 다.NSURLProtocol 은 프로 토 콜 처럼 보이 지만 사실은 이것 은 클래스 이 며,이러한 하위 클래스 를 사용 해 야 하 며,등록 되 어야 합 니 다.
필드 사용
 UIWebView,NSURLConnection 또는 제3자 라 이브 러 리(AFNetworking,MKNetwork Kit 등)를 통 해 든 NSURLConnection 또는 NSURLSession 을 기반 으로 이 루어 지기 때문에 NSURLProtocol 을 통 해 사용자 정의 작업 을 할 수 있 습 니 다.
네트워크 요청
네트워크 요청 무시,로 컬 캐 시 사용사용자 정의 네트워크 요청 의 반환 결과전체 네트워크 요청 설정
 iOS 시스템 에서 URL Loading System 을 접 한 적 이 있 습 니 다.NSURLProtocol 은 이렇게 강력 합 니 다.응용 프로그램 에 있 는 거의 모든 네트워크 요청 을 차단 할 수 있 고 요청 헤드 를 수정 할 수 있 으 며 client 가 임의로 사용자 정의 한 데 이 터 를 되 돌려 줄 수 있 습 니 다.많은 네트워크 저장 소 는 이런 종 류 를 이용 한 것 이 라 고 합 니 다.
그럼 우선 NSURLProtocol 을 어떻게 사용 하 는 지 설명해 주세요.
1.NSURLProtocol 의 하위 클래스 정의
NSURLProtocol 계승 에서 우 리 는 실현 해 야 한다.
+(BOOL)canInitWithRequest:(NSURLRequest*)request,요청 을 차단 하 는 URL 규칙 정의
-(void)startLoading,차단 요청 에 대해 시스템 이 NSURLProtocol 대상 을 만 들 고 startLoading 방법 을 실행 하여 로드 요청 을 시작 합 니 다.
-(void)stopLoading,차단 요청 에 대해 NSURLProtocol 대상 이 불 러 오 는 것 을 중지 할 때 이 방법 을 사용 합 니 다.
+(NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request,선택 가능 한 방법,요청 헤더 수정 이 필요 한 요청 은 이 방법 에서 수정 합 니 다.
다음 코드 는 https 요청 을 차단 하 는 NSURLProtocol 하위 클래스 를 정의 하고 CFHttpMessage Ref 를 통 해 다시 요청 합 니 다.

@interface CFHttpMessageURLProtocol () <NSStreamDelegate> { 
  NSMutableURLRequest *curRequest; 
  NSRunLoop *curRunLoop; 
  NSInputStream *inputStream; 
} 
 
@end 
 
@implementation CFHttpMessageURLProtocol 
 
/** 
 *             
 * 
 * @param request       
 * 
 * @return   YES       ,  NO        
 */ 
+ (BOOL)canInitWithRequest:(NSURLRequest *)request { 
   
  /*       ,               ,        ,        ,       ,         */ 
  if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) { 
    return NO; 
  } 
   
  NSString *url = request.URL.absoluteString; 
   
  //   url https  ,       ,      
  if ([url hasPrefix:@"https"]) { 
    return YES; 
  } 
  return NO; 
} 
 
/** 
 *             ,         ,          
 */ 
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 
  return request; 
} 
 
/** 
 *     ,     ,       
 */ 
- (void)startLoading { 
  NSMutableURLRequest *request = [self.request mutableCopy]; 
  //           ,       
  [NSURLProtocol setProperty:@(YES) forKey:protocolKey inRequest:request]; 
  curRequest = request; 
  [self startRequest]; 
} 
 
/** 
 *      
 */ 
- (void)stopLoading { 
  if (inputStream.streamStatus == NSStreamStatusOpen) { 
    [inputStream removeFromRunLoop:curRunLoop forMode:NSRunLoopCommonModes]; 
    [inputStream setDelegate:nil]; 
    [inputStream close]; 
  } 
  [self.client URLProtocol:self didFailWithError:[[NSError alloc] initWithDomain:@"stop loading" code:-1 userInfo:nil]]; 
} 
상기 코드 중의 startRequest 방법 은 원본 요청 헤 더 를 복사 하여 CFHttpMessage Ref 를 사용 하여 다시 요청 하 는 것 입 니 다.이 부분 에 관 한 코드 는 본 글 의 내용 과 관계 가 크 지 않 기 때문에 여기 서 놓 지 않 습 니 다.관심 이 있 는 분 들 은 제 다음 블 로 그 를 참고 하 실 수 있 습 니 다.
2.네트워크 요청 전에 NSURLProtocol 등록

 //        NSURLProtocol 
[NSURLProtocol registerClass:[CFHttpMessageURLProtocol class]]; 
NSURLSession 의 요청 에 대해 NSURLProtocol 을 등록 하 는 방식 은 조금 다 르 며 NSURLSession Configuration 을 통 해 등 록 됩 니 다.

// NSURLSession   
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
NSArray *protocolArray = @[ [CFHttpMessageURLProtocol class] ]; 
configuration.protocolClasses = protocolArray; 
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]]; 
NSURLSessionTask *task = [session dataTaskWithRequest:_request]; 
[task resume]; 
3.NSURLProtocol 로그아웃 요청

[NSURLProtocol unregisterClass:[CFHttpMessageURLProtocol class]]; 
자,이제 NSURLProtocol 의 사용법 에 대해 알 아 보 셨 을 겁 니 다.다음은 NSURLProtocol 이 사용 하 는 과정 에서 만 날 수 있 는 구 덩이 를 설명 하고 자신 과 필요 한 친구 에 게 알림 을 남 깁 니 다.
1.위 에서 처음부터 말 했 듯 이 WebView 의 요청 에 대해 NSURLProtocol 은 아직 WKWebView 의 요청 을 차단 할 수 없고 UIWebview 만 차단 할 수 있 지만 후 자 는 App Store 가 심 사 를 통과 시 키 지 못 하 게 한 것 같다(난감 한 얼굴).
2.NSURLProtocol 은 NSURLSession 의 POST 요청 을 차단 할 때 Request 에 있 는 HTTPBody 를 가 져 오지 못 하 는 것 으로 보 입 니 다.이 는 이미 해외 게시판 에 올 라 온 것 같 지만 국내 에 서 는 아직 알려 지지 않 은 것 같 습 니 다.애플 의 공식 설명 에 따 르 면 Body 는 NSData 유형,즉 바 이 너 리 콘 텐 츠 일 수 있 고 크기 제한 이 없 기 때문에 성능 을 고려 하여아예 차단 할 때 는 복사 하지 않 는 다.이 문 제 를 해결 하기 위해 서 우 리 는 바디 데 이 터 를 Header 에 넣 을 수 있 습 니 다.그러나 Header 의 크기 는 제한 이 있 는 것 같 습 니 다.저 는 2M 을 시험 해 보 았 지만 문제 가 없 었 습 니 다.10M 이 넘 으 면 바로 Request timeout 을 했 습 니 다.또한 Body 데이터 가 바 이 너 리 데이터 일 때 이 방법 은 어 쩔 수 없습니다.Header 에 텍스트 데이터 가 있 기 때문에 다른 방안 은 NSDictionary 나 NSCache 로 요청 하지 않 은 Body 데 이 터 를 저장 하고 URL 을 key 로 하 는 것 입 니 다.마지막 방법 은 NSURLSession 을 사용 하지 말고 오래된 NSURLConnection 을 성실 하 게 사용 하 는 것 입 니 다.
3.NSURLProtocol 을 사용 할 때 두 가지 방법 으로 동기 화 네트워크 요청 을 보 낼 수 있 습 니 다.예 를 들 어 startLoading 은 시간 이 초 과 될 때 까지 인 스 턴 스 방법 이 있 는 스 레 드 가 runloop 을 시작 하지 않 았 기 때 문 입 니 다.NSURLConnection 같은 네트워크 요청 은 runloop 에 의존 해 야 하기 때문에 이 요청 은 보 낼 수 없 기 때문에 비동기 요청 을 사용 해 야 합 니 다.NSURLConnection/NSURRLSession 의 비동기 요청 스 레 드 가 runloop 을 시작 하도록 보장 합 니 다.
이상 은 제 가 지금 발견 한 구덩이 입 니 다.여러분 의 보충 을 환영 합 니 다.여러분 의 개발 에 도 도움 이 되 었 으 면 좋 겠 습 니 다.다행히 NSURLProtocol 은 대량 합병 에 대한 지원 이 괜 찮 았 습 니 다.그렇지 않 으 면 버 려 야 합 니 다.여러분 의 학습 에 도움 이 되 었 으 면 좋 겠 습 니 다.여러분 의 많은 응원 바 랍 니 다.

좋은 웹페이지 즐겨찾기