Как издеваться над вызовом AJAX с помощью NSURLProtocol?

У меня есть интерфейс UIWebview, который вызывает вызовы AJAX внешним службам. Когда в автономном режиме мне нужно поймать запросы тезисов и вернуть локальный json.

Я реализовал NSURLProtocol, и мне удалось поймать запрос AJAX, проблема в jquery всегда возвращает код ошибки 0:

$.ajax({ url: url, dataType: 'json', contentType: "application/json", success: function(jsonData){ alert("success :"); }, error: function (request, status, error) { alert("failure :" + request.status ); } 

});

Я всегда получаю request.status = 0

Чтобы проверить мой протокол, я попытался высмеять изображение внутри своего html, и он отлично работает.

  • HTML-запрос на изображение из google.fr => отлично работает
  • AJAX вызов json на amazon => не удается

Вот моя полная реализация:

 #import "EpubProtocol.h" @implementation EpubProtocol #pragma mark - NSURLProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { BOOL awsRequest = [self request:request contains:@"s3.amazonaws.com"]; BOOL imgRequest = [self request:request contains:@"google.fr"]; BOOL match = awsRequest || imgRequest; return match; } + (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest { return theRequest; } - (void)startLoading { NSURLRequest *request = [self request]; //Mock Amazon call if([EpubProtocol request:request contains:@"s3.amazonaws.com"]) { NSString *path = [[NSBundle bundleForClass:self.class] pathForResource:@"epub1" ofType:@"json"]; NSData *data = [NSData dataWithContentsOfFile:path]; [self mockRequest:request mimeType:@"application/json" data:data]; } //Mock image call else if([EpubProtocol request:request contains:@"google.fr"]) { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.itespresso.fr/wp-content/gallery/yahoo/1-yahoo-logo.jpg"]] queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { [self mockRequest:request mimeType:@"image/jpeg" data:data]; }]; } } - (void)stopLoading { NSLog(@"Did stop loading"); } #pragma mark - Request utils + (BOOL) request:(NSURLRequest*)request contains:(NSString*)domain { NSString *str = [[request URL] absoluteString]; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", domain]; return [pred evaluateWithObject:str]; } #pragma mark - Mock responses -(void) mockRequest:(NSURLRequest*)request mimeType:(NSString*)mimeType data:(NSData*)data { id client = [self client]; NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[request URL] MIMEType:mimeType expectedContentLength:-1 textEncodingName:nil]; [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [client URLProtocol:self didLoadData:data]; [client URLProtocolDidFinishLoading:self]; } @end 

2 Solutions collect form web for “Как издеваться над вызовом AJAX с помощью NSURLProtocol?”

Проблема возникает из webkit, который блокирует ответ из-за запроса на перекрестный домен. Поскольку мы издеваемся над ответом, нам нужно заставить Access-Control-Allow-Origin.

Затем нам также необходимо принудительно ввести тип содержимого ответа.

Здесь происходит волшебство:

 NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"}; NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:headers]; 

Окончательная реализация протокола:

 #import "EpubProtocol.h" @implementation EpubProtocol #pragma mark - NSURLProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { BOOL isAwsRequest = [self request:request contains:@"s3.amazonaws.com"]; return isAwsRequest; } + (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest { return theRequest; } - (void)startLoading { NSURLRequest *request = [self request]; //Mock Amazon call if([EpubProtocol request:request contains:@"s3.amazonaws.com"]) { NSString *path = [[NSBundle bundleForClass:self.class] pathForResource:@"epub1" ofType:@"json"]; NSData *data = [NSData dataWithContentsOfFile:path]; [self mockRequest:request data:data]; } } - (void)stopLoading { NSLog(@"Did stop loading"); } #pragma mark - Request utils + (BOOL) request:(NSURLRequest*)request contains:(NSString*)domain { NSString *str = [[request URL] absoluteString]; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", domain]; return [pred evaluateWithObject:str]; } #pragma mark - Mock responses -(void) mockRequest:(NSURLRequest*)request data:(NSData*)data { id client = [self client]; NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"}; NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:headers]; [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [client URLProtocol:self didLoadData:data]; [client URLProtocolDidFinishLoading:self]; } @end 

Ничего особенного в JS:

 function loadJSONDoc() { var url = "https://s3.amazonaws.com/youboox_recette/epub.json"; $.ajax({ url: url, dataType: 'json', contentType: "application/json", success: function(jsonData){ alert('success'); document.getElementById("myDiv").innerHTML='<p>'+$.param(jsonData)+'</p>'; }, error: function (request, status, error) { alert("failure :" + request.status ); } }); } 

Некоторое время назад мне приходилось делать подобные вещи.

Сначала мне удалось найти код, который может заставить UIWebViewDelegate поймать вызов ajax, поэтому в моей части webapp у меня было:

 //code to extend XMLHttpRequest, and have ajax call available in uiwebviewdelegate. var s_ajaxListener = new Object(); s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; s_ajaxListener.callback = function () { window.location=this.url; }; XMLHttpRequest.prototype.open = function(a,b) { if (!a) var a=''; if (!b) var b=''; s_ajaxListener.tempOpen.apply(this, arguments); s_ajaxListener.method = a; s_ajaxListener.url = b; if (a.toLowerCase() == 'get') { s_ajaxListener.data = b.split('?'); s_ajaxListener.data = s_ajaxListener.data[1]; } } XMLHttpRequest.prototype.send = function(a,b) { if (!a) var a=''; if (!b) var b=''; s_ajaxListener.tempSend.apply(this, arguments); if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; s_ajaxListener.callback(); } 

Затем в iOS я возвращаю NO в UIWebViewDelegate shouldStartLoad (мое состояние было немного уродливым):

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if ([[[request URL] scheme] rangeOfString:@"https"].length > 0) { return NO; } return YES; } 

В верхней части этого я бы зарегистрировал мой протокол:

 [NSURLProtocol registerClass:[MyProtocol class]]; 

С реализацией StartLoad. Вы также должны иметь подкласс canInitWithRequest

 + (BOOL)canInitWithRequest:(NSURLRequest *)request { if ([request.URL.scheme rangeOfString:@"https"].length > 0) { return YES; } return NO; } 

Чтобы сообщить протоколу, что он должен использоваться для запроса.

И не забудьте отменить регистрацию, когда у вас есть сеть.

Если вы не хотите беспокоиться о внедрении NSURLProtocol, вы можете использовать мой собственный: https://github.com/bcharp/BOURLProtocol 😉

Надеюсь, поможет !

  • Объективные представления предварительной загрузки iOS
  • Как открыть UIWebview и воспроизвести видео в полноэкранном режиме и заставить пейзаж?
  • Как автовоспроизведение видео YouTube в интерфейсе UIWebView
  • Как вызвать функцию JavaScript в объекте C
  • Приложение получает предупреждения о памяти и сбои при загрузке HTML-файла со многими видеороликами YouTube в UIWebView
  • webview не работает в объективе c
  • Неверный размер встроенного видео YouTube
  • UIWebView не загружает ответную веб-страницу правильно
  • UIWebView и определить словарь
  • iPhone - Автоматическое изменение размера содержимого UIWebView не соответствует рамке
  • Безопасная приостановка / возобновление удаленных UIWebView WebSockets при входе приложения в фоновое / активное состояние
  • Interesting Posts

    xcode 4 – невозможно построить, потому что конструктор интерфейса не смог открыть файл

    Google Maps iOS rightCalloutAccessoryView замена?

    Использовать основные данные или нет?

    Нарушен UICollectionView.backgroundView

    Как определить режим редактирования на iPhone UITableView

    Угловая форма модального вида на iPad в ios: квадратная или закругленная?

    Запустите сценарий оболочки перед сборкой в ​​Xcode

    Почему view.layer.renderInContext () занимает более высокий объем временной памяти для снимков с одинаковым размером

    Размер фонового изображения Sprite Kit Game

    Swift – UITableView сделалSelectRowAtIndexPath & didDeselectRowAtIndexPath Добавить и удалить идентификаторы индекса

    Xcode Parse.com сохранить в csv / любой файл?

    Не удается установить приложение на устройстве 9.3.2 из Xcode 7.3.1

    XCode 6.1 Отсутствует требуемая архитектура X86_64 в файле

    custom selectedBackgroundView исходящий в UITableView Style Grouped

    Пакет документов приложений iOS

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.