HTTP 初学者指南 - 第 1 部分:定义
作为一名 Web 开发者,我有时会将自己的工作描述为“让事物通过互联网相互沟通”。HTTP(超文本传输协议)使这成为可能。换句话说,HTTP 是一种通过互联网从一个程序向另一个程序发送消息的方法。
在本文中,我将介绍 HTTP 术语、工具和 HTTP 消息的结构。我使用类比和隐喻,并从多种方式解释事物,试图提供有用的心理模型。在HTTP 初学者指南 - 第 2 部分:响应中,我将深入研究如何编写代码以在服务器中生成 HTTP 响应消息。之后,在HTTP 初学者指南 - 第 3 部分:请求中,我将介绍如何在客户端中生成 HTTP 请求。在HTTP 初学者指南 - 第 4 部分:API中,我们将对我们的应用程序和其他人为我们构建的一些免费使用 API 进行一些有趣的操作。最后,我将在 HTTP初学者指南 - 第 5 部分:身份验证中介绍 API 密钥等。
引言和目录
本文假设您熟悉 JavaScript 基础知识。我将简要讲解异步 JavaScript 和基本的 Web 开发概念,并在文章末尾提供更多学习资源。
我不会解释TCP 、“协议”一词的众多定义,也不会解释互联网的工作原理。本文只是对如何在 Web 应用程序中使用 HTTP 消息进行概述和指导。
Web 开发术语
首先,让我们定义几个我将经常使用的术语。应用程序或应用程序是在计算机上运行的软件。大多数 Web 应用程序的基本设置是在浏览器(如 Chrome、Firefox 或 Safari)中运行的客户端应用程序,以及为客户端提供服务和资源的服务器应用程序。这样,浏览器就充当了客户端或客户端代码的运行时环境。在 JavaScript 中,用于服务器或服务器端代码的最常见运行时环境是Node.js。换句话说,客户端是与用户交互的代码部分 - 单击按钮或在浏览器中阅读页面上的信息。为了获取用户想要阅读的信息,或者在用户点击某些内容后获取或更新信息,我的客户端将使用 HTTP 与我的服务器通信。
我经常用“应用”来指代我的客户端,因为并非每个 Web 应用都需要服务器。一个 Web 应用可以只包含一个客户端,例如一个计算器,它可以执行所有数学运算,而无需从其他资源获取更多信息。也可以只构建一个客户端,并使用其他人构建的服务器端资源。您可能见过“无服务器”这个术语,它指的是无需自行构建服务器即可创建类似服务器的服务和资源的方法。实际上,无服务器应用需要构建一个客户端,然后使用AWS或Netlify等工具在客户端内部编写服务器端代码。当需要时,您的客户端将使用该工具在其他人构建和托管的服务器上执行服务器端代码。为了在本指南中学习 HTTP,我们将重点关注我上面描述的经典客户端-服务器模型。
我不会使用“前端”和“后端”,因为“客户端”和“服务器”更具体。例如,Web 应用的后端不仅包括服务器,还包括数据库以及服务器使用的任何其他服务和工具。
API 代表应用程序编程接口 (API)。它允许两个应用程序(例如客户端和服务器)相互通信。如果说服务器是整个餐厅,那么 API 就是服务员,菜单就是 API 提供的方法列表,而饥肠辘辘的顾客就是客户端。我将在第四部分介绍 API 的标准化格式及其他内容。
库是开发人员可以在其编写的程序中使用的文件和函数的包/集合/模块。由于 API 是一个广义的术语,并且 API 不仅用于客户端-服务器模型,因此库提供给开发人员使用的方法也可以称为 API。
HTTP 术语、异步 JavaScript 和 HTTP 工具
HTTP有多个版本。HTTP/2 比 HTTP/1.1 更加优化且更安全,大约一半的网站都在使用它。此外,还有由 Google 开发的 HTTP/3。您可能已经熟悉 URL 中的 http:// 和 https:// 以及浏览器的安全警告。HTTP 消息在使用 HTTPS 发送时是加密的,而使用 HTTP 发送时则不加密。
有多个库可用于发送 HTTP 消息。例如,curl可以在命令行中使用。它们都使用 HTTP,因此所需的信息相同。区别在于使用场景、创建 HTTP 消息的语法、它们提供的选项以及使用的协议(例如 HTTP 与 HTTPS、HTTP/1.1 与 HTTP/2)。更强大的库可以做更多的事情。
在查看 JavaScript HTTP 库时,您可能会遇到术语 AJAX 或 Ajax。它代表异步 JavaScript 和 XML。简而言之,异步代码运行顺序混乱。通过互联网发送消息并接收消息需要时间。异步代码本质上可以暂停执行,直到收到数据,然后从中断处继续执行。XML 代表可扩展标记语言。它类似于 HTML,但没有预定义的标签。它是一种用于构建您可能在 HTTP 消息中发送的数据的格式。即使消息不包含数据或数据不是用 XML 构建的,Ajax 也可以指将 HTTP 与 JavaScript 结合使用。
当你编写 JavaScript 并将其运行在浏览器中时,你可以使用许多内置工具。很难想象构建一个没有 Web API(例如HTML DOM和URL)的网站会是什么样子。长期以来,唯一可用的 HTTP Web API 是XMLHttpRequest或 XHR。由于它是一个 Ajax 库,它终于允许网页从数据库中提取数据,而无需刷新整个页面。
除 IE 外,所有浏览器都支持更现代的版本,即Fetch。对 Fetch 的支持刚刚在2022 年 1 月的 Node.js 最新版本中实现。它基于 XHR 构建,为 HTTP 对话的两部分都提供了接口(预期格式),其中 XHR 使用回调,而 Fetch 使用 Promises。
回调和 Promise 是相当大的话题。本质上,回调函数作为参数传递给异步 (async) 函数。异步函数获取所需信息后,将执行回调函数。另一方面,Promise 是异步函数返回的对象。它们有三种状态:待处理、已完成和已拒绝。返回 Promise 的异步函数可以使用.then()
和进行链式调用.catch()
。这样,开发人员可以将返回的已完成 Promise 传递给函数 in ,.then()
或将返回的已拒绝 Promise 传递给函数 in.catch()
并处理错误。JavaScript 还具有 async/await 语法,该语法使用 Promise,而无需显式创建 Promise 对象或将其传递给链式调用。(不过,如果您愿意,仍然可以将它们链式调用。)其他函数可以调用await asyncFunction()
并等待结果,然后再继续执行。通常,函数调用的结果会设置为稍后使用的变量。我将在第 3 部分中提供代码示例,并在本文末尾提供更多学习这些主题的资源。
最后,还有像Axios这样的包。Axios 不仅提供接口并使用 Promises,还允许开发人员使用 XHR 在浏览器中发出客户端 HTTP 请求,以及在 Node.js 中发出服务器端 HTTP 请求。它还提供更多选项并为您格式化消息。
在我们讨论第 2 部分和第 3 部分中如何编写通过互联网发送 HTTP 消息的代码之前,让我们先深入了解一下消息本身的结构。
请求的结构
如果我们说客户端和服务器正在进行对话,那么对话的两部分就是请求和响应。使用 HTTP 请求,客户端正在向服务器发出请求。
每个请求都需要一些信息才能工作:
- 方法:方法告诉服务器客户端希望它做什么。
- URL:URL 告诉 HTTP 工具将请求发送到哪里。
- 协议:由所使用的HTTP工具设置。
- 标头:标头向服务器提供有关请求本身的更多信息。
HTTP 请求消息中的 URL 就像你在浏览器中输入 URL 来访问网页一样。URL 还可以用于发送其他信息——我将在第二部分中详细解释 URL 及其使用方法。
还有一个可选部分:
- 正文:如果请求使用向服务器发送数据的方法,则数据将包含在正文中,紧跟在标头之后。
因此 HTTP 请求消息看起来是这样的:
第一行(此处显示为红色)包含方法、URL 和协议。第二行(黄色)包含所有标头。中间有一个空行,如果包含正文,则放在末尾(此处显示为蓝色)。
方法
解释方法最简单的方法是将它们映射到持久存储缩写 CRUD。CRUD 代表创建、读取、更新和删除。您可以从使用 SQL 的数据库角度来思考它:
创建 = INSERT
读取 = SELECT
更新 = UPDATE
删除 = DELETE
您可以从应用程序的 UI 角度来考虑这个问题:
创建 = 用户发表新帖子
阅读 = 用户查看新闻源
更新 = 用户编辑帖子
删除 = 用户删除帖子
对于 HTTP 请求:
创建 = POST
读取 = GET
更新 = PUT 或 PATCH
删除 = DELETE
注意:我没有介绍更多方法,因为我还没有使用它们。
POST 向服务器发送数据并导致更改。它需要一个主体。GET
请求服务器通过响应返回数据。它没有主体。PUT 向
服务器发送数据以创建新资源或替换现有资源。它需要一个主体。PATCH
向服务器发送数据以更新现有资源的部分内容。它需要一个主体。DELETE
请求删除资源。如果 URL 中不包含用于标识要删除的资源的信息,则可能需要主体。
请求标头
HTTP 请求标头有很多。如果服务器是一场音乐会,HTTP 请求是参加者,则标头就像参加者的门票和 ID。Origin 标头会告诉服务器请求来自哪里。Accept 标头会告诉服务器应该使用哪种格式进行响应。Content-Type 标头告诉服务器请求主体正在使用哪种格式。其中一些是由 HTTP 库自动生成的。还有一些,比如身份验证标头,由服务器指定。我将在第 4 部分中介绍身份验证,届时我将从需要密钥的 API 请求数据。您会在请求和响应中找到许多标头。如果 HTTP 规范将标头称为请求标头,则它仅提供有关请求上下文的信息。开发人员会在对话中将请求中包含的标头称为请求标头,即使它们也可以用作响应标头,反之亦然。
请求正文
HTTP 消息体可以打包成多种标准化的数据传输格式。这些格式被称为媒体类型或 MIME 类型,种类繁多。XML 和 JSON 是你最常看到的两种。它们都创建单资源消息体,这意味着它们在 HTTP 消息体中是一个文件。
JSON 代表 JavaScript 对象表示法。它拥有标准语法,可以创建更小的文件。JavaScript 内置方法可以轻松地将 JSON 字符串转换为有效的 JavaScript 对象。JSON 只能使用 UTF-8 编码,并且具有多种类型。XML 无类型,可以保留原始数据的结构,支持多种编码类型,更安全,并且可以在浏览器中直接显示,无需任何更改。XML 需要一些工作才能解析为 JavaScript,人类阅读起来更困难,但机器更容易读取。XML 与 JSON 的比较,JSON 如何成为最广泛使用的 HTTP 数据传输格式,以及还有哪些其他格式仍然存在,这是一个很大的话题。Twobithistory的概要将带您深入其中。我将在第 2 部分和第 3 部分中使用 JSON 并介绍其语法和内置的 JavaScript 方法。
请求正文中使用的 MIME 类型和字符编码在 Content-Type 请求标头中声明,以便服务器知道如何解码和处理请求正文中的数据。XML 内容会application/xml
在标头中包含 。JSON 内容则会包含application/json
。
多资源主体的最佳示例是从网页上的 HTML 表单发送的数据。它应该包含multipart/form-data
在 Content-Type 标头中。与单个主体不同,表单的每个部分都有多个主体,每个主体都有各自的 Content-Type 标头。因此,用户输入的数据可以连同他们用于输入数据的 HTML 元素的属性一起发送到服务器。因此,如果您有一个<input>
包含类似 属性的name="first_name"
请求体,则请求主体将包含“name='first_name'”,其中包含用户在 中输入的姓名<input>
。
回复结构
客户端发送 HTTP 请求后,服务器会返回 HTTP 响应。每个响应都会返回一些信息:
- 协议:由所使用的 HTTP 工具设置。
- 状态代码:一组数字,告诉您从请求到响应的过程如何。
- 状态消息:一个人类可读的描述,它将告诉您从请求到响应的过程如何进行。
- 标题:向客户端提供有关响应本身的更多信息。
还有一个可选部分:
- Body:如果响应包含来自服务器的数据,则会包含在此处。请求和响应主体使用相同的格式。
因此 HTTP 响应消息看起来是这样的:
第一行(此处以红色显示)包含协议、状态码和状态消息。接下来,黄色部分包含报头。报头之后是一行空行。最后,如果有数据需要返回,则包含正文(此处以蓝色显示)。
状态代码和消息
您在使用互联网时一定遇到过状态代码。每个人都见过“404 未找到”,您可能也见过“403 禁止访问”。编写 HTTP 请求时,您最希望看到的是成功的“200 OK”。编写客户端代码时,您最不想看到的是 400 类状态代码,例如“400 错误请求”和“405 方法不允许”。服务器出现问题时,则会出现 500 类状态代码,例如“500 内部服务错误”或“503 服务不可用”。
从技术上讲,这些都是标准化的。问题在于,人们可以编写要返回的响应,并可以选择他们想要的任何状态代码和消息。理想情况下,来自非您构建的资源的响应将使用标准化的代码和消息。您经常会发现,您必须阅读文档或与资源交互才能了解如何处理其响应格式。
如果您希望了解带有动物图片的状态代码和消息,请查看HTTP Cats和HTTP Status Dogs。
跨域资源共享 (CORS)
由于大多数(但不是全部)CORS 标头都是请求标头,因此让我们在这里深入研究 CORS。
CORS代表跨域资源共享。默认情况下,运行 JavaScript 的浏览器和服务器会使用 CORS 来阻止来自与服务器不同源的客户端的请求,以确保安全。CORS 的目标是保护客户端和服务器免于执行 HTTP 请求中包含的恶意代码,并防止服务器数据被窃取。
对于大多数浏览器来说,来源指的是主机、协议和端口(如果指定了端口)。主机是 URL 中www之后、/ 之前的部分。因此,对于www.google.com来说,主机就是 google.com。协议是 HTTP 而不是 HTTPS,协议是 HTTP/1.1 而不是 HTTP/2。在http://localhost:3000中,端口为 3000 。
在发送原始请求之前,HTTP 会发送一个预检请求,其中包含一些标头,例如源和方法,以检查您要发出的请求是否安全。然后,服务器会返回一个预检响应,其中包含 CORS 标头,例如 Access-Control-Allow-Origin 和 Access-Control-Allow-Methods,用于告知浏览器原始请求是否被允许。如果请求被 CORS 阻止,则此时该请求将被阻止。
只有在编写服务器代码时,您才能指定服务器是否允许 CORS 请求。例如,服务器的响应将包含 Access-Control-Allow-Origin 标头,以列出可以接收请求的来源。如果您的来源不在响应的 Access-Control-Allow-Origin 标头列表中,则您的请求将被阻止,并且除非您编写发送响应的代码,否则您无法更改此设置。
如果服务器放宽了 CORS 限制,通常会将其替换为强制身份验证,或使用 Access-Control-Allow-Methods 标头将请求方法限制为仅限 GET。身份验证信息可以通过标头或 URL 发送(更多内容请参见第四部分)。
然而,即使服务器允许 CORS 请求,您的浏览器也会在客户端代码中阻止 CORS 请求。您可以通过使用自己的服务器向服务器请求数据,然后将所需的响应内容传递给客户端来解决这个问题。
更多资源
如果你只是初次接触异步 Javascript,我强烈建议你放下手中的一切,立即观看两个视频:Philip Roberts 的“事件循环到底是什么?”和Jake Archibald 的“In The Loop”。
回调和 Promises 是比较难的概念,我解释得很快。我真正理解它们,是经过几个月每天用它们写代码之后。在学习 Promises 之前,最好先了解一下回调,因为 Promises 对象和链式调用本身就有一定的挑战性。以下是一些资源,应该能帮助你理解它们:
- https://www.digitalocean.com/community/tutorials/understanding-the-event-loop-callbacks-promises-and-async-await-in-javascript
- https://www.better.dev/callbacks-promises-and-async
- https://theunlikelydeveloper.com/javascript-callbacks/
- https://bitsofco.de/javascript-promises-101/
- https://ebooks.humanwhocodes.com/promises
- https://javascript.info/async-await
结论
在开始写代码之前,我们做了大量的定义!HTTP 消息很复杂,但它们也是 Web 应用程序的核心。如果您对此感到困惑,或者想了解更多关于我所讨论主题的资源,请随时在下方留言。
接下来,请查看HTTP 初学者指南 - 第 2 部分:响应!
文章来源:https://dev.to/abbeyperini/a-beginners-guide-to-http-part-1-definitions-38m7