Swift通用网络层改造:支持GET/POST请求及授权实现指导
改造Swift网络层支持GET/POST及授权密钥处理
以下是针对你的需求的完整改造方案,核心是扩展网络层的通用性,同时解决GET/POST请求切换和授权密钥的问题:
1. 新增HTTP方法枚举
先定义支持的HTTP方法,方便后续扩展和统一管理:
enum HTTPMethod: String { case get = "GET" case post = "POST" }
2. 重构网络层协议
修改HTTPDataDownloader协议,新增HTTP方法、请求头、请求体参数,让接口适配更多请求场景:
protocol HTTPDataDownloader { func fetchData<T: Decodable>( as type: T.Type, endpoint: String, method: HTTPMethod, headers: [String: String]?, body: Encodable? ) async throws -> T }
3. 实现通用网络请求逻辑
更新协议扩展,根据不同HTTP方法构建请求,处理授权头和请求体编码:
extension HTTPDataDownloader { func fetchData<T: Decodable>( as type: T.Type, endpoint: String, method: HTTPMethod = .get, headers: [String: String]? = nil, body: Encodable? = nil ) async throws -> T { guard let url = URL(string: endpoint) else { throw APIError.requestFailed(description: "无效URL") } var request = URLRequest(url: url) request.httpMethod = method.rawValue // 注入自定义请求头(包括授权密钥) headers?.forEach { key, value in request.setValue(value, forHTTPHeaderField: key) } // 处理POST请求的JSON请求体 if let body = body, method == .post { do { request.httpBody = try JSONEncoder().encode(body) request.setValue("application/json", forHTTPHeaderField: "Content-Type") } catch { throw APIError.requestFailed(description: "请求体编码失败: \(error.localizedDescription)") } } let (data, response) = try await URLSession.shared.data(for: request) guard let httpResponse = response as? HTTPURLResponse else { throw APIError.requestFailed(description: "请求无响应") } // 放宽成功状态码范围,覆盖200-299的标准成功码 guard (200...299).contains(httpResponse.statusCode) else { throw APIError.invalidStatusCode(statuscode: httpResponse.statusCode) } do { return try JSONDecoder().decode(type, from: data) } catch { throw error as? APIError ?? .unknownError(error: error) } } }
4. 改造数据服务类,支持GET/POST请求
以CommentsDataService为例,添加POST请求方法,并演示授权密钥的使用方式:
// 定义POST请求需要的参数结构体(遵循Encodable) struct CreateCommentRequest: Encodable { let postId: Int let name: String let email: String let body: String } class CommentsDataService: HTTPDataDownloader { private let baseUrl = "https://jsonplaceholder.typicode.com" // 示例授权密钥,实际项目中请用Keychain存储,不要硬编码 private let authToken = "Bearer your_actual_auth_token" // 原有GET请求逻辑,可选择性添加授权头 func fetchComments() async throws -> [Comments] { let endpoint = "\(baseUrl)/posts/1/comments" return try await fetchData( as: [Comments].self, endpoint: endpoint, method: .get, headers: ["Authorization": authToken] ) } // 新增POST请求创建评论 func createComment(request: CreateCommentRequest) async throws -> Comments { let endpoint = "\(baseUrl)/comments" return try await fetchData( as: Comments.self, endpoint: endpoint, method: .post, headers: ["Authorization": authToken], body: request ) } }
5. 更新ViewModel调用POST方法
在CommentsViewModel中添加创建评论的业务逻辑:
@Observable class CommentsViewModel { var comments = [Comments]() var errorMessage: String? private let service: CommentsDataService init(service: CommentsDataService) { self.service = service Task { await fetchComments() } } @MainActor func fetchComments() async { do { self.comments = try await service.fetchComments() } catch { guard let error = error as? APIError else { return } self.errorMessage = error.customDescription } } // 添加创建评论的方法 @MainActor func createNewComment(postId: Int, name: String, email: String, body: String) async { let request = CreateCommentRequest(postId: postId, name: name, email: email, body: body) do { let newComment = try await service.createComment(request: request) self.comments.append(newComment) } catch { guard let error = error as? APIError else { return } self.errorMessage = error.customDescription } } }
核心要点说明
- 授权密钥处理:通过
headers参数传入Authorization字段,常见格式为Bearer token或Basic base64编码字符串,实际项目中务必用Keychain存储密钥,不要硬编码在代码里。 - POST请求体:请求参数需遵循
Encodable协议,通过JSONEncoder转为JSON数据,同时设置Content-Type为application/json适配接口要求。 - 状态码判断:将原有的仅判断200改为判断200-299区间,符合HTTP标准的成功状态码范围。
内容的提问来源于stack exchange,提问作者NodlesView
相关产品推荐
相关产品推荐

