来自服务器的所有 HTTP 响应都带有 header ,通知我们的应用不要缓存响应:
Cache-Control: no-cache
Pragma: no-cache
Expires: 0
因此,如果您使用默认缓存策略“NSURLRequestUseProtocolCachePolicy”发出 NSUrlRequests,那么应用程序将始终从服务器加载数据。但是,我们需要缓存响应,显而易见的解决方案是将这些 header 设置为某个时间,例如(在后端),设置为 10 秒。但我对如何绕过此策略并将每个请求缓存 10 秒的解决方案感兴趣。
为此你需要设置共享缓存。这可能在 AppDelegate didFinishLaunchingWithOptions 中完成:
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
然后,我们需要嵌入我们的代码来强制缓存响应。如果您使用 AFHttpClient 的实例,则可以通过覆盖以下方法并将缓存手动存储到共享缓存中来完成:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse {
NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];
NSMutableData *mutableData = [[cachedResponse data] mutableCopy];
NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;
// ...
return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
data:mutableData
userInfo:mutableUserInfo
storagePolicy:storagePolicy];
}
最后一件事是为请求设置 cachePolicy。在我们的例子中,我们希望为所有请求设置相同的缓存策略。再次强调,如果您使用 AFHttpClient 的实例,则可以通过覆盖以下方法来完成:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters {
NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters];
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
return request;
}
到目前为止一切顺利。 “NSURLRequestReturnCacheDataElseLoad”使得第一次执行请求并在所有其他时间从缓存加载响应。问题是,不清楚如何设置缓存过期时间,比如10秒。
最佳答案
您可以实现一个自定义的 NSURLCache,它只返回尚未过期的缓存响应。
例子:
#import "CustomURLCache.h"
NSString * const EXPIRES_KEY = @"cache date";
int const CACHE_EXPIRES = -10;
@implementation CustomURLCache
// static method for activating this custom cache
+(void)activate {
CustomURLCache *urlCache = [[CustomURLCache alloc] initWithMemoryCapacity:(2*1024*1024) diskCapacity:(2*1024*1024) diskPath:nil] ;
[NSURLCache setSharedURLCache:urlCache];
}
-(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
NSCachedURLResponse * cachedResponse = [super cachedResponseForRequest:request];
if (cachedResponse) {
NSDate* cacheDate = [[cachedResponse userInfo] objectForKey:EXPIRES_KEY];
if ([cacheDate timeIntervalSinceNow] < CACHE_EXPIRES) {
[self removeCachedResponseForRequest:request];
cachedResponse = nil;
}
}
return cachedResponse;
}
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request {
NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary];
[userInfo setObject:[NSDate date] forKey:EXPIRES_KEY];
NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];
[super storeCachedResponse:newCachedResponse forRequest:request];
}
@end
如果这不能给你足够的控制权,那么我将使用如下所示的 startLoading 方法实现自定义 NSURLProtocol,并将其与自定义缓存结合使用。
- (void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:@"CacheSet" inRequest:newRequest];
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
if (cachedResponse) {
[self connection:nil didReceiveResponse:[cachedResponse response]];
[self connection:nil didReceiveData:[cachedResponse data]];
[self connectionDidFinishLoading:nil];
} else {
_connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
}
一些链接:
关于ios - 绕过 http 响应头 Cache-Control : how to set cache expiration?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19840688/
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
我正在使用Heroku(heroku.com)来部署我的Rails应用程序,并且正在构建一个iPhone客户端来与之交互。我的目的是将手机的唯一设备标识符作为HTTPheader传递给应用程序以进行身份验证。当我在本地测试时,我的header通过得很好,但在Heroku上它似乎去掉了我的自定义header。我用ruby脚本验证:url=URI.parse('http://#{myapp}.heroku.com/')#url=URI.parse('http://localhost:3000/')req=Net::HTTP::Post.new(url.path)#boguspara