通过原生表单或 ajax,实现 node.js 中的文件上传
后端功能
文件上传是开发中必不可少的功能,最常见的就是上传头像。本篇文章讲述如何使用不同的方式进行文件上传。在开始之前,我们先编写后端功能(node):
javascript
// router.js
import express from 'express'
import formidable from 'formidable'
import path from 'path'
const app = express()
app.post('/', (req, res, next) => {
const form = formidable({
uploadDir: path.resolve('uploads'), //临时文件位置
multiples: true,
maxFileSize: 20 * 1024 * 1024, //限制上传的大小
})
form.parse(req, (err, fields, files) => {
if (err) {
next(err)
return
}
res.json({ fields, files })
})
})
app.listen(5000, () => {
console.log('运行在5000端口')
})
// router.js
import express from 'express'
import formidable from 'formidable'
import path from 'path'
const app = express()
app.post('/', (req, res, next) => {
const form = formidable({
uploadDir: path.resolve('uploads'), //临时文件位置
multiples: true,
maxFileSize: 20 * 1024 * 1024, //限制上传的大小
})
form.parse(req, (err, fields, files) => {
if (err) {
next(err)
return
}
res.json({ fields, files })
})
})
app.listen(5000, () => {
console.log('运行在5000端口')
})
form 表单的相关属性
- action:服务器接收数据的 URL。
- method:提交数据的 HTTP 方法.
- enctype:当 method 属性等于 post 时,该属性指定提交给服务器的 MIME 类型。可能的值为 application/x-www-form-urlencoded(默认值),multipart/form-data(文件上传的情况),text/plain。
表单形式上传
接下来创建一个表单:
html
<form
action="http://localhost:5000"
id="myForm"
method="post"
enctype="multipart/form-data"
>
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required />
</div>
<div>
<label for="userfile">上传文件:</label>
<input type="file" id="userfile" name="avatar" required />
</div>
<input type="submit" value="Submit!" />
</form>
<form
action="http://localhost:5000"
id="myForm"
method="post"
enctype="multipart/form-data"
>
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required />
</div>
<div>
<label for="userfile">上传文件:</label>
<input type="file" id="userfile" name="avatar" required />
</div>
<input type="submit" value="Submit!" />
</form>
点击 submit 提交表单,此时浏览器会跳转页面,并且在浏览器显示后端解析后的对象,我们在控制台的 nextwork 中点击相应请求的 Preview 可以看到以对象形式展示的数据:
说明我们已经成功的上传了文件,我们可以查看与 router.js 同目录的 uploads 中多了一个没有后缀名的文件,它和前端上传文件的大小是相同的。接下来我们修改 router.js 文件,将上传的文件保存到“服务端”。
javascript
//引入 path fs
+ import Path from 'path'
+ import fs from 'fs'
//修改form.parse
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
const { path, name } = files.avatar
const new_path = Path.resolve('upload', fields.username + Path.extname(name))
const fsread = fs.createReadStream(path)
const fswrite = fs.createWriteStream(new_path)
fsread.pipe(fswrite)
fsread.on('end', () => {
res.send('ok')
})
});
//引入 path fs
+ import Path from 'path'
+ import fs from 'fs'
//修改form.parse
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
const { path, name } = files.avatar
const new_path = Path.resolve('upload', fields.username + Path.extname(name))
const fsread = fs.createReadStream(path)
const fswrite = fs.createWriteStream(new_path)
fsread.pipe(fswrite)
fsread.on('end', () => {
res.send('ok')
})
});
这个时候再次进行文件上传,会发现在 rouer.js 同目录下的 upload 中多了一个图片,文件名就是表单中输入的值。
ajax 上传
有时候我们不希望直接通过 form 表单提交数据,那么我们可以使用 ajax 进行文件上传。 在前端 html 中加入以下代码
javascript
const form = document.getElementById('myForm')
// 为 form 表单添加 submit 事件
form.addEventListener('submit', (e) => {
// 取消默认行为(提交)
e.preventDefault()
//创建 ajax 实例
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:5000', true)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
console.log(xhr.response)
}
}
//我们需要通过 form 表单创建FormData实例,然后直接发送到服务端
xhr.send(new FormData(form))
})
const form = document.getElementById('myForm')
// 为 form 表单添加 submit 事件
form.addEventListener('submit', (e) => {
// 取消默认行为(提交)
e.preventDefault()
//创建 ajax 实例
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:5000', true)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
console.log(xhr.response)
}
}
//我们需要通过 form 表单创建FormData实例,然后直接发送到服务端
xhr.send(new FormData(form))
})
之后我们进行文件上传,页面不会进行跳转,并且文件同样上传成功。