Alamofire 网络库:Swift 优雅 HTTP 客户端
Alamofire 网络库:Swift 优雅 HTTP 客户端
什么是 Alamofire?
Alamofire 是一个用 Swift 编写的 HTTP 网络库,由 Alamofire 软件基金会维护。它的命名源自阿拉莫之火(Alamo Fire),寓意强大而炽热的性能。Alamofire 提供了极其简洁的链式调用接口,能够大幅简化 iOS、macOS、tvOS 和 watchOS 应用中的网络请求处理。
核心特点:
- 链式响应处理:使用闭包和 Combine/async/await 风格处理异步操作。
- 请求与响应序列化:自动将 JSON、Property List、XML 等数据解码为模型。
- URL / JSON 参数编码:内置多种编码器,轻松构建 GET、POST 请求。
- 上传与下载:支持文件、数据流和多部分表单上传,以及带进度、断点续传的下载。
- 认证与安全:原生支持 HTTP 基础认证、Bearer Token、SSL Pinning 等。
- 网络可达性:提供
NetworkReachabilityManager监听网络状态变化。 - 拦截器与适配器:可在请求发送前后插入自定义逻辑,例如刷新 Token、全局错误处理。
安装 Alamofire
推荐使用 Swift Package Manager(SPM)集成。
通过 Xcode 添加
- 在 Xcode 中选择 File → Add Packages…
- 在搜索栏输入
https://github.com/Alamofire/Alamofire.git - 依赖规则选择 Up to Next Major Version,输入
5.8.0或更高版本(截止 2025 年推荐使用 5.x) - 点击 Add Package
通过 Package.swift 添加
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.8.0"))
]
CocoaPods 和 Carthage 仍被支持,但最佳实践推荐 SPM。
快速入门:第一个请求
import Alamofire
AF.request("https://httpbin.org/get").response { response in
debugPrint(response)
}
AF 是 Alamofire 提供的全局会话单例,足以覆盖大多数需求。你也可以创建自定义 Session 实例来实现更精细的控制。
处理 JSON 响应
AF.request("https://api.example.com/users")
.validate() // 自动检查状态码 200..<300
.responseDecodable(of: [User].self) { response in
switch response.result {
case .success(let users):
print("获取到 \(users.count) 个用户")
case .failure(let error):
print("请求失败: \(error)")
}
}
配合 Codable 模型,Alamofire 可以直接将响应解析为 Swift 对象。
构建各种请求
GET 请求与查询参数
let parameters = ["page": "1", "limit": "20"]
AF.request("https://api.example.com/items", parameters: parameters)
.responseDecodable(of: [Item].self) { response in
// 处理结果
}
默认使用 URLEncoding.default 编码参数,适用于 GET 和 DELETE 请求。
POST 请求与 JSON 参数
struct LoginRequest: Encodable {
let email: String
let password: String
}
let login = LoginRequest(email: "user@example.com", password: "secret")
AF.request("https://api.example.com/login",
method: .post,
parameters: login,
encoder: JSONParameterEncoder.default)
.responseDecodable(of: AuthToken.self) { response in
// 处理令牌
}
使用 JSONParameterEncoder 将请求体序列化为 JSON,并自动设置 Content-Type: application/json。
设置自定义请求头
let headers: HTTPHeaders = [
"Authorization": "Bearer your_token",
"Accept": "application/json"
]
AF.request("https://api.example.com/profile", headers: headers)
.responseDecodable(of: Profile.self) { response in
// ...
}
上传文件
通过文件 URL 上传
let fileURL = Bundle.main.url(forResource: "image", withExtension: "png")!
AF.upload(fileURL, to: "https://httpbin.org/post")
.uploadProgress { progress in
print("上传进度: \(progress.fractionCompleted)")
}
.responseJSON { response in
debugPrint(response)
}
多部分表单上传
let imageData = UIImage(named: "cat")!.jpegData(compressionQuality: 0.8)!
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "file", fileName: "cat.jpg", mimeType: "image/jpeg")
multipartFormData.append("field1_value".data(using: .utf8)!, withName: "field1")
}, to: "https://httpbin.org/post")
.responseDecodable(of: UploadResponse.self) { response in
print(response)
}
下载文件
Alamofire 自动管理下载任务的临时文件和目标位置。
let destination: DownloadRequest.Destination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("video.mp4")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
AF.download("https://example.com/video.mp4", to: destination)
.downloadProgress { progress in
print("下载进度: \(progress.fractionCompleted)")
}
.response { response in
if let error = response.error {
print("下载失败: \(error)")
} else {
print("下载完成,文件位置: \(response.fileURL!)")
}
}
如需恢复中断的下载,可提前保存 resumeData。
请求拦截与适配
RequestInterceptor 协议
自定义拦截器可以实现请求适配、重试逻辑。最常见的场景是在 Token 过期时自动刷新。
class AuthenticationInterceptor: RequestInterceptor {
let tokenManager: TokenManager
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
var urlRequest = urlRequest
if let token = tokenManager.accessToken {
urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
completion(.success(urlRequest))
}
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
return completion(.doNotRetry)
}
tokenManager.refreshToken { success in
completion(success ? .retry : .doNotRetry)
}
}
}
将此拦截器注入到自定义 Session 实例中即可全局生效:
let session = Session(interceptor: AuthenticationInterceptor(tokenManager: tokenManager))
session.request("https://api.example.com/secure-data").responseJSON { ... }
网络可达性检测
let manager = NetworkReachabilityManager()
manager?.startListening { status in
switch status {
case .notReachable:
print("网络不可用")
case .reachable(.ethernetOrWiFi):
print("通过 WiFi 连接")
case .reachable(.cellular):
print("通过蜂窝网络连接")
case .unknown:
print("未知状态")
}
}
注意在不需要时调用 stopListening() 释放资源。
使用 async/await(iOS 13+, Swift 5.5+)
Alamofire 5.5 开始原生支持 Swift 并发,使异步代码更加简洁。
func fetchUsers() async throws -> [User] {
let response = await AF.request("https://api.example.com/users")
.serializingDecodable([User].self)
.response
switch response.result {
case .success(let users):
return users
case .failure(let error):
throw error
}
}
或使用 responseDecodable 的便捷方法:
let users = try await AF.request("https://api.example.com/users")
.serializingDecodable([User].self)
.value
请求路由与 URLRequestConvertible
将 API 接口定义为枚举,并遵循 URLRequestConvertible 协议,可以使网络层组织更清晰。
enum UserRouter: URLRequestConvertible {
case getUsers(page: Int)
case createUser(parameters: Parameters)
var baseURL: URL {
URL(string: "https://api.example.com")!
}
var path: String {
switch self {
case .getUsers: return "/users"
case .createUser: return "/users"
}
}
var method: HTTPMethod {
switch self {
case .getUsers: return .get
case .createUser: return .post
}
}
func asURLRequest() throws -> URLRequest {
let url = baseURL.appendingPathComponent(path)
var request = URLRequest(url: url)
request.method = method
switch self {
case .getUsers(let page):
request = try URLEncoding.default.encode(request, with: ["page": page])
case .createUser(let parameters):
request = try JSONEncoding.default.encode(request, with: parameters)
}
return request
}
}
// 使用
AF.request(UserRouter.getUsers(page: 2)).responseJSON { ... }
结构与错误处理
Alamofire 的所有错误均遵循 AFError 枚举,包含以下常见成员:
invalidURL:URL 无效responseSerializationFailed:序列化失败requestAdaptationFailed:适配失败sessionTaskFailed:底层任务失败serverTrustEvaluationFailed:SSL/TLS 评估失败
通过 validate() 可以自动将非期望的状态码和内容类型转换为错误。
性能优化与最佳实践
- 重用
Session:不要为每次请求新建Session,使用单例或基于作用域的管理器。 - 并发请求:利用
withTaskGroup或TaskGroup与 async/await 配合请求。 - 响应缓存:Alamofire 依赖底层的
URLCache,可通过配置session.configuration.urlCache实现缓存策略。 - SSL Pinning:在安全要求极高的场景下,使用
ServerTrustManager和证书绑定。 - 日志与调试:开发阶段可以创建
EventMonitor对象来记录请求/响应的详细信息。
let monitor = ClosureEventMonitor()
monitor.requestDidFinish = { request in
print("请求完成: \(request)")
}
let session = Session(eventMonitors: [monitor])
总结
Alamofire 是 Swift 网络编程的不二之选。它平衡了高级抽象和底层控制,从简单的 JSON 获取到复杂的 Token 刷新、上传下载任务,都能以高度可读的链式代码实现。熟练掌握其核心模式,将显著提升你的开发效率和 App 的可靠性。
下一步,建议前往 Alamofire 官方文档 查阅更深入的高级特性,或动手编写一个涵盖拦截器、路由和并发请求的示例项目,巩固所学知识。