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

问题:

最近在做一个登录相关的迭代开发时,后台对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=/

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

  • OC中key-value是标准的一对一,所以后台发的图1那种形式被转成了图2的样子。其vaule是包含上图所有value的字符串,这个字符串的格式很重要!!!
  • 我进行了换行操作,分成了6行,注意从第二行开始位置错了一个空格。这不是我要逼死强迫症的操作,而是原字符串在第一行结尾和第二行开头中间本来就有一个空格。我实在想不出怎么体现这个空格就出此下策。要是还不信你就仔细看图2里面是不是真的有空格。为什么说这么多废话强调一个空格,因为格式很重要!!!
  • 还是格式问题,每个;和,的后面空格,仔细观察。格式很重要!!!

看完费劲的字符串,我们再来看下苹果提供的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

  • 我考虑过将几个键值对变成字典然后用上面的方法放入请求头,但显然字典不符合value必须是String的设定。
  • 然后我有考虑将字典转成JSONString放入value,但后台拿到的是带有转义字符的字符串,无法解析。
  • 如果将cookie分别以自己的key(比如id,mobile,timestart等)分别加入HTTPHeaderField又不符合后台的标准化需求。
  • 后台反复强调将cookie以发送给我的方式返回,经过再三调试和思考,发现拿到的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,一般来说后台自己在开发完代码后也会用浏览器插件/模拟器发起一个网络请求来调试代码。当然这个东西也是可以打印参数的。如果搞不定你的发送参数的话可以让他把参数打印出来给你,你对比你发送的参数,就能找到问题的所在了。
  • 最后,若有错误,恳请斧正。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • iOS网络编程读书笔记 Facade Tester客户端门面模式的实例(被动版本化) 被动版本化,所以硬编码URL...
    melouverrr阅读 1,602评论 3 7
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,225评论 0 4
  • 百分之九十九的失败根源是懒!
    小磊陈读阅读 132评论 0 0
  • 如果把写作比作一个工具,也就是一个工具类产品,这个工具是用于整理用户的想法和思考,并将其变成可传播的文字内容,就像...
    武明Ray阅读 139评论 0 0