ios htttp网络请求cookie的读取与写入(NSHTTPCookieStorage)【转】
当你访问一个网站时,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的读取与写入:
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
|
[[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
|
1
2
3
4
5
|
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookieArray = [NSArray arrayWithArray:[cookieJar cookies]];
for (id 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://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
|
1
2
|
[request setHTTPShouldHandleCookies:YES];
[request setValue:[NSString stringWithFormat:@"%@=%@", [cookie name], [cookie value]] forHTTPHeaderField:@"Cookie"];
|
四.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>
|
手动保存
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//合适的时机保存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];
}
}
|
一些说明:
- 通过UIWebView登录后,会自动得到web服务器设置的cookie包括服务器中的seesionid。
- cookie不会自动保存在app里面,需要通过设置才能在下次启动app时获取。
- 自动登录,需要设置header,才能将cookie带给web服务器。
- 自动登录,需要web服务器端进行cookie验证方可登录。
实现流程:
NSHTTPCookieStorage *myCookie = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [myCookie cookies]) {
NSLog(@"%@", cookie);
}
NSHTTPCookieStorage *myCookie = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [myCookie cookies]) {
NSLog(@"%@", cookie);
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; // 保存
}
3. 自动登录时,需要将上次保存的cookie取出来设置header拿给web服务器,代码如下。
// 寻找URL为HOST的相关cookie,不用担心,步骤2已经自动为cookie设置好了相关的URL信息
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:HOST]]; // 这里的HOST是你web服务器的域名地址
// 比如你之前登录的网站地址是abc.com(当然前面要加http://,如果你服务器需要端口号也可以加上端口号),那么这里的HOST就是http://abc.com
// 设置header,通过遍历cookies来一个一个的设置header
for (NSHTTPCookie *cookie in cookies){
// cookiesWithResponseHeaderFields方法,需要为URL设置一个cookie为NSDictionary类型的header,注意NSDictionary里面的forKey需要是@"Set-Cookie"
NSArray *headeringCookie = [NSHTTPCookie cookiesWithResponseHeaderFields:
[NSDictionary dictionaryWithObject:
[[NSString alloc] initWithFormat:@"%@=%@",[cookie name],[cookie value]]
forKey:@"Set-Cookie"]
forURL:[NSURL URLWithString:HOST]];
// 通过setCookies方法,完成设置,这样只要一访问URL为HOST的网页时,会自动附带上设置好的header
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:headeringCookie
forURL:[NSURL URLWithString:HOST]
mainDocumentURL:nil];
}
4. web服务器验证app带过来的cookie信息,来完成登录。
如果访问的页面没有cookie验证的代码,那么就访问那些*loginAction之类有验证cookie的页面再跳转,或者告诉同事在你访问的那个页面加个cookie验证登录的就行了。


浙公网安备 33010602011771号