iOS端Swift连接SignalR遇自签名证书协商错误的解决方法
解决iOS 11 Swift SignalR客户端连接自签名证书服务器的问题
你遇到的Error during negotiation request确实大概率是iOS默认拒绝信任自签名证书导致的——iOS的ATS(App Transport Security)会阻止未受信任的HTTPS请求,而SignalR的协商阶段需要正常的HTTP/HTTPS通信才能完成。下面是针对iOS 11 Swift环境的具体解决方案:
步骤1:配置Info.plist的ATS例外
首先需要在项目的Info.plist中添加ATS配置,允许你的服务器域名跳过严格的证书验证:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>services.test.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> </dict> </dict> </dict>
注意:如果你的服务器是HTTPS协议,
NSExceptionAllowsInsecureHTTPLoads设为true是允许跳过证书验证;如果是HTTP,这一步是允许非HTTPS请求(不过生产环境不建议用HTTP)。
步骤2:给SignalR客户端配置自定义URLSession(信任自签名证书)
SignalR-Swift库允许自定义URLSession,我们可以通过实现URLSessionDelegate来手动信任自签名证书。修改你的代码如下:
首先,添加一个自定义的URLSessionDelegate类:
class CustomURLSessionDelegate: NSObject, URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // 信任自签名证书 if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { guard let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } let credential = URLCredential(trust: serverTrust) completionHandler(.useCredential, credential) } else { completionHandler(.performDefaultHandling, nil) } } }
然后修改你的test()函数,给SignalR连接配置这个自定义的URLSession:
func test() { // 初始化自定义Delegate和URLSession let sessionDelegate = CustomURLSessionDelegate() let sessionConfiguration = URLSessionConfiguration.default let urlSession = URLSession(configuration: sessionConfiguration, delegate: sessionDelegate, delegateQueue: nil) // 创建SignalR连接(注意如果是HTTPS,这里要改成https://services.test.com/signalr) let persistentConnection = SignalR("https://services.test.com/signalr", connectionType: .persistent) // 给SignalR连接设置自定义URLSession persistentConnection.urlSession = urlSession let simpleHub1 = Hub("testHub") persistentConnection.useWKWebView = false persistentConnection.addHub(simpleHub1) // 以下是你的原有回调逻辑,修复了重复设置connected的问题 persistentConnection.received = { data in print(data) } persistentConnection.starting = { print("Starting...") } persistentConnection.reconnecting = { print("Reconnecting...") } persistentConnection.connected = { [weak self] in guard let self = self else { return } print("Connected. Connection ID: \(String(describing: persistentConnection.connectionID))") } persistentConnection.reconnected = { [weak self] in guard let self = self else { return } print("Reconnected. Connection ID: \(String(describing: persistentConnection.connectionID))") } persistentConnection.disconnected = { print("Disconnected.") } persistentConnection.connectionSlow = { print("Connection slow...") } persistentConnection.error = { error in print("Error occurred: \(error ?? "Unknown error")") persistentConnection.start() } persistentConnection.start() }
关键说明
- 我注意到你的代码里重复设置了
persistentConnection.connected回调,这会覆盖之前的逻辑,所以合并成了一个,避免冲突。 - 如果你的服务器确实是HTTP协议,那主要问题可能不是证书,但还是建议切换到HTTPS;如果是HTTPS,一定要把连接地址改成
https://开头。 - 自定义Delegate里的逻辑是信任所有服务器证书,只建议在测试环境使用,生产环境应该使用合法的CA签发证书,或者添加特定自签名证书到信任列表(更安全的做法)。
内容的提问来源于stack exchange,提问作者SHEBIN
相关产品推荐
相关产品推荐

