【问题标题】:Alamofire 4 Swift Cache Control - HTTP Statuscode 304 (If Modified Since)Alamofire 4 Swift 缓存控制 - HTTP 状态码 304(如果修改后)
【发布时间】:2017-08-04 22:52:30
【问题描述】:

当我从服务器收到 HTTP 状态代码 304 时,服务器不会发送任何内容数据,因为没有任何变化。

现在我想使用 Alamofire 4 中的缓存控件(用于 Swift 3)。但我无法弄清楚它是如何工作的。我找到了一些 Alamofire 3 here 的示例

 Alamofire.request(req)
    .response {(request, res, data, error) in
        let cachedURLResponse = NSCachedURLResponse(response: res!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
        NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)
    }

所以我认为 Alamofire 4 中的结构会相似。但是我的内容保存在哪里?我希望我能做这样的事情

伪代码:

if response.statusCode == 304 {
   return cacheControl.response
}

有人有想法吗? 怀疑是我自己写的。

【问题讨论】:

  • 你好,我也有同样的问题..你是怎么解决的?谢谢。
  • 在下面查看我的答案

标签: ios swift caching alamofire


【解决方案1】:

如果状态码是 304,我设法恢复了旧的缓存内容,如下所示:

let sessionManager: SessionManager = {
    let configuration = URLSessionConfiguration.default
    configuration.requestCachePolicy = .reloadIgnoringCacheData
    configuration.timeoutIntervalForRequest = 60
    let memoryCapacity = 500 * 1024 * 1024; // 500 MB
    let diskCapacity = 500 * 1024 * 1024; // 500 MB
    let cache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "shared_cache")
     configuration.urlCache = cache
    return SessionManager(configuration: configuration)
}()

func getData(url:URLConvertible,completionHadler:@escaping(Data?,ErrorMessage?)->Void){

    let headers: HTTPHeaders =
    [   "Authorization":token!,
    "Accept": "application/json",
    "if-None-Match":  self.loadEtagUserDefault(keyValue: "Etag")
  ]


  self.sessionManager.request(url, method: .get, parameters:nil, headers: headers)

  .validate()

  .responseJSON { (response) in

    switch (response.result) {
    case .success:

      // SAVE THE RESPONSE INSIDE THE CACHE

      self.saveCache(response)

      //---

      if let unwrappedResponse = response.response {
        _ = unwrappedResponse.statusCode
      }
      // If all went well, I'll return the date
         // Recovery Etag from the Header
      let etag =  response.response?.allHeaderFields["Etag"] as? String
      //update in memoria Etag
      self.saveEtagUserDefault(etagValue: etag!, key: "Etag")

      print("stato codice: \(String(describing: response.response?.statusCode))")

      completionHadler(response.data,nil)


      break
    case .failure(let error):
      print(error.localizedDescription)
      let statusCode = response.response?.statusCode
      let url1:URLRequest? = try! response.request?.asURLRequest()

      //Nel caso lo status code è nil perciò il sito non e raggiungibile restituisce la vecchia cache
      guard let _ = statusCode else {

        let dataOld = self.loadOldDataCache(url: url1!)
        completionHadler(dataOld,nil)

        return
      }
    // If the status code is 304 (no change) I return the old cache
      if statusCode == 304 {

        print("beccato codice 304 ***")
        let dataOld = self.loadOldDataCache(url: url1!)
        guard let _ = dataOld else {
          completionHadler(nil,ErrorMessage.error(description: "data nil"))
          return
        }
        completionHadler(dataOld,nil)
        return
      }


    // *** IN CASE OF ERROR 401 refresh the token and recursively call the same method
      print("error - > \n    \(error.localizedDescription) \n")

      print("stato codice2: \(String(describing: statusCode))")


    }


}

}


//Save the response in the cache
private func saveCache(_ response: (DataResponse<Any>)) {
  let cachedResponse = CachedURLResponse(response: response.response!, data: response.data!, userInfo: nil, storagePolicy: .allowed)
  let mycache:URLCache = self.sessionManager.session.configuration.urlCache!
  mycache.storeCachedResponse(cachedResponse, for: response.request!)
}


// Given a Request URL returns the old CACHE in case the site is unresponsive or offlineprivate func loadOldDataCache(url:URLRequest)->Data?{
  let myCache:URLCache = self.sessionManager.session.configuration.urlCache!
  let cacheResponse = myCache.cachedResponse(for: url)
  return cacheResponse?.data

}

// Except in memory Etag
private func saveEtagUserDefault(etagValue:String,key:String)->Void{

  UserDefaults.standard.set(etagValue, forKey:key)
  UserDefaults.standard.synchronize()

}
// Recovery from the memory Etag
private func loadEtagUserDefault(keyValue:String)->String{
  return UserDefaults.standard.object(forKey: keyValue) as? String ?? "0"
}

}

【讨论】:

    【解决方案2】:

    Diego 在 cmets 中问我如何解决这个问题。不幸的是,我无法以正确的方式解决它。

    我所做的是为 Alamofire 创建了自己的 NetworkManager。

        class NetworkManager {
    
         static let sharedInstance: SessionManager = {
            let configuration = URLSessionConfiguration.default
            configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
            configuration.timeoutIntervalForRequest = 20.0
            configuration.timeoutIntervalForResource = 20.0
            configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
            configuration.urlCache = nil
            return SessionManager(configuration: configuration)
          }()
       }
    

    重要的一行是configuration.urlCache = nil。所以 Alamofire 不会缓存任何东西。当然,我知道这不是正确的方法,但 atm 这对于我的用例来说是可行的解决方案。

    你这样称呼这位经理

        NetworkManager.sharedInstance.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: contentAuthorization).responseJSON { (response) in
            switch(response.result) {
            case .success(_):
                //success
            case .failure(let errorValue):
                print(errorValue)
            }
        }
    

    【讨论】:

    • 感谢您的回答。就我而言,当状态码为 304 时,我必须显示旧内容(缓存)。示例:1)启动应用程序我调用 API 并将数据保存在缓存中 2)如果状态码和 304 显示旧数据在缓存中 3)如果状态码与 304 不同,那么我会更新我的缓存。我希望我能理解并为我的英语道歉。
    • 我没有时间测试它,但它听起来和看起来都不错。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 2013-09-19
    • 2012-08-18
    • 2015-05-21
    • 2023-04-08
    • 1970-01-01
    • 2016-04-15
    相关资源
    最近更新 更多