如何在Alamofire 5中解码错误的内容?

问题描述

我正在尝试将项目从Alamofire 4.9迁移到5.3,并且在错误处理方面遇到了困难。我想尽可能多地使用Decodable,但是当一切顺利时,我的API端点将返回一个JSON结构,而当出现错误时,API端点将返回一个不同的JSON结构,所有端点上的所有错误均相同。我的代码中对应的CodableApiError

我想创建一个自定义响应序列化器,该序列化器可以给我一个Result<T,ApiError>而不是认的Result<T,AFError>。我发现this article似乎可以解释一般过程,但是其中的代码无法编译。

如何创建这样的自定义ResponseSerializer

解决方法

10有一个要求。在很大程度上,您可以复制现有的序列化程序。例如,如果您想解析CSV(不检查响应):

1

您可以在Alamofire's documentation中阅读更多内容。

,

我最终将其与以下ResponseSerializer一起使用:

struct APIError: Error,Decodable {
    let message: String
    let code: String
    let args: [String]
}

final class TwoDecodableResponseSerializer<T: Decodable>: ResponseSerializer {
    
    lazy var decoder: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return decoder
    }()

    private lazy var successSerializer = DecodableResponseSerializer<T>(decoder: decoder)
    private lazy var errorSerializer = DecodableResponseSerializer<APIError>(decoder: decoder)

    public func serialize(request: URLRequest?,response: HTTPURLResponse?,data: Data?,error: Error?) throws -> Result<T,APIError> {

        guard error == nil else { return .failure(APIError(message: "Unknown error",code: "unknown",args: [])) }

        guard let response = response else { return .failure(APIError(message: "Empty response",code: "empty_response",args: [])) }

        do {
            if response.statusCode < 200 || response.statusCode >= 300 {
                let result = try errorSerializer.serialize(request: request,response: response,data: data,error: nil)
                return .failure(result)
            } else {
                let result = try successSerializer.serialize(request: request,error: nil)
                return .success(result)
            }
        } catch(let err) {
            return .failure(APIError(message: "Could not serialize body",code: "unserializable_body",args: [String(data: data!,encoding: .utf8)!,err.localizedDescription]))
        }

    }

}

extension DataRequest {
    @discardableResult func responseTwoDecodable<T: Decodable>(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated),of t: T.Type,completionHandler: @escaping (Result<T,APIError>) -> Void) -> Self {
        return response(queue: .main,responseSerializer: TwoDecodableResponseSerializer<T>()) { response in
            switch response.result {
            case .success(let result):
                completionHandler(result)
            case .failure(let error):
                completionHandler(.failure(APIError(message: "Other error",code: "other",args: [error.localizedDescription])))
            }
        }
    }
}

然后,我可以这样调用我的API:

AF.request(request).validate().responseTwoDecodable(of: [Item].self) { response in
            switch response {
            case .success(let items):
                completion(.success(items))
            case .failure(let error): //error is an APIError
                log.error("Error while loading items: \(String(describing: error))")
                completion(.failure(.couldNotLoad(underlyingError: error)))
            }
        }

我只是认为任何200-299范围之外的状态代码都对应一个错误。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...