我有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 );
}
});
}