tha*_*don 9 ios swift urlsession
我正在为使用 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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
Endpoint 只是一个构建 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
}
}
Run Code Online (Sandbox Code Playgroud)
我在哪里放置允许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
}
}
Run Code Online (Sandbox Code Playgroud)
这是刷新令牌和重做 API 调用的正确方法还是有更好的方法?
小智 0
您必须编写一个函数来更新令牌,并根据结果返回 true 或 false
private func refreshAccessToken(completion: @escaping (Bool) -> Void {
// Make a request to refresh the access token
// Update the accessToken and refreshToken variables when the request is completed
// Call completion(true) if the request was successful, completion(false) otherwise
}
Run Code Online (Sandbox Code Playgroud)
在类的开头声明2个变量
var session: URLSession
var endpoint: Endpoint
Run Code Online (Sandbox Code Playgroud)
在里面case .failure
分配这些变量
session = session
endpoint = endpoint
Run Code Online (Sandbox Code Playgroud)
然后调用refreshAccessToken方法。最终代码如下所示
if let response = response as? HTTPURLResponse {
let result = self.handleNetworkResponse(response)
switch result {
case .failure(FRNetworkingError.invalidAuthToken):
session = session
endpoint = endpoint
self?.refreshAccessToken { success in
if success {
self?.request(using: session, endpoint, completion: completion)
} else {
completion(.failure(.unknownError))
}
}
break
default:
break
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1094 次 |
最近记录: |