前提:基于上一篇文章进行学习
1、后端搭建
使用nodejs、 express 框架搭建后端服务器
- 启动文件app.js
var express = require("express");
var http = require("http");
var fs = require('fs');
var app = express();
// 静态资源托管工具
app.use(express.static("./static"));
app.get("/", function(req, res) {
res.send("Hello");
})
app.post("/file/download", async function(req, res) {
res.setHeader('Access-Control-Allow-Origin','*');
function read() {
return new Promise((resolve, reject) => {
fs.readFile('./static/cat.jpg', function(err, data) {
resolve(data);
reject(err);
})
})
}
let data = await read();
res.send(data);
})
var httpServer = http.createServer(app);
const PORT = 3000;
const HOSTNAME = '0.0.0.0';
httpServer.listen(PORT, HOSTNAME, function() {
console.log('Server is running on http://' + HOSTNAME + ':%s', PORT);
})
静态资源文件目录static, 放置一张图片用于测试
- 启动服务器
node app.js
2、前端vue功能实现
- 页面
<template>
<div>
<el-button type="primary" @click="downloadFile" plain>下载</el-button>
</div>
</template>
<script>
import FileModel from '@/api/file.js';
import { dataToFile } from '@/utils/common/common.js';
export default {
name: 'fileDownLoad',
setup() {
const downloadFile = () => {
FileModel.fileExport().then(res => {
let params = {
data: res,
fileName: '1.jpg',
type: 'application/octet-stream'
}
dataToFile(params);
}).catch(err => {
console.log(err);
})
}
return {
downloadFile
}
}
}
</script>
- api下的file.js
import { exportFile } from "@/utils/http";
export default {
// 文件下载导出
fileExport(data = {}) {
return exportFile("/api/file/download", data);
}
};
- 调整接口封装逻辑utils/http.js
import axios from "./request";
function get(url, params) {
return new Promise((resolve, reject) => {
axios.get(url, {
params
}).then(response => {
resolve(response.data)
}, error => {
reject(error)
})
})
}
function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, params
).then(response => {
resolve(response.data)
}, error => {
reject(error)
})
})
}
function exportFile(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, params, {
responseType: 'blob'
}).then(response => {
resolve(response)
}, error => {
reject(error)
})
})
}
export {
get,
post,
exportFile
}
utils/request.js
import axios from "axios";
// 创建axios 实例
const service = axios.create({
baseURL: "/", // api的base_url
timeout: 10000 // 请求超时时间
});
// request 拦截器
service.interceptors.request.use(
config => {
// config.headers.Authorization = getCookie("Authorization");
// 这里可以自定义一些config 配置
return config;
},
error => {
// 这里处理一些请求出错的情况
Promise.reject(error);
}
);
// response 拦截器
service.interceptors.response.use(
response => {
const res = response.data;
// 这里处理一些response 正常放回时的逻辑
return res;
},
error => {
// 这里处理一些response 出错时的逻辑
return Promise.reject(error);
}
);
export default service;
此时请求接口,看到后台返回的文件流
- 处理文件流,对此功能进行了封装utils/common/common.js
使用blob、配合a标签的download属性实现文件的下载
common.js
function dataToFile(params) {
let type = params.type
let fileName = params.fileName
let data = params.data;
// 兼容 IE
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(new Blob([data]), fileName)
} else {
// 非IE 浏览器
const url = window.URL.createObjectURL(new Blob([data], { type }))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', `${fileName}`)
document.body.appendChild(link)
link.click()
window.URL.revokeObjectURL(url); // 释放内存
}
}
export {
dataToFile
}
3、接口请求跨域处理
项目根目录下新建vue.config.js
const path = require("path");
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://127.0.0.1:3000",
changeOrigin: true,
pathRewrite: {
"^/api": "/"
}
}
}
}
};
项目地址: https://gitee.com/smallgrey/vue3-element-ui
微信公众号:趣享编程