✅近期推荐:求职神器
https://bbs.csdn.net/topics/619384540
🔥欢迎大家订阅系列专栏:flutter_鸿蒙next
💬淼学派语录:只有不断的否认自己和肯定自己,才能走出弯曲不平的泥泞路,因为平坦的大路,太tm无趣了!
写在前面
在现代应用中,处理用户身份验证和缓存是非常重要的。Dio 是一个强大的 Dart HTTP 客户端,支持多种功能,例如请求拦截、响应拦截等。本文将详细讲解如何在 Flutter 中使用 Dio 封装网络请求,并实现登录身份验证及免登录缓存功能。
一、引入 Dio
首先,在 pubspec.yaml
文件中添加 Dio 依赖:
dependencies:
dio: ^5.0.0
shared_preferences: ^2.0.0
运行 flutter pub get
命令安装依赖。
二、创建 Dio 封装类
在 lib/services
目录下新建 network_service.dart
文件,编写以下代码以封装 Dio 功能:
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class NetworkService {
late Dio _dio;
static const String _tokenKey = 'auth_token';
NetworkService() {
_dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com/', // 替换为你的 API 基础 URL
connectTimeout: 5000,
receiveTimeout: 3000,
));
// 添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
final token = await _getToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token'; // 添加 Token 到请求头
}
print('请求: ${options.method} ${options.path}');
handler.next(options);
},
onResponse: (response, handler) {
print('响应: ${response.statusCode} ${response.data}');
handler.next(response);
},
onError: (DioError e, handler) {
print('错误: ${e.response?.statusCode} ${e.message}');
handler.next(e);
},
));
}
// 获取 Token
Future<String?> _getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(_tokenKey);
}
// 登录请求
Future<Response> login(String username, String password) async {
final response = await _dio.post('/login', data: {
'username': username,
'password': password,
});
// 保存 Token
await _saveToken(response.data['token']);
return response;
}
// 保存 Token
Future<void> _saveToken(String token) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_tokenKey, token);
}
// 退出登录
Future<void> logout() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_tokenKey); // 移除 Token
}
// GET 请求
Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
return await _dio.get(path, queryParameters: queryParameters);
}
// POST 请求
Future<Response> post(String path, {dynamic data}) async {
return await _dio.post(path, data: data);
}
}
代码详解
-
Token 存储:
- 使用
shared_preferences
存储用户的 Token,以便后续请求中使用。 _getToken()
方法用于获取存储的 Token。
- 使用
-
登录请求:
login
方法发送用户名和密码进行身份验证,成功后保存返回的 Token。
-
请求拦截:
- 在请求拦截器中,检查是否有 Token,如果有,则添加到请求头中。
-
退出登录:
logout
方法移除存储的 Token,以实现用户登出。
三、使用封装的 NetworkService
在 Flutter 应用中使用 NetworkService
进行身份验证非常简单。以下示例展示了如何创建一个登录界面。
1. 创建登录界面
在 lib/main.dart
文件中编写以下代码:
import 'package:flutter/material.dart';
import 'services/network_service.dart';
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final NetworkService _networkService = NetworkService();
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
String _message = '';
void _login() async {
try {
final response = await _networkService.login(
_usernameController.text,
_passwordController.text,
);
setState(() {
_message = '登录成功: ${response.data}';
});
} catch (e) {
setState(() {
_message = '登录失败: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('登录')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _usernameController,
decoration: InputDecoration(labelText: '用户名'),
),
TextField(
controller: _passwordController,
decoration: InputDecoration(labelText: '密码'),
obscureText: true,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _login,
child: Text('登录'),
),
SizedBox(height: 20),
Text(_message),
],
),
),
);
}
}
void main() => runApp(MaterialApp(home: LoginPage()));
代码详解
- 输入框:使用
TextField
组件获取用户名和密码。 - 登录按钮:点击按钮后调用
_login
方法进行登录。 - 状态管理:通过
setState
更新界面,显示登录结果。
写在后面
通过封装 Dio,我们实现了用户身份验证与 Token 的存储和使用。使用 shared_preferences
实现简单的免登录缓存机制,提高用户体验。希望这篇博客能帮助你更好地在 Flutter 中使用 Dio 进行网络请求与身份验证。如有疑问或建议,欢迎讨论!