【问题标题】:NSURLProtocol. requestIsCacheEquivalent never calledNSURL 协议。 requestIsCacheEquivalent 从未调用过
【发布时间】:2015-03-17 17:33:13
【问题描述】:

我不确定这里的交易是什么,但功能:

class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool

在我的 NSURLProtocol 子类中从未调用过。我什至见过使用缓存的情况(通过使用网络代理进行验证并且没有看到任何调用),但是这个方法永远不会被调用。我不知道为什么会这样。

我要解决的问题是我有一些要缓存数据的请求,但这些请求的签名参数对于每个请求都不同(有点像随机数)。这使得尽管数据相同,但缓存键并不相同。

详细说明:

  1. 我发出一个带有自定义签名的请求(如下所示: www.example.com?param1=1&param2=2&signature=1abcdefabc312093)
  2. 请求返回一个 Etag
  3. Etag 应该由 NSURLCache 管理,但因为它认为正在发出不同的请求 (www.example.com?param1=1&param2=2&signature=1abdabcda3359809823),所以它不会打扰。

我认为使用 NSURLProtocol 可以解决我所有的问题,因为 Apple 的文档说:

class func requestIsCacheEquivalent(_ aRequest: NSURLRequest,
                      toRequest bRequest: NSURLRequest) -> Bool

如果 aRequest 和 bRequest 对于缓存目的是等效的,则为是,否 否则。出于缓存目的,请求被认为是等效的,如果 并且仅当它们将由相同的协议处理并且 协议在执行后声明它们等效 特定于实现的检查。

遗憾的是,该函数从未被调用。不知道是什么问题...

class WWURLProtocol : NSURLProtocol, NSURLSessionDataDelegate {
var dataTask: NSURLSessionDataTask?
var session: NSURLSession!
var trueRequest: NSURLRequest!

private lazy var netOpsQueue: NSOperationQueue! = NSOperationQueue()
private lazy var delegateOpsQueue: NSOperationQueue! = NSOperationQueue()

override class func canInitWithRequest(request: NSURLRequest) -> Bool {
    println("can init with request called")
    return true
}

override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
    println("canonical request for request called")
    return request
}

override class func requestIsCacheEquivalent(a: NSURLRequest, toRequest b: NSURLRequest) -> Bool     {
    // never ever called?!?
    let cacheKeyA = a.allHTTPHeaderFields?["CacheKey"] as? String
    let cacheKeyB = b.allHTTPHeaderFields?["CacheKey"] as? String

    println("request is cache equivalent? \(cacheKeyA) == \(cacheKeyB)")

    return cacheKeyA == cacheKeyB
}

override func startLoading() {
    println("start loading")

    let sharedSession = NSURLSession.sharedSession()
    let config = sharedSession.configuration
    config.URLCache = NSURLCache.sharedURLCache()
    self.session = NSURLSession(configuration: config, delegate: self, delegateQueue: self.delegateOpsQueue)

    dataTask = session.dataTaskWithRequest(request, nil)
    dataTask?.resume()
}

override func stopLoading() {
    println("stop loading")
    dataTask?.cancel()
}


//SessionDelegate

func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
    println("did become invalid with error")
    client?.URLProtocol(self, didFailWithError: error!)
}


func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
    println("did complete with error")
    if error == nil {
        client?.URLProtocolDidFinishLoading(self)
    } else {
        client?.URLProtocol(self, didFailWithError: error!)
    }
}

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
    println("did receive response")
    client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .Allowed)
    completionHandler(.Allow)
}

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
    println("did receive data called")
    client?.URLProtocol(self, didLoadData: data)
}

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse!) -> Void) {
    println("will cache response called")
    client?.URLProtocol(self, cachedResponseIsValid: proposedResponse)

    completionHandler(proposedResponse)
}

我在我的应用委托中注册了如下协议:

NSURLProtocol.registerClass(WWURLProtocol.self)

我触发协议如下:

@IBAction func requestData(endpointString: String) {
    let url = NSURL(string: endpointString)
    let request = NSMutableURLRequest(URL: url!)
    var cacheKey = endpointString
    request.setValue("\(endpointString)", forHTTPHeaderField: "CacheKey")
    request.cachePolicy = .UseProtocolCachePolicy

    NSURLConnection.sendAsynchronousRequest(request, queue: netOpsQueue) { (response, data, error) -> Void in
        if data != nil {
            println("succeeded with data:\(NSString(data: data, encoding: NSUTF8StringEncoding)))")
        }
    }

}

【问题讨论】:

    标签: ios caching nsurlsession nsurlcache nsurlprotocol


    【解决方案1】:

    我认为在实践中,加载系统只是将规范化的 URL 用于缓存目的,并进行直接的字符串比较。不过,我不确定。尝试在规范化时附加您的 nonce,以某种易于移除/可检测的形式(以防它已经存在)。

    【讨论】:

      【解决方案2】:

      您的代码似乎没问题。您只需关注 Apple 关于URLProtocol 的文档即可。您可以尝试使用URLSession,因为在较新的iOS 版本中不推荐使用NSURLConnection。祝您好运。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-15
        • 1970-01-01
        • 2019-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-13
        相关资源
        最近更新 更多