現在私はアプリ側でAlamofireを用いてAPIを実装をしておりますが、通信のリトライの実装に関して気になったことがあったので、 備忘録的ではありますがここで紹介したいと思います。
結論
- Alamofireで通信のリトライが実現できる
setValueメソッドを用いるとHTTPヘッダを書き換えることができる
開発環境
- Xcode 8.2.1
- Swift 3.0.2
詳細
通信機能を実装する際に、以下のような流れで通信のリトライを行いたいのはよくある話だと思います。
- 何某かのAPIを叩く
- アクセストークンが有効期限切れになっている
- アクセストークンを再取得する
- HTTPヘッダに新たに取得したアクセストークンを詰めて再度同じリクエストを行う
ぱっと思いつく方法としては、以下のように同じ引数でリクエストを行うメソッドを再度呼び出すことが挙げられますが、 重複したコードになったりと何かと煩雑になりがちです。実装の工夫次第にはなりますが・・・
let dataRequest: DataRequest = Alamofire.request("https://hoge.huga.com/piyo",
method: HTTPMethod.get,
parameters: [
"key1": "value1",
"key2": "value2"
],
encoding: URLEncoding.methodDependent,
headers: [
"headerKey1": "headerValue1",
"headerKey2": "headerValue2",
"accesstoken": "[oldAccessToken]"
])
dataRequest.responseString(completionHandler: { (_) -> Void in
// 中略(アクセストークン有効期限切れにより、「"[newAccessToken]"」というアクセストークンを新たに取得したとする)
// リクエストのリトライを行う
let dataRetryRequest: DataRequest = Alamofire.request("https://hoge.huga.com/piyo",
method: HTTPMethod.get,
parameters: [
"key1": "value1",
"key2": "value2"
],
encoding: URLEncoding.methodDependent,
headers: [
"headerKey1": "headerValue1",
"headerKey2": "headerValue2",
"accesstoken": "[newAccessToken]"
])
dataRetryRequest.responseString(completionHandler: { (_) -> Void in
// 以下省略...
})
})
そこで、通信して返却されたレスポンスオブジェクトのプロパティを調べてみると、
URLRequest?型の response.requestというものが見つかりました。
この
response.requestには元々のリクエストがどのようなHTTPヘッダを持っているのかなどといった情報が入っているようです。
そのため、これをアンラップしたものをAlamofireによる通信のリクエストを行うメソッドの引数に入れることで、通信のリトライを実装しました。
また、再取得したアクセストークンをHTTPヘッダに詰めたかったので、
リトライを行う前に
setValueメソッドを使用しました。
上記を踏まえると、先程のコードは以下のようになりました。
let dataRequest: DataRequest = Alamofire.request("https://hoge.huga.com/piyo",
method: HTTPMethod.get,
parameters: [
"key1": "value1",
"key2": "value2"
],
encoding: URLEncoding.methodDependent,
headers: [
"headerKey1": "headerValue1",
"headerKey2": "headerValue2",
"accesstoken": "[oldAccessToken]"
])
dataRequest.responseString(completionHandler: { (response: Alamofire.DataResponse<String>) -> Void in
// 中略(アクセストークン有効期限切れにより、「"[newAccessToken]"」というアクセストークンを新たに取得したとする)
// レスポンスからリクエストオブジェクトを得る
guard var request: URLRequest = response.request else {
return
}
// リクエストのHTTPヘッダーにアクセストークンを詰める
request.setValue("[newAccessToken]", forHTTPHeaderField: "accesstoken")
// 通信のリトライを行う
let dataRetryRequest: DataRequest = Alamofire.request(request)
dataRetryRequest.responseString(completionHandler: { (_) -> Void in
// 以下省略...
})
})
リトライの部分が一行で済むのはうれしいですね。 若干ですが、重複したコードが無くなっただけにだいぶすっきりしたように感じます。
福成毅
2年目のiOSエンジニアです!