在flutter中上传图片文件的最佳实践

问题描述 投票:0回答:1

我对图像上传场景相当陌生,社区能否建议将图像文件上传到服务器时遵循的最佳实践。端点已经开发出来,现在我正在使用 dio 和改造直接调用 api。我想了解基于行业标准的最佳实践,其中包括错误处理和处理任何其他场景,例如重新上传等..

flutter amazon-s3 image-upload
1个回答
0
投票

如果您使用 dio,您可能熟悉“拦截器”,对吗? 有很多方法可以让你的拦截器变得干净。这是我的

class AppInterceptors extends Interceptor {
  const AppInterceptors(this.dio);
  final Dio dio;

  @override
  void onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    String? token = await TokenStorage.getToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }

    super.onRequest(options, handler);
  }

  @override
  Future<void> onError(
    DioException err,
    ErrorInterceptorHandler handler,
  ) async {
    ErrorResponse resp = ErrorResponse.fromJson(err.response?.data);
    log(
      '[${err.response?.statusCode ?? '?'}] ${err.message}',
      name: 'interceptor',
    );
    log('Error ID: ${resp.error?.errorId}', name: 'Interceptor');
    log('Error Messages:', name: 'Interceptor');
    for (String msg in resp.error?.errorMessages ?? <String>[]) {
      log('  - $msg', name: 'Interceptor');
    }

    bool unauthorized = err.response?.statusCode == 401;
    String? refreshToken = await TokenStorage.getRefreshToken();
    log('${err.response?.statusCode} and $unauthorized', name: 'findme');

    if (unauthorized && refreshToken.notEmptyOrNull) {
      AuthApi refresher = AuthApi.create(dio);
      LoginResponse? refreshResult = await refresher
          .refreshToken(
        RefreshTokenRequest(refreshToken: refreshToken).toJson(),
      )
          .onError<DioException>((DioException? error, StackTrace stackTrace) {
        Future<void>.microtask(() async {
          log('expiredRefreshToken: $refreshToken');

          await TokenStorage.deleteAllToken();
          ToastHelper.error('Session expired, please login again.');

          throwToAuthScreen();
        });

        return null;
      });

      if (refreshResult != null) {
        await TokenStorage.writeToken(refreshResult.jwtToken ?? '');
        await TokenStorage.writeRefreshToken(refreshResult.refreshToken ?? '');

        // retry the previous request
        RequestOptions options = err.requestOptions;
        options.headers['Authorization'] = 'Bearer ${refreshResult.jwtToken}';
        try {
          Response<dynamic> response = await dio.fetch(options);
          return handler.resolve(response);
        } catch (e) {
          ToastHelper.error(
            'An unknown error occurred, please try again later.',
          );
          return;
        }
      }
    } else {
      throwToAuthScreen();
      ToastHelper.error('There was a problem, Please try again.');
    }

    return handler.reject(err);
  }
}

这是我的 http_client

class HttpClient {
  static Dio init({
    required String baseUrl,
    int sendTimeout = 60000,
    int connectTimeout = 60000,
    int receiveTimeout = 60000,
    String contentType = Headers.jsonContentType,
    ResponseType responseType = ResponseType.plain,
  }) {
    Dio dio = Dio(BaseOptions(
      baseUrl: baseUrl,
      receiveTimeout: Duration(seconds: receiveTimeout),
      connectTimeout: Duration(seconds: connectTimeout),
      sendTimeout: Duration(seconds: sendTimeout),
      contentType: contentType,
      responseType: responseType,
    ));

    // TODO(Andrew): add ssl pinning
    // dio.interceptors.add(
    //   CertificatePinningInterceptor(),
    // );

    dio.interceptors.add(AppInterceptors(dio));
    dio.interceptors.add(PrettyDioLogger(
      request: kDebugMode,
      requestBody: kDebugMode,
      requestHeader: kDebugMode,
      responseHeader: false,
      responseBody: kDebugMode,
      error: true,
      logPrint: (Object object) => log(
        object.toString(),
        name: DateTime.now().toTimeShort,
      ),
      maxWidth: 80,
    ));
    dio.interceptors.add(CurlLoggerDioInterceptor(printOnSuccess: true));
    dio.interceptors.add(RetryInterceptor(
      dio: dio,
      retries: 3,
      retryDelays: <Duration>[3.seconds, 5.seconds, 15.seconds],
    ));

    return dio;
  }
}

RetryInterceptor 是 dio 拦截器的封装和扩展。你可以制作自己的拦截器,就像我上面写的那样(AppInterceptor)这个拦截器有3个功能:onRequest、onError、onResponse。 正如其名称所示,这 3 个函数是不言自明的。您可以拥有许多拦截器,使您能够管理应用程序的每个请求,例如将令牌添加到标头,有很多方法可以做到这一点,但在我的代码中,我将其尽可能模块化。与 Riverpod 结合,我可以使用 Riverpod 制作多个端点并模块化使用它

@riverpod
class DioClient extends _$DioClient {
  @override
  Dio build() {
    return HttpClient.init(baseUrl: F.baseUrl);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.