點燈坊

失くすものさえない今が強くなるチャンスよ

Upload File with Unique File Name and Extension

Sam Xiao's Avatar 2022-08-19

We can get file extension on the server and set unique file name and extension by Multer.

Version

Node 16.16.0
Express 4.17.1
Alpine 3.10.3

Alpine

ext000

Upload single file by Alpine and Express.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/alpinejs" defer></script>
    <title>Upload</title>
  </head>
  <body x-data="fileUpload">
    <input x-ref="upload" type="file" />
    <button @click="onClick">Upload</button>
    <div x-text="resMsg"></div>
  </body>
  <script>
    let fileUpload = {
      resMsg: '',
      async onClick() {
        let formData = new FormData()
        formData.append('file', this.$refs.upload.files[0])

        try {
          let res = await fetch(`http://localhost:8080/upload`, {
            method: 'POST',
            body: formData,
          })

          let data = await res.json()
          this.resMsg = data.message
        } catch (e) {
          console.error(e)
        }
      },
    }
  </script>
</html>

Line 8

<body x-data="fileUpload">
  <input x-ref="upload" type="file" />
  <button @click="onClick">Upload</button>
  <div x-text="resMsg"></div>
</body>
  • x-data:with fileUpload Object to control the component
  • x-ref:to set the name for the DOM element
  • @click:upload the file to the server
  • x-text:display the result message

Line 17

let formData = new FormData();
formData.append("file", this.$refs.upload.files[0]);
  • fetch() accepts FormData as argument for body
  • Append file key for uploaded file

Line 20

try {
  let res = await fetch(`http://localhost:8080/upload`, {
    method: 'POST',
    body: formData,
  })

  let data = await res.json()
  this.resMsg = data.message
} catch (e) {
  console.error(e)
}
  • Use fetch() API with method POST and body formData
  • response.json()fetch() returns Promise with Response Object, use json() to convert Response Object to JSON Object

Express

import express, { json } from 'express'
import cors from 'cors'
import multer, { diskStorage } from 'multer'

let app = express()
app.use(cors())
app.use(json())

let storage = diskStorage({
  destination(req, file, cb) {
    cb(null, 'uploads')
  },
  filename(req, file, cb) {
    let extension = file.originalname.split('.').pop()
    let uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9)
    let filename = `${file.originalname}-${uniqueSuffix}.${extension}`

    cb(null, filename)
  },
})

let opts = multer({ storage }).single('file')

app.post('/upload', opts, (req, res) => {
  res.json({ message: 'Successfully uploaded files' })
})

app.listen(8080, () => {
  console.log('Node listen on port: 8080')
})

Line 1

import express, { json } from 'express'
import cors from 'cors'
import multer, { diskStorage } from 'multer'
  • Import expresscors and multer

Line 5

let app = express()
  • Create app Object for Express

Line 6

app.use(cors())
  • Create cors middleware by cors()
  • Use cors middleware by Express

Line 7

app.use(json())
  • Create json middleware by json(). This is a built-in middleware by Express
  • Use json middleware by Express

Line 9

let storage = diskStorage({
  destination(req, file, cb) {
    cb(null, 'uploads')
  },
  filename(req, file, cb) {
    let extension = file.originalname.split('.').pop()
    let uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9)
    let filename = `${file.originalname}-${uniqueSuffix}.${extension}`

    cb(null, filename)
  },
})
  • Use diskStorage() to create storage Object for Multer options
  • destination:determine within which folder the uploaded files should be stored
  • filename:determine what the file should be named inside the folder, get extension from file.originalname, and set new name by cb()

Line 22

let opts = multer({ storage }).single('file')
  • Create opts Object for Multer
  • dest:set folder to place files
  • single:upload single file by Multer, the argument for single() must depend on the name for the input specified in formData in Alpine

Line 24

app.post('/upload', opts, (req, res) => {
  res.json({ message: 'Successfully uploaded files' })
})
  • Create /upload POST with Multer options
  • Use Object Destructuring to destructure req Object to get other POST data
  • Return JSON Object with successful message

Line 28

app.listen(8080, () => {
  console.log('Node listen on port: 8080')
})
  • Express listens on port 8080

Conclusion

  • We can get file extension on the server by file.originalname.split('.').pop()