icon

新闻 资讯

News and information

前端Javascript下载文件

发布时间:2021-01-25

项目开发中经常会有导出数据到Excel类似的需求,或者是下载文档的需求。最简单的下载方式是直接请求服务端文件地址,通过浏览器http实现文件下载。但是开发中,由于项目需求,你要下载的文件地址不会暴露给用户,而且需要鉴权才允许下载文件,这个时候我们该怎么处理呢?


应用场景

文件地址没有暴露在公网,无法通过文件url直接下载文件。


要下载的文件内容可能是根据用户请求动态生成的,如导出Excel数据表。


后端需要鉴权验证用户提交的下载请求。


实现流程

前端发送get/post请求,携带header信息(如token用于鉴权),后端接收请求,完成鉴权后,读取对应的文件,将文件以文件流的形式发送给浏览器,浏览器完成下载。


我们把这种方式叫做Blob方式下载。


Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。


前端代码

我们以下载图片为例,使用axios来做前端异步下载请求。


get方式请求中,我们要在header中携带token信息,这个token就是你在系统中的通行证,一般是你在登录的时候后端给你的token,相当于一张游乐场的门票,有了这张门票,你可以到游乐场里游玩任意项目,只是在游玩时给工作人员出示这个token门票就可以了。


并且还要告诉后端,需要后端返回blob类型的数据,使用responseType: 'blob'。


axios.get('http://localhost:9998/download.php', {

headers: {

'token': '1234512345'

},

responseType: 'blob'

}).then((res) => {

if (res.data.type !== 'application/octet-stream') {

alert('下载失败');

return false;

}


const blob = new Blob([res.data], {

type: 'image/jpeg'

})


let a = document.createElement("a");

let objUrl = URL.createObjectURL(blob);

a.href="pckVsm;

a.download = 'abc.jpg' //文件名

a.click();

URL.revokeObjectURL(objUrl); // 释放内存

document.body.removeChild(a);

alert('下载成功');

}).catch((err) => {

console.log(err);

alert('下载失败');

});

我们拿到后端返回的blob对象数据后,在页面上创建一个a标签,然后模拟点击事件,将blob数据保存成文件。注意URL.createObjectURL(blob)将blob保存在内存中,下载完后记得释放内存哦。


后端代码

在后端download.php中,先要在header中允许接收token,如果是跨域请求那就应该还要设置header("Access-Control-Allow-Origin: *");允许跨域请求。


header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, token");


$token = isset($_SERVER['HTTP_TOKEN']) ? $_SERVER['HTTP_TOKEN'] : '';

if ($token != '1234512345') {

echo 'error.';

exit;

}


$file = '../file/cc.jpg';

if (!file_exists($file)) {

header('HTTP/1.1 404 Not Found');

exit;

}


$fileSize = filesize($file); 

//下载文件需要用到的头 

header("Content-type: application/octet-stream"); 

header("Accept-Ranges: bytes"); 

header("Accept-Length:".$fileSize);

$fp = fopen($file, "rb"); 

$buffer = 1024; 

$fileCount = 0; 

//向浏览器发送数据 

while(!feof($fp) && $fileCount < $fileSize){ 

    $cont = fread($fp, $buffer); 

    $fileCount += $buffer; 

    echo $cont; 

}

fclose($fp);

接着就是验证token是否正确,上述代码中的验证过程是伪代码,实际开发中应该根据业务需求,按照一定的算法验证token。token里面可能含有用户信息和过期时间等数据。


然后判断要下载的文件是否存在,这个文件可能不在web目录下,用户无法直接通过url访问。


最后就是读取文件流,发送给浏览器。


  • qq

    联系QQ:

    1149675376

  • wechat

    客服微信:

    406319040

  • phone

    咨询热线:

    0356-2618837

  • address

    公司地址:

    如何才能让自己戒赌市城区凤台西街太行日报纸库综合楼四楼