Dio — 是一个用于 Dart 和 Flutter 的强大 HTTP 客户端,由中国工程师 Wenda Wang 开发。该库提供高级 API,支持拦截器、FormData、文件上传和请求取消。根据 pub.dev, 2025 的数据,Dio 是 Flutter 生态系统中最流行的 HTTP 客户端,在 GitHub 上拥有超过 8000 颗星。
要点
Dio — 是一个用于 Dart 语言的强大 HTTP 客户端库,最广泛地用于 Flutter 应用程序。Dio 提供丰富的 API,支持拦截器、全局配置、转换器、FormData、文件上传和灵活的超时管理,使其成为 Flutter 社区中网络通信的主要选择。
该库由 Wenda Wang 于 2018 年创建,作为内置 dart:io HttpClient 的替代方案,后者缺乏许多现代功能:所有请求的统一配置、拦截器和自动序列化。到 2025 年,Dio 在流行度上已经超过了 Dart 团队的 http 包,根据 pub.dev 的数据,在 Flutter 生态系统的 HTTP 客户端中占据首位。
Dio 支持三种适配器:DartNativeAdapter(Android、iOS、Desktop 上的默认设置)、BrowserAdapter(Web 上)和 IOAdapter。适配器会根据平台自动选择。Dio 还为所有 Flutter 平台提供统一接口 — Android、iOS、Web、macOS、Windows 和 Linux。
Dio 的架构建立在处理器链(handler chain)之上。每个请求都经过一系列拦截器,这些拦截器可以修改请求(InterceptorsWrapper.onRequest)、响应(onResponse)或处理错误(onError)。在拦截器之后,请求到达转换器(Transformer),在发送前转换数据。
Dio 实例通过 BaseOptions 对象进行配置,该对象包含基础 URL、默认标头、超时时间、响应类型(JSON、stream、plain)、查询参数和数据格式。这些设置适用于所有请求,但可以在特定请求中被覆盖。BaseOptions 为整个应用程序提供统一的配置点,简化了 API 端点的更改或全局标头的添加。
Dio 中的每个请求都返回 Response<T>,其中 T — 是经过转换器处理后的数据类型。默认情况下,Dio 会自动将 JSON 响应转换为 Map<String, dynamic>。对于类型化响应,Dio 与序列化包一起使用:json_serializable、freezed 或 built_value。Response 包含 data、headers、statusCode、requestOptions 和附加数据。
基本配置通过 Dio(BaseOptions) 创建。可以为所有请求设置 baseUrl、connectTimeout 和 receiveTimeout、content-type 和 accept 标头,以及 queryParameters。所有这些参数都应用于每个请求,从而消除了代码重复并集中了网络设置的管理。
Dio 支持两种序列化模式:默认 JSON(responseType: ResponseType.json)和流式(ResponseType.stream)。在流式模式下,Response.data 返回一个可以分部分读取的 ResponseBody。这对于大型有效负载文件很方便,当不希望完全加载到内存中时。Plain 模式返回原始字符串,无需自动 JSON 解析。
拦截器 — Dio 用于拦截和修改请求、响应和错误的关键机制。它们完全取代了 OkHttp 的 Interceptor 和 Ktor 的插件,但具有 Dart 特定的 API 和通过 Future 实现的异步支持。拦截器既可以添加到 Dio 的全局配置中,也可以添加到单个请求中。
| 拦截器方法 | 用途 | 使用示例 |
|---|---|---|
| onRequest | 在发送前修改请求 | 添加授权令牌 |
| onResponse | 处理成功响应 | 将数据转换为 DTO 对象 |
| onError | 处理请求错误 | 在 503 时自动重试 |
内置的 LogInterceptor 记录每个请求:方法、URL、标头、正文和执行时间。它有两种模式:compact(每个请求一行)和 full(包含正文的完整信息)。LogInterceptor 在开发过程中特别有用,但建议通过条件导入或全局标志在发布版本中禁用它。
自定义拦截器通过 InterceptorsWrapper 类创建。可以重写一个、两个或全部三个方法(onRequest、onResponse、onError)。Dio 严格按照拦截器添加到 interceptors 列表的顺序执行它们。如果拦截器不调用 handler.next(),则链会中断,响应/错误不会到达应用程序。
在 Dio 中进行身份验证时,使用一个将 Bearer 令牌添加到 Authorization 标头的拦截器。如果服务器返回 401,拦截器在 onError 中尝试通过刷新请求更新令牌,并使用新令牌重复原始请求。这种模式称为令牌刷新拦截器,通过 DioException 实现,检查 response?.statusCode == 401。
Dio 通过 dio_smart_retry 包或自定义的 RetryInterceptor 提供内置的重试逻辑支持。重试对于移动应用程序很重要:当连接断开 2–3 秒时,Dio 会抛出类型为 connectionTimeout 或 connectionError 的 DioException。RetryInterceptor 捕获此异常并以指数延迟(1s、2s、4s)重试请求最多 3 次,从而提高了应用程序在不稳定网络条件下的可靠性。
让我们看一下通过 Dio 的基本 GET 请求。使用 BaseOptions 创建实例,设置基础 URL 和超时。请求通过 get() 方法执行,返回带有 Map 格式数据的 Response。
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['登录'])
对于带有 JSON 正文的 POST 请求,传递一个 Map 对象或自定义 DTO。Dio 通过 jsonEncode 自动将 Map 序列化为 JSON。对于类型化的 DTO,使用 queryParameters 选项、data 字段或自定义 Transformer。
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['id'])
自定义拦截器为每个请求添加 Bearer 令牌。onRequest 方法在发送前触发,修改标头。在 401 响应时,拦截器可以刷新令牌并通过 dio.fetch(requestOptions) 方法重复请求。
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
Dio 简化了通过 FormData 上传文件。要发送文件,从 File、Bytes 或 AssetBundle 创建 MultipartFile。FormData 自动设置 multipart/form-data 标头,具有正确的边界和编码。Dio 通过 onSendProgress 支持上传进度。
对于文件下载,使用 download() 方法,将数据流直接保存到文件。Dio 通过 Range 标头支持断点续传(resume),这对大文件特别有用。下载进度通过 onReceiveProgress 跟踪,允许在 UI 中显示进度条。
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('上传:$progress%')
},
)
// 下载文件
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('下载:${received / total * 100}%')
},
)
错误的错误处理 — 最常见的问题。Dio 在任何问题时都会抛出 DioException(以前是 DioError):无网络、超时、HTTP 4xx/5xx 错误。许多开发人员只捕获通用的 Exception,丢失了有关错误类型及其自定义处理可能性的信息。使用 DioException.type 来确定故障原因。
忽略 CancelToken 会导致请求泄漏。如果用户离开屏幕而请求仍在执行,Dio 会消耗资源,并可能尝试更新已销毁的 State。始终为每个请求创建 CancelToken,并在 dispose() 中取消它。CancelToken 会生成类型为 cancel 的 DioException,需要正确处理。
缺乏临时故障的重试逻辑。在移动设备上,网络经常会暂时不可用。实现一个在超时或 503/502 响应时自动重试请求的拦截器。使用 dio_smart_retry 包中的 RetryInterceptor,或编写一个在尝试之间具有指数延迟的自定义拦截器。
常见问题
Dio 提供拦截器、BaseOptions 全局配置、FormData、上传进度和 CancelToken。Dart 团队的 http 包 — 简约,没有拦截器和全局配置。Dio 用于大型项目,http — 用于简单脚本。
Dio 默认通过 jsonDecode 将 JSON 转换为 Map。对于类型化序列化,使用 json_serializable 或 freezed 包。创建一个自定义拦截器,在 onResponse 中通过 fromJson() 将 response.data 转换为 DTO。
创建一个 CancelToken 并将其传递给请求选项。调用 token.cancel() 会中断请求并引发类型为 cancel 的 DioException。CancelToken 支持同时取消多个请求,这对于在离开屏幕时取消所有请求很方便。
是的,Dio 在所有六个 Flutter 平台上运行:Android、iOS、Web、macOS、Windows 和 Linux。每个平台都使用自适应 HTTP 客户端:DartNativeAdapter(原生平台)和 BrowserAdapter(Web)。所有平台的统一 API — 是 Dio 在 Flutter 项目中的关键优势。
Dio 不会自动管理 cookie。为了支持 cookie,使用 dio_cookie_manager 包与 cookie_jar 一起使用。CookieManager 拦截 Set-Cookie 和 Cookie 标头,并将 cookie 存储在 PersistCookieJar 中,以便在后续对同一域的请求中自动发送。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。