方式一:a标签直接下载
<a href="链接">下载</a>
一个文件链接(一般是服务器上的某个文件),这个链接一般地址栏输入是预览,不是附件下载
如果想改成附件下载,以下两种方式任选一个均可:
1、后端处理,后端加上一个响应头
res.setHeader('Content-Dispostion','attachment','name.pdf')
2、a标签 加上 download属性
<a href="链接" download="文件名">下载</a>
方式一的缺点:
缺点:在 JavaScript 中使用 a 标签下载文件时,直接通过 a标签的点击事件触发浏览器下载,是无法设置请求头的,因为这是一个简单的 GET 请求。如果这个文件的下载要求的是携带token,那a标签这种就不生效了(a标签没法携带token),会成为预览。
方案:a标签可以携带cookie,所以可以有另一种解决方法,在下载文件前,发送一个请求获取一个临时token通过cookie进行携带,a标签下载是流式下载,会把服务器的文件像流水一样存储到本地磁盘,所以下载直接能看到下载,不会将文件缓存到浏览器。
标题方式二:使用 XMLHttpRequest 或 Fetch API 请求。
写一个方法进行下载 (本质还是利用a标签进行下载)
这个方法可以是一个ajax请求,这个请求就可以携带token,然后将请求到的服务器文件转成blob,在创建一个a标签进行下载,创建虚拟的链接元素,模拟点击下载。该方法会占用前端线程。
import fetch from'isomorphic-fetch';constexportFile=(url, options)=>{const projectId = sessionStorage.getItem(PROJECT_ID);const downLoadURL = projectId ?BATCH_ACTION_URL_PREFIX.V2:BATCH_ACTION_URL_PREFIX.V1;const defaultOptions ={credentials:'same-origin',};const newOptions ={...defaultOptions,...options };if(
newOptions.method ==='POST'||
newOptions.method ==='PUT'||
newOptions.method ==='DELETE'){const projectId = sessionStorage.getItem(PROJECT_ID);const appId = sessionStorage.getItem(APP_ID);const shopId = sessionStorage.getItem(SHOP_ID);const params ={};
projectId && Object.assign(params,{ projectId });
appId && Object.assign(params,{ appId });
shopId && Object.assign(params,{ shopId });
newOptions.body ={...newOptions.body,...params };if(!(newOptions.body instanceofFormData)){
newOptions.headers ={Accept:'application/json','Content-Type':'application/json; charset=utf-8',...newOptions.headers,};}else{// newOptions.body is FormData
newOptions.headers ={Accept:'application/json',...newOptions.headers,};}}const token = window.localStorage.getItem(TOKEN);if(token){
newOptions.headers ={'X-Authorization':`Bearer ${token}`,...newOptions.headers,};}const lang = localStorage.getItem(LOCALE_KEY);if(lang){
newOptions.headers ={'Accept-Language': lang,...newOptions.headers,};}const requestURL =`${downLoadURL}/${url}`;returnrequest(requestURL, newOptions).then(res=>{let filename;if(res.headers){
filename =(
res.headers.get('Content-Disposition')|| res.headers.get('content-disposition')).split('attachment;filename=')[1];}if(res.blob){
res.blob().then(blob=>{var alink = document.createElement('a');
alink.style.display ='none';
alink.target ='_blank';if(window.navigator && window.navigator.msSaveOrOpenBlob){// 兼容IE/Edge
window.navigator.msSaveOrOpenBlob(blob, filename);}else{
alink.href = window.URL.createObjectURL(blob);
alink.download = filename;}
document.body.appendChild(alink);
alink.click();URL.revokeObjectURL(alink.href);// 释放URL 对象
document.body.removeChild(alink);});return res;}else{if(res.code ===0){return res;}else{
message.warning(res.message);}}});};exportdefault exportFile;exportdefaultfunctionrequest(url: string,options: Object){const defaultOptions ={credentials:'same-origin',};const newOptions ={...defaultOptions,...options };if(
newOptions.method ==='POST'||
newOptions.method ==='PUT'||
newOptions.method ==='DELETE'||
newOptions.method ==='PATCH'){if(!(newOptions.body instanceofFormData)){
newOptions.headers ={Accept:'application/json','Content-Type':'application/json; charset=utf-8',...newOptions.headers,};
newOptions.body =JSON.stringify(newOptions.body);}else{// newOptions.body is FormData
newOptions.headers ={Accept:'application/json',...newOptions.headers,};}}returnfetch(url, newOptions).then(response=>checkStatus(response, url, options));}
方式二的缺点:
**如果文件小还行,文件大了就会出现点击了下载,但是没有反应,过了几分钟后才出现了下载,这种等待时间就是将服务器端的那个文件转成了blob(res.blob()花的时间特别长),才进行a标签的流式下载(这里页面才开始出现有下载的交互体现)
版权归原作者 Yolanda_2022 所有, 如有侵权,请联系我们删除。