跳转至正文

从互联网获取数据

如何发起 HTTP 请求并解析响应的说明。

学习 MVVM 架构模式,以及如何使用 async/await 构建 HTTP 请求。

你将完成的内容

理解 MVVM 架构模式
使用 async/await 构建 HTTP 请求
处理错误并解析 JSON 响应

步骤

1

简介

本教程实现的总体模式称为 模型-视图-视图模型 (Model-View-ViewModel) 或 MVVM。 MVVM 是一种用于客户端应用的架构模式,它将应用分为三层:

  • Model:处理数据操作。

  • View:显示 UI。

  • ViewModel:管理状态并连接前两者。

MVVM(及许多其他模式)的核心原则是 关注点分离。在单独的类中管理状态(在 UI widget 之外)使代码更易测试、复用和维护。

应用中的单个功能包含 MVVM 的每个组件。在本教程中,除了 Flutter widget 外,你还将创建 ArticleModelArticleViewModelArticleView

2

定义 Model

Model 是应用数据的唯一真实来源,负责底层任务,例如发起 HTTP 请求、缓存数据,或管理 Flutter 插件等使用的系统资源。 Model 通常不需要导入 Flutter 库。

main.dart 文件中创建一个空的 ArticleModel 类:

dart
class ArticleModel {
  // Properties and methods will be added here.
}
3

构建 HTTP 请求

Wikipedia 提供返回文章 JSON 数据的 REST API。在本应用中,你将使用返回随机文章摘要的端点。

https://en.wikipedia.org/api/rest_v1/page/random/summary

添加一个获取随机 Wikipedia 文章摘要的方法:

dart
class ArticleModel {
  Future<Summary> getRandomArticleSummary() async {
    final uri = Uri.https(
      'en.wikipedia.org',
      '/api/rest_v1/page/random/summary',
    );
    final response = await get(uri);

    // TODO: Add error handling and JSON parsing.
    throw UnimplementedError();
  }
}

使用 asyncawait 关键字处理异步操作。 async 关键字将方法标记为异步, await 会等待返回 Future 的表达式。

Uri.https 构造函数通过处理编码和格式安全地构建 URL。这种方式比字符串拼接更可靠,尤其在处理特殊字符或查询参数时。

4

处理网络错误

发起 HTTP 请求时务必处理错误。状态码 200 表示成功,其他状态码表示错误。若状态码不是 200,Model 会抛出错误供 UI 向用户显示。

dart
class ArticleModel {
  Future<Summary> getRandomArticleSummary() async {
    final uri = Uri.https(
      'en.wikipedia.org',
      '/api/rest_v1/page/random/summary',
    );
    final response = await get(uri);

    if (response.statusCode != 200) {
      throw const HttpException('Failed to update resource');
    }

    // TODO: Parse JSON and return Summary.
    throw UnimplementedError();
  }
}
5

解析来自 Wikipedia 的 JSON

Wikipedia API 返回 JSON 数据,你需要将其解码为 Summary 类。完成 getRandomArticleSummary 方法:

dart
class ArticleModel {
  Future<Summary> getRandomArticleSummary() async {
    final uri = Uri.https(
      'en.wikipedia.org',
      '/api/rest_v1/page/random/summary',
    );
    final response = await get(uri);

    if (response.statusCode != 200) {
      throw const HttpException('Failed to update resource');
    }

    return Summary.fromJson(jsonDecode(response.body) as Map<String, Object?>);
  }
}

Summary 类定义在 summary.dart 中。如果你不熟悉 JSON 解析,请查看 Getting started with Dart 教程。

6

回顾

你已完成的内容

以下是你本课构建与学习内容的摘要。
理解了 MVVM 架构模式

MVVM 将应用分为 Model(数据操作)、 View(用户界面)和 ViewModel(状态管理)。这种关注点分离使代码更易测试、复用和维护。

构建了获取 Wikipedia 数据的 HTTP 请求

你创建了 ArticleModel 类,其中包含使用 asyncawait 从 Wikipedia API 获取数据的方法。为安全构建请求 URL,你使用了 Uri.https 构造函数,它会为你处理编码和特殊字符。

处理了错误并解析了 JSON 响应

你检查了 HTTP 状态码以检测错误,并使用 jsonDecode 解析响应体。然后将原始 JSON 转换为类型化的 Dart 对象时,你使用了 Summary.fromJson 命名构造函数。

7

自测

HTTP 请求测验

1 / 2
Dart 中 asyncawait 关键字的作用是什么?
  1. 它们让代码在单独线程上运行。

    不正确。

    Dart 是单线程的;async/await 在不使用线程的情况下处理异步操作。

  2. 它们将函数标记为异步,并暂停执行直到 Future 完成。

    正确!

    async 关键字将函数标记为异步,await 会暂停执行直到 Future 完成。

  3. 它们自动缓存函数调用的结果。

    不正确。

    缓存需要单独实现;async/await 用于处理异步操作。

  4. 它们将同步代码转换为在后台运行。

    不正确。

    它们不会把代码移到后台;它们管理异步执行流程。

在 Dart 中构建 URL 时,为什么更推荐使用 Uri.https 而不是字符串拼接?
  1. 它让代码更短。

    不正确。

    代码长度不是主要好处;正确编码才是。

  2. 它安全处理编码和格式,尤其适用于特殊字符和查询参数。

    正确!

    Uri.https 正确编码特殊字符并格式化 URL,避免常见错误。

  3. http package 要求必须使用它。

    不正确。

    可以使用字符串,但 Uri.https 更安全可靠。

  4. 它会自动验证 URL 是否存在。

    不正确。

    Uri.https 构建 URL;不会检查端点是否存在。