當你訪問一個網站時,NSURLRequest都會幫你主動記錄下來你訪問的站點設置的Cookie,如果 Cookie 存在的話,會把這些信息放在 NSHTTPCookieStorage 容器中共享,當你下次再訪問這個站點時,NSURLRequest會拿着上次保存下來了的Cookie繼續去請求。
同樣適用於ASIHTTPRequest,AFNetworking, Webview等,Cookie常用於一些基於認證的網絡請求
認識下NSHTTPCookieStorage
NSHTTPCookieStorage 實現了一個管理cookie的單例對象(只有一個實例),每個Cookie都是NSHTTPCookie類的實例,最為一個規則,Cookie在所有應用之間共享並在不同進程之間保持同步。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寫法
一.獲取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 寫法
[[APIClient sharedClient] postPath:@"http://api.skyfox.org/api-test.php" parameters:p success:^(AFHTTPRequestOperation *operation, id JSON) { NSDictionary *fields = [operation.response allHeaderFields]; //afnetworking寫法 NSLog(@"fields = %@",[fields description]); NSURL *url = [NSURL URLWithString:@"http://api.skyfox.org/api-test.php"]; //獲取cookie方法1 NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:fields forURL:url]; //獲取cookie方法2 //NSString *cookieString = [[HTTPResponse allHeaderFields] valueForKey:@"Set-Cookie"]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
二.清空Cookie
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; NSArray *cookieArray = [NSArray arrayWithArray:[cookieJar cookies]]; for (id obj in cookieArray) { [cookieJar deleteCookie:obj]; }
三.手動設置Cookie 手動設置的Cookie不會自動持久化到沙盒
第一次請求手動設置個cookie -(void)test1:(NSString*)urlString{ NSURL *url = [NSURL URLWithString:@"http://api.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:@"api.skyfox.org" forKey:NSHTTPCookieDomain]; [cookieProperties setObject:@"api.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://api.skyfox.org/cookie.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [self.mywebview2 loadRequest:request]; }
request還可以這樣設置個Cookie
[request setHTTPShouldHandleCookies:YES]; [request setValue:[NSString stringWithFormat:@"%@=%@", [cookie name], [cookie value]] forHTTPHeaderField:@"Cookie"];
四.Cookie的本地緩存策略
//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:"api.skyfox.org" path:"/"isSecure:FALSE>
|
持久化到了文件中,地址是 沙盒的 /Library/Cookies/org.skyfox.AFNetworking-demo.binarycookies
使用BinaryCookieReader.py腳本 解析 org.skyfox.AFNetworking-demo.binarycookies 結果如下
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:"api.skyfox.org" path:"/" isSecure:FALSE>
|
手動保存
//合適的時機保存Cookie - (void)saveCookies{ NSData *cookiesData = [NSKeyedArchiver archivedDataWithRootObject: [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject: cookiesData forKey: @"org.skyfox.cookie"]; [defaults synchronize]; } //合適的時機加載Cookie 一般都是app剛剛啟動的時候 - (void)loadCookies{ NSArray *cookies = [NSKeyedUnarchiver unarchiveObjectWithData: [[NSUserDefaults standardUserDefaults] objectForKey: @"org.skyfox.cookie"]]; NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in cookies){ [cookieStorage setCookie: cookie]; } }