【问题标题】:Alamofire: [Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled"Alamofire: [结果]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled"
【发布时间】:2017-02-20 10:41:36
【问题描述】:

我正在连接的服务正在使用自签名证书。 出于开发目的,我不想验证该链。

在 Alamofire 4 中使用 swift 3。 相应地修复了 ATS:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>url.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

连接和禁用评估的代码。

    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "example.domain.com": .pinCertificates(
            certificates: ServerTrustPolicy.certificates(),
            validateCertificateChain: false,
            validateHost: true
        ),
        "sub.url.com": .disableEvaluation
    ]

    let sessionManager = Alamofire.SessionManager(
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )

    let headers = ["Authorization": "Basic /*...*/"]

    sessionManager.request("https://sub.url.com/path", headers: headers).responseJSON { response in
        print(response.request)  // original URL request
        print(response.response) // HTTP URL response
        print(response.data)     // server data
        print(response.result)   // result of response serialization

        debugPrint(response)

        if let JSON = response.result.value {
            print("JSON: \(JSON)")
        }
    }

dumpPrint 中的错误日志

[结果]:失败:错误域=NSURLErrorDomain 代码=-999 “已取消” UserInfo={NSErrorFailingURLKey=https://sub.url.com/path, NSLocalizedDescription=取消, NSErrorFailingURLStringKey=https://sub.url.com/path}

网址已被屏蔽。

【问题讨论】:

    标签: ios swift xcode alamofire


    【解决方案1】:

    要保留SessionManager 实例,您需要在传递给responseJSON 的闭包中捕获它:

    sessionManager.request("https://sub.url.com/path", headers: headers).responseJSON { response in
        let _ = sessionManager // retain
        // ...
    }
    

    否则sessionManager 很快就会被释放,它会超出范围并且所有正在执行的请求都会被取消。

    【讨论】:

    • 这不是一个合适的解决方案,是一种反模式。您应该使您的管理器实例成为单例,或者使用其他方式在本地使用之外将其持久化。
    • @JonShier 作为反模式的解决方案并没有被广泛使用 :) 您可能会遇到在应用程序的整个生命周期内不需要保留 SessionManager 的情况,所以这是明智的在请求完成后释放它。
    • 那么应该适当地延长生命周期,也许通过将管理器存储在某个地方并在时机成熟时适当地取消它。强制本地引用只是为了让某些东西保持活动状态始终是一种反模式,因为这意味着您没有正确处理变量的生命周期。
    • @JonShier 我同意你的看法。上述“变通方法”通常用于在方法返回后保留方法范围内定义的某些实例。我们可以在类范围内定义var sessionManager: SessionManager? 变量并将其设置为responseJSON 中的nil。这是更清洁的解决方案,但在内存管理和其他底层事物方面,它与“解决方法”有何不同?
    【解决方案2】:

    请将此语句添加到 responseJson 块的末尾:

    manager.session.invalidateAndCancel()
    

    如果在块执行完成之前没有保留管理器的对象,则会发生这种情况,因此这将确保其保留。

    干杯!

    【讨论】:

    • sessionManager.request("sub.url.com/path", headers: headers).responseJSON { response in /*...*/ if let JSON = response.result.value { print("JSON: ( JSON)") } sessionManager.session.invalidateAndCancel() }
    • 抱歉,我在尝试时搞砸了我的配置。
    【解决方案3】:
    self.getSessionManager().request(urlstring, method: methods, parameters: parameters, encoding: JSONEncoding.prettyPrinted, headers: Header).responseJSON(queue: nil, options: JSONSerialization.ReadingOptions.allowFragments) { (responseObject) in ... .... }.session.finishTasksAndInvalidate()
    

    只要把任务完成后失效的方法,就是session.finishTasksAndInvalidate()

    【讨论】:

      【解决方案4】:

      请签入sessiondidReceiveChallenge:NSURLSession 的委托实现。 NSURLSessionAuthChallengeCancelAuthenticationChallenge 很有可能在某处被执行。

      【讨论】:

        【解决方案5】:

        您需要正确管理SessionManager 实例的生命周期。最常见的是通过创建一个单例实例来完成。否则,当您的经理超出范围并被deinited 时,所有未完成的请求都将被取消。

        【讨论】:

          【解决方案6】:

          您的请求“取消”可能有很多原因。
          在您的情况下,您的请求会立即取消。 这个问题可以参考Alamofire repository issues

          jshier 于 2016 年 10 月 10 日发表评论

          意外错误 -999 几乎总是意味着您的 SessionManager 解除分配,取消任何正在进行的请求。我建议你创建一个 您的自定义 SessionManager 的单例值,或者可能只是 重新评估你是否真的需要一个。

          如果你为你的对象创建一个单例值,它会保留在内存中并防止释放

          我避免的另一件事是将你的变量命名为不同的,一个 sessionManager 在 Alamofire 中,你的变量也称为 sessionManager。

          Alamofire 4.7,斯威夫特 4

          import Alamofire
          
          class Networking {
          
            public static let sharedManager: SessionManager = {
                let configuration = URLSessionConfiguration.default
                configuration.timeoutIntervalForRequest=20
                let manager = Alamofire.SessionManager(configuration: configuration, delegate: SessionManager.default.delegate)
                return manager
            }()
          }
          

          Alamofire 5.4.4 , Siwft 5.2

          import Alamofire
          
          class Networking {
          
            static let APIManager: Session = {
                let configuration = URLSessionConfiguration.default
                configuration.timeoutIntervalForRequest = 20
                let delegate = Session.default.delegate
                let manager = Session.init(configuration: configuration,
                                           delegate: delegate,
                                           startRequestsImmediately: true,
                                           cachedResponseHandler: nil)
                return manager
            }()
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-11-18
            • 2017-03-08
            • 2020-02-03
            • 1970-01-01
            • 2017-03-19
            • 2018-10-11
            • 1970-01-01
            相关资源
            最近更新 更多