Har*_*lue 5 dependency-injection nsurlprotocol ios swift urlsession
我一直在研究拦截器,用于在我的应用程序中向网络请求添加身份验证标头。
final class AuthInterceptor: URLProtocol {
private var token: String = "my.access.token"
private var dataTask: URLSessionTask?
private struct UnexpectedValuesRepresentationError: Error { }
override class func canInit(with request: URLRequest) -> Bool {
guard URLProtocol.property(forKey: "is_handled", in: request) as? Bool == nil else { return false }
return true
//return false // URL Loading System will handle the request using the system’s default behavior
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
guard let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else { return }
URLProtocol.setProperty(true, forKey: "is_handled", in: mutableRequest)
mutableRequest.addValue(token, forHTTPHeaderField: "Authorization")
dataTask = URLSession.shared.dataTask(with: mutableRequest as URLRequest) { [weak self] data, response, error in
guard let self = self else { return }
if let error = error {
self.client?.urlProtocol(self, didFailWithError: error)
} else if let data = data, let response = response {
self.client?.urlProtocol(self, didLoad: data)
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
} else {
self.client?.urlProtocol(self, didFailWithError: UnexpectedValuesRepresentationError())
}
self.client?.urlProtocolDidFinishLoading(self)
}
dataTask?.resume()
}
override func stopLoading() {
dataTask?.cancel()
dataTask = nil
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我目前只是private var token: String = "my.access.token"用来模拟令牌。我想介绍一个TokenLoader将从它的缓存中获取我的令牌。
由于 URL 加载系统将根据需要初始化我的协议实例,我不确定如何注入它。它目前注册使用:URLProtocol.registerClass(AuthInterceptor.self)
想象一下我有一个这样的界面 -
public typealias LoadTokenResult = Result<String, Error>
public protocol TokenLoader {
func load(_ key: String, completion: @escaping (LoadTokenResult) -> Void)
}
Run Code Online (Sandbox Code Playgroud)
我想确保这是可测试的,所以我希望能够在测试用例中存根或使用间谍。
我怎样才能做到这一点?
一种可能的选择是为此使用泛型。
protocol TokenProvider {
static var token: String {get}
}
class MockTokenProvider: TokenProvider {
static var token: String = "my.access.token"
}
Run Code Online (Sandbox Code Playgroud)
并像这样更改 AuthInterceptor:
final class AuthInterceptor<T: TokenProvider>: URLProtocol {
private var token: String = T.token
....
...
}
Run Code Online (Sandbox Code Playgroud)
并像这样注册:
URLProtocol.registerClass(AuthInterceptor<MockTokenProvider>.self)
Run Code Online (Sandbox Code Playgroud)
上面是在操场上编译的,但还没有在实际项目中尝试过。
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |