逻辑模型
逻辑模型 | 协议 | 设备 | 备注 |
---|---|---|---|
应用层 | (运行在tcp上有)FTP、http、SMTP、TEL*** (运行在udp上有)TFTP、DHCP、DNS、SNMP | ||
表示层 | JPEG、ASCII、GIF、PES、MPEG | 媒体信息,JPEG等 | 被称为翻译官 |
会话层 | RPC,SQL,NFS | 建立会话IP,这个时候,就可以称报文了 | |
传输层 | TCP,UDP | TCP 面向连接,可靠连接 三次握手,四次挥手 UDP:不可靠,不稳定,但是速度快 | |
网络层 | IP、ICMP、IGMP、IPX、ARP、RARP | 路由器 | 有两个作用:1. 寻址2. 路由 通过IP 进行寻址 |
数据链路层 | IEEE802.3/2 | 网桥(实现物理层虎数据链路层协议转换) | MAC地址:每个网卡的唯一标识 |
物理层 | RJ-45 | 中继器 | 单位比特(bit),在这一层主要就是窜书比特流 |
基本的协议
FTP:文本传输协议
TFTP:简单文件传输协议
HTTP:超文本传输协议
SMTP:简单邮件传输协议
DHCP:动态主机配置协议
TEL***:远程登录协议
DNS:域名系统
SNMP:简单网络管理协议
ICMP:网络控制报文协议
IGMP:国际组管理协议
ARP:地址解析协议
RARP:反向地址解析协议
NFS:网络文件存储系统
在浏览器中输入URL后,执行的全部过程。(一次完整的http请求过程)
- 域名解析
- 发起TCP3次握手
- 发起http 请求
- 服务器响应http 请求
- 浏览器解析html 代码 ,并且请求html 代码中的资源
- 浏览器对页面进行渲染
- 断开TCP 连接
域名解析
DNS,就是Domain Name System的缩写,翻译过来就是域名系统,是互联网上作为域名和IP地址相互映射的一个分布式数据库。DNS能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过域名,最终得到该域名对应的IP地址的过程叫做域名解析(或主机名解析)。
关于DNS解析的TTL参数:
我们在配置DNS解析的时候,有一个参数常常容易忽略,就是DNS解析的TTL参数,Time To Live。TTL这个参数告诉本地DNS服务器,域名缓存的最长时间。用阿里云解析来举例,阿里云解析默认的TTL是10分钟,10分钟的含义是,本地DNS服务器对于域名的缓存时间是10分钟,10分钟之后,本地DNS服务器就会删除这条记录,删除之后,如果有用户访问这个域名,就要重复一遍上述复杂的流程。
其实,如果网站已经进入稳定发展的状态,不会轻易更换IP地址,我们完全可以将TTL设置到协议最大值,即24小时。带来的好处是,让域名解析记录能够更长时间的存放在本地DNS服务器中,以加快所有用户的访问。设置成24小时,其实,还解决了Googlebot在全球部署的服务器抓取网站可能带来的问题,这个问题麦新杰专门有一篇博文,请参考:http://www.maixj.***/wlyx/googlebot-8890
阿里云之所以只将TTL设置成10分钟,是为了让域名解析更快生效而已。因为之前的解析会在最长10分钟之后失效(本地DNS服务器将对应的解析条目删除),然后新的解析生效。如果是24小时,这个生效的时间最长就是24小时,甚至更长(本地DNS服务器要有用户请求,才会发起查询)。
参考文档:https://www.***blogs.***/crazylqy/p/7110357.html
DNS 缓存:
DNS,(域名系统)缓存,有时也称为 DNS Resolver Cache,是信息的临时存储。它由您的计算机维护,其中包含所有最近访问的网站及其 IP 地址的记录。
它充当数据库,保存 DNS 查找的副本,本地存储在您的浏览器或操作系统上。每当尝试加载网站时,您的计算机都可以快速引用它。DNS 缓存就像一个电话簿,存储所有公共网站及其 IP 地址的索引。它的主要目的是通过在请求发送到大量公共 DNS 服务器之前处理您最近访问的地址的名称解析来加快加载网站的请求。由于信息在本地可用,因此该过程要快得多。
————————————————
参考文档:https://blog.csdn.***/allway2/article/details/124099989
注意:student 公司有两个权限域名服务器
下面来详细解释DNS 域名解析的过程:
在网页输入一个url 地址,例如www.baidu.***
第一步,先看浏览器缓存
查看浏览器缓存中有没有这个域名对应的解析过的IP地址;如果缓存中有,那么就返回域名。
注意:浏览器缓存大小、时间都有限制。域名缓存的时间,可以通过TTL 属性设置。
例如查看chrome 浏览器的缓存,chrome://***-internals/#dns,可以对缓存进行查看和清空。
第二步 看操作系统DNS缓存
查看操作系统DNS 缓存有没有这个域名对应的解析过的IP地址;如果缓存中有,那么就返回域名。
通过命令提示符
查看
在cmd 中,输入命令:
ipconfig /displaydns
执行该命令后,将显示以下结果:
属性 | 属性值 | 备注 |
---|---|---|
记录名称 | assets-cdn.Github.*** | DNS 中查询的名称以及记录 |
记录类型 | 1 | 条目类型,每个DNS协议都有一个编号 |
生存时间 | 194667 | 有效时间值,单位秒 |
数据长度 | 4 | 字节长度,IPv4:4字节,IPv6 :16字节 |
部分 | 答案 | 查询的答案 |
A (主机)记录 | 140.82.114.9 | 域名 |
导出查看
ipconfig /displaydns>dnstlog.txt
其他命令:
ipconfig /flushdns//强制更新缓存
服务器上清除:
dnscmd /clearcache
使用powershell
查看
Get-DnsClientCache
获取更多信息
Help Get-DnsClientCache –full
清除本地 DNS 服务器缓存,请使用命令行:
Clear-DnsServerCache
清除客户端缓存,请使用以下命令:
Clear-DnsClientCache
第三步 查看host 文件
查看host 文件中有没有这个域名对应的解析过的IP地址;如果缓存中有,那么就返回域名。
Windows hosts文件路径: C:\WINDOWS\system32\drivers\etc\hosts
第四步 查看本地DNS 服务器缓存
查看本地DNS服务器缓存中有没有这个域名对应的解析过的IP地址;如果缓存中有,那么就返回域名。
本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动
第五步 查看根域名服务器
本地DNS域名服务器中没有,那么就向根域名服务器请求;
第六步 根域名服务器返回顶级域名服务器地址
根域名服务器返回给本地DNS域名服务器一个顶级域名服务器地址,它是国际顶级域名服务器,
如.***、.***、.org等,全球只有13个不同域名。
第七步 本地域名服务器访问顶级域名服务器
本地DNS服务器再向上一步获得的顶级DNS服务器发送解析请求
第八步 顶级域名服务器返回给本地DNS服务器 要访问的权威服务器地址
顶级域名服务器查找并返回此域名对应的Name Server 域名服务器的地址。这个Name Server 服务器就是我要访问的网站域名提供商的服务器。
其实该域名的解析任务就是由域名提供商的服务器来完成。 比如我要访问www.baidu.***,而这个域名是从A公司注册获得的,那么A公司上的服务器就会有www.baidu.***的相关信息。
Name Server服务器会查询存储的域名和IP的映射关系表,再把查询出来的域名和IP地址等等信息,连同一个TTL值返回给本地DNS服务器。本地DSN 服务器会混存着域名和IP 的对应关系。缓存时间由TTL 值控制。如果没有查到,那么就会告诉本地DNS 服务器一个权威域名服务器的地址。
第九步 本地DNS 服务器请求权威DNS服务器
第十步 权威DNS服务器把对应的ip 地址发送给本地DNS 服务器
第十一 本地DNS 服务器把域名解析结果返回给本地电脑
把解析的结果返回给本地电脑后,本地电脑根据TTL值缓存在本地系统缓存中,域名解析过程结束在实际的DNS解析过程中,可能还不止这11步,如Name Server可能有很多级,或者有一个GTM来负载均衡控制,这都有可能会影响域名解析过程。
递归查询:
本地电脑向本地DNS 请求;等待结果就行,不需要本地电脑在去做什么;
迭代查询:
当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:“你下一步应当向哪一个域名服务器进行查询”。然后让本地服务器进行后续的查询。
发起TCP3次握手
全双工:双方都能够接收到信息
TCP: 传输控制协议,是一种,面向连接,可靠的数据传输协议。
面向连接: 数据传输之前客户端和服务端必须建立链接
可靠的:数据传输是有序的,要对数据进行校验
SYN:同步位;SYN=1,表示要做一个连接请求;
ACK :确认位;ACK=1,表示确认有效;ACK==0,表示确认无效;
seq:序列号
ack:确认号;对方发送的序号+1;
前提条件:
服务端是启动状态;
流程:
- 客户端主动发起请求; 请求发送到服务器;携带信息:
SYN=1;
seq = x;(x 序列号是客户端随机的) - 服务器给客户端发送一个响应,表示自己收到了;携带信息:
SYN=1;
ACK=1;
ack = x+1;
seq = y;(y序列号是服务器随机的) - 客户端给服务端发送一个响应,表示自己收到了;携带信息:
ACK=1;
ack =y+1;
seq = x+1;(每次都会发送一个seq,值为上次的x+1)
此时就可以进行数据传输了
发起http请求
发送请求的方法
方法名称 | 方法说明 | 支持的HTTP 协议版本 |
---|---|---|
get | GET 方法用于根据 URI 参数从服务器中获取数据,是最常用的请求方法之一 | 1.0、1.1 |
head | HEAD 方法与 GET 方法类似,但服务器在响应时只返回响应行和响应头,不会返回响应体 | 1.0、1.1 |
post | POST 请求用于将数据发送到服务器。例如使用 HTML 表单上传文件或提交客户信息等 | 1.0、1.1 |
put | PUT 方法可以向服务器中写入文档,有点类似于使用 FTP 上传文件 | 1.0、1.1 |
delete | DELETE 方法用于删除 URI 所指定的目标资源,与 PUT 方法正好相反 | 1.0、1.1 |
connect | CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信 | 1.1 |
options | OPTIONS 方法用来查询目标资源所在服务器支持的 HTTP 方法 | 1.1 |
trace | TRACE 方法可以让服务器端将收到的请求返回给客户端,主要用于开发阶段的测试和诊断 | 1.1 |
link | 建立和资源之间的联系 | 1.0 |
unlink | 断开链接关系 | 1.0 |
http 状态码
- 1xx:指示信息-表示请求已接收,继续处理;这类响应是临时响应
- 2xx:成功-表示请求已被成功接收
- 3xx:重定向-要完成请求必须进行更进一步的操作
- 4xx:客户端错误-请求有语法错误或请求无法实现
- 5xx:服务器错误-服务器未能实现合法的请求
比如: - 200 OK:客户端请求成功
- 202 A***epted 已接受,但是未处理成功
- 204 请求处理成功,但是没有资源返回
- 206 Partial Content:客户发送了一个带有Range头的GET请求,服务器完成了它
- 301 Moved Permanently:永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替。
- 302 Found:临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
- 303 303和302状态码有着相同的功能,但是303明确表示客户端应当采用get方法获取资源
- 304 Not Modified:客户端有缓冲的文档并发出了一个条件性的请求,服务器告诉客户原来缓冲的文档还可以继续使用
- 305 Use Proxy: 使用代理。所请求的资源必须通过代理访问
- 307 Temporary Redirect:临时重定向。与302类似。使用GET请求重定向
- 400 Bad Request:客户端请求有语法错误,不能被服务器所理解
- 401 Unauthorized:请求未经授权,这个状态代码必须和WW-Authenticate报头域一起使用
- 403 Forbidden:对被请求页面的访问被禁止
- 404 Not Found:请求资源不存在
- 500 Internal Server Error:服务器发生不可预期的错误原来缓冲的文档还可以继续使用
- 502 Bad Gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求
- 503 Server Unavailable:请求未完成,服务器临时过载或当机,一段时间后可能恢复正常
get 和post 的区别
其实get 和post 没有本质的差别;
两者只是请求方法不一样;
get 请求浏览器里面带不了请求体;在nodejs 里面可以携带请求体。
post 请求在浏览器里面可以带请求体
所以在浏览器中,get 和post 的区别:
- GET 通过url 传递参数,POST 可以通过url 和request body 传递参数;
- GET 传递的参数上限是2k;POST 没有限制
- GET在浏览器回退时是无害的,而POST会再次提交请求
- GET产生的URL地址可以被收藏,而POST不可以
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置
- GET请求只能进行url编码,而POST支持多种编码方式
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
- GET请求在URL中传送的参数是有长度限制的,而POST没有限制
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
<script>
axios({
method:'GET',
url:'/list',
data:{
page:1,
num:20
}// 请求体会被直接忽略掉 抓包可以看到只有请求头,没有请求体
}).then(res=>{
console.log(res.data)
})
</script>
但是如果在nodejs 中
const axios = require('axios')
axios({
method:'GET',
url:'http://localhost:8002/list',
data:{
page:1,
num:20
}//nodejs 会从get 请求中获取这个请求体的
}).then(res=>{
console.log(res.data)
})
nodejs 接收打印
app.get('*',(req,res)=>{
console.log('nodejs server get',{
method:req.method,
url:req.url,
headers:req.headers,
body:req.body
})
res.send('ok')
})
post 两次请求
当发送post时,有时候,有发现有options请求;有options 一共有两种情况:
当请求头是application/json 的形式的时候:
1.跨域;
2. 自定义请求头的时候也会发送;
当发送跨域的POST请求时,浏览器会先发送一次OPTIONS请求,这是因为浏览器的同源策略。OPTIONS请求被称为预检请求(pre-flightrequest),它是CORS(跨源资源共享)机制中的一部分。
预检请求的目的是为了确保实际请求(例如POST、PUT等)对目标服务器是安全的。在实际请求之前,浏览器向服务器发送一个预检请求,询问服务器是否允许跨域请求以及允许哪些HTTP方法、头部字段等。服务器通过响应头信息告诉浏览器它支持哪些方法和头部字段。
OPTIONS请求会包含以下头部信息:
0zigin’:表示请求来源的域名
表示实际请求将使用的HTTP方法。A***ess-Control-Request-Method: 表示实际请求将携带哪些自定义头部字段。A***ess-Control-Request-Headers
:
服务器需要在响应头中返回一些CORS相关的信息,例如:
表示哪些域名可以进行跨域访问A***ess-Control-Allow-0rigin
表示允许哪些HTTP方法。A***ess-Control-Allow-Methods:
表示允许哪些头部字段。A***ess-Control-Allow-Headers`:
如果服务器允许当前请求的跨域访问,那么浏览器才会发起实际的POST请求。否则,浏览器将阻止请求,并在控制台报告错误。
跨域
解决跨域的方式
-
- jsonp
-
- axja cors 跨域
-
- websocket
-
- postMessage
-
- document.domain+iframe
-
- window.name+iframe
-
- location.hash+iframe
-
- nginx
-
- node 中间件代理跨域
比如:
c++ 在后台设置跨域:
- node 中间件代理跨域
A***ess-Control-Allow-Headers:Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE,x-requested-with,Authorization
nodejs 在后台设置跨域:
app.all("*",function(req,res,next){
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("A***ess-Control-Allow-Origin","*");
//允许的header类型
res.header("A***ess-Control-Allow-Headers","content-type");
//跨域允许的请求方式
res.header("A***ess-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
if (req.method.toLowerCase() == 'options')
res.send(200); //让options尝试请求快速结束
else
next();
}
减少http请求的策略
cdn
cdn
代理模式
- 解决系统之间的耦合度以及系统资源开销大的问题
- 通过代理对象可以保护被代理对象,使被代理对象扩展性不受外界的影响
- 可以通过代理对象解决某一交互或者某一需求中造成的大量系统开销
浏览器的缓存策略
按照缓存存储位置:
名称 | 内存缓存(memory cache) | 硬盘缓存(disk cache) | Service Worker |
---|---|---|---|
特点 | 快速读取和时效性; | 读取复杂,速度比内存缓存慢;允许跨会话,跨站点情况使用;持久存储;HTTP头部判断’ | |
方式 | preloader、preload | ||
判断方 | 浏览器内部 | 浏览器内部 | 可以人直接操控 |
内存缓存:
特点
- 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
- 时效性:一旦该进程关闭,则该进程的内存则会清空。
- 短期存储
- 网络请求几乎都会自动加入
使用方式:
-
preloader
浏览器打开网页,先请求html,若有js、css等资源,会使用CPU资源进行解析并执行。之前是串行模式,即请求js/css-解析执行-请求下一个js/css-解析执行。我们会发现解析时候,网络请求是空闲的,使用preloader则可以在解析资源的同时,还能请求下一批资源 ,使用preloader请求来的资源会放到memory cache,供之后解析执行操作 -
preload
显式的预加载资源,也会放到memory cache。比如 memory
cache保证了页面中两个相同请求,都实际请求最多一次,比如(两个src相同的,两个href相同的),匹配缓存时,不仅匹配相同的url,还会比较他们的类型、CORS中的域名规则等。脚本(script)类型被缓存的资源是不能用在(image)类型的请求中,即使他们的src相等Service Worker
Service Worker 是由开发者编写的额外的脚本,且缓存位置独立,出现也较晚,使用还不算太广泛。memory cache与disk cache都是通过浏览器内部判断,Service Worker可以直接操作缓存,储存在Application中的Cache Storage 。关闭浏览器或者tab缓存依然存在。除非手动调用cache.delete(resource)或者容量超出限制,被浏览器全清空。 Service Worker没能命中缓存,则会用fetch()方法继续获取资源,此时memory cache或者disk cache进行下一次找缓存工作。Service Worker 的 fetch() 方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,也会标注为 ServiceWorker缓存。
为了提升之后请求的缓存命中率,自然要把这个资源添加到缓存中去。
- 根据 Service Worker 中的 handler 决定是否存入 Cache Storage (额外的缓存位置)
- 根据HTTP头部字段(Cache-control,Pragma等)决定是否加入disk cache
- preloader、preload保存一份资源的引用
举例:
区别 | 内存缓存 | 硬盘缓存 |
---|---|---|
存储内容 | JS、字体、图片等 | CSS 等 |
读取速度 | 快 | 慢 |
时效性 | 进程关闭则清空 | 可以缓存很长一段时间 |
空间 | 空间小 | 空间大 |
内存缓存和硬盘缓存并存:优先考虑内存缓存
浏览器缓存按照失效策略主要有两类:
浏览器向服务器请求一次数据之后,会进行存储为离线资源;即本地已经缓存下来了。这样可以减少网络带宽的使用。访问速度加快,是一种提升网站性能的有效策略。
key | 说明 |
---|---|
Last-Modified | 标记此文件在服务期端最后被修改的时间 |
Expires | 过期时间 |
If-Modified-Since | 在发送HTTP请求时,接收浏览器端缓存页面上一次请求返回的L的最后修改时间一起发到服务器去 |
Etag | Etag 是资源对应的hash值(比如Apache,默认是对文件的索引节“Inode”、大小“Size”、和最后的修改时间“MTime”进行hash),每个资源的hash值都不一样;第一次请求时,服务器返回头中,有Etag字段; |
If-None-Match | 再次请求相同的资源的时候;浏览器会在请求头中,加入If-None-Match:上一次的Etag;服务器接收到请求后后,会和请求资源进行比对,然后返回200或者304 |
协商缓存和强缓存
1.强制缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的***work选项中可以看到该请求返回200的状态码;
2.协商缓存:在使用本地缓存之前,需要向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;协商缓存可以解决强制缓存的情况下,资源不更新的问题。
共同点:
都是从客户端缓存中读取资源;
区别:
强缓存不会发请求,协商缓存会发请求。
强缓存
实现方式:
都是后端实现,在响应头设置;
- Expires:HTTP/1.0 表示资源过期时间,缺点是采用的是本机时间(绝对时间)
- Cache-Control:HTTP/1.1
为了解决Expires时间不准的问题(相对时间)
Catch-Control:max-age=0;强制不缓存
Expires:
在发送请求中,请求头携带
If-Modified-Since:Tue, 06 Jun 2023 12:10:04 GMT
key | value |
---|---|
If-Modified-Since | Tue, 06 Jun 2023 12:10:04 GMT |
value 值是上次请求,响应头返回的
Last-Modified: Tue, 06 Jun 2023 12:10:04 GMT
key | value |
---|---|
Last-Modified | Tue, 06 Jun 2023 12:10:04 GMT |
也就是说;
第一次请求:
响应头返回两个数据:
Expires:Tue, 06 Feb 2024 11:34:32 GMT
Last-Modified:Tue, 06 Jun 2023 12:10:04 GMT
第二次请求:
把第一次请求的Last-Modified 的value 值给到
If-Modified-Since 的值;
服务器接收到请求后,会把请求头里的If-Modified-Since 与之前给请求头的Last-Modified 做对比,如果不一样,那么就返回
资源+expires+ Last-Modified;
如果一样,那么就返回304状态码
Expires | Cache-Control | |
---|---|---|
时间 | 取本机时间(绝对时间) | 取本机时间(相对时间) |
时间单位 | min | second |
预期 | 本地时间和服务器时间不一致;导致缓存时间和预期不一致;如果资源1min 一换,那么expires 检测不出来 | 采用相对时间,至少保证缓存时间长度是正确的 |
优先级 | 低 | 高 |
Expires:设置以分钟为单位的绝对过期时间,设置相对过期时间,max-age指明以秒为单位的缓存时间;
Expires优先级比Cache-Control低,同时设置Expires和Cache-Control,优先考虑Cache-Control
Cache-Control几个比较常用的设置值:
名称 | 说明 |
---|---|
max-age=300 | 距离上次请求服务器资源没有超过300s,那么就访问本地缓存,与响应头的ETage 相互配合 |
no-cache | 不使用本地缓存。需要使用缓存协商;先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载 |
no-store | 不使用任何缓存(包括强缓存和协商缓存),强制服务器返回资源 |
public | 可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器 |
private | 只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存 |
min-fresh | min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。 |
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。 |
协商缓存
协商缓存中header 的参数
前提 | Catch-Control | 缺点 |
---|---|---|
Last-Modify与 If-Modify-Since | 第一次服务端在返回header中标有Last-Modify;在第二次请求相同资源的时候,请求头会带有加一个字段If-Modify-Since;If-Modify-Since里面存的是上次Last-Modify 的内容;服务器收到If-Modify-Since,会判断,如果没有更改过,那么就返回304;如果改变了,那么客户端就会得到最新的资源 | 单位:秒;如果更改的间隔是毫秒,那么Last-Modify 是察觉不出来的。会有bug,会检测不出来 |
Etag/if-None-Match | Etag 是资源对应的hash值(比如Apache,默认是对文件的索引节“Inode”、大小“Size”、和最后的修改时间“MTime”进行hash),每个资源的hash值都不一样;第一次请求时,服务器返回头中,有Etag字段;再次请求相同的资源的时候;浏览器会在请求头中,加入If-None-Match:上一次的Etag; 服务器接收到请求后后,会和请求资源进行比对,然后返回200或者304 | 由服务器端生成,会加大服务器的开销 |
ETag和Last-Modified的作用和用法,他们的区别:
1.Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;
2.在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
3. 如果某些文件会被定期生成,如果内容没有变化,但是Last-Modified 改变了,那么就会导致文件服务使用缓存了。
4. 有可能存在服务器和代理服务器的时间不一致,导致文件获取不准确。
5. 在优先级上,服务器校验有限考虑Etag.
只有Etag 的hash是服务器做的,其他的都是浏览器自发行为。
Etag 举例:
Etag:W/“17603-kHySP8DmOeWEJJfBL4qq25Qi4SY”
服务器比对一致:那么就返回304;
用户行为与缓存
浏览器缓存过程
-
调用 Service Worker 的 fetch 事件响应
-
查看内存缓存( memory cache)
-
查看硬盘缓存( disk cache)。这里又细分:
– 如果有强制缓存且未失效,则使用强制缓存,不请求服务器。这时的状态码全部是 200
– 如果有强制缓存但已失效,使用对比缓存,比较后确定 304 还是 200 -
发送网络请求,等待网络响应
-
把响应内容存入 硬盘缓存(disk cache) (如果 HTTP 头信息配置可以存的话)
-
把响应内容 的引用 存入 内存缓存(memory cache) (无视 HTTP 头信息的配置)
-
把响应内容存入 Service Worker 的 Cache Storage (如果 Service Worker 的脚本调用了 cache.put())
浏览器对资源区别对待
- 对html 采用强缓存策略
- 对png 会使用协商缓存策略
浏览器缓存的优点有:
1.减少了冗余的数据传输,节省了网费
2.减少了服务器的负担,大大提升了网站的性能
3.加快了客户端加载网页的速度
服务器响应http 请求
负载均衡
nginx
浏览器解析html 代码,并请求html 代码中的资源
文档类型:html,xml
DTD:告诉浏览器我是什么文档类型,然后浏览器根据DTD 来决定使用什么样的协议来解析,和切换浏览器模式。
DOCTYPE:用来声明文档类型和DTD 规范的。
常见的文档类型
HTML 5
<!DOCTYPE html>
HTML 4 有两种模式:strict (严格模式) 和transitional (传统模式)
strict: 不包含弃用
transitional: 包含弃用
HTML4
HTML4.01 Strict 该 DTD 包含所有 HTML 元素和属性,但不包括展示性的和弃用的元素(比如 font)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
HTML 4.01 Transitional 该 DTD 包含所有 HTML 元素和属性,包括展示性的和弃用的元素(比如 font)
<!DOCTYPE HTML PUBLIC "-/3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
脚本
script 标签是组设文档的解析的。在执行的时候,如果遇到脚本,会停下来,等脚本运行完,才会继续向下解析。
名称 | 默认加载 | defer 加载 | async 加载 | 动态加载 |
---|---|---|---|---|
阻塞 | 会阻塞 | 不会阻塞 | 不会阻塞 | 不会阻塞 |
支持情况 | 所有浏览器都支持 | 仅仅IE 支持defer | IE 10+和其他现代浏览器支持 | 均支持 |
使用情况 | 遇到script ,就会解析script 脚本 | 下载照旧,但执行延后 | 下载完就立即执行,适合没有依赖的脚本 | 它无法做到比 HTML 中其他非动态加载的 script 脚本更早执行 |
使用建议 | 规范使用 | 如果脚本需要等待页面解析,且依赖于其它脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中 | 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 async | 推荐使用 |
动态加载
让预加载器知道这些动态文件的存在;
在文档头部显示的声明他们
<link rel="preload" href="demo01.js">
动态加载脚本1
let script = document.createElement('script');
script.src = 'demo01.js';
script.async = false;
document.head.appendChild(script);
动态加载脚本2
var xhr = new XMLHttpRequest();
xhr.open('GET', 'demo01.js', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var script = document.createElement('script');
script.text = xhr.responseText;
document.body.appendChild(script);
}
};
xhr.send();
动态加载脚本3:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'example.js', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
eval(xhr.responseText);
}
};
xhr.send();
一般使用async ,await 来实现
const assets = [
'https://demo1.js',
'https://demo2.js',
'https://demo3.js',
'https://demo4.js',
'https://demo5.js'
]
const loadJS = url => {
return new Promise(resolve => {
const recaptchaScript = document.createElement('script')
recaptchaScript.setAttribute('src', url)
recaptchaScript.defer = true
recaptchaScript.onload = () => {
resolve()
}
document.head.appendChild(recaptchaScript)
}).catch(console.error)
}
// 按次序加载 JS 文件
const loadAssets = async () => {
for (const url of assets) {
await loadJS(url, true)
}
}
优势:
-
加速页面加载速度:将JS代码单独放在一个文件中,可以避免HTML文件过大,从而提高页面加载速度。
-
提高用户体验:通过动态加载JS文件,可以使页面加载更快,从而提高用户体验。
-
实现更多的功能和特效:动态加载JS文件可以实现更多的功能和特效,例如异步加载、按需加载等。
浏览器对页面进行渲染
- 根据 HTML 解析出 DOM 树
- 根据 CSS 解析生成 CSS 规则树
- 结合 DOM 树和 CSS 规则树,生成渲染树
- 根据渲染树计算每一个节点的信息
- 根据计算好的信息绘制页面
在layout 的时候,页面其实是不知道元素的位置的。只是组件出一个Render tree.
回流(Reflow)大流
当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
会导致回流的操作:
- 页面首次渲染
- 浏览器窗口大小发生改变。元素尺寸或位置发生改变。元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的 DOM 元素
- 激活CSS伪类(例如::hover
- 修改网页的默认字体
- 移动DOM元素,比如动画
- 查询某些属性或调用某些方法
一些常用且会导致回流的属性和方法:
eclientwidth、clientHeight、clientTop、clientLefteoffsetWidth、offsetHeight、offsetTop 、offsetLeft。scrollwidth、scrollHeight、scrollTop、scrollLeftscrollIntoView()、scrollIntoViewIfNeeded()get***putedstyle()
getBoundingclientRect()
scrollTo()
重绘 绘色
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
- DOM 改动
- css 改动
减少回流和重绘
- 尽量使用css属性简写:如:用boder代替boder-width,boder-style,boder-color
- 批量修改元素样式 elem.className
- 尽量避免用table布局(table元素一旦触发回流就会导致table里所有的其它元素回流)
- 需要创建多个DOM节点时,使用DocumentFragment创建。因为:每次创建一个页面就会发生回流,所以采用DocumentFragment批量创建
- 尽量去写css表达式。因为每次调用都会重新计算值(包括加载页面)
回流和重绘 对比
回流必定会引起重绘,但是重绘一定不会引起回流;
回流会导致页面重排;
回流的性能消耗,比重绘大;
举例:
display:none | visibility:hidden | |
---|---|---|
相同点 | 都可以隐藏dom 元素 | |
区别 | 会引起页面的回流和重绘 | 只会引起重绘 |
性能 | 稍差 | 比display:none 好一些 |
子元素 | 子元素不会进行显示 | 子元素可以进行显示 |
display | visibility | opacity | width |
---|---|---|---|
元素消失,不占位 | 元素消失,占位置 | 透明度设为0,元素看不见,占位置 | 宽度设为0,元素看不见,不占位置 |
断开tcp 连接
断开链接tcp四次挥手
seq: 随机生成的序列号
ack:ack = seq+1; 是确认号
ACK:确认序列号有效
SYN:发起新链接
FIN:完成
客户端和服务端都可以发起。以客户端发起为例
FIN:FIN=1;断开链接;并且客户端会停止向服务端发数据
流程:
- 客户端主动发起一个关闭请求;携带信息:
FIN=1;
seq =u; - 服务器给客户端发送一个响应,表示自己收到了;携带信息:
ACK=1;
ack=u+1;
seq = v;(服务器生成)
此时称为半关闭状态;此时服务器还是会向客户端发送数据 - 服务器向客户端发送一个关闭请求;携带信息:
FIN=1;
ACK=1;
seq=w;(因为,此时还是半关闭状态,服务器生成的序列号并不能确定,不一定是v 了,所以用w 来表示)
ack=u+1;(客户端没有向服务器端再次发送序列号,所以,此时的确认号,仍然是上次浏览器发过来的序列号+1;即:u+1) - 客户端给服务端响应,表示自己收到了;携带信息:
ACK=1;
ack=w+1;
seq = u+1;
注意:
- 在fin_wait_2:会等待未完成的任务完成
- 1-4min 超时等待状态;
参考文档:
https://www.zhihu.***/question/23042131
https://blog.csdn.***/zzg19950824/article/details/79518678
https://cloud.tencent.***/developer/article/2364755?areaId=106001
https://cloud.tencent.***/developer/article/1985866?areaId=106001
https://zhuanlan.zhihu.***/p/161560683
明天不气