简体   繁体   中英

Alamofire: [Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled"

The service I'm connecting to is using a self signed certificate. For dev purposes I do not want to validate that chain.

Using swift 3 with Alamofire 4. Fixed the ATS accordingly:

<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>

Code to connect and disable evaluation.

    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)")
        }
    }

Error log from dumpPrint

[Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey= https://sub.url.com/path , NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey= https://sub.url.com/path }

URL has been masked.

To retain SessionManager instance you need to capture it in closure passed to responseJSON :

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

Otherwise sessionManager is deallocated shortly it goes out of scope and any executing requests are cancelled.

Please add this statement to the end of responseJson block:

manager.session.invalidateAndCancel()

It happens if the object of the manager is not retained till execution of the block completes, so this would ensure its retention.

Cheers!

Please check in sessiondidReceiveChallenge: delegate implementation of NSURLSession . Chances are NSURLSessionAuthChallengeCancelAuthenticationChallenge is getting executed somewhere.

self.getSessionManager().request(urlstring, method: methods, parameters: parameters, encoding: JSONEncoding.prettyPrinted, headers: Header).responseJSON(queue: nil, options: JSONSerialization.ReadingOptions.allowFragments) { (responseObject) in ... .... }.session.finishTasksAndInvalidate()

任务完成后只需放置invalidate方法,意味着session.finishTasksAndInvalidate()

You need to properly manage the lifetime of your SessionManager instance. Most commonly this is done by making a singleton instance. Otherwise, when your manager goes out of scope and is deinit ed, all outstanding requests will be cancelled.

There could be a lot of reason to why your requests "cancelled".
In your case your request cancels immediately. You can refer to this issue in Alamofire repository issues

jshier commented on Oct 10, 2016

An unexpected error -999 almost always means your SessionManager was deallocated, cancelling any ongoing requests. I suggest you create a singleton value for your custom SessionManager, or perhaps just reevaluate if you really need one.

if you create a singleton value for your object it remains in memory and prevent from deallocate

and another thing that i avoid is to name your variables diffrent, a sessionManager is in Alamofire and your variable is also called sessionManager.

Alamofire 4.7 , Swift 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
  }()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM