Why does flutter dio interceptor not invoking the method?
Asked Answered
W

1

6

I am working on a flutter application which uses JWT to access backend endpoints. When the access token expires, I added an interceptor to refresh the token based on the solutions provided here: Using Interceptor in Dio for Flutter to Refresh Token I could see server logs which says 401.

Here is my code:

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:dummy/utils/config.dart';

Future<Response> uploadVideo(filePath, fileName, title, jwt) async {
  Dio dio = new Dio();
  var token = json.decode(jwt);
  dio.interceptors.clear();

  dio.options.headers["Authorization"] = "Bearer ${token['access']}";
  dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    _retry(error.request, dio);
     }
    return error.response;
  }));
  Response response;
  try {
    FormData formData = FormData.fromMap({
      "file_name": fileName,
      "content": await MultipartFile.fromFile(filePath),
      'title': title,
    });
    response = await dio.post("$BASE_URL/video/create/", data: formData);
    return response;
  } on DioError catch (e) {
    if (e.response) {
      print(e.response.data);
      print(e.response.headers);
      print(e.response.request);
    } else {
      // Something happened in setting up or sending the request that triggered an Error
      print(e.request);
      print(e.message);
    }
    return e.response;
  }
}

Future<Response<dynamic>> _retry(RequestOptions requestOptions, Dio dio) async {
  final options = new Options(
    method: requestOptions.method,
    headers: requestOptions.headers,
  );
  return dio.request<dynamic>(requestOptions.path,
      data: requestOptions.data,
      queryParameters: requestOptions.queryParameters,
      options: options);
}

Future<Response> refreshToken(jwt) async {
  print("COMING INSIDE");
  Dio dio = new Dio();
  var token = json.decode(jwt);
  var refreshToken = token['refresh'];
  Response response;
  try {
    FormData formData = FormData.fromMap({
      "refresh": refreshToken,
    });
    response = await dio.post("$BASE_URL/auth/login/refresh/", data: formData);
    return response;
  } catch (e) {
    return e.response;
  }
}

I tried with debugger as well, but its not executing the code after if statement where it checks for 401 and 403. Server clearly gives 401 as I am running it locally so I can see the logs.

What am I doing wrong here?

Thanks in advance.

Wow answered 23/3, 2021 at 15:4 Comment(21)
could you provide an output example of print(error.response);?Wilterdink
Hi, I am getting this ` DioError [DioErrorType.DEFAULT]: SocketException: OS Error: Broken pipe, errno = 32, address = 172.22.22.55, port = 47164.response `Wow
I could confirm the app reaches the backend server, have login and register screens which works fine.Wow
Did this happen with the upgrade to dio 4?Grimm
@Anoop.P.AI didnt upgrade to dio 4, am on 3.0.10, is there a 4 version? I thought the latest is 3.0.10Wow
Is there any restriction on the file size on the server side? Check thisKilligrew
Nope, the same endpoint was working fine with sending files before JWT restriction was applied.Wow
As I said earlier as well, I could see my server logs, it says 401Wow
could you please print out more things and show it in your question. e.g. print out error.response?.statusCode in your onError.Streaming
error.response?.statusCode is not printing ..its null as error.response is not thereWow
@Wow could you please give a minimal reproducible sample, then I can debug on it. p.s. please "@ch271828n" otherwise I cannot see your replyStreaming
@Wow maybe you have a problem with the refresh token itself ?Unbated
based on your print(error.response); output I think it could be an endpoint issue check this link. I think you need to hadle if(e.error is SocketException) case also.Brim
You are getting a DioErrorType.DEFAULT which has no response and thus also no status code. Only DioErrorType.RESPONSE has a response attached. This also means your error probably has nothing to with the refresh token or the server response. You are likely seeing some problem due to TLS, proxy, connection abort, whatever. Something in between the server and Dio.Edelsten
Hi @Edelsten I could see the logs on the server end, request is reaching there.Wow
No doubt there but the response is not coming back. The socket is being closed before the response can be read, write timeout, whatever. SocketException: OS Error: Broken pipe, errno = 32 is your problem. You need to investigate there, I don't think anyone here can help you.Edelsten
@Wow print the error object in the first line of your error callback to check which existing DioError types are occurring the error.response exists only if the error type is DioErrorType.response if other error types are happing for example DioErrorType.connectTimeout or DioErrorType.other those have their own problem and they are not related to the status code of the responseAppal
@Wow if your token is based on jwt, you can check token is expired or not with jwt_decoder package instead of adding interceptorDaffie
I face kinda the same thing in dio 3.0.10. Have tried dio 4.0.0?Creodont
@Creodont did it work for you in 4.0.0? Havent tried it yet.Wow
No I haven't but I guess it may work. For your auth flow this issue may offer some help github.com/flutterchina/dio/issues/590Creodont
E
1

I think the problem is in your Interceptor:

dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    _retry(error.request, dio);
     }
    return error.response;
  }));

You're calling retry method, but:

  • you don't wait for result;
  • you return an error anyway.

Try to add return before _retry instead:

dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    return _retry(error.request, dio);
     }
    return error.response;
  }));
Eos answered 27/3, 2021 at 15:4 Comment(1)
Hey, thanks for replying. I would think this could be the case if the execution reaches that if block, but it doest as statuscode is not present.Wow

© 2022 - 2024 — McMap. All rights reserved.