首先发送请求一共分为几步?
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("表单数据的测试"),
),
),
],
),
),
);
}
}