flutter-handling-http-and-json
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHandling HTTP and JSON
处理HTTP与JSON
Contents
目录
Core Guidelines
核心准则
- Enforce HTTPS: iOS and Android disable cleartext (HTTP) connections by default. Always use HTTPS endpoints. If HTTP is strictly required for debugging, configure (Android) and
network_security_config.xml(iOS).NSAppTransportSecurity - Construct URIs Safely: Always use to safely build URLs. This handles encoding and formatting reliably, preventing string concatenation errors.
Uri.https(authority, unencodedPath, [queryParameters]) - Handle Status Codes: Always validate the . Treat
http.Response.statusCode(OK) and200(Created) as success. Throw explicit exceptions for other codes (do not return201).null - Prevent UI Jank: Move expensive JSON parsing operations (taking >16ms) to a background isolate using the function.
compute() - Structured AI Output: When integrating LLMs, enforce reliable JSON output by specifying a strict JSON schema in the system prompt and setting the response MIME type to .
application/json
- 强制使用HTTPS:iOS和Android默认禁用明文(HTTP)连接。请始终使用HTTPS端点。如果调试时确实需要使用HTTP,请配置Android的和iOS的
network_security_config.xml。NSAppTransportSecurity - 安全构造URI:请始终使用来安全构建URL。它能可靠地处理编码和格式化,避免字符串拼接错误。
Uri.https(authority, unencodedPath, [queryParameters]) - 处理状态码:务必验证。将
http.Response.statusCode(成功)和200(已创建)视为请求成功。对于其他状态码,抛出明确的异常(不要返回201)。null - 避免UI卡顿:使用函数将耗时的JSON解析操作(超过16ms)移至后台隔离线程执行。
compute() - 结构化AI输出:集成大语言模型(LLM)时,通过在系统提示中指定严格的JSON模式,并将响应MIME类型设置为,确保输出可靠的JSON格式。
application/json
Workflow: Executing HTTP Operations
工作流:执行HTTP操作
Use this workflow to implement network requests using the package.
httpTask Progress:
- Add the package to
http.pubspec.yaml - Configure platform permissions (Internet permission in and macOS
AndroidManifest.xml)..entitlements - Construct the target .
Uri - Execute the HTTP method.
- Validate the response and parse the JSON payload.
Conditional Implementation:
- If fetching data (GET): Use .
http.get(uri) - If sending new data (POST): Use . Ensure
http.post(uri, headers: {...}, body: jsonEncode(data))isContent-Type.application/json; charset=UTF-8 - If updating data (PUT): Use .
http.put(uri, headers: {...}, body: jsonEncode(data)) - If deleting data (DELETE): Use .
http.delete(uri, headers: {...})
Feedback Loop: Validation & Error Handling
- Run the HTTP request.
- Check .
response.statusCode - If or
200, call201and map to a Dart object.jsonDecode(response.body) - If any other code, throw an .
Exception('Failed to load/update/delete resource') - Review errors -> fix endpoint, headers, or payload structure.
使用此工作流,基于包实现网络请求。
http任务进度:
- 在中添加
pubspec.yaml包。http - 配置平台权限(AndroidManifest.xml中的互联网权限,以及macOS的权限)。
.entitlements - 构造目标。
Uri - 执行HTTP方法。
- 验证响应并解析JSON负载。
条件化实现:
- 如果是获取数据(GET):使用。
http.get(uri) - 如果是发送新数据(POST):使用。确保
http.post(uri, headers: {...}, body: jsonEncode(data))设置为Content-Type。application/json; charset=UTF-8 - 如果是更新数据(PUT):使用。
http.put(uri, headers: {...}, body: jsonEncode(data)) - 如果是删除数据(DELETE):使用。
http.delete(uri, headers: {...})
反馈循环:验证与错误处理
- 执行HTTP请求。
- 检查。
response.statusCode - 如果状态码为200或201,调用并映射为Dart对象。
jsonDecode(response.body) - 如果是其他状态码,抛出(加载/更新/删除资源失败)。
Exception('Failed to load/update/delete resource') - 排查错误 -> 修复端点、请求头或负载结构。
Workflow: Implementing JSON Serialization
工作流:实现JSON序列化
Choose the serialization strategy based on project complexity.
Conditional Implementation:
- If building a small prototype or simple models: Use manual serialization with .
dart:convert - If building a production app with complex/nested models: Use code generation with .
json_serializable
根据项目复杂度选择序列化策略。
条件化实现:
- 如果是构建小型原型或简单模型:使用进行手动序列化。
dart:convert - 如果是构建包含复杂/嵌套模型的生产应用:使用进行代码生成。
json_serializable
Manual Serialization Setup
手动序列化设置
Task Progress:
- Import .
dart:convert - Define the Model class with properties.
final - Implement a constructor.
factory Model.fromJson(Map<String, dynamic> json) - Implement a method.
Map<String, dynamic> toJson()
任务进度:
- 导入。
dart:convert - 定义带有属性的Model类。
final - 实现构造函数。
factory Model.fromJson(Map<String, dynamic> json) - 实现方法。
Map<String, dynamic> toJson()
Code Generation Setup (json_serializable
)
json_serializable代码生成设置(json_serializable
)
json_serializableTask Progress:
- Add dependencies: and
flutter pub add json_annotation.flutter pub add -d build_runner json_serializable - Import in the model file.
json_annotation.dart - Add the directive.
part 'model_name.g.dart'; - Annotate the class with . Use
@JsonSerializable()if the class contains nested models.explicitToJson: true - Define the factory and
fromJsonmethod delegating to the generated functions.toJson - Run the generator: .
dart run build_runner build --delete-conflicting-outputs
任务进度:
- 添加依赖:和
flutter pub add json_annotation。flutter pub add -d build_runner json_serializable - 在模型文件中导入。
json_annotation.dart - 添加指令。
part 'model_name.g.dart'; - 使用注解类。如果类包含嵌套模型,设置
@JsonSerializable()。explicitToJson: true - 定义工厂方法和
fromJson方法,委托给生成的函数。toJson - 运行生成器:。
dart run build_runner build --delete-conflicting-outputs
Workflow: Parsing Large JSON in the Background
工作流:在后台解析大型JSON
Use this workflow to prevent frame drops when parsing large JSON payloads (e.g., lists of 1000+ items).
Task Progress:
- Create a top-level or static function that takes a (the response body) and returns the parsed Dart object (e.g.,
String).List<Model> - Inside the function, call and map the results to the Model class.
jsonDecode - In the HTTP fetch method, pass the top-level parsing function and the to Flutter's
response.bodyfunction.compute()
当解析大型JSON负载(例如包含1000+条目的列表)时,使用此工作流防止界面掉帧。
任务进度:
- 创建一个顶级或静态函数,接收类型的响应体,并返回解析后的Dart对象(例如
String)。List<Model> - 在函数内部,调用并将结果映射到Model类。
jsonDecode - 在HTTP获取方法中,将顶级解析函数和传递给Flutter的
response.body函数。compute()
Examples
示例
Example 1: HTTP GET with Manual Serialization
示例1:手动序列化的HTTP GET请求
dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
Future<Album> fetchAlbum() async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums/1');
final response = await http.get(uri);
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to load album');
}
}dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
Future<Album> fetchAlbum() async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums/1');
final response = await http.get(uri);
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to load album');
}
}Example 2: HTTP POST Request
示例2:HTTP POST请求
dart
Future<Album> createAlbum(String title) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums');
final response = await http.post(
uri,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to create album.');
}
}dart
Future<Album> createAlbum(String title) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums');
final response = await http.post(
uri,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to create album.');
}
}Example 3: Background Parsing with compute
compute示例3:使用compute
进行后台解析
computedart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// 1. Top-level function for parsing
List<Photo> parsePhotos(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>)
.cast<Map<String, Object?>>();
return parsed.map<Photo>(Photo.fromJson).toList();
}
// 2. Fetch function using compute
Future<List<Photo>> fetchPhotos(http.Client client) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/photos');
final response = await client.get(uri);
if (response.statusCode == 200) {
// Run parsePhotos in a separate isolate
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load photos');
}
}dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// 1. 用于解析的顶级函数
List<Photo> parsePhotos(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>)
.cast<Map<String, Object?>>();
return parsed.map<Photo>(Photo.fromJson).toList();
}
// 2. 使用compute的获取函数
Future<List<Photo>> fetchPhotos(http.Client client) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/photos');
final response = await client.get(uri);
if (response.statusCode == 200) {
// 在独立隔离线程中运行parsePhotos
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load photos');
}
}Example 4: Code Generation (json_serializable
)
json_serializable示例4:代码生成(json_serializable
)
json_serializabledart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
(explicitToJson: true)
class User {
final String name;
(name: 'registration_date_millis')
final int registrationDateMillis;
User(this.name, this.registrationDateMillis);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
(explicitToJson: true)
class User {
final String name;
(name: 'registration_date_millis')
final int registrationDateMillis;
User(this.name, this.registrationDateMillis);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}