记一次前端文件下载处理过程

Axios 请求拦截处理

TypeScript 复制代码
  // 响应拦截器
  instance.interceptors.response.use(async (response: AxiosResponse<customRes, any>): Promise<any> => {
    // 文件流处理
    if (response.config.responseType == "blob") return Promise.resolve(response);
  
    return Promise.resolve(response.data);
  }, responseErrorHandle)

当响应的数据类型是文件流(Blob)时,拦截器直接返回了一个包含 response 的 Promise,以便在调用这个接口的地方能够获取到文件流并进一步处理。

请求方法处理

通过 Axios 请求文件流(Blob)并进行文件下载的函数。

请求服务器返回的文件流数据,并通过浏览器的下载机制将其保存到本地文件。

设置响应类型为 Blob 是为了告知服务器返回的数据是二进制流,方便后续在客户端进行文件下载。

TypeScript 复制代码
  /**
   * 返回文件流测试
   */
  export const getFile = () => {
    instance.get('/test/file/stream', {
      responseType: "blob", // 设置响应类型为blob
      params: {}
    }).then((response) => {
      // 处理下载文件
      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement("a");
      link.href = url;
      link.setAttribute("download", getFileNameFromHeaders(response)); // 设置下载的文件名和扩展名
      link.click();
    })
  }

从headers中取出文件名方法封装

TypeScript 复制代码
  // 文件名处理
  export const getFileNameFromHeaders = (response: AxiosResponse) => {
    // 从响应头中获取Content-Disposition信息
    const contentDisposition = response.headers['content-disposition'];
  
    // 使用正则表达式匹配文件名
    const match = /filename="(.*)"/.exec(contentDisposition);
  
    // 获取匹配的文件名
    return match ? decodeURI(match[1]) : 'unknown'
  }
  1. instance.get('/test/file/stream', {...})
    • 使用 Axios 的 get 方法向服务器端发送 GET 请求,请求的地址是 '/test/file/stream'。
  2. responseType: "blob"
    • 在请求配置中设置 responseType 为 "blob",表示期望服务器响应的数据是二进制数据(Blob 对象)。
  3. .then((response) => {...})
    • 使用 Promise 的 .then 处理请求成功的回调函数,response 包含了从服务器返回的 Blob 对象。
  4. window.URL.createObjectURL(new Blob([response.data]))
    • 通过 window.URL.createObjectURL 创建一个临时的 URL,该 URL 表示了从服务器返回的 Blob 对象的内容。这个 URL 通常用于创建下载链接。
  5. const link = document.createElement("a");
    • 创建一个 <a> 元素,用于模拟文件下载。
  6. link.href = url;
    • 将刚刚创建的 URL 赋值给 <a> 元素的 href 属性。
  7. link.setAttribute("download", getFileNameFromHeaders(response));
    • 设置 <a> 元素的 download 属性为从服务器响应头中获取的文件名。这里使用 getFileNameFromHeaders 的函数,它可能用于从响应头中获取文件名,确保文件名包含在 Content-Disposition 头中。
  8. link.click();
    • 模拟点击 <a> 元素,触发文件下载。

整个流程的目的是通过 Axios 请求获取服务器端返回的文件流,然后使用 Blob 对象创建一个临时的 URL,并通过创建 <a> 元素模拟点击以触发文件下载。

网络服务处理

返回文件流的接口

JavaScript 复制代码
  // 服务端返回文件流,并将文件名通过 attachment 返回
  router.get('/file/stream', async (ctx, next) => {
      const filePath = path.join(__dirname, '../upload/file/测试表格.xlsx');
      // 设置响应头,告诉浏览器文件名
      ctx.attachment(encodeURI('测试表格.xlsx'));
      // 读取文件流并设置为响应体
      ctx.body = await fs.createReadStream(filePath);
  })

跨域配置

允许前端访问 Content-Disposition

JavaScript 复制代码
app.use(cors({
    exposeHeaders: ['Content-Disposition'],
    credentials: true,  // 允许携带cookies
}));

总结

服务端返回文件流,并将文件名通过 attachment 返回,文件名会被携带在 Content-Disposition中。

前端通过 getFileNameFromHeaders 方法取出 文件名

前端通过 window.URL.createObjectURL(new Blob([response.data])) 创建一个可用于浏览器中的文件下载的 URL

相关推荐
vvilkim4 分钟前
Flutter 常用组件详解:Text、Button、Image、ListView 和 GridView
前端·flutter
笨笨马甲6 分钟前
Qt Http Server模块功能及架构
qt·http·架构
豆豆(设计前端)10 分钟前
在 JavaScript 中,你可以使用 Date 对象来获取 当前日期 和 当前时间、当前年份。
开发语言·javascript·ecmascript
vvilkim10 分钟前
Flutter 命名路由与参数传递完全指南
前端·flutter
NA11 分钟前
redis
前端
你真好看_11 分钟前
6年低代码 零代码 系统二开人员的角度,看低代码 到底有多好用!!!
前端
JC_You_Know19 分钟前
边缘计算一:现代前端架构演进图谱 —— 从 SPA 到边缘渲染
前端·人工智能·边缘计算
DoraBigHead21 分钟前
深入 JavaScript 作用域机制:透视 V8 引擎背后的执行秘密
前端·javascript
薛定谔的算法23 分钟前
JavaScript闭包深度解析:从基础概念到柯里化实践
javascript
Tu_Jipang23 分钟前
前端从零搭建企业级后台系统实战指南
前端