fileupload 文件上传

214 阅读5分钟

了解文件上传情况

  • 在前端把本地的img视频,音频之类的文件
  • 发送给服务端,服务端存储在服务器里面
  • 把文件地址存储在数据库里

前端上传的操作

表单直接上传

  • input
    • type 选择成file
    • name 设置一个名字
  • form标签的设置
    • action 设置服务器地址
    • method POST方式
    • enctype multipart/form-data
      • enctype 请求头里面的 content-type

      • multipart 设置以二进制流的形式上传


  <form action="http://localhost:8080/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="avatar">
    <input type="text" name="username">
    <button>上传</button>
  </form>

原生JS上传

  • 需要用HTTP/2.0的技术
  • 一个内置构造函数叫做FormData()
    • 语法:new FormData(form元素)
    • 返回一个包含form元素里面所有带有name属性元素的值
  • 直接打印看不到
  1. 获取元素绑定事件

  2. 拿到文件

  3. 正常AJAX发送

    // 1. 获取元素绑定事件
        const form = document.querySelector('form')
        form.addEventListener('submit', function (e) {
          e.preventDefault()
    
          // 2. 拿到文件
          const formData = new FormData(this)
    
          // 3. 正常 ajax 发送
          const xhr = new XMLHttpRequest()
    
          xhr.open('POST', '地址')
    
          // 不需要单独设置请求头
          // 因为 formData 会自动设置请求头
          xhr.send(formData)
    
          xhr.onload = function () {
    
          }
    
        })
    

jQuery上传文件

  • 和原生JS基本一致,就是绑定事件

  • 使用formData()拿到数据

  • 使用$.ajax()

      $('form').submit(function (e) {
          e.preventDefault()
    
          const formData = new FormData($('form')[0])
    
          $.ajax({
            method: 'POST',
            url: 'http://localhst:8080/upload',
            data: formData,
            contentType: false, // 不要动请求头, 直接上传
            processData: false, // 不要管我的数据, 直接上传
            success (res) {
              console.log(res)
            }
          })
    
    
    
        })
    
  1. 问题
    • formData 会自定设置请求头,但jQuery不会
    • jQuery会默认设置成 application/x-www-form-urlencoded
    • formData 以二进制流
    • jQuery

后端接收文件以后存储起来

单文件上传

单文件上传的简单版本
  • 解决跨域问题

    • 下载一个包叫cors
  • 接受文件

    • 准备一个文件夹,在服务器上存储上传的文件
    • 需要一个插件multer 进行下载导入
  • 需要使用multer配置一个接收器

    • multer(dest:'')}
  • 使用接收器接收文件

    • 哪一个路由需要接收文件,配置在哪一个文件上
    • 写在路由标识符后面,路由出来函数的前面
    • 接收器.single('前端上传文件的key‘)
  • 在路由处理函数里面

    • 会在 req 上面多加一个信息叫做 file

    • 就是你上传的文件的信息

    • 注意: 会把你的文件存储起来, 但是没有后缀, 随机命名

      const express = require('express')
      const router = express.Router()
      // 1. 导入 cors 插件
      const cors = require('cors')
      
      // 2-2. 导入 multer 插件
      const multer = require('multer')
      
      // 2-3. 使用 multer 去生成一个接收其
      //      我配置的这个接收器, 将来接收到的文件就直接存储在 指定目录
      const fileUpload = multer({ dest: '../uploads/' })
      
      const app = express()
      
      // 1. 挂载上 cors 就跨域了
      app.use(cors())
      
      // 2-4. 在需要的路由上进行配置
      router.post('/upload', fileUpload.single('avatar'), (req, res) => {
        console.log('接收请求')
        console.log(req.file)
      })
      
      app.use(router)
      
      app.listen(8080, () => console.log(8080))
      
      
单文件上传的复杂版本
  • 解决跨域问题

    • 下载一个包叫cors
  • 接受文件

    • 准备一个文件夹,在服务器上存储上传的文件
    • 需要一个插件multer 进行下载导入
  • 生成一个仓库信息

    • multer.deskStorage({配置})
      • destitnation:function({}) 设置存储路径
      • filename:function(){}设定文件名称
    • 返回值:是一个仓库信息
  • 使用multer生成一个接收器

    • 接收器里面配置一个仓库信息
    • 语法:multer({storage: 仓库信息})
    const express = require('express')
    const path = require('path')
    const router = express.Router()
    // 1. 导入 cors 插件
    const cors = require('cors')
    
    // 2-2. 导入 multer 插件
    const multer = require('multer')
    
    // 2-3. 使用 multer 生成一个仓库信息
    const storage = multer.diskStorage({
      destination: function (req, file, cb) {
        // req, 本次请求信息
        // file, 本次请求的文件
        // cb, 回调函数, 利用回调函数来设定存储路径
        // 第一个参数 null, 表示不要修改我的 二进制流 文件
        cb(null, '../uploads/')
      },
      filename: function (req, file, cb) {
        // req, 本次请求信息
        // file, 本次上传的文件信息
        // cb, 回调函数, 通过回调函数来设定文件名称
        // 从 file 信息里面把后缀名拿出来, 前面我们自己拼接随机数
        const tmp = path.extname(file.originalname)
        cb(null, `avatar_${ new Date().getTime() }-${ Math.random().toString().slice(2) }${ tmp }`)
      }
    })
    
    // 2-4. 配置接收器, 带有仓库信息
    const fileUpload = multer({ storage })
    
    const app = express()
    
    // 1. 挂载上 cors 就跨域了
    app.use(cors())
    
    // 2-5. 使用我们配置好的接收其去接收文件
    router.post('/upload', fileUpload.single('avatar'), (req, res) => {
      console.log('接收请求')
      console.log(req.file)
    })
    
    app.use(router)
    
    app.listen(8080, () => console.log(8080))
    
    

单名称多文件上传

  • 解决跨域问题

    • 下载一个包叫cors
  • 接受文件

    • 准备一个文件夹,在服务器上存储上传的文件
    • 需要一个插件multer 进行下载导入
  • 生成一个仓库信息

    • multer.deskStorage({配置})
      • destitnation:function({}) 设定存储路径
      • filename:function(){}设定文件名称
    • 返回值:是一个仓库信息
  • 使用multer生成一个接收器

    • 接收器里面配置一个仓库信息
    • 语法:multer({storage: 仓库信息})
  • 使用方法发生一些变换

    • single 方法是专门接收单文件,一个名称配一个文件
    • array 方法是专门接收多文件,一个名称配多个文件
    • 在后面的路由处理函数里面就不能接收 req.file
      • file 只是接收单文件
      • files 接收多文件(以一个数组的形式, 里面存储着每一个文件信息)
const express = require('express')
const path = require('path')
const router = express.Router()
// 1. 导入 cors 插件
const cors = require('cors')

// 2-2. 导入 multer 插件
const multer = require('multer')

// 2-3. 使用 multer 生成一个仓库信息
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // req, 本次请求信息
    // file, 本次请求的文件
    // cb, 回调函数, 利用回调函数来设定存储路径
    // 第一个参数 null, 表示不要修改我的 二进制流 文件
    cb(null, '../uploads/')
  },
  filename: function (req, file, cb) {
    // req, 本次请求信息
    // file, 本次上传的文件信息
    // cb, 回调函数, 通过回调函数来设定文件名称
    // 从 file 信息里面把后缀名拿出来, 前面我们自己拼接随机数
    const tmp = path.extname(file.originalname)
    cb(null, `avatar_${ new Date().getTime() }-${ Math.random().toString().slice(2) }${ tmp }`)
  }
})

// 2-4. 配置接收器, 带有仓库信息
const fileUpload = multer({ storage })

const app = express()

// 1. 挂载上 cors 就跨域了
app.use(cors())

// 2-5. 使用我们配置好的接收其去接收文件
router.post('/upload', fileUpload.array('avatar'), (req, res) => {
  console.log('接收请求')
  console.log(req.file)
  console.log(req.files)
})

app.use(router)

app.listen(8080, () => console.log(8080))

多名称多文件上传

  • 解决跨域问题

    • 下载一个包叫cors
  • 接受文件

    • 准备一个文件夹,在服务器上存储上传的文件
    • 需要一个插件multer 进行下载导入
  • 生成一个仓库信息

    • multer.deskStorage({配置})
      • destitnation:function({}) 设定存储路径
      • filename:function(){}设定文件名称
    • 返回值:是一个仓库信息
  • 使用multer生成一个接收器

    • 接收器里面配置一个仓库信息
    • 语法:multer({storage: 仓库信息})
  • 使用方法发生一些变换

    • single 方法是专门接收单文件,一个名称配一个文件
    • array 方法是专门接收多文件,一个名称配多个文件
    • fields 方法是专门接收多文件,多个名称配多个文件
    • 在后面的路由处理函数里面就不能接收 req.file
      • file 只是接收单文件
      • files 接收多文件(以一个数组的形式, 里面存储着每一个文件信息)
  • 注意: 涉及到多个名称, 我们要一个一个标志好

const express = require('express')
const path = require('path')
const router = express.Router()
// 1. 导入 cors 插件
const cors = require('cors')

// 2-2. 导入 multer 插件
const multer = require('multer')

// 2-3. 使用 multer 生成一个仓库信息
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // req, 本次请求信息
    // file, 本次请求的文件
    // cb, 回调函数, 利用回调函数来设定存储路径
    // 第一个参数 null, 表示不要修改我的 二进制流 文件
    cb(null, '../uploads/' + file.fieldname)
  },
  filename: function (req, file, cb) {
    // req, 本次请求信息
    // file, 本次上传的文件信息
    // cb, 回调函数, 通过回调函数来设定文件名称
    // 从 file 信息里面把后缀名拿出来, 前面我们自己拼接随机数
    const tmp = path.extname(file.originalname)
    cb(null, `${ file.fieldname }_${ new Date().getTime() }-${ Math.random().toString().slice(2) }${ tmp }`)
  }
})

// 2-4. 配置接收器, 带有仓库信息
const fileUpload = multer({ storage })

const app = express()

// 1. 挂载上 cors 就跨域了
app.use(cors())

// 2-5. 使用我们配置好的接收其去接收文件
router.post('/upload', fileUpload.fields([
  { name: 'avatar' },
  { name: 'photo' }
]), (req, res) => {
  console.log('接收请求')
  console.log(req.file)
  console.log(req.files)
})

app.use(router)

app.listen(8080, () => console.log(8080))