自定义验证错误不再适用于 Alamofire 5
Custom validation error no longer working in Alamofire 5
使用 Alamofire 4,我们有一个 API 响应验证器,我们这样调用:
func request<Endpoint: APIEndpoint>(_ baseURL: URL, endpoint: Endpoint, completion: @escaping (_ object: Endpoint.ResponseType?, _ error: AFError?) -> Void) -> DataRequest where Endpoint.ResponseType: Codable {
let responseSerializer = APIObjectResponseSerializer(endpoint)
let request = self.request(baseURL, endpoint: endpoint)
.validate(APIResponseValidator.validate) << VALIDATOR PASSED HERE
.response(responseSerializer: responseSerializer) { response in
completion(response.value, response.error)
}
return request
}
看起来像这样:
static func validate(request: URLRequest?, response: HTTPURLResponse, data: Data?) -> Request.ValidationResult {
// **INSERT OTHER FAILURE CHECKS HERE**
// Verify server time is within a valid time window.
let headers = response.allHeaderFields
guard let serverTimeString = headers["Date"] as? String, let serverTime = DateUtils.headerDateFormatter().date(from: serverTimeString) else {
Log.error("APIValidation: no Date in response header")
return .failure(APIError.appTimeSettingInvalid))
}
// **INSERT OTHER FAILURE CHECKS HERE**
return .success(Void())
}
适当的错误会返回到请求完成处理程序,
▿ APIError
▿ appTimeSettingInvalid
我们可以用正确的错误更新 UI,大家都很高兴。
但是现在有了 Alamofire,就是这样:
▿ Optional<Error>
▿ some : AFError
▿ requestRetryFailed : 2 elements
▿ retryError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
▿ originalError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
我需要这样访问:
if let underlyingError = (error as? AFError)?.underlyingError as? AFError,
case let AFError.requestRetryFailed(_, originalError) = underlyingError,
case let AFError.responseValidationFailed(reason) = originalError,
case let .customValidationFailed(initialCustomError) = reason {
showAlert(initialCustomError)
}
这似乎很荒谬。我错过了什么?为什么自定义验证在方法没有任何变化时失败,为什么它被包裹在一层其他错误中?为什么当验证将以同样的方式失败时重试请求?
如何在所有请求中始终如一地恢复自定义错误?
在 Alamofire 5 中,返回的所有错误都包含在 AFError
实例中,包括自定义验证错误。这允许我们的 Response
类型包含类型错误并提供一致的错误类型。然而,不幸的是,验证 API 仍然是 returns Error
个实例,因此还有一个额外的层要剥离。您可以使用方便的 asAFError
属性 来执行转换,并使用 underlyingError
属性 来获取任何潜在的错误。使用 switch
语句也可以使提取更容易。您还可以 mapError
在响应中提取您想要的特定错误类型。
至于重试,很可能您的重试器尚未更新以提取错误,以便使用您的自定义错误类型正确避免重试。
使用 Alamofire 4,我们有一个 API 响应验证器,我们这样调用:
func request<Endpoint: APIEndpoint>(_ baseURL: URL, endpoint: Endpoint, completion: @escaping (_ object: Endpoint.ResponseType?, _ error: AFError?) -> Void) -> DataRequest where Endpoint.ResponseType: Codable {
let responseSerializer = APIObjectResponseSerializer(endpoint)
let request = self.request(baseURL, endpoint: endpoint)
.validate(APIResponseValidator.validate) << VALIDATOR PASSED HERE
.response(responseSerializer: responseSerializer) { response in
completion(response.value, response.error)
}
return request
}
看起来像这样:
static func validate(request: URLRequest?, response: HTTPURLResponse, data: Data?) -> Request.ValidationResult {
// **INSERT OTHER FAILURE CHECKS HERE**
// Verify server time is within a valid time window.
let headers = response.allHeaderFields
guard let serverTimeString = headers["Date"] as? String, let serverTime = DateUtils.headerDateFormatter().date(from: serverTimeString) else {
Log.error("APIValidation: no Date in response header")
return .failure(APIError.appTimeSettingInvalid))
}
// **INSERT OTHER FAILURE CHECKS HERE**
return .success(Void())
}
适当的错误会返回到请求完成处理程序,
▿ APIError
▿ appTimeSettingInvalid
我们可以用正确的错误更新 UI,大家都很高兴。
但是现在有了 Alamofire,就是这样:
▿ Optional<Error>
▿ some : AFError
▿ requestRetryFailed : 2 elements
▿ retryError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
▿ originalError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
我需要这样访问:
if let underlyingError = (error as? AFError)?.underlyingError as? AFError,
case let AFError.requestRetryFailed(_, originalError) = underlyingError,
case let AFError.responseValidationFailed(reason) = originalError,
case let .customValidationFailed(initialCustomError) = reason {
showAlert(initialCustomError)
}
这似乎很荒谬。我错过了什么?为什么自定义验证在方法没有任何变化时失败,为什么它被包裹在一层其他错误中?为什么当验证将以同样的方式失败时重试请求?
如何在所有请求中始终如一地恢复自定义错误?
在 Alamofire 5 中,返回的所有错误都包含在 AFError
实例中,包括自定义验证错误。这允许我们的 Response
类型包含类型错误并提供一致的错误类型。然而,不幸的是,验证 API 仍然是 returns Error
个实例,因此还有一个额外的层要剥离。您可以使用方便的 asAFError
属性 来执行转换,并使用 underlyingError
属性 来获取任何潜在的错误。使用 switch
语句也可以使提取更容易。您还可以 mapError
在响应中提取您想要的特定错误类型。
至于重试,很可能您的重试器尚未更新以提取错误,以便使用您的自定义错误类型正确避免重试。