Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tatsuyasusukida/8937f63d1baa1833910a7d2b6200df3d to your computer and use it in GitHub Desktop.
Save tatsuyasusukida/8937f63d1baa1833910a7d2b6200df3d to your computer and use it in GitHub Desktop.
⬆️ Node.js file upload example without using multipart/form-data [video version available]

⬆️ Node.js file upload example without using multipart/form-data [video version available]

Video thumbnail: Node.js file upload example without using multipart/form-data

About this article

This article describes you how to upload files in Node.js without using multipart/form-data. The related resources are as follows.

Procedure

The procedure is as follows:

  1. Preparing for coding
  2. Coding
  3. Check

Preparing for coding

Open a terminal and execute the following command.

mkdir nodejs-upload-non-multipart
cd nodejs-upload-non-multipart
npm init -y
touch client.js index.html server.js

Coding

index.html

Open index.html in your editor and enter the following content.

Click to go to index.html

client.js

Open client.js in your editor and enter the following content.

Click to go to client.js

The points are as follows:

  1. If you need to send some parameters, use a query string.
  2. Specify the file in the body of the fetch function call.

server.js

Open server.js in your editor and enter the following content.

Click to go to server.js

The points are as follows:

  1. Get the request body as a buffer.
  2. Write the file using the fsPromises.writeFile function. Create a directory using the fsPromises.mkdir function before writing the file.

Check

Execute the following command to start the server.

node server.js

Go to http://localhost:3000/ in your browser.

Select the file and then click the submit button.

Confirm that the selected file has been uploaded.

Conclusion

I think the advantage of the method described in this article is that it consumes less memory than the method using multipart/form-data.

If the server sends the received file to cloud storage such as Amazon S3, you don't need to write the file to local storage. If the file you are uploading is large, it is better to use the fs.createWriteStream function instead of getting the request body as a buffer.

If you have any questions, please feel free to comment. Thank you for reading!

/node_modules/
/upload/
/package-lock.json
# Do not ignore package-lock.json other than gist.
main()
function main () {
try {
const image = document.querySelector('#image')
const submit = document.querySelector('#submit')
const message = document.querySelector('#message')
submit.addEventListener('click', async (event) => {
try {
event.preventDefault()
const [file] = image.files
if (!file) {
message.innerHTML = 'Please select file'
return
}
const filename = file.name
const search = '?' + new URLSearchParams({filename})
const url = '/api/v1/upload' + search // <1>
const response = await fetch(url, {
method: 'POST',
body: file // <2>
})
if (response.status === 201) {
message.innerHTML = 'Upload completed'
} else {
message.innerHTML = 'Upload failed: '
message.innerHTML += `status = ${response.status}`
}
} catch (err) {
console.error(err)
}
})
} catch (err) {
console.error(err)
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Node.js file upload example without using multipart/form-data</title>
</head>
<body>
<h1>Node.js file upload example without using multipart/form-data</h1>
<form>
<div>
<label for="image">Image</label>
<input type="file" name="image" id="image" accept="image/*">
</div>
<button type="submit" id="submit">Submit</button>
<p id="message"></p>
</form>
<script src="client.js"></script>
</body>
</html>
{
"name": "nodejs-upload-non-multipart",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.1"
}
}
const path = require('path')
const fsPromises = require('fs/promises')
const express = require('express')
if (require.main === module) {
main()
}
async function main () {
try {
const router = express()
router.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'))
})
router.get('/client.js', (req, res) => {
res.sendFile(path.join(__dirname, 'client.js'))
})
router.post('/api/v1/upload', async (req, res, next) => {
try {
const buffer = await new Promise((resolve, reject) => {
const chunks = []
req.on('data', (chunk) => chunks.push(chunk))
req.on('end', () => resolve(Buffer.concat(chunks)))
req.on('error', (err) => reject(err))
}) // <1>
const {filename} = req.query
const basename = path.basename(filename)
const dirname = path.join(__dirname, 'upload')
const destination = path.join(dirname, basename)
await fsPromises.mkdir(dirname, {recursive: true})
await fsPromises.writeFile(destination, buffer) // <2>
res.status(201).end()
} catch (err) {
next(err)
}
})
const port = parseInt(process.env.PORT || '3000', 10)
router.listen(port, () => {
console.info(`Listening on ${port}`)
})
} catch (err) {
console.error(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment