【问题标题】:How can I log each request/response using Alamofire?如何使用 Alamofire 记录每个请求/响应?
【发布时间】:2014-12-31 10:03:11
【问题描述】:

有没有办法使用 Alamofire(类似于 AFNetworkActivityLogger)记录每个请求/响应?

我知道 Printable、DebugPrintable 和 Output (cURL),但它们并不是我想要的。

【问题讨论】:

    标签: ios debugging afnetworking-2 alamofire


    【解决方案1】:

    有一个可爱的小豆荚:https://github.com/konkab/AlamofireNetworkActivityLogger

    将此添加到您的 podfile:

    pod 'AlamofireNetworkActivityLogger', '~> 2.0'
    

    在您的 AppDelegate 中:

    import AlamofireNetworkActivityLogger
    

    然后在您的didFinishLaunchingWithOptions 中添加:

    NetworkActivityLogger.shared.level = .debug
    NetworkActivityLogger.shared.startLogging()
    

    编辑: 实际上,我在生产中遇到了崩溃。为了安全起见,使用“构建标志”仅在调试中使用它,如下所示:

    #if DEBUG
        NetworkActivityLogger.shared.level = .debug
        NetworkActivityLogger.shared.startLogging()
    #endif
    

    【讨论】:

    • 这是最好的选择,因为它不需要对现有代码进行任何更改。
    • 很好的解决方案。谢谢!
    • 支持 Swift 5 / Xcode 11 需要小更新,但运行良好!
    • @vedrano 那是什么?
    • @VarunRaj 没什么特别的,只是对最新的 Swift 语法进行了简单的调整。
    【解决方案2】:

    这样的东西可能就是你要找的东西:

    extension Request {
       public func debugLog() -> Self {
          #if DEBUG
             debugPrint(self)
          #endif
          return self
       }
    }
    

    用法:

    Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
             .debugLog()
             .response {…}
    

    如果要打印所有响应,可以编写自己的响应方法,类似于本教程顶部的 responseObject() 方法:

    http://www.raywenderlich.com/87595/intermediate-alamofire-tutorial

    [更新:根据@trauzti 的要求在下面添加。]

    为了在每个请求上打印输出,我们可以使用 responseObject() 方法。

    警告讲师:我没有亲自测试过这段代码,并且可能会在生产中做出不同的选择。这只是显示了 Wenderlich 教程代码如何包含调试日志记录。另请注意:由于本教程是 Swift 2.0 之前的版本,因此我使用了旧的 println() 而不是 print()。

    @objc public protocol ResponseObjectSerializable {
      init(response: NSHTTPURLResponse, representation: AnyObject)
    }
    
    extension Alamofire.Request {
      public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest, NSHTTPURLResponse?, T?, NSError?) -> Void) -> Self {
        let serializer: Serializer = { (request, response, data) in
    
          #if DEBUG
             println("Request: \(request.URL)")
          #endif
    
          let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
          let (JSON: AnyObject?, serializationError) = JSONSerializer(request, response, data)
          if response != nil && JSON != nil {
            #if DEBUG
               println("Response:")
               debugPrint(JSON)
            #endif
    
            return (T(response: response!, representation: JSON!), nil)
          } else {
            #if DEBUG
               println("Failed Serialization:")
               debugPrint(serializationError)
            #endif
    
            return (nil, serializationError)
          }
        }
    
        return response(serializer: serializer, completionHandler: { (request, response, object, error) in
          completionHandler(request, response, object as? T, error)
        })
      }
    }
    

    【讨论】:

    • 太棒了,谢谢!您能否发布您想到的 responseObject 扩展代码?
    • 现在没有时间重新审视这个,@MatthieuRiegler。愿意提供与 v3 兼容的文章吗? :)
    • @clozach 我们可以让它在调用请求时自动调用 debugLog 吗?
    • @clozach 如果在 debugLog() 中满足某些条件,我们可以停止请求吗,我尝试了 request.cancel(),但它仍然以结果失败的请求进行请求
    • @vinbhai4u 抱歉,不确定……我目前没有在生产代码中使用这些。
    【解决方案3】:

    从 Alamofire 5 开始,最简单的方法是定义一个EventMonitor 子类:

    final class AlamofireLogger: EventMonitor {
        func requestDidResume(_ request: Request) {
            let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None"
            let message = """
            ⚡️ Request Started: \(request)
            ⚡️ Body Data: \(body)
            """
            NSLog(message)
        }
    
        func request<Value>(_ request: DataRequest, didParseResponse response: DataResponse<Value>) {
            NSLog("⚡️ Response Received: \(response.debugDescription)")
        }
    }
    

    然后在你的session上使用它:

    let session = Session(eventMonitors: [ AlamofireLogger() ])
    

    此示例代码改编自https://github.com/Alamofire/Alamofire/issues/2867#issuecomment-509662892

    【讨论】:

    • 在 Alamofire 5.0.0 中,我不得不将“DataResponse”替换为“AFDataResponse”
    • 如果我使用 'AF.request' 会怎样?
    • 这正是我想要的。 @LMaker AF 正在引用 Alamofire 会话。然后你会使用 session.request 来代替。
    【解决方案4】:

    Timberjack 就是您正在寻找的东西。 Timberjack 是一个简单的、非侵入式的网络活动记录器。记录你的应用程序发出的每个请求,或者如果你愿意的话,只限制那些使用某个 NSURLSession 的请求。它也适用于 Alamofire,如果你喜欢的话。

    https://cocoapods.org/pods/Timberjack

    用法:

    import Alamofire
    import Timberjack
    
    class HTTPManager: Alamofire.Manager {
    static let sharedManager: HTTPManager = {
        let configuration = Timberjack.defaultSessionConfiguration()
        let manager = HTTPManager(configuration: configuration)
        return manager
    }()
    }
    

    【讨论】:

    • 如何将其限制为 NSURLSession?
    • 它可以工作,但是由于某种原因,当 Timberjack 处于活动状态并且并非所有请求都被自动跟踪时,应用程序变得太慢了。也许这是设计使然。
    【解决方案5】:

    添加到上面的答案 用于 Alamofire 4.0+ Swift 3

    extension DataRequest {        
            public func LogRequest() -> Self {
            //Your logic for logging
            return self
        }
    }
    

    请求时

    Alamofire.request(requestUrl, method: .post, parameters: parameter, encoding: JSONEncoding.default)
                .LogRequest()
                .responseJSON { response in
                //Do your thing
                }
    

    如果您想在任何情况下取消请求(这是我想要的),您可以在返回 self 之前的任何地方self.cancel()

    【讨论】:

      【解决方案6】:

      在 Alamofire 5 中,URLRequest 是异步创建的,这意味着

      extension Request {
       public func debugLog() -> Self {
        #if DEBUG
           debugPrint(self)
        #endif
        return self
        }
      }
      

      不再是最好的解决方案了。相反,建议如下调用cURLDescription

      let request = AF.request(<Your request>))
      request.cURLDescription { (curl) in
         print("CURL \(curl)")
      }
      request.responseJSON { response in
         //Do something with your response...
      }
      

      extension Request {
      public func debugLog() -> Self {
          #if DEBUG
          cURLDescription(calling: { (curl) in
              debugPrint("=======================================")
              print(curl)
              debugPrint("=======================================")
          })
          #endif
          return self
        }
       }
      

      【讨论】:

        【解决方案7】:

        SWIFT 3.0+ 的解决方案

        对于打印请求参数和标头:

        Alamofire.request(url, method: .get, parameters: parameters, headers: headers)
                    .validate()
                    .responseObject { (response: DataResponse<T>) in
                        self.pendingRequests.removeValue(forKey: endPoint)
                        completion!(response)
        
                        if(NetworkConfig.loggingEnable) {
                            debugPrint("************* printing REQUEST parameter and Headers *************")
                            debugPrint("RESPONSE : \(response.debugDescription)")
                        }
                }.responseDebugPrint()
        

        打印回复 .使用下面的扩展名。

        import Foundation
        import Alamofire
        
        extension Alamofire.DataRequest {
            func responseDebugPrint() -> Self {
                if NetworkConfig.loggingEnable {
        
                    return responseJSON() {
                        response in
                        if let  JSON = response.result.value,
                            let JSONData = try? JSONSerialization.data(withJSONObject: JSON, options: .prettyPrinted),
                            let prettyString = NSString(data: JSONData, encoding: String.Encoding.utf8.rawValue) {
                            print(prettyString)
                        } else if let error = response.result.error {
                            print("Error Debug Print: \(error.localizedDescription)")
                        }
                    }
                }
                return self
            }
        }
        

        给你的小要点: https://gist.github.com/manishpathak99/348f2eb0167c0ff6e12ecd667612bc9b/edit

        【讨论】:

          【解决方案8】:

          在 Alamofire 5.0.0 中,我使用的答案基于: https://github.com/Alamofire/Alamofire/issues/2867#issuecomment-509662892 但我不得不用 AFDataResponse 替换 DataResponse。例如:

          import Alamofire
          
          final class AlamofireLogger: EventMonitor {
          
              func requestDidResume(_ request: Request) {
          
                  let allHeaders = request.request.flatMap { $0.allHTTPHeaderFields.map { $0.description } } ?? "None"
                  let headers = """
                  ⚡️⚡️⚡️⚡️ Request Started: \(request)
                  ⚡️⚡️⚡️⚡️ Headers: \(allHeaders)
                  """
                  NSLog(headers)
          
          
                  let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None"
                  let message = """
                  ⚡️⚡️⚡️⚡️ Request Started: \(request)
                  ⚡️⚡️⚡️⚡️ Body Data: \(body)
                  """
                  NSLog(message)
              }
          
              func request<Value>(_ request: DataRequest, didParseResponse response: AFDataResponse<Value>) {
          
                  NSLog("⚡️⚡️⚡️⚡️ Response Received: \(response.debugDescription)")
                  NSLog("⚡️⚡️⚡️⚡️ Response All Headers: \(String(describing: response.response?.allHeaderFields))")
              }
          }
          

          然后你可以通过以下方式使用它:

          let session = Session(eventMonitors: [ AlamofireLogger() ])
          

          正如 0xced 在上述帖子中所解释的那样。

          【讨论】:

          • 它没有记录所有数据,我的身体正在被修剪。不要使用NSLog
          猜你喜欢
          • 2014-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-10
          • 1970-01-01
          • 1970-01-01
          • 2015-10-07
          相关资源
          最近更新 更多