Flutter 如何优化flatter-dio令牌一次刷新请求

Flutter 如何优化flatter-dio令牌一次刷新请求,flutter,Flutter,现在我使用dio(4.0.0)作为Flatter 2.x中的http客户端,我想刷新令牌,但现在我遇到了一个问题:当auth令牌无效时,我只想向服务器发送一个请求来刷新令牌。但是现在http请求是异步的,当令牌无效时,许多请求发送到服务器以刷新令牌,虽然令牌最终可以成功刷新,但您知道服务器必须处理一些无效的重复令牌刷新请求。我应该如何优化客户端?只有一个请求发送到服务器以刷新令牌?这是我现在使用的代码: class AppInterceptors extends InterceptorsWrap

现在我使用dio(
4.0.0
)作为Flatter 2.x中的http客户端,我想刷新令牌,但现在我遇到了一个问题:当auth令牌无效时,我只想向服务器发送一个请求来刷新令牌。但是现在http请求是异步的,当令牌无效时,许多请求发送到服务器以刷新令牌,虽然令牌最终可以成功刷新,但您知道服务器必须处理一些无效的重复令牌刷新请求。我应该如何优化客户端?只有一个请求发送到服务器以刷新令牌?这是我现在使用的代码:

class AppInterceptors extends InterceptorsWrapper {
  @override
  Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    if (!options.headers.containsKey("token")) {
      String? token = await storage.read(key: "token");
      options.headers["token"] = token;
    }
    handler.next(options);
  }

  @override
  Future onResponse(Response response, ResponseInterceptorHandler handler) async {
    autoLogin(response);
    return super.onResponse(response, handler);
  }

  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    return super.onError(err, handler);
  }

  void autoLogin(Response response) async {
    String loginInvalidCode = ResponseStatus.LOGIN_INVALID.statusCode;
    String notLoginCode = ResponseStatus.NOT_LOGIN.statusCode;
    String statusCode = response.data["statusCode"];
    if (statusCode == loginInvalidCode || statusCode == notLoginCode) {
      Dio dio = RestClient.createDio();
      String? userName = await storage.read(key: "username");
      String? password = await storage.read(key: "password");
      if (userName != null && password != null) {
        refreshAuthToken(dio, userName, password, response);
      } else {
        NavigationService.instance.navigateToReplacement("login");
      }
    }
  }

  void refreshAuthToken(Dio dio, String userName, String password, Response response) async {
    dio.lock();
    try {
      AuthResult result = await Auth.login(username: userName, password: password, loginType: LoginType.PHONE);
      if (result.result == Result.ok) {
        // resend a request to fetch data
        Dio req = RestClient.createDio();
        req.request(response.requestOptions.path);
      }
    } on Exception catch (e) {
      CruiseLogHandler.logErrorException("login failed", e);
    } finally {
      dio.unlock();
    }
  }
}
类AppInterceptors扩展了InterceptorsWrapper{
@凌驾
未来onRequest(RequestOptions选项、RequestInterceptorHandler处理程序)异步{
if(!options.headers.containsKey(“令牌”)){
String?token=wait storage.read(键:“token”);
options.headers[“token”]=token;
}
handler.next(选项);
}
@凌驾
未来onResponse(响应响应,响应InterceptorHandler)异步{
自体蛋白(应答);
返回super.onResponse(response,handler);
}
@凌驾
未来onError(DioError错误,ErrorInterceptorHandler)异步{
返回super.onError(err,handler);
}
void autoLogin(响应-响应)异步{
字符串loginValidCode=ResponseStatus.LOGIN\u无效的状态码;
字符串notLoginCode=ResponseStatus.NOT\u LOGIN.statusCode;
字符串statusCode=response.data[“statusCode”];
if(状态代码==LoginValidCode | |状态代码==notLoginCode){
Dio-Dio=RestClient.createDio();
字符串?用户名=等待存储。读取(键:“用户名”);
字符串?密码=等待存储。读取(键:“密码”);
如果(用户名!=null和密码!=null){
refreshAuthToken(dio、用户名、密码、响应);
}否则{
NavigationService.instance.navigateToReplacement(“登录”);
}
}
}
void refreshAuthToken(Dio Dio、字符串用户名、字符串密码、响应)异步{
锁();
试一试{
AuthResult结果=等待身份验证登录(用户名:用户名,密码:密码,登录类型:loginType.PHONE);
if(result.result==result.ok){
//重新发送请求以获取数据
Dio req=RestClient.createDio();
请求(response.requestOptions.path);
}
}关于异常捕获(e){
logErrorException(“登录失败”,e);
}最后{
dio.unlock();
}
}
}

最好只向服务器发送一个刷新令牌的请求。但我不知道怎么做。我希望刷新逻辑更加流畅。

我只是将此作为一个答案发布,因为将所有这些内容都写在评论中很麻烦

我正要向你推荐拦截器,但你已经这么做了

即使您有重复的请求?

我看到的另一件事是,您在
onResponse

我认为可以更精细,如:


@凌驾
未来onResponse(响应响应,响应InterceptorHandler)异步{
如果(响应?.statusCode==401){
//我认为你应该把锁移到这里,这样你就可以更早地停止其他请求。
//interceptors.requestLock.lock();
等待(回应);//这里缺少等待
//dio.interceptors.requestLock.unlock()
}
返回super.onResponse(response,handler);
}

我还注意到,传递一个新客户机时的名称是
Dio-Dio=RestClient.createDio()
这是一个单例吗?因为如果不是,你可能会锁定另一个客户端

我只是将此作为一个答案发布,因为在注释中写入所有这些内容很麻烦

我正要向你推荐拦截器,但你已经这么做了

即使您有重复的请求?

我看到的另一件事是,您在
onResponse

我认为可以更精细,如:


@凌驾
未来onResponse(响应响应,响应InterceptorHandler)异步{
如果(响应?.statusCode==401){
//我认为你应该把锁移到这里,这样你就可以更早地停止其他请求。
//interceptors.requestLock.lock();
等待(回应);//这里缺少等待
//dio.interceptors.requestLock.unlock()
}
返回super.onResponse(response,handler);
}

我还注意到,传递一个新客户机时的名称是
Dio-Dio=RestClient.createDio()这是单例吗?因为如果不是,您可能会锁定另一个客户端

您这里的问题是发出了多个请求,并且令牌无效,因为拦截器,所有这些请求都将尝试从服务器刷新令牌?我说得对吗?是的,很多请求都发送到服务器,但我只希望一个请求发送到服务器,而另一个请求应该停止并等待令牌刷新并升级本地cahe,有没有更好的方法使其像这样工作。有什么建议吗@Croxx5fy您的问题是发出了多个请求,并且令牌无效,由于拦截器的原因,所有这些请求都将尝试从服务器刷新令牌?我说得对吗?是的,很多请求都发送到服务器,但我只希望一个请求发送到服务器,而另一个请求应该停止并等待令牌刷新并升级本地cahe,有没有更好的方法使其像这样工作。有什么建议吗@croxx5f