跳到主要内容

设计网络层

问题

如何设计一个可扩展的 iOS 网络层?

答案

分层架构

API 协议定义

protocol APIEndpoint {
associatedtype Response: Decodable
var path: String { get }
var method: HTTPMethod { get }
var headers: [String: String]? { get }
var body: Encodable? { get }
}

struct GetUserEndpoint: APIEndpoint {
typealias Response = User
let userId: String
var path: String { "/api/users/\(userId)" }
var method: HTTPMethod { .get }
var headers: [String: String]? { nil }
var body: Encodable? { nil }
}

网络客户端

class NetworkClient {
private let session: URLSession
private let baseURL: URL
private var interceptors: [RequestInterceptor] = []

func request<E: APIEndpoint>(_ endpoint: E) async throws -> E.Response {
var request = buildURLRequest(endpoint)

// 拦截器链 - 请求前
for interceptor in interceptors {
request = try await interceptor.intercept(request: request)
}

let (data, response) = try await session.data(for: request)

guard let httpResponse = response as? HTTPURLResponse,
200..<300 ~= httpResponse.statusCode else {
throw NetworkError.serverError(statusCode: (response as? HTTPURLResponse)?.statusCode ?? 0)
}

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

// 拦截器
protocol RequestInterceptor {
func intercept(request: URLRequest) async throws -> URLRequest
}

struct AuthInterceptor: RequestInterceptor {
func intercept(request: URLRequest) async throws -> URLRequest {
var request = request
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
return request
}
}

关键设计点

设计点方案
类型安全泛型 + Codable
可扩展拦截器链模式
重试自动重试 + 指数退避
Mock协议抽象,注入 MockSession

常见面试问题

Q1: Token 过期如何自动刷新?

答案:在拦截器中检测 401 响应 → 刷新 Token → 重新发起请求。需要加锁避免多个请求并发刷新。

相关链接