这里每天分享一个 iOS 的新知识,快来关注我吧
前言
在前几篇文章中,我们探讨了 URLSession 的基本使用和安全性。这一篇文章将重点介绍如何使用 URLSession
统计一个 HTTPS
网络请求各个阶段的耗时,以帮助我们更好地了解网络请求的性能表现,然后才能进一步的优化。
在阅读这篇文章之前,建议你先阅读我们前几篇关于 URLSession
的文章,这样你会更容易理解本文的内容。
URLSession 系列第一篇:iOS 开发者必须掌握的 URLSession 使用指南
URLSession 系列第二篇:手把手教你封装超实用的网络工具类
URLSession 系列第三篇:告别回调地狱,掌握 Completion Handlers 和 async/await!
URLSession 系列第四篇:彻底防止中间人攻击,确保网络安全!
统计网络请求各个阶段的耗时
在分析网络请求的性能时,我们通常关心以下几个阶段的耗时:
-
DNS 解析时间:从开始 DNS 解析到 DNS 解析完成的时间。
-
TCP 连接时间:从开始建立 TCP 连接到连接完成的时间。
-
TLS 握手时间:从开始 TLS 握手到握手完成的时间。
-
请求发送时间:从请求开始发送到请求发送完成的时间。
-
服务器处理时间:从请求发送完成到服务器开始响应的时间。
-
响应接收时间:从响应开始接收到响应接收完成的时间。
接下来我们逐一介绍如何使用 URLSession
统计这些阶段的耗时。
使用 URLSessionTaskMetrics
从 iOS 10 开始,URLSession
提供了 URLSessionTaskMetrics
类,用于统计网络请求的性能数据。
可以通过实现 URLSession
的委托方法 urlSession(_:task:didFinishCollecting:)
,来获取这些性能数据。
具体实现步骤
创建一个 URLSessionTaskMetricsLogger 类
首先,我们创建一个 URLSessionTaskMetricsLogger
类,用于记录和打印网络请求的各个阶段耗时。
import Foundation
class URLSessionTaskMetricsLogger: NSObject, URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
for transactionMetric in metrics.transactionMetrics {
// 打印各个阶段的耗时
if let fetchStartDate = transactionMetric.fetchStartDate, // 开始请求时间
let domainLookupStartDate = transactionMetric.domainLookupStartDate, // DNS 解析开始时间
let domainLookupEndDate = transactionMetric.domainLookupEndDate, // DNS 解析结束时间
let connectStartDate = transactionMetric.connectStartDate, // TCP 连接开始时间
let connectEndDate = transactionMetric.connectEndDate, // TCP 连接结束时间
let secureConnectionStartDate = transactionMetric.secureConnectionStartDate, // TLS 握手开始时间
let secureConnectionEndDate = transactionMetric.secureConnectionEndDate, // TLS 握手结束时间
let requestStartDate = transactionMetric.requestStartDate, // 请求发送开始时间
let requestEndDate = transactionMetric.requestEndDate, // 请求发送结束时间
let responseStartDate = transactionMetric.responseStartDate, // 服务器处理开始时间
let responseEndDate = transactionMetric.responseEndDate { // 服务器处理结束时间
let dnsTime = domainLookupEndDate.timeIntervalSince(domainLookupStartDate)
let connectTime = connectEndDate.timeIntervalSince(connectStartDate)
let tlsTime = secureConnectionEndDate.timeIntervalSince(secureConnectionStartDate)
let requestTime = requestEndDate.timeIntervalSince(requestStartDate)
let serverProcessingTime = responseStartDate.timeIntervalSince(requestEndDate)
let responseTime = responseEndDate.timeIntervalSince(responseStartDate)
print("DNS 解析耗时: \(dnsTime) seconds")
print("TCP 连接时间: \(connectTime) seconds")
print("TLS 握手时间: \(tlsTime) seconds")
print("请求发送时间: \(requestTime) seconds")
print("服务端处理时间: \(serverProcessingTime) seconds")
print("服务器响应时间: \(responseTime) seconds")
}
}
}
}
修改 NetworkManager 类
接下来,我们在上一期的代码基础上修改一下 NetworkManager
类,并将 URLSessionTaskMetricsLogger
作为其委托代理。
import Foundation
class NetworkManager {
// 创建一个单例 NetworkManager 对象
static let shared = NetworkManager()
// 一个共享的 URLSession 对象
private let session: URLSession
// 防止其他对象创建 NetworkManager 对象,所以将 init() 方法私有化
private init() {
let configuration = URLSessionConfiguration.default
// 设置代理为 URLSessionTaskMetricsLogger 对象
self.session = URLSession(configuration: configuration, delegate: URLSessionTaskMetricsLogger(), delegateQueue: nil)
}
}
在这个代码示例里,URLSessionTaskMetricsLogger
被设置为 URLSession
的代理,以便在网络请求完成时收集和打印各个阶段的耗时。
didFinishCollecting
方法会在网络请求完成时被调用,我们在这个方法中计算并打印各个阶段的耗时。
统计到的耗时数据可以上传到我们的 APM 平台,以便进一步分析和优化网络请求的性能。
使用示例
然后我们随便调用一个接口,看看使用 NetworkManager
进行 HTTPS 请求是否能够正常统计各个阶段耗时:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Task {
await post()
}
}
func post() async {
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let body = """
{
"title": "标题",
"body": "这是一个新的帖子",
"userId": 1
}
""".data(using: .utf8)
do {
let data = try await NetworkManager.shared.postAsync(url: url, body: body)
if let responseString = String(data: data, encoding: .utf8) {
print("Response: \(responseString)")
}
} catch {
print("Error: \(error)")
}
}
}
在这个示例中,我们发送了一个 HTTPS 请求,并使用 URLSessionTaskMetricsLogger
收集和打印各个阶段的耗时。
运行之后可以在控制台看到对应的打印:
DNS 解析耗时: 0.013000011444091797 seconds
TCP 连接时间: 1.1759999990463257 seconds
TLS 握手时间: 0.4500000476837158 seconds
请求发送时间: 9.703636169433594e-05 seconds
服务端处理时间: 0.6955169439315796 seconds
服务器响应时间: 0.004144072532653809 seconds
Response: {
"title": "标题",
"body": "这是一个新的帖子",
"userId": 1,
"id": 101
}
总结
在这篇文章中,我们介绍了如何使用 URLSession 统计一个 HTTPS 网络请求各个阶段的耗时。希望对你有所帮助,能够在实际项目中应用这些技术来监控和优化网络请求的性能。下一篇文章准备继续探讨 URLSession 的其他高级用法,敬请期待!
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!