flutter-http-and-json
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseflutter-http-json-networking
flutter-http-json-networking
Goal
目标
Manages HTTP networking and JSON data handling in Flutter applications. Implements secure, asynchronous REST API calls (GET, POST, PUT, DELETE) using the package. Handles JSON serialization, background parsing via isolates for large datasets, and structured JSON schemas for AI model integrations. Assumes the package is added to and the environment supports Dart 3 pattern matching and null safety.
httphttppubspec.yaml管理Flutter应用中的HTTP网络请求和JSON数据处理。使用包实现安全的异步REST API调用(GET、POST、PUT、DELETE)。支持JSON序列化、针对大型数据集的isolate后台解析,以及用于AI模型集成的结构化JSON schema。假设包已添加到中,且运行环境支持Dart 3模式匹配和空安全。
httphttppubspec.yamlDecision Logic
决策逻辑
When implementing JSON parsing and serialization, evaluate the following decision tree:
- Payload Size:
- If the JSON payload is small, parse synchronously on the main thread.
- If the JSON payload is large (takes >16ms to parse), use background parsing via to avoid UI jank.
compute()
- Model Complexity:
- If the data model is simple or a quick prototype, use manual serialization ().
dart:convert - If the data model is highly nested or part of a large production app, STOP AND ASK THE USER: "Should we configure and
json_serializablefor automated code generation?"build_runner
- If the data model is simple or a quick prototype, use manual serialization (
实现JSON解析和序列化时,请参考以下决策树:
- 负载大小:
- 如果JSON负载很小,在主线程上同步解析。
- 如果JSON负载很大(解析耗时>16ms),通过使用后台解析避免UI卡顿。
compute()
- 模型复杂度:
- 如果数据模型简单或者是快速原型,使用手动序列化()。
dart:convert - 如果数据模型嵌套层级很深,或者属于大型生产应用,请暂停并询问用户:"我们是否需要配置和
json_serializable来实现自动化代码生成?"build_runner
- 如果数据模型简单或者是快速原型,使用手动序列化(
Instructions
使用说明
1. Configure Platform Permissions
1. 配置平台权限
Before making network requests, ensure the target platforms have the required internet permissions.
Android ():
android/app/src/main/AndroidManifest.xmlxml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
</manifest>macOS ( and ):
macos/Runner/DebugProfile.entitlementsRelease.entitlementsxml
<dict>
<!-- Required to fetch data from the internet. -->
<key>com.apple.security.network.client</key>
<true/>
</dict>发起网络请求前,请确保目标平台已配置所需的网络权限。
Android():
android/app/src/main/AndroidManifest.xmlxml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
</manifest>macOS( 和 ):
macos/Runner/DebugProfile.entitlementsRelease.entitlementsxml
<dict>
<!-- Required to fetch data from the internet. -->
<key>com.apple.security.network.client</key>
<true/>
</dict>2. Define the JSON Data Model
2. 定义JSON数据模型
Create a strongly typed Dart class to represent the JSON data. Use factory constructors for deserialization and a method for serialization.
toJsondart
import 'dart:convert';
class ItemModel {
final int id;
final String title;
const ItemModel({required this.id, required this.title});
// Deserialize using Dart 3 pattern matching
factory ItemModel.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'id': int id, 'title': String title} => ItemModel(id: id, title: title),
_ => throw const FormatException('Failed to parse ItemModel.'),
};
}
// Serialize to JSON
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
};
}创建强类型Dart类来表示JSON数据。使用工厂构造函数实现反序列化,通过方法实现序列化。
toJsondart
import 'dart:convert';
class ItemModel {
final int id;
final String title;
const ItemModel({required this.id, required this.title});
// Deserialize using Dart 3 pattern matching
factory ItemModel.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'id': int id, 'title': String title} => ItemModel(id: id, title: title),
_ => throw const FormatException('Failed to parse ItemModel.'),
};
}
// Serialize to JSON
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
};
}3. Implement HTTP Operations (CRUD)
3. 实现HTTP操作(CRUD)
Use the package to perform network requests. Always use for safe URL encoding. Validate the status code and throw exceptions on failure.
httpUri.httpsdart
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService {
final http.Client client;
ApiService(this.client);
// GET Request
Future<ItemModel> fetchItem(int id) async {
final uri = Uri.https('api.example.com', '/items/$id');
final response = await client.get(uri);
if (response.statusCode == 200) {
return ItemModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to load item: ${response.statusCode}');
}
}
// POST Request
Future<ItemModel> createItem(String title) async {
final uri = Uri.https('api.example.com', '/items');
final response = await client.post(
uri,
headers: <String, String>{'Content-Type': 'application/json; charset=UTF-8'},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
return ItemModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to create item: ${response.statusCode}');
}
}
// DELETE Request
Future<void> deleteItem(int id) async {
final uri = Uri.https('api.example.com', '/items/$id');
final response = await client.delete(
uri,
headers: <String, String>{'Content-Type': 'application/json; charset=UTF-8'},
);
if (response.statusCode != 200) {
throw Exception('Failed to delete item: ${response.statusCode}');
}
}
}使用包执行网络请求。始终使用实现安全的URL编码。校验状态码,请求失败时抛出异常。
httpUri.httpsdart
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService {
final http.Client client;
ApiService(this.client);
// GET Request
Future<ItemModel> fetchItem(int id) async {
final uri = Uri.https('api.example.com', '/items/$id');
final response = await client.get(uri);
if (response.statusCode == 200) {
return ItemModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to load item: ${response.statusCode}');
}
}
// POST Request
Future<ItemModel> createItem(String title) async {
final uri = Uri.https('api.example.com', '/items');
final response = await client.post(
uri,
headers: <String, String>{'Content-Type': 'application/json; charset=UTF-8'},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
return ItemModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to create item: ${response.statusCode}');
}
}
// DELETE Request
Future<void> deleteItem(int id) async {
final uri = Uri.https('api.example.com', '/items/$id');
final response = await client.delete(
uri,
headers: <String, String>{'Content-Type': 'application/json; charset=UTF-8'},
);
if (response.statusCode != 200) {
throw Exception('Failed to delete item: ${response.statusCode}');
}
}
}4. Implement Background Parsing for Large JSON Arrays
4. 为大型JSON数组实现后台解析
If fetching a large list of objects, move the JSON decoding and mapping to a separate isolate using .
compute()dart
import 'package:flutter/foundation.dart';
// Top-level function required for compute()
List<ItemModel> parseItems(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>).cast<Map<String, Object?>>();
return parsed.map<ItemModel>(ItemModel.fromJson).toList();
}
Future<List<ItemModel>> fetchLargeItemList(http.Client client) async {
final uri = Uri.https('api.example.com', '/items');
final response = await client.get(uri);
if (response.statusCode == 200) {
// Run parseItems in a separate isolate
return compute(parseItems, response.body);
} else {
throw Exception('Failed to load items');
}
}如果要获取大量对象列表,使用将JSON解码和映射逻辑移到单独的isolate中执行。
compute()dart
import 'package:flutter/foundation.dart';
// Top-level function required for compute()
List<ItemModel> parseItems(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>).cast<Map<String, Object?>>();
return parsed.map<ItemModel>(ItemModel.fromJson).toList();
}
Future<List<ItemModel>> fetchLargeItemList(http.Client client) async {
final uri = Uri.https('api.example.com', '/items');
final response = await client.get(uri);
if (response.statusCode == 200) {
// Run parseItems in a separate isolate
return compute(parseItems, response.body);
} else {
throw Exception('Failed to load items');
}
}5. Define Structured JSON Output for AI Models
5. 为AI模型定义结构化JSON输出
When integrating LLMs (like Gemini), enforce reliable JSON output by passing a strict schema in the generation configuration and system instructions.
dart
import 'package:firebase_vertexai/firebase_vertexai.dart';
// Define the expected JSON schema
final _responseSchema = Schema(
SchemaType.object,
properties: {
'width': Schema(SchemaType.integer),
'height': Schema(SchemaType.integer),
'items': Schema(
SchemaType.array,
items: Schema(
SchemaType.object,
properties: {
'id': Schema(SchemaType.integer),
'name': Schema(SchemaType.string),
},
),
),
},
);
// Initialize the model with the schema
final model = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.5-pro',
generationConfig: GenerationConfig(
responseMimeType: 'application/json',
responseSchema: _responseSchema,
),
);
Future<Map<String, dynamic>> analyzeData(String prompt) async {
final content = [Content.text(prompt)];
final response = await model.generateContent(content);
// Safely decode the guaranteed JSON response
return jsonDecode(response.text!) as Map<String, dynamic>;
}集成LLM(例如Gemini)时,通过在生成配置和系统指令中传入严格的schema来确保JSON输出稳定可靠。
dart
import 'package:firebase_vertexai/firebase_vertexai.dart';
// Define the expected JSON schema
final _responseSchema = Schema(
SchemaType.object,
properties: {
'width': Schema(SchemaType.integer),
'height': Schema(SchemaType.integer),
'items': Schema(
SchemaType.array,
items: Schema(
SchemaType.object,
properties: {
'id': Schema(SchemaType.integer),
'name': Schema(SchemaType.string),
},
),
),
},
);
// Initialize the model with the schema
final model = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.5-pro',
generationConfig: GenerationConfig(
responseMimeType: 'application/json',
responseSchema: _responseSchema,
),
);
Future<Map<String, dynamic>> analyzeData(String prompt) async {
final content = [Content.text(prompt)];
final response = await model.generateContent(content);
// Safely decode the guaranteed JSON response
return jsonDecode(response.text!) as Map<String, dynamic>;
}Constraints
约束条件
- Immutable URL Construction: Always use or
Uri.https()to build URLs. Never use raw string concatenation for endpoints with query parameters.Uri.parse() - Error Handling: Never return on a failed network request. Always throw an
nullor a custom error class so the UI (e.g.,Exception) can catch and display the error state viaFutureBuilder.snapshot.hasError - Status Code Validation: Always validate . Use
response.statusCodefor successful GET/PUT/DELETE and200for successful POST.201 - Library Restriction: Do not use
dart:iodirectly for standard cross-platform networking. Always use theHttpClientpackage to ensure web compatibility.http - Isolate Communication: When using , ensure the parsing function is a top-level function or a static method, and only pass primitive values or simple objects (like
compute()response bodies) across the isolate boundary. Do not passStringobjects.http.Response
- URL构造不可变: 始终使用或
Uri.https()构建URL。不要对带查询参数的接口使用原始字符串拼接。Uri.parse() - 错误处理: 网络请求失败时永远不要返回。始终抛出
null或自定义错误类,以便UI(例如Exception)可以通过FutureBuilder捕获并展示错误状态。snapshot.hasError - 状态码校验: 始终校验。GET/PUT/DELETE请求成功使用200状态码,POST请求成功使用201状态码。
response.statusCode - 库使用限制: 标准跨平台网络请求不要直接使用的
dart:io。始终使用HttpClient包以保证web端兼容性。http - Isolate通信: 使用时,确保解析函数是顶层函数或者静态方法,并且仅跨isolate边界传递基础类型值或简单对象(例如
compute()类型的响应体)。不要传递String对象。http.Response