Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Protocol
- UITextView
- ribs
- 리펙터링
- map
- combine
- Observable
- SWIFT
- 클린 코드
- ios
- Clean Code
- collectionview
- rxswift
- RxCocoa
- 리팩토링
- uiscrollview
- Xcode
- Refactoring
- MVVM
- clean architecture
- UICollectionView
- Human interface guide
- tableView
- HIG
- swift documentation
- 스위프트
- 애니메이션
- 리펙토링
- swiftUI
- uitableview
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 2. Alamofire 사용 방법 - 토큰 갱신 방법1 (Interceptor, adapt, retry) 본문
iOS 응용 (swift)
[iOS - swift] 2. Alamofire 사용 방법 - 토큰 갱신 방법1 (Interceptor, adapt, retry)
jake-kim 2021. 10. 16. 02:431. Alamofire 사용 방법 - Network Layer 구현 (Moya 프레임워크처럼 사용하는 방법)
2. Alamofire 사용 방법 - 토큰 갱신 방법1 (Interceptor, adapt, retry)
3. Alamofire 사용 방법 - 토큰 갱신 방법2 (AuthenticationCredential, Authenticator, AuthenticationInterceptor)
4. Alamofire 사용 방법 - 로그 Log (EventMonitor)
Interceptor란?
- 서버에 요청을 보내기 전에, 중간에 가로채서 어떤 작업을 한 뒤 다시 서버로 보내는 역할
- Alamofire를 사용하면 RequestInterceptor 프로토콜을 준수한 클래스의 인스턴스를 request에 실어서 보내면 동작
- adapt(): API 호출 전에 urlRequest에 관한 처리를 가로채서 적용하는 메서드
- retry(): API 호출 결과로 Error가 발생한 경우, 처리한 다음에 Error가 발생한 API를 다시 호출할것인지 적용하는 메서드
RequestInterceptor
- RequestInterceptor: RequestAdaptor와 RequestRetrier의 성격을 가지고 있는 프로토콜
RequestAdaptor
- adapt 메서드: request전에 특정 작업을 하고싶은 경우 사용
- 예시) request전에 header에 bearer token 값을 세팅
let accessToken: String
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
var urlRequest = urlRequest
urlRequest.headers.add(.authorization(bearerToken: accessToken))
completion(.success(urlRequest))
}
- RequestRetrier
- retry 메서드: 요청을 재시도해야하는지 여부를 결정하는 메소드
- completion으로 RetryResult를 넘기며, 재시도하는 유형에 대한 값
- 예시) 특정 오류가 발생한 경우, retry가 필요한 경우 delay값을 주고 retry하는 방법
open func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if request.retryCount < retryLimit,
let httpMethod = request.request?.method,
retryableHTTPMethods.contains(httpMethod),
shouldRetry(response: request.response, error: error) {
let timeDelay = pow(Double(exponentialBackoffBase), Double(request.retryCount)) * exponentialBackoffScale
completion(.retryWithDelay(timeDelay))
} else {
completion(.doNotRetry)
}
}
예제)
- API호출 시 adapt에서 가로채서 urlRequest에 accessToken을 추가한 urlRequest으로 다시 반환
- RequestInterceptor를 준수하여 adapt메서드에서 구현
import Alamofire
final class MyRequestInterceptor: RequestInterceptor {
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
guard urlRequest.url?.absoluteString.hasPrefix("https://api.agify.io") == true,
let accessToken = KeychainServiceImpl.shared.accessToken else {
completion(.success(urlRequest))
return
}
var urlRequest = urlRequest
urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
completion(.success(urlRequest))
}
}
- accessToken을 가지고 요청했을 때 401에러가 떨어지는 경우, 토큰을 refresh시키는 로직
- retry 메서드에서 구현
- 이전 API에 대해서 retry가 필요한 경우, completion(.retry)를하고 필요하지 않은 경우 completion(.doNotRetryWithError(error) 실행
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
completion(.doNotRetryWithError(error))
return
}
RefreshTokenAPI.refreshToken { result in
switch result {
case .success(let accessToken):
KeychainServiceImpl.shared.accessToken = accessToken
completion(.retry)
case .failure(let error):
completion(.doNotRetryWithError(error))
}
}
}
- 전체 코드
import Alamofire
final class MyRequestInterceptor: RequestInterceptor {
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
guard urlRequest.url?.absoluteString.hasPrefix("https://api.agify.io") == true,
let accessToken = KeychainServiceImpl.shared.accessToken else {
completion(.success(urlRequest))
return
}
var urlRequest = urlRequest
urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
completion(.success(urlRequest))
}
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
completion(.doNotRetryWithError(error))
return
}
/* TODO
RefreshTokenAPI.refreshToken { result in
switch result {
case .success(let accessToken):
KeychainServiceImpl.shared.accessToken = accessToken
completion(.retry)
case .failure(let error):
completion(.doNotRetryWithError(error))
}
}
*/
}
}
- 사용하는 쪽 - AF.request(_:interceptor)에서 interceptor에 객체 삽입
* 전체 소스코드: https://github.com/JK0369/ExAlamofire
* 참고
'iOS 응용 (swift)' 카테고리의 다른 글
Comments