【问题标题】:AsyncHTTPClient Requests not working (Swift iOS)AsyncHTTPClient 请求不起作用(Swift iOS)
【发布时间】:2021-07-02 11:45:00
【问题描述】:

Swift 和 iOS 开发新手(本周末开始学习)。

我正在尝试使用SotoSignerV4AsyncHTTPClient 制作一个通用的HTTP 客户端包装器,用于对API Gateway (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 我做错了什么?

【问题讨论】:

    标签: ios swift http aws-api-gateway soto


    【解决方案1】:

    您在这里遇到的问题是,当您调用异步代码时,您希望代码同步运行。您致电future.whenComplete,但之后立即关闭客户端。请求永远没有机会完成。

    您可以设置您的函数,以便在请求完成时调用回调(从您的 whenComplete 闭包中调用),或者您可以添加一个future.wait(),它将等待请求完成后再继续。第一个选项可能更可取,因为第二个选项会在等待响应时停止您正在运行的线程。

    或者第三种选择是让函数返回EventLoopFuture&lt;TEntity&gt;

    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)
        }
    

    EventLoopF​​uture https://apple.github.io/swift-nio/docs/current/NIO/Classes/EventLoopFuture.html 的参考文档非常全面,如果您要与他们互动,值得一读。

    如果您选择第一个或第三个选项,您将无法在函数内关闭客户端。您需要在确定请求已完成时执行此操作。始终保持HTTPClient 的实例可能更容易

    【讨论】:

    • 是的,这完全正确。实际上,在您发布此答案之前不久,我就意识到了我的错误。我假设whenComplete 的调用实际上是在等待结果。我最终通过EventLoopFuture 进行进一步处理。谢谢!
    猜你喜欢
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多