当前位置: 首页 > 知识库问答 >
问题:

前端下载功能怎么实现?

谭伟
2023-07-12

1.项目使用window.open下载时,并没有携带token,容易被盗链下载,况且使用这个api,后端没有办法校验token,把token拼接在url后面还是一样的,前端直接去对应地址取文件,后端并没办法取到token;
2.使用正常的接口下载,blob格式的,由于文件比较大,经常会出现数百M或者上G的大小,在下载过程中,如果页面被刷新也会失败;好像还不能用分片下载,因为文件可能是安装包,有可能会在关键位置切断,导致安装包失效。
就是这样的问题,想咨询下大佬们,还有什么办法处理这个下载吗?
拜谢!!!

共有4个答案

查宜修
2023-07-12

那就用户点击下载,你生成一个一次性的下载地址。可以解决问题嘛?

司寇瑾瑜
2023-07-12

先鉴权,成功后返回文件地址,再 open ?

郑正阳
2023-07-12

点击按钮下载时,先调用接口创建一次性 token,然后 window.open 带上一次性 token 在 url 中去下载文件。这样既能鉴权,又能直接下载。

阎建德
2023-07-12

服务器必须支持 HTTP Range 请求。可以发送一个 HEAD 请求来检查响应头中是不是包含 Accept-Ranges: bytes 来确认:

// 大概思路没有加错误处理和重试逻辑

const url = 'http://example.com/big-file';
const chunkSize = 1024 * 1024 * 10; // 10 MB
let start = 0;
let end = start + chunkSize;
let chunks = [];

fetchSize(url).then(size => {
    downloadChunk(url, start, end);

    function downloadChunk(url, start, end) {
        fetch(url, {
            headers: {
                'Range': `bytes=${start}-${end}`
            }
        })
        .then(response => response.arrayBuffer())
        .then(data => {
            chunks.push(data);

            if (end < size) {
                start += chunkSize;
                end = Math.min(end + chunkSize, size);
                downloadChunk(url, start, end);
            } else {
                const blob = new Blob(chunks);
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = 'big-file';
                a.click();
            }
        });
    }
});

function fetchSize(url) {
    return fetch(url, {
        method: 'HEAD'
    })
    .then(response => {
        const size = response.headers.get('Content-Length');
        return Number(size);
    });
}

用 HTTP Range Requests 来实现分片下载。这种方法可以让客户端请求文件的特定部分,而不是整个文件。这样,就算在下载过程中出现问题,也可以从上次的位置重新开始,而不是从头开始,服务端要支持,如果其中一个文件部分的下载失败,你应该让用户重试下载,直到成功才行,最后你要用一种方法来合并已下载的文件部分。可以用 File API、Blob 对象或者 Stream API 。

 类似资料: