Flutter Web公网图片可展示但下载报XMLHttpRequest错误求生产环境方案
Flutter Web生产环境图片下载XMLHttpRequest错误解决方案
问题描述
Flutter Web环境中,公网图片可正常展示,但点击下载时触发如下错误:
Error: XMLHttpRequest error. dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 299:10 createErrorWithStack dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 355:28 _throw dart-sdk/lib/core/errors.dart 120:5 throwWithStackTrace dart-sdk/lib/async/zone.dart 1385:11 callback dart-sdk/lib/async/schedule_microtask.dart 40:11 _microtaskLoop dart-sdk/lib/async/schedule_microtask.dart 49:5 _startMicrotaskLoop dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15 <fn>
当前使用image_downloader_web: ^2.0.2插件,Web端下载代码如下:
if (kIsWeb) { await WebImageDownloader.downloadImageFromWeb( "$image_url", imageQuality: 100, name: 'image', ); }
仅修改Flutter文件只能在测试环境实现图片下载,现寻求生产环境可用的解决方案。另外,Android端使用以下代码可正常下载该图片:
var response = await Dio().get( "$image", options: Options(responseType: ResponseType.bytes) ); final result = await ImageGallerySaver.saveImage( Uint8List.fromList(response.data), quality: 100, name:"image" );
解决方案
方案1:浏览器原生API实现下载(绕过CORS限制)
直接用浏览器a标签逻辑完成下载,避免插件的XMLHttpRequest跨域限制,和Android端逻辑统一,生产环境稳定:
import 'dart:html' as html; import 'dart:typed_data'; import 'package:dio/dio.dart'; Future<void> downloadImageWeb(String imageUrl) async { // 用Dio获取图片字节数据 final response = await Dio().get( imageUrl, options: Options(responseType: ResponseType.bytes), ); final Uint8List bytes = response.data; // 转换为Blob对象并生成临时URL final html.Blob blob = html.Blob([bytes]); final String url = html.Url.createObjectUrlFromBlob(blob); // 创建隐藏a标签触发下载 final html.AnchorElement anchor = html.AnchorElement(href: url) ..setAttribute("download", "image.jpg") ..style.display = "none"; html.document.body?.children.add(anchor); anchor.click(); // 清理资源 html.document.body?.children.remove(anchor); html.Url.revokeObjectUrl(url); }
方案2:配置服务器CORS策略
如果能控制图片所在服务器,添加以下CORS响应头,允许你的Web域名跨域访问:
Access-Control-Allow-Origin: 你的Web域名(生产环境避免用*)Access-Control-Allow-Methods: GET, HEADAccess-Control-Allow-Headers: Range
配置完成后,原插件的下载代码可直接在生产环境使用。
方案3:代理服务器中转请求
无法修改目标服务器时,搭建代理服务器转发图片请求,同时配置代理服务器允许跨域:
示例Node.js代理代码:
const express = require('express'); const axios = require('axios'); const app = express(); app.get('/proxy-image', async (req, res) => { const imageUrl = req.query.url; try { const response = await axios.get(imageUrl, { responseType: 'stream' }); res.setHeader('Access-Control-Allow-Origin', '你的Web域名'); response.data.pipe(res); } catch (err) { res.status(500).send('下载失败'); } }); app.listen(3000, () => console.log('代理服务器运行在3000端口'));
客户端修改为请求代理地址:
await WebImageDownloader.downloadImageFromWeb( "http://你的代理服务器地址/proxy-image?url=$image_url", imageQuality: 100, name: 'image', );
方案选择建议
- 优先选方案1:无需服务器改动,客户端独立实现,适配性强
- 能控制服务器选方案2:代码无改动,最简洁
- 无法控制服务器选方案3:适合依赖原插件功能的场景
内容的提问来源于stack exchange,提问作者Sarthakpandit
相关产品推荐
相关产品推荐

