开发者社区> 问答> 正文

HTTPDNS域名解析场景下如何使用Cookie?(2)



3. 适配策略


适配目的是在使用HTTPDNS服务,可以像通用HTTP请求对Cookie进行存储、匹配和发送,这就需要自行管理使用HTTPDNS服务的HTTP请求的Cookie。

  • 存储,收到服务端返回的HTTP Header Set-Cookie,可以正确解析并存储;
  • 匹配,发送HTTP请求前,可正确搜索匹配Cookie;
  • 发送,将匹配的Cookie放入HTTP请求中发送到服务端。


3.1 iOS适配

  • 根据苹果文档说明,按照以下方式可以改变Cookie接受策略,文档说明默认策略为NSHTTPCookieAcceptPolicyAlways,经测试发现默认策略其实为NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;使用以下方式手动将策略修改为NSHTTPCookieAcceptPolicyAlways,测试发现Accept Cookie Always没有生效,原因需要进一步确定。
NSHTTPCookieStorage *cookieStorage = [ NSHTTPCookieStorage sharedHTTPCookieStorage];[cookieStorage setCookieAcceptPolicy: NSHTTPCookieAcceptPolicyAlways];

  • 实现了简单的HTTPDNS专用的HTTPDNSCookieManager(【注意】此处仅提供Cookie管理的示例,Cookie管理细节如生命周期、匹配规则等不涉及,如有需要可参考RFC 2965),适用于使用HTTPDNS服务的HTTP请求,

  • HTTPDNSCookieManager.h
#ifndef HTTPDNSCookieManager_h#define HTTPDNSCookieManager_h // URL匹配Cookie规则 typedef BOOL (^HTTPDNSCookieFilter)( NSHTTPCookie *, NSURL *); @interface HTTPDNSCookieManager : NSObject+ ( instancetype)sharedInstance; /**指定URL匹配Cookie策略@param filter 匹配器*/- ( void)setCookieFilter:(HTTPDNSCookieFilter)filter; /**处理HTTP Reponse携带的Cookie并存储@param headerFields HTTP Header Fields@param URL 根据匹配策略获取查找URL关联的Cookie@return 返回添加到存储的Cookie*/- ( NSArray< NSHTTPCookie *> *)handleHeaderFields:( NSDictionary *)headerFields forURL:( NSURL *)URL; /**匹配本地Cookie存储,获取对应URL的request cookie字符串@param URL 根据匹配策略指定查找URL关联的Cookie@return 返回对应URL的request Cookie字符串*/- ( NSString *)getRequestCookieHeaderForURL:( NSURL *)URL; /**删除存储cookie@param URL 根据匹配策略查找URL关联的cookie@return 返回成功删除cookie数*/- ( NSInteger)deleteCookieForURL:( NSURL *)URL; @end#endif /* HTTPDNSCookieManager_h */
  • HTTPDNSCookieManager.m
#import <Foundation/Foundation.h>#import "HTTPDNSCookieManager.h" @implementation HTTPDNSCookieManager{HTTPDNSCookieFilter cookieFilter;}- ( instancetype)init { if ( self = [ super init]) { /**此处设置的Cookie和URL匹配策略比较简单,检查URL.host是否包含Cookie的domain字段通过调用setCookieFilter接口设定Cookie匹配策略,比如可以设定Cookie的domain字段和URL.host的后缀匹配 | URL是否符合Cookie的path设定细节匹配规则可参考RFC 2965 3.3节*/cookieFilter = ^ BOOL( NSHTTPCookie *cookie, NSURL *URL) { if ([URL.host containsString:cookie.domain]) { return YES;} return NO;};} return self;}+ ( instancetype)sharedInstance { static id singletonInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!singletonInstance) {singletonInstance = [[ super allocWithZone: NULL] init];}}); return singletonInstance;}+ ( id)allocWithZone:( struct _NSZone *)zone { return [ self sharedInstance];}- ( id)copyWithZone:( struct _NSZone *)zone { return self;}- ( void)setCookieFilter:(HTTPDNSCookieFilter)filter { if (filter != nil) {cookieFilter = filter;}}- ( NSArray< NSHTTPCookie *> *)handleHeaderFields:( NSDictionary *)headerFields forURL:( NSURL *)URL { NSArray *cookieArray = [ NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:URL]; if (cookieArray != nil) { NSHTTPCookieStorage *cookieStorage = [ NSHTTPCookieStorage sharedHTTPCookieStorage]; for ( NSHTTPCookie *cookie in cookieArray) { if (cookieFilter(cookie, URL)) { NSLog( @"Add a cookie: %@", cookie);[cookieStorage setCookie:cookie];}}} return cookieArray;}- ( NSString *)getRequestCookieHeaderForURL:( NSURL *)URL { NSArray *cookieArray = [ self searchAppropriateCookies:URL]; if (cookieArray != nil && cookieArray.count > 0) { NSDictionary *cookieDic = [ NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray]; if ([cookieDic objectForKey: @"Cookie"]) { return cookieDic[ @"Cookie"];}} return nil;}- ( NSArray *)searchAppropriateCookies:( NSURL *)URL { NSMutableArray *cookieArray = [ NSMutableArray array]; NSHTTPCookieStorage *cookieStorage = [ NSHTTPCookieStorage sharedHTTPCookieStorage]; for ( NSHTTPCookie *cookie in [cookieStorage cookies]) { if (cookieFilter(cookie, URL)) { NSLog( @"Search an appropriate cookie: %@", cookie);[cookieArray addObject:cookie];}} return cookieArray;}- ( NSInteger)deleteCookieForURL:( NSURL *)URL { int delCount = 0; NSHTTPCookieStorage *cookieStorage = [ NSHTTPCookieStorage sharedHTTPCookieStorage]; for ( NSHTTPCookie *cookie in [cookieStorage cookies]) { if (cookieFilter(cookie, URL)) { NSLog( @"Delete a cookie: %@", cookie);[cookieStorage deleteCookie:cookie];delCount++;}} return delCount;} @end
  • 使用HTTPDNS处理Cookie示例(使用上述默认简单匹配策略):
- ( void)connectToUrlStringUsingHTTPDNS:( NSString *)urlString { NSURL *url = [ NSURL URLWithString:urlString]; NSURLSessionConfiguration *configuration = [ NSURLSessionConfiguration defaultSessionConfiguration];configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; NSURLSession *session = [ NSURLSession sessionWithConfiguration:configuration delegate: self delegateQueue: nil]; NSMutableURLRequest *request = [ NSMutableURLRequest requestWithURL:url]; NSString *ip = [[HttpDnsService sharedInstance] getIpByHostAsync:url.host]; if (ip) { NSLog( @"Get IP(%@) for host(%@) from HTTPDNS Successfully!", ip, url.host); NSRange hostFirstRange = [urlString rangeOfString:url.host]; if (hostFirstRange.location != NSNotFound) { NSString *newUrlString = [urlString stringByReplacingCharactersInRange:hostFirstRange withString:ip]; NSLog( @"New URL: %@", newUrlString);request.URL = [ NSURL URLWithString:newUrlString];[request setValue:url.host forHTTPHeaderField: @"host"]; // 匹配合适Cookie添加到request中,这里传入的是原生URL[request setValue:[[HTTPDNSCookieManager sharedInstance] getRequestCookieHeaderForURL:url] forHTTPHeaderField: @"Cookie"]; // 删除Cookie[[HTTPDNSCookieManager sharedInstance] deleteCookieForURL:url];}} NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^( NSData *data, NSURLResponse *response, NSError *error) { if (error) { NSLog( @"error: %@", error);} else { NSLog( @"response: %@", response); NSHTTPURLResponse *httpResponse = ( NSHTTPURLResponse *)response; // 解析HTTP Response Header,存储cookie[[HTTPDNSCookieManager sharedInstance] handleHeaderFields:[httpResponse allHeaderFields] forURL:url]; NSLog( @"data: %@", [[ NSString alloc] initWithData:data encoding: NSUTF8StringEncoding]); NSHTTPCookieStorage *cookieStorage = [ NSHTTPCookieStorage sharedHTTPCookieStorage];}}];[task resume];}

3.2 Android适配

  • 使用如下方式HTTPDNS解析"http://test.com" 域名进行访问,
String urlStr = "http://test.com"; // HTTPDNS解析"test.com"域名,发HTTP请求访问 new DownloadWebPageTask().execute(urlStr); private class DownloadWebPageTask extends AsyncTask<String, Void, String> {@Overrideprotected String doInBackground( String... params) { try { return downloadUrl(params[ 0]);} catch (IOException e) {e.printStackTrace();} return null;}@Overrideprotected void onPostExecute( String result) { if (result != null) {Log.e(TAG, "Get response: " + result);} else {Log.e(TAG, "Get response error.");}}} private String downloadUrl( String urlStr) throws IOException { try {URL url = new URL(urlStr);conn = (HttpURLConnection) url.openConnection(); String ip = httpDnsService.getIpByHostAsync(urlStr); if (urlStr.equals(url2)) {ip = IP;} if (ip != null) {Log.d(TAG, "Get IP: " + ip + " for host: " + url.getHost() + " from HTTPDNS successfully!"); String new UrlStr = urlStr.replaceFirst(url.getHost(), ip);conn = (HttpURLConnection) new URL( new UrlStr).openConnection();conn.setRequestProperty( "Host", url.getHost());}conn.setConnectTimeout( 1000 * 15);int responseCode = conn.getResponseCode(); if (responseCode == 200) {Log.i(TAG, "Reponse code is 200.");dis = new DataInputStream(conn.getInputStream());int len;byte[] buff = new byte[ 4096];StringBuilder response = new StringBuilder(); while ((len = dis.read(buff)) != -1) {response.append( new String(buff, 0, len));} return response.toString();} else {Log.e(TAG, "Response code is " + responseCode); return null;}} catch (MalformedURLException e) {e.printStackTrace();} return null;}
  • CookieManager配置如下:
/***  配置cookie manager*/ private void setCookieHandler() { /***  指定cookie存储policy*  系统已定义策略有:*  CookiePolicy.ACCEPT_ALL,存储全部cookie*  CookiePolicy.ACCEPT_NONE,不存储cookie*  CookiePolicy.ACCEPT_ORIGINAL_SERVER,按照RFC 2965 3.3节标准域名匹配存储cookie* */cookieManager.setCookiePolicy( new CookiePolicy() {@Override public boolean shouldAccept(URI uri, HttpCookie cookie) { // 为方便测试,此处都返回true,存储全部cookie Log.i( TAG, "Uri: " + uri.toString() + ", cookie: " + cookie.toString() + ", domain: " + cookie.getDomain()); return true;}});CookieHandler.setDefault(cookieManager);  }
  • 使用CookieManager管理App的Cookie缓存,当对应Cookie满足策略存储到本地时,针对使用HTTPDNS域名解析进行HTTP访问的场景,不用修改即可完成适配。
  • 基于HTTPDNS访问http://test.com,获取到Cookie如下,shouldAccept()返回true后网络库自动缓存该Cookie;
name1 = value1;expires = Wed, 15-Nov- 17 15: 41: 02 GMT;path = /;domain = .test.com;
  • Cookie存储时,该Cookie直接和访问的URL(http://201.87.1.125)相关联,并且Cookie的domain为test.com;所以,再次使用HTTPDNS服务防伪URL(http://201.87.1.125)时,系统可自动获取到该Cookie。Cookie存储后可按照下面代码测试,基于域名/IP的URL查询缓存Cookie,都可以正确获取该Cookie,因此使用HTTPDNS服务时可自动完成适配。
String url1 = "http://test.com"; String url2 = "http://201.87.1.125";CookieStore cookieStore = cookieManager.getCookieStore(); try {Log.e(TAG, "store cookie is " + cookieStore. get( new URI(url1)));Log.e(TAG, "store cookie is " + cookieStore. get( new URI(url2)));} catch (URISyntaxException e) {e.printStackTrace();}

展开
收起
猫饭先生 2017-10-20 11:15:22 2441 0
0 条回答
写回答
取消 提交回答
问答排行榜
最热
最新

相关电子书

更多
域名大数据的应用 立即下载
“域”见更美好的未来——域名筑梦互联网+ 立即下载
“域”感——《域名投资从入门到精通》 立即下载

相关镜像