有以下几个场景说明浏览器与客户端通信过程
1.浏览器上输入url之后发生了什么?
①url解析
②获取ip地址
③建立tcp连接
④发送http请求
⑤返回http响应
⑥建立dom树和cssdom树,进行页面渲染
⑦断开或者保持连接
这六个点都是一个知识点呀
url解析
判断是输入了待搜索的关键字还是url。根据输入的内容进行自动编码,补全等工作。还有一些安全性检查
重大问题!判断缓存是在哪一步的呢?
对于比较强缓存来说,他是在dns查询之前,但是协商缓存就在dns解析之后了
①向服务器请求之前先查看本地是否有缓存,没有就直接请求客户端资源
②有缓存,比较是否命中强缓存
通过比较cache-control:max-age
(这个时间是客户端的相对时间)
或者expires+last-modified
(这个时间是服务端资源失效的绝对时间,所以需要和last-modified比较)
优先级cache-control
比expires-modified
要高
有强缓存则不会发送http请求了
③没有命中强缓存但是有协商缓存,就会发送get请求带上一些cookies信息(
if-modified-since
和if-None-Match
)然后服务端进行通过比较Etag
和if-None-Match
,last-modified
和if-modified-since
进行决策,并返回last-modified
和Etag
这两个字段,和状态码。如果Etag=if-None-Match
并且if-modified-since>=last-modified
那么会返回304,否则返回200
返回304就意味着可以直接使用本地缓存,服务器不会继续发送这个资源
返回200意味缓存资源已经被修改,需要重新向服务器请求该资源
服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
使用last-modified
和Etag
组合判断资源是否被修改的意义?
①如果是在一秒内多次修改资源,last-modified和last-modified-since不能准确标注资源修改时间,所有要有
etag
和if-none-match
②一些动态内容的生成,实际上资源没变但是修改时间会发生变化,导致不能使用缓存
③一些图片等静态文件的修改,如果每次扫描内容生成 ETag 来比较,显然要比直接比较last-modified和last-modified-since慢很多
域名解析详细:
①先看本地客户端是否有这个域名缓存,未找到
②操作系统DNS缓存
③查询本地域名服务器(一般成功率在80%)
④第③步查找失败就发起一个迭代的dns请求
迭代的dns请求??
本地域名服务器向根域名服务器(com,org,net等)发起请求,返回com域名服务器地址。
本地域名服务器向com域的顶级服务器发起请求,返回baidu.com域名服务器地址
本地域名服务器向baidu.com域名服务器,返回www.baidu.com的ip地址,返回给操作系统,同时缓存起来。
操作系统返回ip给浏览器,同时自身缓存起来
从客户端到本地DNS服务器是属于递归查询,而DNS服务器之间就是的交互查询就是迭代查询。
渲染页面过程
①解析html文档,生成dom树(不可见元素,注释,script标签内容都会在dom树中)
②解析css文件,生成css dom树。CSS解析可以与DOM解析同进行。
③生成Render Tree。display:none
元素不在Render Tree,visbility:hidden
元素还在Render Tree里
④Render Tree布局。进行元素在屏幕的大小,位置的确定
float元素,absoulte元素,fixed元素会发生位置偏移
我们常说的脱离文档流,其实就是脱离Render Tree
⑤Render Tree绘制
在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容
几个注意点:
- 当我们浏览器获得HTML文件后,会自上而下的加载,并在加载过程中进行解析和渲染。
- 加载说的就是获取资源文件的过程,如果在加载过程中遇到外部CSS文件和图片,浏览器会另外发送一个请求,去获取CSS文件和相应的图片,这个请求是异步的,并不会影响HTML文件的加载。
- css解析不会阻碍dom解析,但是会阻碍浏览器渲染。这是为了性能和用户体验,要尽量减少渲染的次数,防止渲染之后又重新渲染更新
为什么js文件不能放在css文件之前进行解析?
但是如果遇到Javascript文件,HTML文件会挂起渲染的进程,等待JavaScript文件加载完毕后,再继续进行渲染。
为什么HTML需要等待JavaScript呢?
因为JavaScript可能会修改DOM,导致后续HTML资源白白加载,所以HTML必须等待JavaScript文件加载完毕后,再继续渲染,这也就是为什么JavaScript文件在写在底部body标签前的原因。
为什么要先解析css文件?
放在头部,浏览器进行一部分渲染,减少白屏时间
如果放在底部的话,引发了回流,会有闪屏这种不好的体验
2.用户登录过程
① 用户输入账号密码之后。登陆成功则服务器会返回setCookies字段,要求客户端保存cookies信息。setCookies字段包括了登录账号密码信息,domain,expires等信息。
②下一次登录,浏览器就会自动带上cookies信息
但是出于安全性的考虑,我们不会真的把账户密码信息放在cookie,因为这样每次登陆都要把账号密码信息传送一次,这是十分不安全的。
所以现在一般返回senssionId代替登录账号密码信息,第一次登陆成功,服务器会生成一个session,然后经过加密生成了sessionId字段,通过cookie发回给客户端,下次访问的时候,带上这个sessionId,服务器收到以后们就会解密,并且和session相比较。
如果浏览器禁用了cookie/不支持cookie,可以通过URL重写的方式发送到服务。
这个时候,通过sessionId通信的弊端也产生了。这需要在服务端产生并保存每一个人的session,耗费了服务器的空间。同时当服务器集群的时候,也很不好搞。于是新技术JSON Web Token(简称:JWT)(下文使用token代替)就产生了,他相当于一个令牌,持有这个令牌就给予通过。这样避免了频繁去查询账号密码表。
token的结构包括了下面三部分,他们使用.
隔开
Header(头部)
Payload(负载)
Signature(签名)
header:是这样一个json对象,alg代表加密的算法,生成这个对象之后,使用base64Url转化为字符串,typ属性表示这个令牌(token)的类型(type)
{
"alg": "HS256",
"typ": "JWT"
}
Payload:也是一个json对象,用来存放实际的数据。比如:
过期时间等等信息
同样使用使用base64Url
进行加密
Signature通过一个密钥(只有服务器知道)和header指定的签名算法生成一个签名(生成内容也和Header、Payload内容有关)
拼接好Header、Payload、Signature形成token然后发回给用户
这个token 服务器不保存, 当用户把这个token 给服务器发过来的时候,服务器再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证。
过程:
服务端只是生成token,验证token,不会存储token。使用签名认证避免了别人恶意拼接获取token,这样就会安全许多
token最好放在请求头的Authorization字段里面,因为放在cookies里面不能跨域
说到这里,不免要提一下refer。refer字段保存请求源的url,其实现在已经有手段可以改变refer了,所以也不够安全
https://segmentfault.com/a/1190000014527692?utm_source=tag-newest