MST

星途 面试题库

面试题:Flutter 网络请求异常处理与 UI 优雅降级

在复杂的Flutter应用场景下,网络请求可能遇到各种异常,如网络超时、服务器内部错误、解析数据失败等。当这些异常发生时,不仅要给用户友好的提示,还要保证UI处于一个合理的、降级后的可用状态(例如显示缓存数据,如果有缓存的话)。请设计一套完整的网络请求异常处理与UI优雅降级的架构,并说明各部分的职责及交互流程。
30.8万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

架构设计

  1. 网络请求层
    • 职责:负责发起实际的网络请求,处理网络相关的基础操作,如设置请求头、处理HTTP状态码等。使用如httpdio库进行网络请求。
    • 示例代码(以dio为例)
import 'package:dio/dio.dart';

class NetworkService {
  final Dio dio = Dio();

  Future<Response> get(String url, {Map<String, dynamic>? queryParameters}) async {
    try {
      return await dio.get(url, queryParameters: queryParameters);
    } catch (e) {
      throw NetworkException.fromDioError(e);
    }
  }
}
  1. 异常处理层
    • 职责:捕获网络请求层抛出的异常,将其转换为自定义的异常类型,并根据异常类型进行分类处理。比如区分网络超时、服务器错误、解析失败等异常。
    • 自定义异常类
class NetworkException implements Exception {
  final String message;
  final int? statusCode;

  NetworkException(this.message, {this.statusCode});

  factory NetworkException.fromDioError(DioError error) {
    switch (error.type) {
      case DioErrorType.connectTimeout:
        return NetworkException('网络连接超时', statusCode: error.response?.statusCode);
      case DioErrorType.sendTimeout:
        return NetworkException('网络发送数据超时', statusCode: error.response?.statusCode);
      case DioErrorType.receiveTimeout:
        return NetworkException('网络接收数据超时', statusCode: error.response?.statusCode);
      case DioErrorType.response:
        return NetworkException('服务器错误 ${error.response?.statusCode}', statusCode: error.response?.statusCode);
      case DioErrorType.cancel:
        return NetworkException('网络请求已取消');
      case DioErrorType.other:
        return NetworkException('网络其他错误');
    }
  }
}
  1. 数据缓存层
    • 职责:负责缓存网络请求的数据。可以使用如shared_preferences(简单数据缓存)或hive(更复杂数据结构缓存)。缓存的数据应包含过期时间,以便判断数据是否仍然有效。
    • 示例代码(以shared_preferences缓存简单字符串数据为例)
import 'package:shared_preferences/shared_preferences.dart';

class CacheService {
  static const String cacheKeyPrefix = 'network_cache_';

  Future<void> saveCache(String key, String value, {int durationInSeconds = 3600}) async {
    final prefs = await SharedPreferences.getInstance();
    final cacheData = '$value|${DateTime.now().millisecondsSinceEpoch + durationInSeconds * 1000}';
    await prefs.setString('$cacheKeyPrefix$key', cacheData);
  }

  Future<String?> getCache(String key) async {
    final prefs = await SharedPreferences.getInstance();
    final cacheData = prefs.getString('$cacheKeyPrefix$key');
    if (cacheData == null) return null;
    final parts = cacheData.split('|');
    final expirationTime = int.parse(parts[1]);
    if (DateTime.now().millisecondsSinceEpoch > expirationTime) {
      await prefs.remove('$cacheKeyPrefix$key');
      return null;
    }
    return parts[0];
  }
}
  1. UI层
    • 职责:向网络请求层发起数据请求,接收异常处理层传递的异常信息并展示友好提示给用户。当发生异常时,尝试从数据缓存层获取缓存数据并展示。
    • 示例代码(使用FutureBuilder
import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final NetworkService networkService = NetworkService();
  final CacheService cacheService = CacheService();
  String? data;
  String? errorMessage;

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  Future<void> _fetchData() async {
    try {
      final response = await networkService.get('https://example.com/api/data');
      data = response.data.toString();
      await cacheService.saveCache('my_data_key', data!);
    } on NetworkException catch (e) {
      errorMessage = e.message;
      final cachedData = await cacheService.getCache('my_data_key');
      if (cachedData != null) {
        data = cachedData;
      }
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('网络请求异常处理'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (errorMessage != null)
              Text('错误: $errorMessage'),
            if (data != null)
              Text('数据: $data'),
          ],
        ),
      ),
    );
  }
}

交互流程

  1. 正常流程
    • UI层发起网络请求到网络请求层。
    • 网络请求层成功获取数据后返回给UI层,UI层更新界面展示数据。同时,数据缓存层将数据进行缓存。
  2. 异常流程
    • UI层发起网络请求到网络请求层。
    • 网络请求层发生异常,将异常抛给异常处理层。
    • 异常处理层将异常转换为自定义异常类型并返回给UI层。
    • UI层收到异常后,展示友好的错误提示给用户。同时,尝试从数据缓存层获取缓存数据,如果有且未过期,则展示缓存数据,保证UI处于可用状态。