日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

iOS端WebView " IP直連 " 如何處理 Cookie

更新時(shí)間:

本文主要介紹防DNS污染方案在WebView場(chǎng)景下所遇到的一些問(wèn)題及解決方案。

重要

當(dāng)前最佳實(shí)踐文檔只針對(duì)結(jié)合使用時(shí),如何使用HTTPDNS解析出的IP,關(guān)于HTTPDNS本身的解析服務(wù),請(qǐng)先查看iOS SDK 開(kāi)發(fā)手冊(cè)

WKWebView無(wú)法使用NSURLProtocol攔截請(qǐng)求

針對(duì)該問(wèn)題方案如下: 

  • 換用UIWebView 

  • 換用UIWebView方案不做贅述,說(shuō)明下使用私有API進(jìn)行注冊(cè)攔截的方法 :

      // 注冊(cè)自己的 protocol
      [NSURLProtocol registerClass:[CustomProtocol class]];
      // 創(chuàng)建 WKWebview
      WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc] init];
      WKWebView * wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0,   [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) configuration:config];
      [wkWebView loadRequest:webViewReq];
      [self.view addSubview:wkWebView];
      //注冊(cè) scheme
      Class cls = NSClassFromString(@"WKBrowsingContextController");
      SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
      if ([cls respondsToSelector:sel]) {
          // 通過(guò) http 和 https 的請(qǐng)求,同理可通過(guò)其他的 Scheme 但是要滿足 ULR Loading System
          [cls performSelector:sel withObject:@"http"];
          [cls performSelector:sel withObject:@"https"];
      }

    使用私有API的另一風(fēng)險(xiǎn)是兼容性問(wèn)題,比如上面的 browsingContextController就只能在iOS 8.4以后才能用,反注冊(cè)scheme的方法 unregisterSchemeForCustomProtocol :也是在iOS 8.4 以后才被添加進(jìn)來(lái)的,要支持iOS 8.0 ~ 8.3機(jī)型的話,只能通過(guò)動(dòng)態(tài)生成字符串的方式拿到 WKBrowsingContextController,而且還不能反注冊(cè),不過(guò)這些問(wèn)題都不大。至于向后兼容,這個(gè)也不用太擔(dān)心,因?yàn)閕OS發(fā)布新版本之前都會(huì)有開(kāi)發(fā)者預(yù)覽版的,那個(gè)時(shí)候再測(cè)一下也不遲。對(duì)于本文的例子來(lái)說(shuō),如果將來(lái)哪個(gè)iOS版本移除了這個(gè)API,那很可能是因?yàn)楣俜教峁┝送暾慕鉀Q方案,到那時(shí)候自然也不需要本文介紹的方法了 。

    重要

    避免執(zhí)行太晚,如果在 - (void)viewDidLoad中注冊(cè),可能會(huì)因?yàn)樽?cè)太晚,引發(fā)問(wèn)題。建議在 +load方法中執(zhí)行 。然后同樣會(huì)遇到iOS端HTTPS(含SNI)業(yè)務(wù)場(chǎng)景:IP直連方案說(shuō)明里提到的各種NSURLProtocol相關(guān)的問(wèn)題,可以參照里面的方法解決。

WebView中的Cookie處理業(yè)務(wù)場(chǎng)景“IP直連”方案說(shuō)明

本章節(jié)將討論類(lèi)似這樣的問(wèn)題:

  • WKWebView對(duì)于Cookie的管理一直是它的短板,那么iOS11是否有改進(jìn),如果有,如何利用這樣的改進(jìn)?

  • 采用IP直連方案后,服務(wù)端返回的Cookie里的Domain字段也會(huì)使用IP。如果IP是動(dòng)態(tài)的,就有可能導(dǎo)致一些問(wèn)題:由于許多H5業(yè)務(wù)都依賴(lài)于Cookie作登錄態(tài)校驗(yàn) ,而WKWebView上請(qǐng)求不會(huì)自動(dòng)攜帶 Cookie。

WKWebView使用NSURLProtocol攔截請(qǐng)求無(wú)法獲取Cookie信息

iOS 11推出了新的APIWKHTTPCookieStore可以用來(lái)攔截WKWebView的Cookie信息。

用法示例如下:

   WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
   // get cookies
    [cookieStroe getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookies) {
        NSLog(@"All cookies %@",cookies);
    }];

    // set cookie
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[NSHTTPCookieName] = @"userid";
    dict[NSHTTPCookieValue] = @"123";
    dict[NSHTTPCookieDomain] = @"xxxx.com";
    dict[NSHTTPCookiePath] = @"/";

    NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:dict];
    [cookieStroe setCookie:cookie completionHandler:^{
        NSLog(@"set cookie");
    }];

    // delete cookie
    [cookieStroe deleteCookie:cookie completionHandler:^{
        NSLog(@"delete cookie");
    }];

利用iOS 11 API WKHTTPCookieStore解決WKWebView首次請(qǐng)求不攜帶Cookie的問(wèn)題

  • 問(wèn)題說(shuō)明:由于許多H5業(yè)務(wù)都依賴(lài)于Cookie作登錄態(tài)校驗(yàn),而WKWebView上請(qǐng)求不會(huì)自動(dòng)攜帶 Cookie。比如,如果你在Native層面做了登錄操作,獲取了Cookie信息,也使用 NSHTTPCookieStorage存到了本地,但是使用WKWebView打開(kāi)對(duì)應(yīng)網(wǎng)頁(yè)時(shí),網(wǎng)頁(yè)依然處于未登錄狀態(tài)。如果是登錄也在WebView里做的,就不會(huì)有這個(gè)問(wèn)題。

  • iOS 11的API可以解決該問(wèn)題,只要是存在WKHTTPCookieStore里的cookie,WKWebView每次請(qǐng)求都會(huì)攜帶,存在NSHTTPCookieStorage的cookie,并不會(huì)每次都攜帶。于是會(huì)發(fā)生首次WKWebView 請(qǐng)求不攜帶Cookie的問(wèn)題。

  • 解決方法:

    在執(zhí)行 -[WKWebView loadReques:]前將 NSHTTPCookieStorage中的內(nèi)容復(fù)制到 WKHTTPCookieStore中,以此來(lái)達(dá)到 WKWebView Cookie 注入的目的。示例代碼如下:

        [self copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:^{
                NSURL *url = [NSURL URLWithString:@"https://www.v2ex.com"];
                NSURLRequest *request = [NSURLRequest requestWithURL:url];
                [_webView loadRequest:request];
            }];

    - (void)copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:(nullable void (^)())theCompletionHandler; {
        NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
        WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
        if (cookies.count == 0) {
            !theCompletionHandler ?: theCompletionHandler();
            return;
        }
        for (NSHTTPCookie *cookie in cookies) {
            [cookieStroe setCookie:cookie completionHandler:^{
                if ([[cookies lastObject] isEqual:cookie]) {
                    !theCompletionHandler ?: theCompletionHandler();
                    return;
                }
            }];
        }
    }

    這個(gè)是iOS 11的API ,針對(duì)iOS 11之前的系統(tǒng) ,需要另外處理。

利用 iOS 11之前的API解決WKWebView首次請(qǐng)求不攜帶Cookie的問(wèn)題

通過(guò)讓所有WKWebView共享同一個(gè)WKProcessPool實(shí)例,可以實(shí)現(xiàn)多個(gè)WKWebView之間共享Cookie(session Cookie and persistent Cookie)數(shù)據(jù)。不過(guò)WKWebView WKProcessPool實(shí)例在app殺進(jìn)程重啟后會(huì)被重置,導(dǎo)致WKProcessPool中的Cookie、session Cookie數(shù)據(jù)丟失,目前也無(wú)法實(shí)現(xiàn) WKProcessPool實(shí)例本地化保存。可以采取cookie放入Header的方法來(lái)做。

 WKWebView * webView = [WKWebView new]; 
 NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://xxx.com/login"]]; 
 [request addValue:@"skey=skeyValue" forHTTPHeaderField:@"Cookie"]; 
 [webView loadRequest:request];

其中對(duì)于skey=skeyValue這個(gè)cookie值的獲取,也可以統(tǒng)一通過(guò)domain獲取,獲取的方法,可以參照下面的工具類(lèi):

HTTPDNSCookieManager.h

#ifndef HTTPDNSCookieManager_h
#define HTTPDNSCookieManager_h

// URL匹配Cookie規(guī)則
typedef BOOL (^HTTPDNSCookieFilter)(NSHTTPCookie *, NSURL *);

@interface HTTPDNSCookieManager : NSObject

+ (instancetype)sharedInstance;

/**
 指定URL匹配Cookie策略

 @param filter 匹配器
 */
- (void)setCookieFilter:(HTTPDNSCookieFilter)filter;

/**
 處理HTTP Response攜帶的Cookie并存儲(chǔ)

 @param headerFields HTTP Header Fields
 @param URL 根據(jù)匹配策略獲取查找URL關(guān)聯(lián)的Cookie
 @return 返回添加到存儲(chǔ)的Cookie
 */
- (NSArray<NSHTTPCookie *> *)handleHeaderFields:(NSDictionary *)headerFields forURL:(NSURL *)URL;

/**
 匹配本地Cookie存儲(chǔ),獲取對(duì)應(yīng)URL的request cookie字符串

 @param URL 根據(jù)匹配策略指定查找URL關(guān)聯(lián)的Cookie
 @return 返回對(duì)應(yīng)URL的request Cookie字符串
 */
- (NSString *)getRequestCookieHeaderForURL:(NSURL *)URL;

/**
 刪除存儲(chǔ)cookie

 @param URL 根據(jù)匹配策略查找URL關(guān)聯(lián)的cookie
 @return 返回成功刪除cookie數(shù)
 */
- (NSInteger)deleteCookieForURL:(NSURL *)URL;

@end

#endif /* HTTPDNSCookieManager_h */

HTTPDNSCookieManager.m
#import <Foundation/Foundation.h>
#import "HTTPDNSCookieManager.h"

@implementation HTTPDNSCookieManager
{
    HTTPDNSCookieFilter cookieFilter;
}

- (instancetype)init {
    if (self = [super init]) {
        /**
            此處設(shè)置的Cookie和URL匹配策略比較簡(jiǎn)單,檢查URL.host是否包含Cookie的domain字段
            通過(guò)調(diào)用setCookieFilter接口設(shè)定Cookie匹配策略,
            比如可以設(shè)定Cookie的domain字段和URL.host的后綴匹配 | URL是否符合Cookie的path設(shè)定
            細(xì)節(jié)匹配規(guī)則可參考RFC 2965 3.3節(jié)
         */
        cookieFilter = ^BOOL(NSHTTPCookie *cookie, NSURL *URL) {
            if ([URL.host containsString:cookie.domain]) {
                return YES;
            }
            return NO;
        };
    }
    return self;
}

+ (instancetype)sharedInstance {
    static id singletonInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!singletonInstance) {
            singletonInstance = [[super allocWithZone:NULL] init];
        }
    });
    return singletonInstance;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

- (id)copyWithZone:(struct _NSZone *)zone {
    return self;
}

- (void)setCookieFilter:(HTTPDNSCookieFilter)filter {
    if (filter != nil) {
        cookieFilter = filter;
    }
}

- (NSArray<NSHTTPCookie *> *)handleHeaderFields:(NSDictionary *)headerFields forURL:(NSURL *)URL {
    NSArray *cookieArray = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:URL];
    if (cookieArray != nil) {
        NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *cookie in cookieArray) {
            if (cookieFilter(cookie, URL)) {
                NSLog(@"Add a cookie: %@", cookie);
                [cookieStorage setCookie:cookie];
            }
        }
    }
    return cookieArray;
}

- (NSString *)getRequestCookieHeaderForURL:(NSURL *)URL {
    NSArray *cookieArray = [self searchAppropriateCookies:URL];
    if (cookieArray != nil && cookieArray.count > 0) {
        NSDictionary *cookieDic = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
        if ([cookieDic objectForKey:@"Cookie"]) {
            return cookieDic[@"Cookie"];
        }
    }
    return nil;
}

- (NSArray *)searchAppropriateCookies:(NSURL *)URL {
    NSMutableArray *cookieArray = [NSMutableArray array];
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [cookieStorage cookies]) {
        if (cookieFilter(cookie, URL)) {
            NSLog(@"Search an appropriate cookie: %@", cookie);
            [cookieArray addObject:cookie];
        }
    }
    return cookieArray;
}

- (NSInteger)deleteCookieForURL:(NSURL *)URL {
    int delCount = 0;
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [cookieStorage cookies]) {
        if (cookieFilter(cookie, URL)) {
            NSLog(@"Delete a cookie: %@", cookie);
            [cookieStorage deleteCookie:cookie];
            delCount++;
        }
    }
    return delCount;
}

@end

發(fā)送請(qǐng)求使用方法示例:

 WKWebView * webView = [WKWebView new]; 
 NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://xxx.com/login"]]; 
NSString *value = [[HTTPDNSCookieManager sharedInstance] getRequestCookieHeaderForURL:url];
[request setValue:value forHTTPHeaderField:@"Cookie"];
 [webView loadRequest:request];

接收處理請(qǐng)求:

    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            // 解析 HTTP Response Header,存儲(chǔ)cookie
            [[HTTPDNSCookieManager sharedInstance] handleHeaderFields:[httpResponse allHeaderFields] forURL:url];
        }
    }];
    [task resume];

通過(guò)document.cookie設(shè)置Cookie解決后續(xù)頁(yè)面(同域)Ajax、iframe請(qǐng)求的Cookie問(wèn)題。

WKUserContentController* userContentController = [WKUserContentController new]; 
 WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: @"document.cookie = 'skey=skeyValue';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 
 [userContentController addUserScript:cookieScript];

Cookie包含動(dòng)態(tài)IP導(dǎo)致登錄失效問(wèn)題

關(guān)于Cookie失效的問(wèn)題,假如客戶(hù)端登錄session存在Cookie,此時(shí)這個(gè)域名配置了多個(gè)IP,使用域名訪問(wèn)會(huì)讀對(duì)應(yīng)域名的Cookie,使用IP訪問(wèn)則去讀對(duì)應(yīng)IP的Cookie,假如前后兩次使用同一個(gè)域名配置的不同IP訪問(wèn),會(huì)導(dǎo)致Cookie的登錄session失效。

如果App里面的WebView頁(yè)面需要用到系統(tǒng)Cookie存的登錄session,之前App所有本地網(wǎng)絡(luò)請(qǐng)求使用域名訪問(wèn),是可以共用Cookie的登錄session的,但現(xiàn)在本地網(wǎng)絡(luò)請(qǐng)求使用HTTPDNS后改用IP訪問(wèn),導(dǎo)致還使用域名訪問(wèn)的WebView讀不到系統(tǒng)Cookie存的登錄session了(系統(tǒng)Cookie對(duì)應(yīng)IP了)。IP直連后,服務(wù)端返回Cookie包含動(dòng)態(tài)IP導(dǎo)致登錄失效。

使用IP訪問(wèn)后,服務(wù)端返回的cookie也是IP。導(dǎo)致可能使用對(duì)應(yīng)的域名訪問(wèn),無(wú)法使用本地Cookie,或者使用隸屬于同一個(gè)域名的不同IP去訪問(wèn),Cookie也對(duì)不上,導(dǎo)致登錄失效。

我這邊的思路是這樣的:

  • 應(yīng)該得干預(yù)Cookie的存儲(chǔ),基于域名。

  • 根源上,API域名返回單IP。

第二種思路將失去DNS調(diào)度特性,故不考慮。第一種思路更為可行。

基于iOS11 API WKHTTPCookieStore來(lái)解決WKWebView的Cookie管理問(wèn)題

當(dāng)每次服務(wù)端返回Cookie后,在存儲(chǔ)前都進(jìn)行下改造,使用域名替換下IP。之后雖然每次網(wǎng)絡(luò)請(qǐng)求都是使用IP訪問(wèn),但是host我們都手動(dòng)改為了域名,這樣本地存儲(chǔ)的Cookie也就能對(duì)得上了。

代碼演示:

在網(wǎng)絡(luò)請(qǐng)求成功后,或者加載網(wǎng)頁(yè)成功后,主動(dòng)將本地的domain字段為IP的Cookie替換IP為host域名地址。

- (void)updateWKHTTPCookieStoreDomainFromIP:(NSString *)IP toHost:(NSString *)host {
    WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
    [cookieStroe getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookies) {
        [[cookies copy] enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull cookie, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([cookie.domain isEqualToString:IP]) {
                NSMutableDictionary<NSHTTPCookiePropertyKey, id> *dict = [NSMutableDictionary dictionaryWithDictionary:cookie.properties];
                dict[NSHTTPCookieDomain] = host;
                NSHTTPCookie *newCookie = [NSHTTPCookie cookieWithProperties:[dict copy]];
                [cookieStroe setCookie:newCookie completionHandler:^{
                    [self logCookies];
                    [cookieStroe deleteCookie:cookie
                            completionHandler:^{
                                [self logCookies];
                            }];
                }];
            }
        }];
    }];
}

iOS 11中也提供了對(duì)應(yīng)的API供我們來(lái)處理替換Cookie的時(shí)機(jī),那就是下面的API:

@protocol WKHTTPCookieStoreObserver <NSObject>
@optional
- (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore;
@end

//WKHTTPCookieStore
/*! @abstract Adds a WKHTTPCookieStoreObserver object with the cookie store.
 @param observer The observer object to add.
 @discussion The observer is not retained by the receiver. It is your responsibility
 to unregister the observer before it becomes invalid.
 */
- (void)addObserver:(id<WKHTTPCookieStoreObserver>)observer;

/*! @abstract Removes a WKHTTPCookieStoreObserver object from the cookie store.
 @param observer The observer to remove.
 */
- (void)removeObserver:(id<WKHTTPCookieStoreObserver>)observer;

用法如下:

@interface WebViewController ()<WKHTTPCookieStoreObserver>
- (void)viewDidLoad {
    [super viewDidLoad];
    [NSURLProtocol registerClass:[WebViewURLProtocol class]];
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
    WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
    [cookieStroe addObserver:self];

    [self.view addSubview:self.webView];
    //... ...
}

#pragma mark -
#pragma mark - WKHTTPCookieStoreObserver Delegate Method

- (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore {
    [self updateWKHTTPCookieStoreDomainFromIP:CYLIP toHost:CYLHOST];
}

-updateWKHTTPCookieStoreDomainFromIP方法的實(shí)現(xiàn),在上文已經(jīng)給出。

這個(gè)方案需要客戶(hù)端維護(hù)一個(gè)IP —> HOST的映射關(guān)系,需要能從IP反向查找到HOST,這個(gè)維護(hù)成本還時(shí)挺高的。下面介紹下,更通用的方法,也是iOS11之前的處理方法:

iOS 11之前的處理方法:NSURLProtocal攔截后,手動(dòng)管理Cookie的存儲(chǔ):

步驟:做IP替換時(shí)將原始URL保存到Header中

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReq = [request mutableCopy];
    NSString *originalUrl = mutableReq.URL.absoluteString;
    NSURL *url = [NSURL URLWithString:originalUrl];
    // 異步接口獲取IP地址
    NSString *ip = [[HttpDnsService sharedInstance] getIpByHostAsync:url.host];
    if (ip) {
        NSRange hostFirstRange = [originalUrl rangeOfString:url.host];
        if (NSNotFound != hostFirstRange.location) {
            NSString *newUrl = [originalUrl stringByReplacingCharactersInRange:hostFirstRange withString:ip];
            mutableReq.URL = [NSURL URLWithString:newUrl];
            [mutableReq setValue:url.host forHTTPHeaderField:@"host"];
            // 添加originalUrl保存原始URL
            [mutableReq addValue:originalUrl forHTTPHeaderField:@"originalUrl"];
        }
    }
    NSURLRequest *postRequestIncludeBody = [mutableReq cyl_getPostRequestIncludeBody];
    return postRequestIncludeBody;
}

然后獲取到數(shù)據(jù)后,手動(dòng)管理Cookie :

- (void)handleCookiesFromResponse:(NSURLResponse *)response {
    NSString *originalURLString = [self.request valueForHTTPHeaderField:@"originalUrl"];
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSDictionary<NSString *, NSString *> *allHeaderFields = httpResponse.allHeaderFields;
        if (originalURLString && originalURLString.length > 0) {
            NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:allHeaderFields forURL: [[NSURL alloc] initWithString:originalURLString]];
            if (cookies && cookies.count > 0) {
                NSURL *originalURL = [NSURL URLWithString:originalURLString];
                [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:originalURL mainDocumentURL:nil];
            }
        }
    }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest *))completionHandler {
    NSString *location = response.allHeaderFields[@"Location"];
    NSURL *url = [[NSURL alloc] initWithString:location];
    NSMutableURLRequest *mRequest = [newRequest mutableCopy];
    mRequest.URL = url;
    if (location && location.length > 0) {
        if ([[newRequest.HTTPMethod lowercaseString] isEqualToString:@"post"]) {
            // POST重定向?yàn)镚ET
            mRequest.HTTPMethod = @"GET";
            mRequest.HTTPBody = nil;
        }
        [mRequest setValue:nil forHTTPHeaderField:@"host"];
        // 在這里為 request 添加 cookie 信息。
        [self handleCookiesFromResponse:response];
        [XXXURLProtocol removePropertyForKey:XXXURLProtocolHandledKey inRequest:mRequest];
        completionHandler(mRequest);
    } else{
       completionHandler(mRequest);
    }
}

發(fā)送請(qǐng)求前,向請(qǐng)求中添加Cookie信息:

+ (void)handleCookieWithRequest:(NSMutableURLRequest *)request {
    NSString* originalURLString = [request valueForHTTPHeaderField:@"originalUrl"];
    if (!originalURLString || originalURLString.length == 0) {
        return;
    }
    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
    if (cookies && cookies.count >0) {
        NSDictionary *cookieHeaders = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
        NSString *cookieString = [cookieHeaders objectForKey:@"Cookie"];
        [request addValue:cookieString forHTTPHeaderField:@"Cookie"];
    }
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReq = [request mutableCopy];
//...
     [self handleCookieWithRequest:mutableReq];
    return [mutableReq copy];
}

相關(guān)的文章:

302重定向問(wèn)題.

上面提到的Cookie方案無(wú)法解決302請(qǐng)求的Cookie問(wèn)題,比如,第一個(gè)請(qǐng)求是http://www.example1.com,我們通過(guò)在request header里帶上Cookie解決該請(qǐng)求的Cookie問(wèn)題,接著頁(yè)面302跳轉(zhuǎn)到http://www.example2.com,這個(gè)時(shí)候http://www.example2.com這個(gè)請(qǐng)求就可能因?yàn)闆](méi)有攜帶Cookie而無(wú)法訪問(wèn)。當(dāng)然,由于每一次頁(yè)面跳轉(zhuǎn)前都會(huì)調(diào)用回調(diào)函數(shù):

 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

可以在該回調(diào)函數(shù)里攔截302請(qǐng)求,copy request,在request header中帶上Cookie并重新 loadRequest。不過(guò)這種方法依然解決不了頁(yè)面iframe跨域請(qǐng)求的Cookie問(wèn)題,畢竟 -[WKWebView loadRequest:]只適合加載mainFrame請(qǐng)求。

相關(guān)參考

相關(guān)的庫(kù):

相關(guān)的文章:

可以參考的Demo: