文章首次整理自 个人博客->iOS AFN 3.x Cookie的管理(最新)
问题提出
最近遇到的这个问题,让我想到了3年前遇到的问题,这个就是
Cookie
的管理。接下来,我们就一步一步来看看Cookie
的管理;经过半天各种尝试,iOS这边,杀掉APP,重新运行,Cookie就丢了,是什么原因呢,可以先自己猜猜看;
2年前的插曲,容我回忆一下。。。
2年前的尝试
2年前,也就是17年的大概这个时候,我在一家英语在线教育公司工作,那时候,还不知道,也就是大概2个月后,公司因为模式、资金等问题解散,不过这都是后话,想看的朋友可以点击这个文章写在创业公司的那一年;
那时候,我才工作没多久,不晓得 token
跟 Cookie
对后台有什么不一样,后台说用什么就用什么,结果,在开发中,我们用AFN 2.x,服务端的同学说自己把Cookie的有效期设置了一天,但是实际上,我们测试,很快就过期了,而且,我们通过手动设置登录返回的Cookie给服务端,结果还是很快就过期了,并且,服务端收到的Cookie跟我们给的并不一样,我们做了很多实验,测试,最后,决定切换Token,由后台生成一个Token登录返回给我们,我们存储,然后在访问接口是,给Http的头部带过去,这个事情就算完结了;
出来混总是要还的
然而,当时,没有实际解决的问题,现在又碰到了;
公司在做一个大平台的项目,服务端为了便于Web跟APP统一管理,登录接口都是一样的,并且跟其他API的主域名还不一样,而且,用了Cookie的校验,登录校验流程看起来就是下面这个样子的:
什么是Cookie
Cookie的分类
Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie。
内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。
简单地说,cookie就是浏览器储存在用户电脑上的一小段文本文件。cookie 是纯文本格式,不包含任何可执行的代码。
因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,所以Cookie就是用来绕开HTTP的无状态性的“额外手段”之一。服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。
Http通过发送一个称为 Set-Cookie 的 HTTP 请求头来创建一个 cookie,Set-Cookie 是请求头一个字符串,大概的格式就是下面这个样子:
Set-Cookie = "SESSION=OTMyZjViNGItNDk3OS00Y2NjLWI2MTEtODY4MmM1MGNhZTZk; Path=/",
AFN Cookie的存取
印象里,Cookie一般都是浏览器自己管理,客户端很少用,但是,既然服务端决定用了,并且Android的小伙伴都弄好了,就是我这边得找找办法;
所幸,项目中的网络请求都是单独封装的,只需要修改底层配置manger的方法就行,也不难;搜了一下,以下是尝试的办法;
尝试方法一
通过创建请求序列化配置的实例设置,无效
// AFHTTPRequestSerializer *requestSerialization = [AFHTTPRequestSerializer serializer];
// requestSerialization.timeoutInterval = 15;
// // 设置自动管理Cookies
// requestSerialization.HTTPShouldHandleCookies = YES;
// [requestSerialization setValue:[kUserDefault objectForKey:@"Cookie"] forHTTPHeaderField:@"Cookie"];
更详细的代码配置如下,以 GET 方法为例:
NSString *URL = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
AFHTTPSessionManager *manger = [AFHTTPSessionManager manager];
// AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
// [policy setAllowInvalidCertificates:YES];
// [manger setSecurityPolicy:[LXNetworkItem customSecurityPolicy]];
manger.requestSerializer = [AFJSONRequestSerializer serializer];
manger.responseSerializer = [AFJSONResponseSerializer serializer];
manger.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
//创建请求序列化配置,这种是无效的
// AFHTTPRequestSerializer *requestSerialization = [AFHTTPRequestSerializer serializer];
// requestSerialization.timeoutInterval = 15;
// // 设置自动管理Cookies
// requestSerialization.HTTPShouldHandleCookies = YES;
// [requestSerialization setValue:[kUserDefault objectForKey:@"Cookie"] forHTTPHeaderField:@"Cookie"];
[manger GET:URL parameters:self.params progress:^(NSProgress * _Nonnull downloadProgress) {
//进度
} success:^(NSURLSessionDataTask *task, id responseObject) {
} failure:^(NSURLSessionDataTask *task, NSError *error) {
}];
}
尝试方法二
是不是这个属性设置错了:HTTPShouldHandleCookies
这个属性,默认是YES,也就是自动管理Cookie的生命周期,设置为NO,运行,没用,当杀掉APP后,再次打开还是失效;
上面这个的尝试,是这个文章误导我了
解决办法
搞了半天,头也比较大,出去透透风。。。
仔细想想,上面的设置其实是没用的,为什么呢?
因为,你单独创建了一个请求序列化实例,而这个实例并不是manger的属性,manger其实内部也有一个requestSerializer
,这个才是真正的请求序列化配置,当然我也是尝试敲出来的,这么一修改,完美解决;
当APP杀掉后,再次打开,接口有效;
manger.requestSerializer.HTTPShouldHandleCookies = NO;
manger.requestSerializer.timeoutInterval = 15;
[manger.requestSerializer setValue:[kUserDefault objectForKey:@"Cookie"] forHTTPHeaderField:@"Cookie"];
Cookie的持久化
Cookie要保存在客户端,作为服务端校验客户端的一种身份验证,因此需要持久化,否则,当APP杀掉后,HTTP 就短了,Cookie就掉了,就会发生我遇到的问题
NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
NSDictionary *allHeaderFieldsDic = response.allHeaderFields;
NSString *setCookie = allHeaderFieldsDic[@"Set-Cookie"];
if (setCookie != nil) {
NSString *cookie = [[setCookie componentsSeparatedByString:@";"] objectAtIndex:0];
NSLog(@"登录之后存的cookie : %@", cookie); // 这里可对cookie进行存储
[kUserDefault setObject:cookie forKey:@"Cookie"];
}
Cookie的清除
当用户退出登录后,清除本地存储的Cookie,或者当Cookie失效后,清除本地存储的Cookie,重新登录,然后再存储新的Cookie;
以上就是本次分享,如有问题,欢迎留言探讨;