Flutter学习-网络请求

Posted GY-93

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter学习-网络请求相关的知识,希望对你有一定的参考价值。

前言:项目中展示的大部分数据都是来自服务器,我们需要向服务器请求数据,并且对他们进行解析展示。
向服务器发出请求就需要用到网络请求相关的知识。

1. 网络请求的方式

在Flutter中常见的网络请求方式有三种:HttpClient、http库、dio库;

1.1 HttpClient的示例

HttpClient是dart自带的请求类,在io包中,实现了基本的网络请求相关的操作。

网络调用通常遵循如下步骤:

  1. 创建 client.
  2. 构造 Uri.
  3. 发起请求, 等待请求,同时您也可以配置请求headers、 body。
  4. 关闭请求, 等待响应.
  5. 解码响应的内容.

网络请求案例:

void requestNetwotk() async {
    //1. 创建HttpClient的请求实例
    final httpClient = HttpClient();

    //2.构建请求的URI
    // https://httpbin.org/get
    // http://123.207.32.32:8000/api/v1/recommend
    // https://httpbin.org/post
    final uri = Uri.parse("https://httpbin.org/get");

    //3.构建请求 返回值类型是 Future<HttpClientRequest> 是一个未来的对象,使用await之后可以使用HttpClientRequest类型来接收
    HttpClientRequest request = await httpClient.getUrl(uri);//get请求
    //final request = await httpClient.postUrl(uri);//post请求

    //4.发送请求 
    HttpClientResponse response = await request.close();

    //判断请求结果
    if (response.statusCode == HttpStatus.ok) {
      //打印成功结果
      print(await response.transform(utf8.decoder).join());
    } else {
      print(response.statusCode);
    }
  }
  //关闭HttpClient
    httpClient.close();
  • 代码分析:
    • 新建HttpClient对象,通过 getUrl方法获取 HttpClientRequest
    • 通过HttpClientRequest.close(),发起Http请求, 获取 HttpClientResponse
    • 判断请求结果根据code码,response.statusCode来判断
    • HttpClientResponse是一个Stream对象,通过Utf8Decoder解码,然后join操作符转换成String对象,可以打印出HttpClientResponse 的字符串。
    • 关闭HttpClient

HttpClient虽然可以发送正常的网络请求,但是会暴露过多的细节:

  • 比如需要主动关闭request请求,拿到数据后也需要手动的进行字符串解码
  • 在开发中,我们一般很多直接面向HttpClient进行网络请求并不是直接使用HttpClient,而是使用一些库来完成

注意:HttpClient其中还有很多知识,如果大家需要深入了解HttpClient,建议大家多看文档,多找资料学习

1.2 Http库

httpDart 官方提供的另一个网络请求类,相比于 HttpClient,易用性提升了不少。

但是,没有默认集成到Dart的SDK中,所以我们需要先在pubspec中依赖它:

大家如果需要找第三方库:https://pub.dev,直接在这个网站搜索:

  • dev_dependencies: 表示是开发阶段导入,打包app是不会把这下面的依赖打包进去的

  • 导入并使用

void requestNeteorkThridHttp() async {
    // 1.创建Client
    final client = http.Client();

    // 2.构建uri
    final url = Uri.parse("http://123.207.32.32:8000/api/v1/recommend");

    // 3.发送请求
    final response = await client.get(url);

    // 4.获取结果
    if (response.statusCode == HttpStatus.ok) {
      print(response.body);
    } else {
      print(response.statusCode);
    }
  }

1.3 dio三方库

官方提供的HttpClient和http都可以正常的发送网络请求,但是对于现代的应用程序开发来说,我们通常要求的东西会更多:比如拦截器、取消请求、文件上传/下载、超时设置等等;
这个时候,我们可以使用一个在Flutter中非常流行的三方库:dio;
官网有对dio进行解释:

dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等…

使用dio三方库必然也需要先在pubspec中依赖它:

dio代码简单演练:

import 'package:dio/dio.dart';

void dioNetwork() async {
  // 1.创建Dio请求对象
  final dio = Dio();

  // 2.发送网络请求
  final response = await dio.get("http://123.207.32.32:8000/api/v1/recommend");

  // 3.打印请求结果
  if (response.statusCode == HttpStatus.ok) {
    print(response.data);
  } else {
    print("请求失败:${response.statusCode}");
  }
}

1.4 dio库的简单封装

建议大家在使用三方库的时候,必须要自己封装一层,防止后期三方库弃用和更换别的三方库,导致程序改动困难

更对并且具体的使用方法参考github上的源码和文档:https://github.com/flutterchina/dio

import 'package:dio/dio.dart';


class HttpConfig {
  static const String baseUrl = "https://httpbin.org";
  static const int timeOut = 5000;
}

class HttpRequest {
  static final BaseOptions _baseOptions = BaseOptions(baseUrl: HttpConfig.baseUrl,connectTimeout: HttpConfig.timeOut);
  //防止每次请求都创建一个新的Dio对象
  static final Dio _dio = Dio(_baseOptions);

  /**
   * 参数后面的  ? 作用: 表示该参数可以为null, 如果不加? 则必须附一个默认值, 获取标记为必传参数
   */
  static Future<T> request<T>(String url, {
    String method = "get",
    Map<String, dynamic>? params,
    Interceptor? inter}) async {
    //1.创建单独配置
    final options = Options(method: method);

    //创建一个全局的拦截器
    Interceptor interceptor = InterceptorsWrapper(
        onRequest: (options, handle) {
          print("请求拦截");
		// 1.在进行任何网络请求的时候, 可以添加一个loading显示

        // 2.很多页面的访问必须要求携带Token,那么就可以在这里判断是有Token

        // 3.对参数进行一些处理,比如序列化处理等
			
          return;
        },
        onResponse: (response, handle) {
          print("响应拦截");

          return;
        },
        onError: (err, handle) {
          print("错误拦截");

          return;
        }
    );
    List<Interceptor> inters = [interceptor];

    // 请求单独拦截器
    if (inter != null) {
      inters.add(inter);
    }

    // 统一添加到拦截器中
    _dio.interceptors.addAll(inters);

    //2.发送网络请求
    try {
      Response response = await _dio.request(url,queryParameters: params,options: options);
      return response.data;
    } on DioError catch(e) {
        return Future.error(e);
    }
  }
}

使用:

 HttpRequest.request("/get",method: "get",params: {"name":"gwy"}).then((value) {
                  print("请求数据回来=========$value");
                });

2. JSON的读取和解析

在开发中,我们经常会使用本地JSON或者从服务器请求数据后回去到JSON,拿到JSON后通常会将JSON转成Model对象来进行后续的操作,因为这样操作更加的方便,也更加的安全。
所以学习JSON的相关操作以及读取JSON后如何转成Model对象对于Flutter开发也非常重要。

2.1 本地JSON资源配置

JSON也属于一种资源,所以在使用之前需要先进行相关的配置,配置本地JSON文件和之前我们配置本地图片一样

2.2 JSON数据的读取解析

JSON资源读取

如果我们希望读取JSON资源,可以使用package:flutter/services.dart包中的rootBundle

rootBundle中有一个loadString方法,可以去加载JSON资源

  • 但是注意,查看该方法的源码,你会发现这个操作是一个异步的
Future<String> loadString(String key, { bool cache = true }) async {
  ...省略具体代码,可以自行查看源码
}

代码如下:

import 'package:flutter/services.dart' show rootBundle;

// 打印读取的结果是一个字符串
rootBundle.loadString("assets/yz.json").then((value) => print(value));

JSON字符串转化

拿到JSON字符串后,我们需要将其转成成我们熟悉的List和Map类型。
我们可以通过dart:convert包中的json.decode方法将其进行转化

代码如下:

// 1.读取json文件
String jsonString = await rootBundle.loadString("assets/yz.json");

// 2.转成List或Map类型
final jsonResult = json.decode(jsonString);

对象Model定义
将JSON转成了List和Map类型后,就可以将List中的一个个Map转成Model对象,所以我们需要定义自己的Model

class Anchor {
  String nickname;
  String roomName;
  String imageUrl;

  Anchor({
    this.nickname,
    this.roomName,
    this.imageUrl
  });

  Anchor.withMap(Map<String, dynamic> parsedMap) {
    this.nickname = parsedMap["nickname"];
    this.roomName = parsedMap["roomName"];
    this.imageUrl = parsedMap["roomSrc"];
  }
}

2.3 JSON解析代码

完整解析逻辑代码:

import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'dart:async';

class Anchor {
  String nickname;
  String roomName;
  String imageUrl;

  Anchor({
    this.nickname,
    this.roomName,
    this.imageUrl
  });

  Anchor.withMap(Map<String, dynamic> parsedMap) {
    this.nickname = parsedMap["nickname"];
    this.roomName = parsedMap["roomName"];
    this.imageUrl = parsedMap["roomSrc"];
  }
}

Future<List<Anchor>> getAnchors() async {
  // 1.读取json文件
  String jsonString = await rootBundle.loadString("assets/yz.json");

  // 2.转成List或Map类型
  final jsonResult = json.decode(jsonString);

  // 3.遍历List,并且转成Anchor对象放到另一个List中
  List<Anchor> anchors = new List();
  for (Map<String, dynamic> map in jsonResult) {
    anchors.add(Anchor.withMap(map));
  }
  return anchors;
} 

以上是关于Flutter学习-网络请求的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

Flutter学习日记之Http&Dio网络请求的使用与封装

Flutter 领券联盟网络请求

Flutter学习-Dart异步