AsyncHTTPClient 请求不工作 (Swift iOS)
AsyncHTTPClient Requests not working (Swift iOS)
Swift 和 iOS 开发的新手(本周末开始学习)。
我正在尝试使用 SotoSignerV4
和 AsyncHTTPClient
创建一个通用的 HTTP 客户端包装器来签署请求并将请求发送到 API 网关 (AWS)。我按照 excellent guide 获得了一些关于如何实现此目标的样板想法,但是当我在单元测试 (XCTestCase
) 中测试此方法时,它根本无法按预期工作。似乎请求甚至没有被执行(事实上我知道它不是,因为我可以检查我的 Lambda 应用程序上的日志 - 请求没有到达 lambda)。
这是我的大部分代码:
private func request<TEntity: Codable>(
type: TEntity.Type,
body: Codable? = nil,
resource: String,
method: HTTPMethod) throws -> TEntity {
// A bunch of AWS Sig4 signing stuff happens here, already tested and working...
let timeout = HTTPClient.Configuration.Timeout(
connect: .seconds(30), read: .seconds(30))
let httpClient: HTTPClient = HTTPClient(
eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(timeout: timeout))
var entity: TEntity? = nil;
var responseString: String? = nil;
let request = try! HTTPClient.Request(
url: processedUrl,
method: method,
headers: signedHeaders,
body: requestPayload)
let future = httpClient.execute(request: request)
future.whenComplete {
result in
switch result {
case .success(let response):
guard let responseBuffer = response.body, response.status == .ok
else { return }
let responseBody = Data(buffer: responseBuffer)
responseString = String(decoding: responseBody, as: UTF8.self)
case .failure(_):
return
}
}
try httpClient.syncShutdown()
entity = try! JSONDecoder().decode(TEntity.self, from: Data(responseString!.utf8));
return entity!;
}
失败在 entity
赋值行,说明
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file MyFramework/AWSSignedClient.swift, line 158
它不能解包的可选是响应字符串,这意味着 .success
案例中的代码从未被命中。我也尝试通过捕获表示错误的字符串来测试错误情况,但即使这样也行不通。就好像与 whenComplete
关联的回调被完全跳过,请求从未被发出。我也尝试过使用 URLSession.shared.dataTask
,结果相同 - 从未提出任何请求。
请帮忙! HTTPClient
我做错了什么?
这里的问题是您希望代码在调用异步代码时 运行 同步。您调用 future.whenComplete
但之后立即关闭客户端。请求永远不会有机会完成。
您可以设置您的函数,使其在请求完成时调用回调(从您的 whenComplete 闭包中调用),或者您可以添加一个 future.wait()
,它将等待请求完成,然后再继续。第一个选项可能更可取,因为第二个选项会在等待响应时停止您正在使用的线程 运行。
或者第三个选项是函数 return a EventLoopFuture<TEntity>
.
return httpClient.execute(request: request)
.flatMapThrowing { response in
guard let responseBuffer = response.body, response.status == .ok
else { throw Error.requestFailed }
let responseBody = Data(buffer: responseBuffer)
return try JSONDecoder().decode(TEntity.self, responseBody)
}
EventLoopFuture https://apple.github.io/swift-nio/docs/current/NIO/Classes/EventLoopFuture.html 的参考文档非常全面,如果您要与它们进行交互,值得一读。
如果您选择第一个或第三个选项,则无法在函数内关闭客户端。您需要在确定请求已完成时执行此操作。一直保持 HTTPClient
的实例可能更容易
Swift 和 iOS 开发的新手(本周末开始学习)。
我正在尝试使用 SotoSignerV4
和 AsyncHTTPClient
创建一个通用的 HTTP 客户端包装器来签署请求并将请求发送到 API 网关 (AWS)。我按照 excellent guide 获得了一些关于如何实现此目标的样板想法,但是当我在单元测试 (XCTestCase
) 中测试此方法时,它根本无法按预期工作。似乎请求甚至没有被执行(事实上我知道它不是,因为我可以检查我的 Lambda 应用程序上的日志 - 请求没有到达 lambda)。
这是我的大部分代码:
private func request<TEntity: Codable>(
type: TEntity.Type,
body: Codable? = nil,
resource: String,
method: HTTPMethod) throws -> TEntity {
// A bunch of AWS Sig4 signing stuff happens here, already tested and working...
let timeout = HTTPClient.Configuration.Timeout(
connect: .seconds(30), read: .seconds(30))
let httpClient: HTTPClient = HTTPClient(
eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(timeout: timeout))
var entity: TEntity? = nil;
var responseString: String? = nil;
let request = try! HTTPClient.Request(
url: processedUrl,
method: method,
headers: signedHeaders,
body: requestPayload)
let future = httpClient.execute(request: request)
future.whenComplete {
result in
switch result {
case .success(let response):
guard let responseBuffer = response.body, response.status == .ok
else { return }
let responseBody = Data(buffer: responseBuffer)
responseString = String(decoding: responseBody, as: UTF8.self)
case .failure(_):
return
}
}
try httpClient.syncShutdown()
entity = try! JSONDecoder().decode(TEntity.self, from: Data(responseString!.utf8));
return entity!;
}
失败在 entity
赋值行,说明
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file MyFramework/AWSSignedClient.swift, line 158
它不能解包的可选是响应字符串,这意味着 .success
案例中的代码从未被命中。我也尝试通过捕获表示错误的字符串来测试错误情况,但即使这样也行不通。就好像与 whenComplete
关联的回调被完全跳过,请求从未被发出。我也尝试过使用 URLSession.shared.dataTask
,结果相同 - 从未提出任何请求。
请帮忙! HTTPClient
我做错了什么?
这里的问题是您希望代码在调用异步代码时 运行 同步。您调用 future.whenComplete
但之后立即关闭客户端。请求永远不会有机会完成。
您可以设置您的函数,使其在请求完成时调用回调(从您的 whenComplete 闭包中调用),或者您可以添加一个 future.wait()
,它将等待请求完成,然后再继续。第一个选项可能更可取,因为第二个选项会在等待响应时停止您正在使用的线程 运行。
或者第三个选项是函数 return a EventLoopFuture<TEntity>
.
return httpClient.execute(request: request)
.flatMapThrowing { response in
guard let responseBuffer = response.body, response.status == .ok
else { throw Error.requestFailed }
let responseBody = Data(buffer: responseBuffer)
return try JSONDecoder().decode(TEntity.self, responseBody)
}
EventLoopFuture https://apple.github.io/swift-nio/docs/current/NIO/Classes/EventLoopFuture.html 的参考文档非常全面,如果您要与它们进行交互,值得一读。
如果您选择第一个或第三个选项,则无法在函数内关闭客户端。您需要在确定请求已完成时执行此操作。一直保持 HTTPClient
的实例可能更容易