swift 记录来自URLSession的请求和响应数据

hrirmatl  于 11个月前  发布在  Swift
关注(0)|答案(1)|浏览(106)

我有一个在多个地方使用URLSession.shared.data的iOS应用程序。我希望能够创建将请求和响应数据记录到控制台的功能。我已经创建了执行此日志记录的函数,但我目前必须将此功能添加到应用程序中使用URLSession.shared.data的所有位置。有没有一种方法可以在URLSession上创建一个扩展,以便能够一次性记录数据是否收到答复?

kb5ga3dv

kb5ga3dv1#

我建议你做你自己的网络层而不是直接使用URLSession.shared.data。主要是因为这样很难实现单元测试。
但是你可以做这样的东西:

import Foundation
import OSLog

private extension Logger {
   static let network = Logger(subsystem: "Your App's name", category: "network")
    }

    final class URLProtocolLogger: URLProtocol {
        private static let ignoredURL = ["any url that you want"]
    let logger = Logger()
    private var response: URLResponse?
    private var responseData: NSMutableData?

    private lazy var session: URLSession = { [unowned self] in
        return URLSession(configuration: .default, delegate: self, delegateQueue: nil)
    }()

    override class func canInit(with task: URLSessionTask) -> Bool {
        guard let request = task.currentRequest else { return false }
        return canServeRequest(request)
    }

    override class func canInit(with request: URLRequest) -> Bool {
        canServeRequest(request)
    }

    private class func canServeRequest(_ request: URLRequest) -> Bool {
        guard let url = request.url,
            (url.absoluteString.hasPrefix("http") || url.absoluteString.hasPrefix("https")) else {
            return false
        }

        let absoluteString = url.absoluteString
        guard !ignoredURL.contains(where: { absoluteString.hasPrefix($0) }) else { return false }

        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        request
    }

    override func startLoading() {
        session.dataTask(with: request).resume()
    }

    override func stopLoading() {
        session.getTasksWithCompletionHandler { dataTasks, _, _ in
            dataTasks.forEach { $0.cancel() }
            self.session.invalidateAndCancel()
        }
    }
}

extension URLProtocolLogger: URLSessionDataDelegate {
    public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        responseData?.append(data)

        client?.urlProtocol(self, didLoad: data)
    }

    public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        self.response = response
        responseData = NSMutableData()

        client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
        completionHandler(.allow)
    }

    public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        defer {
            if let error = error {
                client?.urlProtocol(self, didFailWithError: error)
            } else {
                client?.urlProtocolDidFinishLoading(self)
            }
        }

        guard let request = task.originalRequest, let url = request.url else {
            return
        }

        if error != nil {
            Logger.network.warning("Request: \(url.pathComponents) failed with: \(error)")
        } else if response != nil {
            let data = (responseData ?? NSMutableData()) as Data
            Logger.network.info("Request: \(url.absoluteString) success with: \(data)")
        }
    }

    public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {

        client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response)
        completionHandler(request)
    }
}

字符串
然后你需要像这样创建你自己的URLSession:

static let appSession: URLSession = {
    let configuration = URLSessionConfiguration.default
    configuration.protocolClasses = [URLProtocolLogger.self]
    return URLSession(configuration: configuration)
}()

相关问题