我正在尝试使用临时的NSURLSessions为我的应用程序中的多个任务提供单独的cookie处理。这些任务不直接绑定到 UI。问题:无论我做什么,短暂的 NSHTTPCookieStorage 的 cookieAcceptPolicy 仍然是 NSHTTPCookieAcceptPolicyNever。
这是我的代码:
// use a pure in-memory configuration with its own private cache, cookie, and credential store
__block NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
// do anything to accept all cookies
config.HTTPShouldSetCookies = YES;
config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
config.HTTPCookieStorage.cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
__block NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask* task = [session dataTaskWithURL:[NSURL URLWithString:@"https://test.cgmlife.com/Catalogs"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPCookieStorage* cookies = session.configuration.HTTPCookieStorage;
NSLog(@"%@", cookies);
NSLog(@"%lu", cookies.cookieAcceptPolicy);
}];
[task resume];
NSLog 的输出始终为:
Ephemeral <NSHTTPCookieStorage cookies count:0>
1
其中 1 是 NSHTTPCookieAcceptPolicyNever 的值(NSHTTPCookieAcceptPolicyAlways的值为 0)。响应中的标头在那里。
我该怎么做才能让 NSHTTPCookieStorage 在会话处于活动状态时记住我的 cookie?我不需要也不想要任何坚持。我只想将 cookie 保留在内存中,以便在同一会话中将它们重新用于进一步的请求。
看起来短暂的会话永远不会存储cookie。 爱斯基摩人1在开发者论坛上说:
ISTR认为临时会话配置无法正常工作 人们期望基于文档。 我从来没有来得及 详细看这个,但似乎你有。 您应该提交 关于这个的错误;实现和文档清楚地出来了 的同步,因此需要修复其中一个。
看起来iOS9 ephemeralSessionConfiguration按预期工作。 但是,在iOS8上,似乎cookie存储返回其策略的"从不",并且无法重置。 尽管有私有类名,但实现似乎是无存储的,而不是仅内存。
对于 iOS8,我能够替换一个基本的实现,它似乎可以工作(至少在具有轻度测试的模拟器中)。 实现获取任务对象的新方法至关重要。
#import <Foundation/Foundation.h>
@interface MemoryCookieStorage : NSHTTPCookieStorage
@property (nonatomic, strong) NSMutableArray *internalCookies;
@property (atomic, assign) NSHTTPCookieAcceptPolicy policy;
@end
@implementation MemoryCookieStorage
- (id)init
{
if (self = [super init]) {
_internalCookies = [NSMutableArray new];
_policy = NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
}
return self;
}
- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
return self.policy;
}
- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
self.policy = cookieAcceptPolicy;
}
- (NSUInteger)_indexOfCookie:(NSHTTPCookie *)target
{
return [_internalCookies indexOfObjectPassingTest:^BOOL(NSHTTPCookie *cookie, NSUInteger idx, BOOL *stop) {
return ([target.name caseInsensitiveCompare:cookie.name] == NSOrderedSame &&
[target.domain caseInsensitiveCompare:cookie.domain] == NSOrderedSame &&
(target.path == cookie.path || [target.path isEqual:cookie.path]));
}];
}
- (void)setCookie:(NSHTTPCookie *)cookie
{
if (self.cookieAcceptPolicy != NSHTTPCookieAcceptPolicyNever)
{
@synchronized(_internalCookies) {
NSInteger idx = [self _indexOfCookie:cookie];
if (idx == NSNotFound)
[_internalCookies addObject:cookie];
else
[_internalCookies replaceObjectAtIndex:idx withObject:cookie];
}
}
}
- (void)deleteCookie:(NSHTTPCookie *)cookie
{
@synchronized(_internalCookies) {
NSInteger idx = [self _indexOfCookie:cookie];
if (idx != NSNotFound)
[_internalCookies removeObjectAtIndex:idx];
}
}
- (NSArray *)cookies
{
@synchronized(_internalCookies) {
return [_internalCookies copy];
}
}
static BOOL HasCaseSuffix(NSString *string, NSString *suffix)
{
return [string rangeOfString:suffix options:NSCaseInsensitiveSearch|NSAnchoredSearch|NSBackwardsSearch].length > 0;
}
static BOOL IsDomainOK(NSString *cookieDomain, NSString *host)
{
return ([cookieDomain caseInsensitiveCompare:host] == NSOrderedSame ||
([cookieDomain hasPrefix:@"."] && HasCaseSuffix(host, cookieDomain)) ||
(cookieDomain && HasCaseSuffix(host, [@"." stringByAppendingString:cookieDomain])));
}
- (NSArray *)cookiesForURL:(NSURL *)URL
{
NSMutableArray *array = [NSMutableArray new];
NSString *host = URL.host;
NSString *path = URL.path;
@synchronized(_internalCookies)
{
for (NSHTTPCookie *cookie in _internalCookies)
{
if (!IsDomainOK(cookie.domain, host))
continue;
BOOL pathOK = cookie.path.length == 0 || [cookie.path isEqual:@"/"] || [path hasPrefix:cookie.path];
if (!pathOK)
continue;
if (cookie.isSecure && [URL.scheme caseInsensitiveCompare:@"https"] != NSOrderedSame)
continue;
if ([cookie.expiresDate timeIntervalSinceNow] > 0)
continue;
[array addObject:cookie];
}
}
array = (id)[array sortedArrayUsingComparator:^NSComparisonResult(NSHTTPCookie *c1, NSHTTPCookie *c2) {
/* More specific cookies, i.e. matching the longest portion of the path, come first */
NSInteger path1 = c1.path.length;
NSInteger path2 = c2.path.length;
if (path1 > path2)
return NSOrderedAscending;
if (path2 > path1)
return NSOrderedDescending;
return [c1.name caseInsensitiveCompare:c2.name];
}];
return array;
}
- (NSArray *)sortedCookiesUsingDescriptors:(NSArray *)sortOrder
{
return [[self cookies] sortedArrayUsingDescriptors:sortOrder];
}
- (void)getCookiesForTask:(NSURLSessionTask *)task completionHandler:(void (^) (NSArray *taskCookies))completionHandler
{
NSArray *urlCookies = [self cookiesForURL:task.currentRequest.URL];
completionHandler(urlCookies);
}
- (void)setCookies:(NSArray *)newCookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL
{
NSString *host = mainDocumentURL.host;
for (NSHTTPCookie *cookie in newCookies)
{
switch (self.cookieAcceptPolicy)
{
case NSHTTPCookieAcceptPolicyAlways:
[self setCookie:cookie];
break;
case NSHTTPCookieAcceptPolicyNever:
break;
case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
if (IsDomainOK(cookie.domain, host))
[self setCookie:cookie];
break;
}
}
}
- (void)storeCookies:(NSArray *)taskCookies forTask:(NSURLSessionTask *)task
{
NSURL *mainURL = task.currentRequest.mainDocumentURL ?: task.originalRequest.mainDocumentURL ?: task.originalRequest.URL;
[self setCookies:taskCookies forURL:task.currentRequest.URL mainDocumentURL:mainURL];
}
@end
应该可以在创建临时会话后测试sessionConfiguration.HTTPCookieStorage.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever
以查看是否需要将HTTPCookieStorage替换为上述类的实例(在iOS9上不需要它)。 可能有一些错误...我只需要这个来演示,它的效果很好。但是,如果出现任何问题,它们应该不会太难修复。