小程式:Form上傳檔案到Node.js的Express伺服器
彙整項目
- 使用HTML form的2種post方法上傳檔案
- 使用javascript以put方法上傳檔案
- 針對表單上傳對應的伺服器端寫法
- 各種上傳對應的CURL指令(見註解)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const express = require('express'); | |
const bodyParser = require('body-parser'); | |
const app = express(); | |
const crypto = require('crypto'); | |
const multer = require('multer'); | |
const upload = multer(); | |
app.use(bodyParser.urlencoded({ extended: true })); | |
// app.use(express.urlencoded()); // deprecated | |
app.get('/', (req, res) => { | |
res.send(` | |
POST: | |
<form method="POST" action="/post"> | |
<input type="text" name="fieldName" value="name"> | |
<input type="file" name="uploadFile"> | |
<input type="file" name="uploadFile2"> | |
<input type="submit"> | |
</form> | |
POST form-urlencoded: | |
<form method="POST" action="/urlencoded" enctype="application/x-www-form-urlencoded"> | |
<input type="text" name="fieldName" value="name"> | |
<input type="file" name="uploadFile"> | |
<input type="file" name="uploadFile2"> | |
<input type="submit"> | |
</form> | |
POST form-data: | |
<form method="POST" action="/formdata" enctype="multipart/form-data"> | |
<input type="text" name="fieldName" value="name"> | |
<input type="file" name="uploadFile"> | |
<input type="file" name="uploadFile2"> | |
<input type="submit"> | |
</form> | |
PUT file: | |
<form class="put-form"> | |
<input type="file" name="uploadFile" multiple> | |
<input type="submit"> | |
</form> | |
<script src="postForm.js"></script> | |
`); | |
}); | |
// script for put form | |
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data | |
app.get('/postForm.js', function (req, res) { | |
res.type('text/javascript').send(` | |
var putForm = document.querySelector('form.put-form') | |
putForm.addEventListener('submit', submitPutForm) | |
function submitPutForm(e) { | |
e.preventDefault() | |
var files = e.target.elements[0].files; | |
for (var i = 0 ; i < files.length ; ++ i) { | |
openFile(files[i], | |
function (err, file) { | |
if (err) return console.error(err) | |
putBlob(file.name, file.data, | |
function (err, rsp) { | |
if (err) return console.error(err) | |
appendText(rsp); | |
} | |
) | |
} | |
) | |
} | |
e.target.reset(); | |
} | |
function appendText(text, root) { | |
if (!root) root = document.body | |
var p = document.createElement('p') | |
p.textContent = text | |
root.appendChild(p) | |
} | |
function openFile(file, cb) { | |
var r = new FileReader() | |
r.onload = function () { cb(null, {name: file.name, data: r.result}) } | |
r.onerror = function (error) { cb(error) } | |
r.readAsArrayBuffer(file) | |
} | |
function putBlob(name, blob, cb) { | |
var r = new XMLHttpRequest() | |
r.onerror = function (err) { cb(err) } | |
r.open("PUT", "/put/" + name) | |
r.onreadystatechange = function () { | |
if (r.readyState != 4) return | |
if (r.status != 200) return cb('response status != 200,' + r.status) | |
cb(null, r.responseText) | |
} | |
r.send(blob) | |
} | |
`); | |
}); | |
// the default post is urlencoded | |
app.post('/post', function (req, res) { | |
res.send(req.path + JSON.stringify(req.body)); | |
}); | |
// curl -d fieldName=name -d uploadFile="Screenshot from 2021-09-30 14-45-46.png" http://localhost:3000/urlencoded | |
app.post('/urlencoded', function (req, res) { | |
res.send(req.path + JSON.stringify(req.body)); | |
}); | |
function getInfoFromData(name, data) { | |
return { | |
name: name, | |
size: data.length, | |
md5: crypto.createHash('md5').update(data).digest('hex'), | |
sha1: crypto.createHash('sha1').update(data).digest('hex'), | |
sha256: crypto.createHash('sha256').update(data).digest('hex'), | |
} | |
} | |
// curl -F fieldName=name -F uploadFile=@"Screenshot from 2021-09-30 14-45-46.png" http://localhost:3000/formdata | |
app.post('/formdata', upload.any(), function (req, res) { | |
res.send(req.path + | |
JSON.stringify(req.body) + | |
JSON.stringify(req.files.map(f => getInfoFromData(f.originalname, f.buffer))) | |
); | |
}); | |
// curl -T "Screenshot from 2021-09-30 14-45-46.png" http://localhost:3000/put/ | |
// https://nodejs.dev/learn/get-http-request-body-data-using-nodejs | |
app.put('/put/:filename', async function (req, res) { | |
let filename = req.params.filename; | |
let buffers = []; | |
for await (const chunk of req) buffers.push(chunk); | |
let data = Buffer.concat(buffers); | |
res.send(req.path + JSON.stringify(getInfoFromData(filename, data))); | |
}); | |
const PORT = process.env.PORT || 3000; | |
app.listen(PORT, () => console.log('Port:', PORT)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"scripts": { | |
"start": "node index.js" | |
}, | |
"dependencies": { | |
"body-parser": "^1.19.0", | |
"crypto": "^1.0.1", | |
"express": "^4.17.1", | |
"multer": "^1.4.3" | |
} | |
} |
留言