通过 JavaScript 发送表单

例如,当用户点击提交按钮提交 HTML 表单时,浏览器会发送一个HTTP请求以发送表单中的数据。但有时,Web 应用程序会使用 JavaScript API(例如fetch())以编程方式将数据发送到期望表单提交的端点,而不是这种声明性方法。本文解释了为什么这是一个重要的用例以及如何实现它。

为什么要使用 JavaScript 提交表单数据?

标准 HTML 表单提交(如我们关于发送表单数据的文章中所述)会加载发送数据到的 URL,这意味着浏览器窗口将进行完整的页面加载。

但是,许多 Web 应用程序,尤其是渐进式 Web 应用程序单页应用程序,使用 JavaScript API 从服务器请求数据并更新页面的相关部分,从而避免了完整页面加载带来的开销。

因此,当这些 Web 应用程序想要提交表单数据时,它们只使用 HTML 表单来收集用户的输入,而不是用于数据提交。当用户尝试发送数据时,应用程序会接管并使用 JavaScript API(例如fetch())来发送数据。

JavaScript 表单提交的问题

如果 Web 应用程序将表单数据发送到的服务器端点由 Web 应用程序开发人员控制,那么他们可以选择任何方式发送表单数据:例如,以 JSON 对象的形式。

但是,如果服务器端点期望表单提交,则 Web 应用程序必须以特定方式对数据进行编码。例如,如果数据只是文本,则它由 URL 编码的键/值对列表组成,并使用Content-Typeapplication/x-www-form-urlencoded 的方式发送。如果表单包含二进制数据,则必须使用 multipart/form-data 内容类型发送。

FormData 接口负责以这种方式对数据进行编码,在本篇文章的剩余部分,我们将简要介绍 FormData。有关更多详细信息,请参见我们的使用 FormData 对象指南。

手动构建 FormData 对象

您可以通过调用对象append() 方法来填充 FormData 对象,该方法用于您要添加的每个字段,并传入字段的名称和值。对于文本字段,该值可以是字符串;对于二进制字段(包括File 对象),该值可以是Blob

在以下示例中,当用户单击按钮时,我们将数据作为表单提交发送。

js
async function sendData(data) {
  // Construct a FormData instance
  const formData = new FormData();

  // Add a text field
  formData.append("name", "Pomegranate");

  // Add a file
  const selection = await window.showOpenFilePicker();
  if (selection.length > 0) {
    const file = await selection[0].getFile();
    formData.append("file", file);
  }

  try {
    const response = await fetch("https://example.org/post", {
      method: "POST",
      // Set the FormData instance as the request body
      body: formData,
    });
    console.log(await response.json());
  } catch (e) {
    console.error(e);
  }
}

const send = document.querySelector("#send");
send.addEventListener("click", sendData);
  1. 首先,我们构造一个新的、空的 FormData 对象。
  2. 接下来,我们调用 append() 两次,向 FormData 对象添加两个项目:一个文本字段和一个文件。
  3. 最后,我们使用 fetch() API 发出一个POST 请求,并将 FormData 对象设置为请求主体。

请注意,我们不需要设置Content-Type 头部:当我们将 FormData 对象传递到 fetch() 时,会自动设置正确的头部。

关联 FormData 对象和 <form>

如果您提交的数据确实来自<form>,则可以通过将表单传递到 FormData 构造函数来填充 FormData 实例。

假设我们的 HTML 声明了 <form> 元素

html
<form id="userinfo">
  <p>
    <label for="username">Enter your name:</label>
    <input type="text" id="username" name="username" value="Dominic" />
  </p>
  <p>
    <label for="avatar">Select an avatar</label>
    <input type="file" id="avatar" name="avatar" required />
  </p>
  <input type="submit" value="Submit" />
</form>

该表单包含文本输入、文件输入和提交按钮。

JavaScript 代码如下

js
const form = document.querySelector("#userinfo");

async function sendData() {
  // Associate the FormData object with the form element
  const formData = new FormData(form);

  try {
    const response = await fetch("https://example.org/post", {
      method: "POST",
      // Set the FormData instance as the request body
      body: formData,
    });
    console.log(await response.json());
  } catch (e) {
    console.error(e);
  }
}

// Take over form submission
form.addEventListener("submit", (event) => {
  event.preventDefault();
  sendData();
});

我们为表单元素添加了一个提交事件处理程序。首先,它调用preventDefault() 来阻止浏览器的内置表单提交,以便我们接管。然后,我们调用 sendData(),它检索表单元素并将其传递到 FormData 构造函数。

之后,我们使用 fetch()FormData 实例作为 HTTP POST 请求发送。

另请参阅

学习路径

高级主题