
因为我Boss可能会看到!(这句话写的是不是有点太明显了?)
开发平台:iOS
语言:OC
新需求的内容如下:
获取淘宝App(以下简称App),点击淘气值之后显示的淘宝评级数据
https://h5.m.taobao.com/app/mconsumer/www/index/index.html
没错,就是这货(至于Fiddler的使用,不是本文讨论内容)
但是一上手我傻眼了,这个网页源码竟然没有想要的数据,我擦嘞,原来是ajax请求,已经好久没有搞过前端代码的我瞬间懵圈了,搞个App开发还是离不开前端知识啊!
https://api.m.taobao.com/h5/mtop.vip.gold.user.info/1.0/?appKey=12574478&t=1470640510077&sign=44b0bcaf92f23777bf00d0097fb6b780&api=mtop.vip.gold.user.info&v=1.0&type=jsonp&dataType=jsonp&callback=mtopjsonp1&data=%7B%7D
这个也就是淘宝自家开发人员写的获取淘宝评级信息的请求API,刚看到这的时候我兴奋了一下,这样的话我就可以直接在加载完这个页面之后get一下这个Api不就可以了??接着在浏览器里面试了一下还真行!然后我就开始打开Xcode开始测试可行性。
就在这时我忽然想的一个很严肃的问题,这个Api是登录淘宝账号之后才会返回信息的,也就是说它必然,依赖于淘宝账号的cookie和缓存数据,那如果我脱离这些之后还可以再获取到数据吗?
想到就做,于是我在HTTP请求工具上面测试了一下,果然不可以,返回的数据是
mtopjsonp1({"api":"mtop.vip.gold.user.info","v":"1.0","ret":["FAIL_SYS_ILLEGAL_ACCESS::非法请求"],"data":{}})
也就是说我的请求是非法的,为毛是非法的呢?后来经过一番研究,发现,其中有两个参数是变化的
t=1470640510077&sign=44b0bcaf92f23777bf00d0097fb6b780
也就是说这两个参数的值是动态的,那他们究竟是什么呢?继续研究...
原来他们分别是token(令牌,不知道什么意思,问百度,或者问你家的后台开发哥哥)和登录账号的验证信息
令牌是由服务器返回或者本地根据某些规则生成的一串数字(一般是前者),验证信息是根据登录账号和密码加密转码的一串字符串
说的太多了,总之我到此算是无能为力了,因为以我的知识范围,我还不知道这个t和sign怎么获取到或者以什么规则生成的?
于是我绕到了另外一个角度去思考这个问题,既然我没办法拼接这个API请求的参数,那我能不能直接获取到这个完整的URL呢?就好像在浏览器的开发者工具上能看到连接地址一样!在App端能不能抓到这个地址?
试试看!于是我查阅了相关的资料(“UIWebView截获ajax请求”,用的谷歌搜索,搜索结果大部分都是英文)
找到一个使用NSURLCache这个类实现本地资源替换网络资源的方法
http://www.cocoawithlove.com/2010/09/substituting-local-data-for-remote.html
其中详细讲解了怎么使用本地图片资源替换获取的网络资源的方法和过程,不过我只需要其中的一部分内容
来吧,下面是Po代码的时间:
在AppDelegate文件中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
调用
MyUrlCache *cache = [[MyUrlCache alloc] init]; [NSURLCache setSharedURLCache:cache];
其中MyUrlCache是我继承自NSURLCache的自定义类,然后我需要在MyUrlCache中重写NSURLCache的一个方法
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
在这个方法里面可以截获到App中所有的请求(包括资源、http、https等)的request,因为所有的请求都会经过这个判断是否有缓存的方法!!
但是问题来了,我使用这个方法获取到了那个ajax请求的完整URL(还是值得兴奋的),然并卵,因为我在这个时机试着get了一下这个URL返回数据依然是"非法的请求"!!
虾米意思?我忙活了这么久,就给个这结果吗?我不甘心呐!于是就继续忙活!终于发现,原来NSURLCache这货居然还有这么一个方法
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request
看到没有,这货竟然有一个参数是cachedResponse,没错,我就是要它,因为这个方法里面有所有请求的respone,也就是说所有的请求的返回数据在这个方法里都可以截获!
牛大发了,赶紧操刀子干起来
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request { if ([request.URL.absoluteString rangeOfString:@"https://api.m.taobao.com/h5/mtop.vip.gold.user.info/2.0"].length > 0) { NSLog(@"%@", [[NSString alloc] initWithData:cachedResponse.data encoding:NSUTF8StringEncoding]); } }
根据我得到的ajax请求的URL(去除QueryString)路径进行过滤,如果是这个URL的话,我就把这个cachedResponse的data数据拿到,然后用NSString进行NSUtf8解码就得到了我想要的结果
终于搞定了,一天的时间,因为期间走了很多的弯路,所以大部分时间是在原地转圈,其实解决问题就是这样,一个问题的研究深度和角度本身就是矛盾体,如果你往一个方向研究的深了,自然也就耽误了去多角度思考问题的时间。权衡利弊,因地制宜。
后来我才发现原来使用NSURLCache的第一个方法获取的那个完整的URL还是可以直接请求的,不过第一次会返回“非法请求”,第二次就正常了,具体原因吗?改天再研究吧,今天搞了一天,头疼!