dio_web_adapter 实战指南:让 Dio 在 Web 与 WASM 上无缝运行
dio_web_adapter 实战指南让 Dio 在 Web 与 WASM 上无缝运行【免费下载链接】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/dioDio 是 Dart / Flutter 生态中流行的 HTTP 客户端而dio_web_adapter仓库位于 plugins/web_adapter为 Dio 提供了 Web 平台专用适配器使基于 XHR 的网络请求、文件下载、进度回调与超时控制能够在浏览器中正常工作。读完本文你将掌握如何安装与启用该适配器、理解其核心参数withCredentials、enableCORSWarning的语义、弄清 Web 端文件下载的限制与正确用法并从源码层面理解 CORS 预检、超时判定与取消机制是如何实现的。一、包定位Web 平台能力的默认实现dio_web_adapter的核心定位是把 Dio 在 Web 平台的底层 HTTP 能力从主包中拆分出来独立成包。它通过实现 Dio 的 HttpClientAdapter 接口让同一套 Dio API 在浏览器中正常工作。事实依据该包的 1.0.0 版本变更日志CHANGELOG.md明确记录“Split the Web ability from thepackage:dio”即“将 Web 能力从 package:dio 中拆分”。从包的导出结构看lib/dio_web_adapter.dart它主要导出五部分实现adapter_impl.dartBrowserHttpClientAdapter核心的 HTTP 适配器基于 XMLHttpRequestdio_impl.dartDioForBrowser为 Web 定制的Dio实例覆盖了download等平台相关行为compute_impl.dartWeb 端的compute实现对应 Flutter foundation 的_isolates_web.dartmultipart_file_impl.dartWeb 端不支持MultipartFile.fromPath直接抛出UnsupportedErrorprogress_stream_impl.dart对请求流的进度包装支持取消检查。其中adapter.dart已被标记为Deprecated提示改为导入adapter_impl.dart这是为了避免与package:web等产生命名冲突见 CHANGELOG 2.1.1。二、版本兼容性与安装版本兼容矩阵该适配器与 Dart / Flutter 的兼容关系如下摘自 README.md版本Dart最低Flutter最低1.x2.18.03.3.02.x3.3.03.19.0注意实际可解析到的版本由你使用的 SDK 决定。运行dart pub upgrade或flutter pub upgrade可获取当前 SDK 下最新的可解析版本。2.x 系列之所以要求更高 SDK是因为其引入了 WASMWebAssembly编译目标支持见 CHANGELOG.md 2.0.0。安装步骤虽然包名为dio_web_adapter但它已经被内嵌进package:dio主包正常情况下你无需显式安装直接用dio即可在 Web 端获得浏览器适配器。只有当你有特殊诉求时才需要把dio_web_adapter显式加入 pubspec 依赖dependencies: dio: ^5.8.0 dio_web_adapter: ^2.2.1该包自身的依赖很轻dio、http_parser、meta以及webDart 官方的浏览器互操作库见 pubspec.yaml这也是它能同时支持 JS 与 WASM 编译目标的关键。三、快速上手一分钟跑通 Web 请求官方示例README.md给出了一段最小可用代码import package:dio/dio.dart; // 该导入并非必需甚至可能触发 lint 提示。 // import package:dio_web_adapter/dio_web_adapter.dart; void main() async { final dio Dio(); dio.httpClientAdapter BrowserHttpClientAdapter(withCredentials: true); // 发起请求。 final response await dio.get(https://dart.dev); print(response); }两个关键点无需显式导入默认的Dio()在 Web 平台会自动使用BrowserHttpClientAdapter。显式导入dio_web_adapter只在你需要直接引用适配器类型比如自定义构造参数时才需要。入口选择如果希望显式使用浏览器实现可以像 test/browser_test.dart 那样import package:dio/browser.dart;该入口提供DioForBrowserexample/main.dart 还演示了配合LogInterceptor的使用方式。核心构造参数BrowserHttpClientAdapter的构造函数源码见 lib/src/adapter_impl.dart只有两个参数参数默认值含义withCredentialsfalse跨域请求是否携带凭据如 Cookie、Authorization 头enableCORSWarningtrue当请求不是 CORS “简单请求”、会触发预检OPTIONS时是否打印告警日志withCredentials的逐请求覆盖除了在构造时全局设置你还可以通过Options.extra[withCredentials]为单个请求覆盖该值源码 adapter_impl.dartdio.get( https://api.example.com/me, options: Options(extra: {withCredentials: true}), );enableCORSWarning的语义置为false可以关闭“非简单请求”的每请求告警日志但即便关闭DioException.connectionError中经过 CORS 信息增强的错误原因仍然会输出见 CHANGELOG.md 2.2.1 与 adapter_impl.dart。四、Web 端文件下载Dio.download的完整说明从 2.2.0 起Dio.download在 Web 平台得到支持。其实现位于 lib/src/dio_impl.dart流程是先用 Dio 以字节形式ResponseType.bytes请求完整响应再通过 Blob URL 触发浏览器下载。savePath 的真实语义在 Web 端savePath不是本地文件系统路径而是“建议文件名”。实际保存位置由浏览器决定。_suggestedFilenameFromPathdio_impl.dart会做三件事把反斜杠\归一化为/截取最后一个/之后的部分作为文件名若结果为空回退为download。因此以下调用会建议浏览器以report.pdf为名保存文件await dio.download(https://example.com/report, downloads/report.pdf);返回 Response 不等于写入成功一个容易误解的点download返回的Response仅代表Dio 已经获取到响应字节并派发了浏览器下载动作click它不保证浏览器真的写盘、保留你建议的文件名或跳过用户确认弹窗。是否写盘、是否改名、是否弹窗完全由浏览器、用户设置与页面安全策略控制。平台限制清单务必逐条对照Web 端下载存在以下硬性限制摘自 README.md 的 Downloading files 一节CORS 依然生效请求仍然经由 Dio 发起因此受 CORS 约束协议由浏览器决定网络请求通过 XHR 由浏览器处理HTTP/1.1、HTTP/2、HTTP/3 等协议细节均由浏览器控制整响应先入内存浏览器开始下载前完整响应体已经加载进内存不适合超大文件流式下载依赖标准浏览器 API触发下载依赖浏览器对Blob、URL.createObjectURL与HTMLAnchorElement.download的标准支持FileAccessMode.append不支持会直接抛出UnsupportedError见 dio_impl.dartdeleteOnError无实际作用Web 端没有本地文件可删除自定义lengthHeader不生效进度总大小来自浏览器响应进度事件progress event而非 Content-Length 头。底层下载触发器的实现下载触发逻辑在 lib/src/download_trigger.dart 中通过可注入的函数createObjectUrl、createDownloadAnchor、clickDownloadAnchor等均标注visibleForTesting实现便于浏览器端测试替换。核心_triggerBrowserDownload流程将响应字节转为 JS 类型化数组构造web.Blob可选传入 Content-Type用web.URL.createObjectURL生成blob:URL创建a downloadfilename hrefblob:...并挂载到document.body后再点击部分浏览器对脱离文档的节点更严格在finally中移除锚点并调用revokeObjectURL释放 URL。其中特意改用package:web与dart:js_interop而不是旧的dart:html以保证该路径在 Dart 的 WASM 编译目标下依然可用见 download_trigger.dart 的注释。五、源码深读BrowserHttpClientAdapter 的请求生命周期BrowserHttpClientAdapter.fetchlib/src/adapter_impl.dart是 Web 请求的完整实现下面拆解其关键阶段。1. 建立 XHR 并配置凭据与请求头final xhr web.XMLHttpRequest(); xhrs.add(xhr); xhr ..open(options.method, ${options.uri}) ..responseType arraybuffer;响应类型固定为arraybuffer保证能拿到原始字节withCredentials优先取options.extra[withCredentials]未设置时才回退到构造参数Content-Length头会被移除浏览器不允许手动设置其他请求头通过setRequestHeader写入Iterable值会以,拼接。2. 超时计时connect receive 合并为 XHR timeoutfinal xhrTimeout (connectTimeout receiveTimeout).inMilliseconds; xhr.timeout xhrTimeout;连接超时通过独立的Timer实现只有xhr.readyState HEADERS_RECEIVED即尚未收到响应头时才判定为连接超时收到响应头后的等待交给“接收超时”处理adapter_impl.dart。这样避免了一个请求已完成却仍触发超时的误判。接收超时采用“每次收到进度事件就重置计时器”的滑动窗口策略watchReceiveTimeout在每个 progress 事件到来时重置receiveStopwatch超时后调用xhr.abort()并抛出DioException.receiveTimeoutadapter_impl.dart。3. 发送进度与上传监听器的“副作用”源码中有段注释非常关键adapter_impl.dart只有绝对必要时才注册xhr.upload的 progress 监听器因为一旦注册上传监听器该请求就不再属于 CORS “简单请求”会强制触发预检。具体逻辑仅当requestStream ! null且设置了sendTimeout或onSendProgress时才会注册上传监听器sendTimeout用Stopwatch记录“有数据上传的耗时”超过阈值则抛DioException.sendTimeout若没有请求体却设置了sendTimeout/onSendProgress会输出告警日志因为它们根本无法生效。4. 取消与关闭传入的cancelFuture一旦完成会调用xhr.abort()并抛出DioException.requestCancelledadapter_impl.dartclose(force: true)会 abort 所有活跃的 XHRclose()默认清空追踪集合adapter_impl.dart每个活跃 XHR 被记录在xhrs集合中标注visibleForTesting供测试断言如 test/browser_test.dart 验证withCredentials是否正确传递。5. 错误映射XHR 的onError回调无法提供具体错误信息浏览器 API 限制因此适配器统一抛出DioException.connectionError并附上 CORS 增强说明见下文。XHR 自身的timeout事件则依据readyState区分连接超时与接收超时。六、CORS 预检的智能告警与错误增强跨域请求在浏览器中最大的坑是 CORS 预检。该适配器 2.2.1 起内置了一套“预检原因分析”机制实现集中在 lib/src/cors.dart且全部是纯函数便于脱离浏览器做单元测试。“简单请求”判定标准corsPreflightReason(RequestOptions)会按以下顺序检查任何一条不满足都会返回触发预检的原因方法必须是 CORS 白名单方法GET/HEAD/POSTContent-Type必须是白名单值application/x-www-form-urlencoded、multipart/form-data、text/plain含;charset...等参数时会先截取 MIME 部分再比较请求头必须全部在安全名单内accept、accept-language、content-language、content-type、range。运行时叠加因素collectCorsPreflightReasons在静态分析之外还会叠加两个运行时因素注册了上传进度监听器sendTimeout或onSendProgress存在withCredentials被启用凭据请求一律需要预检。告警与错误增强当检测到预检原因且enableCORSWarning true时适配器会打印告警日志明确指出该请求会触发 OPTIONS 预检若服务器不处理预检则请求必然失败。同时corsEnrichedErrorReason会把预检原因拼进DioException.connectionError的reason中提示开发者检查服务器是否正确响应 CORS 预检——这一增强不管enableCORSWarning如何设置都会输出。实战建议当你发现 Web 请求报DioException.connectionError且附带 “not a CORS simple request” 类说明时优先排查服务器对 OPTIONS 预检的处理而不是怀疑 Dio 本身。七、Web 端的其他实现细节computeWeb 上不存在真正的并发compute_impl.dart对应 Flutter foundation 的_isolates_web.dartWeb 平台没有 isolate因此实现为await null后同步执行回调避免昂贵的计算立即阻塞 UI 帧compute_impl.dart。它本质上只是把执行推迟到下一帧。进度流取消检查的注入点progress_stream_impl.dart的addProgress在数据流中逐块检查options.cancelToken若已取消则把cancelToken.cancelError注入流错误并关闭流progress_stream_impl.dart。MultipartFile文件路径 API 在 Web 不可用multipart_file_impl.dart中MultipartFile.fromPath/fromPathSync直接抛出UnsupportedError提示“MultipartFile 仅在可用 dart:io 的平台受支持”。Web 端应改用字节内容构造MultipartFile.fromBytes浏览器没有本地文件路径概念。八、测试与验证仓库为该适配器配备了浏览器环境测试运行方式遵循 Dart 标准测试约定dart_test.yaml见 plugins/web_adapter/dart_test.yaml。现有用例包括browser_test.dart以TestOn(browser)标注验证withCredentials是否正确透传到 XHRcors_preflight_test.dart对cors.dart的纯函数做单元测试download_test.dart利用download_trigger.dart中可注入的测试钩子验证下载触发逻辑。如果你在使用中遇到问题仓库 README 的呼吁同样适用于你与其坐等修复不如提交一个失败的测试用例failing test case或直接提 PR。总结dio_web_adapter是 Dio 在 Web 与 WASM 平台的“心脏”BrowserHttpClientAdapter基于 XHR 提供请求、超时、进度、取消与 CORS 告警DioForBrowser提供了贴合浏览器语义的download实现compute与progress_stream则补齐了平台差异。理解“savePath 只是建议文件名”“返回 Response 不代表写盘成功”“注册上传监听会破坏简单请求判定”这三个关键点就能在 Web 端写出行为可预期、问题可定位的 Dio 代码。【免费下载链接】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),仅供参考

相关新闻

发offer前必看的5个新手避坑指南

发offer前必看的5个新手避坑指南

发offer前必看的5个新手避坑指南 凌晨两点,你盯着屏幕上的红色报错信息,心里只剩一个念头:这代码到底怎么就挂了?Stack Trace 长得像天书,从最底层的 NullPointerException 到最外层的…

2026/9/23 2:47:17 阅读更多 →
lol大脚下载图解原理与高频面试题实战拆解

lol大脚下载图解原理与高频面试题实战拆解

lol大脚下载图解原理与高频面试题实战拆解 刚把网上扒来的 lol大脚下载 脚本丢进项目,直接 npm run dev 报错,控制台一片红,心累不累?这种“复制代码跑不通”的困境,是不少后端开发在接触非主流开源库时的常态。更尴尬的是,面试被…

2026/9/23 2:46:17 阅读更多 →
GitHub Trending 深度解读:开源生态的技术脉搏与产线拐点

GitHub Trending 深度解读:开源生态的技术脉搏与产线拐点

1. 这份周报不是“榜单”,而是开源生态的脉搏监测仪很多人点开 GitHub Trending 页面,第一反应是“找新项目”——看到 star 增速快的就 clone 下来,顺手点个 star,再发条朋友圈:“又发现一个神器!”但连续…

2026/9/23 2:46:17 阅读更多 →

最新新闻

3个坑搞定名网证书下载,实战项目里不再报错

3个坑搞定名网证书下载,实战项目里不再报错

3个坑搞定名网证书下载,实战项目里不再报错 复制来的代码跑不通,报错信息一堆看不懂,这是很多开发者的噩梦。特别是在处理 名网 相关的业务逻辑,比如证书查询或材料上传时,稍有不慎就会陷入死胡同。…

2026/9/23 4:20:51 阅读更多 →
豆包生成Word文档实战:从Markdown中转稿到Coze自动化全解析

豆包生成Word文档实战:从Markdown中转稿到Coze自动化全解析

1. 先想明白一件事:豆包生成Word文档,本质是两件事很多人上来就问“豆包怎么生成Word文档”,然后期待一句话给个文件、点开就能用。实际我做了一圈下来,先给大家泼盆冷水:豆包这种AI助手,擅长的是内容生成&…

2026/9/23 4:20:51 阅读更多 →
2025年OA系统选型与实施指南:从协同底座到ERP集成避坑

2025年OA系统选型与实施指南:从协同底座到ERP集成避坑

办公自动化这个词,搁十年前,大家脑子里蹦出来的画面多半是“一台服务器、一个IE浏览器、一堆需要装控件的审批表单”。但到了2025年,OA系统早就不是那个只用来走请假流程的电子签章工具了。它正在变成企业里连接人、流程、数据和业务的“协同…

2026/9/23 4:20:51 阅读更多 →
misaya实战搭建保姆级教程:3步搞定报错排查

misaya实战搭建保姆级教程:3步搞定报错排查

misaya实战搭建保姆级教程:3步搞定报错排查 Stack Trace 刷屏,红色警告满天飞,盯着屏幕发呆?别慌。 这份 misaya 保姆级教程,专为解决“报错一堆看不懂”而生。 我们直接上手,从零搭建一个可运行的 misaya…

2026/9/23 4:20:51 阅读更多 →
跑跑卡丁车怎么全屏:3种方案避坑指南,面试不再卡壳

跑跑卡丁车怎么全屏:3种方案避坑指南,面试不再卡壳

跑跑卡丁车怎么全屏:3种方案避坑指南,面试不再卡壳 面试被问“跑跑卡丁车怎么全屏”却答不上来原理,这不仅是尴尬,更是技术底层的缺失。很多人以为这只是个游戏设置问题,实则背后涉及窗口管理、分辨率适配与底层API调用的复杂交互。这份避坑指南,旨…

2026/9/23 4:20:51 阅读更多 →
Easydict 中基于 Agent Skill 的 PR 审查报告结构规范与实现解析

Easydict 中基于 Agent Skill 的 PR 审查报告结构规范与实现解析

Easydict 中基于 Agent Skill 的 PR 审查报告结构规范与实现解析 【免费下载链接】Easydict 一个简洁优雅的词典翻译 macOS App。开箱即用,支持离线 OCR 识别,支持有道词典,🍎 苹果系统词典,🍎 苹果系统翻译…

2026/9/23 4:19:50 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →