当你访问一个网站时,NSURLRequest都会帮你主动记录下来你访问的站点设置的Cookie,如果 Cookie 存在的话,会把这些信息放在 NSHTTPCookieStorage 容器中共享,当你下次再访问这个站点时,NSURLRequest会拿着上次保存下来了的Cookie继续去请求。
同样适用于ASIHTTPRequest,AFNetworking, Webview等,Cookie常用于一些基于认证的网络请求
认识下NSHTTPCookieStorage
NSHTTPCookieStorage 实现了一个管理cookie的单例对象(只有一个实例),每个Cookie都是NSHTTPCookie类的实例,作为为一个规则,Cookie在(macOS)所有应用之间共享并在不同进程之间保持同步,在iOS中不会多应用共享。Session Cookie(一个isSessionOnly方法返回YES的Cookie)只能在单一进程中使用。
Cookie
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器或者客户端),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站地址时就发送该Cookie给服务器
HTTP header
HTTP header中包含HTTP请求与响应的操作参数. header属性定义了所传输数据的各种特性. header属性以属性名开始,以冒号结尾,最后是属性值.属性名及值会因应用的不同
一.iOS htttp网络请求Cookie的读取与写入:
Cookie必然会通过HTTP的Respone传过来,并且Cookie在Respone中的HTTP header中。不管是什么请求框架,必然会存在Respone对象,比如AFNetworking2.x的operation.response,AFNetworking3.x的task.response等等。。。。
1.原生NSURLConnection写法
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 26 27 28 29 30 |
一.获取cookie - (IBAction)cookieTouched:(id)sender { NSURL *url = [NSURL URLWithString:@"http://api.skyfox.org/api-test.php"]; NSURLRequest *request = [NSURLRequest requestWithURL:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:3]; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ //转换NSURLResponse成为HTTPResponse NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; //获取headerfields NSDictionary *fields = [HTTPResponse allHeaderFields];//原生NSURLConnection写法 // NSDictionary *fields = [operation.response allHeaderFields]; //afnetworking写法 NSLog(@"fields = %@",[fields description]); //获取cookie方法1 // NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:fields forURL:url]; //获取cookie方法2 //NSString *cookieString = [[HTTPResponse allHeaderFields] valueForKey:@"Set-Cookie"]; //获取cookie方法3 NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in [cookieJar cookies]) { NSLog(@"cookie%@", cookie); } }]; } |
2.AFNetworking 写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.responseSerializer = [AFCompoundResponseSerializer serializer]; //demo中的api返回的是html数据,不是json [manager POST:@"http://dev.skyfox.org/cookie.php" parameters:nil progress:^(NSProgress * _Nonnull uploadProgress) { } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"\n======================================\n"); NSDictionary *fields = ((NSHTTPURLResponse*)task.response).allHeaderFields; NSLog(@"fields = %@",[fields description]); NSURL *url = [NSURL URLWithString:@"http://dev.skyfox.org/cookie.php"]; NSLog(@"\n======================================\n"); //获取cookie方法1 NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:fields forURL:url]; for (NSHTTPCookie *cookie in cookies) { NSLog(@"cookie,name:= %@,valuie = %@",cookie.name,cookie.value); } NSLog(@"\n======================================\n"); // //获取cookie方法2 // NSString *cookies2 = [((NSHTTPURLResponse*)task.response) valueForKey:@"Set-Cookie"]; // NSLog(@"cookies2 = %@",[cookies2 description]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { }]; |
二.清空Cookie
1 2 3 4 5 |
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; NSArray *cookieArray = [NSArray arrayWithArray:[cookieJar cookies]]; for (NSHTTPCookie *obj in cookieArray) { [cookieJar deleteCookie:obj]; } |
三.手动设置Cookie 手动设置的Cookie不会自动持久化到沙盒
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 |
第一次请求手动设置个cookie -(void)test1:(NSString*)urlString{ NSURL *url = [NSURL URLWithString:@"http://dev.skyfox.org/cookie.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary]; [cookieProperties setObject:@"username" forKey:NSHTTPCookieName]; [cookieProperties setObject:@"my ios cookie" forKey:NSHTTPCookieValue]; [cookieProperties setObject:@"dev.skyfox.org" forKey:NSHTTPCookieDomain]; [cookieProperties setObject:@"dev.skyfox.org" forKey:NSHTTPCookieOriginURL]; [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath]; [cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion]; [cookieProperties setObject:[NSDate dateWithTimeIntervalSinceNow:60*60] forKey:NSHTTPCookieExpires];//设置失效时间 [cookieProperties setObject:@"0" forKey:NSHTTPCookieDiscard]; //设置sessionOnly NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties]; [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; [self.myWebView loadRequest:request]; } //第二次请求会自动带上Cookie - (IBAction)test2:(id)sender { NSURL *url = [NSURL URLWithString:@"http://dev.skyfox.org/cookie.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [self.mywebview2 loadRequest:request]; } |
request还可以这样设置个Cookie
1 2 |
[request setHTTPShouldHandleCookies:YES]; [request setValue:[NSString stringWithFormat:@"%@=%@", [cookie name], [cookie value]] forHTTPHeaderField:@"Cookie"]; |
四.Cookie的本地缓存策略
1 2 3 4 5 |
//NSHTTPCookieAcceptPolicyAlways:保存所有cookie,这个是默认值 //NSHTTPCookieAcceptPolicyNever:不保存任何响应头中的cookie //NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:只保存域请求匹配的cookie [[NSHTTPCookieStorage sharedHTTPCookieStorage]setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyNever]; |
五.Cookie的持久化存储
1.服务器端设置Cookie,以PHP为例
语法
1 |
setcookie(name,value,expire,path,domain,secure) |
参数 | 描述 |
---|---|
name | 必需。规定 cookie 的名称。 |
value | 必需。规定 cookie 的值。 |
expire | 可选。规定 cookie 的有效期。 |
path | 可选。规定 cookie 的服务器路径。 |
domain | 可选。规定 cookie 的域名。 |
secure | 可选。规定是否通过安全的 HTTPS 连接来传输 cookie。 |
1 2 3 |
setcookie("TestCookie","my cookie value"); //没设置失效时间 关闭app后系统不会持久化Cookie setcookie("TestCookie","my cookie value",time()+3600*24); //设置expire失效时间 关闭app后系统自动持久化Cookie |
如果服务器设置了Cookie失效时间expiresDate ,sessionOnly:FALSE会被持久化到文件中,kill掉后系统自动保存,下次启动app会自动加载.binarycookies中的Cookies,以下是一条Cookie输出
1 |
<NSHTTPCookie version:0 name:"TestCookie" value:"my+cookie+value" expiresDate:2016-04-08 09:31:09 +0000 created:2016-04-08 09:30:49 +0000 sessionOnly:FALSE domain:"dev.skyfox.org" path:"/" isSecure:FALSE> |
持久化到了文件中,地址是 沙盒的 /Library/Cookies/org.skyfox.iOS-Cookie.binarycookies
使用终端执行 BinaryCookieReader.py脚本 解析 org.skyfox.iOS-Cookie.binarycookies 结果如下:
1 2 3 4 5 |
Jakey-mini:Cookies Jakey$ python BinaryCookieReader.py org.skyfox.iOS-Cookie.binarycookies #*************************************************************************# # BinaryCookieReader: developed by Satishb3: http://www.securitylearn.net # #*************************************************************************# Cookie : TestPHPWriteCookie=php+write+my+cookie+value; domain=dev.skyfox.org; path=/; expires=Thu, 08 Dec 2016; |
2.app端手动存储Cookie
如果没设置Cookie失效时间expiresDate:(null),sessionOnly:true,kill掉后系统不会自动保存Cookie,如果想持久化Cookie 模仿浏览器存住Cookie,使用NSUserDefaults存下即可,以下是一条Cookie输出
1 |
<NSHTTPCookie version:0 name:"TestCookie" value:"my+cookie+value" expiresDate:(null) created:2016-04-08 09:33:34 +0000 sessionOnly:TRUE domain:"dev.skyfox.org" path:"/" isSecure:FALSE> |
手动保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//合适的时机持久化Cookie - (void)saveCookies{ NSData *cookiesData = [NSKeyedArchiver archivedDataWithRootObject: [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject: cookiesData forKey:@"org.skyfox.cookiesave"]; [defaults synchronize]; } //合适的时机加载持久化后Cookie 一般都是app刚刚启动的时候 - (void)loadSavedCookies{ NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData: [[NSUserDefaults standardUserDefaults] objectForKey: @"org.skyfox.cookiesave"]]; NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in cookies){ NSLog(@"cookie,name:= %@,valuie = %@",cookie.name,cookie.value); } } |
※iOS12以后WKWebView的Cookie已经完全使用WKHTTPCookieStore管理,WKHTTPCookieStore与NSHTTPCookieStorage有着相同的职能
iOS12以后必须使用WKHTTPCookieStore获取allHeaderFields中已经读取不到cookie了
1 2 3 |
WKHTTPCookieStore *cookieStore = webView.configuration.websiteDataStore.httpCookieStore; [cookieStore getAllCookies:^(NSArray* cookies) { }]; |