обработка кода состояния HTTP с помощью URLSession и Combine

Я пытаюсь обработать ответы, поступающие от DataTaskPublisher, читающего код состояния ответа.

Когда код состояния больше 299, я хотел бы вернуть тип ServiceError как Failure. Во всех примерах, которые я видел, я использовал .mapError и _4 _... в этом конкретном случае из .flatMap, я действительно не знаю, как обработать ответ издателя, чтобы вернуть ошибку вместо _6 _...

    return URLSession.DataTaskPublisher(request: urlRequest, session: .shared)
        .mapError{error in return ServiceError.request}
        .flatMap{ data, response -> AnyPublisher<TResponse, ServiceError> in

            if let httpResponse = response as? HTTPURLResponse,
                (200...299).contains(httpResponse.statusCode){

                return Just(data)
                    .decode(type: TResponse.self, decoder: JSONDecoder())
                    .mapError{error in return ServiceError.decode}
                    .eraseToAnyPublisher()
            }else{
                //???? HOW TO HANDLE THE ERROR?
            }
        }
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()

person MatterGoal    schedule 23.12.2019    source источник


Ответы (2)


Если я правильно понял вашу цель, вам нужно что-то вроде

}else{
    return Fail(error: ServiceError.badServiceReply)
              .eraseToAnyPublisher()
}

Простой пример:

URLSession.shared
    .dataTaskPublisher(for: URL(string: "https://www.google.com")!)
    .receive(on: DispatchQueue.main)
    .flatMap { _ in
        Fail(error: URLError(URLError.unsupportedURL)).eraseToAnyPublisher()
    } //for the sake of the demo
    .replaceError(with: "An error occurred") //this sets Failure to Never
    .assign(to: \.stringValue, on: self)
    .store(in: &cancellableBag)

всегда будет назначать строку «Произошла ошибка» из-за переназначения на Fail издателя

person Asperi    schedule 25.12.2019

enum ServiceErrors { 
    case internalError(_ statusCode: Int)
    case severError(_ statusCode: Int)
}

return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap { data, response in
                guard let httpResponse = response as? HTTPURLResponse,
                    200..<300 ~= httpResponse.statusCode else {
                        switch (response as! HTTPURLResponse).statusCode {
                        case (400...499):
                            throw ServiceErrors.internalError((response as! HTTPURLResponse).statusCode)
                        default:
                            throw ServiceErrors.serverError((response as! HTTPURLResponse).statusCode)
                        }
                }
                return data
            }
            .mapError { $0 as! ServiceErrors }
            .decode(type: T.self, decoder: JSONDecoder())
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()

Я полагался на эту ссылку, чтобы сделать мой обработчик ошибок https://gist.github.com/stinger/7cb1a81facf3d7f8 / а>

person gandhi Mena    schedule 28.03.2020