在地址栏输入URL后发生了什么?

401 阅读9分钟

写在前面

在浏览器地址栏输入URL会发生什么?主要是网络传输资源和浏览器渲染两部分。其中,浏览器的渲染机制部分早已写好,欢迎食用👏👏

我有一颗复杂的心,很少人能读懂。-- 浏览器内核篇(一)

接下来,本文将从计算机网络层面梳理该部分内容(基于建立连接的网络请求过程)。

正文

解析URL(统一资源定位符)

URL用于定位目标服务器上的资源。解析URL之前,我们需要知道URL可以分为几部分,下面以 www.example.com:80/path/index.… 为例。

1.https - 方案(scheme)

我们常说的超文本传输协议是一种方案,在上述样例URL中,https表示必须通过https这种方案来请求网络资源,它的非安全版本是http。

二者的安全体现在加密方式上,http是一种未加密的超文本传输协议,而https则是结合对称加密非对称加密的传输协议。

2.www.example.com - 域名(domain)

域名就是服务器地址(IP)的别名,例如本机地址是:127.0.0.1。但是为了更方便记忆,会使用localhost当成IP地址的代名词,也就是域名。

3.80 - 端口(port)

端口是访问服务器具体资源的入口。

只有传输协议 域名 端口三个内容相同的对象,才会被浏览器视为同源。

4./path/index.html - 资源路径(path)

在web发展早期,资源路径是远程服务器上对应资源的物理位置。

5.?value=20 - 路径参数(params)

资源路径参数通常是以&分割的键-值对,用于Web服务器在返回资源前的一些操作。

6.#anchor - 锚点(anchor)

锚点是URL的最后一部分,相当于一个页面的书签。

image.png

一、DNS(Domain Name System)域名系统解析

域名虽然符合人类的记忆习惯,但是对于浏览器来说,IP地址来的更直接。所以,在请求远程Web服务器的资源前,浏览器需要先找到域名对应的IP地址

具体找法如下:

  • 在本地域名服务器缓存中查找域名对应的ip地址。
  • 如果上一步未找到,则去根域名服务器查找。
  • 如果上一步未找到,则去(com)顶级域名服务器查找。
  • 如果上一步未找到,则去权威域名服务器查找,这里是最终保存域名对应IP地址的服务器。

在这个过程中,每个参与了查询的服务器都会缓存一份结果。最后,浏览器也会将得到的对应IP地址写入本地DNS缓存

二、基于TCP协议建立网络连接

TCP是传输控制协议,深入挖掘底层涉及到网络传输模型等内容,这里不做详细讲解。 要进行网络资源传输,建立连接是稳定、可靠的做法。基于TCP建立连接主要就是经历三次握手

这里我们以客户端和服务端为对象说明:

三次握手
  • 第一次握手,客户端向服务端发送建立连接的请求,客户端进入SYN_SEND状态。
  • 第二次握手,服务端接收到了客户端的建立连接请求后,返回同意连接的应答,服务端进入SYN_RECEIVED状态。
  • 第三次握手,客户端接收到了服务端的应答后,再次发送确认接收到响应的应答,客户端、服务端都进入ESTABLISHED状态(已确立)。

也就是一请求,一应答,再是应答的应答。像不像你和女朋友说拜拜的场景:

你:拜拜👋

                            她:拜拜,我会xxxxx

你:我也xxxxx

嗯,没错!有内味了。

但是这个逻辑放在建立连接当中是不是有点不太合适呢?为什么要有第三次握手,两次行不行?

📒回答:

不行,因为第三次握手是客户端向服务端确认接收到回复的应答,表明服务器可以开始传输数据了。

如果只是两次握手,服务端有可能进入无效等待。如果在第一次握手时,客户端第一次发送的SYN数据包在失效前刚好到达了服务端,服务端依旧会响应一个SYN_ACK包给客户端,但是客户端此时可能已经关闭了连接,导致服务端一直收不到应答,一直在等待客户端的回复。

三、基于超文本传输协议传输数据

HTTP是客户端--服务端的一个无状态协议,这表明服务器不会保留两端请求的任何数据。我们可以将HTTP请求抽象地看成是一个实体,一个基于代理(proxy)的实体。

image.png

  1. 请求行(Request Line)
  • 请求行包含了三个主要的部分:

    • 请求方法(Method) :指示了希望对资源执行的操作,常见的有 GETPOSTPUTDELETEHEAD 等。
    • 请求URI(Uniform Resource Identifier) :标识了请求的目标资源,通常是一个路径名或文件名,也可以是完整的 URL。
    • HTTP 版本:指定了使用的 HTTP 协议版本,如 HTTP/1.1 或 HTTP/2

    例如:

    GET /index.html HTTP/1.1
    
  1. 请求头(Request Headers)
  • 请求头包含了多个字段,每个字段由一个关键字和一个值组成,用来传递客户端和服务器之间的元数据。

  • 一些常见的请求头包括:

    • Host: 指定被请求的服务器主机名或 IP 地址。

    • User-Agent: 描述了发出请求的客户端软件的信息。

    • Accept: 表明客户端能够接受哪些类型的内容。

    • Accept-Language: 表示客户端首选的语言。

    • Accept-Encoding: 指出客户端能够理解的内容编码方式,如 gzip 压缩。

    • Authorization: 包含认证信息。

    • Cookie: 包含客户端的 cookie 信息。

    • 请求头的各个字段之间以回车换行符分隔,并且整个头部以一个额外的空行结束。

例如:

Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate

3. 空行(Blank Line)

  • 空行是一个单独的行,用来分隔请求头和请求体。
  1. 请求体(Request Body)
  • 请求体是可选的,只存在于某些类型的请求中(例如 POSTPUT)。请求体包含了要发送给服务器的数据,比如表单提交的数据或者 API 调用中的参数。
  • 在 POST 请求中,请求体通常包含了用户输入的数据。
  • 请求体的数据类型可以通过 Content-Type 头部字段来指定。 例如,对于一个表单提交的 POST 请求:
username=johndoe&password=secret

四、服务端解析请求生成HTTP响应

服务端解析请求后会返回对应响应数据。

1.状态行(Status Line)

  • HTTP 版本:指定了使用的 HTTP 协议版本,如 HTTP/1.1 或 HTTP/2
  • 状态码:表示请求的结果,常用的有 200 OK404 Not Found500 Internal Server Error 等。
  • 状态消息:对状态码的简短描述,如 OKNot Found 等。这个部分是可选的,但在实践中几乎总是存在。

例如:

HTTP/1.1 200 OK

2.响应头(Response Headers)

响应头包含了多个字段,每个字段由一个关键字和一个值组成,用来传递服务器和客户端之间的元数据。这些元数据可以用于帮助客户端处理响应。

一些常见的响应头包括:

  • Content-Type:指定了响应体的媒体类型,如 text/htmlapplication/json 等。
  • Content-Length:指定了响应体的长度(以字节为单位)。
  • Date:指定了响应生成的时间。
  • Server:描述了服务器软件的信息。
  • Set-Cookie:用于设置客户端的 cookie。
  • Cache-Control:用于控制缓存行为。
  • Expires:指定了响应何时过期。
  • Content-Encoding:指定了内容的编码方式,如 gzip 或 deflate

例如:

Content-Type: text/html; charset=UTF-8
Content-Length: 1234
Date: Sat, 24 Aug 2024 22:04:00 GMT
Server: Apache/2.4.41 (Ubuntu)
Set-Cookie: sessionId=abc123; Max-Age=3600; HttpOnly
Cache-Control: max-age=3600
Expires: Sat, 24 Aug 2024 23:04:00 GMT

3. 空行(Blank Line)

空行是一个单独的行,用来分隔响应头和响应体。

  1. 响应体(Response Body)

响应体是可选的,包含了服务器返回给客户端的实际内容。例如,如果请求的是一个 HTML 页面,响应体将包含 HTML 内容;如果请求的是 JSON 数据,响应体将包含 JSON 格式的数据。

五、断开TCP连接

当客户端完成接收来自服务端的数据后可能会断开连接,服务端响应的也可能会断开连接,特别是在收到来自客户端的FIN包后。断开TCP连接的过程被称为四次挥手

  • 第一次挥手:客户端向服务器发送断开连接请求。

  • 第二次挥手:服务器接收到断开请求后,向客户端返回同意断开的响应,并进入 CLOSE_WAIT 状态。

  • 第三次次挥手:如果服务器还有未发送的数据,会继续发送给客户端。发送完之后,服务器进入 LAST_ACK 状态。

  • 第四次挥手:客户端向服务器发送确认应答,并进入 CLOSE_WAIT 状态,持续时间为 2MSL。服务器接收到客户端的应答后,进入 CLOSED 状态。在 2MSL 时间后,客户端自动进入 CLOSED 状态。

其他

后续就是浏览器解析资源的步骤,准备渲染页面。不过,为了让用户更快地浏览页面,浏览器可能会在TCP连接完全断开之前去渲染页面,只要资源是足够的,这取决于浏览器的渲染机制。

总结

浏览器解析URL的前半部分可以分为:

  • DNS解析
  • 建立TCP连接(三次握手)
  • 基于传输协议的数据传输
    • 随请求发送
    • 随响应返回
  • 断开连接(四次挥手)

当然,还有后半部分:

  • 解析HTML
  • 解析CSS
  • 生成渲染树
  • 计算布局
  • 元素分层
  • 绘制图像
  • 合成页面

具体见: 我有一颗复杂的心,很少人能读懂。-- 浏览器内核篇(一)

后续打算围绕HTTP协议的发展写一篇文章,下期见。