iOS AFN 3.x Cookie的管理(最新)

Cookie的生命周期

Posted by 陕西毅杰 on May 5, 2019

问题提出

最近遇到的这个问题,让我想到了3年前遇到的问题,这个就是Cookie的管理。接下来,我们就一步一步来看看Cookie的管理;经过半天各种尝试,iOS这边,杀掉APP,重新运行,Cookie就丢了,是什么原因呢,可以先自己猜猜看;

2年前的插曲,容我回忆一下。。。

2年前的尝试

2年前,也就是17年的大概这个时候,我在一家英语在线教育公司工作,那时候,还不知道,也就是大概2个月后,公司因为模式、资金等问题解散,不过这都是后话,想看的朋友可以点击这个文章写在创业公司的那一年

那时候,我才工作没多久,不晓得 tokenCookie 对后台有什么不一样,后台说用什么就用什么,结果,在开发中,我们用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 是请求头一个字符串,大概的格式就是下面这个样子:

1
Set-Cookie = "SESSION=OTMyZjViNGItNDk3OS00Y2NjLWI2MTEtODY4MmM1MGNhZTZk; Path=/",

AFN Cookie的存取

印象里,Cookie一般都是浏览器自己管理,客户端很少用,但是,既然服务端决定用了,并且Android的小伙伴都弄好了,就是我这边得找找办法;

所幸,项目中的网络请求都是单独封装的,只需要修改底层配置manger的方法就行,也不难;搜了一下,以下是尝试的办法;

尝试方法一

通过创建请求序列化配置的实例设置,无效

1
2
3
4
5
6
//            AFHTTPRequestSerializer *requestSerialization = [AFHTTPRequestSerializer serializer];
//            requestSerialization.timeoutInterval = 15;
//            // 设置自动管理Cookies
//            requestSerialization.HTTPShouldHandleCookies = YES;
//            [requestSerialization setValue:[kUserDefault objectForKey:@"Cookie"] forHTTPHeaderField:@"Cookie"];

更详细的代码配置如下,以 GET 方法为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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杀掉后,再次打开,接口有效;

1
2
3
manger.requestSerializer.HTTPShouldHandleCookies = NO;
manger.requestSerializer.timeoutInterval = 15;
[manger.requestSerializer setValue:[kUserDefault objectForKey:@"Cookie"] forHTTPHeaderField:@"Cookie"];

Cookie的持久化

Cookie要保存在客户端,作为服务端校验客户端的一种身份验证,因此需要持久化,否则,当APP杀掉后,HTTP 就短了,Cookie就掉了,就会发生我遇到的问题

1
2
3
4
5
6
7
8
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;

以上就是本次分享,如有问题,欢迎留言探讨;


☛兄dei,请我喝杯茶☚
%