How does the browser communicate with the server?

The TCP connection includes three stages: establishing a connection, transmitting data and disconnecting the connection, and this time the HTTP protocol we are going to introduce is based on the TCP connection.

The HTTP protocol is a protocol that allows browsers to obtain resources from servers, and is also the basis for our front-end development of the Web. The HTTP protocol is usually initiated by the browser to obtain different types of files from the server, such as HTML files and CSS files commonly used in the front end. The HTTP protocol itself is also the most widely used protocol by browsers.

When we use the browser, we usually encounter the following two situations:

  • When we visit a website for the first time, it may be very slow to open, but the speed is significantly faster when we visit it again.
  • When we log in to a website, the next time we visit the website, we are already logged in.

The principles behind this all require an understanding of the request process of the HTTP protocol. That's exactly what we're going to talk about.

The HTTP request process is roughly divided into two parts: the first part is that the browser initiates an HTTP request to the server, and the second part is the server's response. We will explain from these two parts next.

HTTP 与 TCP

It has been mentioned that the HTTP protocol is based on the TCP connection, so before we explain the HTTP request, we first need to have a deeper understanding of the relationship between the HTTP protocol and TCP.

The browser uses the HTTP protocol as the application layer and the TCP/IP protocol as the transport layer protocol to send it over the network.

Therefore, before HTTP actually starts to work, the browser needs to establish a connection with the server through the TCP protocol, which means that the content of HTTP is essentially realized through the data transmission phase of TCP.

The first step in establishing a TCP connection is to know the IP address and port number of the destination address.

We generally do not directly use the IP address as the URL to access, but access through the domain name deployed on the IP address. Therefore, the first thing we need to use is our domain name address to obtain the destination address.

Domain names and IP addresses are actually a one-to-one mapping relationship, and the system that builds this mapping relationship is called the Domain Name System, or DNS Domain Name System for short.

因此我们在拿到网址 URL 之后,我们就可以通过 DNS 和域名来获得目的地址的 IP 地址。

至于端口号,如果在访问地址的时候没有直接指明端口号,那 么HTTP 协议默认的端口号就是 80。

于是到现在我们就明白了HTTP请求与TCP连接之间的关系大致如下。

  1. HTTP 是应用层协议,需要通过网络层协议 TCP 建立网络连接。
  2. TCP 建立网络连接需要获得目的地址的 IP 地址和端口号。
  3. 我们通过 DNS 和域名可以获得目的地址的 IP 地址。

浏览器发起请求

我们假设在浏览器地址框种输入地址:yucohny.github.io/index.html。那么接下来我们尝试分析浏览器将完成的动作。

构建请求

首先,浏览器需要构建请求行信息,随后,浏览器再准备发起网络请求:

GET /index.html HTTP1.1
复制代码

查找缓存

在正式发起网络请求之前,浏览器都会首先在浏览器的缓存当中查询是否有要请求的文件。

浏览器缓存本身是一种在本地保存资源的副本,以供下次请求时直接使用的一种技术。

当浏览器发现我们想要请求的资源已经存在于缓存当中时,就会拦截请求,直接返回该资源的副本,同时结束请求。这样做有几个明显的好处:

  • 能够缓解服务器端的压力,提升性能。
  • 缓存是实现快速资源下载的重要组成部分。

如果在缓存当中没有找到我们想要请求的资源,那么就会进入正式的网络请求过程。

准备 IP 地址和端口

在前面介绍 HTTP 和 TCP 之间关系的时候,我们已经介绍了如何获取IP地址和端口号:

我们通过 DNS 查找到目的地址的 IP 地址;同时查看 HTTP 协议,本身是否指定了端口号,如果没有指定端口号,那么默认则是 80 端口。

等待 TCP 队列

在一切都准备好了之后,我们仍然不能直接建立 TCP 连接,这是因为 chrome 谷歌浏览器存在一个机制:对于同一个域名,我们最多只能同时建立 6 个 TCP 连接,因此如果在同一个域名下有大于 6 个 TCP 连接同时发生,那么后面的请求则会进入排队等待状态,直到有多的空位来连接。

建立 TCP 连接

这一部分就是浏览器,通过TCP协议与服务器已经成功建立连接。

发送 HTTP 请求

在成功建立 TCP 连接之后,浏览器就可以和服务器进行通信。HTTP 中想要发送的数据,就是在这个通讯过程中传输的。

浏览器请求信息至服务器,本质上请求信息包含了三个部分:请求行、请求头与请求体。

对于请求行而言,则包括了请求方法,请求 URL 和 HTTP 协议版本三个部分,也就是我们前面所提到的构建请求。

请求头包括了一些浏览器的基础信息,比如浏览器所使用的操作系统、浏览器内核,以及浏览器端的 Cookie 等信息。

而请求体则是我们真正想要发送的数据的内容。

至此,浏览器就已经成功向服务器发送了请求。

服务器处理请求

接下来复习将会根据浏览器的请求信息来准备响应的内容。

返回请求

一旦服务器处理结束,就可以返回信息至浏览器。我们可以通过 curl 命令查看响应信息。

我们在本地命令行输入:

curl -i "https://yucohny.github.io/index.html"
复制代码

精简后的返回信息如下:

HTTP/1.1 200 OK
​
Connection: keep-alive
Content-Length: 405
Server: GitHub.com
Content-Type: text/html; charset=utf-8
permissions-policy: interest-cohort=()
Last-Modified: Sat, 26 Mar 2022 14:46:30 GMT
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31556952
ETag: "623f2746-195"
expires: Sun, 27 Mar 2022 07:32:24 GMT
Cache-Control: max-age=600
x-proxy-cache: MISS
X-GitHub-Request-Id: 7CAA:49EE:2FEA23:336FBC:624010B0
Accept-Ranges: bytes
Date: Sun, 27 Mar 2022 07:22:24 GMT
Via: 1.1 varnish
Age: 0
X-Served-By: cache-icn1450078-ICN
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1648365744.209898,VS0,VE183
Vary: Accept-Encoding
X-Fastly-Request-ID: c05cfa310b4d32d60f2c76f6c1d4f38a08916b56
​
<!doctype html>
<html lang="en">
<head></head>
<body>
​
</body>
</html>
复制代码

我使用空行将请求信息划分为了三个部分,分别对应了响应行、响应头与响应体。不难看出这三个部分本质上对应了我们请求信息的三个部分。

响应行包括了 HTTP 协议版本与状态码。

常用的状态码有许多。其中状态码 200 表示处理成功;状态码 404 表示没有找到对应页面。

响应头则包括了服务器自身的一些信息,比如服务器生成返回数据的时间、返回的数据类型,以及服务器要在客户端保存的 cookie 的信息。

而响应体则包含了 HTML 的实际内容。

断开连接

通常情况下,一旦服务器向客户端返回了响应信息,那么就需要关闭 TCP 连接,但是如果浏览器与服务器都在他们的请求信息或者返回信息中加入了以下信息

Connection: Keep-Alive
复制代码

那么 TCP 连接在服务器返回信息后,仍然保持打开状态,这样浏览器就可以继续通过同一个 TCP 连接发送请求。保持 TCP 连接打开可以省去下次需要建立连接的时间提升资源下载的速度。

Guess you like

Origin juejin.im/post/7079678785221558302