
dio_http2_adapter 演进全景Dio HTTP/2 适配器的连接复用、安全加固与版本能力图谱【免费下载链接】dioA powerful HTTP client for Dart and Flutter, which supports global settings, Interceptors, FormData, aborting and canceling a request, files uploading and downloading, requests timeout, custom adapters, etc.项目地址: https://gitcode.com/gh_mirrors/di/dio导读本文以dio_http2_adapter插件Dio 生态中基于package:http2的 HTTP/2 适配器的 CHANGELOG 为主线结合源码逐项还原其从 0.0.2 到 2.8.0 的能力演进连接复用与超时体系、重定向与敏感头保护、代理隧道、证书校验、回退机制与流式传输修复。读完本文你将掌握该适配器各核心配置参数的语义与默认值、底层调用链以及升级到新版时需要注意的破坏性变更可直接用于实际接入与排障。一、插件定位与版本脉络总览dio_http2_adapter是 Dio 官方插件体系中把HTTP/2 协议能力接入 Dio 的标准方案。它实现了HttpClientAdapter接口通过package:http2提供连接复用connection reuse、头部压缩header compression等 HTTP/2 特性覆盖原生平台IO场景。安装方式是在项目pubspec.yaml的 dependencies 中加入依赖版本以 pubspec.yaml 中version: 2.8.0为准dependencies: dio: ^5.2.0 dio_http2_adapter: ^2.8.0包要求 Dart SDK3.0.0 4.0.0该要求自 2.5.0 起因http2包升级而引入。CHANGELOG 记录了从 2019 年 9 月首个版本到当前 2.8.0 的完整演进核心里程碑如下版本发布时间/阶段关键变化0.0.22019.9.17首个支持 HTTP/2.0 的 Dio HttpAdapter1.0.02019.9.18支持重定向2.0.0-beta2null-safety 时代支持空安全、适配 dio 4.x2.0.0dio 4.0 时代正式支持 dio 4.0.02.1.0dio 5.0 时代面向 dio 5.0 发布新增validateCertificate2.2.0适配器支持代理2.3.0DioError全面替换为DioException2.3.2实现sendTimeout/receiveTimeout忽略Duration.zero2.4.0支持非 TLS 连接请求改进receiveTimeout2.5.0修复流式响应/下载的取消与进度Dart SDK 升至 3.0.0支持 HTTP/1.0 代理新增回退适配器2.6.0缓存连接尊重重定向与 scheme含破坏性变更2.7.0修复缓存键不一致导致的内存泄漏新增handshakeTimeoutResponse.extra提供httpVersion2.7.1修复:authority头生成未包含非默认端口的问题2.8.0Unreleased跨源重定向剥离敏感头修复上传时连接关闭抛StateError二、核心架构Http2Adapter 与 ConnectionManager 的双层设计从源码结构看插件入口 lib/dio_http2_adapter.dart 仅导出src/http2_adapter.dart而后者通过part指令把 client_setting.dart、connection_manager.dart、connection_manager_imp.dart 组合为一个库形成清晰的职责分层Http2Adaptersrc/http2_adapter.dart实现HttpClientAdapter.fetch()负责把 Dio 的RequestOptions翻译为 HTTP/2 帧流并处理响应、重定向、超时ConnectionManager抽象接口src/connection_manager.dart管理可复用连接定义idleTimeout、handshakeTimeout、onClientCreate、proxyConnectedPredicate等配置_ConnectionManager默认实现src/connection_manager_imp.dart维护_transportsMap与_connectFutures两张缓存表实现连接创建、复用、空闲回收ClientSettingsrc/client_setting.dart透传SecurityContext、onBadCertificate、validateCertificate、proxy到 socket 层。最简接入示例与 example/example.dart 一致import package:dio/dio.dart; import package:dio_http2_adapter/dio_http2_adapter.dart; void main() async { final dio Dio() ..options.baseUrl https://pub.dev ..interceptors.add(LogInterceptor()) ..httpClientAdapter Http2Adapter( ConnectionManager(idleTimeout: Duration(seconds: 10)), ); ResponseString response; response await dio.get(/?xx6); for (final e in response.redirects) { print(redirect: ${e.statusCode} ${e.location}); } print(response.data); }三、连接复用缓存键、空闲回收与握手超时3.1 缓存键与内存泄漏修复2.7.0_ConnectionManager用_getCacheKey(uri)生成连接缓存键格式为scheme://host:port例如https://example.com:443。在 2.7.0 之前getConnection()与_connect()两处生成缓存键的方式不一致导致空闲超时清理时_transportsMap.remove()静默失败进而引发连接泄漏。2.7.0 统一了键格式保证存储与移除路径一致src/connection_manager_imp.dart。3.2 idleTimeout非活动持久连接的空闲回收idleTimeout控制非活动持久连接的存活时长默认 15 秒。注意实现中的下限约束_ClientTransportConnectionState.delayClose会把小于 100ms 的超时强制提升为 100mssrc/connection_manager_imp.dart。定时器逻辑会在连接活跃时重置计时仅在连续空闲达到阈值后才关闭连接并移除缓存。3.3 handshakeTimeout握手超时兜底2.7.02.7.0 为ConnectionManager新增handshakeTimeout默认 15 秒作用于SecureSocket.connect与代理场景下SecureSocket.secure返回的握手 Future避免对端握手异常时无限期等待src/connection_manager_imp.dart。注意工厂构造参数实际拼写为handshakeTimout历史拼写保留语义即握手超时ConnectionManager( idleTimeout: const Duration(seconds: 15), handshakeTimout: const Duration(seconds: 15), onClientCreate: (uri, config) { /* 自定义 socket 配置 */ }, )3.4 缓存连接尊重重定向与 scheme2.6.02.6.0 让缓存连接感知重定向结果与协议 schemegetConnection()新增ListRedirectRecord redirects参数在查找/新建连接前先用重定向目标解析出真实 URIsrc/connection_manager_imp.dart从而保证从非 TLS 重定向到 TLS 目标时能正确建立新连接。这是 CHANGELOG 标注的破坏性变更若你在子类中自定义了ConnectionManager需要同步把getConnection签名改为携带redirects参数详见 doc/migration_guide.mdFutureClientTransportConnection getConnection( RequestOptions options, ListRedirectRecord redirects, );四、重定向从支持到跨源敏感头保护1.0.0起支持重定向。Http2Adapter内核对 301/302/303/307/308 状态码、在followRedirects maxRedirects 0时自动跟进并在无location头时抛出connectionErrorsrc/http2_adapter.dart。重定向次数通过maxRedirects - 1递归递减控制。2.7.1修复:authority头生成未包含非默认端口的问题保证代理或非标准端口场景下 Host 协商正确。2.8.0新增跨源敏感头保护适配器维护_sensitiveRedirectHeaders集合authorization、www-authenticate、cookie、cookie2、proxy-authorization、proxy-authenticate。当重定向目标与当前请求不同源scheme、host、port 任一不同时会从重定向请求中移除这些敏感头防止凭据泄露到跨源服务器src/http2_adapter.dart 与 src/http2_adapter.dart。同源判定由_isSameOrigin实现。五、超时体系connect、send、receive 三态实现2.3.2为适配器实现了sendTimeout与receiveTimeout并忽略Duration.zero超时零值视为未设置同时修复requestStream null时重定向不生效的问题。2.4.0改进receiveTimeout实现使其更精确地作用于响应头到达阶段。2.7.0通过handshakeTimeout补全了握手阶段的兜底。从源码看src/http2_adapter.dart发送超时对“请求体流式上传完成”这一 Future 施加timeout超时后关闭出站消息流并抛出DioException.sendTimeout接收超时则对“响应头到达”的 Future 施加timeout超时后取消订阅、关闭响应流并抛出DioException.receiveTimeoutsrc/http2_adapter.dart。连接阶段超时则由connectTimeout透传至Socket.connect/SecureSocket.connect的timeout参数并区分“超时”与“普通连接错误”抛错。六、证书校验ClientSetting 的三个层级2.1.0 为ClientSetting新增validateCertificate与 Dio 5.0 一起发布。ClientSetting提供三套证书处理入口src/client_setting.dartcontextSecurityContext决定使用哪些受信任根证书做链校验onBadCertificate不可验证证书的可选处理回调返回true则放行该SecureSocket连接validateCertificate对叶子证书做最终裁决仅在链校验通过后才被调用返回false时抛出DioExceptionType.badCertificate。忽略证书的典型用法来自 README.mdfinal dio Dio() ..httpClientAdapter Http2Adapter( ConnectionManager( idleTimeout: Duration(seconds: 10), onClientCreate: (_, config) config.onBadCertificate (_) true, ), );七、代理支持CONNECT 隧道与 HTTP/1.x 代理2.2.0起支持代理。代理通过ClientSetting.proxy设置用Uri完整表达 scheme、地址、端口及可选凭据。2.5.0允许连接代理时使用 HTTP/1.0放宽了对代理协议版本的限定。底层实现src/connection_manager_imp.dart先与代理地址建立 TCP 连接发送CONNECT host:port HTTP/1.1请求带Host头与Proxy-Authorization: Basic ...随后用SecureSocket.secure在该隧道上做 TLS 握手并协商h2。代理握手结果通过proxyConnectedPredicate判定默认实现defaultProxyConnectedPredicate接受状态行匹配HTTP/1.x 200的响应src/connection_manager.dart。final dio Dio() ..httpClientAdapter Http2Adapter( ConnectionManager( idleTimeout: Duration(seconds: 10), onClientCreate: (_, config) config.proxy Uri.parse(http://login:password192.168.0.1:8888), ), );八、回退机制与异常体系HTTP/2 不可用时的兜底路径2.5.0引入回退能力当目标服务器未协商出h2协议时_createSocket会通过_throwIfH2NotSelected抛出DioH2NotSupportedExceptionsrc/connection_manager_imp.dartHttp2Adapter.fetch捕获后若配置了onNotSupported回调则交由回调处理否则交给fallbackAdapter默认IOHttpClientAdapter发起普通 HTTP/1.x 请求src/http2_adapter.dart。2.5.1把握手/建连阶段的SocketException统一包装为DioExceptionType.connectionError消息含timed out的包装为connectionTimeout而不是笼统的unknown便于调用方精确分类src/http2_adapter.dart。2.3.0起全面用DioException替代DioError与 dio 5.x 的异常体系对齐。九、流式上传下载、取消与进度修复该插件对流式场景的修复贯穿多个版本是排障时最容易踩坑的部分2.5.0修复流式响应与下载的取消和进度问题取消时同步关闭出站消息流、终止响应订阅。2.5.2移除Http2Adapter中不合理的客户端流终止逻辑此前在请求体结束后会提前关闭出站流导致部分场景异常。2.5.3改进CancelToken场景下的内存分配_connectFutures中失败后及时移除缓存项避免悬挂 Future 长期占用。2.8.0修复上传时连接提前关闭导致的StateError向出站消息队列添加DataStreamMessage时用 try/catch 捕获StateError并优雅终止请求流src/http2_adapter.dart。2.8.0 同时把 HTTP 集成测试与证书固定测试切换到配置的测试服务器上运行。此外2.7.0 起在ResponseBody.extra中提供httpVersion值如2.0调用方可通过response.extra[HttpClientAdapter.extraKeyHttpVersion]感知实际协商到的协议版本src/http2_adapter.dart。十、与 Dio 主版本协同及升级检查清单该插件版本与 Dio 主版本强绑定升级前请对照插件版本对应 Dio关键前提2.0.0-beta2 / 2.0.0dio 4.x空安全2.1.0 及以上dio 5.xDioException取代DioError2.5.0 及以上dio 5.xDart SDK ≥ 3.0.0升级到 2.6.0 时若自定义过ConnectionManager子类必须为getConnection增加redirects参数见 doc/migration_guide.md升级到 2.8.0 后跨源重定向将默认剥离Authorization、Cookie等敏感头若你的业务确实依赖跨源携带这些头需要在重定向前自行处理例如调整重定向选项或预解析 location。其余版本均以缺陷修复与内部实现优化为主可在保持 dio 5.x 的前提下平滑升级。结语纵观 CHANGELOG 与源码dio_http2_adapter的演进脉络清晰可循早期版本补齐 HTTP/2 基础能力连接复用、重定向、空安全中期围绕 dio 5.x 完善异常体系与超时/代理/证书能力近期则聚焦可靠性与安全性缓存键修复防泄漏、握手超时兜底、流式上传异常修复、跨源敏感头剥离。理解这些版本背后的实现细节不仅能帮助你在接入时选对配置idleTimeout、handshakeTimeout、onClientCreate、onNotSupported等也能在遇到“连接泄漏”“上传抛 StateError”“重定向丢失 Cookie”等问题时快速定位到对应的修复版本与底层调用链。【免费下载链接】dioA powerful HTTP client for Dart and Flutter, which supports global settings, Interceptors, FormData, aborting and canceling a request, files uploading and downloading, requests timeout, custom adapters, etc.项目地址: https://gitcode.com/gh_mirrors/di/dio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考