You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift带证书的REST请求返回-999错误,求问题排查

iOS Alamofire请求错误-999(NSURLErrorCancelled)排查与修复

错误代码 -999 对应的是 NSURLErrorCancelled,意味着你的登录请求在完成前被主动取消了。结合你的代码和场景,主要有以下几个核心问题点,我们逐一排查修复:

1. SessionManager配置错误:未使用自定义配置实例

看你初始化 almgr 的代码,你明明创建并配置了自定义的 URLSessionConfiguration,但最后创建SessionManager时却误用了全新的 URLSessionConfiguration.default,这会导致你设置的HTTP头和自定义配置完全失效,进而引发请求异常:

// 错误代码片段
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
// 这里错误地使用了新的默认配置,而非上面已经配置好的configuration
let man = Alamofire.SessionManager(configuration: URLSessionConfiguration.default, serverTrustPolicyManager: serverTrustPolicyManager)

修复方案:
替换为你已经配置好的 configuration 实例:

let man = Alamofire.SessionManager(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager)

2. 服务器信任策略的Host不匹配

你设置的服务器信任策略的host是 "liper":

let serverTrustPolicies = ["liper":trustPolicy]

但如果你的 REST_MAIN_URL 的实际域名是类似 "liper.yourdomain.com" 或者其他变体,这个不匹配会导致Alamofire拒绝信任服务器,直接取消请求。

修复方案:
确保 serverTrustPolicies 中的key和你请求URL的host完全一致。比如如果你的接口地址是 https://api.liper.com/login,那么key应该是 "api.liper.com"。

3. 证书文件未正确添加到项目中

你加载证书的代码用了强制解包 !,如果证书文件 certf.cer 没有被正确添加到项目Target中,或者文件名存在大小写拼写错误(iOS的Bundle文件名区分大小写),会导致证书加载失败,进而引发信任验证失败,请求被取消。

检查与修复:

  • 确认 certf.cer 文件在Xcode项目中,并且在「Target Membership」中勾选了你的主App Target。
  • 改用安全的非强制解包写法,方便排查问题:
class func getCertificates() -> [SecCertificate]{
    guard let url = Bundle.main.url(forResource: "certf", withExtension: "cer") else {
        print("Certificate file not found in bundle")
        return []
    }
    do {
        let localCertificate = try Data(contentsOf: url) as CFData
        guard let certificate = SecCertificateCreateWithData(nil, localCertificate) else {
            print("Failed to create certificate from data")
            return[]
        }
        return [certificate]
    } catch {
        print("Failed to load certificate data: \(error)")
        return []
    }
}

4. 避免强制解包导致的潜在崩溃

在登录请求的回调中,你使用了 try! 来解析JSON:

guard let receivedResponse = try! JSONSerialization.jsonObject(with: response.data!, options: []) as? [String:Any] else { ... }

如果 response.data 为nil,或者JSON解析失败,这行代码会直接崩溃,同时可能导致请求流程异常中断。

修复方案:
改用 do-catch 安全解析:

case .success:
    print("\(self.TAG), receiving response from login with \(response)")
    guard let data = response.data else {
        print("\(self.TAG), No data received from login response")
        return
    }
    do {
        guard let receivedResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else {
            print("\(self.TAG), Error parsing response from login for json")
            return
        }
        // 后续处理token逻辑
        if let token:String = receivedResponse["token"] as? String {
            print("\(self.TAG), \(token)")
        } else {
            print("\(self.TAG), error receiving token")
            if let errorMessage:String = receivedResponse["status"] as? String {
                print("\(self.TAG), error message for login with received response status: \(errorMessage)")
            }
            return
        }
    } catch {
        print("\(self.TAG), JSON parsing error: \(error)")
        return
    }

5. 确认单例调用的正确性

你的 RestService 是单例模式,初始化是 private init(),这部分没问题,但要确保你在控制器中调用的是 RestService.shared.loginRest(...),避免意外创建多个实例导致的请求异常。

按照以上步骤修复后,应该能解决请求被取消的问题。

内容的提问来源于stack exchange,提问作者M. Wojcik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:30:38