UIWebView capturing the response headers

前端 未结 4 963
耶瑟儿~
耶瑟儿~ 2020-12-05 08:29

I searched/googled a lot but could not get the answer on how to capture HTTP response headers in UIWebview. Say I redirect to user to registration gateway(which

相关标签:
4条回答
  • 2020-12-05 08:56

    If you want a more high level API code of what @Richard J. Ross III's wrote, you need to subclass NSURLProtocol.

    An NSURLProtocol is an object which handles URL Requests. So you can use it for specific tasks which are described better on NSHipster and Ray Wenderlich, which includes your case of getting the HTTP Headers from the Response.

    Code

    Create a new class subclassing from NSURLProtocol and your .h file should look like this:

    @interface CustomURLProtocol : NSURLProtocol <NSURLConnectionDelegate>
    
    @property (nonatomic, strong) NSURLConnection *connection;
    
    @end
    

    Your .m file should have these methods to handle what you wish for

    @implementation CustomURLProtocol
    
    + (BOOL)canInitWithRequest:(NSURLRequest *)request {
        // Here you can add custom filters to init or not specific requests
        return YES;
    }
    
    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
        // Here you can modify your request
        return request;
    }
    
    + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
        return [super requestIsCacheEquivalent:a toRequest:b];
    }
    
    - (void)startLoading {
        // Start request
        self.connection = [NSURLConnection connectionWithRequest:self.request delegate:self];
    }
    
    - (void) stopLoading {
        [self.connection cancel];
        self.connection = nil;
    }
    
    #pragma mark - Delegation
    
    #pragma mark NSURLConnectionDelegate
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            
            // Here we go with the headers
            NSDictionary *allHeaderFields = [httpResponse allHeaderFields];
        }
        
        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
        [self.client URLProtocol:self didLoadData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        [self.client URLProtocolDidFinishLoading:self];
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
        [self.client URLProtocol:self didFailWithError:error];
    }
    

    Also last thing to do is to register this protocol to the loading system which is easy achievable on AppDelegate:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [NSURLProtocol registerClass:[CustomURLProtocol class]];
        return YES;
    }
    
    0 讨论(0)
  • 2020-12-05 09:10

    There is no way to get the response object from the UIWebView (file a bug with apple for that, id say)

    BUT two workarounds

    1) via the shared NSURLCache

    - (void)viewDidAppear:(BOOL)animated {
        NSURL *u = [NSURL URLWithString:@"http://www.google.de"];
        NSURLRequest *r = [NSURLRequest requestWithURL:u];
        [self.webView loadRequest:r];
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        NSCachedURLResponse *resp = [[NSURLCache sharedURLCache] cachedResponseForRequest:webView.request];
        NSLog(@"%@",[(NSHTTPURLResponse*)resp.response allHeaderFields]);
    }
    @end
    

    if this works for you this is ideal


    ELSE

    1. you could use NSURLConnection altogether and then just use the NSData you downloaded to feed the UIWebView :)

    that'd be a bad workaround for this! (as Richard pointed out in the comments.) It DOES have major drawbacks and you have to see if it is a valid solution in your case

    NSURL *u = [NSURL URLWithString:@"http://www.google.de"];
    NSURLRequest *r = [NSURLRequest requestWithURL:u];
    [NSURLConnection sendAsynchronousRequest:r queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *resp, NSData *d, NSError *e) {
        [self.webView loadData:d MIMEType:nil textEncodingName:nil baseURL:u];
        NSLog(@"%@", [(NSHTTPURLResponse*)resp allHeaderFields]);
    }];
    
    0 讨论(0)
  • 2020-12-05 09:11

    NSHTTPURLResponse has method like

    - (NSDictionary *)allHeaderFields
    

    For more info https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSHTTPURLResponse_Class/Reference/Reference.html#//apple_ref/occ/cl/NSHTTPURLResponse

    EDIT: Sorry I did not think about UIWebView. My solution works if you use NSURLConnection

    But if you feed you webview with a NSURLConnection then you have the chance to capture the connection including response headers.

    0 讨论(0)
  • 2020-12-05 09:18

    I love the objective-c runtime. Is there something that you want to do but don't have an API for it? DM;HR.

    Alright, on a more serious note, here's the solution to this. It will capture every URL Response that initiated from CFNetwork, which is what UIWebView happens to use behind the scenes. It will also capture AJAX requests, image loads, and more.

    Adding a filter to this should probably be as easy as doing a regex on the contents of the headers.

    @implementation NSURLResponse(webViewHack)
    
    static IMP originalImp;
    
    static char *rot13decode(const char *input)
    {
        static char output[100];
    
        char *result = output;
    
        // rot13 decode the string
        while (*input) {
            if (isalpha(*input))
            {
                int inputCase = isupper(*input) ? 'A' : 'a';
    
                *result = (((*input - inputCase) + 13) % 26) + inputCase;
            }
            else {
                *result = *input;
            }
    
            input++;
            result++;
        }
    
        *result = '\0';
        return output;
    }
    
    +(void) load {
        SEL oldSel = sel_getUid(rot13decode("_vavgJvguPSHEYErfcbafr:"));
    
        Method old = class_getInstanceMethod(self, oldSel);
        Method new = class_getInstanceMethod(self, @selector(__initWithCFURLResponse:));
    
        originalImp = method_getImplementation(old);
        method_exchangeImplementations(old, new);
    }
    
    -(id) __initWithCFURLResponse:(void *) cf {
        if ((self = originalImp(self, _cmd, cf))) {
            printf("-[%s %s]: %s", class_getName([self class]), sel_getName(_cmd), [[[self URL] description] UTF8String]);
    
            if ([self isKindOfClass:[NSHTTPURLResponse class]])
            {
                printf(" - %s", [[[(NSHTTPURLResponse *) self allHeaderFields] description] UTF8String]);
            }
    
            printf("\n");
        }
    
        return self;
    }
    
    @end
    
    0 讨论(0)
提交回复
热议问题