前端简单公共下载方法

// 引入所需的依赖项
import Axios from '@/utils/request'; // 替换为你的axios导入路径
import { ElLoading } from 'element-plus'; // 引入element-plus组件库中的loading组件
import FileSaver from 'file-saver';

// 分片大小设置
const CHUNK_SIZE = 52428800;

/**
 * 下载方法
 *
 * @param url 下载的URL地址
 * @param params 参数对象
 * @param filename 文件名
 */
async function download(url: string, params: any, filename: string, contentType?: string) {
    // 初始化loading状态
    const loading = ElLoading.service({
        text: '正在下载...',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.5)',
    });

    try {
        // 使用 Axios 发送请求
        const response = await Axios.request<any>({
            url: url,
            method: 'post',
            responseType: 'arraybuffer',
            data: params,
            headers: {
                'Content-Type': contentType || 'application/octet-stream',
                'Access-Control-Allow-Origin': '*' // 允许跨域请求
            }
        });

        let realFilename = filename; // 默认为前端提供的文件名
        // 解析响应头中的Content-Disposition信息,得到原文件名
        if (response.headers['content-disposition']) {
            let headerFilename = decodeURI(response.headers['content-disposition'].split(';')[1].trim();
            if(headerFilename.startsWith('filename=')){
                realFilename = headerFilename.replace('filename=', '');
            }
        }

        let content;
        // 检查响应体的数据类型,如果是ArrayBuffer则转成blob
        if (response.data instanceof ArrayBuffer) {
            content = new Blob([new Uint8Array(response.data)], { type: contentType });
            let fileSize = content.size;

            // 如果文件超过500M启用分片下载
            if (fileSize > CHUNK_SIZE) {
                let loaded = 0;
                let chunks = Math.ceil(fileSize / CHUNK_SIZE);

                for (let chunkId = 0; chunkId < chunks; chunkId++) {
                    const chunkStart = chunkId * CHUNK_SIZE;
                    const chunkEnd = Math.min(chunkId * CHUNK_SIZE + CHUNK_SIZE - 1, fileSize - 1);
                    const blobPart = content.slice(chunkStart, chunkEnd);
                    const partName = `${realFilename}-${chunkId}.${filename.split('.')[1]}`;

                    // 保存分片文件
                    await FileSaver.saveAs(blobPart, partName);

                    // 更新进度
                    loaded += CHUNK_SIZE;
                    loading.message = `${loaded}/${fileSize} (${(loaded / fileSize * 100).toFixed(2)}%)`;

                    if (chunkId === chunks - 1) {
                        break;
                    }
                    // 暂停一段时间以避免网络拥堵
                    setTimeout(() => {}, 500);
                }
            } else {
                // 如果未超出大小限制,则直接下载
                await FileSaver.saveAs(content, realFilename);
            }
        } else if (response.data instanceof Blob) {
            const file = await response.data.arrayBuffer();
            saveAs(new Blob([file]), filename);
        } else {
            throw new Error("未知文件类型");
        }
    } catch (e) {
        console.error(e);
    } finally {
        // 关闭loading状态提示
        loading.close();
    }
}

我在示例代码中明确写出定义CHUNK_SIZE的地方,你可以根据实际情况自己设定它的值,如CHUNK_SIZE=2097152(大约2MB),它代表着每一片要下载的大小,如果你想要更快的下载速度,可以适当增大此数值,反之减小则会提高对服务器的压力。

优点:

- 合理设置响应头信息后,能够处理不同格式的文件,例如csv,txt,jpg等等。
- 适应各种类型的返回值,包括arrayBuffer或Blob。
- 提供进度指示,能够让用户了解文件下载的进度情况。
- 使用回调函数对下载操作进行监控。

缺点:
- 缺少断点续传功能,若网络故障导致文件下载中断,之前下载过的部分不会被保留,从零开始重新下载。
- 当客户端内存不足以一次性承载整个文件时,可能会影响用户体验。
- 不能利用HTTP分段请求(Range request),避免并发下载导致网络拥塞。
- 对于非常大的文件,可能存在性能问题,尤其是对超大型文件分片处理不够细致。
- 服务器如果没有特别指定 Access-Control-Allow-Origin 头,就不能下载来自其他网站的资源。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值