- vừa được xem lúc

Refresh token và retry request sử dụng RxSwift

0 0 29

Người đăng: Nguyen The Trinh

Theo Viblo Asia

Đặt vấn đề

Trong các dự án iOS sử dụng authenticator, việc đăng nhập thường hay được sử dụng bằng access token sau khi đã đăng nhập thành công bằng tài khoản và mật khẩu. Cách làm này khá phổ biến và rộng rãi hiện nay. Một tình huống điển hình là nếu đăng nhập rồi không sử dụng app dẫn đến access token hết hạn (thường sẽ có giới hạn thời gian) thì ứng dụng sẽ văng ra ngoài màn login và tiến hành đăng nhập lại. Với trường hợp này thì chúng ta thường tạo thêm 1 API refresh token để lấy lại access token mới, và ngay sau đó gọi lại api cũ để không cần phải đăng nhập lại. Hoặc là tự động login nếu khi kill app mà chưa đăng xuất. Việc xử lý này chính là retry lại API trong trường hợp call api bị failed. Hôm nay mình sẽ hướng dẫn mọi người cách xử lý tình huống này trên frameword RxSwift sử dụng thư viện AlamoreFire.

Trường hợp Ví dụ

Trường hợp này xảy ra khi chúng ta:

  • Gọi 1 API sử dụng access token, nhưng bị failed do access token đã quá hạn
  • Tiếp tục gọi một API để refresh lại access token với mục đích lấy về access token mới
  • Đến bước này có hai trường hợp xảy ra:
  • Một là API refresh thành công, access token mới sẽ được dùng để call api trước đó, app lại chạy bình thường (1)
  • Trường hợp thứ 2 là cái API refresh cũng bị lỗi luôn, vậy chúng ta cần xử lý tiếp, thường là bắn về màn Login, bắt đăng nhập lại.

Xử lý token hết hạn

Chúng ta có hàm gọi và lấy dữ liệu từ API như sau:

static func request<T: Codable> (_ urlConvertible: URLRequestConvertible) -> Observable<T> { return Observable<T>.create { observer in let request = AF.request(urlConvertible) .validate(statusCode: 200..<300) .responseJSON { (response) in switch response.result { case .success(let value): observer.onNext(value) observer.onCompleted() return case .failure(let error): observer.onError(error) } } return Disposables.create { request.cancel() }

Khi accesstoken hết hạn, chúng ta dùng retryWhen{} của RxSwift để xử lý. Gọi API refresh token và lưu lại access token mới, sau đó gọi lại api lúc đầu.

static func request<T: Codable> (_ urlConvertible: URLRequestConvertible) -> Observable<T> { return Observable<T>.create { observer in let request = AF.request(urlConvertible) .validate(statusCode: 200..<300) .responseJSON { (response) in switch response.result { case .success(let value): observer.onNext(value) observer.onCompleted() return case .failure(let error): observer.onError(error) } } return Disposables.create { request.cancel() }.retryWhen { error -> Observable<Error> in return error.flatMapLatest { error-> Observable<Error> in return refreshToken() .flatMapLatest { respone -> Observable<Error> in //save respone return Observable.error(error) } } else { return Observable.error(error) } }

Đối với cách xử lý này chúng ta phải viết thêm 1 hàm resfresh token riêng, để tránh bị lặp vô hạn

func refreshToken() -> Observable<Respone> { return renewToken()
} static func renewToken(_ urlConvertible: URLRequestConvertible) -> Observable<Respone> { return Observable.create { observer in let request = AF.request(urlConvertible) .validate(statusCode: 200..<300) .responseJSON { (response) in switch response.result { case .success(let value): observer.onNext(data) observer.onCompleted() return case .failure(let error): observer.onError(error) } } return Disposables.create { request.cancel() } } }

Xử lý refresh token hết hạn

Tình huống thứ 2 xảy ra là API refresh cũng bị lỗi luôn, vậy chúng ta cần xử lý tiếp, thường là bắn về màn Login, bắt đăng nhập lại. Khi đó chúng ta chỉ viêc xử lý lỗi ở observale gọi refreshToken

static func request<T: Codable> (_ urlConvertible: URLRequestConvertible) -> Observable<T> { return Observable<T>.create { observer in let request = AF.request(urlConvertible) .validate(statusCode: 200..<300) .responseJSON { (response) in switch response.result { case .success(let value): observer.onNext(value) observer.onCompleted() return case .failure(let error): observer.onError(error) } } return Disposables.create { request.cancel() }.retryWhen { error -> Observable<Error> in return error.flatMapLatest { error-> Observable<Error> in return refreshToken().do(onError: { error in //Handle getout to login screen }).flatMapLatest { respone -> Observable<Error> in //save respone return Observable.error(error) } } }

Trên đây là hướng dẫn xử lý token hết hạn của mình, hi vọng sẽ giúp các bạn xử lý được tình huống tương tự nếu gặp phải. Xin cám ơn đã đọc !

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 254

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

0 0 189

- vừa được xem lúc

Swift: Tạo custom phép toán tử (Operator) của riêng bạn!

Swift cho phép bạn tạo các toán tử có thể tùy chỉnh của riêng bạn. Điều này đặc biệt hữu ích khi bạn xử lý các loại dữ liệu của riêng mình. Operator Types in Swift. Có năm loại toán tử chính trong Swift.

0 0 45

- vừa được xem lúc

Chương 6 Protocol oriented programming.

Cuốn sách này là về lập trình hướng protocol. Khi Apple thông báo swift 2 ở WWDC 2015.

0 0 28

- vừa được xem lúc

Ví dụ về UIActivityViewController

Trên iOS, UIActivityViewController cung cấp giao diện thống nhất để người dùng chia sẻ và thực hiện các hành động trên văn bản, hình ảnh, URL và các mục khác trong ứng dụng. let string = "Hello, world!". let url = URL(string: "https://nshipster.com").

0 0 45

- vừa được xem lúc

Quản lý self và cancellable trong Combine.

. . Công việc quản lý bộ nhớ memory management thường trở nên phức tạp khi chúng ta thực hiện các tác vụ bất đồng bộ asynchronous vì chúng ta thường phải lưu giữ một số object nằm ngoài scope mà object được define trong khi vẫn phải đảm bảo được việc giải phóng object đó được thực hiện đúng quy trìn

0 0 28