Flutter HttpClient 的使用

首先发送请求一共分为几步?

HttpClient http = HttpClient(); 创建一个HttpClient

HttpClientRequest request = await httpClient.postUrl(url);  发送一个post请求

在这里注意,有些请求需要添加请求头才能够使用该api

request.add(utf8.encode(jsonEncode(        传一个json数据给api用来登录
    {
      "username":_email.text,
      "password":_password.text
    },
))); 

设置我们接收的参数类型,参数类型有很多种, 比如x-www-form-urlencoded, 还有form-data等等...就不一一赘述了

request.headers.set("Content-Type", "application/json");

HttpClientResponse response = await request.close(); 获取请求返回的结果

然后判断请求是否成功

if(response.statusCode == HttpStatus.ok){
String responseBody = await response.transform(utf8.decoder).join();将字节流转为utf8 编码的字符串类型
final json = jsonDecode(responseBody);再将数据序列化为json数据
Data.token = json['token'];最后使用一个静态变量接收他,后续有些api需要登录后产生的token才能获取数据

这个案例的完整代码

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

import 'package:flutter/material.dart';
import 'package:httpclient_basic/data.dart';

import 'home_screens.dart';
import 'index_bottom.dart';

class LoginScreen extends StatefulWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> with SingleTickerProviderStateMixin{
  late TabController _tabController;
  @override
  void initState() {
    _tabController = TabController(length: 2,vsync: this);
    super.initState();
  }
  bool loginType = true;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: Stack(
          alignment: Alignment.center,
          children: [
            Container(
              height: double.infinity,
              width: double.infinity,
              decoration: BoxDecoration(
                image: DecorationImage(
                  image:AssetImage("assets/user/ic_travel_car.jpg"),fit: BoxFit.cover
                )
              ),
            ),
            Container(
              height: double.infinity,
              width: double.infinity,
              color: Colors.black.withOpacity(0.4),
            ),
            Container(
              height: 370,
              width: 350,
              child: Stack(
                children: [
                  Positioned(
                    top: 20,
                      child: Container(
                    height: 380,
                    width: 350,
                    color: Colors.white,
                    child: Column(
                      children: [
                        Container(
                          height: 50,
                          width: 350,
                          decoration: BoxDecoration(
                            border: Border.all(color: Colors.blue,width: 2)
                          ),
                          child: TabBar(
                            onTap: (index){
                              loginType = !loginType;
                              setState(() {
                              });
                            },
                             controller: _tabController,
                            labelColor: Colors.white,
                            unselectedLabelColor: Colors.blue,
                            indicator: BoxDecoration(
                              color: Colors.blue
                            ),
                            tabs: [
                              Tab(
                                child: Text("Sign in"),
                              ),
                              Tab(
                                child: Text("Sign up"),
                              ),
                            ],
                          ),
                        ),
                        Container(
                          height: 330,
                          child: TabBarView(
                            controller: _tabController,
                            children: [
                              LoginWidget(title: "Sign in", subTitle: "Forgot your password?"),
                              LoginWidget(title: "Sign in", subTitle: ""),
                            ],
                          ),
                        )
                      ],
                    ),
                  )
                  ),
                  Positioned(
                    left: 140,
                      child: Container(
                        height: 70,
                        width: 70,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(50),
                          border: Border.all(color: Colors.blue,width: 2),
                          image: DecorationImage(
                            image: AssetImage(loginType ? "assets/user/sigin_boy_img.jpg" : "assets/user/sigup_boy_img.jpg")
                          )
                        )
                      )
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

class LoginWidget extends StatefulWidget {
  const LoginWidget({Key? key,required this.title,required this.subTitle}) : super(key: key);
  final String title;
  final String subTitle;

  @override
  State<LoginWidget> createState() => _LoginWidgetState();
}

class _LoginWidgetState extends State<LoginWidget> {
  final _formKey = GlobalKey<FormState>();
  late TextEditingController _email;
  late TextEditingController _password;
  Future<void> _login() async{
    final url = Uri.parse("http://124.93.196.45:10001/prod-api/api/login");
    try{
      HttpClient httpClient = HttpClient();
      HttpClientRequest request = await httpClient.postUrl(url);
      request.headers.set("Content-Type", "application/json");
      request.add(utf8.encode(jsonEncode(
          {
            "username":_email.text,
            "password":_password.text
          },
      )));
      httpClient.close();
      HttpClientResponse response = await request.close();
      if(response.statusCode == HttpStatus.ok){
        String responseBody = await response.transform(utf8.decoder).join();
        final json = jsonDecode(responseBody);
        Data.token = json['token'];
        //当登录成功后判断用户是否选择记住密码,如果选中了,则将调用android原生功能将账号密码存储    
        if(remember){
          await plat.invokeMethod("addUser",{
            "email": _email.text,
            "password": _password.text,
          });
        }else{    //如果没选中那么就将账号密码删除SharedPreferences 这个类是原生中的用来存储数据比较小的键值对数据的,就算没有这个账号密码也不会报错
         final android =  await plat.invokeMethod("deleteUser");
         print(android);
        }
        Navigator.push(context, PageRouteBuilder(
          pageBuilder: (context,animation,secondaryAnimation){
            return IndexBottom();
          },
          transitionsBuilder: (context,animation,secondaryAnimation,child){
            return FadeTransition(opacity: animation,child: child);
          }
        ));
      }
    }catch(error){
      print("报错信息为: $error");
    }
  }
  @override
  void initState() {
    _email = TextEditingController();
    _password = TextEditingController();

    getLogin();
    super.initState();
  }
  void getLogin() async{
    //当用户第一次进来的时候判断调用android原生通信,判断是否有账号密码的存储
    final response = await plat.invokeMethod("getUser");
    if(response.toString().trim() != "0"){
      final form = response.toString().split("-");
      _email.text = form[0];
      print(form[0]);
      _password.text = form[1];
      remember = true;
    }
    setState(() {
    });
  }
  bool look = true;
  bool remember = false;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          SizedBox(height: 10),
          Text(widget.title,style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold
          ),),
          SizedBox(height: 10),
          Container(
            margin: EdgeInsets.symmetric(horizontal: 10),
            child: TextFormField(
              controller: _email,
              validator: (value){
                if(value == null || value.toString().trim() == ""){
                  return "请输入邮箱地址";
                }
              },
              decoration: InputDecoration(
                  hintText: "Email",
                  prefixIcon: Icon(Icons.email)
              ),
            ),
          ),
          SizedBox(height: 20),
          Container(
            margin: EdgeInsets.symmetric(horizontal: 10),
            child: TextFormField(
              controller: _password,
              validator: (value){
                if(value == null || value.trim() == "" || value.toString().length <= 5){
                  return "请输入至少包含六位数的密码";
                }
              },
              obscureText: look,
              decoration: InputDecoration(
                  hintText: "Password",
                  prefixIcon: Icon(Icons.lock),
                 suffixIcon: GestureDetector(
                   onTap: (){
                     setState(() {
                       look = !look;
                     });
                   },
                   child: Icon(look ? Icons.visibility : Icons.visibility_off),
                 )
              ),
            ),
          ),
          SizedBox(height: 20),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                height: 20,
                width: 20,
                margin: EdgeInsets.only(right: 5),
                child: Checkbox(
                  onChanged: (value){
                    remember = value as bool;
                    setState(() {
                    });
                  },
                  value: remember,
                ),
              ),
              Text("Remember Password?"),
            ],
          ),
          SizedBox(height: 10),
          Container(
            height: 40,
            width: 150,
            child: ElevatedButton.icon(
                onPressed: (){
                  if(_formKey.currentState!.validate()){
                    _login();
                  }
                },
                icon: Icon(Icons.touch_app),
                label: Text(widget.title)
            ),
          ),
          SizedBox(height: 10),
          Text(widget.subTitle,style: TextStyle(fontSize: 12,color: Colors.black87),)
        ],
      ),
    );
  }
}

由于本案例写了原生安卓代码,用户选择记住密码将会把账号密码存储至

SharedPreferences文件当中,这是我的android原生代码
package com.example.httpclient_basic;

import android.content.Context;
import android.content.SharedPreferences;

import androidx.annotation.NonNull;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "com.example.httpclient_basic";
    private MethodChannel.Result result;

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        GeneratedPluginRegistrant.registerWith(flutterEngine);

        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),CHANNEL)
                .setMethodCallHandler(
                        (call, result) -> {
                            this.result = result;
                            if(call.method.equals("addUser")){
                                String email = call.argument("email");
                                String password = call.argument("password");
                                addUser(email,password);
                            }else if(call.method.equals("getUser")){
                                getUser();
                            }else if(call.method.equals("deleteUser")){
                                deleteUser();
                            }
                        }
                );
    }

    private void deleteUser() {
        SharedPreferences sp = getSharedPreferences("user",Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove("email");
        editor.remove("password");
        editor.apply();
        result.success("1");
    }

    private void getUser() {
        SharedPreferences sp = getSharedPreferences("user",Context.MODE_PRIVATE);
        String email = sp.getString("email",null);
        String password = sp.getString("password",null);
        System.out.println(password);
        if(email == null || email.trim() == ""){
            result.success("0");
        }else{
            result.success(email + "-" + password);
        }
    }

    private void addUser(String email, String password) {
        SharedPreferences sp = getSharedPreferences("user", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("email",email);
        editor.putString("password",password);
        editor.apply();
        result.success("1");
    }
}

也有的时候需要设置数据的字节长度,这个字符串正好由 6 个字符组成所以占用一个字节,下面是一个get请求这需要传入你需要获取的数据的类型, 这个api需要你传入的是表单数据,所以要将发送的数据类型写好,

var contentLength = utf8.encode('type=1').length; ,
Future<void> getData() async{
    Uri url = Uri.parse("http://124.93.196.45:10001/prod-api/api/rotation/list");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(url);
    // 设置请求头部
    request.headers.set('Content-Type', 'application/x-www-form-urlencoded');
// 计算表单数据的长度,并设置请求头部 Content-Length
    var contentLength = utf8.encode('type=1').length;
    request.headers.set('Content-Length', contentLength.toString());
    request.write("type=1");    //然后将请求参数传入
    var response = await request.close();
    String responseBody = await response.transform(utf8.decoder).join();
    final json = jsonDecode(responseBody)['rows'];
    _list = json;
    setState(() {
    });
  }

下列将讲解登陆之后传递的token将如何使用,有些私人信息,就会需要用到token,他是用来告诉api我这个已经登陆过了,然后将token传送过去,进行验证你是哪一个账号,然后将数据给你返回过去,代码中有注释,就不过多赘述了

Future<void> getData() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/common/user/getInfo");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(uri);
    //设置请求头获取的参数类型
    request.headers.set("Content-Type", "application/json");
    //设置请求头获取的token, 这个token我写成了全局静态数据,方便于所有页面的使用
    request.headers.set("Authorization", Data.token);
    HttpClientResponse response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      final responseBody =await response.transform(utf8.decoder).join();
      final json = jsonDecode(responseBody.toString());
      _user = json['user'];
      setState(() {
      });
      print(responseBody);
    }
  }

总结的大部分请求类型

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

import 'package:api_test/data.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<dynamic> _list = [];
  int currentIndex = 0;
  Timer? _timer;
  @override
  void initState() {
    getData();
    getPerson();
    banner();
    super.initState();
  }
  void banner() {
    if(_timer == null){
      _timer = Timer.periodic(Duration(seconds: 3), (timer) {
        currentIndex++;
        if(currentIndex >= _list.length){
          currentIndex = 0;
        }
        setState(() {
        });
      });
    }
  }
  Future<void> getData() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/rotation/list");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(uri);
    request.headers.add("Content-Type", "application/json");
    HttpClientResponse response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      String responseBody = await response.transform(utf8.decoder).join();
      final json = jsonDecode(responseBody);
      _list = json['rows'];
      _timer!.cancel();
      _timer = null;
      setState(() {
      });
    }
  }
  Map<String,dynamic> _person = {};
  Future<void> getPerson() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/common/user/getInfo");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(uri);
    request.headers.add("Authorization", Data.token);
    HttpClientResponse response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      String body = await response.transform(utf8.decoder).join();
      final json = jsonDecode(body);
      _person = json['user'];
      setState(() {
      });
    }
  }
  
获取需要传递token的api, 然后这是一个修改
  Future<void> setPerson() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/common/user");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.putUrl(uri);
    request.headers.add("Authorization", Data.token);
    request.headers.add("Content-Type", "application/json");
    request.add(utf8.encode(jsonEncode({
      "email": "tanrui@qq.com",
      "idCaard": "123123123123123",
      "nickName": "我叫大卫",
      "phonenumber":"15333134390",
      "sex": "0"
    })));
    HttpClientResponse response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      String body = await response.transform(utf8.decoder).join();
      final json = jsonDecode(body);
      print(json);
    }
  }

获取需要传递表单数据的,不过这是只是一个参数,如果传递多个请看下一个方法
  Future<void> getType() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/rotation/list");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(uri);
    request.headers.add("Content-Type","application/json");
    String param = "type=1";
    final length = param.length.toString();
    request.headers.add("Content-Length", length);
    request.write("type=1");
    HttpClientResponse response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      String body = await response.transform(utf8.decoder).join();
      print(body);
    }
  }
  
  //发送多表单数据
  Future<void> setForm() async{
    Uri uri = Uri.parse("http://124.93.196.45:10001/prod-api/api/common/gps/city");
    HttpClient httpClient = HttpClient();
    HttpClientRequest request = await httpClient.getUrl(uri);
   设置请求头类型
    request.headers.add("Content-Type", "application/x-www-form-urlencoded");
    var formData = { //设置form数据
      "name" :"衡阳市",
      "provinceName" : "湖南省"
    };

    //确保将每个参数的名称和值进行编码, 将每个参数用字符串&连接起来
    var body = formData.entries.map(
            (e) => '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}').join("&");
    request.headers.add("Content-Length", body.length.toString());
    request.write(body);
    var response = await request.close();
    if(response.statusCode == HttpStatus.ok){
      String responseBody = await response.transform(utf8.decoder).join();
      print(responseBody);
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: Column(
          children: [
            SizedBox(height: (MediaQuery.of(context).padding.top)),
            _list.length > 0 ? AnimatedSwitcher(
                duration: Duration(milliseconds: 500),
              transitionBuilder: (child,animated){
                  return SlideTransition(
                      position: Tween<Offset>(
                        begin: Offset(1.0,0.0),
                        end: Offset.zero
                      ).animate(animated),
                    child: child,
                  );
              },
              child: Container(
                height: 200,
                width: 350,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(20),
                  image: DecorationImage(
                    image: NetworkImage("http://124.93.196.45:10001${_list[currentIndex]['advImg']}"),
                    fit: BoxFit.cover
                  )
                ),
                alignment: Alignment.bottomCenter,
                key: UniqueKey(),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: List.generate(_list.length, (index){
                    return GestureDetector(
                      onTap: (){
                        currentIndex = index;
                        _timer!.cancel();
                        _timer = null;
                        banner();
                        setState(() {
                        });
                      },
                      child: Container(
                        height: 15,
                        width: 15,
                        margin: EdgeInsets.only(right: 10,bottom: 10),
                        decoration: BoxDecoration(
                          color: currentIndex == index ? Colors.red: Colors.grey,
                          borderRadius: BorderRadius.circular(10)
                        ),
                      ),
                    );
                  }),
                ),
              ),
            ): CircularProgressIndicator(),
            _person.length > 0 ? Text(_person['email']) : Container(),
            Container(
              height: 50,
              width: 200,
              child: ElevatedButton(
                onPressed: setPerson,
                style: ElevatedButton.styleFrom(
                  primary: Colors.red,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(20)
                  )
                ),
                child: Text("修改用户数据"),
              ),
            ),
            SizedBox(height: 20,),
            Container(
              height: 50,
              width: 200,
              child: ElevatedButton(
                onPressed: getType,
                style: ElevatedButton.styleFrom(
                    primary: Colors.red,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20)
                    )
                ),
                child: Text("获取主页或引导页"),
              ),
            ),
            SizedBox(height: 20,),
            Container(
              height: 50,
              width: 200,
              child: ElevatedButton(
                onPressed: setForm,
                style: ElevatedButton.styleFrom(
                    primary: Colors.red,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20)
                    )
                ),
                child: Text("表单数据的测试"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值