网络基础:HTML表格
#html #网络开发人员 #初学者 #deno

内容

  1. 什么是表格?
  2. 他们如何工作?
  3. 我们如何构建它?
  4. 摘要

1.什么是形式?

表单是我们每天与Web互动的基本工具之一[1]。它使我们能够登录应用程序,注册新闻通讯,在线购买内容并发布评论以列出一些。它们是我们将信息从浏览器发送到服务器的关键机制。

在本教程中,我们将从最简单的表单化身开始,并开始对Web平台内置多少功能获得一些欣赏。我们将介绍他们的工作方式以及如何构建它。为了跟随,您需要一个文本编辑器和一个可以服务于HTML文件并处理请求的Web服务器。对于我的Web服务器,我将使用Deno [2]和一个名为Oak [3]的Web框架来处理请求。在前端,它将是普通的html。

先决条件:

  • 对服务器的工作方式的基本理解[MDN]
  • http动词[MDN]
  • deno [Website]的安装

2.他们如何工作?

在我们深入研究表格之前,让我们从访问网站时会发生什么:

  1. 您通过地址栏或链接请求网站
  2. 服务器接收您的请求
  3. 服务器通过将HTML作为文本发送
  4. 来响应您的请求
  5. 您的浏览器呈现为HTML

访问网站时,您对服务器的请求是GET请求。需要将服务器配置为根据要访问的网站的路径来处理请求,还需要提出哪种类型的请求(即获取,发布或任何其他HTTP动词[4])。例如,当您访问网站https://hasanhaja.com/picks时,您就向路径/picks提出了get请求。好像您去https://hasanhaja.com一样

在这种情况下,让我们遵循一个示例,其中返回的HTML包含一个表格。

A diagram showing the client and server relationship when the client requests for a web page. There are two boxes containing the text "Client" and "Server" with two arrows going between them. Above the arrow going from "Client" to "Server" is the text "GET / req", and below the arrow going from "Server" to "Client" is the text "res" and "HTML". To the right of the "Client" box is an HTML snippet with a part of a form shown.

该表单用HTML标签<form>表示,并嵌套在其中是我们要收集的数据的字段,以及提交按钮。表单的默认行为是带有表单数据的搜索查询的构造,并向同一路径提出另一个获取请求。

A color-coded diagram showing the client and server relationship when the client sends form data to the server. The HTML on the right hand side of the client box has been color-coded with orange to represent what will become the form data and blue to represent the submit action. Consequently, the arrow and the GET request label is blue with only the form data "name=Hasan" colored orange.

可以配置该服务器以识别搜索查询参数,以便可以按照指示进行响应。

The same diagram but with a response arrow from the server to the client with the text "res" below it and a box containing the word "HTML" to denote that it is an HTML response.

还可以在前端配置另一种方式。如果我们希望表格通过使用请求正文中的表单数据向相同的路径提交数据来提交数据,则可以将方法属性添加到HTML中,例如此<form method="post">。服务器的配置非常相似以处理此请求。

For the form's POST version of the same client-server relationship diagram, the text above the arrow going from "Client" to "Server" has the text "POST / req", and above that is an orange box that denotes the form data sent with the POST request. To the right of the "Client" box is an HTML snippet with a part of a form shown with the "method" attribute set to "post".

Similar response diagram with a response arrow from the server to the client with the text "res" below it and a box containing the word "HTML" to denote that it is an HTML response.

在上面的示例中,我们仅将服务器返回HTML作为对请求的响应,但实际上它可以配置为使用数据执行任何任意操作。如果这是订阅新闻通讯的表格,则服务器将执行逻辑以将其添加到电子邮件列表中,然后发送HTML响应以告知用户该请求已成功处理。

如果表单字段是电子商务网站中的搜索过滤器,则表单数据可用于查询数据库中与搜索相关的所有产品,然后可以使用这些结果来构建响应。形式的应用是无穷无尽的,这就是为什么它们到处都是。

3.我们如何构建它?

好吧,让我们建立一个表格并开始修补!

为了使事情尽可能简单,我们的表格将包含其资格作为表格所需的最小字段数量。这是一个带有一个文本字段[5]的表格,称为“名称”:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Form</title>
    </head>
    <body>
        <h1>Our form</h1>
    <form>
      <h2>Your details</h2>
      <label for="name">Name</label>
      <input id="name" name="name" type="text">
      <button type="submit">Submit</button>
    </form>
    </body>
</html>

这是单击提交时HTTP请求的样子:

GET /?name=Hasan HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://localhost:8000/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

HTML表单为我们构建了整个HTTP请求,我们只需要在服务器上使用它并将响应发送回去即可。让我们看一下可以处理此表单提交的服务器代码:

import { Application, Router } from "oak";

const router = new Router();

router
  .get("/", async (context) => {
      const { search } = context.request.url;

      if (!search) {
        await context.send({
          root: `${Deno.cwd()}/static`,
          index: "index.html",
        });
        return;
      }

      const params = new URLSearchParams(search);
      const name = params.get("name");
      context.response.body = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Form</title>
  </head>
  <body>
    <h1>Our form</h1>
    <p>Hi there, ${name}!</p>
  </body>
</html>
      `;
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

路径"/".get处理程序处理页面的请求和表单提交的请求。条件检查if (!search)是要区分所请求的表格或要提交的表格。当没有搜索查询参数的情况下请求页面时,这意味着用户请求表单,并且当要求使用查询参数时,这意味着表单已提交。在遇到表单提交表单时的实施中,我们构建了HTML内联构造并用html主体中的名称响应。

context.send的功能是读取服务器文件系统中的静态HTML文件,并在响应中以文本发送。 OAK框架与适当的标头构建了HTTP响应,以告诉浏览器它将呈现哪种内容。您可以在浏览器开发人员工具的“网络”选项卡中调试响应标题,这就是我们的表单提交响应的外观:

HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
content-encoding: gzip
content-length: 187
date: Mon, 10 Jul 2023 22:05:42 GMT

旁边: content-type: text/html是为什么通过设置context.response.body用嵌入的html字符串做出响应的原因,既有效又等同于context.send方法。 context是特定于橡木框架的实现详细信息,您的里程可能会根据您处理HTTP请求的方式而有所不同。

这可能会使服务器上有些混乱。这是令人困惑的,因为当形式数据发送到服务器时,基础HTTP动词仍然是 get 。这意味着,当服务器收到GET请求时,它还需要检查是否已将表单数据发送到该请求。使用获取数据是一个完全有效的模式,但是在处理表格时,我们可以使我们的生活变得更轻松,以分开 get form form 的逻辑和 porting data。数据。

要切换此表单以通过帖子发送表单数据,我们可以将带有值“ post”的“方法”属性添加到form tag。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Form</title>
    </head>
    <body>
        <h1>Our form</h1>
    <form method="post">
      <h2>Your details</h2>
      <label for="name">Name</label>
      <input id="name" name="name" type="text">
      <button type="submit">Submit</button>
    </form>
    </body>
</html>

这似乎太微不足道了。 Web平台功能强大且功能丰富。这一小声明完全改变了通信机制。这是发送到服务器的HTTP请求:

POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Origin: http://localhost:8000
Connection: keep-alive
Referer: http://localhost:8000/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

这是请求随附的有效载荷:

name=Hasan

在服务器上,我们可以通过将另一个处理程序添加到我们的router
来处理此操作。

/* --snip-- */
router
  .get("/", async (context) => {
      const { search } = context.request.url;

      if (!search) {
        await context.send({
          root: `${Deno.cwd()}/static`,
          index: "index.html",
        });
        return;
      }
            /* --snip-- */
  })
  .post("/", async (context) => {
    const formBody = await context.request.body({ type: "form" }).value;
    const name = formBody.get("name");

    context.response.body = `<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Form</title>
    </head>
    <body>
        <h1>Our form</h1>
    <p>Hi there, ${name}!</p>
    </body>
</html>
    `;
  })
;

/* --snip-- */

我们将保持.get处理程序,以便它仍然可以向我们提供表格,但是当我们提交时,我们的.post处理程序将处理该请求。这就是简单的形式!

这是我们的整个服务器代码,它通过get和post方法处理表单:

import { Application, Router } from "oak";

const router = new Router();

router
  .get("/", async (context) => {
      const { search } = context.request.url;

      if (!search) {
        await context.send({
          root: `${Deno.cwd()}/static`,
          index: "index.html",
        });
        return;
      }

      const params = new URLSearchParams(search);
      const name = params.get("name");
      context.response.body = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Form</title>
  </head>
  <body>
    <h1>Our form</h1>
    <p>Hi there, ${name}!</p>
  </body>
</html>
      `;
  })
  .post("/", async (context) => {
    const formBody = await context.request.body({ type: "form" }).value;
    const name = formBody.get("name");

    context.response.body = `<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>Form</title>
    </head>
    <body>
        <h1>Our form</h1>
    <p>Hi there, ${name}!</p>
    </body>
</html>
    `;
  })
;

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

本文的所有源代码也可以在我的GitHub上找到。

概括

表单很简单,并且在Web平台中得到了深厚的支持。它们使我们能够捕获用户的数据,这提供了交互式的网络体验。在这篇文章中,我们研究了HTML形式的解剖结构以及如何构建它们。我们看到了两种将表单数据提交给服务器的方法,我们看到,尽管代码的差异很小,但意图的通信与POST方法相当强大。

html表单中有很多包装的功能。还有更多有趣而复杂的情况,需要深入研究它们。这样的示例可以是:

  • 验证输入以确保将其以正确的格式发送到服务器
  • 如果验证失败
  • ,请验证服务器上的数据并响应错误消息

请继续关注此网络基础系列中的后续帖子。

如果您想到了我错过的或只是想取得联系的任何东西,可以通过Mastodon,通过Threads,通过TwitterLinkedIn与我联系。

参考

  1. Web表单与用户数据[MDN]
  2. 一起工作
  3. deno [Website]
  4. 橡树框架[Website]
  5. http动词[MDN]
  6. 形式输入元素[MDN]