1. 普通下载
当后端返回的资源是链接时,此时可以使用 a
标签或者 window.location.href
直接打开。
1.1 a 标签形式
在 H5 中,a
标签新增了download
属性,包含该属性的链接被点击时,浏览器会以下载文件方式下载 href 属性上的链接。
<a rel="nofollow" href="/links?url=aHR0cHM6Ly94eHguIGNvbQ==" download="example.html">下载</a> // 或者封装 function download(href, title) { const a = document.createElement('a'); a.setAttribute('href', href); a.setAttribute('download', title); a.click(); } download('https://xxx. com', 'test')
1.2 window.location.href 直接打开
window.location.href === 'https://xxx. com'
2. 流文件下载
当后端返回的文件是流文件时,以 umi-request
请求方法为例
首先应在请求中设置返回类型:responseType: "blob"
import request from "umi-request"; export const downLoad = (url, fileName) => request(url, { method: "POST", data: data, responseType: "blob", // 代表内存之中的一段为二进制 }).then(data) => { const blob = data; let link = document.createElement("a"); link.href = URL.createObjectURL( new Blob([blob], { type: "application/vnd.ms-excel" }) ); link.download = fileName; document.body.appendChild(link); link.click(); URL.revokeObjectURL(link.href); };
2.1 自定义文件名
此时可以发现后端返回的是流文件,前端接到的是乱码。当前端自定义文件名时,可以直接下载
downLoad('https://xxx. com/api/download', 'test.xlsx')
2.1 采用后端定义的文件名
当采用后端的fileName
时,此时要获取后端在 content-disposition
中定义的文件名。
首先调用接口,发现文件名是在请求头content-disposition
中,需要注意的是:虽然我们能看到,但是却拿不到请求头。
如果想让浏览器能访问到其他响应头的话,需要后端在服务器上设置 Access-Control-Expose-Headers
:
// 后端面大致写法 headers.add("Access-Control-Expose-Headers", "Content-Disposition");
此时可以拿到相关信息,发现是编码的,需要 decodeURI 进行解码:
const disposition = response.headers.get('Content-Disposition'); const fileName = decodeURI(disposition.split(";")[1].split("filename=")[1])
注:直接在请求方法里是不能获取到请求头信息的,需要对请求进行拦截
request.interceptors.response.use(async (response) => { const disposition = response.headers.get("Content-Disposition"); // 获取 Content-Disposition return disposition // 当 Content-Disposition 中有值的时候进行处理,其他请求的响应则放过 ? { blob: await response.blob(), // 将二进制的数据转为 blob 对象,这一步是异步的因此使用 async/await fileName: decodeURI(disposition.split(";")[1].split("filename=")[1]), // 处理 Content-Disposition,获取 header 中的文件名 } : response; });
完整的代码
request 文件:
import request from "umi-request"; // 响应拦截 request.interceptors.response.use(async (response) => { const disposition = response.headers.get("Content-Disposition"); // 获取 Content-Disposition return disposition // 当 Content-Disposition 中有值的时候进行处理,其他请求的响应则放过 ? { blob: await response.blob(), // 将二进制的数据转为 blob 对象,这一步是异步的因此使用 async/await fileName: decodeURI(disposition.split(";")[1].split("filename=")[1]), // 处理 Content-Disposition,获取 header 中的文件名 } : response; }); export const downLoadExcel = (url) => request(url, { method: "POST", data: data, // responseType: "blob", // 注释掉这一段 }).then(data => { const { blob, fileName } = response; let link = document.createElement("a"); link.href = URL.createObjectURL( new Blob([blob], { type: "application/vnd.ms-excel" }) ); link.download = fileName; document.body.appendChild(link); link.click(); URL.revokeObjectURL(link.href); document.body.removeChild(link); });
react 文件:
<Buttton onClick={download}> 下载 </Button>
js 文件:
async download() { await downLoadExcel('http://xxx. com/api/download'); },
以上内容为自己平时遇到的问题记录,供参考,如果能帮到你那再好不过了。