Flutter lesson 9: Flutter的网络(HTTP)请求

Flutter中网络请求有两种,一个是使用Flutter自带的网络请求,另一种则是使用第三方HTTP请求插件dio

Flutter中自带的HTTP请求

如果要使用Flutter自带的HTTP请求,需要引入下面两个库

import 'dart:io';
import 'dart:convert';

dart:io 用于发起http请求。这个库里面才有 HttpClient

var httpClient = new HttpClient();

因为网络请求需要时间,我们需要在网络请求成功后在来更新数据,所以,我们需要使用到异步。Flutter 官网建议我们使用 async/await 来进行处理异步(借鉴了前端中的ES7的异步处理)。

使用Flutter自带的HTTP请求一般包含以下几个步骤:

  1. 创建 client。 new HttpClient(),这个对象下面有许多方法,get,post等等。见下图
  1. 构造 Uri。不同于前端(HTML)的网页请求,直接一个 URL 链接就可以了。在Flutter中,请求需要使用 Uri 而不是 Url。关于 URL 与 URI 的区别,可以HTTP 协议中 URI 和 URL 有什么区别?
  2. 发起请求,等待请求,同时您也可以配置请求的headers,body等等。
  3. 关闭请求。等待响应。
  4. 解码响应的内容。

看看下面的代码,代码来源于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 需要修安装 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的源码地址

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券