koa处理上传图片

简介: koa处理上传图片

我们都知道图片的存储是二进制的。当上传图片的时候,如果不使用第三方库,那么解析body是非常麻烦的。所以下面我们就来看看如何通过koa以及相关库,来对上传的图片处理吧。


以下代码及步骤只是给出参考的思路,具体代码请访问github


建立一个数据库,创建一个file表


async createAvatar (filename, mimetype, size, userId) {
        const state = `INSERT INTO avatar (filename, mimetype, size, user_id) VALUES (?, ?, ?, ?)`;
        const result = await connection.execute(state, [filename, mimetype, size, userId])
        return result[0]
      }


网络异常,图片无法展示
|


我们知道,一般做一些业务,最常见的就是上传用户图像或者一些大的action图片。就好比掘金来说,就是上传用户头像和文章背景图像。


处理头像的上传


对于koa来说,有一个库koa-multer可以方便我们处理上传的图片。具体的使用就不介绍了,具体请看以前的文章。koa的学习。并且,如果我们想要对图片做处理,我们可以通过jimp库,来操作。体积比较小。


首先我们需要封装一个图片上传的中间件。


const path = require("path")
    const multer = require("koa-multer");
    const Jimp = require("jimp");
    const { AVATAR_PATH, PICTURE_PATH } = require("../app/filePath");
    // 处理头像上传
    const avatarUpload = multer({
      dest: path.resolve(__dirname, AVATAR_PATH)
    })
    // 处理图片上传
    const pictureUpload = multer({
      dest: path.resolve(__dirname, PICTURE_PATH)
    })
    // 处理用户头像
    const avatarHandler = avatarUpload.single("avatar")
    // 处理action动态头像
    const pictureHandler = pictureUpload.array("picture")
    // 处理图片大小
    // 根据前端传入的w*h来确定图片的大小,这里就没有复杂处理,我们只做了大中小处理。
    const pictureResizeHandler = async (ctx, next) => {
      const files = ctx.req.files;
      for (let file of files) {
        Jimp.read(file.path).then(image => {
          // 根据宽度,高度自适应
          image.resize(1280, Jimp.AUTO).write(`${file.path}-large`);
          image.resize(640, Jimp.AUTO).write(`${file.path}-middle`);
          image.resize(320, Jimp.AUTO).write(`${file.path}-small`);
        })
      }
      await next()
    }
    module.exports = {
      avatarHandler,
      pictureHandler,
      pictureResizeHandler
    }


一般情况下,我们点击用户头像,都是通过http://localhost/users/avatar/:userId这样的方式访问。并且会将图片保存在user表中。


// 创建用户头像
      async createAvatar (ctx, next) {
        // 获取上传的头像信息。
        const { filename, mimetype, size } = ctx.req.file;
        const userId = ctx.user.id;
        const result = await createAvatar(filename, mimetype, size, userId)
        // 将头像的url保存到users表中
        const avatarUrl = `${APP_HOST}:${APP_PORT}/users/avatar/${userId}`
        await saveAvatar(avatarUrl, userId)
        ctx.body = result
      }


通过上面的操作,图片将被保存到本地指定的文件夹下,接下来,我们就需要通过读取数据库中头像的信息,来返回本地头像给用户了。


先来读取头像信息


// 获取头像图片详情
  async detailAvatar (userId) {
    const state = `SELECT * FROM avatar WHERE user_id = ?;`;
    const [result] = await connection.execute(state, [userId])
    return result.pop()
  }


下面我们就可以读取本地文件,返回头像。根据用户id


// 返回用户头像
      async getUserAvatar (ctx, next) {
        const { userId } = ctx.params;
        // 从数据库中获取当前图片的详情信息。然后用于本地获取图片。
        const avatarInfo = await detailAvatar(userId);
        // 2.提供图像信息,以便浏览器解析
        ctx.response.set('content-type', avatarInfo.mimetype);
        ctx.body = fs.createReadStream(path.resolve(__dirname, `${AVATAR_PATH}/${avatarInfo.filename}`));
      }


下面来看看效果吧


网络异常,图片无法展示
|


处理图片的上传


其实上传的过程都是一样的。只不过,我们还需要处理图片的大小,就是上面的中间件。 创建图片表,并且根据图片名称获取图片的详细信息。


// 创建动态图片
      async createPicture (filename, mimetype, size, userId, actionId) {
        const state = `INSERT INTO file (filename, mimetype, size, user_id, action_id) VALUES (?, ?, ?, ?, ?)`;
        const result = await connection.execute(state, [filename, mimetype, size, userId, actionId])
        return result[0]
      }


一般情况下,我们点击用户头像,都是通过http://localhost/actions/images/:filename?type=small这样的方式访问。由于图片和文章是多对一或者多对多的,所以我们需要将action_id保存在file表中。


// 创建action图像
      async createPicture (ctx, next) {
        const files = ctx.req.files;
        const userId = ctx.user.id;
        const actionId = ctx.request.query.actionId;
        for (let file of files) {
          const { filename, mimetype, size } = file
          await createPicture(filename, mimetype, size, userId, actionId)
        }
        ctx.body = "上传成功"
      }


通过上面的操作,图片将被保存到本地指定的文件夹下(并且保存了大中小三种大小的图片),接下来,我们就需要通过读取数据库中对应图片的信息,来返回本地图片。


先来读取头像信息, 根据图片名称(自动生成的名称)


// 获取图片详情
      async getActionPictureInfoByFileName (filename) {
        const state = `SELECT * FROM file WHERE filename = ?;`;
        const [result] = await connection.execute(state, [filename])
        return result
      }


下面我们就可以读取本地文件,返回图片信息了。根据图片名称,然后我们可以指定query的type字段来决定返回那种大小的图片。


// 返回action动态图片
  async getActionPictureByFileName (ctx, next) {
    // 通过params传入的filename
    const filename = ctx.request.params.filename;
    // 通过query传入的type
    const imageType = ctx.request.query.type;
    let imageUrl = ""
    const types = ["small", "middle", "large"];
    if (types.includes(imageType)) {
      imageUrl = path.resolve(__dirname, `${PICTURE_PATH}/${filename}-${imageType}`)
    } else {
      imageUrl = path.resolve(__dirname, `${PICTURE_PATH}/${filename}`)
    }
    const result = await getActionPictureInfoByFileName(filename)
    ctx.response.set("content-type", result[0].mimetype)
    ctx.body = fs.createReadStream(imageUrl)
  }


下面来看看效果吧


网络异常,图片无法展示
|

以上代码及步骤只是给出参考的思路,具体代码请访问github


相关文章
|
8天前
Koa图片上传
koa2一般处理 post 请求使用的是 koa-bodyparser,图片上传使用的是 koa-multer。 这两个在一起没什么问题,但是 koa-multer 和 koa-route(不是 koa-router) 存在不兼容的问题。 故,建议在koa中全局引入
42 0
|
7月前
|
中间件
84 # koa 实现文件上传功能
84 # koa 实现文件上传功能
37 0
|
JavaScript
【ElementUI】Vue+ElementUI多文件上传,一次请求上传多个文件!
教大家一次请求,上传多个文件。 ElementUI如果是默认方案,上传多张图片并不是真正的一次上传多张,而是发送多次请求,一次请求携带一张图片。
794 0
|
8天前
|
小程序 JavaScript
在使用微信小程序开发中用vant2框架中的Uploader 文件上传wx.uploadFile无反应和使用多图上传
网上有的说是bind:after-read="afterRead"的命名问题不支持-,但是我这儿执行了console.log("file",file);证明函数运行了。后来发现是multiple="true"原因开启了多图上传,如果是多图上传的话file就是数组了
100 2
|
6月前
|
JavaScript 前端开发
nodejs使用axios以formdata形式上传图片
nodejs使用axios以formdata形式上传图片
|
8天前
UEditor配置后端上传图片
UEditor配置后端上传图片
60 0
UEditor配置后端上传图片
|
9月前
|
前端开发 JavaScript 数据库
vue3如何上传图片
Vue3 上传图片可以使用 axios 库来发送 POST 请求,将图片上传到服务器,然后在前端展示或者保存到数据库中。
609 0
|
9月前
|
API
uniapp图片上传
uniapp图片上传
400 0
|
10月前
|
JavaScript 前端开发
vue3上传图片(组件上传)
vue3上传图片(组件上传)
304 0
|
10月前
|
JavaScript
js实现简单上传图片
js实现简单上传图片