适配Linux Swift且兼容Vapor的HTTP请求框架/包选型问询
兼容多平台的API-Wrapper实现方案
核心思路:多平台适配层抽象
通过通用协议隔离不同平台的HTTP实现,不需要修改原有上层Wrapper逻辑,同时满足苹果端、Vapor Linux端的运行要求:
- 定义通用HTTP请求协议,统一所有平台的调用入口
- 苹果端(iOS/macOS)复用原有
URLSession实现,兼容你已经写完的逻辑 - Linux Vapor端直接使用Vapor内置的
Client,完全规避自行管理HTTP客户端生命周期的问题
具体实现步骤
- 定义通用请求协议
// 通用请求方法枚举,和平台无关 enum HTTPMethod: String { case get = "GET" case post = "POST" case put = "PUT" case delete = "DELETE" } // 通用响应结构 struct HTTPResponse { let status: Int let data: Data let headers: [String: String] } // 通用客户端协议 protocol HTTPClientProtocol { func send(method: HTTPMethod, url: String, headers: [String: String], body: Data?) async throws -> HTTPResponse }
- 苹果平台实现
直接复用系统URLSession实现协议,原有逻辑不需要改动:
#if os(iOS) || os(macOS) extension URLSession: HTTPClientProtocol { func send(method: HTTPMethod, url: String, headers: [String: String], body: Data?) async throws -> HTTPResponse { var request = URLRequest(url: URL(string: url)!) request.httpMethod = method.rawValue request.httpBody = body headers.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) } let (data, response) = try await self.data(for: request) let httpResponse = response as! HTTPURLResponse var resHeaders = [String: String]() httpResponse.allHeaderFields.forEach { resHeaders["\($0.key)"] = "\($0.value)" } return HTTPResponse( status: httpResponse.statusCode, data: data, headers: resHeaders ) } } #endif
- Vapor Linux平台实现
直接使用Vapor自带的Client实现协议,不需要自行实例化AsyncHTTPClient,Vapor会自动管理客户端的生命周期,完全不会出现uncleanShutdown、wait()不可用的问题:
#if os(Linux) import Vapor extension Client: HTTPClientProtocol { func send(method: HTTPMethod, url: String, headers: [String: String], body: Data?) async throws -> HTTPResponse { var reqHeaders = HTTPHeaders() headers.forEach { reqHeaders.add(name: .init($0.key), value: $0.value) } let res = try await self.send( .init(rawValue: method.rawValue), to: URI(string: url), headers: reqHeaders, body: body.flatMap { .init(data: $0) } ).get() var resHeaders = [String: String]() res.headers.forEach { resHeaders[$0.name.rawName] = $0.value } return HTTPResponse( status: Int(res.status.code), data: Data(buffer: res.body ?? .init()), headers: resHeaders ) } } #endif
独立运行场景兼容
如果需要你的API-Wrapper可以脱离Vapor独立在Linux上运行,自行维护AsyncHTTPClient全局单例即可:
- 全局只初始化一次
HTTPClient实例,不要每次请求都新建实例 - 程序退出前再调用
syncShutdown(),运行过程中不要主动销毁实例 - 所有请求全走async/await异步调用,不要使用
wait()阻塞线程
避坑提示
- 不要在Vapor的请求生命周期内调用任何
wait()方法,会阻塞EventLoop导致服务异常 - Swift 5.5环境请使用1.10.0以上版本的AsyncHTTPClient,对async/await的兼容性更稳定
内容的提问来源于stack exchange,提问作者MatzeLoCal
相关产品推荐
相关产品推荐

