09-Flutter鸿蒙网络请求入门:HTTP数据请求和JSON模型封装

09. Flutter鸿蒙网络请求入门:HTTP数据请求和JSON模型封装

网络请求是业务项目最常见的能力之一。Flutter 鸿蒙项目中,普通 HTTP 请求仍然可以在 Flutter 层完成:添加依赖、封装模型、写请求服务、处理加载状态和错误状态即可。

添加依赖

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.2

执行:

bash 复制代码
flutter pub get

定义模型

dart 复制代码
class User {
  final int id;
  final String name;
  final String phone;

  const User({
    required this.id,
    required this.name,
    required this.phone,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int? ?? 0,
      name: json['name'] as String? ?? '',
      phone: json['phone'] as String? ?? '',
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'phone': phone,
    };
  }
}

封装服务

dart 复制代码
import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiService {
  ApiService({http.Client? client}) : _client = client ?? http.Client();

  final http.Client _client;
  static const String baseUrl = 'https://example.com/api';

  Future<List<User>> fetchUsers() async {
    final uri = Uri.parse('$baseUrl/users');
    final response = await _client.get(uri);

    if (response.statusCode != 200) {
      throw Exception('请求失败:${response.statusCode}');
    }

    final data = jsonDecode(response.body);
    if (data is! List) {
      throw Exception('接口返回格式不是数组');
    }

    return data
        .map((item) => User.fromJson(item as Map<String, dynamic>))
        .toList();
  }

  Future<User> createUser(String name, String phone) async {
    final uri = Uri.parse('$baseUrl/users');
    final response = await _client.post(
      uri,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'name': name, 'phone': phone}),
    );

    if (response.statusCode != 200 && response.statusCode != 201) {
      throw Exception('新增失败:${response.statusCode}');
    }

    return User.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
  }
}

页面状态

dart 复制代码
class UserListPage extends StatefulWidget {
  const UserListPage({super.key});

  @override
  State<UserListPage> createState() => _UserListPageState();
}

class _UserListPageState extends State<UserListPage> {
  late Future<List<User>> _future;

  @override
  void initState() {
    super.initState();
    _future = ApiService().fetchUsers();
  }

  Future<void> _reload() async {
    setState(() {
      _future = ApiService().fetchUsers();
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<User>>(
      future: _future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        }
        if (snapshot.hasError) {
          return Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('加载失败:${snapshot.error}'),
                const SizedBox(height: 12),
                FilledButton(onPressed: _reload, child: const Text('重试')),
              ],
            ),
          );
        }
        final users = snapshot.data ?? [];
        if (users.isEmpty) {
          return const Center(child: Text('暂无数据'));
        }
        return RefreshIndicator(
          onRefresh: _reload,
          child: ListView.builder(
            itemCount: users.length,
            itemBuilder: (_, index) {
              final user = users[index];
              return ListTile(
                title: Text(user.name),
                subtitle: Text(user.phone),
              );
            },
          ),
        );
      },
    );
  }
}

排错

网络问题常见排查:

text 复制代码
1. 接口地址是否能在浏览器或 Postman 打开
2. 设备是否有网络权限和网络连接
3. HTTP/HTTPS 是否符合服务端要求
4. JSON 顶层结构是对象还是数组
5. statusCode 是否被正确处理
6. 页面是否处理 loading、empty、error 三种状态

请求层不要直接写在页面里

页面里直接写 http.get 能跑,但项目变大后很难维护。更好的做法是页面只关心状态,网络细节放到 service:

text 复制代码
lib
├─ models
│  └─ user.dart
├─ services
│  └─ api_service.dart
└─ pages
   └─ user_list_page.dart

这样接口地址变化、请求头变化、错误处理变化时,不需要翻每个页面。

调试接口返回

开发阶段可以临时打印响应:

dart 复制代码
debugPrint('statusCode: ${response.statusCode}');
debugPrint('body: ${response.body}');

正式提交前不要在日志里输出敏感信息,比如 token、手机号、身份证、详细地址。网络日志要能辅助排错,但不能泄露用户数据。

不需要翻每个页面。

相关推荐
2401_8685347811 分钟前
无线网络规划设计
服务器·网络
我命由我1234521 分钟前
Photoshop - Photoshop 矢量蒙版
学习·职场和发展·产品运营·求职招聘·职场发展·产品经理·photoshop
螺蛳粉 螺蛳粉24 分钟前
第二篇:keepalived VRRP 原理篇:协议与 VIP 漂移机制深入解析
网络·智能路由器·负载均衡·keepalived·高可用
律宏阔34 分钟前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
特立独行的猫A36 分钟前
cj-tauri开源项目介绍与imovie观影客户端项目实战
harmonyos
盟接之桥41 分钟前
AI助手:你的7×24小时智能管家——让异常预警无处不在
大数据·网络·数据库·人工智能·制造·ai编程
律宏阔1 小时前
Dart 3 Record:解决 Future.wait 异构返回值的类型问题
前端·flutter
熊猫钓鱼>_>1 小时前
越顺,越空:当 AI 把学习 “优化“ 到消失
人工智能·学习·ai·llm·agent·ai编程·metaai
一条破秋裤1 小时前
02_注册设备号_从主次设备号到成对注销
学习
@codercjw2 小时前
企业实战电机和传感器选型
学习