Swift do/try/catch处理API响应:如何在catch块获取LoginResponse的msg
如何在Swift登录API的Catch块中获取后端返回的错误提示msg
方案一:调整模型,在业务逻辑中直接判断(最简便)
如果后端无论登录成功还是失败,都返回LoginResponse结构(成功时token有值,失败时token为空或缺失),可以先修改模型让token变为可选类型,直接在成功回调里处理业务失败场景,不用走到catch块:
struct LoginResponse: Decodable { let token: String? // 改为可选,适配失败场景 let msg: String } // 调用代码修改 Task { do { let request: Request<LoginResponse> = .postLogin(email: email, password: password) let response = try await URLSession.shared.decode(request) if let validToken = response.token { // 登录成功,存储token print("登录成功,token: \(validToken)") } else { // 登录失败,直接拿到后端提示 print("登录失败:\(response.msg)") } } catch { // 处理网络中断、数据格式错误等系统级异常 print("系统错误:\(error.localizedDescription)") } }
这种方式把**业务失败(比如账号密码错误)和系统错误(网络、解码问题)**分开处理,逻辑更清晰,也不需要在catch块里额外解析错误信息。
方案二:自定义错误类型,在解码时捕获业务错误
如果后端在登录失败时返回非2xx的HTTP状态码,但响应体里依然包含msg错误提示,需要重构解码逻辑,把后端的错误信息包装成自定义错误抛出,这样就能在catch块中获取:
1. 定义自定义错误枚举
enum LoginServiceError: Error { case loginFailed(String) // 携带后端返回的msg case invalidResponse case networkFailure(Error) case decodingFailure(Error) }
2. 重构URLSession的decode方法
加入HTTP状态码检查,失败时尝试解析LoginResponse获取错误信息:
extension URLSession { func decode<Value: Decodable>( _ request: Request<Value>, using decoder: JSONDecoder = .init() ) async throws -> Value { let (data, response) = try await data(for: request.urlRequest) // 校验HTTP响应合法性 guard let httpResponse = response as? HTTPURLResponse else { throw LoginServiceError.invalidResponse } // 状态码非2xx时,尝试解码错误信息 if !(200...299).contains(httpResponse.statusCode) { do { let errorResp = try decoder.decode(LoginResponse.self, from: data) throw LoginServiceError.loginFailed(errorResp.msg) } catch { throw LoginServiceError.decodingFailure(error) } } try Task.checkCancellation() // 正常解码成功响应 do { return try decoder.decode(Value.self, from: data) } catch { throw LoginServiceError.decodingFailure(error) } } }
3. 在调用处捕获自定义错误
Task { do { let request: Request<LoginResponse> = .postLogin(email: email, password: password) let response = try await URLSession.shared.decode(request) // 登录成功,存储token print("登录成功:\(response.token)") } catch let LoginServiceError.loginFailed(errorMsg) { // 直接拿到后端的错误提示 print("登录失败:\(errorMsg)") } catch let LoginServiceError.networkFailure(error) { print("网络错误:\(error.localizedDescription)") } catch let LoginServiceError.decodingFailure(error) { print("数据解析错误:\(error.localizedDescription)") } catch { print("未知错误:\(error.localizedDescription)") } }
补充说明
如果后端在失败时返回的是和LoginResponse不同的错误结构,需要单独定义对应的错误模型(比如LoginErrorResponse),在状态码异常时优先解码这个模型获取错误信息。
内容的提问来源于stack exchange,提问作者soleil
相关产品推荐
相关产品推荐

