Antd 4 Upload 图片上传(后端篇)

简介

这篇文章是Antd 4 Upload 图片上传(前端篇)的后续,使用nodejsexpress搭建服务端,使用multer处理文件上传,将前端上传的文件保存到服务端。

实现

创建一个新的文件夹作为后端服务:

  1. 初始化npm

    npm init -y
    
  2. 安装expressmulter

    npm i express multer
    

运行简单的服务

创建入口文件index.js,创建一个简单的Web服务:

const express = require('express')
const app = express()
const port = 8000

app.listen(port, () => {
  console.log(`http://localhost:${port}`)
})

CORS 和 路由

1. CORS 跨域

由于前后端运行在不同的端口上,属于跨域请求,我就直接在后端做操作吧。

首先前端使用了Ant DesignUpload组件,它的action属性是通过POST请求提交FormData数据,并且带有x-requested-with请求头,那么我们先处理OPTION检请求:

// 处理所有的 OPTIONS 预检请求
app.options('*', (req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  res.setHeader('Access-Control-Allow-Headers', 'x-requested-with')
  next()
})

然后在写一个用来允许跨域的中间件cors

// 跨域中间件
const cors = (req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  next()
}

2. 路由

我们先定义好一个multer用来文件上传的中间件,创建好文件夹public,还有子文件夹uploads

const path = require('path')
const multer = require('multer')
const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, cb) {
      // 上传文件存在 public/uploads 下
      cb(null, 'public/uploads')
    },
    filename(req, file, cb) {
      // 使用时间戳作为上传的文件名
      const extname = path.extname(file.originalname)
      cb(null, Date.now() + extname)
    }
  })
})

然后添加前端请求的/upload路由来处理文件上传,给前端返回JSON数据,数据包含上传文件的文件名以及该文件在服务端的存储位置。

// 使用前面定义好的 cors 中间件和 upload 中间件
app.post('/upload', cors, upload.single('file'), (req, res) => {
  const { file: { filename, path } } = req
  res.json({
    ok: true,
    message: '图片上传成功',
    data: {
      name: filename,
      url: path
    }
  })
})

然后我们还需要让这些上传的静态资源可以访问:

app.use('/public', express.static(path.join(__dirname, 'public')))

错误处理

比如前面的中间件upload出现错误,我们可以在路由后面添加一个错误处理,返回给前端。

// 处理前面发生的错误
app.use((err, req, res, next) => {
  console.log(err + '')
  res.json({
    ok: false,
    message: '服务器错误'
  })
})

补充:删除文件

添加一个删除上传的文件的API:

const fs = require('fs')

// 客户端请求体的JSON
app.use(express.json())

// delete删除请求
app.delete('/delete', cors, async (req, res,next) => {
  const { path } = req.body
  fs.unlink(path, (err) => {
    if (err) return next(err)
    res.json({
      ok: true,
      message: '删除图片成功'
    })
  })
})

这个路由使用了DELETE请求方法,而且传了JSON数据,我们需要修改下OPTIONS处理的响应头:

app.options('*', (req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  // 追加允许的请求方法
  res.setHeader('Access-Control-Allow-Methods', 'POST, DELETE')
  // 客户端发了JSON 追加允许的请求头 Content-Type
  res.setHeader('Access-Control-Allow-Headers', 'x-requested-with,Content-Type')
  next()
})

完整代码

const express = require('express')
const app = express()
const port = 8000
const path = require('path')
const multer = require('multer')
const fs = require('fs')

// 文件上传
const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, cb) {
      // 上传文件存在 public/uploads 下
      cb(null, 'public/uploads')
    },
    filename(req, file, cb) {
      // 使用时间戳作为上传的文件名
      const extname = path.extname(file.originalname)
      cb(null, Date.now() + extname)
    }
  })
})

// 静态资源
app.use('/public', express.static(path.join(__dirname, 'public')))

// 处理所有的 OPTIONS 预检请求
app.options('*', (req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  // 追加允许的请求方法
  res.setHeader('Access-Control-Allow-Methods', 'POST, DELETE')
  // 客户端发了JSON 追加允许的请求头 Content-Type
  res.setHeader('Access-Control-Allow-Headers', 'x-requested-with,Content-Type')
  next()
})

// 跨域中间件
const cors = (req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  next()
}

// 使用前面定义好的 cors 中间件和 upload 中间件
app.post('/upload', cors, upload.single('file'), (req, res) => {
  const { file: { filename, path } } = req
  res.json({
    ok: true,
    message: '图片上传成功',
    data: {
      name: filename,
      url: path
    }
  })
})

// 解析客户端请求的JSON数据
app.use(express.json())

// 删除文件
app.delete('/delete', cors, async (req, res, next) => {
  // const { path } = req.body
  const path = '11'
  fs.unlink(path, (err) => {
    if (err) return next(err)
    res.json({
      ok: true,
      message: '删除图片成功'
    })
  })
})

// 处理前面发生的错误
app.use((err, req, res, next) => {
  console.log(err + '')
  res.json({
    ok: false,
    message: '服务器错误'
  })
})

app.listen(port, () => {
  console.log(`http://localhost:${port}`)
})

版权声明:

Anand's Blog文章皆为站长Anand Zhang原创内容,转载请注明出处。

包括商业转载在内,注明下方要求的文章出处信息即可,无需联系站长授权。

请尊重他人劳动成果,用爱发电十分不易,谢谢!

请注明出处:

本文出自:Anand's Blog

本文永久链接:https://anandzhang.com/posts/frontend/15