在 Flutter 中使用 http 包【Flutter 专题 2】

简介: 在 Flutter 中使用 http相信大家在使用应用的时候都发现了,大多数应用程序必须通过互联网执行网络请求。因此,优雅地处理网络调用以避免 API 调用中出现不必要的错误非常重要。

在 Flutter 中使用 http

相信大家在使用应用的时候都发现了,


大多数应用程序必须通过互联网执行网络请求。因此,优雅地处理网络调用以避免 API 调用中出现不必要的错误非常重要。


在本文中,我们将看看如何在 Flutter 中使用http包处理 REST API 请求。


这也是非常重要的一个环节,如果你想与后端交互,就不得不用到它,当然,还有另外一个 dio 包,我也会在后面给大家做介绍。

入门

使用以下命令创建一个新的 Flutter 项目:


flutter create flutter_http_networking

复制代码


您可以使用自己喜欢的 IDE 打开项目,但在本示例中,我将使用 VS Code:


code flutter_http_networking

复制代码


http 包添加到您的pubspec.yaml文件中:


在这里,我将 http 包的文档放到这儿,以供大家查阅https://pub.flutter-io.cn/packages/http 在 pub.dev 有 3600+喜欢,所以大家可以看到他的实力。


dependencies:  http: ^0.13.3

复制代码


用以下基本结构替换main.dart文件的内容:


import 'package:flutter/material.dart';
import 'screens/home_page.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Networking',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

复制代码


我们在执行网络操作的 API 之后,我们将创建 HomePage。

请求 API 数据

对于 API 请求的演示,我们将使用来自JSONPlaceholder的示例数据。这是一个用于测试和原型制作的免费假 API。


我们将首先使用 GET 请求获取单个帖子数据。您必须使用的端口是:/posts


GET https://jsonplaceholder.typicode.com/posts/<id>

复制代码


在这里,您必须将 替换为<id>代表您要检索的帖子 ID 的整数值。


如果您的请求成功,您将收到的示例 JSON 响应将如下所示:


{
  "userId" : 1 , 
  "id" : 1 , 
  "title" : "sunt aut facere repellat Provident occaecati excepturi optio reprehenderit" , 
  "body" : "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit moestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 
}

复制代码

指定模型类

模型类可帮助您打包 API 调用返回的数据或使用网络请求整齐地发送数据。


我们将定义一个模型类来处理单个帖子数据。您可以使用JSON-to-Dart 类转换工具来轻松生成模型类。将其复制并粘贴到名为 post.dart 的文件中:,这个网站简直不要太爽哦,,


https://app.quicktype.io/


class Post {
  Post({
    this.id,
    this.userId,
    this.title,
    this.body,
  });
  int? id;
  int? userId;
  String? title;
  String? body;
  factory Post.fromJson(Map<String, dynamic> json) => Post(
        userId: json["userId"],
        id: json["id"],
        title: json["title"],
        body: json["body"],
      );
  Map<String, dynamic> toJson() => {
        "userId": userId,
        "id": id,
        "title": title,
        "body": body,
      };
}

复制代码


或者,您也可以使用 JSON 序列化并自动生成fromJsontoJson方法,这有助于防止在手动定义时可能发生的任何未注意到的错误。


如果您使用 JSON 序列化,您将需要以下包:


  • json_serializable
  • json_annotation
  • build_runner


将它们添加到您的pubspec.yaml文件中:


dependencies:
  json_annotation: ^4.0.1
dev_dependencies:
  json_serializable: ^4.1.3
  build_runner: ^2.0.4



要使用 JSON 序列化,您必须按如下方式修改post类:


import 'package:json_annotation/json_annotation.dart';
part 'post.g.dart';
@JsonSerializable()
class Post {
  Post({
    this.id,
    this.userId,
    this.title,
    this.body,
  });
  int? id;
  int? userId;
  String? title;
  String? body;
  factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
  Map<String, dynamic> toJson() => _$PostToJson(this);
}



您可以使用以下命令触发代码生成工具:


flutter pub run build_runner build



如果你想让代码生成工具在后台运行——它会自动应用你对模型类所做的任何进一步修改——使用命令:


flutter pub run build_runner serve --delete-conflicting-outputs



如果发现任何冲突,--delete-conflicting-outputs标志有助于重新生成类的一部分。

执行 API 请求

现在您可以开始在 REST API 上执行各种网络请求。为了保持代码整洁,您可以在单独的类中定义与网络请求相关的方法。


创建一个名为post_client.dart 的新文件,并在其中定义类:PostClient


class PostClient {
  // TODO: Define the methods for network requests
}



在变量中定义服务器的基本 URL 以及所需的端口:


class PostClient {
  static final baseURL = "https://jsonplaceholder.typicode.com";
  static final postsEndpoint = baseURL + "/posts";
}



我们将在执行请求时使用这些变量。

获取数据

您可以使用 GET 请求从 API 检索信息。要获取单个帖子数据,您可以定义这样的方法:


Future<Post> fetchPost(int postId) async {
  final url = Uri.parse(postsEndpoint + "/$postId");
  final response = await http.get(url);
}



此方法尝试根据传递给它的 ID 检索帖子数据。该方法使用 URL 从服务器获取存储在变量中的数据。http.get()``response


通过检查 HTTP 状态代码来验证请求是否成功,如果成功应该是200。您现在可以使用 Post.fromJson()解码原始 JSON 数据,并使用模型类以良好的结构化方式存储它。``


Future<Post> fetchPost(int postId) async {
  final url = Uri.parse(postsEndpoint + "/$postId");
  final response = await http.get(url);
  if (response.statusCode == 200) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load post: $postId');
  }
}


发送数据

您可以使用 POST 请求向 API 发送数据。我们将通过使用以下方法发送数据来创建一个新帖子:


uture<Post> createPost(String title, String body) async {
  final url = Uri.parse(postsEndpoint);
  final response = await http.post(
    url,
    headers: {
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode({
      'title': title,
      'body': body,
    }),
  );
}



发送数据时,您必须指定标头类型headers以及body要发送到指定端口的标头类型。此外,JSON 数据应使用该jsonEncode方法以编码格式发送。


您可以使用 HTTP 状态代码检查您的 POST 请求是否成功。如果返回状态码为201,则请求成功,我们可以返回 post 数据。


Future<Post> createPost(String title, String body) async {
  // ...
  if (response.statusCode == 201) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to create post');
  }
}


更新数据

您可以使用 PUT 请求更新 API 服务器上存在的任何发布信息。像这样定义方法:


Future<Post> updatePost(int postId, String title, String body) async {
  final url = Uri.parse(postsEndpoint + "/$postId");
  final response = await http.put(
    url,
    headers: {
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode({
      'title': title,
      'body': body,
    }),
  );
}



在这里,我们使用了帖子 ID 来指定要更新和发送请求的帖子。如果响应状态码为200,则请求成功,您可以返回服务器发送的更新后的帖子。


Future<Post> updatePost(int postId, String title, String body) async {
  // ...
  if (response.statusCode == 200) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to update post');
  }
}


删除数据

您可以使用 DELETE 请求从 API 服务器中删除帖子。该方法可以定义如下:


Future<Post> deletePost(int postId) async {
  final url = Uri.parse(postsEndpoint + "/$postId");
  final response = await http.delete(
    url,
    headers: {
      'Content-Type': 'application/json; charset=UTF-8',
    },
  );
  if (response.statusCode == 200) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to delete post: $postId');
  }
}


我们使用帖子 ID 来指定要删除的帖子并将请求发送到相应的端口。您可以通过检查 HTTP 状态代码是否为 200来验证请求是否成功。


您应该注意,在删除的情况下,响应返回空数据。


Future<Post> deletePost(int postId) async {
  //...
  if (response.statusCode == 200) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to delete post: $postId');
  }
}


构建用户界面

用户界面将在HomePage小部件中定义。这将是一个StatefulWidget因为我们需要在每个网络请求之后更新它的状态。


import 'package:flutter/material.dart';
import 'package:flutter_http_networking/utils/post_client.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}



首先,我们将定义将存储的两个变量title,和body并通过 API 调用返回的帖子,然后我们会初始化PostClient类:


import 'package:flutter/material.dart';
import 'package:flutter_http_networking/utils/post_client.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
  final PostClient _postClient = PostClient();
  String? _postTitle;
  String? _postBody;
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}



我们现在将创建将触发网络请求方法并使用服务器返回的信息更新变量的按钮。下面是触发该方法的代码片段:fetchPost()


ElevatedButton(
  onPressed: () async {
    final post = await _postClient.fetchPost(1);
    setState(() {
      _postTitle = post.title;
      _postBody = post.body;
    });
  },
  child: Text('GET'),
)



您可以类似地触发其余的网络请求方法。


最终的应用程序 UI 如下所示:


image.png

测试网络请求

您可以使用Mockito测试 Dart 中的 API 请求,该包有助于模拟网络请求并测试您的应用程序是否有效处理各种类型的请求,包括空响应和错误响应。


要使用 Mockito 进行测试,请将其添加到您的文件中,并确保您有如下依赖


dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.0.4
  mockito: ^5.0.10

复制代码


现在,您必须对要测试的网络请求方法进行一些小的修改。我们将对方法进行修改。为fetchPost()


方法提供一个get(),并使用http.Client客户端来执行请求。修改后的方法将如下所示:


Future<Post> fetchPost(http.Client client, int postId) async {
  final url = Uri.parse(postsEndpoint + "/$postId");
  final response = await client.get(url);
  if (response.statusCode == 200) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load post: $postId');
  }
}



创建一个fetch_post_test.dart文件在test夹内调用的测试文件,并添加方法.@GenerateMocks([http.Client])


import 'package:flutter_http_networking/models/post.dart';
import 'package:flutter_http_networking/utils/post_client.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'fetch_post_test.mocks.dart';
@GenerateMocks([http.Client])
void main() {}



这将有助于MockClient使用该build_runner工具生成类。使用以下命令触发代码生成:


flutter pub run build_runner build



我们将只定义两个测试:一个针对成功的 API 请求,另一个针对有错误的不成功请求。您可以使用 Mockito 提供的函数测试这些条件。when()


@GenerateMocks([http.Client])
void main() {
  PostClient _postClient = PostClient();
  final postEndpoint =
      Uri.parse('https://jsonplaceholder.typicode.com/posts/1');
  group('fetchPost', () {
    test('successful request', () async {
      final client = MockClient();
      when(
        client.get(postEndpoint),
      ).thenAnswer((_) async => http.Response(
          '{"userId": 1, "id": 2, "title": "mock post", "body": "post body"}',
          200));
      expect(await _postClient.fetchPost(client, 1), isA<Post>());
    });
    test('unsuccessful request', () {
      final client = MockClient();
      when(
        client.get(postEndpoint),
      ).thenAnswer((_) async => http.Response('Not Found', 404));
      expect(_postClient.fetchPost(client, 1), throwsException);
    });
  });
}
   });  });}



您可以使用以下命令运行测试:


flutter test test/fetch_post_test.dart



或者,您也可以直接在 IDE 中运行测试。当我使用 VS Code 运行测试时,我收到了这个结果:


image.png

结论

http包有助于在 Flutter 中执行所有类型的网络请求。它还提供对 Mockito 的支持,从而简化了 API 调用的测试。


如果你想对你的请求进行更高级的控制,那么你可以使用 Dio 包,它有助于避免一些样板代码,并支持全局配置、拦截器、转换器和其他功能。

项目地址:https://github.com/ITmxs/flutter_http_networking

相关文章
|
4月前
防抓包破解(HTTP.Debugger)
防抓包破解(HTTP.Debugger)
313 3
|
4月前
|
资源调度
#发布npm包遇到错误,因为用了淘宝镜像地址的原因的解决方法-403 403 Forbidden - PUT https://registry.npmmirror.com/-/user/org.cou
#发布npm包遇到错误,因为用了淘宝镜像地址的原因的解决方法-403 403 Forbidden - PUT https://registry.npmmirror.com/-/user/org.cou
313 0
|
2天前
|
Web App开发 存储
常见抓包工具配置抓取HTTPS
常见抓包工具配置抓取HTTPS
|
8天前
|
机器学习/深度学习 Ubuntu Linux
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
|
18天前
|
XML 安全 Android开发
Flutter配置Android和IOS允许http访问
Flutter配置Android和IOS允许http访问
32 3
|
2月前
|
JSON Dart API
Flutter dio http 封装指南说明
本文介绍了如何实现一个通用、可重构的 Dio 基础类,包括单例访问、日志记录、常见操作封装以及请求、输出、报错拦截等功能。
Flutter dio http 封装指南说明
|
2月前
|
JSON 网络协议 安全
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(1)-HTTP和HTTPS基础知识
【7月更文挑战第16天】本文介绍了HTTP和HTTPS协议的基本概念与作用,强调了理解HTTP协议对使用抓包工具Fiddler的重要性。HTTP是用于Web浏览器与服务器间信息传输的协议,不加密,易被截取,不适合传输敏感信息。HTTPS是HTTP的安全版,通过SSL/TLS提供加密和服务器身份验证,确保数据安全。HTTP请求包括请求行、请求头、空行和可选的请求主体,响应则有响应行、响应头、空行和响应主体。HTTP协议无状态,而HTTPS解决了安全性问题,但也带来了额外的计算开销。Fiddler作为一个强大的抓包工具,可以帮助开发者和测试人员分析HTTP/HTTPS通信,理解请求和响应的结构。
41 4
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(1)-HTTP和HTTPS基础知识
|
2月前
|
Web App开发 XML 缓存
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(4)-会话面板和HTTP会话数据操作详解
【7月更文挑战第19天】Fiddler会话面板概览:Fiddler的会话列表显示HTTP请求的详细信息,包括ID、状态码、协议、主机名、URL、内容类型、大小、进程及自定义备注。颜色和图标标识状态,如红色表示错误,黄色为认证,蓝色是HTML响应。用户可右键列进行搜索、标记重复、隐藏或自定义列,如添加请求方法。通过界面或脚本可添加自定义列,如显示ServerIP。会话还可复制和保存,解决乱码问题需解码响应体。
52 0
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(4)-会话面板和HTTP会话数据操作详解
|
3月前
|
Web App开发 存储 网络安全
Charles抓包神器的使用,完美解决抓取HTTPS请求unknown问题
本文介绍了在 Mac 上使用的 HTTP 和 HTTPS 抓包工具 Charles 的配置方法。首先,强调了安装证书对于抓取 HTTPS 请求的重要性,涉及 PC 和手机端。在 PC 端,需通过 Charles 软件安装证书,然后在钥匙串访问中设置为始终信任。对于 iOS 设备,需设置 HTTP 代理,通过电脑上的 IP 和端口访问特定网址下载并安装证书,同时在设置中信任该证书。配置 Charles 包括设置代理端口和启用 SSL 代理。完成这些步骤后,即可开始抓包。文章还提及 Android 7.0 以上版本可能存在不信任用户添加 CA 证书的问题,但未提供解决办法。
550 0
Charles抓包神器的使用,完美解决抓取HTTPS请求unknown问题
|
2月前
|
人工智能
AI绘画,Stable Diffusion如何使用中文简体包,黑色页面切换参数http://127.0.0.1:7860/?__theme=dark 两个__,中文包下载和安装
AI绘画,Stable Diffusion如何使用中文简体包,黑色页面切换参数http://127.0.0.1:7860/?__theme=dark 两个__,中文包下载和安装

热门文章

最新文章

下一篇
云函数