如何解决当响应数据不包含可通过Combine解码的对象时,如何抛出错误?
我有一个发布者包装结构,可以处理响应状态代码。如果状态码不在200..300范围内,则返回一个对象,否则抛出错误。效果很好。
public func anyPublisher<T:Decodable>(type: T.Type) -> AnyPublisher<T,Error> {
return URLSession.shared.dataTaskPublisher(for: urlRequest)
.tryMap { output in
guard let httpResponse = output.response as? HTTPURLResponse,200..<300 ~= httpResponse.statusCode else {
throw APIError.unknown
}
return output.data
}
.decode(type: T.self,decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
使用:
let sendNewUserPublisher = NetworkPublisher(urlRequest: request).anyPublisher(type: User.self)
cancellationToken = sendNewUserPublisher.sink(receiveCompletion: { completion in
if case let .failure(error) = completion {
NSLog("error: \(error.localizedDescription)")
}
},receiveValue: { post in
self.post = post
})
如上所述,即使响应数据不包含要解码的对象,我也要处理错误。
public func anyPublisher() -> AnyPublisher<URLSession.DataTaskPublisher.Output,URLSession.DataTaskPublisher.Failure> {
return URLSession.shared.dataTaskPublisher(for: urlRequest)
// I'd like to handle status code here,and throw an error,if needed
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
在此先感谢您提供的帮助。
解决方法
我建议创建一个处理HTTP响应状态代码验证的Publisher
,并将其用于您的其他两个发布者-一个处理空的请求主体,另一个对主体进行解码。
如果即使在验证状态码后仍需要HTTPURLResponse
对象,则:
extension URLSession.DataTaskPublisher {
/// Publisher that throws an error in case the data task finished with an invalid status code,otherwise it simply returns the body and response of the HTTP request
func httpResponseValidator() -> AnyPublisher<Output,CustomError> {
tryMap { data,response in
guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
let statusCode = httpResponse.statusCode
guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
return (data,httpResponse)
}
.mapError { CustomError.network($0) }
.eraseToAnyPublisher()
}
}
或者,如果您不关心响应的任何其他属性,则仅确认其状态码有效:
func httpResponseValidator() -> AnyPublisher<Data,CustomError> {
tryMap { data,response in
guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
let statusCode = httpResponse.statusCode
guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
return data
}
.mapError { CustomError.network($0) }
.eraseToAnyPublisher()
}
然后,您可以使用它重写anyPublisher
函数的两个版本:
extension URLSession.DataTaskPublisher {
func anyPublisher<T:Decodable>(type: T.Type) -> AnyPublisher<T,Error> {
httpResponseValidator()
.decode(type: T.self,decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
func anyPublisher() -> AnyPublisher<Output,CustomError> {
httpResponseValidator()
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。