Flutter中网络请求有两种,一个是使用Flutter自带的网络请求,另一种则是使用第三方HTTP请求插件dio
Flutter中自带的HTTP请求 如果要使用Flutter自带的HTTP请求,需要引入下面两个库
1 2 import 'dart:io' ;import 'dart:convert' ;
dart:io
用于发起http请求。这个库里面才有 HttpClient
。
1 var httpClient = new HttpClient();
因为网络请求需要时间,我们需要在网络请求成功后在来更新数据,所以,我们需要使用到异步。Flutter 官网建议我们使用 async/await
来进行处理异步(借鉴了前端中的ES7的异步处理)。
使用Flutter自带的HTTP请求一般包含以下几个步骤:
创建 client。 new HttpClient()
,这个对象下面有许多方法,get,post等等。见下图
构造 Uri。不同于前端(HTML)的网页请求,直接一个 URL 链接就可以了。在Flutter中,请求需要使用 Uri 而不是 Url。关于 URL 与 URI 的区别,可以HTTP 协议中 URI 和 URL 有什么区别? 。
发起请求,等待请求,同时您也可以配置请求的headers,body等等。
关闭请求。等待响应。
解码响应的内容。
看看下面的代码,代码来源于Flutter中文网
1 2 3 4 5 6 7 8 get () async { var httpClient = new HttpClient(); var uri = new Uri .http( 'example.com' , '/path1/path2' , {'param1' : '42' , 'param2' : 'foo' }); var request = await httpClient.getUrl(uri); var response = await request.close(); var responseBody = await response.transform(utf8.decoder).join(); }
因为在请求中,返回的数据一般都是 JSON 格式的数据,但是在Flutter中不能直接拿出来就用,这里需要转一下,这时候就需要用到 dart:convert
。
使用dart:convert库可以简单解码和编码JSON。 有关其他的JSON文档,请参阅JSON和序列化 。
看看最后的代码,下面两个都是get,使用了不同的方式,第二个还带了参数。如果要使用post或者其他请求,可以自己尝试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 import 'dart:io' ;import 'dart:convert' ;import 'package:flutter/material.dart' ;void main() => runApp(LocaleHttp());class LocaleHttp extends StatefulWidget { LocaleHttp({Key key}) : super (key: key); _LocaleHttpState createState() => _LocaleHttpState(); } class _LocaleHttpState extends State <LocaleHttp > { var data; Map _person = { "name" : "点击按钮开始请求" , "joinTime" : "点击按钮开始请求" , "email" : "点击按钮开始请求" }; _getData() async { var url = "http://rap2api.taobao.org/app/mock/162174/common/content" ; var httpClient = new HttpClient(); String result; try { var request = await httpClient.getUrl(Uri .parse(url)); var response = await request.close(); if ( response.statusCode == HttpStatus.ok ) { var json = await response.transform(utf8.decoder).join(); var data = jsonDecode(json); result = data['data' ][0 ]["description" ]; } } catch (err) { result = "Some Error" ; } setState(() { data = result; }); } _getPerson() async { var httpClient = new HttpClient(); var uri = new Uri .http('rap2api.taobao.org' , "app/mock/162174/common/get-test" , { "id" : "1" }); Map result = new Map (); setState(() { _person = { "name" : "请求中" , "joinTime" : "请求中" , "email" : "请求中" }; }); try { var request = await httpClient.getUrl(uri); var response = await request.close(); if ( response.statusCode == HttpStatus.ok ) { var json = await response.transform(utf8.decoder).join(); var data = jsonDecode(json)["res" ]; result = data; } } catch (err) { result = { "name" : "请求失败" , "joinTime" : "请求失败" , "email" : "请求失败" }; } setState(() { _person = result; }); } @override Widget build(BuildContext context) { return Container( child: Column( children: <Widget>[ RaisedButton( child: Text('获取数据' ), onPressed: _getData, ), Text(data == null ? "空" : data), RaisedButton( child: Text('获取人物信息' ), onPressed: _getPerson, ), Text(_person["name" ]), Text(_person["joinTime" ]), Text(_person["email" ]), ], ), ); } }
上面的代码中用到了 Map 对象,注意注意的是 Map 中的对象的每一个字段的值在最开始如果已经确定好了(比如都是字符串),在后面 setState 中,如果返回的数据中有其他的数据类型(比如 number ),那这个时候你在设置的时候就会报错 type int is not a subtype of type "String"
。或者你会遇到其他的错误,这个不会像在 JavaScript 中那样随意。
使用 dio 使用 dio 需要修安装 dio 插件,当前我使用的是最新的版本 2.1.11
1 2 3 4 5 6 7 dependencies: flutter: sdk: flutter flutter_webview_plugin: ^0.3.5 image_picker: 0.6 .0 +9 fluttertoast: ^3.1.0 dio: 2.1 .11
dio 具体的时候方法可以去 dio-github 上面查看,很简单,这里就不做过多说明。总之,相比于原生的 HTTP 请求,dio可谓是方便实用了需要,从下面的代码中就可以看出来。就绪在前端中,原生的 XMLHttpRequest
几乎看不见,实际开发用的基本都是 axios 一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import 'package:flutter/material.dart' ;import 'package:dio/dio.dart' ;void main() => runApp(DioHttp());class DioHttp extends StatefulWidget { DioHttp({Key key}) : super (key: key); _DioHttpState createState() => _DioHttpState(); } class _DioHttpState extends State <DioHttp > { var data; Map _person = { "name" : "点击按钮开始请求" , "sex" : -1 , "joinTime" : "点击按钮开始请求" , "email" : "点击按钮开始请求" }; _getData() async { var url = "http://rap2api.taobao.org/app/mock/162174/common/content" ; Dio dio = new Dio(); String result; try { Response response = await dio.get (url); print (response.data["data" ]); result = response.data["data" ][0 ]["description" ]; } catch (err) { result = "Some Error" ; } setState(() { data = result; }); } @override Widget build(BuildContext context) { return Container( child: Column( children: <Widget>[ RaisedButton( child: Text('获取数据' ), onPressed: _getData, ), Text(data == null ? "空" : data) ], ), ); } }
具体的App的源码地址