首页>>前端>>JavaScript->码二说之写一个前端下载文件功能

码二说之写一个前端下载文件功能

时间:2023-12-01 本站 点击:0

前言

过去有很多次文件下载的功能,但是都没有记录下来,这次有空就把文件下载的功能从0写一遍,于是就有了这篇文章。 我会从简到难的方式去实现下载功能。从直接下载字符串到简单请求下载文件,最终通过后端返回的文件名来实现动态下载文件。

简单下载

常见的文件下载就是office系列格式文件了,然后再就是txt格式的文件,前端下载通过a标签来实现下载的,其实也是调用浏览器内置功能。

那么把文件格式的mimeType列举一下: 这个篇文章中更全:百度文库

const mimeTypeMapping = {    xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',    xls: 'application/vnd.ms-excel',    docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',    doc: 'application/msword',    pdf: 'application/pdf',    default: 'text/plain' // 默认的文件下载方式};

浏览器内置的下载功能,虽然知道有新出的api,但是我记得得谷歌浏览器97版本及之后才能使用,于是我用了兼容性最好的方式,a标签 + URL.createObjectURL + blob。

const link = document.createElement('a');const urlObject = window.URL || window.webkitURL || window;link.href = urlObject.createObjectURL(new Blob([data], {    type: mimeTypeMapping[fileType]}));link.download = fileName;document.body.appendChild(link);

它其实通过创建对象字符串,赋值为a标签的href属性,然后通过超链接下载协议实现文件的下载。

完整代码如下:

// 下载文件export function downloadFile(data, fileName = '未知文件', callback) {  const mimeTypeMapping = {    xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',    xls: 'application/vnd.ms-excel',    docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',    doc: 'application/msword',    pdf: 'application/pdf',    default: 'text/plain' // 默认的文件下载方式  };  const fileType = fileName.split('.')[1] || 'default';  const link = document.createElement('a');  const urlObject = window.URL || window.webkitURL || window;  link.href = urlObject.createObjectURL(    new Blob([data], {      type: mimeTypeMapping[fileType]    })  );  link.download = fileName;  document.body.appendChild(link);  link.click();  if (typeof callback === 'function') {    callback('success');  }  document.body.removeChild(link);}

通过请求下载文件

通过请求下载文件,需要将请求头部的responseType设置为 arrayBuffer 或者 blob。 其它的就是简单的基本操作了。这里我用到的是umi-request,axios或者jquery都是类似的逻辑。

import request from 'umi-request';// 简单下载,超级简单,只能下载前端已知的文件类型的文件,不支持后端动态设置类型。export async function simpleDownload(url, data = {}, method = 'get', fileName) {  const options = {    responseType: 'arrayBuffer' // blob  };  let requestMethod;  if (method.toLocaleLowerCase() === 'get') {    requestMethod = request.get(url, { params: data, ...options, });  } else {    requestMethod = request.post(url, { data, ...options });  }  return new Promise((resolve, reject) => {    requestMethod      .then(res => {        const blob = new Blob([res]);        downloadFile(blob, fileName, resolve);      })      .catch(reject);  });}

根据后端返回的文件名及类型来动态下载文件

也是通过请求来下载文件,只是会根据后端返回的响应头部的信息content-disposition来下载文件,这时候你能够知道文件类型及文件名称,而不是前端写死的。

import React from 'react';import { message } from 'antd';import request from 'umi-request';// 发请求下载文件,复杂一点,支持后端动态设置文件类型export async function download(url, data = {}, method = 'get') {  const options = {    responseType: 'arrayBuffer' // blob  };  let requestMethod;  if (method.toLocaleLowerCase() === 'get') {    requestMethod = request.get(url, { prefix, timeout, ...options });  } else {    requestMethod = request.post(url, { data, prefix, timeout, ...options });  }  return new Promise((resolve, reject) => {    requestMethod      .then(response => {        // 状态码不对,报错        if (response.status < 200 || response.status >= 300) {          const errorData = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(response.data)));          message.error(errorData.message);          return reject('error');        }        // 文件名提取不出来,报错        const disposition = response.headers?.['content-disposition'];        const matchGroup = /filename=(.*);?/.exec(`${disposition}`);        let fileName = matchGroup && window.decodeURI(matchGroup[0]);        if (['', null, undefined].includes(fileName)) {          if (response.headers.msg) {            message.error(response.headers.msg);          }          return reject('error');        }        // 去掉字符串两边的 " 符号        fileName = fileName.replace(/^\"?([\s\S]{0,})\"?$/, "$1")        downloadFile(response.data, fileName, resolve);      })      .catch(() => {        resolve('error');      });  });}

总结

这些都是比较常见的下载文件的方式,其实也没啥难度,只不过你稍不注意,可能就会踩坑了,比如我从写到测试,就花了近三个小时。 有时你觉得很简单的东西,兴许也会变成很费时费力的东西,所以习惯记录,不然脑子是不会把发生的每一件事每一个细节都给记的死死的,时间久了,就容易忘记,然后就会出现很多小问题。

原文:https://juejin.cn/post/7098511096197152776


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/JavaScript/6402.html