使用URLSession 连接https

环境:
macOS Monterey 12.0.1、
Xcode 13.1、
Swift 5.5.1

  1. 网络的基础请求
    涉及类: URL, URLRequest, URLSession, URLResponse
        let url = URL(string: "https://local.lexandera.com/openapi/login.json")
        let request = URLRequest(url: url!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30)
        let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        session.dataTask(with: request) { data, response, error in
            if let data = data {
                print(String(data: data, encoding: .utf8) as Any)
            }
            
            print(response as Any)
            if let e = error {
                print(e.localizedDescription)
            }
        }.resume()

此处是使用了block的形式获取了数据, 同时也可以选择代理的方式获取更详细的请求过程

        session.dataTask(with: request).resume()
.....
.....

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        print(#function)
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        print(#function)
        guard let response = task.response as? HTTPURLResponse else { return }
        print(response.allHeaderFields)
    }
  1. 验证证书
    实现URLSessionDelegate的验证证书的代理方法
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

}

AFNetworking验证https证书的方式有3种,

  • 无条件认可
    使用服务端给过来的证书重新给回代理即可
   let ser = challenge.protectionSpace.serverTrust
   let m = URLCredential(trust: ser!)
   completionHandler(.useCredential, m)
  • 验证证书
        let ser = challenge.protectionSpace.serverTrust
        let path = Bundle.main.path(forResource: "server", ofType: "cer")
        if let cer = SecTrustGetCertificateAtIndex(ser!, 0) {
            let n = SecCertificateCopyData(cer) as Data
            print(n)
            do {
                let data = try Data(contentsOf: .init(fileURLWithPath: path!))
                let cer2 = SecCertificateCreateWithData(nil, data as CFData)
                if cer == cer2 {
                    print("本地证书是一样的")
                    let credential = URLCredential(trust: ser!)
                    challenge.sender?.use(credential, for: challenge)
                    completionHandler(.useCredential, credential)
                    return
                }
            } catch {
                print("本地并没有该证书")
            }
        }
        completionHandler(.cancelAuthenticationChallenge, nil)
  • 验证公钥
   let publicKey  = SecCertificateCopyKey(cer)
   let publicKey2 = SecCertificateCopyKey(cer2)

当我们使用Finder, Charles这类代理工具抓包的时候, 它们会把一个他们自己的自签名证书给到我们,这个时候我们比对证书的时候 就知道证书有问题了, 拒绝/取消请求即可

       completionHandler(.rejectProtectionSpace, nil)     
       completionHandler(.cancelAuthenticationChallenge, nil)      

注: 关于自签名证书的获取

  1. 该文将会告诉你怎么获取crt证书 然后使用以下命令导出cer
$ openssl x509 -in demo.crt -out demo.cer -outform der
  1. 将crt文件双击导入到钥匙串(KeyChain)中,然后右键导出为cer文件即可

  2. 访问拥有自签名证书的网站,在提醒安全页面,信任并访问它.然后在查看钥匙串,你将发现那个证书已经在钥匙串中,之后右键导出为cer文件即可.

番外: 使用Combine请求数据

func testNetwork2() {
    let cancellable = URLSession.shared.dataTaskPublisher(for: URL(string: "https://local.lexandera.com/openapi/login.json")!)
//            .map{ data , _ in data}
        .subscribe(on: RunLoop.main)
//            .print()
        .sink { completion in
        switch completion {
        case .finished:
            break
        case .failure(_):
            return
        }
        print("hahah")
    } receiveValue: { data in
        print(data)
    }
}
posted @ 2021-12-31 15:11  古龙•历山大亚  阅读(231)  评论(0编辑  收藏  举报