在前后端分离的架构中,前端和后端交互通过HTTP API接口实现。对于文件下载功能,通常有两种常见的方式可以实现:
后端生成文件并返回URL: 后端可以根据请求参数生成需要下载的文件,并将文件保存到服务器的某个目录下。随后,后端将生成的文件路径或者访问地址等信息以JSON格式返回给前端。最后,前端使用类似a标签的下载组件发送GET请求到后端所返回的URL即可。
返回文件流数据:另一种方式是,后端处理请求后直接将文件的字节流发送给前端。一般来说,我们会通过response对象提供的OutputStream流将文件内容发送给前端。前端则可以封装一个基于xhr或fetch的异步请求功能函数,使用JavaScript读取后端发送过来的二进制数据,传递给Blob对象, 然后再通过new URL().createObjectURL()方法创建出Blob对象的网络请求地址,从而实现文件下载操作。
第1种方法无需多说,我们看第2种方法具体如何实现。
以下是一个基于Java Spring Boot框架的后端代码示例,用于返回文件流数据:
@GetMapping("/downloadFile") public ResponseEntity<byte[]> downloadFile()throws IOException{ File file = new File("your_file_path"); HttpHeaders headers = new HttpHeaders(); headers.add("Content-Disposition", "attachment;filename=" + file.getName()); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK); }
此代码中,downloadFile()
方法在接收到请求后,将服务器上指定路径下的文件读入内存,并以字节流的方式返回给前端。
在编写前端代码时,可以使用XMLHttpRequest(XHR)或Fetch API等来发出异步网络请求,并处理返回的文件流数据。下面是一个使用XHR实现的简单示例,你可以根据自己的需求进行调整和优化:
function downloadFile(){ var xhr = new XMLHttpRequest(); xhr.open('GET', '/downloadFile', true); xhr.responseType = "blob"; xhr.onload = function(e) { if (this.status == 200) { var blob = new Blob([this.response], {type: xhr.getResponseHeader('Content-Type')}); var fileName = ""; var contentDisposition = xhr.getResponseHeader('Content-Disposition'); if(contentDisposition != null && contentDisposition.indexOf("=") > 0) { fileName = contentDisposition.substring(contentDisposition.indexOf("=") + 1); } var link = document.createElement("a"); link.href = window.URL.createObjectURL(blob); link.download = decodeURIComponent(fileName.trim()); link.click(); } }; xhr.send(); }
该函数将设定一个XHR对象,发出GET请求,responseType
设置为 blob
, 并解析响应头信息中的文件名(fileName)和 Content-Type。在成功接收到服务器返回数据后,使用Blob对象创建通过URL生成下载地址的超链接,并模拟点击操作来下载文件。
使用 axios 实现文件下载,可以像下面这样编写:
import axios from 'axios'; function downloadFile() { // 发出GET请求,responseType设置为 'blob',并指定需要下载的文件路径 axios({ method: 'get', url: '/downloadFile', // 这里填写文件下载接口地址 responseType: 'blob' // 响应类型为 blob }).then(res => { const contentDisposition = res.headers['content-disposition']; // 获取响应头中的文件信息 let fileName = 'wanmait.com.txt'; // 文件名 if (contentDisposition) { const matchArray = contentDisposition.match(/filename=(.*?)(;|$)/); // 通过正则表达式解析出文件名 if (matchArray && matchArray.length > 1) { fileName = decodeURIComponent(matchArray[1]); } } // 接收到二进制流后创建URL对象,并模拟点击下载操作 const blob = new Blob([res.data], { type: res.headers['content-type'] }); const objectUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = objectUrl; a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(objectUrl); }).catch(error => { console.error(error); }); }
在这个示例中,我们使用了axios发出一个GET请求,将响应的数据类型设置为blob。 在成功获取到响应后,通过xhr对象提供的response获取到响应的二进制流数据,并同步获取文件名和文件类型等信息,在前端通过blob对象和URL.createObjectURL()方法将响应内容转换为url地址,并在创建一个a标签模拟点击下载操作。
在前端中,为了提供方便的文件下载功能,我们通常采用的是基于浏览器默认行为的<a>标签实现,它可以直接传递指定 URL 规则作为href,通过 href 属性和html5中新增的download 属性来控制文件名下载等相关特性。
但是,如果以模拟点击的方式使用 JavaScript 的下载操作,就能完成异步获取文件数据后的下载需求。如:在创建一个a标签,设置a.href 和 a.download 表示要下载哪个文件,将其附加到DOM中,并通过调用a.click()方法来出发默认行为,从而实现下载文件的效果。
需要注意的是,在模拟点击中需要注意对对象URL的及时回收三必要性,避免因悬挂对象URL导致的性能问题或者对内存资源的浪费。
0条评论
点击登录参与评论