Ios 在AFN网络中处理304个响应

Ios 在AFN网络中处理304个响应,ios,afnetworking,Ios,Afnetworking,我正试图找出处理来自API服务器的304 Not Modified响应的最佳方法。在每个请求中,如果没有匹配项,则通过覆盖-requestWithMethod:URLString:parameters:error:并设置标头值,在中传递一个etag 在返回304的情况下,我没有得到响应体。在这种情况下,我从核心数据存储中获取缓存数据,并将其返回到GET:methodcompletionhandler中 是否有更好的方法在响应序列化程序中返回缓存的值,或者是否有其他我缺少的最佳实践?我应该缓存原始

我正试图找出处理来自API服务器的304 Not Modified响应的最佳方法。在每个请求中,如果没有匹配项,则通过覆盖
-requestWithMethod:URLString:parameters:error:
并设置标头值,在
中传递一个etag

在返回304的情况下,我没有得到响应体。在这种情况下,我从核心数据存储中获取缓存数据,并将其返回到
GET:
methodcompletionhandler中

是否有更好的方法在响应序列化程序中返回缓存的值,或者是否有其他我缺少的最佳实践?我应该缓存原始200响应中的响应数据吗


欢迎指导。

我认为这在很大程度上取决于您的场景,但您不必自己将数据存储在核心数据中

如果服务器正确响应(看起来是这样的),那么这应该可以透明地使用
NSURLCache

初始请求没有电子标签,服务器返回响应头和响应体
NSURLCache
将注意到响应是可缓存的,并将其存储在内部sqlite缓存数据库中

在下一个请求中,它将发送e-tag,服务器响应304 Not Modified,缓存将为您建立来自缓存数据库的响应。您的回调将收到200响应(您将永远看不到304响应)


在实践中,这是透明的,但我必须始终对其进行监视,以确保其正确缓存,方法是使用或手动检查数据库(您可以在应用程序的缓存目录中找到数据库)。

我使用的应用程序严重依赖于
NSURLCache
。我的一位同事也注意到了这类问题,并通过添加一个
AFURLConnectionOperation+CacheControlBugFix
类别来解决它,该类别也将缓存304s。我搜索了一下,我不确定这是否都是原创的,或者他是否在别处找到了一些,但我找不到原创的来源。以下是类别,您应该将其导入到任何您希望使用它的相关位置,或者导入到您的
AppName Prefix.pch
(如果您希望它无处不在):

AFURLConnectionOperation+CacheControlBugFix.h的内容

#import <Foundation/Foundation.h>
#import "AFURLConnectionOperation.h"

@interface AFURLConnectionOperation (CacheControlBugFix)
@end

我不确定我是否理解“缓存304s”的愿望。如果是304,那么缓存中已经有了内容。我的理解是,@BenScheirman,它只是工作不正常,数据实际上不会从缓存中出来。因此,该类别的名称包括
错误修复
#import "AFURLConnectionOperation+CacheControlBugFix.h"
#import <AFDownloadRequestOperation/AFDownloadRequestOperation.h>

@implementation AFURLConnectionOperation (CacheControlBugFix)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swizzle:@selector(finish) replacement:@selector(da_finish)];
        [self swizzle:@selector(connection:willCacheResponse:) replacement:@selector(da_connection:willCacheResponse:)];
    });
}

- (void)da_finish {
    if ([self isKindOfClass:[AFDownloadRequestOperation class]]) {
        [self da_finish];
        return;
    }

    [self setValue:@(3) forKey:@"state"];

    // Part 1 of fix for 304 URL Caching bug.
    // We force all 200 request and 304 requests to be cached here, so that NSURLConnection's default behavior of not caching is corrected.
    NSHTTPURLResponse *response = (NSHTTPURLResponse *) [self response];
    if ([response isKindOfClass:[NSHTTPURLResponse class]] && [response statusCode] == 200) {
        NSCachedURLResponse *cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:self.responseData];
        NSMutableURLRequest *urlRequest = [self.request mutableCopy];
        urlRequest.cachePolicy = NSURLRequestUseProtocolCachePolicy; // Allow caching of all requests, even ones that have their cache policy set to not allow responses from cache

        // Make sure that we aren't here because the request was canceled. If it was, we do not want to cache.
        if ([self.error code] != NSURLErrorCancelled) {
            [[NSURLCache sharedURLCache] storeCachedResponse:cachedURLResponse forRequest:urlRequest];
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
    });
}

- (NSCachedURLResponse *)da_connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
    if ([self isKindOfClass:[AFDownloadRequestOperation class]]) {
        return [self da_connection:connection willCacheResponse:cachedResponse];
    }
    // Part 2 of fix for 304 URL Caching bug. Since we'll force all 200 requests (as well as 304 requests, which masquerade as 200 in NSURLConnection) to be cached, we don't need NSURLConnection to store it's cache in the normal way.
    return nil;
}

+ (void)swizzle:(SEL)originalSelector replacement:(SEL)swizzledSelector {
        Class class = [self class];
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
}

@end