iOS下的cookies使用

今天无意间翻到了以前有关cookies的代码,就顺便整理了一下,和大家分享下。

Cookies简介

这里有比较详细的介绍,本文就不再赘述了。click me

在iOS当中需要注意以下几点:

  1. 不管是NSURLConnection还是UIWebView都会保留并传递服务端的cookie,就是说基本所有的网络请求都会使用cookie
  2. 多个应用之间默认不共享cookie
  3. 临时cookie在应用重启之后就会消失
  4. 持久cookie在应用或系统重启之后不会消失
  5. cookie不能跨域,像.baidu.com和image.baidu.com这种也是跨域
  6. WKWebView因为没有缓存,不能使用cookie,想要使用,需做特殊处理。

注:cookie不能跨域是通用的,在所有情况下都是这样,并非在iOS系统上如此。.baidu.com和image.baidu.com可以使用彼此的cookie是因为服务端做了特殊的处理。

Cookies操作

iOS系统当中的cookies由系统底层实现和使用,同时提供了NSHTTPCookieStorageNSHTTPCookie来统一操作cookie。NSHTTPCookieStorage是一个单例,我们所有的cookies都存放在这里,当我们发起网络请求时,系统会默认从NSHTTPCookieStorage当中匹配相应cookie并带上去,所以我们只需要操作NSHTTPCookieStorage即可。

以下是一些简单的使用

/**
 *  获得url对应的cookie
 *
 *  @param url url
 *
 *  @return url对应的cookie
 */
- (NSArray *)getCookiesForUrl:(NSString *)url
{
    NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

    if ([sharedHTTPCookieStorage cookieAcceptPolicy] != NSHTTPCookieAcceptPolicyAlways) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
    }

    NSArray *cookies = [sharedHTTPCookieStorage cookiesForURL:[NSURL URLWithString:url]];

    return cookies;
}

/**
 *  获取应用下所有的cookie
 *
 *  @return 所有的cookie
 */
- (NSArray *)getAllCookies
{
    NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

    if ([sharedHTTPCookieStorage cookieAcceptPolicy] != NSHTTPCookieAcceptPolicyAlways) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
    }

    return sharedHTTPCookieStorage.cookies;
}

/**
 *  将cookie数组当中的cookie设置到cookie缓存中
 *
 *  @param mArrCookie cookie数组
 */
- (void)setCookiesFromArr:(NSArray *)mArrCookie
{
    if (mArrCookie != nil && [mArrCookie count]>0) {
        NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

        for (NSHTTPCookie *cookie in mArrCookie) {
            [sharedHTTPCookieStorage setCookie:cookie];
        }
    }
}

/**
 *  为特殊的url设置cookie
 *
 *  @param mArrCookie cookie数组
 *  @param url        地址,此处地址格式需为.baidu.com这样
 */
- (void)setCookie:(NSArray *)mArrCookie forUrl:(NSString *)url
{
    if (mArrCookie != nil && [mArrCookie count]>0) {
        NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

        for (NSHTTPCookie *cookie in mArrCookie) {
            NSMutableDictionary *cookieDic = [NSMutableDictionary dictionaryWithDictionary:[cookie properties]];
            [cookieDic setObject:url forKey:@"Domain"];
            NSHTTPCookie *tempCookie = [NSHTTPCookie cookieWithProperties:cookieDic];
            [sharedHTTPCookieStorage setCookie:tempCookie];
        }
    }
}

/**
 获取特定url相应key的value值

 @param key cookie的key值
 @param url url,一个完整的url地址,例如https://www.baidu.com/
 @return 当前url下cookie当中当前key对应的value值
 */
- (NSString *)cookieValueWithKey:(NSString *)key forUrl:(NSURL *)url
{
    NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

    if ([sharedHTTPCookieStorage cookieAcceptPolicy] != NSHTTPCookieAcceptPolicyAlways) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
    }

    NSArray *cookies = [sharedHTTPCookieStorage cookiesForURL:url];
    for (NSHTTPCookie *item in cookies) {
        if ([[item name] isEqualToString:key]) {
            return [NSString stringWithString:[[item value] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
    }
    return nil;
}

//以下是一些将cookies本地化的操作

- (void)saveCacheCookie:(id)sender {
    NSArray *mArrCookie = [self getAllCookies];
    NSData *cookieData = [NSKeyedArchiver archivedDataWithRootObject:mArrCookie];
    [[NSUserDefaults standardUserDefaults] setObject:cookieData forKey:@"cookieData"];
}

- (void)unzipCookie:(id)sender {
    NSData *cookieData = [[NSUserDefaults standardUserDefaults] objectForKey:@"cookieData"];
    NSArray *mArrCookie = [NSKeyedUnarchiver unarchiveObjectWithData:cookieData];        
    [self setCookiesFromArr:mArrCookie];
}

跨域问题

针对跨域问题,可以在服务器和客户端分别做处理解决

服务器:在服务器返回cookie时同时将相关联的其他域的cookie返回

客户端:在每次请求完成后,对想跨域的域名进行设置,添加对应的cookie

推荐在服务器配置相关策略

WKWebView使用cookie

因为WKWebView没有缓存,不使用NSHTTPCookieStorage,其cookie只存在内存当中,当前页面被释放其cookie也就消失了。因此WKWebView当中的请求不能使用其他请求的cookie,同时两个WKWebView页面也不共享cookie。

所以想要WKWebView使用其他请求的cookie或者前一个WKWebView页面的cookie需要在WKWebView加载前执行一段js代码,将cookie设置进去,而每次WKWebView请求之后获取cookie,将其保存起来。至于存在哪里,NSHTTPCookieStorageNSUserDefaults都是不错的选择。