美文网首页杂乱
40- WKWebView(四) - 项目实践:Cookie

40- WKWebView(四) - 项目实践:Cookie

作者: 春田花花幼儿园 | 来源:发表于2018-04-22 14:52 被阅读280次

    Cookie对webView的重要性不言而喻,也就是Cookie很大成都的影响我们是否使用WKWebView。iOS8.0-iOS11.0的时候,苹果并没有向WKWebView提类似UIWebView+NSHttpCookieStorage这样便利的方案。
    关于为什么在长达三年的时间里,苹果没有理会开发者的抱怨推出客户端管理Cookie的类。CSDN作者请叫我马老师的一篇文章中,提出了猜想,苹果是想让服务端完全控制Cookie,毕竟客户端操作Cookie是有一定安全风险的。WKWebView设计出来,对安全性就有比较高的要求,比如说对跨域的限制。
    那么客户端不传Cookie了,服务端怎么确认用户的身份信息呢?其中的一种方式,我们可以在首次请求的时候,将用户信息身份信息通过POST请求的方式放到requst中。服务端接收到首次请求,判断用户身份信息,如果身份信息有效,则在之后的请求中,有服务器主动设置Cookie保证后续的请求身份。如果身份信息无效,则跳转到登录页面。 这种方式Cookie就完全交给服务器管理了。

    但是,实际开发中,我们还是免不了客户端设置Cookie。

    WKWebView的Cookie方案。

    在UIWebView中,可以通过NSHttpCookieStorage来管理Cookie。
    在UIWebView中,如果添加Cookie到NSHttpCookieStorage中。这个Cookie在发起请求的时候自动添加到request Header中。并且是零延迟的,也就是说,你第一行代码添加Cookie到NSHttpCookieStorage中,第二行代码loadRequest:,发起的请求中是带有你设置的Cookie的。
    关于零延迟这一点非常重要,因为你设置了Cookie,但是请求的时候,带不到服务器,这不是白设置嘛。

    NSHttpCookieStorage对WKWebView而言,只能管理Cookie,但是没有了零延迟自动同步到request Header这一关键的特性。所以我们只能另找出路,下边需要版本适配,也是因为这个原因

    截至置顶的iOS版本,需要适配iOS的三个版本,分别是iOS8iOS11.0、iOS11.0iOS11.2、iOS11.3。 下边看具体的方案:

    Cookie版本适配方案

    下边就针对每个适配版本来说一下具体操作方案。

    适配iOS8~iOS11.0

    首先很明确的说明下,这这里需要关注Cookie设置的地方有两处。
    第一处是我们每次调用loadRequest:方法的时候。
    另一处就是loadRequest:成功之后,在这个webView的进行操作,后续页面跳转的时候。

    关于Cookie管理,我们还是使用NSHttpCookieStorage。

    在每次调用loadRequest:方法的时候

    我们把Cookie手动写入到request Header中。具体代码和步骤如下:

    // 1. 清除NSHTTPCookieStorage中存储的Cookies,避免重复Cookie
    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in cookieJar.cookies) {
        if ([cookie.comment isEqualToString:WebCookieComment]) {
            [cookieJar deleteCookie:cookie];
        }
    }
    
    // 2. 重新设置Cookies
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    // 3. 向Http Header中设置Cookie    
     NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
     request.allHTTPHeaderFields = dict.copy;
    
    // 4. 加载请求
    [self.wkwebView loadRequest: request];
    

    后续页面跳转

    后续跳转,我们把Cookie添加到document.Cookie的方案。

    //1. 添加自定义的cookie,后续请求Ajax页面用到
    WKUserScript *newCookieScript = [[WKUserScript alloc] initWithSource:[WebViewCookieTool cookieJavaScriptString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    [contentController addUserScript:newCookieScript];
    webConfiguration.userContentController = contentController;
    
    
    //2. 获取Cookie的JS代码
    + (NSString *)cookieJavaScriptString
        NSMutableString *script = [NSMutableString string];
        for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
        if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
             continue;
        }
        [script appendFormat:@"document.cookie='%@'; \n", [self getCookieJSFromatString:cookie]];
    }
        
        
    + (NSString *)getCookieJSFromatString:(NSHTTPCookie *)cookie
    {
        NSString *cookieStr = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",
                               cookie.name,
                               cookie.value,
                               cookie.domain,
                               cookie.path ?: @“/"];
        return cookieStr;
    }
    

    这种方案出现的问题

    这种方案基本解决了适配版本中的Cookie问题,但是在实测中,发现将Cookie添加到request Header中会导致另一个问题出现。那就是服务器如果设置一些Cookie到header中,是不能正常设置的,导致网页无法正常显示。又是一个坑。针对这个问题,想到了两个解决方案:

    解决服务器无法在Header中正常设置Cookie

    所以,我项目里有一个区分是不是本公司请求的静态方法:

    static inline BOOL checkURLIsNeedCookies(NSURL *url) {
        if ([url.host hasSuffix:@".myCompany.com") {
            return YES;
        }
        return NO;
    }
    

    适配iOS11.0~iOS11.2

    iOS11.0之后的适配就爽啦,可能苹果了解到开发者的实际情况并且做出了妥协。在iOS11.0推出了WKHTTPCookieStore,这个类对WKWebView的作用和NSHttpCookieStorage对UIWebView的效果一样,并且也是零延迟。所以,只需要在你请求的时候,将Cookie设置到WKHTTPCookieStore就可以了。代码:

    // 1. 设置Cookie
    WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
    [store.httpCookieStore setCookie:cookie completionHandler:^{
    NSLog(@“cookie添加成功”);
    }];
    
    // 2. 加载请求
    [self.wkwebView loadRequest: request];
    

    适配iOS11.3

    前几天升级iOS11.3之后发现需要Cookie的页面,第一次设置的时候,WKHTTPCookieStore中Cookie不同步到request请求中。然后,重新请求页面,WKHTTPCookieStore的作用才会恢复正常,有序请求其他的webView也不会出现问题。

    解决方式是,我们在执行loadRequest之前主动设置一次Cookie。我这里是在didFinishLaunchOption:中设置的。设置完之后,其它的就和在iOS11.0~iOS11.2中一样了。

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    {
       WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
        [store.httpCookieStore setCookie:cookie completionHandler:^{
            NSLog(@“cookie添加成功”);
        }];
    }
    

    好了,关于WKWebView的Cookie设置就到此为止。

    参考

    交流


    希望能和大家交流技术
    Blog:http://www.lilongcnc.cc


    相关文章

      网友评论

        本文标题:40- WKWebView(四) - 项目实践:Cookie

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