0
点赞
收藏
分享

微信扫一扫

观察 Form 表单提交时携带的参数

快乐小码农 2021-09-24 阅读 88
基础前端

前言:前端现在写项目基本用的都是框架,以前学的 HTML 基础,因为长期不用,细节都忘的七七八八了,不知道各位前端小伙伴看到慌不慌。今天要写的 Form 表单,大有文章。

如果你对 Form 已经不太熟悉了,请再去看一篇文档,给你个菜鸟教程的链接:html-forms

开始之前我先把,前后端的代码,给出来:

前端:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>form 表单提交</title>
</head>

<body>

    <h3>GET 方法默认提交</h3>
    <form action="/submit-user-info" method="GET" autocomplete="off" >
        <p>昵称:<input type="text" name="nickName" /></p>
        <p>性别
            <input type="radio"" name="sex" value="male" checked /> 男
            <label>
                <input type="radio" name="sex" value="female" /> 女
            </label>
        </p>
        <p><input type="submit" value="提交" /></p>
    </form>

    <h3>POST 方法默认提交</h3>
    <form action="/submit-user-info" method="POST" autocomplete="off" >
        <p>昵称:<input type="text" name="nickName" /></p>
        <p>性别
            <input type="radio"" name="sex" value="male" checked /> 男
            <input type="radio" name="sex" value="female" /> 女
        </p>
        <p><input type="submit" value="提交" /></p>
    </form>

    <h3>POST 方法以 application/x-www-form-urlencoded 编码方法提交 </h3>
    <form action="/submit-user-info" method="POST" enctype="application/x-www-form-urlencoded" autocomplete="off" >
        <p>昵称:<input type="text" name="nickName" /></p>
        <p>性别
            <input type="radio"" name="sex" value="male" checked /> 男
            <input type="radio" name="sex" value="female" /> 女
        </p>
        <p><input type="submit" value="提交" /></p>
    </form>

    <h3>POST 方法以 multipart/form-data 编码方法提交 </h3>
    <form action="/submit-user-info" method="POST" enctype="multipart/form-data" autocomplete="off" >
        <p>昵称:<input type="text" name="nickName" /></p>
        <p>性别
            <input type="radio"" name="sex" value="male" checked /> 男
            <input type="radio" name="sex" value="female" /> 女
        </p>
        <p>
            上传文件1:
            <input type="file" name="file1" />
        </p>
        <p>
            上传文件2:
            <input type="file" name="file2" />
        </p>
        <p><input type="submit" value="提交" /></p>
    </form>
</body>

</html>

NodeJS 后端:

const bodyParser = require("body-parser");
const express = require("express");
const app =  express();

app.use(express.static(resolvePath("/public")));
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json({ limit: "50mb" }));
app.use(bodyParser.urlencoded({ extended: true }));

app.get("/submit-user-info", function (req, res) {
    res.send("发送成功")
});

app.post("/submit-user-info", function (req, res) {
    console.log(req.body);
    res.send("发送成功")
});

一、Form 表单提交时最重要的三个属性

  • method 表单触发提交按钮时发送 HTTP 的方法。支持 GET 和 POST 两种,method 的值可以为别的,例如 DELETE ,虽然浏览器不会报错,但是也不起作用,发送请求的时候默认 GET。
    1. GET :会把数据放在 URL 里面。
    2. POST :会把数据放在请求体里面。
  • action 发送 HTTP 请求的 URL。
  • enctype 只在 POST 请求下有效,表示对请求体的编码方式。
    1. application/x-www-form-urlencoded (default)
      • 数据编码成以 & 分割的键值对,同时以 = 分割键值对,字符以 URL 的方式进行编码
    2. multipart/form-data
      • boundary 分隔符开始
      • 表单每部分的描述。
      • last boundary 结尾
    3. text/plain(不准使用)

二、案例讲解

1. GET 方法默认提交

这种最常见了,不用过多解释了。

2. POST 方法默认提交

提交方式由 GET 的 Query String Parameters 变为 FormData,同时 URL 的参数变为请求体里面去了。

3. POST 方法以 application/x-www-form-urlencoded 编码方法提交

POST 方法默认提交的编码方式就是 application/x-www-form-urlencoded ,所以实验结果同上。

4. POST 方法以 multipart/form-data 编码方法提交

先填写好表单:

再点击提交,查看 network 面板:

诶,请求体里面的数据呢,浏览器看不到,这没办法了,要想观察只能通过抓包来看了,打开 Wireshark 。

是不是有点看不懂?正常因为你还没学会 RFC1521RFC822 分别对 multipart 的定义和 multipart-body 的定义。

用我们朴素的情感,我们先想一下,这是一个表单提交,如果还是用 & 符号分隔不同输入框的内容,是不是不是合理,你肯定会说肯定不合理。因为现在的表单里面文件,文件经过编译会造成分隔符 & 难以辨认。肯定需要另一种方式,没错,天选单词——boundary 出现了。

简化下,现在这个复杂表单的数据的,分隔其实长下面这样:

boundary=------WebKitFormBoundarybaOZVQaeWiyOkvuw # 注意每个boundary前面都加了两个--
内容1
boundary=------WebKitFormBoundarybaOZVQaeWiyOkvuw # 注意每个boundary前面都加了两个--
内容1
boundary=------WebKitFormBoundarybaOZVQaeWiyOkvuw--    # 注意结尾又加了两个--

看见没,如果你把 boundary=----WebKitFormBoundarybaOZVQaeWiyOkvuw 换成 & 是不是就是 Form 表单提交时,其携带内容的默认分隔方式,不要因为它太复杂,被吓住了。

来看看,Content-Type 中 boundary 的格式,以 form-data 编码方式发送 HTTP 请求的时候,Content-Type 会自动添加 boundary=----WebKitFormBoundarybaOZVQaeWiyOkvuw,而且 boundary 的长度为 [0-69] 个字符,字符限制为 US-ASCII

具体到,每个 input 里面编码的内容,可以一个等式来表达:

multipart-body = preamble 1*encapsulation close-delimiter epilogue

preamble 和 epilogue 都会被丢弃,我们在 Wireshark 里面的抓包啥也没看见,所以不讲。1*encapsulation 表示一到多个 input 的内容。这些内容使用 --boundary 进行分隔,最后结束的时候,分隔符 boundary 后面再加两个 --,即 --boundary--

再来看分隔符里面的内容,分两种情况,如果是单纯的 input, 即不上传电脑里面的文件的 input,它的 Encapsulated multipart part 分两部分:

  • Content-Disposition 而且里面只有 name
  • 第二个就是此 input 表示的数据了。

如果上传本地文件的话,Content-Disposition 里面多个 filename 文件名,同时多个 content-type 表示文件类型。

关于表单的内容讲完了,如果你想更加详细的了解 boundary 的细节,请去 https://roytuts.com/boundary-in-multipart-form-data/ 这个博客看下,文章后面的问答写的非常好。

但是 Content-Disposition 我的补充下一个常用用法,那就是后端给链接直接下载的时候,你会发现那个链接的 HTTP 头里面的内容大概是这样的:

Content-Disposition: attachment; filename="filename.jpg"

浏览器会直接保存一个 filename.jpg 的文件到本地,一个常见的下载就完成了。详情见 Content-Disposition-MDN

三、最后

这周过的很悲催,先是脖子特别的疼,最严重的那天,随便转转都受不了,然后就是有一天眼睛特别的干涩,接着感冒了,平时感冒不可怕,关键是现在疫情时机,还是挺吓人的,不过还好,我几乎不怎么打喷嚏,偶尔才打一次,不过流清水鼻涕挺烦人。

今天,周五,早上刚到公司,买的豆浆都没来的及喝,结果被通知公司全员去雍和宫小学做核酸检测,然后就去了,到地方我都被惊呆了,长这么大就没见过这么长的队。

但是的夸一句,核酸检测速度真快,刷刷的,所以虽然队伍长,但是也没等多长时间,我还打算这次疫情过去我都不用打疫苗和做核酸检测的呢,还是新冠猛。对了,检测的时候,是捅喉咙的方式,同事都被弄的挺难受的,我正好感冒,喉咙有点发炎,本来有点担心,好在运气不错,没有碰我的喉咙,只采集了我上颚的样本。

对了,今天还有件大事,公司的年会暂缓了,上周末还排练小品呢,看来用不到了。

希望过年的时候,疫情被压制住,大家安心回家几天过年,如果今年不回去的话,我想明年可能也不回去了,因为明年北京有冬奥会,这得酌情留下,凑个热闹。

举报

相关推荐

0 条评论