从输入URL到页面返回都需要经过什么
从输入URL到页面返回都需要经过什么
- DNS域名解析
- TCP三次握手
- 发送HTTP请求
- 服务器处理请求并返回HTTP响应
- 浏览器解析渲染页面
- 断开连接
DNS域名解析
浏览器如何通过域名查询URL对应的IP地址
- 浏览器缓存:浏览器搜索自己的 DNS 缓存
- 操作系统缓存:搜索操作系统中的 DNS 缓存(内存中)
- hosts:搜索操作系统的 hosts 文件
- DNS服务器:操作系统将域名发送至 DNS服务器
- LDNS:默认情况下,操作系统会将域名发送至LDMS(本地域名服务器),LDNS会查询自己的DNS缓存,查找成功则返回结果,失败则发起一个迭代DNS解析请求
- LDNS 向 Root Name Server (根域名服务器,其虽然没有每个域名的的具体信息,但存储了负责每个域,如 com、net、org等的解析的顶级域名服务器的地址)发起请求,此处,Root Name Server 返回 com 域的顶级域名服务器的地址
- LDNS 向 com 域的顶级域名服务器发起请求,返回 google.com 域名服务器地址
- LDNS 向 google.com 域名服务器发起请求,得到 www.google.com 的 IP 地址
- LDNS 将得到的 IP 地址返回给操作系统,同时自己也将 IP 地址缓存起来
- 操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
- 浏览器已经得到了域名对应的 IP 地址
TCP三次握手
第一次握手
建立连接时,客户端选择一个序号发送SYN包(SEQ=x)到服务器,并进入SYN_SEND状态,等待服务器确认
第二次握手
服务器收到SYN包,回应一个ACK段作为对x(ACK=x)的回应,同时宣告它自己的序号为y(SEQ=y),也就是SYN+ACK包,即ACK(SEQ=y,ACK=x),这个时候服务器进入SYN_RECV状态
第三次握手
客户端收到服务器ACK包,并在它发送的第一个数据段中(SEQ=x),对服务器选择的序号(ACK=y)进行确认,即DATA(SEQ=x,ACK=y)。之后客户端和服务器进入ESTABLISHED(TCP连接成功状态),完成三次握手。
SEQ: Sequence number 序号
ACK: Acknowledgement number 确认号
SYN: Synchronize Sequence Numbers 同步序列编号
发送HTTP请求
客户端发送一个HTTP请求到服务器的请求消息包括以下格式
- 请求行:请求方法 URL 协议/版本 回车符和换行符(例:POST /admin/auth/login HTTP/1.1)
-
请求头部:头部字段名:值 回车符和换行符(例:Accept-Encoding:gzip,deflate)
-
空行: 回车符和换行符
-
请求数据: (例:{“account”:”admin”,”password”:”admin”})
完整例子
POST /admin/auth/login HTTP/1.1
Host: www.test.com
Connection: keep-alive
Content-Length: 38
Accept: application/json, text/plain, */*
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8
{"account":"admin","password":"admin"}
服务器处理请求并返回HTTP响应
正向代理
如上图,因为google被墙,我们需要vpn翻墙才能访问google.com。
vpn对于“我们”来说,是可以感知到的(我们连接vpn)
vpn对于”google服务器”来说,是不可感知的(google只知道有http请求过来)。
对于人来说可以感知到,但服务器感知不到的服务器,我们叫他正向代理服务器。
反向代理
如上图,我们访问baidu.com的时候,baidu有一个代理服务器,通过这个代理服务器,可以做负载均衡,路由到不同的server。
此代理服务器,对于“我们”来说是不可感知的(我们只能感知到访问的是百度的服务器,不知道中间还有代理服务器来做负载均衡)。
此代理服务器,对于”server1 server2 server3″是可感知的(代理服务器负载均衡路由到不同的server)
对于人来说不可感知,但对于服务器来说是可以感知的,我们叫他反向代理服务器
Nginx
Nginx是什么
Nginx (“engine x”) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。
Php-fpm是什么
cgi、fast-cgi协议
cgi的历史
早期的webserver只处理html等静态文件,但是随着技术的发展,出现了像php等动态语言。
webserver处理不了了,怎么办呢?那就交给php解释器来处理吧!
交给php解释器处理很好,但是,php解释器如何与webserver进行通信呢?
为了解决不同的语言解释器(如php、python解释器)与webserver的通信,于是出现了cgi协议。只要你按照cgi协议去编写程序,就能实现语言解释器与webwerver的通信。如php-cgi程序。
fast-cgi的改进
有了cgi协议,解决了php解释器与webserver通信的问题,webserver终于可以处理动态语言了。
但是,webserver每收到一个请求,都会去fork一个cgi进程,请求结束再kill掉这个进程。这样有10000个请求,就需要fork、kill php-cgi进程10000次。
有没有发现很浪费资源?
于是,出现了cgi的改良版本,fast-cgi。fast-cgi每次处理完请求后,不会kill掉这个进程,而是保留这个进程,使这个进程可以一次处理多个请求。这样每次就不用重新fork一个进程了,大大提高了效率。
2、php-fpm是什么
php-fpm即php-Fastcgi Process Manager.
php-fpm是 FastCGI 的实现,并提供了进程管理的功能。
进程包含 master 进程和 worker 进程两种进程。
master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。
Nginx如何与Php-fpm结合
当我们访问www.example.com的时候,处理流程是这样的:
www.example.com
-> Nginx
-> 路由到www.example.com/index.php
-> 加载nginx的fast-cgi模块
-> fast-cgi监听127.0.0.1:9000地址
-> www.example.com/index.php请求到达127.0.0.1:9000
-> php-fpm 监听127.0.0.1:9000
-> php-fpm 接收到请求,启用worker进程处理请求
-> php-fpm 处理完请求,返回给nginx
-> nginx将结果通过http返回给浏览器
服务器返回一个 HTTP 响应
经过前面的几个步骤,服务器收到了我们的请求,也处理我们的请求,到这一步,它会把它的处理结果返回,也就是返回一个HTPP响应。 HTTP响应与HTTP请求相似,HTTP响应也由3个部分构成,分别是:
- 状态行
- 响应头(Response Header)
- 空行
- 响应正文
HTTP/1.1 200 OK
Server: nginx/1.13.12
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.1.20
Cache-Control: no-cache, private
Date: Tue, 20 Aug 2019 07:42:25 GMT
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="csrf-token" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>seakee-admin</title>
<!-- Styles -->
<link href="/css/app.css" rel="stylesheet">
<link href="/css/element-ui/2.10.1/index.css" rel="stylesheet">
<link href="/css/font-awesome/5.9.0/all.min.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="/js/app.js"></script>
</body>
</html>
浏览器解析渲染页面
浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。
当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。因为JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。所以我明平时的代码中,js是放在html文档末尾的。
### 断开连接
现在的页面为了优化请求的耗时,默认都会开启持久连接(keep-alive),那么一个TCP连接确切关闭的时机,是这个tab标签页关闭的时候。这个关闭的过程就是著名的四次挥手。关闭是一个全双工的过程,发包的顺序的不一定的。一般来说是客户端主动发起的关闭,过程如下。
对于一个已经建立的连接,TCP使用改进的三次握手来释放连接(使用一个带有FIN附加标记的报文段)。TCP关闭连接的步骤如下:
第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。
未经允许禁止转载!!!!本文标题:从输入URL到页面返回都需要经过什么