使用nuxt3-提供文件上传

741 阅读2分钟

我们知道 nuxt3是一个全栈框架, 可以单纯的只写前端,也可以写后端接口, 今天我们使用 nuxt3写一个 文件上传接口

express 中,我们需要借助 multer 等 包进行文件文件上传操作, 我们看看 nuxt3 可以怎么处理

00659-2574501837.png 00677-2439749082.png

安装依赖

pnpm add uuid -S

为了防止前端上传的文件名 重名覆盖的问题,这里使用 uuid 生成文件名

我们将上传后的文件,写入到 public/uploads 目录, 请提前创建好 这个目录

代码实现

  1. server/api 下面创建一个 upload.ts 文件, 这个就是一个接口

  2. 创建接口的基础雏形

export default defineEventHandler(async (event) => {
    ... 业务代码
})

这里其实没有看到 GET, POST等请求方式的区分,你可以理解为 expressall

只要请求地址 http://localhost:3000/api/upload 都会走这里, 不区分 method

  1. 写代码
  • 使用流和管道 进行文件的读写
  • 使用 readMultipartFormData API 读取 body中的表单内容, readMultipartFormData 是 h3提供的,在nuxt3中属于全局的API
  • 支持多文件上传
import { createWriteStream } from 'node:fs'
import { fileURLToPath } from 'url'
import { pipeline, PassThrough } from 'node:stream'
import { v4 as uuidV4 } from 'uuid'
import path from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

/**
 * 支持多个文件上传
 */
export default defineEventHandler(async (event) => {
  // 使用 表单上传文件, readBody是不能解析的,它解析的是 json 格式的数据
  // let r1 = await readBody(event)

  const form = await readMultipartFormData(event)

  // form-data 里面什么都没有,这里form解析的就是 undefined
  if (!form) {
    return {
      code: 1000,
      data: null,
      message: '上传文件不存在'
    }
  }

  const allFiles = form.filter((item) => item.type)

  let filePromise = allFiles.map((item) => {
    let filename = uuidV4() + path.parse(item!.filename!).ext

    // 创建写的文件流
    const filePath = path.resolve(__dirname, '../../', `public/uploads/${filename}`)

    const wirteStream = createWriteStream(filePath)

    let data = item.data as Buffer

    // 创建一个可读流, item.data 是一个Buffer
    const readStream = new PassThrough().end(data)

    return new Promise((resolve, reject) => {
      pipeline(readStream, wirteStream, (err) => {
        if (err) {
          reject(err)
          console.log('报错了')
          console.log(err)

          return
        }

        resolve({
          url: `http://localhost:3000/uploads/${filename}`,
          type: item.type
        })
      })
    })
  })

  try {
    let res = await Promise.all(filePromise)

    return {
      code: 0,
      data: res,
      message: '上传成功'
    }
  } catch (error: any) {
    console.log('文件上传报错')
    console.log(error)
    return {
      code: 1000,
      data: null,
      message: '上传失败' + error.message
    }
  }
})

测试

image.png

image.png

image.png

是不是相当的简单。

465766696-2678277711-mw_3dmh,-fangs,-full-body,-dragon,-blue-eyes,-smile,-red-hair,-simple-background,-closed-mouth,-claws,-fangs-out,-jewelry,-stand (1).gif

参考资料