how to resend multipart request

581 Views Asked by At

I am retrying my api call if get 401 response but when Retrying I am ending with an following exception Bad state following is my code for retrying multipart I had used http_interceptor package for retrying Api Calls interceptor.dart

class AuthorizationInterceptor extends InterceptorContract {
  @override
  Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
    final prefs = await SharedPreferences.getInstance();

    final extractData =
        json.decode(prefs.getString('userData')!) as Map<String, dynamic>;

    final Map<String, String> headers = Map.from(request.headers);
    headers['Authorization'] = await extractData['accessToken'];
    print(
        'this is from AuthorizationInterceptor: ${extractData['accessToken']}');
    // TODO: implement interceptRequest

    return request.copyWith(
      headers: headers,
    );
  }

retry.dart

class ExpiredTokenRetryPolicy extends RetryPolicy {
  BuildContext context;
  ExpiredTokenRetryPolicy(this.context);
  @override
  // TODO: implement maxRetryAttempts
  int get maxRetryAttempts => 2;

  @override
  Future<bool> shouldAttemptRetryOnResponse(BaseResponse response) async {
    if (response.statusCode == 401) {
      print('retry token started');
      //perform token refresh,get the new token and update it in the secure storage

      await Provider.of<Auth>(context, listen: false).restoreAccessToken();
      return true;
    }
    return false;
  }

I am using interceptors in my widget following is my code where I am using interceptors and using retry policy

@override
  Widget build(BuildContext context) {
    var flutterFunctions = Provider.of<FlutterFunctions>(context);

    // print('this is from insert package${token.token}');
    ApiCalls repository = ApiCalls(
      client: InterceptedClient.build(
        retryPolicy: ExpiredTokenRetryPolicy(context),
        interceptors: [
          AuthorizationInterceptor(),
        ],
      ),
    );

following is my restore access token method

Future<void> restoreAccessToken() async {
    print('restoreAccessToken started');

    //print(token);
    final url = '${Ninecabsapi().urlHost}${Ninecabsapi().login}/$sessionId';

    var response = await http.patch(
      Uri.parse(url),
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': accessToken!
      },
      body: json.encode(
        {"refresh_token": refreshtoken},
      ),
    );
    var userDetails = json.decode(response.body);

    if (response.statusCode == 401) {
      print(userDetails['messages']);
    }

    sessionId = userDetails['data']['session_id'];
    accessToken = userDetails['data']['access_token'];
    accessTokenExpiryDate = DateTime.now().add(
      Duration(seconds: userDetails['data']['access_token_expiry']),
    );
    refreshToken = userDetails['data']['refresh_token'];
    refreshTokenExpiryDate = DateTime.now().add(
      Duration(seconds: userDetails['data']['refresh_token_expiry']),
    );
    final userData = json.encode({
      'sessionId': sessionId,
      'refreshToken': refreshToken,
      'refreshExpiry': refreshTokenExpiryDate!.toIso8601String(),
      'accessToken': accessToken,
      'accessTokenExpiry': accessTokenExpiryDate!.toIso8601String()
    });
    //print(userDetails);

    notifyListeners();
    final prefs = await SharedPreferences.getInstance();

    prefs.setString('userData', userData);
    print("this is from restoreAcessToken :$userDetails");
    final extractData =
        json.decode(prefs.getString('userData')!) as Map<String, dynamic>;
    print('restore access token: ${extractData['accessToken']}');
    reset();
  }
1

There are 1 best solutions below

1
On

As a rule. You must NOT write using the same Stream/MultipartFile more than once. If you need to retry sending to the same destination, you have to use a new MultipartFile each time you retry.