flutter Dio插件的使用 (十三)

本文详细介绍了如何在Flutter中使用Dio库进行HTTP请求,并通过自定义拦截器实现token验证、日志记录等功能。实例展示了get、post和delete方法的封装,以及登录请求处理过程。

AI 驱动代码审查实战

Claude code-review 插件深度解析,把 AI 智能审查接进 CI/CD 流水线

Dio对象在App请求中一般在单例对象中使用,用来与后端进行普通的网络请求,如POST\GET等。Dio支持使用拦截器对所有的请求进行拦截,从而进行特殊处理,如增加token参数、请求和响应日志记录等。参考代码片段:

引用头文件:

import 'package:dio/dio.dart';
import 'interceptor/http_interceptor.dart';

在类的构造中,添加自定义的拦截器:

class ThingsboardClient {
        ///......
        
  factory ThingsboardClient() {
    var dio = Dio();
    dio.options.baseUrl = apiEndpoint;
    dio.interceptors.clear();
    dio.interceptors.add(HttpInterceptor());
    ///......
  }

自定义的拦截器,拦截所有的API类型的请求,并添加token:

class HttpInterceptor extends Interceptor {
  static const String _authScheme = 'Bearer ';
  static const _authHeaderName = 'X-Authorization';
  ///...
  
  @override
  Future onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    if (options.path.startsWith('/api/')) {
      var config = _getInterceptorConfig(options);
      var isLoading = !_isInternalUrlPrefix(options.path);
      if (!config.isRetry) {
        _updateLoadingState(config, isLoading);
      }
       ///路径是否需要token
      if (_isTokenBasedAuthEntryPoint(options.path)) {
        ///token是否有效
        if (_tbClient.getJwtToken() == null &&
            !_tbClient.refreshTokenPending()) {
          return _handleRequestError(
              options, handler, ThingsboardError(message: 'Unauthorized!'));
        } else if (!_tbClient.isJwtTokenValid()) {
            ///token不可用,返回错误,刷新token后,重新提交请求
            return _handleRequestError(
              options, handler, ThingsboardError(refreshTokenPending: true));
        } else {
              ///处理请求,添加token等头信息
          return _jwtIntercept(options, handler);
        }
      } else {
        return _handleRequest(options, handler);
      }
    } else {
      return handler.next(options);
    }
  }

  ///需要启用token的路径
  bool _isTokenBasedAuthEntryPoint(String url) {
    return url.startsWith('/api/') &&
        !url.startsWith(Constants.entryPoints['login']!) &&
        !url.startsWith(Constants.entryPoints['tokenRefresh']!) &&
        !url.startsWith(Constants.entryPoints['nonTokenBased']!);
  }


  bool _updateAuthorizationHeader(RequestOptions options) {
    var jwtToken = _tbClient.getJwtToken();
    if (jwtToken != null) {
      options.headers[_authHeaderName] = _authScheme + jwtToken;
      return true;
    } else {
      return false;
    }
  }

  Future _jwtIntercept(
      RequestOptions options, RequestInterceptorHandler handler) async {
    ///更新头授权token等信息
    if (_updateAuthorizationHeader(options)) {
      return _handleRequest(options, handler);
    } else {
      return _handleRequestError(options, handler,
          ThingsboardError(message: 'Could not get JWT token from store.'));
    }
  }

   ///...
}

封装后的 get、post、delete代码示例: 


  Future<Response<T>> get<T>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      return await _dio.get(path,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onReceiveProgress: onReceiveProgress);
    } catch (e) {
      throw toThingsboardError(e);
    }
  }

  Future<Response<T>> post<T>(
    String path, {
    data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      return await _dio.post(path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress);
    } catch (e) {
      throw toThingsboardError(e);
    }
  }

  Future<Response<T>> delete<T>(
    String path, {
    data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      return await _dio.delete(path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken);
    } catch (e) {
      throw toThingsboardError(e);
    }
  }

定义请求和应答对象:

class LoginRequest {
  String username;
  String password;

  LoginRequest(this.username, this.password);

  Map<String, dynamic> toJson() {
    return {
      'username': username,
      'password': password,
    };
  }
}

class LoginResponse {
  final String token;
  final String refreshToken;

  LoginResponse(this.token, this.refreshToken);

  LoginResponse.fromJson(Map<String, dynamic> json)
      : token = json['token'],
        refreshToken = json['refreshToken'];
}

提交请求(代码中为用户登录,并获取token和refreshToken):

 Future<LoginResponse> login(LoginRequest loginRequest,
      {RequestConfig? requestConfig}) async {
    var response = await post('/api/auth/login',
        data: jsonEncode(loginRequest),
        options: defaultHttpOptionsFromConfig(requestConfig));
    var loginResponse = LoginResponse.fromJson(response.data);
    await _setUserFromJwtToken(
        loginResponse.token, loginResponse.refreshToken, true);
    return loginResponse;
  }

AI 驱动代码审查实战

Claude code-review 插件深度解析,把 AI 智能审查接进 CI/CD 流水线

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值