Network programming 发布服务器出现故障时,联合收割机接收器未完成

Network programming 发布服务器出现故障时,联合收割机接收器未完成,network-programming,swiftui,combine,Network Programming,Swiftui,Combine,我目前正在构建一个SwiftUI应用程序,并使用github()中的一个网络库来实现api调用 它工作正常,除非请求失败,然后库内部调试消息指示错误(在我的测试中为404),但联合收割机订户从未收到完成信号 我创建了一个新请求,它将尝试获取并解码“jsonplaceholder.typicode.com”的用户 用户只是一个简单的结构: struct User: Decodable { let id: Int let username: String let name:

我目前正在构建一个SwiftUI应用程序,并使用github()中的一个网络库来实现api调用

它工作正常,除非请求失败,然后库内部调试消息指示错误(在我的测试中为404),但联合收割机订户从未收到完成信号

我创建了一个新请求,它将尝试获取并解码“jsonplaceholder.typicode.com”的用户

用户只是一个简单的结构:

struct User: Decodable {
    let id: Int
    let username: String
    let name: String
}
在我的ApiRequestManager.swift文件中,我声明了一个请求调度的函数:

public func getUsersFromMockApi() -> Response<GetUsersFromMockApiRequest> {
    return GetUsersFromMockApiRequest().schedule(with: ApiService(apiUrl: "jsonplaceholder.typicode.com"))
}
如果api请求成功,则一切正常。但一旦出现任何错误,接收器将收到任何信号/完成

我试着打印订阅者收到的每一条消息,并且一步一步地跟踪库,看看他是否抛出了一个错误。它会根据NetworkScheduler.swift文件中schedule()函数中接受的状态代码正确检查HTTP响应代码,并在第285行抛出一个自定义错误
throw Squid.error.requestFailed(状态代码:状态代码,响应:response.data)


然而,由于我缺乏调试和组合知识,我很难在之后的测试中完成

您看到的问题可能是404不被底层Cocoa库(特别是URLSession)视为错误。这看起来像是Squid库中正在做(或不做)的事情,您正在对它提供的内容做出反应

URLSession本身只有在无法从服务器获得响应时才会抛出错误——因此,当问题与无法解析主机名或建立连接之类的事情有关时。如果您确实建立了连接并得到了响应,URLSession不会抛出错误,但状态代码会正确反映出来——它看起来就像是一个成功的请求

上面的示例没有显示该部分,但是来自
URLSession
的404响应发生的情况是请求完成,并且状态代码
404
在响应中编码,但不会作为错误状态抛出

在联合发布器链中处理此问题的典型模式是将结果数据从URLSession传递到
tryMap
操作符,在该操作符中,您可以进一步检查结果(状态代码、数据等),并确定是否要将其转化为抛出的错误(例如,如果收到404响应)

你可以在网站上找到这种模式的一个例子。此模式的要点是允许您基于对结果的检查定义任何您想要的错误(假设在这些情况下引发了异常)


您可以在中找到使用Combine(以及
URLSession.dataTaskPublisher
)的其他示例。

您看到的问题可能是404不被底层Cocoa库(特别是URLSession)视为错误。这看起来像是Squid库中正在做(或不做)的事情,您正在对它提供的内容做出反应

URLSession本身只有在无法从服务器获得响应时才会抛出错误——因此,当问题与无法解析主机名或建立连接之类的事情有关时。如果您确实建立了连接并得到了响应,URLSession不会抛出错误,但状态代码会正确反映出来——它看起来就像是一个成功的请求

上面的示例没有显示该部分,但是来自
URLSession
的404响应发生的情况是请求完成,并且状态代码
404
在响应中编码,但不会作为错误状态抛出

在联合发布器链中处理此问题的典型模式是将结果数据从URLSession传递到
tryMap
操作符,在该操作符中,您可以进一步检查结果(状态代码、数据等),并确定是否要将其转化为抛出的错误(例如,如果收到404响应)

你可以在网站上找到这种模式的一个例子。此模式的要点是允许您基于对结果的检查定义任何您想要的错误(假设在这些情况下引发了异常)


您可以在中找到其他使用Combine(以及
URLSession.dataTaskPublisher
)的示例。

非常有洞察力,是的,这就是问题所在。我联系了图书馆的开发人员,他似乎只是错过了404案例。他很快就修好了,现在一切都正常了!谢谢你的帮助。很有洞察力,是的,这就是问题所在。我联系了图书馆的开发人员,他似乎只是错过了404案例。他很快就修好了,现在一切都正常了!谢谢你的帮助。
public func getUsersFromMockApi() -> Response<GetUsersFromMockApiRequest> {
    return GetUsersFromMockApiRequest().schedule(with: ApiService(apiUrl: "jsonplaceholder.typicode.com"))
}
@State private var cancellableSet: Set<AnyCancellable> = []
private let requestManager = ApiRequestManager()
self.requestManager.getUsersFromMockApi()
  .print("Debug:")
  .sink(receiveCompletion: { completion in
    switch completion {
    case .failure:
      print("ApiCall failed.")
    case .finished:
      print("ApiCall finished.")
    }
  }) { result in
    print("Received users from apiCall: \(result)")
  }
  .store(in: &cancellableSet)