Featured image of post 远程URL文件批量下载打包的方法

远程URL文件批量下载打包的方法

通过前端批量下载大文件

开始

  • 最近代码重构遇到了一个问题,需要把OSS 上的一批图片打包下载
  • 旧服务器的硬盘是直接挂载OSS,所以直接调的Linux系统命令复制打包,所以速度比较快。新服务器重构代码行不通,这样做也不好
  • 查阅OSS并没有提供相关API(七牛支持)

解决方法:

  • PASS掉 PHP后台fetch图片到内存然后进行打包输出给前端(图片有ai,psd内存撑不住)
  • PASS掉 PHP后台fetch图片到服务器硬盘,然后进行打包输出一个临时链接给前端(同上,文件太大,导致fetch时间和打包的时间太久)
  • JS 尝试通过前端请求后端,后端返回文件信息,然后前端异步请求所有文件,最后在前端打包下载

前提

想法很好,并且已经有人这样做了,我们只用考虑按照别人的做法坐下去
前端打包有两个前提:

  1. 跨域问题,需要运维在OSS或者下载的资源服务器设置允许跨域
  2. CDN问题,让运维配置一个新域名不要走CDN(如没使用CDN可忽略)

步骤

// 引入文件
<script type="text/javascript" src="/xxx/jszip.min.js"></script>
<script type="text/javascript" src="/xxx/jszip-utils.min.js"></script>
<!--[if IE]>
<script type="text/javascript" src="/xxx/jszip-utils-ie.min.js"></script>
<![endif]-->
<script>
let total = 0;
let progress = 0;

// 可通过按钮或者其它事件触发
$.get('/urls', function(res) {

    // 假设 res.data 是后端返回的一组远程数据对象
    // {url: 'x.jpg', filename: 'xx.jpg', path: 'xxxx'}

    total = res.data.length;
    if (total === 0) {
        console.error('图集无图片可下载');
        return;
    }

    let zip = new JSZip();
    // map 存储 folder 对象
    let folderMap = {};
    // 遍历所有后端返回的 urls
    res.data.map(function (data) {

        // 获取远程资源数据
        JSZipUtils.getBinaryContent(
            data.url,
            function (err, binData) {

                ++ progress;

                if (err && progress < total) {
                    console.log(err);
                    return;
                }

                // 第一次实例化 folder 对象
                if (! folderMap[data.path]) {
                    folderMap[data.path] = zip.folder(data.path);
                }

                let pf = folderMap[data.path];
                // 第三个参数必须设置,否则下载的文件将产生错误
                pf.file(data.filename, binData, {binary: true});

                if (progress === total) {

                    console.log('请稍等,数据打包中');
                    zip.generateAsync({type:"blob"}).then(function(content) {

                        // 下载文件
                        const link = document.createElement('a');
                        link.href = window.URL.createObjectURL(content);
                        link.download = 'data.zip';
                        link.click();
                        document.body.removeChild(link);
                    });
                }


            }
        );
    })
})
</script>

完成之后,发现效果还不错。速度也比后端的来的块。毕竟不经过后端。而且可以多个请求异步处理。