Skip to content

请求与响应报文 ​

本页对应 1-2请求与响应报文,共 3 段视频,约 22 分钟。

学习目标 ​

  • 能说出 HTTP 请求报文的四个组成部分(请求行、请求头、空行、请求体),并说明每一部分的作用与排列顺序。
  • 能识别请求行中的请求方法、URL 和协议版本,并解释请求头中 Content-Type 的含义(告知服务器提交数据的格式)。
  • 能在 Chrome 开发者工具的“网络”面板中定位 Ajax 请求,通过“标头 / 载荷(Payload)”查看请求头与请求体,并通过“查看源代码”查看原始报文。
  • 能借助请求报文中的载荷数据反推前端错误位置:先确认提交给服务器的数据是否正确,再回溯到数据获取与赋值代码,定位并修复选择器错误。
  • 能说出响应报文的四个组成部分(响应行/状态行、响应头、空行、响应体),并在浏览器中查看响应标头、响应体与格式化预览数据。
  • 能解释常见 HTTP 响应状态码的分类(2xx 成功、4xx 客户端错误),并说明 404 的含义及“URL 写错”这一典型排查方向。

知识点 ​

从“格式约定”理解请求报文 ​

为什么需要:浏览器和服务器要通信,不能各发各的。HTTP 协议规定了浏览器发送内容、服务器返回内容的格式。浏览器按照 HTTP 协议要求发给服务器的内容,就叫“请求报文”。服务器收到符合格式的请求报文后,才知道浏览器要做什么。

怎么想:先别急着记四个部分,先抓住一个核心——请求报文是“按协议组织起来的一段文本”。服务器会从上往下解析:第一行先判断请求方法,再找 URL,再看协议;后面按“键值对”读附加信息;遇到空行后,才把后面的内容当作提交给服务器的数据。

怎么做:以注册用户为例,浏览器发起请求后,服务器收到的请求报文格式如笔记图所示:

注册用户时发送的请求报文

从图中可以看到,请求报文由四部分组成:请求行、请求头、空行、请求体。

易错点:不要以为请求报文里所有内容都是手写的。请求行中的请求方法、URL 来自代码设置,例如请求方法在 method 中设置,URL 在 action 一类属性中设置;而请求头中很多内容由浏览器自动生成。目前需要重点关注 Content-Type,它告诉服务器本次提交的数据是什么格式。

请求报文的四个组成部分 ​

为什么需要:把请求报文拆成四部分,是为了知道服务器“按什么顺序、按什么含义”读取内容。否则看到一大段文本,就不知道哪一行是地址、哪一段是数据。

怎么想:按从上到下的顺序记:第一行是请求行;第二行到空行前是请求头;空行是分隔符;空行后面是请求体。

怎么做:

  • 请求行:包含请求方法、URL、协议。服务器先看到 POST,就知道浏览器要提交数据;再看到 URL,就知道要找哪个资源;最后看到协议,就知道内容符合 HTTP 要求。
  • 请求头:以“键: 值”的格式携带附加信息。比如 Content-Type 指定本次传递的内容类型。转写稿中特别强调,注册案例里提交的是 JSON 格式数据,服务器看到 Content-Type 后就知道按 JSON 来理解。
  • 空行:分割请求头。服务器看到空行,就知道上面的头部信息告一段落,下面的内容是浏览器提交给服务器的数据。
  • 请求体:发送给服务器的资源或数据。注册案例中,请求体里就是用户名、密码等 JSON 数据。

易错点:请求头和请求体不要混。请求头是“说明信息”,请求体是“真正提交的数据”。空行不是可有可无的装饰,它是服务器解析时的分界点。

在 Chrome 中查看请求报文 ​

为什么需要:只背组成不够,实际开发中要能打开浏览器确认“到底发出去了什么”。这是排查前后端通信问题的基本技能。

怎么想:请求报文是浏览器发出去的,所以要到 Chrome 开发者工具的“网络”面板看。因为案例是 AJAX 请求,所以分类选 Fetch/XHR,再点击具体请求。

怎么做:按转写稿步骤:F12 打开开发者工具 → 进入“网络”面板 → 切换到 Fetch/XHR → 触发请求(例如点击注册或登录按钮)→ 点击出现的请求 → 在“标头”里找“请求标头”。在这里能看到键值对形式的请求头。若要看请求方法、URL、协议,点击“查看源代码”,请求行就会出现。转写稿提到,Chrome 处理后的 URL 可能显示得短一些,这是浏览器处理后的结果。

查看请求体时,到“载荷”(英文界面为 Payload)界面。这里能看到提交给服务器的数据。笔记图展示了查看请求体的位置:

在 Chrome 网络面板查看请求体

易错点:转写稿中“再核”是“载荷”的同音误写,实际应找“载荷/Payload”。另外,载荷里有时显示的是格式化后的对象,不一定是原始 JSON 字符串;要看原始格式,可点“查看源代码”。空行在 Chrome 处理后的界面里通常看不到,不要因为界面上没有空行就以为请求报文没有空行。

用请求报文辅助定位错误 ​

为什么需要:实际开发中,登录失败、注册失败不一定先靠通读代码解决。先看请求报文,可以快速判断“提交给服务器的数据对不对”。

怎么想:如果页面提示用户名或密码错误,先怀疑提交数据是否有问题。到网络面板看请求的“载荷”:用户名是什么、密码是什么。若载荷里的密码值明显不对,就顺着“哪里给请求参数赋值”往回找。

怎么做:转写稿案例中,输入正确用户名和密码仍登录失败。打开网络面板,点击登录请求,在“载荷”里发现密码字段的值竟然是用户名,而不是输入的密码。回到代码,先找到登录按钮点击事件中的 XHR 请求和 data,发现变量名没问题;继续往上找变量声明和赋值,发现第二个选择器写成了用户名选择器,应该用密码框的选择器。改正选择器后,登录成功。

易错点:不要一上来通读全部代码。请求报文的作用是帮你把范围缩小到“提交数据”和“取数据”的关键位置。变量名对,不代表变量值对;真正要确认的是请求载荷里的值。

小结 ​

浏览器发送给服务器的内容叫请求报文,需要符合 HTTP 协议要求。请求报文由请求行、请求头、空行、请求体四部分组成。请求行包含请求方法、URL、协议;请求头以键值对携带附加信息,目前重点了解 Content-Type;空行分隔请求头;请求体是发送给服务器的资源或数据。Chrome 中通过“网络 → Fetch/XHR → 具体请求 → 标头/请求标头”查看请求行和请求头,通过“载荷/Payload”查看请求体,必要时点“查看源代码”看原始格式。掌握这些,既能理解协议格式,也能在调试时快速定位提交数据的问题。

本节目标:用请求报文定位错误 ​

上一节我们学会了在 Chrome 开发者工具里查看请求报文。本节要解决的是:学会查看请求报文之后,它对实际开发有什么用?
答案很直接:它可以帮我们确认代码发送给服务器的数据是否真的正确,从而快速定位错误。尤其在前后端联调时,页面提示“用户名或密码错误”,不一定是服务器坏了,也不一定是用户输错了,很可能是前端提交的请求体数据有问题。

为什么先看请求报文,而不是先读代码 ​

同桌小花已经写完了登录功能,但输入已注册的用户名和密码后始终登录不了,页面提示用户名或密码错误。按照以前的思路,可能一上来就从头阅读代码。但代码一多,阅读成本很高,而且容易迷路。

更高效的思路是:先确认浏览器实际发给服务器的数据是什么。请求报文是代码运行后的结果,请求体里就带着登录提交的用户名和密码。只要把请求体里的值和用户输入的值对比,就能判断问题出在“提交数据”还是“服务器校验”。这比逐行读代码更快。

复现问题:先确认输入没有错 ​

先别急着改代码。打开页面,输入用户名 IT黑马001,密码 123456。为了确认密码框里确实输入正确,可以右键审查元素,把密码框的 type 临时改成 text,看到明文是 123456,说明输入没有问题。然后点击登录,确实仍然登录失败。

此时不要猜,直接打开开发者工具:按 F12,进入 Network(网络)面板,筛选 XHR/AJAX 请求,点击登录按钮后出现登录请求。点开该请求,在 Payload(载荷,转写中说的“再合”就是它)里查看提交给服务器的数据。

从请求体反推代码位置 ​

在 Payload 中看到:用户名是 IT黑马001,密码却也成了 IT黑马001,而期望密码应是 123456。说明请求体数据错了,怪不得登录不上。

接下来反推:什么时候发的请求?点击登录按钮时。所以先找登录按钮的点击事件。进入对应代码后,找到发起请求的函数,查看提交数据 data 里的变量名,发现 password 这个变量名没有写错。变量名对,不代表值对,于是继续往上找变量的声明和赋值位置。结果发现:第二个选择器本应取密码框,却写成了 username。这就是错误根源。

回到页面右键审查密码框,确认正确的类名是 password,复制后替换代码中的错误选择器,保存并重新登录,问题解决。

易错点 ​

第一,不要一上来通读全部代码,应先看请求体数据,再定位到发请求和取值的代码。第二,Payload 里看到的是格式化后的对象,想看原始 JSON 可点“查看源代码”。第三,变量名写对不代表变量值对,要继续追到赋值处。第四,选择器类名要以前端页面审查结果为准,不能凭感觉写。第五,改完要保存、刷新并重新发请求验证。

小结 ​

查看请求报文的核心价值是:快速确认我们发送的内容是否正确。排查顺序可以记为:复现问题 → 看 Network 中的请求 → 看 Payload 请求体 → 对比期望值 → 找到发请求的位置 → 往上追变量赋值 → 修正后复测。这样不需要阅读所有代码,只找关键位置,能明显缩短调试时间。

答案
  • 可以快速确认我们发送的内容是否正确

响应报文是什么,为什么需要先看格式 ​

HTTP 协议规定了浏览器发送内容和服务器返回内容的格式。浏览器按协议格式发给服务器的内容叫请求报文;服务器按协议格式返回给浏览器的内容叫响应报文。浏览器收到符合格式的响应报文后,才能知道这次请求是成功还是失败,以及服务器返回的是什么资源。

为什么需要:前后端通信不是“随便返回一段文字”,而是按固定结构交换信息。只有结构固定,浏览器和开发者工具才能正确解析状态、内容类型和响应数据。
怎么想:把响应报文看成一封格式固定的信:第一行先说明结果,中间是附加说明,空行后才是正文。
怎么做:阅读响应报文时从上往下看,先看响应行判断结果,再看响应头了解内容类型,最后看响应体。
易错点:不要一上来只盯响应体;响应头和状态码往往先告诉你“这次请求有没有成功、返回的是什么格式”。

HTTP响应报文结构示意图

响应报文的四个组成部分 ​

响应报文和请求报文格式很相似,也由四部分组成:响应行、响应头、空行、响应体。

  1. 响应行(状态行):包含协议、HTTP 响应状态码、状态信息。课程示例中,浏览器看到状态码和状态信息,就能知道请求成功还是失败。

    • 为什么需要:让浏览器第一眼判断本次请求结果。
    • 怎么想:第一行是“结论行”,重点看状态码。
    • 怎么做:从第一行中识别协议、数字状态码和后面的状态文本。
    • 易错点:状态行也叫响应行;不要只记名字,要知道它承载“成功/失败”的判断信息。
  2. 响应头:以键值对格式携带附加信息,例如 Content-Type 告诉浏览器本次返回内容的类型。课程中示例返回 JSON,因此响应头里会出现与 JSON 对应的内容类型。

    • 为什么需要:浏览器需要知道“返回的是什么类型的数据”,才能按相应方式处理。
    • 怎么想:响应头是“附加说明书”,目前重点先掌握 Content-Type。
    • 怎么做:在响应头中找键值对,关注 Content-Type 的值。
    • 易错点:Content-Type 是提示内容类型,不等于响应体本身;其他响应头用到时再查,不必一次全背。
  3. 空行:分隔响应头和响应体。

    • 为什么需要:没有分隔,解析器无法准确判断“说明部分”到哪里结束、“正文”从哪里开始。
    • 怎么想:空行是分界线,空行之后才是服务器返回的资源或数据。
    • 怎么做:阅读原始报文时,看到空行就转入响应体。
    • 易错点:Chrome 开发者工具通常会帮我们处理报文,空行往往看不到,不能因此认为它不存在。
  4. 响应体:服务器返回的资源或数据。课程示例中响应体是 JSON 格式数据,两边是大括号,键用双引号包裹,冒号后是值。

    • 为什么需要:真正业务数据通常在这里。
    • 怎么想:先由状态码判断结果,再由响应体读取数据。
    • 怎么做:在开发者工具中查看 Response;需要格式化查看时看 Preview。
    • 易错点:响应体不一定是 JSON,也可能是 HTML、图片等;要看 Content-Type 和实际内容。

HTTP 响应状态码:先判断请求结果 ​

HTTP 响应状态码用来表明请求是否成功完成。课程中说明状态码是三位数字,从 1xx 到 5xx;目前重点记住:2xx 表示成功,4xx 表示客户端错误。前端开发中,客户端通常可理解为浏览器这一侧。

为什么需要:状态码让浏览器和开发者快速判断结果,不用先解析完整响应体。
怎么想:先看数字大类,再看具体含义。比如 404 表示服务器找不到资源。
怎么做:在响应行中看状态码;课程用把 URL 故意写错的方式演示 404,随后在 Network 面板查看响应报文。
易错点:看到 404 不要先怀疑服务器“坏了”,更常见的是 URL 写错或资源路径不对;课程中错误 URL 返回 404,响应体里的提示也与“资源找不到”对应。

HTTP响应状态码404示例

在 Chrome 中查看响应报文 ​

为什么需要:调试时只看页面提示不够,必须确认服务器实际返回了什么。
怎么想:响应报文属于网络通信结果,应到 Network(网络)面板抓请求,再看对应请求的响应信息。
怎么做:打开开发者工具,进入 Network 面板;当前课程查看的是 XHR 请求,所以切换到 XHR 分类;点击目标请求;在 Headers 中查看响应标头,点击 View source 可看到状态行等原始信息;查看响应体可点 Response,查看格式化后的数据可点 Preview。
易错点:Chrome 会格式化显示,空行通常看不到;Response 里可能是格式化后的对象,想确认原始数据格式可用 View source;中文界面“载荷”对应英文 Payload,“响应”对应 Response,“预览”对应 Preview。

用响应报文辅助调试的思路 ​

课程先用重复注册演示了错误响应报文,又用错误 URL 演示 404。调试时不要急着通读全部代码,而应先确认通信数据:请求有没有发对、服务器响应是什么。若状态码是 404,就优先检查 URL;若响应体提示资源找不到,就与 404 对照。类似地,课程在请求报文调试中通过 Payload 发现提交数据错误,再反推变量赋值和选择器问题。核心是:从报文中的关键数据反推错误位置,缩短定位时间。

易错点:不要把开发者工具格式化后的展示当成原始报文;不要只凭页面提示猜错误,要回到 Network 中看状态码、响应头和响应体。

课件图示 ​

课件第40页:规定了浏览器发送及服务器返回内容的格式 请求报文:浏览器按照HTTP协议要求的格

课件第41页:请求报文的组成部分有: 1. 请求行:请求方法,URL,协议 2. 请求头:以键

课件第46页:规定了浏览器发送及服务器返回内容的格式 响应报文:服务器按照HTTP协议要求的格

课件第48页:总结 总结 1. 响应报文的组成: 响应行(状态行):协议、HTTP响应状态码、

课件第47页:HTTP 响应状态码用来表明请求是否成功完成。 比如:404(服务器找不到资源)

代码示例 ​

代码示例 1:发起注册请求,观察请求报文 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>注册用户 - 请求报文</title>
</head>
<body>
  <button class="btn-register">注册用户</button>

  <!-- 引入 axios -->
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    // 接口地址:换成提供的服务器地址即可
    const BASE_URL = '/api'

    document.querySelector('.btn-register').addEventListener('click', async () => {
      // 要提交给服务器的数据(请求体)
      const data = {
        username: 'itheima001',
        password: '123456'
      }

      const res = await axios({
        url: BASE_URL + '/register', // → 请求行里的 URL
        method: 'post',              // → 请求行里的请求方法
        data: data                   // → 请求体,axios 自动带上 Content-Type: application/json
      })

      console.log(res.data)
    })
  </script>
</body>
</html>

关键行与易错点

  • method: 'post' 对应请求行第一个单词 POST;url 对应请求行第二个部分。这两项写在配置对象里,最终会出现在请求行,而不是请求体。
  • data 是请求体,axios 传入对象时会自动序列化成 JSON,并自动加上请求头 Content-Type: application/json;这一段请求头内容是自动生成的,不用手写。
  • 易错点:不要再写 JSON.stringify(data),否则请求体变成“字符串的字符串”,服务器解析不出 JSON。
  • 查看方式:F12 → 网络(Network) → 选 Fetch/XHR 分栏 → 点击按钮后再点出现的请求 → 标头(Headers)→ 请求标头,点“查看源代码”才看得到请求行;请求体在 载荷(Payload),点“查看源代码”看原始 JSON 字符串。空行被浏览器处理掉了,面板里看不到。

代码示例 2:登录请求体数据错误 —— 用请求报文定位问题 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>登录 - 用请求报文排错</title>
</head>
<body>
  <input type="text" class="username" placeholder="用户名" />
  <input type="text" class="password" placeholder="密码" />
  <button class="btn-login">登录</button>

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    document.querySelector('.btn-login').addEventListener('click', async () => {
      // ❌ 错误写法:密码框也用了 .username,导致提交的 password 是用户名的值
      // const username = document.querySelector('.username').value
      // const password = document.querySelector('.username').value

      // ✅ 正确写法:密码框的类名是 .password
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value

      const res = await axios({
        url: '/api/login',
        method: 'post',
        data: { username, password } // 请求体
      })

      console.log(res.data)
    })
  </script>
</body>
</html>

关键行与易错点

  • 排错顺序:先在页面输入正确账号密码 → 登录失败 → F12 网络 → 点请求 → 载荷,发现 password 的值和 username 一模一样,说明“提交给服务器的数据”错了。
  • 由数据反推代码:点击登录按钮才发请求 → 打开按钮点击事件 → 找到 axios 的 data → 变量名没问题 → 往上找变量声明,发现第二个 querySelector 选择器写错。
  • 易错点:Bootstrap 输入框上通常还有 form-control 类,不要拿它当选择器(两个框都有),要用 .username / .password。类名可以去页面右键“审查元素”里复制确认。
  • 整个过程不需要通读全部代码,只顺着“请求报文里的数据”反推关键位置,这是实际开发中非常重要的调试技能。

代码示例 3:URL 写错 → 观察 404 响应报文 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>响应报文 - 404 演示</title>
</head>
<body>
  <button class="btn-register">注册用户</button>

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    document.querySelector('.btn-register').addEventListener('click', () => {
      axios({
        // 故意在 URL 后面多写一段,服务器找不到这个资源
        url: '/api/register/xxx',
        method: 'post',
        data: { username: 'itheima001', password: '123456' }
      })
        .then((res) => {
          console.log(res.data)
        })
        .catch((err) => {
          console.log(err)
        })
    })
  </script>
</body>
</html>

关键行与易错点

  • 响应报文同样是四部分:响应行(状态行:协议 + 状态码 + 状态信息)、响应头、空行、响应体。状态码 2xx 表示成功,4xx 表示客户端(浏览器)错误。
  • 查看方式:F12 网络 → 点请求 → 标头 里的 响应标头 看响应头;点“查看源代码”看响应行里的 404;响应体在 响应(Response),格式化后的数据在 预览(Preview)。
  • 404 = 服务器找不到资源,最常见原因就是 URL 写错,看到 404 先去检查 url 这一行。
  • 易错点:.then 里只处理成功(2xx),4xx 会走 .catch,所以别只在 .then 里打日志,否则“看起来什么都没发生”。真正的排查依据仍以网络面板里的响应报文为准。

常见错误 ​

  1. 打开网络面板一片空白,怀疑请求根本没发出去

    • 现象:切到 Network 后列表为空,但页面明明有交互。
    • 原因:面板是在请求发出之后才打开的,Chrome 只记录打开之后的请求;或过滤条件停在非 Fetch/XHR 分类上。
    • 修法:先开 F12 再触发操作;勾选 Preserve log 防止页面跳转清空记录;过滤切到 Fetch/XHR。
  2. 在「请求标头」里找不到请求方法、URL 和协议

    • 现象:只看到一堆 key: value,第一行不见了。
    • 原因:DevTools 默认展示解析后的视图,把请求行拆散隐藏了。
    • 修法:点该区域的 view source(查看源代码)切到原始报文视图。
  3. 找不到空行,以为报文格式不对

    • 现象:请求头与请求体之间看不到分隔行。
    • 原因:浏览器渲染时把空行吃掉了。
    • 修法:用 view source、右键 Copy as cURL,或改用抓包工具看原始文本。
  4. Payload 里显示的是对象而不是 JSON 字符串,误判“数据格式错了”

    • 现象:代码里传的是字符串,面板里却是可折叠对象,于是回头乱改代码。
    • 原因:DevTools 对 JSON 做了格式化展示。
    • 修法:点 view source 看原始文本,确认双引号、转义、字段名是否真的符合预期。
  5. 提交失败就从头逐行读代码

    • 现象:几百行代码看半天,找不到问题。
    • 原因:没有先确认“发出去的数据到底对不对”。
    • 修法:先看 Payload 里提交的值 → 不对就找发起请求的那段(按钮点击事件里的 xhr/fetch)→ 顺着 data 里的变量往上看声明和赋值 → 定位到取值处(高发点是选择器写错)。
  6. 看到 404 就断定后端接口挂了

    • 现象:状态码 404,直接去质问后端。
    • 原因:URL 路径拼错、多了或少了斜杠、参数误写进路径。
    • 修法:对照接口文档逐字符核对 URL,先确认是路径错还是资源真不存在。
  7. 状态码 200 就认为业务成功

    • 现象:状态码 200,页面却提示“用户名或密码错误”。
    • 原因:HTTP 状态码只说明这次传输完成,业务结果在响应体里。
    • 修法:看 Response / Preview 里的业务字段(如 message、code)。

练习 ​

  1. 打开任意含 Ajax 的页面,用 Network 找到该请求,分别记录:请求行(view source 视图)、Content-Type 的值、原始请求体,并说明三者各自对应报文的哪一部分。
  2. 故意把请求 URL 末尾追加一串字符,观察状态码与 Preview 中的 message,写出你从“看到现象”到“得出结论”的完整判断流程。
  3. 给定一个“登录失败”的场景,只允许看 Network 面板、不许读代码,写出你定位错误的三个步骤,并说明每一步在排除什么可能。
  4. 对比同一个请求的 Payload 视图与 view source 视图,解释差异原因;再回答:如果后端说“没收到 password 字段”,你第一眼先看哪里?
  5. 用 Copy as cURL 复制该请求到文本编辑器,手工标出四个组成部分(含空行),并指出哪一部分是 DevTools 里看不到的。

原视频对照 ​

#视频时长
1HTTP协议-请求报文08:53
2请求报文-辅助调试05:53
3HTTP协议-响应报文07:45

小结 ​

  1. 报文是“证据”而不是“知识”:出问题的第一动作是打开 Network 看真实发出的内容,而不是读代码。
  2. 请求行、状态行、空行在 DevTools 里默认不可见;凡是要看原始格式,一律走 view source 或 Copy as cURL。
  3. Content-Type 是唯一必须看的头,它决定服务端和浏览器怎么解析后面的 body;格式对不上,body 再对也白搭。
  4. 排查顺序固定为:先看数据(Payload / Response)→ 再看发起请求的位置 → 再看数据来源(变量声明与赋值)。这条链路能把排查范围从整个文件缩到几行。
  5. HTTP 状态码只回答“这次请求成没成”,业务成没成看响应体;遇到 4xx 先怀疑自己的 URL 和参数,别先怀疑后端。
  6. 前端取值类 bug 的高发点是选择器:Payload 里出现“密码变成了用户名”这类张冠李戴,几乎都是复制粘贴后忘了改选择器。
  7. 养成“先开面板再操作”的习惯并常开 Preserve log,否则请求会被页面跳转清空,白忙一场。
  8. 密码框看不到值不代表没输入——必要时临时改 type 或读 value 自证,别把时间浪费在“我肯定输对了”上。