You need to enable JavaScript to run this app. 为什么使用fetch时await未等待APK下载完成就执行文件写入
优惠活动
大模型
产品
解决方案
定价
更多

为什么使用fetch时await未等待APK下载完成就执行文件写入

问题根因
  • 代码中使用的mode: 'no-cors'从一开始就选错了模式。这个模式的设计场景是加载不需要读取内容的跨域静态资源(比如埋点请求、像素追踪),根本不适合下载需要读取内容存本地的APK。这种模式下fetch的Promise刚拿到响应头、根本等不及把11MB的文件全部传输完成就直接resolve,后续调用blob()拿到的是残缺的、未传完的内容,这就是你感知到“await没生效、传输中就开始保存”的核心原因。
  • saveApk方法中调用this.file.writeFile()时没有加await。写文件是异步IO操作,这个调用发出后流程会直接向下执行,既捕获不到写入错误,也会因为没有等待流程完成,出现提前触发后续逻辑的错觉。
  • 没有对下载完成的blob做有效性校验,11MB的APK一旦出现传输截断,会直接把不完整的内容写入本地,生成无法安装的损坏包。
  • 原代码的catch块只打日志不向上抛错误,一旦下载请求异常,上层会拿到值为undefined的blob,后续流程根本感知不到异常,排查时很容易被误导。
修正后可运行代码
async saveApk(){
  try {
    const downloadedBlob = await this.download(this.url);
    // 基础完整性校验,避免残缺内容写入本地
    if (downloadedBlob.size < 10 * 1024 * 1024) {
      throw new Error('下载的APK内容不完整');
    }
    const apkBlob = new Blob([downloadedBlob], {type:'application/vnd.android.package-archive'});
    // 必须await写文件的Promise,等待IO完成
    await this.file.writeFile(this.file.cacheDirectory, 'test.apk', apkBlob, { replace: true});
  } catch (e) {
    console.error('APK下载保存失败', e);
  }
}

async download(url){
  try {
    const request = new Request(url, {
      method: 'GET',
      // 移除no-cors模式,Ionic WebView的跨域限制可通过配置放开,无需靠no-cors妥协
      credentials: 'include'
    });
    const response = await fetch(request);
    if (!response.ok) {
      throw new Error(`下载请求失败,状态码:${response.status}`);
    }
    const data = await response.blob();
    return data;
  } catch (err) {
    console.error('fetch请求异常', err);
    throw err; // 向上抛出错误,不要静默吞掉异常
  }
}
注意事项
  • 如果WebView确实存在跨域拦截,不要硬靠no-cors模式绕过,可在Ionic的WebView配置中放开跨域访问限制,从根源保证fetch能拿到完整的二进制响应。
  • 后续下载更大体积的文件时,可以用response.body.getReader()做流式分块写入,不要等整个Blob在内存中生成完再落盘,避免WebView内存占用过高。
  • 排查时不要靠“await没生效”的模糊感知判断问题,可在每个异步节点打印当前blob的实际大小,就能直观看到哪个环节提前返回了不完整的数据。

内容的提问来源于stack exchange,提问作者Daniel Corbalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 23:36:01