- A+
所属分类:Web前端
概要
前端上传文件的例子很多, 但是下载相关的例子不多, 主要是因为下载本身比较简单.
但是这次做了个文件导出功能, 接收文件流的时候弄了很长时间也没有成功, 就因为请求中缺了个配置…
示例
后端
后端比较简单, 不管有多少需要计算的业务, 最终只是返回文件流.
下面的示例是通过 golang gin 框架实现的.
1 package main 2 3 import ( 4 "strconv" 5 6 "github.com/gin-gonic/gin" 7 ) 8 9 func main() { 10 route(8000) 11 } 12 13 func route(port int) error { 14 15 r := gin.Default() 16 apiV1 := r.Group("/api/v1") 17 18 // file download 19 apiV1.GET("/download/:fileName", DownloadFile) 20 21 return r.Run(":" + strconv.Itoa(port)) 22 } 23 24 func DownloadFile(c *gin.Context) { 25 fileName := c.Param("fileName") 26 27 c.File("./download/" + fileName) 28 }
根据 url 中的文件名, 直接返回 download 文件夹下的某个文件
前端
前端一般有以下几种情况的下载:
直接显示图片
直接将文件流赋给 img 的 src 就行
1 <img src={"http://localhost:8000/api/v1/download/test.png"} width={50} height={60} />
提供下载链接, 点击后下载
1 <a href={"http://localhost:8000/api/v1/download/test.pdf"} />
文件导出, 前端没有显示下载链接的位置
这种方式需要前端模拟一个 a 标签的点击, 从而实现文件的下载.
1 export async function exportFile(params) { 2 return postJson('/api/v1/download/test.xlsx, params, 'blob').then((res) => { 3 let url = URL.createObjectURL(new Blob([res])); 4 let filename = '导出记录.xlsx'; 5 let a = document.createElement('a'); 6 a.href = url; 7 a.download = filename; 8 a.click(); 9 URL.revokeObjectURL(url); 10 }); 11 } 12 13 const postJson = async (url, params, responseType = '') { 14 const response = await request(url, { 15 method: 'POST', 16 header: { 17 'Content-Type': 'application/json', 18 }, 19 data: params, 20 responseType: responseType, 21 }); 22 23 // 省略... (对response的一些处理) 24 25 return Promise.resolve(response); 26 }
这里有个关键的配置 responseType: 'blob' 这个配置不在 header 中,
和 header, data 是平级的. (当时就是这个配置导致导出功能卡了半天, 如果没有这个配置, 导出之后会显示文件已经损坏)