Flutter中网络请求有两种,一个是使用Flutter自带的网络请求,另一种则是使用第三方HTTP请求插件dio
如果要使用Flutter自带的HTTP请求,需要引入下面两个库
import 'dart:io';
import 'dart:convert';
dart:io
用于发起http请求。这个库里面才有 HttpClient
。
var httpClient = new HttpClient();
因为网络请求需要时间,我们需要在网络请求成功后在来更新数据,所以,我们需要使用到异步。Flutter 官网建议我们使用 async/await
来进行处理异步(借鉴了前端中的ES7的异步处理)。
使用Flutter自带的HTTP请求一般包含以下几个步骤:
new HttpClient()
,这个对象下面有许多方法,get,post等等。见下图
看看下面的代码,代码来源于Flutter中文网
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或者其他请求,可以自己尝试
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 ) {
// 如果返回的状态是 200 那么请求成功
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 ) {
// 如果返回的状态是 200 那么请求成功
// 将返回的数据转一次格式,下面一行代码写法可以固定了
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 插件,当前我使用的是最新的版本 2.1.11
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 一样。
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"]);
// 不要使用 response.data.data[0].description 这样的形势,获取不到
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的源码地址