UIWebView使用NSURLProtocol(拦截),aja

作者: Ylang | 来源:发表于2016-08-19 13:57 被阅读1184次

    问题:

    ajax跨域访问是一个老问题了,解决方法很多,比较常用的是JSONP方法,JSONP方法是一种非官方方法,而且这种方法只支持GET方式,不如POST方式安全。
    即使使用jquery的jsonp方法,type设为POST,也会自动变为GET。
    如果跨域使用POST方式,可以使用创建一个隐藏的iframe来实现,与ajax上传图片原理一样,但这样会比较麻烦。
    因此,通过设置Access-Control-Allow-Origin来实现跨域访问
    
    //
    //  JWURLProtocol.h
    //  NSURLProtocolExample
    //
    //  Created by yangjw on 16/8/19.
    //  Copyright © 2016年 lujb. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface JWURLProtocol : NSURLProtocol
    
    @end
    
    
    //
    //  JWURLProtocol.m
    //  NSURLProtocolExample
    //
    //  Created by yangjw on 16/8/19.
    //  Copyright © 2016年 lujb. All rights reserved.
    //
    
    #import "JWURLProtocol.h"
    
    static NSString * const JWURLProtocolHandledKey = @"JWURLProtocolHandledKey";
    
    @implementation JWURLProtocol
    
    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
        //只处理http和https请求
        NSString *scheme = [[request URL] scheme];
        if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
              [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame))
        {
            //看看是否已经处理过了,防止无限循环
            if ([NSURLProtocol propertyForKey:JWURLProtocolHandledKey inRequest:request]) {
                return NO;
            }
            
            return YES;
        }
        return NO;
    }
    
    + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
        /** 可以在此处添加头等信息  */
        //    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
        //    mutableReqeust = [self redirectHostInRequset:mutableReqeust];
        //    return mutableReqeust;
        return request;
    }
    
    + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b
    {
        return [super requestIsCacheEquivalent:a toRequest:b];
    }
    
    - (void)startLoading
    {
        NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
        //打标签,防止无限循环
        [NSURLProtocol setProperty:@YES forKey:JWURLProtocolHandledKey inRequest:mutableReqeust];
        //异步
            NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
            [NSURLConnection sendAsynchronousRequest:mutableReqeust queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                [self mockRequest:mutableReqeust data:data];
            }];
        
        //    同步
        //    NSHTTPURLResponse* urlResponse = nil;
        //    NSError *error = [[NSError alloc] init];
        //    NSData *data =[NSURLConnection sendSynchronousRequest:mutableRequest returningResponse:&urlResponse error:&error];
        //    [self mockRequest:mutableRequest data:data];
    
    }
    
    #pragma mark - Mock responses
    
    -(void) mockRequest:(NSURLRequest*)request data:(NSData*)data {
        id client = [self client];
        
        //    问题来自于webkit块因为起源于跨域请求的响应。因为我们我们必须迫使Access-Control-Allow-Origin模拟响应,然后我们还需要强迫响应的内容类型。
        //    设置为*则所域可以用ajax跨域获取数据,设置为指定的域名只能指定的域名用ajax跨域获取到数据。
        NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"};
        NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.0" headerFields:headers];
        
        [client URLProtocol:self didReceiveResponse:response
         cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        [client URLProtocol:self didLoadData:data];
        [client URLProtocolDidFinishLoading:self];
    }
    - (void)stopLoading
    {
        
    }
    @end
    

    局部使用

    - (void)viewDidLoad 
    {
        [super viewDidLoad];
        /** 注册 网络请求拦截 */
        [NSURLProtocol registerClass:[JWURLProtocol class]];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        /** 取消注册网路请求拦截 */
        [NSURLProtocol unregisterClass:[JWURLProtocol class]];
    }
    

    全局使用

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        
        //注册protocol
        [NSURLProtocol registerClass:[JWURLProtocol class]];
        return YES;
    }
    

    ** 在UIWebView中使用会出现 js、css、图片重定向后无法访问的问题,如果想解决此问题可以使用此方法解决

    //TODO: 重定向
    - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
    {
       if (response != nil)
       {
           [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
       }
       return request;
    }
    

    苹果现在提倡使用NSURLSession

    下面给一个完整的NSURLSession的封装类

    #import <Foundation/Foundation.h>
    
    @interface JWURLSessionProtocol : NSURLProtocol
    
    @end
    
    //
    //  JWURLSessionProtocol.m
    //  NSURLProtocolExample
    //
    //  Created by yangjw on 16/8/22.
    //  Copyright © 2016年 lujb. All rights reserved.
    //
    
    #import "JWURLSessionProtocol.h"
    
    static NSString * const JWURLProtocolHandledKey = @"JWURLProtocolHandledKey";
    
    @interface JWURLSessionProtocol ()<NSURLSessionDataDelegate>
    
    @property (atomic, strong, readwrite) NSURLSessionDataTask *task;
    @property (nonatomic, strong        ) NSURLSession         *session;
    @end
    
    @implementation JWURLSessionProtocol
    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
        //只处理http和https请求
        NSString *scheme = [[request URL] scheme];
        if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
              [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame))
        {
    //        NSLog(@"====>%@",request.URL);
            
            //看看是否已经处理过了,防止无限循环
            if ([NSURLProtocol propertyForKey:JWURLProtocolHandledKey inRequest:request]) {
                return NO;
            }
            
            return YES;
        }
        return NO;
    }
    
    + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
        /** 可以在此处添加头等信息  */
        NSMutableURLRequest *mutableReqeust = [request mutableCopy];
        return mutableReqeust;
    }
    - (void)startLoading
    {
        NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
        //打标签,防止无限循环
        [NSURLProtocol setProperty:@YES forKey:JWURLProtocolHandledKey inRequest:mutableReqeust];
        
        NSURLSessionConfiguration *configure = [NSURLSessionConfiguration defaultSessionConfiguration];
        
          NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        self.session  = [NSURLSession sessionWithConfiguration:configure delegate:self delegateQueue:queue];
        self.task = [self.session dataTaskWithRequest:mutableReqeust];
        [self.task resume];
    }
    
    - (void)stopLoading
    {
        [self.session invalidateAndCancel];
        self.session = nil;
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
    {
        if (error != nil) {
            [self.client URLProtocol:self didFailWithError:error];
        }else
        {
            [self.client URLProtocolDidFinishLoading:self];
        }
    }
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveResponse:(NSURLResponse *)response
     completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
    {
        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        
        completionHandler(NSURLSessionResponseAllow);
    }
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    {
        [self.client URLProtocol:self didLoadData:data];
    }
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable))completionHandler
    {
        completionHandler(proposedResponse);
    }
    
    //TODO: 重定向
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler
    {
        NSMutableURLRequest *    redirectRequest;
        redirectRequest = [newRequest mutableCopy];
        [[self class] removePropertyForKey:JWURLProtocolHandledKey inRequest:redirectRequest];
        [[self client] URLProtocol:self wasRedirectedToRequest:redirectRequest redirectResponse:response];
        
        [self.task cancel];
        [[self client] URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
    }
    
    - (instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client
    {
        self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
        if (self) {
            
            // Some stuff
        }
        return self;
    }
    
    @end
    

    相关文章

      网友评论

      本文标题:UIWebView使用NSURLProtocol(拦截),aja

      本文链接:https://www.haomeiwen.com/subject/wnebsttx.html