mcpField
F
flutter-use-http-package

flutter-use-http-package

github.com/flutter开发3.1k36.5k 次安装2 天前更新
代码仓库

关于 flutter-use-http-package

面向 Flutter 开发的 HTTP 网络编程技能,使用 `http` 包处理请求。内容涵盖平台权限、类型化 JSON 解析、错误处理和后台解析。

主要功能

  1. 01HTTP 配置与平台权限
  2. 02GET、POST、PUT 和 DELETE 请求
  3. 03类型化 JSON 反序列化
  4. 04使用 compute() 后台解析
  5. 05FutureBuilder 错误处理

适用场景

  1. 01为 Flutter 应用添加 API 请求
  2. 02在 UI 线程之外解析大型 JSON 响应
  3. 03在界面中呈现请求和解析错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/flutter/agent-plugins --skill flutter-use-http-package

安装后在 Claude Code 中输入/flutter-use-http-package确认已加载。

详细介绍

实现 Flutter 网络通信

目录

配置和权限

配置访问网络所需的环境和特定平台权限。

  1. 在终端中添加 http 包依赖:
    flutter pub add http
    
  2. 在 Dart 文件中导入该包:
    import 'package:http/http.dart' as http;
    
  3. 在 android/app/src/main/AndroidManifest.xml 中添加 Internet 权限,以配置 Android 权限:
    <uses-permission android:name="android.permission.INTERNET" />
    
  4. 在 macos/Runner/DebugProfile.entitlements 和 macos/Runner/Release.entitlements 中添加网络客户端键,以配置 macOS 权限:
    <key>com.apple.security.network.client</key>
    <true/>
    

请求执行和响应处理

执行 HTTP 操作,并将响应映射为强类型 Dart 对象。

  • URI: 始终使用 Uri.parse('your_url') 解析 URL 字符串。
  • 标头: 通过 headers 参数映射注入授权和内容类型标头。使用 HttpHeaders.authorizationHeader 设置身份验证令牌。
  • 请求负载: 对于 POST 和 PUT 请求,使用 dart:convert 中的 jsonEncode() 对请求正文进行编码。
  • 状态验证: 检查 response.statusCode。将 200 OK(GET/PUT/DELETE)和 201 CREATED(POST)视为成功。
  • 错误处理: 对非成功状态码抛出明确的异常。失败时绝不返回 null,否则会阻止 FutureBuilder 进入错误状态,并导致加载指示器无限显示。
  • 反序列化: 使用 jsonDecode(response.body) 解析原始字符串,并通过工厂构造函数(例如 fromJson)将其映射为自定义 Dart 对象。

后台解析

将耗时的 JSON 解析任务转移到单独的 Isolate 中,以避免 UI 卡顿(帧丢失)。

  • 导入 package:flutter/foundation.dart。
  • 使用 compute() 函数在后台 Isolate 中运行解析逻辑。
  • 确保传递给 compute() 的解析函数是顶层函数或静态方法,因为闭包或实例方法无法跨 Isolate 传递。

工作流:执行网络操作

使用以下检查清单实现并验证网络操作。

任务进度:

  • 1. 定义强类型 Dart 模型,并添加 fromJson 工厂构造函数。
  • 2. 实现返回 Future<Model> 的网络请求方法。
  • 3. 根据操作类型应用条件逻辑:
    • 如果要获取数据(GET): 将查询参数追加到 URI。
    • 如果要修改数据(POST/PUT): 设置 'Content-Type': 'application/json; charset=UTF-8' 并附加 jsonEncode 请求正文。
    • 如果要删除数据(DELETE): 成功时(200 OK)返回空模型实例。
  • 4. 验证 statusCode,失败时抛出 Exception。
  • 5. 使用 FutureBuilder 将 Future 集成到 UI 中。
  • 6. 处理 snapshot.hasData 和 snapshot.hasError,默认显示 CircularProgressIndicator。
  • 7. 反馈循环: 运行应用 -> 触发网络请求 -> 检查控制台中未处理的异常 -> 修复解析或权限错误。

示例

高保真实现:在后台获取并解析
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;

// 1. Top-level parsing function for Isolate
List<Photo> parsePhotos(String responseBody) {
  final parsed = (jsonDecode(responseBody) as List<Object?>)
      .cast<Map<String, Object?>>();
  return parsed.map<Photo>(Photo.fromJson).toList();
}

// 2. Network execution with background parsing
Future<List<Photo>> fetchPhotos() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/photos'),
    headers: {
      HttpHeaders.authorizationHeader: 'Bearer your_token_here',
      HttpHeaders.acceptHeader: 'application/json',
    },
  );

  if (response.statusCode == 200) {
    // Offload heavy parsing to a background isolate
    return compute(parsePhotos, response.body);
  } else {
    throw Exception('Failed to load photos. Status: ${response.statusCode}');
  }
}

// 3. Strongly typed model
class Photo {
  final int id;
  final String title;
  final String thumbnailUrl;

  const Photo({
    required this.id,
    required this.title,
    required this.thumbnailUrl,
  });

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as int,
      title: json['title'] as String,
      thumbnailUrl: json['thumbnailUrl'] as String,
    );
  }
}

// 4. UI Integration
class PhotoGallery extends StatefulWidget {
  const PhotoGallery({super.key});

  @override
  State<PhotoGallery> createState() => _PhotoGalleryState();
}

class _PhotoGalleryState extends State<PhotoGallery> {
  late Future<List<Photo>> _futurePhotos;

  @override
  void initState() {
    super.initState();
    // Initialize Future once to prevent re-fetching on rebuilds
    _futurePhotos = fetchPhotos();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Photo>>(
      future: _futurePhotos,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final photos = snapshot.data!;
          return ListView.builder(
            itemCount: photos.length,
            itemBuilder: (context, index) => ListTile(
              leading: Image.network(photos[index].thumbnailUrl),
              title: Text(photos[index].title),
            ),
          );
        } else if (snapshot.hasError) {
          return Center(child: Text('Error: ${snapshot.error}'));
        }
        
        // Default loading state
        return const Center(child: CircularProgressIndicator());
      },
    );
  }
}

评论

支持 Markdown