前言
<form>
标签的属性enctype
设置以何种编码方式提交表单数据。可选的值有三个:
application/x-www-form-urlencoded
multipart/form-data
text/plain
第一种:这是默认的编码方式。它只处理表单域里的value
属性值,采用这种编码方式的表单会将表单域的值处理成URL方式。
第二种:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定的文件内容封装到请求参数里。
第三种:这种方式当表单的action
属性值为mailto:URL
的形式时比较方便,这种方式主要适用于直接通过表单发送邮件。
前端
<input type="file" name="pic">
标签用来提交文件。
要注意的是,这个标签的
value
值并不是所选择的文件内容,而是这个文件的完整路径名。
正如前面所说的,表单在提交表单时,如果采用默认编码方式,文件的内容是不会被提交的。 要提交文件内容要采用multipart/form-data
编码方式,这需要在服务器端从提交的二进制流中读取文件内容。
后端
中间件的使用方式一般分为两种:
- 使用
app.use
的形式 - 在路由中作为参数的形式使用
我们使用express的中间件 multer
来接收上传的文件,multer中间件是在路由中作为参数使用的。
- multer只会解析form设置为
enctype="multipart/form-data"
表单. - multer可以定制存储引擎
- multer会将上传的信息以及内容挂载到request对象上
具体的使用步骤:
第一 导入 multer 中间件
const multer = require('multer');
第二 调用 multer
const upload = multer({dest: 'uploads/'}); //不采用这种方式
multer 接受一个 options 对象,其中最基本的是 dest 属性,这将告诉 multer 将上传文件保存在哪。如果你省略 options 对象,这些文件将保存在内存中,永远不会写入磁盘。
dest的意思是选择一个路径去存储文件,但是这样写有一个小小的问题,存入进来的文件是没有后缀名的。所以我们用下面的配置项
我们一般会使用一个配置项:
const storage = multer.diskStorage({
// 用来配置文件上传的位置
destination: (req, file, cb) => {
// 调用 cb 即可实现上传位置的配置
cb(null, './public/uploads');
},
// 用来配置上传文件的名称(包含后缀)
filename: (req, file, cb) => {
//filename 用于确定文件夹中的文件名的确定。 如果没有设置 filename,每个文件将设置为一个随机文件名,并且是没有扩展名的。
// 获取文件的后缀
let ext = path.extname(file.originalname);
// 拼凑文件名
cb(null, file.fieldname + '-' + Date.now() + ext);
}
});
const upload = multer({storage: storage});
router.post('/uploader', upload.single('pic'), (req, res) => {
// upload.single('pic')意思是告诉multer只接收name是pic的单个文件
// 将上传成功的文件信息响应给浏览器
res.json(req.file);
})
重要:这里一定要注意一个路径问题,如果admin路由是被引入到app.js中使用的,在destination中设置路径时,设置的是相对于app.js的。
Tips
获取文件扩展名的方式(都是原生)
- path.parse()
- path.extname()
path.extname('index.html');
// 返回: '.html'
path.extname('index.coffee.md');
// 返回: '.md'
path.parse('/home/user/dir/file.txt');
// 返回:
// {
// root: '/',
// dir: '/home/user/dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }