如何使用nodejs实现头像上传,上传多个图片并压缩生成大中小三种图片 (基于Koa2演示)
源码
这里我只是做个演示没有使用分层架构等规范开发流程
本Demo主要用到了
path、fs、koa-multer、jimp库实现上传逻辑
const Koa = require('koa');
const fs = require('fs');
const path = require('path');
const cors = require('@koa/cors');
const Router = require('koa-router');
const Multer = require('koa-multer');
const Jimp = require('jimp');
const app = new Koa();
const router = new Router();
app.use(cors({
origin: '*',
allowMethods: ['GET', 'POST'],
allowHeaders: ['Content-Type', 'Authorization']
}));
const AVATAR_PATH = "./uploads/avatar" //头像路径
const PICTURE_PATH = "./uploads/picture" //图片路径
// 创建的一个 Multer 实例,用于处理头像上传
const avatarUpload = Multer({
dest: AVATAR_PATH
});
// 创建另一个 Multer 实例,用于处理图片上传
const pictureUpload = Multer({
dest: PICTURE_PATH
});
// 创建全局信息用于返回图片(不推荐 只是演示用一下)
let GlobalInfofilename = null
let GlobalInfomimetype = null
let GlobalInfosize = null
// 处理单个图片:处理表单中字段名为 'avatar' 的单个文件上传(其实就是中间件)
const avatarHandler = avatarUpload.single('avatar');
// 处理多个图片:
const pictureHandler = pictureUpload.array('picture', 9);
// 保存头像信息
function saveAvatarInfo(ctx, next) {
const { filename, mimetype, size } = ctx.req.file;
// 将信息保存到全局(你也可以根据userid去保存到数据库中后期用sql查出来也行)
// 注意:中间件函数中修改全局变量是一个不推荐的做法,尤其是在并发请求的情况下(这里只是演示一下用法)
GlobalInfofilename = filename;
GlobalInfomimetype = mimetype;
GlobalInfosize = size;
// 2.将图片地址保存到user表中(TODO...)
// 4.返回结果
ctx.body = {
code: 200,
message: '上传成功',
data: {
filename,
mimetype,
size
}
}
}
// 查看头像
function viewAvatar(ctx, next) {
// 你可以根据userid去数据库中查询头像信息,然后返回给前端(这里比较重要的就是filename,mimetype,size)
// 0.获取用户id到数据库中查询头像信息(TODO...)
const { userId } = ctx.params;
console.log("传递的UserId为:", userId)
// 1.提供图像信息
ctx.response.set('content-type', GlobalInfomimetype);
// 2.创建可读流返回出去
ctx.body = fs.createReadStream(`${AVATAR_PATH}/${GlobalInfofilename}`);
}
// 处理图片生成多种尺寸图片(方案一:不带后缀名保存 —— 很快)
const pictureResize = async (ctx, next) => {
try {
// 1.获取所有的图像信息
const files = ctx.req.files;
// 2.对图像进行处理(sharp/jimp)
for (let file of files) {
const destPath = path.join(file.destination, file.filename);
console.log(destPath);
Jimp.read(file.path).then(image => {
image.resize(1280, Jimp.AUTO).write(`${destPath}-large`);
image.resize(640, Jimp.AUTO).write(`${destPath}-middle`);
image.resize(320, Jimp.AUTO).write(`${destPath}-small`);
});
}
await next();
} catch (error) {
console.log(error);
}
}
// 处理图片生成多种尺寸图片(方案二:带后缀名保存 —— 很慢)
// const pictureResize = async (ctx, next) => {
// try {
// // 1. 获取所有的图像信息
// const files = ctx.req.files;
// // 2. 对图像进行处理(Jimp)
// for (let file of files) {
// // 获取文件扩展名
// const ext = path.extname(file.originalname);
// // 组合完整的目标路径(包含扩展名)
// const destPath = path.join(file.destination, `${file.filename}${ext}`);
// console.log(destPath);
// // 重命名文件,并保存到本地(添加扩展名)
// const originalPath = path.join(file.destination, file.filename);
// fs.renameSync(originalPath, destPath);
// // 读取文件并生成不同尺寸的图片
// await Jimp.read(destPath).then(image => {
// image.resize(1280, Jimp.AUTO).write(`${destPath}-large${ext}`);
// image.resize(640, Jimp.AUTO).write(`${destPath}-middle${ext}`);
// image.resize(320, Jimp.AUTO).write(`${destPath}-small${ext}`);
// });
// }
// await next();
// } catch (error) {
// console.log(error);
// }
// }
// 保存多个图片的逻辑
function savePictureInfo(ctx, next) {
// 1.获取图像信息
const files = ctx.req.files;
// const { id } = ctx.xxx; // 你也可以根据id去数据库中查询xxx信息
// const { xxxid } = ctx.xxx; // 你也可以根据xxxid去数据库中查询xxx信息
// 2.将所有的文件信息保存到数据库中
for (let file of files) {
const { filename, mimetype, size } = file;
console.log(filename, mimetype, size);
// 3.将图片地址保存到数据库中(TODO...)
}
ctx.body = {
code: 200,
message: '上传成功',
}
}
// 上传头像路由
router.post('/uploadavatar', avatarHandler, saveAvatarInfo);
// 上传多个图片路由
router.post('/uploadavatars', pictureHandler, pictureResize, savePictureInfo);
// 查看头像路由
router.get("/viewavatar/:userId", viewAvatar);
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log('服务启动成功🚀:http://localhost:3000');
});
package.json
{
"name": "file-upload-and-download",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@koa/cors": "^5.0.0",
"jimp": "^0.22.12",
"koa": "^2.15.3",
"koa-cors": "^0.0.16",
"koa-multer": "^1.0.2",
"koa-router": "^12.0.1"
}
}