Form表单enctype属性
enctype用于指定提交给后端的数据的编码格式。可选属性为:text/plain,multipart/form-data,以及application/x-www-form-urlencoded,它们用来控制表单中的数据的编码格式。它们的区别如下:
text/plain
前端提交
这种类型用于只发送文本数据而不进行任何编码的情况。它会将表单中的数据按照键值对的形式,用换行符分隔,发送到服务器。
例如,我们使用如下代码来实现表单数据的提交:
html
<form
action="http://localhost:3000/test"
method="post"
enctype="text/plain"
>
First name: <input type="text" name="fname" /><br />
Last name: <input type="text" name="lname" /><br />
<input type="submit" value="Submit" />
</form>
表单中有两个字段,fname
和lname
,我们在页面中输入内容:
发送的请求头内容如下:
请求负载为,也就是请求体内容:
这种类型的优点是简单易读,但缺点是不能发送二进制数据,如文件上传,而且可能会导致一些字符的丢失或错误,如空格、换行符等。
后端处理
我们可以使用express中的express.text()
中间件来处理该类型的数据,处理完毕之后会存储在req.body
中,并且是一个字符串类型的数据,和请求体的内容一致。
application/x-www-form-urlencoded
前端发送
这是默认的表单编码类型,它会将表单中的数据经过URL编码后,用&符号分隔,发送到服务器。
例如,如果表单中有两个字段,fname=张,lname=san,html内容为:
html
<form
action="http://localhost:3000/test"
method="post"
enctype="application/x-www-form-urlencoded"
>
First name: <input type="text" name="fname" /><br />
Last name: <input type="text" name="lname" /><br />
<input type="submit" value="Submit" />
</form>
那么发送的数据就是:
js
fname=%E5%BC%A0&lname=san
请求头中的content-type:application/x-www-form-urlencoded
这种类型的优点是可以发送任何类型的字符,但缺点是不能发送二进制数据,如文件上传,而且URL编码会增加数据的长度,可能会超过服务器的限制。
后端处理
使用express.urlencoded({extended: false})
中间件来处理application/x-www-form-urlencoded
类型的数据,通过req.body
来获取内容:
js
{ fname: '张', lname: 'san' }
可以看到数据被进行了分割并按照key,value的形式作为对象的键值。
疑问?
- text/plain和application/x-www-form-urlencoded有什么区别呢?区别很大嘛?
multipart/form-data
这种类型用于需要发送二进制数据 的情况,如文件上传。
它会将表单中的数据分成多个部分,每个部分都有一个分隔符和一个描述信息,发送到服务器。
例如表单代码为:
html
<form
action="http://localhost:3000/files"
method="post"
enctype="multipart/form-data"
>
姓名:<input type="text" name="name">
<br/>
请选择要上传的文件:<input type="file" name="file" /> <br>
<input type="submit" value="上传" />
</form>
表单格式如下:
上传的数据为:
上述数据是一个多部分表单数据格式的字符串,它由以下几个部分组成:
-
------WebKitFormBoundarylSNPeJJRkGsWkuKA
,这是一个分隔符,用于区分不同的表单数据部分,它是由浏览器自动生成的,每个浏览器可能有不同的分隔符。
css
Content-Disposition: form-data; name="name"
,这是一个表单数据部分的头部,用于描述这个部分的信息,它有以下几个部分:
-
Content-Disposition
,这是一个 HTTP 头部字段,用于指定这个部分的处理方式,它的值是form-data
,表示这是一个表单数据部分。 -
name
,这是一个参数,用于指定这个部分的名称,它的值是name
,表示这是用户输入的姓名。 -
张三
,这是一个表单数据部分的内容,用于存储这个部分的数据,它的值是张三
,表示用户输入的姓名是张三。
kotlin
Content-Disposition: form-data; name="file"; filename="EDG.jpg"
,这是另一个表单数据部分的头部,用于描述这个部分的信息,它有以下几个部分:
-
Content-Disposition
,这是一个 HTTP 头部字段,用于指定这个部分的处理方式,它的值是form-data
,表示这是一个表单数据部分。 -
name
,这是一个参数,用于指定这个部分的名称,它的值是file
,表示这是用户选择的文件。 -
filename
,这是另一个参数,用于指定这个部分的文件名,它的值是EDG.jpg
,表示用户选择的文件名是 EDG.jpg。 -
Content-Type: image/jpeg
,这是另一个 HTTP 头部字段,用于指定这个部分的内容类型,它的值是image/jpeg
,表示这是一个 JPEG 格式的图像文件。 -
------WebKitFormBoundarylSNPeJJRkGsWkuKA--
,这是一个结束符,用于标记多部分表单数据的结束,它是由分隔符加上两个连字符组成的。
这种类型的优点是可以发送任何类型的数据,包括二进制数据,但缺点是数据的格式比较复杂,需要额外的分隔符和描述信息,可能会增加数据的开销。
后端处理
对于multipart/form-data类型,可以使用multer
中间件,它会将请求体中的文件数据解析为一个对象,存放在req.file或req.files属性中,而其他的文本数据则存放在req.body属性中。例如:
js
const multer = require('multer')
const upload = multer({dest: 'uploads/'})
app.use(upload.single('file'))
// 处理文件内容
app.post('/files', (req, res) => {
console.log('文件上传')
console.log(req.file)
res.send('OK')
})
multer会自动存储到后端目录中的uploads/
中,并且以二进制的文件格式存储。
打印的req.file
内容如下:
js
{
fieldname: 'file',
originalname: '9dd38fb5ly1h6728s4qegj22yo1o0af3.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: 'uploads/',
filename: '616f17e7a4206b72df293fdd918fd064',
path: 'uploads\\616f17e7a4206b72df293fdd918fd064',
size: 1420173
}
存储的到文件夹的内容如下:
我们可以看到文件是二进制格式的,至于如何处理为源文件类型,可以参考下面的资料:
除此之外,还有一些关于multer的资料如下:
- nodeJs中间件Multer详解_使用express实现本地文件/图片上传到服务器指定目录_multer.array-CSDN博客
- multer/doc/README-zh-cn.md at master · expressjs/multer · GitHub
- multer - npm (npmjs.com)
总结
本文描述了关于form表单的enctype
的属性,其中有三种类型,并且介绍了他们传递数据时的类型,以及后端如何来接收和处理这些数据,总的来说,普通字符等内容使用text/plain
和application/x-www-form-urlencoded
,二进制文件类型使用multipart/form-data
。
代码
前端代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>测试表单enctype属性</h1>
<h2>text/plain</h2>
<form
action="http://localhost:3000/text"
method="post"
enctype="text/plain"
>
First name: <input type="text" name="fname" /><br />
Last name: <input type="text" name="lname" /><br />
<input type="submit" value="Submit" />
</form>
<h2>application/x-www-form-urlencoded</h2>
<form
action="http://localhost:3000/urlencoded"
method="post"
enctype="application/x-www-form-urlencoded"
>
First name: <input type="text" name="fname" /><br />
Last name: <input type="text" name="lname" /><br />
<input type="submit" value="Submit" />
</form>
<!-- 文件上传 -->
<h2>文件上传</h2>
<form
action="http://localhost:3000/files"
method="post"
enctype="multipart/form-data"
>
姓名:<input type="text" name="name" />
<br />
请选择要上传的文件:<input type="file" name="file" /> <br />
<input type="submit" value="上传" />
</form>
</body>
</html>
后端代码
js
const express = require("express")
const cors = require("cors")
const multer = require("multer")
const app = express()
/* 中间件的处理 */
app.use(cors())
// 处理text/plain
app.use(express.text())
// 处理application/x-www-form-urlencoded类型
app.use(express.urlencoded({ extended: false }))
// 处理multipart/form-data类型
const upload = multer({ dest: "uploads/" })
app.use(upload.single("file"))
// text
app.post("/text", (req, res) => {
console.log('text/plain')
console.log(req.body)
res.send("ok")
})
// urlencoded
app.post("/urlencoded", (req, res) => {
console.log('application/x-www-form-urlencoded')
console.log(req.body)
res.send("OK")
})
// 文件类型
app.post("/files", (req, res) => {
console.log("multipart/form-data")
console.log(req.file)
res.send("OK")
})
app.listen(3000, () => {
console.log("server is running")
})