当响应数据不包含可通过Combine解码的对象时,如何抛出错误? [英] How could I throw an Error when response data does not contain an object to decode with Combine?

查看:48
本文介绍了当响应数据不包含可通过Combine解码的对象时,如何抛出错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个发布者包装结构,可以处理响应状态代码.如果状态码不在200..300范围内,则返回一个对象,否则抛出错误.效果很好.

I have a publisher wrapper struct where I can handle response status code. If the status code is not range in 200..300 it return with an object, otherwise it throws an Error. It works well.

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

如上所述,即使响应数据不包含要解码的对象,我也要处理错误.

As above, I would like to handle the error even if the response data does not contain an object to be decoded.

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

在此先感谢您提供的帮助.

Thank you in advance for any help you can provide.

推荐答案

我建议创建一个用于处理HTTP响应状态代码验证的 Publisher ,并将其用于其他两个发布商-一个处理一个空的请求正文和一个对请求正文进行解码的请求.

I would suggest creating a Publisher that handles the HTTP response status code validation and using that for both of your other publishers - the one that handles an empty request body and the one that decodes the body.

即使在验证其状态代码后仍需要 HTTPURLResponse 对象:

If you need the HTTPURLResponse object even after validating its status code:

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

或者,如果您不关心响应的任何其他属性,则仅确认其状态码是有效的:

Or if you don't care about any other properties of the response, only that its status code was valid:

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 函数的两个版本:

Then you can use this to rewrite both versions of your anyPublisher function:

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

这篇关于当响应数据不包含可通过Combine解码的对象时,如何抛出错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆