簡體   English   中英

Flutter:在 http 調用期間令牌過期時如何刷新令牌?

[英]Flutter: How to Refresh token when token expires during http call?

我是 flutter 的新手,我正在使用http package 進行網絡呼叫。 如果請求的響應代碼為 200,我想刷新令牌並再次調用請求。如何使用 http package 來實現這一點? 我聽說過dio package 但對我來說很復雜。

User getUser(){

   final response = http.post(Uri.https(BASE_URL, '/api/user'), 
    headers: {'Authorization: Bearer $token'});

    if(response.statusCode == 200){
       return User.fromJson(jsonDecode(response.body)['user']);
    }
    else if(response.statusCode == 401){
      //refresh token and call getUser again     
    }

}

您可以按如下方式使用刷新令牌:

User getUser(){

   final response = http.post(Uri.https(BASE_URL, '/api/user'), 
    headers: {'Authorization: Bearer $token'});

    if(response.statusCode == 200){
       return User.fromJson(jsonDecode(response.body)['user']);
    }
    else if(response.statusCode == 401){
      //refresh token and call getUser again
      final response = http.post(Uri.https(BASE_URL, '/api/[YourAuthorizationEndpoint]'), 
    headers: {'grant_type': 'refresh_token', 'refresh_token': '$refresh_token'});
      token = jsonDecode(response.body)['token'];
      refresh_token = jsonDecode(response.body)['refresh_token'];
      return getUser();
    }

}

您可以使用 dart 的http/retry package:

import 'package:http/http.dart' as http;
import 'package:http_retry/http_retry.dart';

final client = RetryClient(
   http.Client(), 
   retries: 1,
   when: (response) {
    return response.statusCode == 401 ? true : false;
   },
   onRetry: (req, res, retryCount) {
     if (retryCount == 0 && res?.statusCode == 401) {
        // refresh token
     }  
   },
);

try {
  final response = await client.get('http://www.example.com');
} finally {
  client.close();
}

您可以使用Dio Package並創建一個客戶端 Class 並從那里管理所有請求。 在這里,我已經完成了 DIO package。

 class DioClient {
  final String baseUrl;

  Dio _dio = new Dio();

  DioClient(
    this.baseUrl,
  ) {
    _dio
      ..options.baseUrl = baseUrl
      ..options.connectTimeout = _defaultConnectTimeout
      ..options.receiveTimeout = _defaultReceiveTimeout
      ..httpClientAdapter
      ..options.responseType = ResponseType.json

    if (kDebugMode) {
      _dio.interceptors.add(LogInterceptor(
          responseBody: true,
          error: true,
          requestHeader: false,
          responseHeader: false,
          request: false,
          requestBody: false));
    }
  }

  Future<Response> get(
    String uri, {
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    ProgressCallback onReceiveProgress,
  }) async {
    try {
      var response = await _dio.get(
        uri,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return response;
    } on SocketException catch (e) {
      throw SocketException(e.toString());
    } on FormatException catch (_) {
      throw FormatException("Unable to process the data");
    } catch (error) {
      if (error is DioError) {
        switch (error.response.statusCode) {
          case 401:
            return await DioConnectivityRetrier(
                    dio: _dio, requestOptions: error.request)
                .requestRetrier();
            break;
          default:
            throw error;
            break;
        }
      } else {
        throw error;
      }
    }
  }

  Future<dynamic> post(
    String uri, {
    data,
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) async {
    try {
      var response = await _dio.post(
        uri,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      return response;
    } on FormatException catch (_) {
      throw FormatException("Unable to process the data");
    } catch (error) {
      if (error is DioError) {
        switch (error.response.statusCode) {
          case 401:
            return await DioConnectivityRetrier(
                    dio: _dio, requestOptions: error.request)
                .requestRetrier();
            break;
          default:
            throw error;
            break;
        }
      } else {
        throw error;
      }
      throw error;
    }
  }

  Future<Response> delete(
    String uri, {
    Map<String, dynamic> queryParameters,
    Map<String, dynamic> data,
    Options options,
    CancelToken cancelToken,
    ProgressCallback onReceiveProgress,
  }) async {
    try {
      var response = await _dio.delete(uri,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          data: data);
      return response;
    } on SocketException catch (e) {
      throw SocketException(e.toString());
    } on FormatException catch (_) {
      throw FormatException("Unable to process the data");
    } catch (error) {
      if (error is DioError) {
        switch (error.response.statusCode) {
          case 401:
            return await DioConnectivityRetrier(
                    dio: _dio, requestOptions: error.request)
                .requestRetrier();
            break;
          default:
            throw error;
            break;
        }
      } else {
        throw error;
      }
    }
  }
}

這是DioConnectivityRetrier class,所以每當您從 API 獲得 401 狀態時,我們的請求都會調用此 class。 我們可以使用相同的請求數據調用相同的 API 並獲取數據。 這里

 class DioConnectivityRetrier {

  final RequestOptions requestOptions;
  final Dio dio;
  BuildContext context;
  DioConnectivityRetrier({this.requestOptions, this.dio,this.context});

  Future<Response> requestRetrier() async {

    print('*** request retrier called');
    await APIService()
        .refreshToken()
        .catchError((error) => throw error);

    requestOptions.headers = {
      'Authorization': 'Bearer ${UserAccess.token}',
    };

    print('new token->' + UserAccess.token);
    try {
      return await dio.request(requestOptions.path,
          options: requestOptions,
          data: requestOptions.data,
          cancelToken: requestOptions.cancelToken,
          onReceiveProgress: requestOptions.onReceiveProgress,
          onSendProgress: requestOptions.onReceiveProgress,
          queryParameters: requestOptions.queryParameters);
    } catch (e) {
      throw NetworkExceptions.getDioException(e);
    }
  }
}

你可以像這樣使用它

  DioClient _dioClient = new DioClient(AppConstant.baseUrl);

 Response response = await _dioClient.post(apiUrl, data: data).catchError((error) => throw error);

到期后調用 api 刷新令牌

你可以使用這個[包][1]

[1]: https://pub.dev/packages/jwt_decoder檢查令牌是否過期

您還可以獲得自令牌創建以來的時間和到期日期

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM