Content-Disposition / Content-TypeContent-Dispositionhttp 头部的 Content-Disposition字段,规定了返回的内容用什么形式展示value含义是否默认inline以网页或者页面的一部分是attachment以附件的形式下载并保存到本地否http.createServer((req, res) => { res.setHeader(“Content-Disposition”, “attachment”) res.end(‘123 - 321 - 1234567’) })前端需要使用window.open 形式访问 此路由就可以实现文件的下载window.open(xxxx)或者使用 H5新属性 a 标签<a type=‘download’ href=xxx> 点击下载 </a>Content-Typehttp.createServer((req, res) => { res.setHeader(“Content-Type”, “application/octet-stream”) res.end(‘123 - 321 - 1234567’) })同上前端使用 open 或者 a标签进行处理备注: 如果使用普通的请求,是不可以的,比如使用ajaxwindow.openwindow.open 可以下载文件的原因是,浏览器遇到无法解析的文件就是执行下载当使用浏览器打开文件时, 如果它无法解析,那么就会把该文件下载下来http.createServer((req, res) => { const data = fs.readFileSync(’./Zip.zip’) res.end(data) })拿到的data是一个buffer 对象,那么直接写一个Buffer可以实现下载么data = new Buffer(‘我是谁,谁是我’)尝试后发现,koa是可以的。但是原生直接这么写是不行的http.createServer((req, res) => { const newBuf = new Buffer(‘我是谁,谁是我’) res.end(newBuf) })通过接口拿到数据之后进行下载在实际项目中,文件下载可能出现的场景对于已经在服务器存在的文件进行下载,比如图片资源将一些查询数据导出到本地, 比如mysql查询结果导出csv对于已存在的资源,可以直接使用 上面说的 winodw.open 或者 a 标签进行下载,那么对于不是以文件形式存在的资源呢data URI经常见到使用 data URI scheme 的是图片, 一般为了减少http请求,会将图片直接以base64的形式展示在html中<img src=‘data:image/png;base64,xxxxxx’/>也可以应用到文件下载中router.get(’/download’, async (ctx, next) => { const newBUf = new Buffer(‘我是谁,谁是我’) ctx.body = newBUf}axios.get(${path}).then(function ({data}) { let a = document.createElement(‘a’); a.href = “data:text/plain;charset=utf-8,” + data; a.download = “myfilename.png”; a.click();})BlobBlob 是表示一个类文件对象,可以用它来表示一个文件server 部分http.createServer((req, res) => { res.setHeader(“Access-Control-Allow-Origin”, “*”); let end = ’’ if (req.url.includes("/down")) { const newBUf = new Buffer(‘我是谁,谁是我’) end = newBUf } res.end(end)} 前端 const xhr = new XMLHttpRequest(); xhr.open(‘GET’, path); xhr.responseType = ‘blob’; xhr.onload = function () { const blob = xhr.response; const url = URL.createObjectURL(blob); // 通过a标签去下载 const link = document.createElement(‘a’); link.href = url; link.download = fileName; link.click(); URL.revokeObjectURL(url); }; xhr.send();尝试用 window.open 方式,发现不可以目前常用的各个第三方库也支持返回内容为blob格式 axios.get(${path}, { responseType: ‘blob’ })或者 fetch fetch(path).then(res => res.blob().then(blob =>{ … })window.URLcreateObjectURL 用 blob 对象来创建一个 object URL(它是一个 DOMString),我们可以用这个 object URL 来表示某个 blob 对象,这个 object URL 可以用在 a 标签的 href属性上,然后触发点击事件,就可以下载文件了revokeObjectURL 为了避免避免内存泄漏,需要手动释放创建的 object URL缺点构建完 blob 对象后才会转换成文件从代码就能看出,需要先将返回内容转为blob才进行下载操作,如果用户操作的是一个很大的资源,在等待文件正式下载前,还需要一段时间等待格式的转化实例将mysql数据 导出 csv这边直接用数据模拟mysql查询结果, 在网上查到两种拼接方式,肯定有其余的方案第一种const result = [ [‘id’, ‘oreder’, ’name’, ‘status’ ], [1, ‘201904120201’, ‘正在加载’, ‘已完成’], [18, ‘201904120204’, ‘测试189’, ‘待付款’], [22, ‘201904120209’, ‘蓝田日暖’, ‘待付款’],]// 可以看到 result 数组的第一组是 csv的各个字段标题 const data = csvData.reduce((cur, next) => ${cur + next.join(',')}\n, ‘’)const blob = new Blob([data]);const url = URL.createObjectURL(blob);var a = document.createElement(‘a’);a.href = url;a.download = filename;a.click();window.URL.revokeObjectURL(url);第二种const result = [ [1, ‘201904120201’, ‘正在加载’, ‘已完成’], [18, ‘201904120204’, ‘测试189’, ‘待付款’], [22, ‘201904120209’, ‘蓝田日暖’, ‘待付款’],]// result 就是正常的数据格式 // 解决乱码问题 let dataType = ‘\uFEFF’ // 添加表格的头子段 dataType += ([’ 订单编号’, ‘用户’, ‘动态ID’].join(’,’)) dataType += ‘\n’ csvData.forEach(item => { dataType += ([item.id, item.order, item.name, item.staus].join(’,’)) dataType += ‘\n’ }) const blob = new Blob([dataType], {type: ’text/csv’}) 如果有几段流文件,前端需要下载拼接成一个完整文件,如何实现肯定是在 server端进行文件的拼接操作,然后返回到前端下载大致过程const content1 = ‘这里是第1段文件内容’const content2 = ‘这里是第2段文件内容’ctx.body = { code:200, data: content1 + content2 }前端就是上文中的blob 下载方式了参考文章Data URI Scheme