我正在使用 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()
}
}
}
您可以具体说明一些情况,这样它就可以绕过拦截器的验证。 例如,在我的例子中,我有
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
的结果