Alamofire: [Результат]: ОШИБКА: Ошибка домена = NSURLErrorDomain Code = -999 отменено

Служба, к которой я подключаюсь, использует самозаверяющий сертификат. В целях разработки я не хочу проверять эту цепочку.

Использование swift 3 с Alamofire 4. Исправил 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

[Результат]: FAILURE: Error Domain = NSURLErrorDomain Code = -999 "cancelled" UserInfo = {NSErrorFailingURLKey = https://sub.url.com/path, NSLocalizedDescription = cancelled, NSErrorFailingURLStringKey = https://sub.url.com/path}

URL был замаскирован.


person Sami M'Barek    schedule 11.10.2016    source источник


Ответы (5)


Чтобы сохранить экземпляр SessionManager, вам необходимо захватить его в закрытии, переданном в responseJSON:

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

В противном случае sessionManager вскоре освобождается, он выходит за пределы области видимости, и все выполняемые запросы отменяются.

person mixel    schedule 23.03.2017
comment
Это неправильное решение и антипаттерн. Вы должны сделать свой экземпляр менеджера синглтоном или использовать другой способ его сохранения за пределами локального использования. - person Jon Shier; 17.07.2017
comment
@JonShier Это не так широко используемое решение, чтобы быть анти-шаблоном :) Вы можете столкнуться с ситуацией, когда вам не нужно хранить SessionManager в течение всего времени существования приложения, поэтому разумно освободить его после завершения запроса. - person mixel; 17.07.2017
comment
Затем срок жизни следует должным образом продлить, возможно, сохранив где-нибудь менеджер и должным образом отменив его, когда придет время. Принуждение к локальной ссылке только для того, чтобы что-то поддерживать, всегда является анти-шаблоном, поскольку это означает, что вы неправильно обрабатываете время жизни своих переменных. - person Jon Shier; 17.07.2017
comment
@JonShier Я согласен с вами. Вышеупомянутый обходной путь обычно используется для сохранения некоторого экземпляра, определенного в области действия метода, после его возврата. Мы можем определить переменную var sessionManager: SessionManager? в области класса и установить для нее значение nil в responseJSON. Это более чистое решение, но чем оно отличается от обходного пути с точки зрения управления памятью и других основных вещей? - person mixel; 18.07.2017

Добавьте этот оператор в конец блока responseJson:

manager.session.invalidateAndCancel()

Это происходит, если объект менеджера не сохраняется до завершения выполнения блока, поэтому это обеспечит его сохранение.

Ваше здоровье!

person Jatin Nandwani    schedule 11.10.2016
comment
sessionManager.request (sub.url.com/path, заголовки: заголовки) .responseJSON {ответ в / * ... * / if let JSON = response.result.value {print (JSON: (JSON))} sessionManager.session.invalidateAndCancel ()} - person Sami M'Barek; 11.10.2016
comment
извините за это, я испортил свою конфигурацию, когда попытался. - person Sami M'Barek; 11.10.2016

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

person Rajukumar Patel    schedule 12.10.2017

Пожалуйста, проверьте sessiondidReceiveChallenge: реализацию делегата NSURLSession. Скорее всего, NSURLSessionAuthChallengeCancelAuthenticationChallenge где-то казнят.

person john7ric    schedule 13.10.2016

Вам необходимо правильно управлять сроком жизни вашего SessionManager экземпляра. Чаще всего это делается путем создания экземпляра синглтона. В противном случае, когда ваш менеджер выходит за рамки и deinited, все невыполненные запросы будут отменены.

person Jon Shier    schedule 17.07.2017