面试题答案
一键面试优化策略
- 文件切片上传
- 原理:将大文件分割成多个小的切片,分别上传这些切片,减少单个请求的数据量,提高上传成功率和并发处理能力。
- 实现:在前端利用
Blob.slice()
方法对文件进行切片。例如:
function sliceFile(file, sliceSize) {
const slices = [];
let start = 0;
while (start < file.size) {
const end = Math.min(start + sliceSize, file.size);
slices.push(file.slice(start, end));
start = end;
}
return slices;
}
- 断点续传
- 原理:记录已经上传成功的切片,当上传中断后,只需要上传未成功的切片。
- 实现:
- 在前端,每次切片上传成功后,记录切片的相关信息(如切片序号、偏移量等)。可以使用
localStorage
或者在 Vuex 中存储。例如:
- 在前端,每次切片上传成功后,记录切片的相关信息(如切片序号、偏移量等)。可以使用
// 在 Vuex 的 mutation 中记录已上传切片
const mutations = {
SET_UPLOADED_SLICE(state, { sliceIndex, offset }) {
state.uploadedSlices[sliceIndex] = offset;
}
};
- 在后端,需要记录每个文件已成功上传的切片,当下次请求时,判断哪些切片还未上传。例如在 Node.js 中使用 `fs` 模块记录切片上传状态:
const fs = require('fs');
const path = require('path');
function saveUploadedSliceInfo(fileId, sliceIndex, offset) {
const infoFilePath = path.join(__dirname, 'uploadInfo', `${fileId}.json`);
let info = {};
try {
info = JSON.parse(fs.readFileSync(infoFilePath, 'utf8'));
} catch (e) {}
info[sliceIndex] = offset;
fs.writeFileSync(infoFilePath, JSON.stringify(info));
}
- 处理跨域问题
- CORS(跨域资源共享)
- 原理:服务端通过设置响应头来允许跨域请求。
- 配置:在 Node.js 中使用
cors
中间件。首先安装cors
:npm install cors
,然后在 Express 应用中配置:
- CORS(跨域资源共享)
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
- 代理服务器
- 原理:在开发环境下,通过配置代理服务器,将跨域请求转发到目标服务器,这样在浏览器看来,请求是同源的。
- 配置:在 Vue 项目中,可以通过
vue - cli
的vue.config.js
配置代理。例如:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://target - server - url',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
完整实现方案
- 前端
- Vue 组件结构:
<template>
<div>
<input type="file" @change="handleFileChange">
<button @click="startUpload">开始上传</button>
</div>
</template>
<script>
export default {
data() {
return {
file: null,
sliceSize: 1024 * 1024, // 1MB 切片大小
uploadedSlices: {}
};
},
methods: {
handleFileChange(e) {
this.file = e.target.files[0];
},
async startUpload() {
const slices = sliceFile(this.file, this.sliceSize);
for (let i = 0; i < slices.length; i++) {
if (this.uploadedSlices[i]) {
continue;
}
const formData = new FormData();
formData.append('file', slices[i]);
formData.append('sliceIndex', i);
try {
const response = await this.$axios.post('/api/upload', formData);
this.$store.commit('SET_UPLOADED_SLICE', { sliceIndex: i, offset: response.data.offset });
} catch (error) {
console.error('上传切片失败', error);
}
}
}
}
};
function sliceFile(file, sliceSize) {
const slices = [];
let start = 0;
while (start < file.size) {
const end = Math.min(start + sliceSize, file.size);
slices.push(file.slice(start, end));
start = end;
}
return slices;
}
</script>
- 后端(以 Node.js + Express 为例)
const express = require('express');
const cors = require('cors');
const app = express();
const multer = require('multer');
const path = require('path');
const fs = require('fs');
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
app.post('/upload', upload.single('file'), (req, res) => {
const { sliceIndex } = req.body;
const fileId = 'your - unique - file - id';
const uploadDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir);
}
const filePath = path.join(uploadDir, `${fileId}_${sliceIndex}`);
fs.writeFileSync(filePath, req.file.buffer);
saveUploadedSliceInfo(fileId, sliceIndex, req.file.buffer.length);
res.json({ offset: req.file.buffer.length });
});
function saveUploadedSliceInfo(fileId, sliceIndex, offset) {
const infoFilePath = path.join(__dirname, 'uploadInfo', `${fileId}.json`);
let info = {};
try {
info = JSON.parse(fs.readFileSync(infoFilePath, 'utf8'));
} catch (e) {}
info[sliceIndex] = offset;
fs.writeFileSync(infoFilePath, JSON.stringify(info));
}
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
以上代码实现了文件切片上传、断点续传以及跨域问题的处理,在实际应用中,还需要考虑更多的细节,如文件合并、错误处理等。