关于request.HTTPBody一点思考

大情景

1 公司最近准备上线银行存管,相关的对接都已完成,现在进入测试尾声,准备近期发布新版上线。
2 存管相关目前都是通过加载h5,主要包括银行开户,充值,提现,投标等大功能模块。(细节很多,就不在这里说了)
3 对h5结果处理大概逻辑:存管页面成功之后会返回一个结果url,客户端截取到这个url,再做相应的处理,例如:投资成功就跳转到投资成功结果展示页,充值成功就跳转到充值结果倒计时页面等等(看需求,具体问题再具体处理)
4 基于之前需要更改uiwebview中ajax请求,程序中使用了NSURLProtocol(这是个抽象类,不可以被实例化)的子类,结果url的拦截就是在该类的canonicalRequestForRequest的方法进行的。

问题

当用户点击投标,跳转到投标存管页面输入交易密码等一系列操作完成之后,测试发现不管是投资成功还是投资失败(交易密码错误次数过多,账户被冻结),存管发的结果链接都是一样的,也就是说不管是投资成功还是失败,只要用户结束h5页面的操作,回到客户端本地时都是投资成功的页面,这显然是不对的。

解决方案

和领导沟通之后,决定如下解决:
步骤一,客户端拦截获取request.HTTPBody,从而截取结果url的tm和data值;
步骤二,请求接口将tm和data发送给后台;
步骤三,后台解密tm和data的到操作状态(成功或者失败),再返回给客户端
步骤四,客户端获得后台结果,成功则到本地投资成功页,失败则到申购页并toast 投资失败

意外情况:
1 h5投标页,当交易密码错误次数过多账号被冻结时,存管那边tm和data返回空
准备当tm和data为空的时候,客户端判断为冻结情况,但是发现出来 2 意外情况
2 发现程序能拦截到2次结果url,第一次有值,第二次没值
处理过程:
步骤一, Charles抓包发现,h5确实只发了一个请求(提醒同事是不是NSURLProtocol的问题?)
步骤二, 同事尝试使用uiwebview的shouldStartLoadWithRequest代理来截取结果url,发现真的只发了一次请求,确实是NSURLProtocol的问题

最终解决

在uiwebview的shouldStartLoadWithRequest中拦截结果url,截取request.HTTPBody,从而得到tm和data值,发送通知相应页面处理。充值模块大概代码如下(具体需求具体分析,我们项目大概逻辑是这样的):

//处理充值完成结果(成功和失败返回的url一样问题)
    if ([request.URL.absoluteString rangeOfString:DepositeCharge].length > 0)
    {
        NSString *HTTPBodyString = [[NSString alloc] initWithData:request.HTTPBody  encoding:NSUTF8StringEncoding];
        NSMutableDictionary *payResultInfo = [NSMutableDictionary dictionaryWithCapacity:1];
        [payResultInfo setObject:HTTPBodyString forKey:@"HTTPBodyString"];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"DepositRechargeResultNotification" object:nil userInfo:payResultInfo];
    }

相应页面处理逻辑:

  //监听充值返回结果通知,放在viewdidload里面
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doResult:) name:@"DepositRechargeResultNotification" object:nil];


- (void)doResult:(NSNotification *)sender{
    NSDictionary *dic = sender.userInfo;
    NSString *httpBodyString = [dic objectForKey:@"HTTPBodyString"];
    if (!(httpBodyString.length>0)) {
        //交易密码错误累计5次账号被冻结之后,返回的url的httpBody tm和data都为空,此时客户端做的处理
        [self.navigationController popToRootViewControllerAnimated:NO];
        return;
    }
    else{
        [[PersonalCenterLogicManager sharedInstance] reqResultInfoWithHttpBody:httpBodyString Success:^(id model) {
            NSLog( @" 充值结果返回%@",model);
            
            NSDictionary *dataDic= [model objectForKey:@"data"];
            if ([[dataDic objectForKey:@"status" ]isEqualToString:@"S"]) {
                //充值成功跳到充值过渡页
                [self.navigationController pushViewController:[[ChargeSuccessVC alloc] initWithTitle:@"充值结果"] animated:NO];
            }
            else {
                //失败回到充值页面
                [self.navigationController popViewControllerAnimated:NO];
                [MBProgressHUD showError:[dataDic objectForKey:@"msg"]];
            }

        } failure:^(NSError *err) {
            [MBProgressHUD showError:ServerError];
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self.navigationController popToRootViewControllerAnimated:NO];
            });
        }];
    }
}

编码问题

上面说到客户端截取结果url,之后获取tm和data值发送给后台,
开始我们是如下得到其值,之后解析并获取相应的tm和data值,AFN以post方式将两个参数传到后台,发现不行

NSString *HTTPBodyString = [[NSString alloc] initWithData:request.HTTPBody  encoding:NSUTF8StringEncoding];

问题:
1 后台接收到值,无法解析(后台接收的值和客户端发送的值是否一致?若一致,后台解析问题或者压根这样的值是无法解析的;若不一致,说明这个请求的方式是否有问题?AFN post请求过程中 一些字符被自动转义了?。同事开发,具体情况不是很清楚,猜测应该是这样。)
2 程序里如何获取Charles抓包时Contents里面Form格式的数据,如下图:

而不是Text格式或者Raw格式(这些格式下面会发现有%2F %2B %3D %2B等转义字符),上述代码得到就是这种格式。如下:

网上搜了很多,最终如下获取:

NSString *HTTPBodyString = [[[NSString alloc] initWithData:request.HTTPBody  encoding:NSUTF8StringEncoding] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

3 最后同事那边跟后台调试之后,是以afn post方式,参数追加到url后面,真正参数为nil发送请求,ok。(有点乱,待调)

总结

不管什么问题,最终总有解决的办法(不管是去解决这个问题,还是通过别的方案去绕开这个问题),而我们需要的是静下心来分析,尽量从多个方面去分析(例如上面说到的程序截取到2次请求问题,也许我们会去让后台找原因,让他们不要发两次请求,当然这也是在解决问题。但同时我们也要想,是不是客户端这边的问题,是不是拦截的框架自己有问题呢,所以通过抓包,我们最后发现,后台确实只发了一次请求,是客户端截取url的框架自身问题。那个编码问题也是如此)

附:
以下是截取子串常用方法,先记录在这里,备以后需要,哈哈

    NSString *strBody = [[NSString alloc]initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
    NSLog(@"request.allHTTPbody = %@",strBody);
    if ([request.URL.absoluteString rangeOfString:DepositRecharge].length > 0)
    {
        NSRange rangeAnd = [strBody rangeOfString:@"&"];
        if (rangeAnd.length > 0) {
            //substringFromIndex:截取从location开始到结束,包括location位置上的字符
            NSString *strData = [strBody substringFromIndex:rangeAnd.location+1];
            //substringToIndex:截取开始到location,不包括loacation位置上的字符
            NSString *strTm = [strBody substringToIndex:rangeAnd.location];
            NSLog(@"tm = %@",[strTm substringWithRange:NSMakeRange(3, strTm.length-3)]);
            NSLog(@"data = %@",[strData substringWithRange:NSMakeRange(5, strData.length-5)]);
        }
    }

后续问题记录

NSURLProtocol h5 post请求变成get请求问题

具体问题:h5页面发送post请求,抓包确实也是post请求 但经过客户端之后就变成了get请求。
客户端对h5的处理:
基于有的活动h5页面,需要判断用户登录状态 从而显示相应的信息。此时h5链接会含有某个标识字符串(例如:auth 字符串),当客户端截取到该字段,会拦截该请求 添加token信息,之后再重新发送该请求。(基于webview不能拦截所有的请求,故项目使用NSURLProtocol子类来拦截请求)
最终解决:
通过不断的调试和分析,发现是因为之前的处理是 不管是get请求还是post请求,token信息一律都是追加到url后面。 我们只要对get和post做分别处理,get请求追加在url后,post请求追加在body里面,如此处理即可。代码如下:

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    NSString *strURL = request.URL.absoluteString;
    //h5 ajax请求中含authentication,截取token信息后重定向
    if (([strURL rangeOfString:@"auth"].length > 0) &&
        ([request.HTTPMethod rangeOfString:@"POST"].length > 0)) {
        NSString *strBody = [[NSMutableString alloc]initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
        [mutableReqeust setHTTPBody: [[StaticTools addParaWithOriginUrl:strBody] dataUsingEncoding: NSUTF8StringEncoding]];
    }
    if (([strURL rangeOfString:@"auth"].length > 0) &&
        ([request.HTTPMethod rangeOfString:@"GET"].length > 0))
    {
        NSString *str = [StaticTools addParaWithOriginUrl:strURL];
        mutableReqeust = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str]];
    }
    
    return mutableReqeust;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,376评论 25 707
  • iOS网络编程读书笔记 Facade Tester客户端门面模式的实例(被动版本化) 被动版本化,所以硬编码URL...
    melouverrr阅读 1,598评论 3 7
  • 年少轻狂无知,谁不曾有; 谁的青春会返?花蕾未开已遮阳,花又如何长? 青春说会飞扬,那折断翅的鸟又如何飞翔? 一沓...
    杨翎阅读 193评论 0 0
  • 向日葵1118阅读 136评论 0 0