Как перехватить сетевые вызовы (REST) в iOS с помощью NSURLProtocol
Мне нужно перехватить сетевой вызов, который клиент выполнит в приложении, пока вызов будет успешно завершен. Я обнаружил, что решение реализует абстрактный класс NSURLProtocol и регистрируется в приложении.
Это, казалось, решило мои проблемы, но затем я ударился о стену, запросил тайм-аут. Я использую AFNetworking последней версии 1.x, потому что мне нужно поддерживать iOS 5.0.
Поэтому теперь мне нужно найти, как продлить время ожидания первоначального запроса, или найти другое более подходящее решение моей проблемы.
Вот что я сделал. Реализация NSURLProtocol:
@implementation SLKURLProtocol
+ (NSURLRequest*) canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
+ (BOOL) canInitWithRequest:(NSURLRequest *)request
{
return [[[request URL] scheme] isEqualToString:@"http"];
}
- (void) startLoading
{
dispatch_async(kBgQueue,
^{
NSLog(@"Intercept Request startLoading");
NSURLRequest* request = self.request;
NSLog(@"URL: %@", request.URL);
NSLog(@"HTTP Method: %@", request.HTTPMethod);
NSLog(@"Data: %@", [NSString stringWithUTF8String:[request.HTTPBody bytes]]);
});
}
- (void) stopLoading
{
dispatch_async(kBgQueue,
^{
NSLog(@"Intercept Request stopLoading");
});
}
@end
Сетевой ViewController:
@implementation SLKViewController
- (void) viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[NSURLProtocol registerClass:[SLKURLProtocol class]];
[self initRequest];
}
- (void) initRequest
{
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://requestb.in/19kcum21"]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
[urlRequest setHTTPMethod:@"POST"];
NSMutableData* postData = [NSMutableData data];
[postData appendData:[@"REQUEST AFNETWORKING" dataUsingEncoding:NSUTF8StringEncoding]];
[urlRequest setHTTPBody:postData];
AFHTTPRequestOperation* operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
[operation setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString* serverResponse = [operation responseString];
NSLog(@"AFNetworking Response: %@", serverResponse);
} failure:
^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"AFNetworking Error: %@", error.description);
}];
[operation start];
}
@end
Вот вывод журнала:
2014-01-15 17: 07: 19.518 InterceptionHttp [510: 1303] Запрос на перехват startLoading 2014-01-15 17: 07: 19.520 InterceptionHttp [510: 1303] URL: http://requestb.in/19kcum21 2014-01- 15 17: 07: 19.521 InterceptionHttp [510: 1303] HTTP-метод: POST 2014-01-15 17:07:19.522 InterceptionHttp[510:1303] Данные: REQUEST AFNETWORKING 2014-01-15 17:07:29.522 InterceptionHttp[510:400b] Запрос на перехват stopLoading 2014-01-15 17:07:29.522 InterceptionHttp[510:70b] Ошибка сети AF: ошибка Domain=NSURLErrorDomain Code=-1001 "Время ожидания истекло". UserInfo = 0x8a5cb10 {NSErrorFailingURLStringKey = http://requestb.in/19kcum21, NSErrorFailingURLKey = http://requestb.in/19kcum21, NSLocalizedDescription = Время запроса истекло. Время запроса NSUnderlyingError=0x8c5 NS5
РЕДАКТИРОВАТЬ:
После ответа jqyao и прочтения статьи я изучил некоторые темы о создании подклассов NSURLProtocol. Но, к сожалению, я все еще не могу перехватить HTTP, что означает, что я хочу, чтобы исходный запрос обычно продолжался.
Между тем, если я добавлю 3 строки, вызывающие селекторы делегатов URLProtocol, исходный запрос будет продолжен, но с ответом данных, а не ответа сервера.
Вот что я добавил в startLoading
метод.
[[self client] URLProtocol:self didReceiveResponse:[[NSURLResponse alloc] init] cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
Вот мой выходной журнал.
2014-02-04 17: 27: 22.253 InterceptionHttp [419: 3a03] Запрос на перехват startLoading 2014-02-04 17: 27: 22.254 InterceptionHttp [419: 3a03] URL: http://requestb.in/tsvc14ts 2014-02- 04 17: 27: 22.255 InterceptionHttp [419: 3a03] HTTP-метод: POST 2014-02-04 17:27:22.255 InterceptionHttp[419:3a03] Данные: { 'message': 'JSON_MESSAGE' } 2014-02-04 17:27:22.258 InterceptionHttp[419:70b] Ответ AFNetworking: { 'message': 'JSON_MESSAGE' } 2014-02-04 17:27:22.260 InterceptionHttp[419:1303] Запрос на перехват stopLoading
2 ответа
Хорошо, я позаимствовал некоторый код из этого действительно классного компонента отладки сети и данных https://github.com/square/PonyDebugger и выполнил работу очень хорошо и гладко.
Соответствующий класс - https://github.com/square/PonyDebugger/blob/master/ObjC/PonyDebugger/PDNetworkDomainController.m
Надеюсь, что это помогает другим людям, которые ищут что-то похожее.
Я предлагаю вам взглянуть на эту статью http://robnapier.net/offline-uiwebview-nsurlprotocol и реализацию https://github.com/rnapier/RNCachingURLProtocol. Как часто вы видите проблему тайм-аута?