首页投稿(暂停使用,暂停投稿)

用AFNetworking访问接口时附带多个cookie

2017-11-23  本文已影响344人  revolution丶

问题:

最近在做一个登录相关的迭代开发时,后台对cookie的支持升级,变的更加“标准”,即:由 原来附在请求头的set-cookie是只对应一个value 变成 对应多个value。要求前段和移动端进行适配接收,保存新的set-cookie,并且在其他接口上传该结构的cookie。

分析:

问题分为两大部分,一是接收并解析保存,二是访问其他接口附带上传。因为接收解析相对简单,苹果有专用的NSHTTPCookie类支持,网上也有很多资料,本文就不多赘述,仅仅带一下。关于第二点,笔者百度了很久都没有合适的解决方案,最后还是在和后台的联调中摸索而出,故写本文以作记录。

一、接收,解析,保存

这个比较简单,无论是AFNetworking还是NSHTTPCookie类都简洁易用,直接上代码:

//从AFNetworking的post请求中获得请求头,该头的格式为NSDictionary
//其中operation是指AFHTTPRequestOperation *operation
NSDictionary *allHeaderFieldDict = [operation.response allHeaderFields];

//用NSHTTPCookie直接将请求头中的setCookie转成键值对形式的数组,后面用到。另外说下NSHTTPCookie会自动过滤非setCookie的键值对。
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:allHeaderFieldDict forURL:[NSURL URLWithString:url]];

//用字符串的形式拿到set-Cookie对应的value
NSString *setCookie = [allHeaderFieldDict objectForKey:@"Set-Cookie"];      
这里说下,后台给我的set-Cookie是多个的,多个是个什么概念呢?后台给我了一张图,便于理解 图1.多个set-Cookie.png
是不是感到很疑惑,如果是key-value的形式,众所周知一个Map(或者说是字典)里,key是唯一的,不可能是一个“set-Cookie”作为key对应多个value。验证这一点我们可以打印下上面代码中的setCookie字符串,看取到了什么? 图2.这是setCookie字符串的打印结果 为了方便阅读我把字符串粘出来并对其一下,*为我手动打码
id=*****; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/,
 mobile=***********; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/,
 timestart=2017/11/23 13:48:20; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/,
 timespan=15; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/,
 identifier=85EF24DAF969423EA129C6A15863936B; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/,
 token=ae9721de81f3b6c336ccd94abae9c698; domain=.*******.com; expires=Fri, 08-Dec-2017 05:48:20 GMT; path=/

这里要着重说明三点,这三点在上传时很重要。

看完费劲的字符串,我们再来看下苹果提供的NSHTTPCookie类拿到的优雅的cookie结构,遍历cookies数组打印如下: 图3.NSHTTPCookie类解析的cookies数组打印截图

太长了,截不下,不过不影响理解,从上图我们可以方便的看出图1的格式。而且这中方法比较好的点在于,不在乎后面的一个key对应了多少个value,有几个value数组就有几个元素。像我公司原来的后台就只有1个value还能用字符串去取,现在改成多个了,显然这个方法更利于理解。
接收到,解析完,储存的话,我相信你肯定会存字符串,也肯定会存数组吧。

二、访问时上传

一般的cookie上传如下:

//manager即[AFHTTPRequestOperationManager manager];返回的单例
//cookStr即cookie
[manager.requestSerializer setValue:cookStr forHTTPHeaderField:@"Cookie"];

事实上AFNetworking只有这一个方法将一个键值对加入请求头,同样value自然也必须是字符串
对于我程序中遇到的多个cookie

最后经过调试,返回了如下格式的字符串,*为手动打码

NSString * cookStr = @"id=*****; mobile=***********; timestart=2017/11/23 13:48:20; timespan=15; identifier=85EF24DAF969423EA129C6A15863936B; token=ae9721de81f3b6c336ccd94abae9c698"

注意,id前面与token最后面没有空格,但每个;后面有一个空格。token字符串最后没有;

[manager.requestSerializer setValue:cookStr forHTTPHeaderField:@"Cookie"];

将以上字符放入请求头后,经过请求后台反馈可以解析返回的cookie。

长求总:

如果你的后台需要在请求头里返回一个包含若干个cookie的set-Cookie,你可以按以下格式尝试返回。务必切记字符串中哪里有空格哪里没空格。

NSString *cookStr = @"key1=value1; key2=value2; key3=value3; key4=value4"
[manager.requestSerializer setValue:cookStr forHTTPHeaderField:@"Cookie"];

最后夹带点私货 /滑稽

  1. 这个是将图2字符串处理成最后上传的字符串的方法,按需自取
/**
  *  其中的需要传入参数在本文第一段中有详细代码
  */
-(NSString *)quickLoginMakeCookieWithCookiesArray:(NSArray *)cookies withCookieString:(NSString *)setCookie {
    NSMutableArray *titleArray = [[NSMutableArray alloc] init];
    for (NSHTTPCookie *cookie in cookies) {
        [titleArray addObject:[NSString stringWithFormat:@"%@=",cookie.name]];
    }
    
    NSMutableString *lastString = [[NSMutableString alloc] init];
    for (NSString *str in titleArray) {
        NSRange tokenRange = [setCookie rangeOfString:str];
        NSInteger beginLoc = tokenRange.location+tokenRange.length;
        NSInteger count = 0;
        for (;;) {
            count++;
            NSString *emunStr = [setCookie substringWithRange:NSMakeRange(beginLoc++, 1)];
            if ([emunStr isEqualToString:@";"]) {
                break;
            }
        }
        NSString *valueString = [setCookie substringWithRange:NSMakeRange(tokenRange.location+tokenRange.length, --count)];
        NSString *resultString = [NSString stringWithFormat:@"%@%@",str,valueString];
        
        if ([str isEqualToString:@"id="]) {
            [lastString appendFormat:@"%@",resultString];
        }
        else {
            [lastString appendFormat:@"; %@",resultString];
        }
    }
    return lastString;
}

  1. 解决联调中格式或者参数不对时候的一个小Tip,一般来说后台自己在开发完代码后也会用浏览器插件/模拟器发起一个网络请求来调试代码。当然这个东西也是可以打印参数的。如果搞不定你的发送参数的话可以让他把参数打印出来给你,你对比你发送的参数,就能找到问题的所在了。
上一篇下一篇

猜你喜欢

热点阅读