我有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 ); }
});
我总是收到一个请求。状态= 0
为了测试我的协议,我尝试在html中模拟图像,并且效果很好。
这是我的完整实现:
#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
问题来自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 ); } }); }