一次完整的http服务过程
在浏览器的地址栏中输入www.baidu.com具体发生了什么
-
对www.baidu.com网址进行DNS域名解析,得到对应的ip地址
-
根据ip找到对应的服务器,发起TCP三次握手
-
建立TCP连接后发起HTTP请求
-
服务器响应HTTP请求,浏览器得到html代码
-
浏览器解析html代码,请求html代码中的资源
-
浏览器对页面进行渲染呈现给用户
-
服务器关闭TCP连接,四次挥手
为什么要建立tcp连接后发起http请求?
tcp是比http更底层的一个连接协议;ip是tcp下面一层
DNS怎么找到域名的?
-
DNS域名解析采用递归查询的方式,先去找DNS缓存,缓存找不到就去根域名服务器,根域名又去找下一级,从ip地址的后面往前逐一解析,
-
如果递归查找之后找到了传输给浏览器
-
如果没找到就会看不到网页
-
-
浏览器自身域名缓存区查找
-
操作系统的域名缓存查找
-
hosts文件查找
-
域名服务器查找
为什么HTTP要基于TCP来实现
TCP是端到端的可靠的面向连接的协议,HTTP基于传输层协议不用担心数据传输的各种问题,当发生错误的时候会重传
三次握手和四次握手的机制:
tcp/ip协议是传输层的面向连接的安全可靠的一个传输协议,三次握手的机制是为了保证能建立一个安全可靠的连接,第一次握手
三次握手
-
客户端给服务端要发送请求报文
发送位码SYN=1的tcp包给服务端,随机产生一个seq(主)作为确认号
-
服务端收到,然后给客户端发送确认信息报文
服务端发送SYN=1,随机产生的seq(服),ACK=1,ack=seq(主)+1给主机,对客户端而言,知道自己可以发送接收消息,但服务端不知道客户端接收到没,所以说要第三次握手
-
客户端给服务端发送确认信息报文
ACK=1,ack=seq(服)+1
双方都能知道双方都能接收发送信息, 链接安全建立
最后异步浏览器是如何进行渲染的
遇见HTML解析器,浏览器用HTML解析器解析Token和html文件构成DOM树
遇见style标记,用css解析器构建cssom树
遇见script标记,用JavaScript解析器处理js代码
将cssom树和dom树合并构成渲染树
边解析边渲染
js单线程运行,有可能修改DOM结构,js执行完成之前,后续所有资源的下载是没有必要的,所以js是单线程,会阻止后续资源的下载
然后提问重排重绘三次握手和四次握手
重排,即回流,当DOM的变化影响了元素的位置尺寸大小,浏览器重新计算元素的几何属性,将其安放在界面的正确位置,
触发:添加删除可见的DOM元素,元素尺寸改变——边距填充边框宽度和高度
重绘:元素的外观发生改变但没有改变布局重新把元素外观绘制出的过程叫做重绘,
触发:改变元素的color,background和box-shadow等属性
四次挥手
-
客户端发起,发送请求报文给服务端,
FIN=1,seq(主(根据报文慢慢增长上来的,不是随机的))
-
服务端收到请求报文后,服务端知道了客户端要断开连接,此时服务端不一定能做好准备,此时还有可能有未发送完的消息,此时只能做一个消息确认
ACK=1,ack=seq(主+1)
-
服务端发送给客户端一个断开连接的报文
FIN=1,seq(服),表示服务端做好了和客户端断开的准备
-
客户端要给服务端发送一个确认的报文,然后连接就可以断开
ACK=1,ack=seq(服+1)
Web缓存:数据库缓存,服务器端缓存,代理服务器缓存,CDN缓存,浏览器缓存
浏览器缓存:HTTP缓存,indexDB,cookie,localStorage
缓存命中率:从缓存中得到的数据的请求和所有请求数的比率
过期内容:超过设置的有效时间,被标记为陈旧的内容,过期内容不能用于恢复客户端的请求,必须重新向源服务器请求信的内容或验证缓存的内容是否仍然准备
验证:验证缓存中的过期内容是否仍然有效,验证通过的话刷新过期时间
失效:把内容从缓存中移除,内容发生改变必须移除失效的内容
浏览器缓存主要是HTTP协议定义的缓存机制,HTML meta标签,
无缓存,向服务端发送请求,请求响应,缓存协商(在第二次请求使用, 是否缓存,缓存时间,Etag,Last-Modified等等)
第二次请求。。。
http缓存作用范围,缓存分类,缓存实现技术
http缓存分类:强缓存和协商缓存
强缓存:不会发请求到服务器,从本地拿到缓存并返回200
http返回码200,size显示为from cache,强缓存是利用返回头中的Expires或cache-control两个字段来控制的,来表示资源的缓存时间,返回一个时间。
Expires:返回一个绝对时间,代表在xxxxxx之前都是有效的;
cache-control是相对时间,代表资源有效期是xxx秒,cache-control优先级高,两个可同时使用
200 form memory cache :直接从内存中读取缓存。浏览器关闭后,数据将不存在
200 from disk cache:直接从硬盘中读取缓存,关闭浏览器后,数据依然存在
协商缓存:未命中强缓存,浏览器将资源加载请求发送到服务器,服务器来判断浏览器本地缓存是否失效,若可以使用,服务器不会返回资源信息,浏览器继续从缓存加载资源
last-modified和if-modified-since
浏览器第一次请求一个资源的时候,服务器返回的header会加上last-modify(该资源的最后的修改时间 )
当浏览器再次请求该资源,发送请求头中包含if-modify-since:
如果和服务器中的最后修改时间一样,返回304和空的响应体,直接从缓存中读取,协商缓存生效;
如果小于服务器中资源的最后修改时间,说明文件有更新,返回新的资源和200,协商缓存失效;
弊端:本地打开缓存文件服务器无法命中缓存导致发送相同的资源
Etag和if-none-match
Etag返回一个校验码,可以保证每一个资源是唯一的,资源变化会导致Etag变化,Etag值的变更说明资源状态已被修改,服务器根据浏览器上发送的if-none-match值来判断是否命中缓存,
如果相等,返回304直接使用本地缓存;
如果不相等,以常规GET 200回包形式将新的资源发给客户端
有了last-modified为什么又要有etag
last-modified标注的最后修改只能精确到秒级,一秒内多次被修改,不能准确的标注文件修改的时间,
如果文件被定期生成,内容没有发生任何变化,last-modified却改变导致文件无法使用缓存,
服务器没有准确获取文件修改时间,或代理服务器时间不一致
Etag和last-modified可以一起使用,优先验证Etag,但Etag性能不如last-modified
新的请求:如果没有命中协商缓存,服务器将完整的资源返回给浏览器,浏览器加载新资源并更新缓存
频繁变动的资源:
Cache-Control: no-cache
使浏览器每次请求服务器,配合协商缓存验证资源是否有效,虽然不能节省请求数量,但是能显著减少响应数据大小
不常变变化的资源:
Cache-Control: max-age=3153600
配置一年,这样浏览器之后请求相同的URL会命中强制缓存,为了解决更新问题,需要在文件名中添加hash版本号等动态字符,之后更改动态字符,达到更改引用URL的目的
http缓存控制/一台服务器如何提高并发效率——回答思路:
http缓存作用范围,(有些资源是可以直接拿浏览器缓存,不需要服务器重新请求,通过强缓存和协商缓存,可以提高并发效率
缓存分类,(强缓存通过expires和cache-control来实现;协商缓存通过last-modified和Etag
为什么有expires又需要cache-control?
因为expires有服务器和浏览器时间不同步的问题,expires是绝对时间,cache-control是相对时间;last-modify和Etag
,last-modified精确到秒,etag没时间精确问题,只要文件改变,etag值就变
js获取cookie设置cookie
// 创建cookie
function setCookie(name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value);
if (expires instanceof Date) {
cookieText += '; expires=' + expires;
}
if (path) {
cookieText += "; path=" + path }
if (domain) {
cookieText += '; domain=' + domain;
}
if (secure) {
cookieText += '; secure';
}
document.cookie = cookieText;
}
// 获取cookie
function getCookie(name) {
var cookieName = encodeURIComponent(name) + '=';
var cookieStart = document.cookie.indexOf(cookieName);
var cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(';', cookieStart);
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
}
// 删除cookie
function unsetCookie(name) {
document.cookie = name + "= ; expires=" + new Date(0);
}
codeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
}
// 删除cookie
function unsetCookie(name) {
document.cookie = name + “= ; expires=” + new Date(0);
}