跳到主要内容

URLSession 详解

问题

URLSession 的架构和核心 API 是什么?如何发起网络请求?

答案

URLSession 架构

Configuration 类型

类型说明
.default使用磁盘缓存、Cookie
.ephemeral无持久化(类似无痕模式)
.background后台下载/上传(App 被挂起仍继续)

基本请求(async/await)

// GET 请求
func fetchUser(id: Int) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, response) = try await URLSession.shared.data(from: url)

guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw NetworkError.invalidResponse
}

return try JSONDecoder().decode(User.self, from: data)
}

// POST 请求
func createUser(_ user: User) async throws -> User {
var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(user)

let (data, _) = try await URLSession.shared.data(for: request)
return try JSONDecoder().decode(User.self, from: data)
}

后台下载

let config = URLSessionConfiguration.background(withIdentifier: "com.app.download")
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

let task = session.downloadTask(with: url)
task.resume()

// 通过 delegate 接收进度和完成回调
extension DownloadManager: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL) {
// 文件下载到临时路径,需要移动到目标路径
try? FileManager.default.moveItem(at: location, to: destinationURL)
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64) {
let progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
print("Progress: \(progress)")
}
}

请求超时与重试

var request = URLRequest(url: url)
request.timeoutInterval = 15 // 请求超时 15 秒

let config = URLSessionConfiguration.default
config.timeoutIntervalForResource = 300 // 整体资源超时 5 分钟
config.waitsForConnectivity = true // 等待网络恢复

常见面试问题

Q1: URLSession.shared 和自定义 URLSession 的区别?

答案

  • URLSession.shared:单例,不可设置 delegate,不可自定义 configuration,适合简单请求
  • 自定义 URLSession:可设置缓存策略、Cookie 策略、后台任务、证书校验等

Q2: 如何实现断点续传?

答案

  1. 下载失败时保存 resumeData(包含已下载的范围信息)
  2. 恢复时调用 session.downloadTask(withResumeData: resumeData)
  3. 服务器需要支持 HTTP Range 请求

相关链接