Flutter的网络请求

一起从0开始学习Flutter!

网络请求在一个APP的分量还是很重的,我们需要熟练的掌握Http请求部分,在Flutter中我们有三种方式,一种是使用Dart给我们提供的HttpClient,第二种是使用第三方的Http请求库,第三种是使用Flutter给我们准备好的Dio。我们主要是看后面两种,第一种比较繁琐一般也不会使用,如果想要了解的可以自行搜索。

HTTP库

这是一个基础的网络请求库,我们在使用之前需要先引入这个类库,在pubspec.yaml中添加:

dependencies:
  http: ^0.12.1

添加完成后在右上角会出现一个pub get的按钮,点击后可以帮助我们下载这个类库,然后在我们需要的地方加载该类:

import 'package:http/http.dart';

这样我们的准备工作就算是完成了,接下来我们开始试一下如果使用Http库进行网络请求了:

void doHttpRequest() async{//里面包含异步请求的时候需要加上asyn关键字
    var url = "http://www.baidu.com";
    var postResponse = await http.post(url,//使用Post请求,在需要等待的时候加上await关键字
        headers: {"": "", "": ""},//添加请求头
        body: {"": "", "": "",});//添加请求的参数

    var response = await http.get(url);//使用get方法,直接请求该地址
    if(response.statusCode == 200){//如果返回的状态码是200则有正确的返回结果
      print("response body = ${response.body}");
    }else{//其他的异常状态码
      print("请求异常${response.statusCode}");
    }
  }

这是比较简单进行一次网络请求,我们也可以根据自己的需要进行一定的封装,这里不多介绍,我们主要是使用Flutter给我们准备好的Dio来进行网络请求。

DIO

套用一下dio中的介绍:
dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等
可以做的事情还是挺多的,我们一点点的进行学习吧。
首先我们需要将它引入到我们项目中:

dependencies:
  dio: ^3.0.9  //目前的最新版本是3.0.9

发送一个get请求,我们可以使用两种形式:

var host = "https://wanandroid.com/wxarticle";
    var getResponse = await Dio().get("$host/list/408/1/json?id=404&page=1");//传统的我们使用的直接请求的方式
    var getResponse1 = await Dio().get("$host/list/408/1/json",
    		queryParameters: {"id":"404","page":"1"});//给我们扩展出来了新的写法,这样可以更好的查看参数

我们看下返回信息Response里都给我们带来了什么:

Response({
    this.data,//返回回来的数据
    this.headers,//响应头信息
    this.request,//请求时带的信息也返回回来了
    this.isRedirect,//是否是重定向,这个字段的是否可用取决于适配器是否支持(不是很理解这个字段)
    this.statusCode,//返回的响应码,成功请求返回200
    this.statusMessage,//返回的响应码的状态描述,如果是失败的时候有个简短的状态信息
    this.redirects,//会将每次重定向的地址以及请求状态放到这里,我们可以跟踪每次的重定向请求
    this.extra,//自定义字段,我们可以在发送请求的时候将想要在返回处理的时候需要处理的信息进行存放,在请求响应完成时可以拿到附加信息
  })

上面就是在完成一次请求后我们可以获取到的响应内容,我们看下通过post方式会是怎样的请求形式:

var postResponse = await Dio().post(host,data: {"name":"403"});

很简单,只是上面的get关键字换成了post,然后传入我们想要的参数就可以了。我们不仅可以通过get和post这两个函数进行请求,我们也可以使用Dio给我们准备的request方法,我们可以根据自己想要的灵活配置:

Future<Response<T>> request<T>(
    String path, {//请求的地址
    data,//post需要传入的参数
    Map<String, dynamic> queryParameters,//get方法的时候可以添加的参数
    CancelToken cancelToken,//可以添加网络取消,网络取消的监听都在这里了
    Options options,//网络的配置,参照下面的详解
    ProgressCallback onSendProgress,//发送网络请求的进度监听回调
    ProgressCallback onReceiveProgress,//接收数据返回的进度监听回调
  });
options

网络请求的配置,我们可以通过它来设置请求头和连接超时的设置,看下我们怎么配置一个网络请求的:

RequestOptions({
    String method,//网络请求的方法
    int sendTimeout,//发送的超时时间
    int receiveTimeout,//接受超时时间
    this.connectTimeout,//链接超时的时间
    this.data,//post请求数据时传递的参数
    this.path,//如果是我们用了http或者https开头则会忽略baseUrl的设置,如果没有,则拼接到baseUrl后面
    this.queryParameters,//使用get方法时候的参数拼接
    this.baseUrl,//请求的根网址
    this.onReceiveProgress,//在收到消息时的进度
    this.onSendProgress,//在发送消息时的进度
    this.cancelToken,//可以添加网络取消,网络取消的监听都在这里了
    Map<String, dynamic> extra,//额外的参数配置,可以在返回的数据中获取到
    Map<String, dynamic> headers,//请求头
    ResponseType responseType,//响应类型,可以是json,可以是数据流,可以是json
    String contentType,//设置内容的类型
    ValidateStatus validateStatus,//给设定一个响应码,如果是返回了True则表示请求成功
    bool receiveDataWhenStatusError = true,//是否在Http的响应码是失败的时候接收响应数据
    bool followRedirects = true,//是否可以重定向
    int maxRedirects,//最多可以重定向的次数
    RequestEncoder requestEncoder,//我们可以设置在发送请求时对请求进行编码,默认是utf-8的编码,可以根据需求进行修改
    ResponseDecoder responseDecoder,//当我们接收返回消息时对内容进行解码,默认是utf-8,可以根据需求进行修改
  })

这是在我们使用dio的request方法的时候传入的option,在get和post方法的时候我们也看到有一个option,这两个传入的option还有一些小区别,我们看下在get和post的时候我们传入的option:

BaseOptions({
    String method,//网络请求的方法
    this.connectTimeout,//链接超时的时间
    int receiveTimeout,//接受超时时间
    int sendTimeout,//发送的超时时间
    this.baseUrl,//设置一个根地址
    this.queryParameters,//在get方法的时候作为拼接的参数
    Map<String, dynamic> extra,//在请求时的携带的额外信息
    Map<String, dynamic> headers,//请求头
    ResponseType responseType = ResponseType.json,//响应类型,可以是json,可以是数据流
    String contentType,//设置内容的类型
    ValidateStatus validateStatus,//给设定一个响应码,如果是返回了True则表示请求成功
    bool receiveDataWhenStatusError = true,//是否在Http的响应码是失败的时候接收响应数据
    bool followRedirects = true,//是否可以重定向
    int maxRedirects = 5,//最多可以重定向的次数
    RequestEncoder requestEncoder,//我们可以设置在发送请求时对请求进行编码,默认是utf-8的编码,可以根据需求进行修改
    ResponseDecoder responseDecoder,//当我们接收返回消息时对内容进行解码,默认是utf-8,可以根据需求进行修改
  })

再看下我们如何来做消息的拦截:

dio.interceptors.add(InterceptorsWrapper(
        onRequest:(options){//发送请求时的过滤
        	if(options.extra["data"] == 1)
	            options.cancelToken.cancel("");//我们可以根据自己的设定过滤来取消请求
        },
        onResponse:(response){//在接收到数据响应的时候过滤
        },
        onError:(error){//在接收到错误信息的时候的拦截
        }
    ));

在网络请求过程中我们有时候还遇到过链式请求,需要在一次请求完成后进行下一次请求,我们看下如何实现这样的一个链式请求:

await Future.wait([dio.get(""),dio.post("")],);//我们可以直接写入多个网络请求,Future可以在一次请求完成后进行下一次的请求

使用Dio我们可以进行文件的上传下载,使用也是比较简单:

//对文件进行下载
 dio.download("下载地址", "保存在本地的地址",onReceiveProgress: (count,total){
        print("已经完成的下载量${count},需要下载的文件大小${total}");
    });
//对文件进行上传
 var file = MultipartFile.fromFile("本地文件路径",filename: "文件名");//先获取到File的对象
 var formData = FormData.fromMap({
      "file1":file,//将File对象传入到待上传的map中
    });
 dio.post(host,data:formData);//开始文件的上传

Dio的基本使用就差不多了,我们可以对它进行封装,这样每次在进行请求不用每个请求单独去做设置了,网上有很多大神给我们提供的封装案例,在这里不多描述,以后可以做一个通用的封装给大家。