关于 flutter-use-http-package
这项 Flutter 开发技能介绍如何使用 Dart 的 `http` 包构建 REST 客户端,涵盖请求处理、错误检查、可测试性及后台 JSON 解析。
主要功能
- 01配置 HTTP 客户端和权限
- 02处理 REST 请求与响应
- 03检查状态码并处理错误
- 04注入客户端以便模拟测试
- 05使用 `compute()` 后台解析 JSON
适用场景
- 01在 Flutter 应用中实现 REST 调用
- 02用模拟客户端测试网络类
- 03在 UI 线程外解析大型 JSON
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dhruvanbhalara/ skills --skill flutter-use-http-package安装后在 Claude Code 中输入/flutter-use-http-package确认已加载。
详细介绍
目录
配置和权限
配置开发环境和特定于平台的访问控制,以启用网络请求:
- 使用终端添加
http依赖:flutter pub add http - 在 Dart 文件中使用别名导入库:
import 'package:http/http.dart' as http; - 在 Android 上启用互联网权限:修改
<manifest>标签内的android/app/src/main/AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> - 在 macOS 上启用互联网客户端:修改
<dict>标签内的macos/Runner/DebugProfile.entitlements和macos/Runner/Release.entitlements:<key>com.apple.security.network.client</key> <true/>
请求执行与响应处理
应用以下最佳实践,构建可靠的 REST 客户端:
- 严格解析 URL:始终通过
Uri.parse('url')解析端点字符串。切勿将原始字符串传递给客户端调用。 - 请求头和身份验证:附加所有授权、接受和内容类型配置。使用
dart:io中的HttpHeaders.authorizationHeader键注入访问令牌。 - 负载编码:更改资源状态(POST、PUT)时,使用
dart:convert中的jsonEncode编码负载正文。 - 状态验证:验证响应代码。仅处理明确的成功状态代码(例如
200 OK或201 Created)。 - 出错时抛出异常:服务器返回失败状态代码时,抛出描述性异常。失败时切勿返回
null,因为这会掩盖问题,并导致 UI 加载指示器无限转圈。 - 客户端模拟:让网络类接收
http.Client依赖,而不是调用标准全局方法。这便于测试和注入模拟对象。
后台解析
处理大于 1 MB 的负载时,将 JSON 解码和映射操作转移到后台线程,以避免 UI 卡顿(丢帧):
- 导入
package:flutter/foundation.dart。 - 在
compute()函数中运行解析逻辑,以启动后台 isolate。 - 确保解析函数定义为顶层函数或静态类方法。闭包和常规实例方法无法跨越 isolate 边界。
工作流:执行网络操作
按照此清单构建并验证网络集成:
- 定义模型契约:创建清晰、不可变的模型类,并实现自定义
fromJson工厂构造函数。 - 建立 HTTP 客户端:构建接收
http.Client的网络客户端类。 - 构造请求:
- 对于读取(GET):将查询参数附加到 URI。
- 对于更改(POST/PUT):设置
'Content-Type': 'application/json; charset=UTF-8'并附加jsonEncode数据。 - 对于删除(DELETE):匹配
200 OK时,返回成功指示值或空模型映射。
- 落实错误处理:针对非成功状态代码抛出有意义的异常。
- 集成 UI 状态:在 UI 层将网络请求绑定到
FutureBuilder或状态管理控制器。 - 验证边界情况:测试正确的加载屏幕、错误对话框和离线处理反馈流程。
示例
完整网络客户端和 Isolate 解析器
此示例演示如何设置可靠、易于测试的网络客户端,并在后台 isolate 中解析复杂的负载列表。
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Article {
final int id;
final String title;
const Article({required this.id, required this.title});
factory Article.fromJson(Map<String, dynamic> json) {
return Article(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
// Top-level function for background isolate computation
List<Article> parseArticles(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Article>((json) => Article.fromJson(json)).toList();
}
class ApiService {
final http.Client client;
ApiService({http.Client? client}) : client = client ?? http.Client();
Future<List<Article>> fetchArticles() async {
final response = await client.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
headers: {
HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
HttpHeaders.acceptHeader: 'application/json',
},
);
if (response.statusCode == 200) {
// Offload to background isolate
return compute(parseArticles, response.body);
} else {
throw HttpException('Failed to load articles: ${response.statusCode}');
}
}
}
评论
支持 Markdown