gpt4 book ai didi

swift - Alamofire 5 RequestInterceptor,如何在不需要使用 .validate() 进行 token 刷新的情况下重试请求?

转载 作者:行者123 更新时间:2023-11-28 13:28:04 32 4
gpt4 key购买 nike

我正在使用 alamofire 5 (rc3) 在我的应用程序中重写网络,如果由于我的 JWT token 已过期而导致请求失败,我将尝试重试请求,如果我简单地标记,我可以让它工作请求上的 .validate() 表示 API 401 响应导致请求“失败”,然后传递给 RequestRetrier,但是每隔 400-499 请求我的API 以相同的形式返回数据并且 message 很有用,但是通过使用 .validate() 它会丢弃 .decodeResponse() 提供的有用的对象化:

{
"data": null,
"message": "Token has expired",
"status": "error"
/* has 401 error code */
}
class NetworkInterceptor: RequestInterceptor {

// MARK: - RequestAdapter
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
print("adapting")
var adaptedRequest = urlRequest
let token = NetworkService.sharedInstance.authToken
adaptedRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
completion(.success(adaptedRequest))
}


// MARK: - RequestRetrier
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if let response = request.task?.response as? HTTPURLResponse, let WWWheader = response.allHeaderFields["Www-Authenticate"] as? String, response.statusCode == 401, WWWheader == "Bearer realm=\"everywhere\"" {
print("Refreshing token for retry...")
NetworkService.sharedInstance.refreshTokens { (success, _, _) in
print("Refreshed token, retrying request")
completion(.retry)
}
} else {
completion(.doNotRetry)
}
}

}

在我的网络管理器中调用我的 API 的示例函数如下所示, session 只是附加(和工作)网络拦截器的正常 session 。

一个典型的 API 调用函数如下所示:

func sendMove(id: Int, move: Move, completion: @escaping APICompletionHandler<GameRender>) {
session.request(APIRouter.sendMove(id: id, move: move)).responseDecodable { (response: DataResponse<APIResponse<GameRender>, AFError>) in
switch response.result {
case .success(let apiResponse):
if apiResponse.status == .success {
// Data from API and success
completion(true, apiResponse.data, apiResponse.message)
} else {
// Data from API but not success
completion(false, apiResponse.data, apiResponse.message)
}
case .failure(let data):
// Could not get anything from API
completion(false, nil, data.localizedDescription)
}
}
}

您可以看到,如果正文的“成功”键为假,我会在 case .success(let apiResponse) 中返回某种形式的错误响应。然而,这意味着请求永远不会被放入 requestRetrier

如果我使用 .validate()

func sendMove(id: Int, move: Move, completion: @escaping APICompletionHandler<GameRender>) {
session.request(APIRouter.sendMove(id: id, move: move)).validate().responseDecodable { (response: DataResponse<APIResponse<GameRender>, AFError>) in
switch response.result {
case .success(let apiResponse):
if apiResponse.status == .success {
// Data from API and success
completion(true, apiResponse.data, apiResponse.message)
} else {
// Data from API but not success
// NOW THIS NEVER RUNS
completion(false, apiResponse.data, apiResponse.message)
}
case .failure(let data):
// Could not get anything from API
completion(false, nil, data.localizedDescription)
}
}
}

您现在可以看到开关第一部分中的 else{} 永远不会运行。这两种模式似乎不一致,是否有一种方法可以在特定调用上调用重试,例如,在解析之后if (token needs refreshing?) -> 重试这个请求

最佳答案

从根本上说,要触发重试,Alamofire 请求路径中的某个步骤必须抛出错误。响应处理程序,如 responseDecodable,将仅在请求期间未产生错误的情况下解析响应数据。使用 validate() 会为所有无效的响应代码和响应 Content-Type 生成错误。这里最简单的选择是使用传递的闭包自定义 validate() 以仅在您想要触发重试的情况下产生错误。然后您的响应处理程序将始终解析它们的数据,您可以根据需要处理其他故障。

一个更高级的解决方案是编写您自己的 ResponseSerializer,它会在出现某些错误时解析响应数据,但不是全部。

关于swift - Alamofire 5 RequestInterceptor,如何在不需要使用 .validate() 进行 token 刷新的情况下重试请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57999941/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com