Understanding HTML Form Encoding: URL Encoded and Multipart Forms URL Encoded Form Multipart Forms Text/plain Forms

2025-05-26

理解 HTML 表单编码:URL 编码和多部分表单

URL 编码形式

多部分表格

文本/纯文本表格

有一天,我尝试用Go编写一个 REST 端点,它将浏览器中提交的表单内容上传到另一个 REST 端点,换句话说,

Form in Browser ----> My GO Rest API ----> Another REST API

在做这些的过程中,我学到了一些HTML表单工作原理的基础知识。所以觉得分享一下我的学习成果或许是件好事,于是就写了这篇文章。:)

表单的编码类型由属性决定enctype。它可以有三个值,

  • application/x-www-form-urlencodedenctype- 表示 URL 编码形式。如果属性未设置任何值,则此为默认值。

  • multipart/form-data- 表示多部分表单。当用户想要上传文件时,会使用此类表单。

  • text/plain- HTML5 中引入的一种新表单类型,顾名思义,它只是发送数据而不进行任何编码

现在,让我们通过示例来查看每种表单类型,以便更好地理解它们。

URL 编码形式

顾名思义,使用此类表单提交的数据是经过 URL 尾编码的。例如以下表单:

<form action="/urlencoded?firstname=sid&lastname=sloth" method="POST" enctype="application/x-www-form-urlencoded">
    <input type="text" name="username" value="sidthesloth"/>
    <input type="text" name="password" value="slothsecret"/>
    <input type="submit" value="Submit" />
</form>
Enter fullscreen mode Exit fullscreen mode

在这里,您可以看到表单使用 POST 请求提交到服务器,这意味着它有一个主体。但是主体是如何格式化的呢?它是经过 URL 编码的。基本上,它(name, value)会创建一个长字符串,其中包含多个对。每(name, value)对之间用一个符号分隔& (ampersand),并且每对(name, value)中的 和之间也用一个符号name分隔,例如:value= (equals)

key1=value1&key2=value2

对于上述形式,它将是,
username=sidthesloth&password=slothsecret

另外,请注意我们在操作 URL 中传递了一些查询参数/urlencoded?firstname=sid&lastname=sloth

URL 编码的主体和 action URL 中传递的查询参数看起来不是很相似吗?因为它们很相似。它们共享上面讨论过的格式。

尝试用上面的代码创建一个 HTML 文件,看看它在开发工具中是如何提交的。如下图所示:

URL 编码快照

这里要注意的是Content-Type标题application/x-www-form-urlencoded,查询字符串和表单字段以上面讨论的格式传输到服务器。

注意:不要对屏幕截图中的“表单数据”一词感到困惑。它只是 Google Chrome 表示表单字段的方式。

一切正常,但编码过程还有一些细节。让我们在提交的值中引入一些空格,例如下面的形式,它与上一个相同,但firstname值从 更改为sidsid slayerusername也从 更改sidtheslothsid the sloth

<form action="/urlencoded?firstname=sid slayer&lastname=sloth" method="POST" enctype="application/x-www-form-urlencoded">
    <input type="text" name="username" value="sid the sloth"/>
    <input type="text" name="password" value="slothsecret"/>
    <input type="submit" value="Submit" />
</form>
Enter fullscreen mode Exit fullscreen mode

现在尝试提交表单,看看表单字段在开发工具中是如何传输的。这是 Chrome 中的开发工具 snap 代码。

带空格的 URL 编码快照

显然,您可以看到空格被替换为“%20”或“+”。查询参数和表单主体均已执行此操作。

阅读此文,了解何时可以使用 + 和 %20。这涵盖了 URL 编码过程。

多部分表格

多部分表单通常用于用户需要将文件上传到服务器的情况。不过,我们只关注基于简单文本字段的表单,因为这足以理解它们的工作原理。

要将上述表单转换为多部分表单,您只需将enctype表单标签的属性从application/x-www-form-urlencoded更改为multipart/form-data

<form action="/multipart?firstname=sid slayer&lastname=sloth" method="POST" enctype="multipart/form-data">
    <input type="text" name="username" value="sid the sloth"/>
    <input type="text" name="password" value="slothsecret"/>
    <input type="submit" value="Submit" />
</form>
Enter fullscreen mode Exit fullscreen mode

让我们继续提交它并看看它在开发工具中是如何显示的。

带空格的 URL 编码快照

这里有两点需要注意:Content-Type表单请求的头部和有效载荷。让我们逐一介绍一下。

内容类型标头

标头的值Content-Type显然是multipart/form-data。但它还有另一个值boundary。上例中,它的值是由浏览器生成的,但用户也可以自行定义,例如boundary=sidtheslothboundary。下一节我们将了解它的具体用途。

请求正文

请求有效负载包含表单字段本身。每对(name, value)字段都会被转换为以下格式的 MIME 消息部分:

--<<boundary_value>>
Content-Disposition: form-data; name="<<field_name>>"

<<field_value>>

每对都重复上述格式(name, value)

boundary最后,整个有效载荷以带有 后缀的值终止--。因此整个请求如下所示:

--<<boundary_value>>
Content-Disposition: form-data; name="<<field_name>>"

<<field_value>>
--<<boundary_value>>
Content-Disposition: form-data; name="<<field_name>>"

<<field_value>>
--<<boundary_value>>--

现在,我们看看如何使用边界值。

对于表单来说application/x-www-form-urlencoded&& 符号充当每对之间的分隔符(name, value),使服务器能够了解参数值何时何地开始和结束。

username=sidthelsloth&password=slothsecret

对于表单来说multipart/form-data,边界值就是用来做这个用途的。假设边界值为XXX,请求负载应该是这样的:

--XXX
Content-Disposition: form-data; name="username"

sidthesloth
--XXX
Content-Disposition: form-data; name="password"

slothsecret
--XXX--

连字符本身不属于边界值,而是请求格式的一部分。Content-Type上述请求的标头如下:

Content-Type: multipart/form-data; boundary=XXX

这使得浏览器能够了解每个字段何时何地开始和结束。

文本/纯文本表格

这些表单与 URL 编码表单基本相同,只是表单字段在发送到服务器时不会进行 URL 编码。它们通常使用不广泛,但它们已被引入 HTML 5 规范。

避免使用它们,因为它们是为了人类理解而不是为了机器。

正如规范中引用的那样


使用 text/plain 格式的有效负载旨在方便人类阅读。由于格式模糊(例如,无法区分值中的文字换行符和值末尾的换行符),计算机无法可靠地解释它们。

希望我能清楚地解释我所学到的东西。下次再见,伙计们。祝你们平安。:)

在我的网站上了解有关我的更多信息..✨

文章来源:https://dev.to/sidthesloth92/understanding-html-form-encoding-url-encoded-and-multipart-forms-3lpa
PREV
为什么 NodeJs 中需要 Helmet?
NEXT
关于我如何使用 DEV.to 和 NextJS 基本规则构建我的投资组合和博客的故事开始设计技术开发结论