浏览器解析 URL
一个标准的 URL 语法通常都建立在由 9 部分构成的通用格式上,浏览器会从用户输入的 URL 字符串中解析对应的内容:
<schema>://<user>:<password>@<host>:<port>;<params>?<query>#<frag>
复制代码
其中比较重要的有:
DNS 域名解析
如果上面提到的
host
部分为
域名
,则需要通过
DNS
对其进行解析。
查找本地 host 文件
用户可以在本地的 host 文件中指定域名和 IP 地址的对应关系,所以浏览器会先去本地的 host 文件中寻找是否存在对应的 IP 地址,如果存在,则向该地址发送请求。
DNS 解析
最终,我们通过 DNS 解析获得了主机的 IP 地址
建立 TCP 连接
三次握手的过程是老生常谈了,资料比较多,这里就不具体赘述了,只列出大致过程:
SYN
报文,请求建立连接
ACK
报文和
SYN
报文,表示同意客户端的建立连接请求,同时自己也请求建立连接
ACK
报文,表示请求已收到
使用 APR 协议定位目标地址
在以太网中,一台主机要把数据帧发送到同一局域网上的另一台主机时,设备驱动程序必须知道以太网地址才能发送数据。而我们只知道IP地址,这时就需要采用 ARP 协议将 IP 地址映射为以太网地址。 在发送第一个 SYN 报文时,IP 层会通过 ARP 协议查询出目标主机的 MAC 地址。 ( TCP/IP协议——ARP详解 )
在
第一次握手
时发送的第一个
SYN
报文首先会通过
connect()
函数到达 IP 层,之后 IP 层会通过查询路由表获取目标主机的 MAC 地址并将其缓存,然后该 MAC 地址会被通过
send()
函数交给网络接口进行封装,最终将数据发送出去。
PS:引用资料的文章非常详细的解释了不同情况下该过程的工作细节,建议认真阅读一遍。
建立 SSL 隧道
如果请求使用的是
HTTPS
协议,则在建立 TCP 连接后,需要通过
四次握手
在其之上再建立一条加密隧道,即
SSL
。
client random
)并传输给服务端
数字证书
server random
)并传输给客户端
数字证书
premaster secret
),使用
公钥
对其进行加密后传输给服务端
client random
、
server random
、
premaster secret
生成
会话密钥
(
session key
)
premaster secret
client random
、
server random
、
premaster secret
生成
会话密钥
(
session key
)
四次握手通过
非对称加密
的方式使客户端和服务端获得并持有相同的
session key
,并通过该 key 值对之后的会话过程进行
对称加密
。
发送 HTTP(s)请求
浏览器使用前两步获得的信息构造
请求报文
,并通过第三步建立起来的 TCP 连接向服务端发送 HTTP 请求。 其中,
请求报文
的基本格式为:
<method><request-URL><version>
<headers>
<entity-body>
复制代码
这三部分分别为
起始行
、
首部
和
主体
,通过浏览器请求发起的默认为
GET
请求,所以没有
主体
部分。
下面展示了一个假想的 HTTP 报文,其中第一行为
起始行
,二三行为
首部
:
GET /index.html HTTP/1.1
Accept: text/html
Host: www.foo.com
复制代码
服务端代理处理请求
服务端代理
即为
nginx
、
apache
等服务器软件,它们会根据配置文件
将请求映射为服务器上具体的文件
,并根据文件类型对其进行处理返回。
直接返回静态文件(.html)
如果文件是类型为
.html
、
.txt
、
.xml
的静态文件,则只需将其内容作为响应的
entity-body
直接返回给客户端。
解析动态文件(.php)
如果文件类型为
.php
、
.jsp
、
.asp
等动态文件,则需要对其进行解析。这里我们只讲解对
.php
文件的操作,以
nginx
服务器为例。
Fast-CGI
模块,构造 Fast-CGI 请求
PHP-FPM
发送 Fast-CGI 请求,
此时 nginx 相当于一个反向代理服务器
master 进程
收到请求
worker 进程
PHP-CGI
解释器对 PHP 文件进行解析,返回结果并生成对 nginx 的响应
服务端代理响应请求
nginx 生成响应报文,返回给客户端。响应报文和请求报文只有起始行的语法有所不同:
<version><status><reason-phrase>
<headers>
<entity-body>
复制代码
关闭 TCP 连接
老生常谈喜闻乐见的四次挥手环节,因为相关资料实在是太多了,这里也不具体赘述了,只列出大致过程:
FIN
报文,表示自己的所有数据已传输完毕
ACK
报文,表示请求已收到
FIN
报文,表示自己的所有数据也都已经传输完毕
ACK
报文,表示请求已收到,并进入
TIME_WAIT
状态