在 Web 开发中,图片上传是一个常见的需求,特别是对于大文件,为了提高上传效率和稳定性,常常需要将文件进行分片上传。本文将介绍如何利用 JavaScript 和 Axios 库实现图片分片上传功能。
HTML部分
首先,我们在 HTML 中创建一个文件上传的 input 元素,以及显示上传进度的 progress 元素和开始上传按钮。
html
<body>
// 上传组件
<input type="file" id="upload"/>
// 进度条
<progress id="progress" value="0" max="100"></progress>
// 上传按钮
<button id="start">开始上传</button>
</body>
JavaScript部分
然后,我们使用 JavaScript 编写上传功能。以下是 JavaScript 代码:
javascript
import axios from "axios";
// 上传组件
const upload = document.querySelector('#upload');
// 进度条
const progress = document.querySelector('#progress');
// 上传按钮
const start = document.querySelector('#start');
// 上传的服务器地址
const uploadApiPath = `http://localhost:8888/upload`;
// 点击开始上传按钮触发事件
start.addEventListener('click', () => {
// 获取文件
const [file] = upload.files;
if (!file) {
throw new Error('请选择文件');
}
// 分片大小,2MB
const chunkSize = 1024 * 1024 * 2;
// 创建文件切片
const createFileChunk = (file, size = chunkSize) => {
const fileChunkList = [];
let cur = 0;
while (cur < file.size) {
const chunk = file.slice(cur, cur + size);
fileChunkList.push(chunk);
cur += size;
}
return fileChunkList;
};
const chunks = createFileChunk(file);
// 上传文件切片
const uploadChunks = async (chunks) => {
const requestList = chunks.map((chunk, index) => {
const formData = new FormData();
formData.append('file', chunk);
formData.append('filename', file.name);
formData.append('index', index);
return { formData };
});
// 分片上传列表
const requestListLength = requestList.length;
// 已上传完成数
let completed = 0;
// 递归上传文件切片
const upload = async () => {
if (completed >= requestListLength) {
// 上传完成
console.log('上传完成');
return;
}
const request = requestList[completed];
try {
// 发送 POST 请求上传文件切片
const res = await axios.post(uploadApiPath, request.formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
// 更新上传进度
progress.value = Math.floor((completed + 1) / requestListLength * 100);
completed++;
await upload();
} catch (error) {
console.log(error);
}
};
await upload();
};
uploadChunks(chunks).then(r => {});
});
服务端部分
以下是服务端部分的代码,基于Express框架实现了文件上传的接口:
javascript
import express from 'express';
import bodyParser from 'body-parser';
import fileUpload from 'express-fileupload';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { existsSync, unlinkSync, writeFileSync, appendFileSync } from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const app = express();
// 开启跨域
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
})
// 处理urlencoded请求
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// 使用express-fileupload中间件处理文件上传
app.use(fileUpload({}));
// 处理静态文件
app.use('/', express.static('static'));
const port = 8888;
app.get('/', (req, res) => {
res.send({
code: 200,
message: 'Hello World!'
});
})
app.post('/upload', (req, res) => {
const { file } = req.files;
const { filename, index } = req.body;
console.log(file, filename, index)
const filePath = resolve(__dirname, `./static/${filename}`);
const url = `http://localhost:${port}/${filename}`
if (parseInt(index) === 0) {
if (existsSync(filePath)) {
// 文件已存在,删除
unlinkSync(filePath);
}
// 写入一个新文件
writeFileSync(filePath, file.data);
res.send({
code: 200,
message: '创建文件成功',
url
});
} else {
// 追加文件
appendFileSync(filePath, file.data);
res.send({
code: 200,
message: '追加文件成功',
url
});
}
})
app.listen(port, () => {
console.log(`Server is running on port http://localhost:${port}`);
})
通过本文的介绍,我们学习了如何使用 JavaScript 和 Axios 库实现图片分片上传功能,同时也了解了服务端部分的实现细节。这种方式可以提高大文件上传的效率和稳定性,是 Web 开发中常用的技术之一。
希望本文对您有所帮助,谢谢阅读!