我有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中模拟一个图像,它的效果很好.
>从google.fr =>向图像发送HTML请求工作正常
> AJAX调用一个json on 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
解决方法
问题来自于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,success: function(jsonData){ alert('success'); document.getElementById("myDiv").innerHTML='<p>'+$.param(jsonData)+'</p>'; },error) { alert("failure :" + request.status ); } }); }