a标签/js 下载服务器文件
主要参考【前端:下载文件实现方式及跨域下载(详解) https://blog.csdn.net/qq_43471802/article/details/103436595】
加上自己遇到的问题,记录并分享,如有错误,请指正
下载文件根据后端返回的是文件流还是URL下载url地址,主要分两种:
- 二进制式下载
- URL下载
一、二进制式下载
如果后端返回二进制文件流,前端需要使用Blob接收。
1、responseType(请求)
首先在前端发送请求时就应在请求头中,用responseType
告知服务器需要返回的数据类型,responseType默认是“json”,这里我们请求的是文件流:“blob”
。
不同的请求插件设置header的方式不同,用axios来说,axios.post(url, data, config),responseType是在config里设置的(这些设置应该是在底层赋给请求头):
export function download(url, data) {
return axiosInstance.post(url,data,{
responseType: 'blob'
}
);
}
如果这里不定义responseType,下载下来的文件内容会乱码
2、Content-Type(响应)判断是普通数据还是文件流(可选)
服务器返回不同数据,我们会做不同的处理,json我们直接取用,文件流数据需处理后下载。
在axios项目中,一般为了给所有的请求做一些统一处理,比如baseURL、请求带token,回包错误码提示,在底层封装一个axios实例,所有的请求都调用该实例的方法。
这种情况下,文件的请求就有可能和普通数据的请求调用的是同一个实例。直接在总响应拦截器里判断出文件流并执行下载,就不用在每一文件请求协议回调里各自再写一遍执行下载的代码。如何区分响应数据的是文件流还是json数据就很有必要了。
头部Content-Type
表示服务端发送的类型及采用的编码方式,一般为application/json.而回包是文件,则Content-Type 一般为“octets/stream”
,我们就以此判断是返回的是文件还是普通数据。
//axios响应拦截器里
if(res.headers &&
(res.headers['content-type'].indexOf('application/x-msdownload') != -1 ||
res.headers['content-type'].indexOf('octets/stream') != -1 ||
res.headers['content-type'].indexOf('application/octet-stream') != -1)){
//执行下载方法
}
3、Content-Disposition(响应)和文件名(可选)
还是针对第2节所描述的情况:判断出来什么时候是文件数据,在回包里拿到整个文件,而文件名就需要从响应头里的Content-Disposition
属性获取
【官方文档:Content-Disposition】
Content-Disposition可以出现在消息主体中, 也可以出现在multipart/form-data类型的应答消息体中。Content-Disposition在不同的地方有不同的作用和意义,而文件下载属于前者,下面我们也只说第一种。
在常规的HTTP应答中,Content-Disposition
在响应头,有两个参数。第一个参数用于指示回复的内容该以何种形式展示:
- inline — 默认值,内联形式。表示回复中的消息体会以页面的一部分或者整个页面的形式展示)
attachment
— 附件形式。意味着消息体应该被下载到本地,大多数浏览器会自动触发一个“保存为”的对话框,将filename的值预填为下载后的文件名,假如它存在的话
当第一个参数为attachment 时才有第二个参数——filename
。
这里Content-Disposition应为attachment
,文件名就在第二个参数里:
我们可以从参数里分离出文件名: