网页端如何实现下载容量比较大的资源?

目前需要下载一个比较大的资源,资源大小可能比机器的内存还要大,而且提供资源的服务器无法被控制。

因为资源需要提供用户凭证(请求字段中的 token)才能获取,使用 a 标签发现不能带上 token。所以试用了 fetch 的方式,但是 fetch 方式要触发下载可能需要把整个资源先下载到内存中,然后再通过 a 标签触发下载到磁盘。这种方式可能会导致内存不够,而且效率上也很低。

请问一下有什么其他方法能更好地下载这个资源,不限于使用浏览器扩展

服务器是第三方服务器,所以无法修改认证的方式,比如把 token 放在 query 或者是 cookie 中,因为这些方式需要服务器配合。

目前尝试一下使用 File System API,使用 fetch 的 body 流,获取一点数据就通过 FileSystemWritableFileStream 写入到系统文件中,主要看一下能否实现断点续传的功能

阅读 483
avatarAI BotBETA

回答

在网页端下载大容量资源时,特别是在资源大小可能超过机器内存且服务器无法被控制的情况下,你可以考虑以下几种方法来实现高效下载:

  1. 使用 XMLHttpRequest 和 Blob 对象

    • 使用 XMLHttpRequest 来发起带有 token 的请求。
    • 在接收到数据时,将数据以流的形式写入一个 Blob 对象,而不是一次性加载到内存中。
    • 当所有数据接收完毕后,可以创建一个带有下载链接的 a 标签,并将 Blob 对象作为其下载内容。

    示例代码:

    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'URL_OF_RESOURCE', true);
    xhr.setRequestHeader('Authorization', 'Bearer ' + token); // 设置 token
    xhr.responseType = 'blob'; // 指示响应类型为 Blob
    
    xhr.onload = function () {
        if (xhr.status === 200) {
            const blob = xhr.response;
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = 'filename.ext'; // 设置下载文件名
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
        } else {
            console.error('Failed to download resource:', xhr.statusText);
        }
    };
    
    xhr.onerror = function () {
        console.error('Error downloading resource');
    };
    
    xhr.send();
  2. 使用 fetch API 的流式处理

    • 虽然你提到 fetch 可能会导致内存问题,但如果你正确地使用 ReadableStreamWritableStream(如通过 Streams API),你可以实现逐块读取和写入数据,从而避免内存溢出。
    • 这通常涉及到将响应体转换为可读流,并使用 WritableStream 将数据写入文件系统(在现代浏览器中,这可能需要一些额外的用户交互或使用浏览器扩展来实现文件系统访问)。

    由于浏览器环境对文件系统访问的限制,这种方法在实际应用中可能不如第一种方法普遍适用。

  3. 使用第三方库

    • 有些第三方库(如 axiossuperagent)提供了更高级的 API 来处理 HTTP 请求,并可能支持流式下载。
    • 这些库通常提供了更灵活的请求配置选项,包括设置自定义头部(如 token)。
  4. 浏览器扩展或应用

    • 如果上述方法不可行或不够方便,你可以考虑开发一个浏览器扩展或应用来管理下载。
    • 浏览器扩展可以拥有更多的权限来访问文件系统,并允许你以更灵活的方式处理下载。

综上所述,使用 XMLHttpRequestBlob 对象的方法可能是最直接且广泛适用的解决方案,特别是在处理大容量资源下载时。

3 个回答

把 token 放到 query 里,服务器上校验 query 即可,不一定非要用 fetch。

如果担心 token 放到 query 里不安全,也可以写个函数,拿长期 token 生成一次性的临时 token,下载启动之后就作废即可。

后端生成一个临时的不需要 token 的链接用来下载。

但是生成这个链接需要校验 token。前端用 fetch 携带 token 获取这个临时链接,然后设置 a 标签的 href。

回答:浏览器资源下载,较好的方法都是通过a链接的href属性来触发,它会采用缓存的思路,逐步写入文件内容,所以就算文件较大,也不会出现占用资源过多的情况,当然它也有缺点,例如断点续传效果支持性不好,下载速度较慢等;你这里添加了安全认证,a链接是可以携带cookie信息的,你可以利用这一点来生成临时的口令,然后下载后将cookie对应的口令删掉,这样可以做到相对安全;如果后台支持分片下载,也可以采用分片下载的思路来进行,就是会复杂一些,然后对资源占用较多;可以参考这个demo:https://gitee.com/anxwefndu/online-cloud-storage-system.git

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏