我正在为使用OAuth 2.0授权技术(Access
和Refresh Token
)的iOS应用构建网络客户端。我一直在努力实现的网络客户端功能:
Access Token
已过期,我需要将Refresh Token
发送到服务器以获得新的Access Token
。Access Token
后,我需要重做上一个收到401错误的请求。到目前为止,我已经为我的网络客户端编写了以下代码:
typealias NetworkCompletion = Result<(Data, URLResponse), FRNetworkingError>
/// I am using a custom result type to support just an Error and not a Type object for success
enum NetworkResponseResult<Error> {
case success
case failure(Error)
}
class FRNetworking: FRNetworkingProtocol {
fileprivate func handleNetworkResponse(_ response: HTTPURLResponse) -> NetworkResponseResult<Error> {
switch response.statusCode {
case 200...299: return .success
case 401: return .failure(FRNetworkingError.invalidAuthToken)
case 403: return .failure(FRNetworkingError.forbidden)
case 404...500: return .failure(FRNetworkingError.authenticationError)
case 501...599: return .failure(FRNetworkingError.badRequest)
default: return .failure(FRNetworkingError.requestFailed)
}
}
func request(using session: URLSession = URLSession.shared, _ endpoint: Endpoint, completion: @escaping(NetworkCompletion) -> Void) {
do {
try session.dataTask(with: endpoint.request(), completionHandler: { (data, response, error) in
if let error = error {
print("Unable to request data \(error)")
// Invoke completion for error
completion(.failure(.unknownError))
} else if let data = data, let response = response {
// Passing Data and Response into completion for parsing in ViewModels
completion(.success((data, response)))
}
}).resume()
} catch {
print("Failed to execute request", error)
completion(.failure(.requestFailed))
}
}
}
端点只是构建URLRequest的结构:
struct Endpoint {
let path: String
let method: HTTPMethod
let parameters: Parameters?
let queryItems: [URLQueryItem]?
let requiresAuthentication: Bool
var url: URL? {
var components = URLComponents()
components.scheme = "http"
components.host = "127.0.0.1"
components.port = 8000
components.path = "/api\(path)"
components.queryItems = queryItems
return components.url
}
func request() throws -> URLRequest {
/// Creates a request based on the variables per struct
}
}
我在哪里放置允许FRNetworking.request()
获得新令牌并重试请求的代码?
我在else if let data = data, let response = response
语句中做了以下操作:
if let response = response as? HTTPURLResponse {
let result = self.handleNetworkResponse(response)
switch result {
case .failure(FRNetworkingError.invalidAuthToken):
break
// TODO: Get new Access Token and refresh?
default:
break
}
}
这是刷新令牌并重做API调用的正确方法,还是有更好的方法?