如何在axios或者fetch里实现文件下载

431 阅读2分钟

前言

通常我们遇到的文件下载,后端都会以文件流的形式将文件传给我们,我们如何在axios或者fetch中实现文件下载的功能呢?

场景

后端返回文件流,文件名在header上,前端需要将其获取下来并且实现文件下载功能。

image.png 从上面的图片我们可以知道后端是以文件流的形式传给我们的,也可以通过headers上面的Content-Disposition上获取文件名。

区别

fetch实现

简单实现

fetch('your-file-url')
  .then((response) => response.blob()) // 将响应体转为Blob对象
  .then((blob) => {
    // 文件名存储在'Content-Disposition'头中
    const filename = response.headers.get('content-disposition').split('filename=')[1].replace(/"/g, '');
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', filename); // 使用从header中获取的文件名
    document.body.appendChild(link);
    link.click();
    link.parentNode.removeChild(link);
  })
  .catch((error) => console.error('Error:', error));

优雅的封装实现

  // get请求下载文件封装
  getFile(url: string, params: string) {
    const queryString = new URLSearchParams(params).toString();
    const requestUrl = queryString ? `${url}?${queryString}` : url;
    let options;

    const requestOptions = {
      ...options,
      method: 'GET',
      headers: {
        ...(options?.headers || {}),
        'Content-Type': 'application/json',
      },
    };

    return fetch(requestUrl, requestOptions)
      .then(authBeforeFormate)
      .then((response) => {
        const { headers } = response;
        headers.forEach((value, key) => {
          headers[key] = value;
        });
        const fileStream = response.blob();
        // 处理 headers
        if (headers?.['content-disposition']?.indexOf('filename=') > -1) {
          const filename = decodeURIComponent(
            headers?.['content-disposition']
              ?.replace('attachment;', '')
              ?.replace('filename=', '')
          );
          const contentType = headers?.['content-type'];
          return {
            success: !!filename,
            fileStream,
            filename,
            contentType,
          };
        }
      })
      .then((data) => {
        // 处理data
        return data;
      })
      .catch((err) => {
       // 处理异常
        return err;
      });
  }

如何调用

// 请求
downloadFile(params?: any) {
  return http.getRequest(`your-file-url`, params);
},

const getFile = async () => {
    const res = await dowloadFile()
    if (res) {
      const fileStream = res?.fileStream;
      const fileName = res?.filename?.split('.');
      const newFileName = fileName[0] + `(${state.level})` + '.' + fileName[1];
      fileStream.then((resData) => {
      const url = window.URL.createObjectURL(resData);
      const link = document.createElement('a');
      link.href = url;
      link.download = newFileName
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);
    });
      message.success('下载成功');
   } else {
      message.error('下载失败');
   }    
}

axios实现

简单实现

axios({
  method: 'get',
  url: 'your-file-url',
  responseType: 'blob',
}).then((response) => {
  // 文件名存储在'Content-Disposition'头中
  const filename = response.headers['content-disposition'].split('filename=')[1].replace(/"/g, '');
  const url = window.URL.createObjectURL(new Blob([response.data]));
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', filename); // 使用从header中获取的文件名
  document.body.appendChild(link);
  link.click();
  link.parentNode.removeChild(link);
});

优雅的封装实现

// 拦截器,统一处理未登录或者没有权限的情况
instance.interceptors.response.use(
  (response: AxiosResponse) => {
    const { data, headers } = response;
    if (headers?.['content-disposition']?.indexOf('filename=') > -1) {
      const filename = decodeURIComponent(
        headers
          ?.['content-disposition']
          ?.replace('attachment;', '')
          ?.replace('filename=', '')
      );
      const contentType = headers?.['content-type'];
      return {
        success: !!filename,
        data: {
          content: data,
          filename,
          contentType
        },
      };
    }

    return data;
 }
 
export const getForm = (url: string, param?: any) => {
  return new Promise((resolve) => {
    instance.get(url, { params: param , responseType: 'blob'}) //这里一定要用responseType: 'blob',也是和fetch的一个区别
      .then(res => resolve(res))
      .catch(err => resolve(err))
  });
};
//请求
downloadFile(param){
    return Http.getForm(`your_request_url`, param)
}

const downloadFile = async () => {
    const param = {
        ....
    }
    const res = await downloadAuditLogs(param);
    const fileContent = res.data.content;
    const fileName = res.data.filename;
    const contentType = res.data.contentType;
    const blob = new Blob([fileContent], { type: contentType });
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a')
    link.href = url;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
}

总结

以上就是axios和fetch实现文件下载的方式,如果有不正确的地方欢迎大家指出。