如何模拟AJAX调用NSURLProtocol? [英] How to mock AJAX call with NSURLProtocol?
问题描述
我的UIWebView这使得AJAX调用外部服务。当离线我需要赶论文请求并返回本地JSON。
我实现了一个NSURLProtocol,我设法抓住了AJAX请求,问题是jQuery的总是返回一个0错误code:
$。阿贾克斯({
网址:网址,
数据类型:JSON,
的contentType:应用/ JSON
成功:函数(jsonData){
警报(成功);
},
错误:函数(请求,状态,错误){
警报(失败:+ request.status);
}
});
我总是得到request.status = 0
要测试我的协议,我试图模拟图像我的HTML里面,它的伟大工程。
- HTML请求从google.fr => 正常工作 图像
- 在AJAX亚马逊=调用一个JSON> 失败
下面是我的全面实施:
#进口EpubProtocol.h
@implementation EpubProtocol
的#pragma马克 - NSURLProtocol
+(BOOL)canInitWithRequest:(的NSURLRequest *)请求{
BOOL awsRequest = [自我请求:请求包含:@s3.amazonaws.com];
BOOL imgRequest = [自我请求:请求包含:@Google.fr的]。
BOOL匹配= awsRequest || imgRequest;
返回匹配;
}
+(的NSURLRequest *)canonicalRequestForRequest:(的NSURLRequest *)theRequest
{
返回theRequest;
}
- (无效)startLoading {
的NSURLRequest *请求= [自我要求]
//模拟亚马逊通话
如果([EpubProtocol请求:请求包含:@s3.amazonaws.com]){
的NSString *路径= [[一个NSBundle bundleForClass:self.class] pathForResource:@epub1ofType:@JSON];
的NSData *数据= [NSData的dataWithContentsOfFile:路径]。
[自mockRequest:请求MIMETYPE:@应用程序/ JSON数据:数据]
}
//模拟图像调用
否则,如果([EpubProtocol请求:请求包含:@Google.fr的]){
NSOperationQueue *队列= [[NSOperationQueue页头]初始化];
[NSURLConnection的sendAsynchronousRequest:[的NSURLRequest requestWithURL:[NSURL URLWithString:@HTTP://www.ites$p$psso.fr/wp-content/gallery/yahoo/1-yahoo-logo.jpg]]队列:队列completionHandler :^(NSURLResponse *响应的NSData *数据,NSError *错误){
[自mockRequest:请求MIMETYPE:@为image / jpeg的数据:数据]
}];
}
}
- (无效)stopLoading
{
的NSLog(@难道停止加载);
}
的#pragma马克 - 请求utils的
+(BOOL)要求:(的NSURLRequest *)请求包含:(的NSString *)域{
的NSString *海峡= [[请求URL] absoluteString]。
NS predicate * preD = NS predicate predicateWithFormat:@自包含[CD]%@,域]。
返回[preD evaluateWithObject:STR]。
}
的#pragma马克 - 模拟响应
- (无效)mockRequest:(的NSURLRequest *)要求MIMETYPE:(的NSString *)MIMETYPE数据:(NSData的*)数据{
ID客户端= [自客户端]
NSHTTPURLResponse *响应= [[NSHTTPURLResponse页头] initWithURL:请求URL] MIMETYPE:MIMETYPE expectedContentLength:-1 textEncodingName:无]
[客户端URLProtocol:自didReceiveResponse:响应
cacheStoragePolicy:NSURLCacheStorageNotAllowed]。
[客户端URLProtocol:自didLoadData:数据]
[客户端URLProtocolDidFinishLoading:个体经营];
}
@结束
该问题来自WebKit的该块,因为跨域起源请求的响应。由于我们嘲笑的回应,我们必须强制访问控制 - 允许 - 产地。
然后,我们还需要强制内容类型的响应。
这里就是奇迹发生:
的NSDictionary *头= @ {@访问控制 - 允许 - 起源:@*,@访问控制 - 允许 - 头:@内容类型};
NSHTTPURLResponse *响应= [[NSHTTPURLResponse页头] initWithURL:request.URL状态code:200 HTTPVersion:@1.1headerFields:头]
该协议的最终实施:
#进口EpubProtocol.h
@implementation EpubProtocol
的#pragma马克 - NSURLProtocol
+(BOOL)canInitWithRequest:(的NSURLRequest *)请求{
BOOL isAwsRequest = [自我请求:请求包含:@s3.amazonaws.com];
返回isAwsRequest;
}
+(的NSURLRequest *)canonicalRequestForRequest:(的NSURLRequest *)theRequest
{
返回theRequest;
}
- (无效)startLoading {
的NSURLRequest *请求= [自我要求]
//模拟亚马逊通话
如果([EpubProtocol请求:请求包含:@s3.amazonaws.com]){
的NSString *路径= [[一个NSBundle bundleForClass:self.class] pathForResource:@epub1ofType:@JSON];
的NSData *数据= [NSData的dataWithContentsOfFile:路径]。
[自mockRequest:请求数据:数据]
}
}
- (无效)stopLoading
{
的NSLog(@难道停止加载);
}
的#pragma马克 - 请求utils的
+(BOOL)要求:(的NSURLRequest *)请求包含:(的NSString *)域{
的NSString *海峡= [[请求URL] absoluteString]。
NS predicate * preD = NS predicate predicateWithFormat:@自包含[CD]%@,域]。
返回[preD evaluateWithObject:STR]。
}
的#pragma马克 - 模拟响应
- (无效)mockRequest:(的NSURLRequest *)请求数据:(NSData的*)数据{
ID客户端= [自客户端]
的NSDictionary *头= @ {@访问控制 - 允许 - 起源:@*,@访问控制 - 允许 - 头:@内容类型};
NSHTTPURLResponse *响应= [[NSHTTPURLResponse页头] initWithURL:request.URL状态code:200 HTTPVersion:@1.1headerFields:头]
[客户端URLProtocol:自didReceiveResponse:响应
cacheStoragePolicy:NSURLCacheStorageNotAllowed]。
[客户端URLProtocol:自didLoadData:数据]
[客户端URLProtocolDidFinishLoading:个体经营];
}
@结束
没有什么特别的JS:
函数loadJSONDoc()
{
VAR URL =https://s3.amazonaws.com/youboox_recette/epub.json;
$阿贾克斯({
网址:网址,
数据类型:JSON,
的contentType:应用/ JSON
成功:函数(jsonData){
警报(成功);
的document.getElementById(myDiv)的innerHTML ='&其中p为H.;'+ $参数(jsonData)+'&所述; / P>';
},
错误:函数(请求,状态,错误){
警报(失败:+ request.status);
}
});
}
I have UIWebview that makes AJAX calls to external services. When offline i need to catch theses requests and return local json.
I implemented a NSURLProtocol and i manage to catch the AJAX request, the problem is jquery always return a 0 error code :
$.ajax({
url: url,
dataType: 'json',
contentType: "application/json",
success: function(jsonData){
alert("success :");
},
error: function (request, status, error) {
alert("failure :" + request.status );
}
});
I always get a request.status = 0
To test my protocol I tried to mock an image inside my html and it works great.
- HTML request to an image from google.fr => works fine
- AJAX call to a json on amazon => fails
Here is my full implementation :
#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
The problem comes from webkit which blocks the response because of cross domain origin request. Since we mock the response we have to force the Access-Control-Allow-Origin.
Then we also need to force the content-type of the response.
Here is where the magic happens :
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];
The final implementation of the protocol :
#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
Nothing special in the 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 );
}
});
}
这篇关于如何模拟AJAX调用NSURLProtocol?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!