8

我正在尝试使用临时 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 保存在内存中,以便在同一会话中将它们重用于进一步的请求。

4

2 回答 2

2

看起来临时会话永远不会存储 cookie。eskimo1 在 devforums 上说

ISTR 认为临时会话配置无法按照人们根据文档所期望的方式工作。我从来没有仔细研究过这个,但看起来你有。你应该提交一个关于这个的错误;实施和文档显然不同步,因此需要修复其中之一。

于 2015-04-08T19:38:55.380 回答
1

看起来 iOS9 ephemeralSessionConfiguration 按预期工作。不过,在 iOS8 上,cookie 存储似乎为其策略返回 Never 并且无法重置。尽管有私有类名,但实现似乎没有存储,而不是仅存储。

对于 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 上不需要)。可能有一些错误......我只是需要这个来进行演示,它运行得很好。但是如果出现任何问题,它们应该不会太难修复。

于 2015-11-03T05:41:54.387 回答