InterceptorとDioを一緒に使用しようとしています。トークンの期限切れを処理する必要があります。以下は私のコードです
Future<Dio> getApiClient() async {
token = await storage.read(key: USER_TOKEN);
_dio.interceptors.clear();
_dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) {
// Do something before request is sent
options.headers["Authorization"] = "Bearer " + token;
return options;
},onResponse:(Response response) {
// Do something with response data
return response; // continue
}, onError: (DioError error) async {
// Do something with response error
if (error.response?.statusCode == 403) {
// update token and repeat
// Lock to block the incoming request until the token updated
_dio.interceptors.requestLock.lock();
_dio.interceptors.responseLock.lock();
RequestOptions options = error.response.request;
FirebaseUser user = await FirebaseAuth.instance.currentUser();
token = await user.getIdToken(refresh: true);
await writeAuthKey(token);
options.headers["Authorization"] = "Bearer " + token;
_dio.interceptors.requestLock.unlock();
_dio.interceptors.responseLock.unlock();
_dio.request(options.path, options: options);
} else {
return error;
}
}));
_dio.options.baseUrl = baseUrl;
return _dio;
}
問題は、新しいトークンでネットワーク呼び出しを繰り返すのではなく、Dioが呼び出し側のメソッドにエラーオブジェクトを返し、それが今度は間違ったウィジェットをレンダリングしていることです。
私は次の方法でインターセプターを使用してそれを解決しました:-
Future<Dio> getApiClient() async {
token = await storage.read(key: USER_TOKEN);
_dio.interceptors.clear();
_dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) {
// Do something before request is sent
options.headers["Authorization"] = "Bearer " + token;
return options;
},onResponse:(Response response) {
// Do something with response data
return response; // continue
}, onError: (DioError error) async {
// Do something with response error
if (error.response?.statusCode == 403) {
_dio.interceptors.requestLock.lock();
_dio.interceptors.responseLock.lock();
RequestOptions options = error.response.request;
FirebaseUser user = await FirebaseAuth.instance.currentUser();
token = await user.getIdToken(refresh: true);
await writeAuthKey(token);
options.headers["Authorization"] = "Bearer " + token;
_dio.interceptors.requestLock.unlock();
_dio.interceptors.responseLock.unlock();
return _dio.request(options.path,options: options);
} else {
return error;
}
}));
_dio.options.baseUrl = baseUrl;
return _dio;
}
トークンの有効期限が切れると、応答ステータスコードは401になります。新しいアクセストークンを要求するには、postメソッドをform dataおよび必須のDioのoptions(content-typeおよびheaders)とともに使用する必要があります。以下のコードは、新しいトークンをリクエストする方法を示しています。
リクエストが成功した後、レスポンスステータスコードを200として取得した場合、新しいアクセストークンの値と更新トークンの値を取得し、使用したいストレージに保存します。たとえば、共有設定。
新しいアクセストークンを保存したら、それを使用して、以下の同じコードに示すgetメソッドを使用してデータをフェッチできます。
onError(DioError error) async {
if (error.response?.statusCode == 401) {
Response response;
var authToken = base64
.encode(utf8.encode("username_value" + ":" + "password_value"));
FormData formData = new FormData.from(
{"grant_type": "refresh_token", "refresh_token": refresh_token_value});
response = await dio.post(
url,
data: formData,
options: new Options(
contentType: ContentType.parse("application/x-www-form-urlencoded"),
headers: {HttpHeaders.authorizationHeader: 'Basic $authToken'}),
);
if (response.statusCode == 200) {
response = await dio.get(
url,
options: new Options(headers: {
HttpHeaders.authorizationHeader: 'Bearer access_token_value'
}),
);
return response;
} else {
print(response.data);
return null;
}
}
return error;
}