说明一:
所谓的下载是浏览器的行为,服务端只需要做到以下几点:
1.设置header头 Content-Type:application/octet-stream,Content-Disposition:attachment; filename=20221117_103544.csv
2.response 返回了数据
![](https://img.haomeiwen.com/i19560490/6597d74c25ca6f94.png)
剩下的事情就是前端的问题
前端实现:如果是简单的 get 请求直接用html 的a标签,浏览器会根据响应的 header 头自动下载,如果是想用 ajax,fetch,或者axios 等,则需要先请求到数据,然后前端再模拟a标签才能实现下载
$("#query").click(function () {
fetch("url", {
headers: {
'Authorization': 'Bearer xxx',
'content-type': 'application/json'
},
method: 'POST',
mode: 'cors',
})
.then(response => {
fileName = response.headers.get("Content-Disposition").split(';')[1].split('=')[1].replace(/\"/g, '')
result = response.blob()
console.log(fileName)
console.log(result)
downloadFile(result, fileName);
})
})
//下载文件,我也是网上抄来的,其实这是属于前端的知识
function downloadFile(res, fileName) { // res为后端传来的文件流,// fileName为文件名称,自己根据实际情况赋值
if (!res) {
return
};
if (window.navigator.msSaveBlob) { // IE以及IE内核的浏览器
try {
window.navigator.msSaveBlob(res, fileName) // res为接口返回数据,这里请求的时候已经处理了,如果没处理需要在此之前自行处理var data = new Blob([res.data]) 注意这里需要是数组形式的,fileName就是下载之后的文件名
// window.navigator.msSaveOrOpenBlob(res, fileName); //此方法类似上面的方法,区别可自行百度
} catch (e) {
console.log(e)
}
} else {
let url = window.URL.createObjectURL(new Blob([res], {
type: 'text/plain;charset=uft-8' // 前后端一定要统一utf-8编码,否则会乱码
}));
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName) // 文件名
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
};
go 的服务端的代码也非常简单:
buffer := &bytes.Buffer{}
//buffer.WriteString("xEFxBBxBF") 这个会原样输出到文件中
buffer.WriteString("\xEF\xBB\xBF") //这个是不可见字符
writer := csv.NewWriter(buffer)
writer.Write([]string{"编号", "姓名", "年龄"})
writer.Write([]string{"1", "张三", "23"})
writer.Flush() // 此时才会将缓冲区数据写入
fileName := time.Now().Format("2006-01-02 15:04") + ".csv"
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
c.Data(http.StatusOK, "text/csv", buffer.Bytes())
这段代码看着很简单,可是我改了很久,因为我用两种方式测试都没有达到我想要的效果,一个是1.apipost 服务端返回200,但response 没有数据,只有发送并保存才有期望的文件保存下来
2.我自己写了个测试文件,用ajax 方式来请求,在response 里有数据返回,可以没有文件下载下来
这两种都不是我想要的,因此我想着应该是我的代码错了,然后在服务端生成了csv文件并把这个文件通过c.File()方法发送到前端,经测试结果还是跟之前一样,所以我没有办法了,最后没有办法,我抱着试试看的心态把 response 的header头,Content-Type: application/octet-stream 拿去搜,结果真让我搜到了,具体详见:https://new.qq.com/rain/a/20210610A0A8W400
最后把问题解决了,我想起以前写 php 时,那时候是前后端不分离的,确实是用的html 的 a 标签来实现的,原来一个 下载文件涉及到浏览器的默认行为!!!这体现了基础知识的用处。
网友评论