You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Alamofire 5实操:如何从AFError中获取服务端自定义API错误

Alamofire 5 自定义服务端错误模型解析方案

你当前调整后的方案已经可以实现需求,我们可以进一步优化为更符合Swift类型安全特性的写法,避免双可选参数的冗余判断:

步骤1:定义错误相关模型

首先定义和服务端返回结构匹配的错误模型,以及统一的API错误枚举:

// 服务端错误详情结构,根据实际返回字段调整
struct ErrorDetail: Decodable {
    // 对应details内的字段
}

// 服务端返回的错误主体
struct ServerError: Decodable, Error {
    let summary: String
    let details: [ErrorDetail]
}

// 服务端错误最外层包装
struct ErrorWrapper: Decodable {
    let errorObject: ServerError
}

// 统一的API错误枚举,覆盖所有可能的错误场景
enum APIError: Error {
    /// 网络层面错误(无网络、超时等)
    case network(AFError)
    /// 服务端返回的业务错误
    case server(ServerError)
    /// JSON解析错误
    case parse(Error)
    /// 响应无数据
    case noData
}

步骤2:改造APIClient请求方法

将原来的双可选回调改为Result类型回调,统一处理成功、失败的解析逻辑:

class APIClient {
    
    static let sessionManager: Session = {
        let configuration = URLSessionConfiguration.af.default
        configuration.timeoutIntervalForRequest = 30
        configuration.waitsForConnectivity = true
        return Session(configuration: configuration, eventMonitors: [APILogger()])
    }()
    
    @discardableResult
    private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:@escaping (Result<T, APIError>)->Void) -> DataRequest {
        return sessionManager.request(route)
            .validate(statusCode: 200..<300)
            .validate(contentType: ["application/json"])
            .responseData { response in
                switch response.result {
                case .success(let data):
                    do {
                        let object = try decoder.decode(T.self, from: data)
                        completion(.success(object))
                    } catch {
                        completion(.failure(.parse(error)))
                    }
                case .failure(let afError):
                    guard let data = response.data else {
                        completion(.failure(.network(afError)))
                        return
                    }
                    do {
                        // 解析服务端返回的错误模型
                        let errorWrapper = try decoder.decode(ErrorWrapper.self, from: data)
                        completion(.failure(.server(errorWrapper.errorObject)))
                    } catch {
                        // 错误解析失败时返回原始网络错误
                        completion(.failure(.network(afError)))
                    }
                }
            }
    }
    
    // 登录接口示例
    static func login(username: String, password: String, completion:@escaping (Result<User, APIError>)->Void) {
        performRequest(route: APIRouter.login(username: username, password: password), completion: completion)
    }
}

步骤3:接口调用示例

调用侧直接通过Result的枚举分支处理不同场景,错误类型明确无需额外判断:

APIClient.login(username: "test", password: "test") { result in
    switch result {
    case .success(let user):
        debugPrint("__________SUCCESS__________")
        debugPrint(user)
    case .failure(let error):
        debugPrint("__________FAILURE__________")
        switch error {
        case .server(let serverError):
            // 直接使用解析好的服务端错误模型处理业务逻辑
            debugPrint("业务错误提示:\(serverError.summary)")
        case .network(let afError):
            debugPrint("网络异常:\(afError.localizedDescription)")
        case .parse(let parseError):
            debugPrint("数据解析失败:\(parseError.localizedDescription)")
        case .noData:
            debugPrint("服务器未返回有效数据")
        }
    }
}

核心说明

之前你获取underlyingError为空的原因是Alamofire的验证失败后,错误响应的原始数据不会存在于underlyingError中,直接从response.data属性即可获取完整的错误响应数据进行解析。


内容的提问来源于stack exchange,提问作者DevinM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 12:48:04