http包、Dio、JSON解析
# pubspec.yaml
dependencies:
http: ^1.1.0
import 'package:http/http.dart' as http;
import 'dart:convert';
// GET请求
Future fetchData() async {
final response = await http.get(
Uri.parse('https://api.example.com/users'),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
print(data);
} else {
throw Exception('请求失败');
}
}
// POST请求
Future createUser() async {
final response = await http.post(
Uri.parse('https://api.example.com/users'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'name': '张三',
'email': 'zhang@example.com',
}),
);
if (response.statusCode == 201) {
print('创建成功');
}
}
# pubspec.yaml
dependencies:
dio: ^5.3.0
import 'package:dio/dio.dart';
class ApiService {
final Dio _dio = Dio(
BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 5),
receiveTimeout: Duration(seconds: 3),
headers: {
'Content-Type': 'application/json',
},
),
);
// GET请求
Future> getUsers() async {
try {
final response = await _dio.get('/users');
return (response.data as List)
.map((json) => User.fromJson(json))
.toList();
} on DioException catch (e) {
throw _handleError(e);
}
}
// POST请求
Future createUser(User user) async {
try {
final response = await _dio.post(
'/users',
data: user.toJson(),
);
return User.fromJson(response.data);
} on DioException catch (e) {
throw _handleError(e);
}
}
// PUT请求
Future updateUser(int id, User user) async {
final response = await _dio.put(
'/users/$id',
data: user.toJson(),
);
return User.fromJson(response.data);
}
// DELETE请求
Future deleteUser(int id) async {
await _dio.delete('/users/$id');
}
String _handleError(DioException e) {
switch (e.type) {
case DioExceptionType.connectionTimeout:
return '连接超时';
case DioExceptionType.sendTimeout:
return '发送超时';
case DioExceptionType.receiveTimeout:
return '接收超时';
case DioExceptionType.badResponse:
return '服务器错误: ${e.response?.statusCode}';
case DioExceptionType.cancel:
return '请求取消';
default:
return '网络错误';
}
}
}
// 用户模型
class User {
final int id;
final String name;
final String email;
final int age;
User({
required this.id,
required this.name,
required this.email,
required this.age,
});
// 从JSON创建对象
factory User.fromJson(Map json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
age: json['age'],
);
}
// 转换为JSON
Map toJson() {
return {
'id': id,
'name': name,
'email': email,
'age': age,
};
}
}
// 使用示例
void main() {
// JSON字符串转对象
String jsonString = '{"id": 1, "name": "张三", "email": "zhang@example.com", "age": 25}';
Map jsonMap = jsonDecode(jsonString);
User user = User.fromJson(jsonMap);
// 对象转JSON字符串
String json = jsonEncode(user.toJson());
print(json);
}
class UserListPage extends StatelessWidget {
final ApiService _apiService = ApiService();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('用户列表')),
body: FutureBuilder>(
future: _apiService.getUsers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text('错误: ${snapshot.error}'),
);
}
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('暂无数据'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
trailing: Text('${user.age}岁'),
);
},
);
},
),
);
}
}
class ApiService {
late Dio _dio;
ApiService() {
_dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
));
// 添加拦截器
_dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
// 添加token
options.headers['Authorization'] = 'Bearer token123';
print('请求: ${options.method} ${options.path}');
return handler.next(options);
},
onResponse: (response, handler) {
print('响应: ${response.statusCode}');
return handler.next(response);
},
onError: (error, handler) {
print('错误: ${error.message}');
return handler.next(error);
},
),
);
}
}
Future uploadFile(File file) async {
String fileName = file.path.split('/').last;
FormData formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
file.path,
filename: fileName,
),
'description': '文件描述',
});
try {
final response = await _dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
print('上传进度: ${(sent / total * 100).toStringAsFixed(0)}%');
},
);
print('上传成功: ${response.data}');
} catch (e) {
print('上传失败: $e');
}
}
Future downloadFile(String url, String savePath) async {
try {
await _dio.download(
url,
savePath,
onReceiveProgress: (received, total) {
if (total != -1) {
print('下载进度: ${(received / total * 100).toStringAsFixed(0)}%');
}
},
);
print('下载完成');
} catch (e) {
print('下载失败: $e');
}
}
// 新闻模型
class News {
final int id;
final String title;
final String content;
final String author;
final DateTime publishTime;
News({
required this.id,
required this.title,
required this.content,
required this.author,
required this.publishTime,
});
factory News.fromJson(Map json) {
return News(
id: json['id'],
title: json['title'],
content: json['content'],
author: json['author'],
publishTime: DateTime.parse(json['publish_time']),
);
}
}
// API服务
class NewsService {
final Dio _dio = Dio(
BaseOptions(baseUrl: 'https://api.news.com'),
);
Future> getNewsList({int page = 1, int pageSize = 20}) async {
final response = await _dio.get(
'/news',
queryParameters: {'page': page, 'page_size': pageSize},
);
return (response.data['data'] as List)
.map((json) => News.fromJson(json))
.toList();
}
Future getNewsDetail(int id) async {
final response = await _dio.get('/news/$id');
return News.fromJson(response.data);
}
}
// 新闻列表页面
class NewsListPage extends StatefulWidget {
@override
State createState() => _NewsListPageState();
}
class _NewsListPageState extends State {
final NewsService _newsService = NewsService();
List _newsList = [];
bool _isLoading = false;
int _currentPage = 1;
@override
void initState() {
super.initState();
_loadNews();
}
Future _loadNews() async {
if (_isLoading) return;
setState(() => _isLoading = true);
try {
final news = await _newsService.getNewsList(page: _currentPage);
setState(() {
_newsList.addAll(news);
_currentPage++;
});
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('加载失败: $e')),
);
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('新闻列表')),
body: RefreshIndicator(
onRefresh: () async {
_currentPage = 1;
_newsList.clear();
await _loadNews();
},
child: ListView.builder(
itemCount: _newsList.length + 1,
itemBuilder: (context, index) {
if (index == _newsList.length) {
return _isLoading
? Center(child: CircularProgressIndicator())
: SizedBox();
}
final news = _newsList[index];
return ListTile(
title: Text(news.title),
subtitle: Text('${news.author} · ${_formatTime(news.publishTime)}'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewsDetailPage(newsId: news.id),
),
);
},
);
},
),
),
);
}
String _formatTime(DateTime time) {
final now = DateTime.now();
final diff = now.difference(time);
if (diff.inDays > 0) return '${diff.inDays}天前';
if (diff.inHours > 0) return '${diff.inHours}小时前';
if (diff.inMinutes > 0) return '${diff.inMinutes}分钟前';
return '刚刚';
}
}