We can upload file with original file name and provide downloadable link by static web server.
Version
Node 16.16.0
Express 4.17.1
Alpine 3.10.3
Alpine
Upload a single file by Alpine and Express with the original file name and provide downloadable link.
<!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
:withfileUpload
Object to control the componentx-ref
:to set the name for the DOM element@click
:upload the file to the serverx-text
:display the result message
Line 17
let formData = new FormData();
formData.append("file", this.$refs.upload.files[0]);
fetch()
acceptsFormData
as an argument forbody
- Append the
file
key for the 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 methodPOST
and bodyformData
response.json()
:fetch()
returns Promise with Response Object, usejson()
to convert Response Object to JSON Object
Express
import express, { json, static as web } from 'express'
import cors from 'cors'
import multer, { diskStorage } from 'multer'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
let __filename = fileURLToPath(import.meta.url)
let __dirname = dirname(__filename)
let app = express()
app.use(cors())
app.use(json())
app.use(web(__dirname))
let storage = diskStorage({
destination(req, file, cb) {
cb(null, 'uploads')
},
filename(req, file, cb) {
cb(null, file.originalname)
},
})
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, static as web } from 'express'
import cors from 'cors'
import multer, { diskStorage } from 'multer'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
- Import
express
、cors
andmulter
- Import
path
fordirname()
- Import
url
forfileURLToPath
Line 7
let __filename = fileURLToPath(import.meta.url)
import.meta.url
:get the file URL of the current module. For example:file:///Users/oomusou/code/express/express-lab/app.js
fileURLToPath()
:return the fully-resolved platform-specific Node file path. For example:/Users/oomusou/code/express/express-lab/app.js
Line 8
let __dirname = dirname(__filename)
dirname()
:return the directories from a file path
Line 10
let app = express()
- Create
app
Object for Express
Line 11
app.use(cors())
- Create
cors
middleware bycors()
- Use
cors
middleware by Express
Line 12
app.use(json())
- Create
json
middleware byjson()
. This is a built-in middleware by Express - Use
json
middleware by Express
Line 13
app.use(web(__dirname))
- Use project root directory as the home directory of the Web
Line 15
let storage = diskStorage({
destination(req, file, cb) {
cb(null, 'uploads')
},
filename(req, file, cb) {
cb(null, file.originalname)
},
})
- Use
diskStorage()
to createstorage
Object for Multer options destination
:determine within which folder the uploaded files should be storedfilename
:determine what the file should be named inside the folder
Line 24
let opts = multer({ storage }).single('file')
- Create
opts
Object for Multer storage
:use thestorage
key for optionssingle
:upload single file by Multer, the argument forsingle()
must depend on the name for the input specified informData
in Alpine
Line 26
app.post('/upload', opts, (req, res) => {
res.json({ message: 'Successfully uploaded files' })
})
- Create
/upload
POST with Multer options - Return JSON Object with successful message
Line 30
app.listen(8080, () => {
console.log('Node listen on port: 8080')
})
- Express listens on port
8080
Conclusion
- If we want to control the file name of the uploaded file, the disk storage engine gives us full control on storing files to disk
- If we want to provide downloadable link with uploaded files, we can use Express to provide static web server