enctype属性/text/plain、multipart/form-data、application/x-www-form-urlencoded对比

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>

表单中有两个字段,fnamelname,我们在页面中输入内容:

发送的请求头内容如下:

请求负载为,也就是请求体内容:

这种类型的优点是简单易读,但缺点是不能发送二进制数据,如文件上传,而且可能会导致一些字符的丢失或错误,如空格、换行符等。

后端处理

我们可以使用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的资料如下:

总结

本文描述了关于form表单的enctype的属性,其中有三种类型,并且介绍了他们传递数据时的类型,以及后端如何来接收和处理这些数据,总的来说,普通字符等内容使用text/plainapplication/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")
})
相关推荐
吕彬-前端15 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱17 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai27 分钟前
uniapp
前端·javascript·vue.js·uni-app
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4112 小时前
无网络安装ionic和运行
前端·npm
理想不理想v2 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云2 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:137971205872 小时前
web端手机录音
前端
齐 飞2 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb