Swift Alamofire RequestInterceptor - 如何返回从服务器收到的原始错误?

问题描述 投票:0回答:1

我正在使用 Alamofire RequestInterceptor 来处理由于 401 未经授权而导致请求失败的情况。 我的问题是,如果错误不是 401,我不会从服务器获取原始错误,而是得到: 请求重试失败不可接受的状态代码。 在使用拦截器之前,我能够解析 JSON 结果并得到错误。 这是我的代码:

class APIRequest {
    
    var method: HTTPMethod
    var path: String
    var params : Codable?
    let retryLimit = 2

    
    init(method : HTTPMethod, path : String, params : Codable?) {
        self.method = method
        self.path = path
        self.params = params
    }
    
    func requestWithAlamofire(with baseURL: URL) -> DataRequest {
        var params:[String: Any]!
        params = self.params?.dictionary ?? [:]
        debugPrint("request params: ", params)
        let urlString = baseURL.appendingPathComponent(path).absoluteString.removingPercentEncoding ?? ""
        debugPrint(urlString)
        let url = URL(string: urlString) ?? baseURL.appendingPathComponent(path)
        
        if self.method == .post || self.method == .put || self.method == .delete {
            return AF.request(url/*baseURL.appendingPathComponent(path)*/, method: self.method, parameters: params, encoding: JSONEncoding.default, headers: httpHeader, interceptor: self).validate()
        }
        return AF.request(url, method: self.method, parameters: params, headers: httpHeader, interceptor: self).validate()
    }
}

extension APIRequest : RequestInterceptor {
    
    
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var request = urlRequest
        guard let token = UserDefaultsManager.shared.getidToken() else {
            completion(.success(urlRequest))
            return
        }
        let bearerToken = "Bearer \(token)"
        request.setValue(bearerToken, forHTTPHeaderField: "authorization")
        debugPrint("\nadapted; token added to the header field is: \(bearerToken)\n")
        completion(.success(request))
    }
    
    func retry(_ request: Request, for session: Session, dueTo error: Error,
               completion: @escaping (RetryResult) -> Void) {
        guard let statusCode = request.response?.statusCode, statusCode == 401, request.retryCount < retryLimit else {
            completion(.doNotRetryWithError(error))
            return
        }
        debugPrint("\nretried; retry count: \(request.retryCount)\n")
        AWSProvider.authProvider.fetchAuthSession { isSuccess in
            isSuccess ? completion(.retry) : completion(.doNotRetry)
        }
    }
    

}

这是处理请求结果的类:

func sendWithAlamofire<T: Decodable>(apiRequest: APIRequest) -> Observable<T?> {
        let baseURL = URL(string:  BASE_URL)
        return Observable<T?>.create { observer in
            let task = apiRequest.requestWithAlamofire(with: baseURL!).responseData(completionHandler: { (data) in
                do {
                    switch data.result {
                    case .success(let successData):
                        debugPrint("success", JSON(successData))
                        debugPrint("statusCode" , data.response?.statusCode)
                        if let response = data.data {
                            if let statusCode = data.response?.statusCode, statusCode != 200 {
                                let err = NSError(domain: "", code: statusCode, userInfo: JSON(data.data ?? Data()).dictionaryObject)
                                observer.onError(err)
                            } else {
                                if response.isEmpty {
                                    observer.onNext(nil)
                                } else {
                                    let model: T = try JSONDecoder().decode(T.self, from: data.data ?? Data())
                                    observer.onNext(model)
                                }
                            }
                        }
                    case .failure(let error):
                        debugPrint(error)
                        observer.onError(error)
                    }
                } catch let error {
                    debugPrint(error)
                    observer.onError(error)
                }
                observer.onCompleted()
            })
            return Disposables.create {
                task.cancel()
            }
        }
    }

ios swift alamofire
1个回答
0
投票

您可以具体说明一些情况,这样它就可以绕过拦截器的验证。 例如,在我的例子中,我有

login
api 有时返回 401,并且客户端拒绝修复它,并且仍然希望解析
login
的响应以显示给用户。所以我必须创建一个状态代码列表,拦截器会将其视为成功
[200, 201, 202]
,但添加对
login
端点的条件检查以包括
401
。然后
session
就会像这样

sessionManager.request(executableRequest).validate(statusCode: [200, 201, 202, 401]).responseDecodable

也在里面

func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

我必须检查

login
端点是否返回为
doNotRetry

if request.request is Login {
     return completion(.doNotRetry)
}

所以会返回

responseDecodable 

的结果
© www.soinside.com 2019 - 2024. All rights reserved.