Flutter基础:通过HTTP请求了解async和await

任何语言都不会少网络编程这块,而谈及网络编程就肯定避免不了异步操作。所以在梳理async和await的知识的时候,就从简单的Http请求来了解这两个关键字的作用。

引入网络请求库

Dart里面,自带HttpClient网络框架,作为Android开发者说实话刚听到这个框架估计要吃惊一下,因为连Android官方都抛弃它了,但其实彼HttpClient非此HttpClient,请你放下屠刀。。。哦不放下成见,先了解一下它哇哈哈哈哈。

HttpClient位于dart.io包中,dart.io包含了文件操作、Socket、HTTP和I/O操作一系列的工具。

另外,目前还有目前比较流行的dio网络请求框架,它支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传、文件下载等,但这篇文章只是介绍基本的网络请求使用,后续系列文章的实战环节会使用这个dio框架。

引入非常简单,因为是内置的库,所以只需要在文件头导入就可以了:

1
import 'dart:io';

HttpClient的使用

HttpClient使用有以下几个步骤:

  1. 创建HttpClient对象
  2. 创建Uri对象
  3. 发起请求,等待请求
  4. 关闭请求,等待响应
  5. 解码响应的内容

步骤理清楚后,我们来找一个目标发起请求。
通过网络上搜索到的知乎日报api,可以看到返回数据是json,非常适合我们用来练手分析,所以目标就是它了:
http://news-at.zhihu.com/api/3/stories/latest

下面我们来一步步进行这个请求:

创建HttpClient对象

1
var httpClient = new HttpClient();

创建Uri对象:

通过查阅dart官方api文档的Uri部分,可以看到Uri对象中通过http命名构造方法创建出来的就是http请求的对象:

Uri.http(
String authority,
String unencodedPath, [
Map<String, String> queryParameters
])

其中示例如下:

1
2
3
4
5
6
7
8
9
10
11
// http://example.org/path?q=dart.
new Uri.http("example.org", "/path", { "q" : "dart" });

// http://user:pass@localhost:8080
new Uri.http("user:pass@localhost:8080", "");

// http://example.org/a%20b
new Uri.http("example.org", "a b");

// http://example.org/a%252F
new Uri.http("example.org", "/a%2F");

其中第三个参数是可选位置参数,所以我们这里可以这么来创建对象:

1
var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');

当然,路径是固定的,有时候开发中基本固定地址路径情况下直接当成一个地址处理,所以也可以这么创建:

1
var uri = new Uri.http('news-at.zhihu.com/api/3/stories/latest','');

发起请求,等待请求

发起请求的时候需要使用await关键字修饰,代表着说要开始做异步操作了,你先等着,放学别走,我去找把刀回来跟你决一死战。。。

1
var request = await httpClient.getUrl(uri);

关闭请求,等待响应

关闭请求的时候,就会返回一个网络响应,这个同样是异步操作,需要await:

1
var response = await request.close();

解码响应的内容

在解码响应内容的时候我们需要rawString形式的返回,所以我们仅仅解码成utf8格式,使用utf8.decode需要导入dart:convert库,这个也是dart内置的库:

1
2
3
4
import 'dart:convert';

//...
var responseData = await response.transform(utf8.decoder).join();

我们将上面的内容封装为一个getDataFromZhihuAPI()方法:

1
2
3
4
5
6
7
getDataFromZhihuAPI() async{
var httpClient = new HttpClient();
var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');
var request = await httpClient.getUrl(uri);
var response = await request.close();
return await response.transform(utf8.decoder).join();
}

我们直接在main()中来调用这个方法测试网络请求的结果是否正确,完整代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import 'dart:io';
import 'dart:convert';


void main() async{
var result = await _getDataFromZhihuAPI();
print(result);
}

_getDataFromZhihuAPI() async{
var httpClient = new HttpClient();
var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');
var request = await httpClient.getUrl(uri);
var response = await request.close();
return await response.transform(utf8.decoder).join();
}

运行后可以得到输出结果如下:

1
{"date":"20181025","stories":[{"images":["https:\/\/pic3.zhimg.com\/v2-82432f8609785f33543d850b46eae7c6.jpg"],"type":0,"id":9699380,"ga_prefix":"102513","title":"为了建高楼大厦,我们拆掉了最适合居住的房子"},{"images":["https:\/\/pic1.zhimg.com\/v2-5523c501a0586d423a6d2bbc60461918.jpg"],"type":0,"id":9699429,"ga_prefix":"102512","title":"大误 · 我为这美丽的名字而沉醉"},{"images":["https:\/\/pic4.zhimg.com\/v2-f44c871afc60a4bff60a0fbdc93dd2bf.jpg"],"type":0,"id":9699543,"ga_prefix":"102510","title":"生命啊,就像打麻将"},{"images":["https:\/\/pic4.zhimg.com\/v2-1f89cbbc34e0ad97e23c191aafc42e57.jpg"],"type":0,"id":9699244,"ga_prefix":"102509","title":"让支付宝用户有难同当的「相互保」,真的靠谱吗?"},{"images":["https:\/\/pic1.zhimg.com\/v2-d06aba189e0414b754c79e880c9bbf30.jpg"],"type":0,"id":9699336,"ga_prefix":"102508","title":"如果要进行星际殖民,哪个恒星可以成为下一个太阳?"},{"images":["https:\/\/pic2.zhimg.com\/v2-2d84eed448e8cfebc26d8a2d8aa95a6d.jpg"],"type":0,"id":9699440,"ga_prefix":"102507","title":"用洗面奶洗完脸,皮肤摸起来滑腻得……像没洗净一样"},{"images":["https:\/\/pic1.zhimg.com\/v2-c7a57ad07f5da1a2b2ef45e55c94f8e4.jpg"],"type":0,"id":9699370,"ga_prefix":"102506","title":"瞎扯 · 如何正确地吐槽"}],"top_stories":[{"image":"https:\/\/pic1.zhimg.com\/v2-8720bb5a80d91125064a7ee219b57c68.jpg","type":0,"id":9699543,"ga_prefix":"102510","title":"生命啊,就像打麻将"},{"image":"https:\/\/pic3.zhimg.com\/v2-d5fffdb201c94a968bcea286e857bda6.jpg","type":0,"id":9699244,"ga_prefix":"102509","title":"让支付宝用户有难同当的「相互保」,真的靠谱吗?"},{"image":"https:\/\/pic1.zhimg.com\/v2-99bddca5d08cd5924ff07fbae8163a1c.jpg","type":0,"id":9699419,"ga_prefix":"102420","title":"马化腾提问:未来十年哪些基础科学突破会影响互联网科技产业?"},{"image":"https:\/\/pic1.zhimg.com\/v2-0ae5c9165f2edd4ddecbb345812fcb5c.jpg","type":0,"id":9699306,"ga_prefix":"102415","title":"云南白药含有处方药成分,「中药牙膏」止血并不靠中药"},{"image":"https:\/\/pic2.zhimg.com\/v2-866c46ed24b0566da3f06ac9aa3384ad.jpg","type":0,"id":9699382,"ga_prefix":"102407","title":"iPhone XR 上手体验:跑马的边框,耐用的电池……真香?"}]}

这就是一个简单的网络请求过程,下面我们就这个过程来分析await和async。

async和await

这两个关键字的使用只需要记住两点:

  1. 只有async方法才能使用await关键字调用方法
  2. 如果调用别的async方法必须使用await关键字

比如上面的例子,我们的_getDataFromZhihuAPI()方法中使用了多次await关键字,所以_getDataFromZhihuAPI()方法增加了async关键字修饰,同样,我们在main()中使用了await,所以main()方法使用async来修饰。

文章作者: Kevin Wu
文章链接: https://kevinwu.cn/p/a962ce59/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KevinWu.CN
支付宝打赏