首先,因为前端代码都是一样的,然后就需要对比他们请求的接口了,对比之后发现两个东西,一个返回的数据,上面的第一种中文是乱码的,然后后面两种都是正常的,再一个就是返回数据里的Response Headers中的Content-Type字段是不一样的,
第一个的Content-Type: application/octet-stream,
第二个和第三个都是Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,类似这种的,然后去查发现第二个和第三个都不是标准的Content-Type,后来才知道是自定义的一个告诉excel客户端,这是一个特殊文件。当然上面都是我的怀疑,怎么能知道真的就是接口返回的Content-Type的问题呢,你说直接找后端,后端不认说第一种不就可以用吗,你都是同一个代码下载的,怼的你都没话说,你还得自己回来找原因,那么不如直接先把原因找到。
const express = require('express'); const cors = require('cors'); const app = express(); // 配置CORS,允许跨域请求 app.use(cors()); app.get('/api/csv-data', (req, res) => { res.setHeader('Content-Type','text/csv') const data = '数据1,数据2,数据3' res.end(data) }); const port = 3001; // 堆代码 duidaima.com // 启动服务 app.listen(port, () => { console.log(`Server listening at http://localhost:${port}`); });启动起来我们的Node接口就写好了,我们就能前端调用下载测试了,前端页面代码如下:
import axios from 'axios'; function App() { const downloadFile = (content, filename) => { // 创建一个 Blob 对象 const blob = new Blob([content], { type: 'application/octet-stream' }); // 创建一个 a 标签 const link = document.createElement('a'); // 设置 href 为 Blob 对象 link.href = URL.createObjectURL(blob); // 设置下载的文件名 link.download = filename; // 将 a 标签添加到 DOM document.body.appendChild(link); // 触发下载 link.click(); // 从 DOM 移除 a 标签 document.body.removeChild(link); // 释放 Blob URL URL.revokeObjectURL(link.href); } const csvDownLoad = () => { axios.get(' http://localhost:3001/api/csv-data') .then(response => { downloadFile(response.data,'测试CSV下载.csv') }).catch(error => { console.log(error); }); } return <button onClick = {csvDownLoad}>下载CSV文件</button>; } export default App;结果下载下来发现文件格式是对的,真的是csv文件,但是内容乱码了,咱也不知道这是啥字:
const express = require('express'); const cors = require('cors'); const app = express(); const iconv = require('iconv-lite'); // 配置CORS,允许跨域请求 app.use(cors()); // 读取CSV文件的接口 app.get('/api/csv-data', (req, res) => { res.setHeader('Content-Type', 'text/csv; charset=GBK'); const data = '数据1,数据2,数据3'; const gbkBuffer = iconv.encode(data, 'GBK'); res.end(gbkBuffer); }); const port = 3001; // 启动服务 app.listen(port, () => { console.log(`Server listening at http://localhost:${port}`); });
然后我们继续使用前面的前端代码进行下载,你会发现下载下来的文件打开依然是乱码,这是为什么呢,我们的数据已经采用GBK编码了,为什么打开还是乱码呢。此时我就在想是不是前端代码下载有问题,看了一下前端下载的代码,发现axios获取到的响应数据是作为一个UTF-8字符串处理的,而不是原始的字节流。
因此,当你将其传递给Blob对象并下载时,它是以UTF-8编码的。也就是说前端下载的时候还是以UTF-8编码的,这是不行的,所以还是得以后端接口给的原来得编码格式进行编码,这样才不会乱码。为了解决这个问题,我们就需要告诉axios将响应数据作为原始的字节流(ArrayBuffer)处理,而不是将其作为UTF-8字符串处理。可以通过设置responseType为'arraybuffer'来实现这一点。这样,当数据从服务器返回时,它将保持其原始的GBK编码。
import axios from 'axios'; function App() { const downloadFile = (content, filename) => { // 创建一个 Blob 对象 const blob = new Blob([content], { type: 'application/octet-stream' }); // 创建一个 a 标签 const link = document.createElement('a'); // 设置 href 为 Blob 对象 link.href = URL.createObjectURL(blob); // 设置下载的文件名 link.download = filename; // 将 a 标签添加到 DOM document.body.appendChild(link); // 触发下载 link.click(); // 从 DOM 移除 a 标签 document.body.removeChild(link); // 释放 Blob URL URL.revokeObjectURL(link.href); } const csvDownLoad = () => { axios.get(' http://localhost:3001/api/csv-data',{ responseType: 'arraybuffer' }).then(response => { downloadFile(response.data,'测试CSV下载.csv') }).catch(error => { console.log(error); }); } return <button onClick = {csvDownLoad}>下载CSV文件</button>; } export default App;