从输入一个url到页面渲染的过程
输入->检查缓存->URL解析->DNS解析->建立TCP连接->发送HTTP请求->服务器处理请求并返回HTTP报文->解析渲染页面->连接结束
- 首先在地址栏输入url进行搜索,浏览器会判断输入的是一个合法的url还是待搜索的关键字,然后根据输入的内容自动完成字符编码等操作。
- 接下来浏览器会检查当前url所需资源是否有缓存,如果本地缓存了所需的资源并且没有过期,则直接使用浏览器缓存的数据,不需要向服务端发送请求。如果没有缓存或者已过期,再开始解析url。
- 把我们请求需要的协议、域名、端口、路径这些信息解析提取出来,然后进行DNS域名解析。
- DNS解析过程:先进行递归查询,浏览器缓存->本机系统->本地域名服务器递归查询自己的 DNS 缓存->如果都没有,则向上级域名服务器进行迭代查询,直到返回结果。
- 浏览器在拿到Ip后,在向服务器发起http请求之前,会先和服务器建立TCP连接(三次握手)。
- 连接建立成功后,浏览器就可以发送http请求到服务器请求数据,每个http请求包含三个部分:请求行(请求方法、请求地址、http协议版本)、请求头、请求正文。
- 服务器处理相关的请求,返回处理后的结果
- 浏览器接受完服务器返回的资源后,需要断开TCP连接。断开TCP连接需要经历四次挥手。
- 浏览器在接收到服务器的资源之后,对响应资源进行解压缓存,然后解析。
- html通过html解析器输出dom树;css通过css解析器输出css规则;结合dom树和css规则,计算出dom树中每个节点的具体样式,生成渲染树;浏览器根据渲染树开始布局和绘制,会触发回流和重绘,最后构建图层树,显示页面。
DNS(域名系统)
1. 定义:是互联网的一项服务,是域名和相对应的 IP 地址进行转换的服务器。
2. 查询过程
递归查询:向本地域名服务器发送请求;迭代查询:本地域名服务器向其他域名服务器发送请求;- 首先检查浏览器缓存中是否缓存过该域名对应的IP地址;
- 如果在浏览器缓存中没有找到,那么将继续查找本机系统是否缓存过,这两步都是在本机系统上进行;
- 如果在本机上无法完成域名的解析,操作系统只能向本地域名解析服务系统发起域名解析的请求,本地域名服务器采用递归查询自己的 DNS 缓存;
- 如果本地域名服务器还没有DNS缓存的话,则本地域名服务器向上级域名服务器进行迭代查询。
- 首先本地域名服务器向根域名服务器发起请求,根域名服务器返回顶级域名服务器的地址给本地服务器
- 本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
- 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
- 本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来
- 操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起
- 至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起
tcp三次握手和四次挥手的步骤
1. 几个重要字段
1.seq: (sequence number) 序号
2.ack: (acknowledgement number) 确认号
3.标志位:
SYN: (SYNchronizatio) 同步
ACK: (ACKnowlegmen) 确认
FIN: (FINish) 终止
2. 三次握手
第一次握手:客户端将同步标志位 SYN 设置为1,表示 SYN 报⽂(SYN=1表示要建立连接,连接成功后该位置会再次被置为0),请求序号 seq 设置为x(在所有的字节排列中,申请从哪一个字节开始发送,这个序号就一般表示当前已经发送到哪个序号,服务器同意后将会从下一个序号开始发送,第一次握手只有请求序号没有确认号),然后把第⼀个 SYN 报⽂发送给服务端,表示向服务端发起连接,然后客户端处于同步已发送状态,等待服务端确认。第二次握手:服务端收到数据包后,由同步标志位SYN=1知道服务端请求建立连接,所以将确认标志位ACK设置为1(这会才有确认标志位,第一次握手并没有确认标志位。当确认标志位为0时,确认号不起作用),确认号ack设置为x+1(确认序号等于请求序号+1,表示x+1之前的服务端都收到了,从服务端发送的请求已经收到)。TCP是全双工协议,服务端也有可能向客户端发送数据,因此服务端也会向客户端发送请求,所以将同步标志位SYN设置为1,还要将seq设置为y,表示服务端给客户端发送的初始化随机序列号。然后将该数据包发送给客户端用来确认连接请求,客户端进入同步收到状态。第三次握手:因为连接是双向的,在服务端确认后,只是客户端知道跟服务端连通了,因此客户端也要确认一下,才能让服务端也知道跟客户端连通了,所以将ACK设置为1,seq设置为x+1,ack设置为y+1。客户端和服务端进入已连接状态,完成三次握手,随后客户端与服务端之间就可以开始传输数据了.只有第三次握手才可以携带数据
3. 四次挥手
第一次挥手:客户端发送一个FIN=1,以及选择号seq=u(表示:u之前的数据已经全部发送,并且数据发到u就可以截止了,就不再有数据了),用来关闭客户端到服务端的数据传送,然后客户端进入FIN-WAIT-1(终止等待1)状态。第二次挥手:服务端收到终止标志位后,发送一个请求号seq=v和确认号ack=u+1给客户端,服务端进入CLOSE-WAIT(关闭等待)状态。 服务端继续给客户端发送数据,将剩下的数据发完。此时客户端进入FIN-WAIT-2(终止等待 2)状态第三次挥手:服务端发送一个FIN,请求号为最新的seq=w和确认序号ack=u+1,用来关闭服务端到客户端的数据传送,服务端进入LAST-ACK (最后确认)状态。第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务端,确认号为ack=w+1。服务端进入TIME-WAIT(时间等待)状态,这时,TCP连接还没有释放掉,等待时间计数器设置的时间 2MSL后,客户端才进入到CLOSED状态,中断连接,完成四次挥手。
4. 为什么要三次握手?为什么是三次?
- 为了确认双方的接收和发送能力是否正常,指定自己的初始化序列号为后面的可靠性传送做准备,其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
- 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误;为了解决网络中存在延迟的重复分组;总之为了避免资源浪费。
5. 为什么要四次挥手
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭。即当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接。收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了。但是在这个TCP连接上仍然能够发送数据,直到另一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,所以总共需要四次来完成双方都关闭。
6. 为什么要经过2MSL时间后,客户端才关闭连接?
MSL是报文最大生存时间,超过这个时间的报文就会被丢弃。保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
TCP和UDP
1. TCP、UDP的概念以及特点
- TCP 和 UDP都是传输层协议,他们都属于TCP/IP协议族;
- UDP也叫作 用户数据报协议 ,在网络中主要用来处理数据包,是一种无连接协议,在OSI模型中,它在传输层。
- UDP是面向无连接的,也就是在发送数据前不需要进行三次握手建立连接,也不会对数据报文进行任何拆分和拼接操作,所以在报文发送后,它不知道报文有没有安全、完整的到达。
- UDP有单播,多播,广播的功能,它的连接个数支持一对一,一对多,多对一和多对多交互通信。
- 它的传输方式是面向报文,UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界,在添加首部后就向下交付IP层,因此,应用程序必须选择合适大小的报文。
- 不可靠性: 一方面体现在无连接上,另一方面它没有拥塞控制和流量控制,一直会以恒定的速度发送数据,跟网络环境没有关系。
- 头部开销小,只有8字节,相比 TCP 的少20多个字节,在传输数据报文时是很高效的。
- 一般适用于实时应用,像视频会议、直播这些时实通讯,速度要求高的。
- TCP 全称是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- TCP的面向连接体现在,发送数据之前必须在两端建立连接,也就是三次握手,为数据的可靠传输打下了基础。
- 仅支持单播传输 每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
- 面向字节流 它UDP一样那样,一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。
- 可靠传输 会通过用TCP的段编号和确认号来判断有没有出现丢包、误码这种情况, 能保证数据的顺序和正确性。具体的话,会给每个包一个序号,保证了接收端按序接收包;同时接收端实体会对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
- 使用流量控制 和 拥塞控制,当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
- 提供全双工通信 允许通信双方的应用程序在任何时候都能发送数据。
- 一般适用于要求可靠传输的应用,像文件传输这种对准确性要求较高,效率要求相对低的。
2. 两者的区别
3. UDP为什么不可靠?
- 在传输数据之前不需要先建立连接,在接收到UDP报文后,不需要确认,提供不可靠交付,也不重传。
- 不保证交付的顺序,不设置包序号,不重排。
- 不进行拥塞控制和流量控制,发送数据跟网络环境没有关系。
- (UDP只有一个socket接受缓冲区,没有socket发送缓冲区,即只要有数据就发,不管对方是否可以正确接受。 而在对方的socket接受缓冲区满了之后,新来的数据报无法进入到socket接受缓冲区,此数据报就会被丢弃,UDP是没有流量控制的,所以UDP的数据传输是不可靠的)
4. TCP为什么可靠?它的重传机制是什么?
- 使用序列号和确认应答:接收方在接收到消息后会返回给发送方一个应答确认信号,也就是ACK。
- 重发超时:使用了ACK使发送方知道数据有没有送达,如果消息发送失败了,TCP会根据往返时间与偏差计算重发超时时间,考虑偏差主要是网络环境存在波动,数据重发之后如果仍无法收到应答,则再次发送,此时,等待确认应答的时间将会以2、4、8倍的指数延长,数据也不会无限重发,当达到一定次数后,则自动判断对方异常,强制关闭连接。
- 三次握手、四次挥手: 在正式通信之前会和服务器请求建立连接,结束时也会请求断开连接。
- 拥塞控制和流量控制(流量控制:TCP实现了发送方可以根据接收方接收能力实现动态控制发送数据量的机制,这里控制的数据量实际也是窗口大小)
- 重传机制: 由于TCP的下层网络(网络层)可能出现丢失、重复或失序的情况,TCP协议提供可靠数据传输服务。为保证数据传输的正确性,TCP会重传那些它认为已经丢失(包括报文中的比特错误)的包。TCP使用两套独立的机制来完成重传,一是基于时间,二是基于确认信息。 TCP在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。
渲染相关(SSR)
1.服务端渲染是什么?如何实现?
- 渲染就是将数据和模板组装成html,当客户端发起一个请求,服务端收到请求后,获取对应的数据,然后把数据结合页面模板渲染为完整的 HTML,接着把渲染完毕的 HTML 发送给客户端,客户端接收到内容将其直接展示到浏览器当中。
2. 浏览器渲染过程?如何优化?
-
- 渲染引擎首先解析HTML文档,生成DOM树。
- 然后将引入的CSS样式解析生成CSS规则树(CSSOM--CSS对象模型),给各个元素添加对应样式信息,再将DOM树与CSSOM合并构建成另外一棵用于渲染的Render树。(生成一颗渲染树的过程称为Attachment,是页面可视化元素按照其显示顺序组成的树,可以让浏览器按照正确的顺序绘制内容。)
- 再对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置。 (浏览器渲染页面默认采用流式布局,从根(对应于HTML文档的元素)开始,然后递归遍历部分或所有的框架层次结构,为呈现器计算几何信息。)
- 最后遍历渲染树并调用渲染对象的 paint 方法将它们的内容显示在屏幕上。(绘制使用 UI 基础组件)。
- 为了更好的用户体验,它是解析完一部分内容就显示一部分内容,同时,可能还通过网络下载其余内容。
- 优化:
- js方面: 因为js既会阻塞html的解析,也会阻塞CSS的解析,因此可以对js的加载方式进行改变,尽量将js文件放在body的最后。
- css方面: 如果导入外部样式加载时间比较长,会降低用户体验,所以CSS一般写在header中,让浏览器尽快发送请求去获取css样式。(使用CSS有三种方式:link、@import、内联样式,其中link和@import都是导入外部样式)
- DOM树、CSSOM树方面: HTML文件的代码层级尽量不要太深、尽量使用语义化的标签,避免不标准语义化的特殊处理、减少CSS代码的层级,因为选择器是从左向右进行解析的。
- 减少回流与重绘:
- 操作DOM时,尽量在低层级的DOM节点进行操作、不要使用
table布局, 一个小的改动可能会使整个table进行重新布局、不要频繁操作元素的样式。 - 浏览器针对页面的回流与重绘,进行了自身的优化——渲染队列。浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。**
- 操作DOM时,尽量在低层级的DOM节点进行操作、不要使用
3. 重绘、回流?重排?
- 重绘 的定义:在一个元素的外观被改变时,所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。比如改变某个元素的文字颜色、背景色等。
- 回流 的定义 :当Rendering Tree 中部分元素的尺寸大小、布局、隐藏等属性改变时,浏览器的布局需要调整,则需要重新渲染DOM。这个过程就叫回流。回流也叫重排(对整个页面进行重新排版)。
- 二者的 联系:
- 回流一定会引起重绘,重绘不一定引起回流。
- 回流需要重新渲染DOM,也要重新处理Rendering Tree。即回流的开销比重绘要大。
4. 渲染过程中遇到js文件如何处理
JavaScript 的加载、解析与执行会阻塞文档的解析,也就是说,在构建 DOM 时,HTML 解析器若遇到了 JavaScript,那么它会暂停文档的解析,将控制权移交给 JavaScript 引擎,等 JavaScript 引擎运行完毕,浏览器再从中断的地方恢复继续解析文档。那么,如果想要首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。(但并不是说 script 标签必须放在底部,因为可以给 script 标签添加 defer 或者 async 属性)。
浏览器本地存储
1. 前端浏览器存储的方式有哪些?什么场景下使用?
- 概念:
cookie:是最早被提出来的本地存储方式,主要在HTML5标准前使用,在此之前,服务端是无法判断网络中的两个请求是否是同一用户发起的,为解决这个问题,Cookie就出现了。cookie存放数据大小一般为4K左右,它的特点是兼容性比较好。每次请求都会向客户端发送,关闭页面不会消失 有可能被坏人复制窃取cookie去登录(xss注入攻击来攻击cookie)(cookie是一种纯文本文件,每次发起HTTP请求都会携带Cookie,cookie字段一般有Domain(域)、Path(路径)、Secure(安全)(是否只有在HTTP使用SSL连接时才发送这个Cookie)、expires(过期)、name(名字)、value(值)这些配置选项。cookie一旦创建成功,名称就无法修改,也无法跨域名,如果需要域名之间跨域共享Cookie,有两种方法:使用Nginx反向代理;在一个站点登陆之后,往其他网站写Cookie,服务端的Session存储到一个节点,Cookie存储sessionId) 使用场景: 最常见的使用场景就是cookie和session结合使用,将sessionId存储到cookie中,每次发请求都会携带这个sessionId,这样服务端就知道是谁发起的请求,从而响应相应的信息;可以用来统计页面的点击次数。localStorage: 是HTML5新引入的特性,localStorage的大小一般为5MB,可以储存更多的信息,localStorage是持久储存,并不会随着页面的关闭而消失,除非主动清理,不然会永久储存在本地,它不像Cookie那样每次HTTP请求都会被携带。但也存在浏览器兼容问题,IE8以下版本的浏览器不支持,如果浏览器设置为隐私模式,那我们将无法读取到LocalStorage,同时,它也受到同源策略的限制。(常用的API: 1. 保存数据到localStorage(localStorage.setItem('key', 'value')); 2. 从localStorage获取数据(let data = localStorage.getItem('key'));3. 从 localStorage 删除保存的数据(localStorage.removeItem('key'));4. 从localStorage删除所有保存的数据(localStorage.clear());5. 获取某个索引的Key(localStorage.key(index));) 使用场景:有些网站有换肤的功能,这时候就可以将换肤的信息存储在本地的LocalStorage中,当需要换肤的时候,直接操作LocalStorage即可; 在网站中的用户浏览信息也会存储在LocalStorage中,还有网站的一些不常变动的个人信息等也可以存储在本地的LocalStorage中。sessionStorage:SessionStorage和LocalStorage都是在HTML5才提出来的存储方案,是会话级别的储存⽅式,SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据。存放数据大小一般为5MB,存储在服务器端,也有同源策略的限制,只有在同一浏览器的同一窗口下才能够共享。(常用的API: 与localStorage类似,改下名字就行) 使用场景:由于SessionStorage具有时效性,所以可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。IndexedDB: indexedDB 是一个基于js的面向对象的数据库,⽤键值对进⾏储存,可以进⾏快速读取操作,适合web场景,同时,它也受到同源限制,网页只能访问自身域名下的数据库,而不能访问跨域的数据库,它的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。Web SQL: 2010年被W3C废弃的本地数据库数据存储⽅案,但是主流浏览器(⽕狐除外)都已经有了相关的实现,web sql类似于SQLite,是真正意义上的关系型数据库,⽤sql进⾏操作,当我们⽤JavaScript时要进⾏转换,较为繁琐,因为 Web SQL database 本质上是一个关系型数据库,后端可能熟悉,但是前端就有很多不熟悉了,虽然SQL的简单操作不难,但是也得需要学习。SQL熟悉后,真实操作中还得把你要存储的东西,比如对象,转成SQL语句,也挺麻烦的。
- 区别比较
- 相同:在本地(浏览器端)存储数据,
cookie已经不建议用于存储,如果没有大量数据存储需求的话,可以使用localStorage和sessionStorage。对于不怎么改变的数据尽量使用localStorage存储,否则可以用sessionStorage存储,sessionStorage和localStorage都是html5后才出现的,所以用法以及场景都差不多。 - 不同: localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。 sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。 localStorage是永久存储,除非手动删除。 sessionStorage当会话结束(当前页面关闭的时候,自动销毁) cookie的数据会在每一次发送http请求的时候,同时发送给服务器而localStorage、sessionStorage不会。
- 相同:在本地(浏览器端)存储数据,
2. token存在哪?
Token定义: 是访问资源对凭证,一般是用户通过用户名和密码登录成功之后,服务器将登录凭证做数字签名,加密之后得到的字符串作为token,它在用户登录成功之后会返回给客户端。token: 的基本使用 && 身份验证流程: 使用基于token的身份验证方法,在服务端不需要存储用户的登录记录,客户端使用用户名跟密码请求登录,服务端收到请求,验证用户名与密码,验证成功后,服务端会签发一个token,再把这个token发送给客户端,客户端收到token以后可以把它存储起来,比如放在Cookie里或者Local Storage里,客户端每次向服务端请求资源的时候需要带着服务端签发的Token,服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据。- Token存储位置
- 存储在localStorage中,每次调用接口的时候都把它当成一个字段传给后台。
- 存储在cookie中,让它自动发送,不过缺点就是不能跨域。
- 存储在localStorage中,每次调用接口的时候放在HTTP请求头的Authorization字段里面。
- 为什么要使用token:
- token完全有应用管理,它可以避开同源策略。
- token可以避免CSRF攻击。
- token可以是无状态的,可以在多个服务间共享。
- token的作用:
- 防止表单重复提交。
- 身份验证,识别用户权限等。
3. 同一个系统开两个网页,两个网页的sessionStorage共享吗?
- 第一种情况: 浏览器中打开A页面,再通过A页面打开新的标签页B页面,此时A、B两个页面的sessionStorage是“共享”的。这里的共享指的是B页面会把A页面的的 sessionStorage 拷贝一份,作为B页面 的初始缓存值,此时改变B页面的session,A页面并不受影响。即不同 Tab 之间,session读写操作独立,互不影响。
- 第二种情况: 浏览器中打开A页面,然后手动新开一个标签页,在新的标签页中打开B页面,此时A、B两个页面的sessionStorage是不“共享”,即B页面不会继承A页面session作为初始值,新开一个标签页总是会初始化一个session,即使是同一个网站。
- localStorage同源状态下,不同标签页之间均可读写,相互影响。
浏览器缓存(HTTP缓存)
1.什么是浏览器缓存?为什么需要浏览器缓存?对浏览器的缓存机制的理解?
- 当浏览器根据url访问过一次网站之后,会将该网站的文件复制一份保存在浏览器中,当第二次访问时,如果网站没有明确表示有更新时,就可以在浏览器缓存中查找内容,不用再发起请求。
- 客户端和浏览器建立连接时需要消耗时间,而大的响应在它们之间需要多次往返通信,这样就增加了服务器压力,利用浏览器的缓存机制,可以让服务器提高效率,避免浏览器在服务器获取很多重复的资源,也提高了网页加载速度。
- 浏览器的缓存机制也就是HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的。
2.浏览器资源缓存的位置有哪些?缓存过程?304的返回体?怎么强制刷新?
- Server Worker(线程缓存)、Memory Cache(内存缓存)、Disk Cache(硬盘缓存)、Push Cache(推送缓存)
- 缓存位置
-
Server Worker 是运行在浏览器的独立线程,一般用来缓存。Server Worker 涉及请求拦截,传输协议必须是HTTPS来保障安全。功能:可以自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
-
Memory Cache 是内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等,占据该进程一定的内存资源,但是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭了 页面,内存中的缓存也就被释放了。 内存缓存特点:①读取速度快 ②时效性:页面关闭进程的内存清空释放
-
Disk Cache 硬盘中的缓存,在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的,绝大部分的缓存都来自 Disk Cache。它会根据HTTP Header中的字段判断哪些资源需要缓存,哪资源不请求直接使用,哪些资源已经过期需要重新请求,它的读取速度慢。
-
Push Cache 是HTTP/2的内容,当以上三种缓存都没有命中时,它会被使用。它只会在会话(Seesion)中存在,一旦会话结束就会被释放,并且缓存时间很短暂,在谷歌浏览器只有5分钟左右。特性:所有的资源都能被推送,并且能够被缓存;Push Cache中的缓存只能被使用一次;可以推送其它域名资源;浏览器可以拒绝接受已经存在的资源推送;一旦关闭,PushCache就会被释放;可以推送到no-cache 和 no-store的资源。
- 缓存过程 浏览器第一次向服务器发起该请求拿到请求结果后,会根据响应报文中的缓存标识,决定是否缓存结果,如果需要,则将请求结果和缓存标识存入浏览器缓存中。接下来浏览器每次发起请求,首先会根据请求头来判断是否命中强缓存,如果命中,就使用强缓存,不发送请求,如果没有命中,则发送请求到服务器看是否命中协商缓存,若命中协商缓存,服务器返回304告诉浏览器可以使用本地缓存,没有命中协商缓存,返回最新的资源。
- 返回304 是对客户端有缓存情况下服务端的一种响应(协商缓存成功后,服务器资源没有更新,继续在浏览器读取缓存)。
- 强制刷新 (1)普通刷新:浏览器优先从缓存中查找资源,如:缓存文字、缓存图片、缓存视频,目的是提高访问速度。操作:网页上右键刷新。 (2)强制刷新:就是不获取缓存,重新从服务器请求网页上的所有资源,适用内容更新比较快的网站。操作:按快捷键ctrl+F5。(3)在强制刷新浏览器或者清除缓存后,请求的页面以及页面内的所有资源会忽略之前的max-age,去服务器做重新认证。因此,如果用户由于max-age出现问题之后,只需要强制刷新或者清缓存就可以修复问题,但是会降低对网站的信任度。
3.浏览器如何缓存静态资源?
第一次请求肯定是从服务器请求过来的,静态资源缓存主要通过HTTP header中的相关字段完成,这些用来控制缓存策略的字段会和资源一起被缓存在客户端,下次请求资源的时候会带着其中一些信息去发起请求,通过这样的前后端交互,配合实现了静态资源的缓存机制。
4.强缓存,协商缓存(两者可以共存)
- 强缓存(本地缓存)
- 定义: 利用http协议头的expires(时间字符串)和cache- control(相对时间)两个字段来控制的,看协议头上有没有用来表示资源的缓存时间;强缓存中,如果普通刷新会忽略他,不会清除他,需要强制刷新。
- 在 http 1.0 版本中,通过 Expires 响应头来实现,expires 表示未来资源会过期的时间。
- 在 http 1.1 版本中,通过 Cache-Control 响应头来实现。
- Cache-Control
- Cache-Control的优先级比Expires高,Expires是绝对时间,Cache-Control是相对时间
- 如何控制强缓存?
通过响应头catch-control中的max-age等指令进行控制,max-age可设置强缓存时间周期,在该周期内将直接从客户端缓存获取资源,不会向服务器发送请求. - 命中规则:Expires字段在,并且没有过期;Cache-Control:max-age/s-maxage字段同时存在,并且没有过期;或者前面两种同时满足。
- s-maxage,s-maxage表示CDN缓存,也就是代理缓存。
- 协商缓存(弱缓存)
- 定义: 协商缓存由服务器决定是否使用缓存。如果协商缓存成功,则返回304,继续使用缓存。如果协商缓存失败,重新获取请求结果,再存入浏览器缓存中。
- 控制字段:Etag/If-None-Match和Last-Modified/If-Modified-Since,其中Etag/If-None-Match的优先级更高。
- 命中规则:没有Expires字段,或者存在但过期了;不存在Cache-Control:max-age/s-maxage字段,或者存在但过期了。
- 字段概念
- 前端如何实现HTTP缓存:
静态的html页面想要设置使用缓存需要通过HTTP的META设置expires和cache-control
- 字段判断过程:Last-Modify是第一次访问此页面时,服务端返回的值,我们把它保存在本地磁盘(像expires和Cache-Control一样),当我们再次发起请求时(已经判断是协商缓存不是强缓存了),会把Last-Modify的值复制一份,放在请求头里发送给服务端,而此时这个属性名就改变为 If-Modify-Since,也就是说,Last-Modify只存在响应头,If-Modify-Since只存在请求头。If-Modify-Since的值被服务端判断,服务端最后一次更新资源时间会被记录下来,对比这两个时间,如果更新时间 等于If-Modify-Since的值,返回304。如果服务端资源更新时间新于If-Modify-Since的值,返回200和最新的缓存数据。
- 为什么还需要Etag?
Etag作为唯一标识,可以进行缓存内容的对比,而不仅仅是时间的对比。服务端一些文件会周期性的更改,但是它的内容并不改变,仅改变时间,这个时候我们并不希望客户端认为这个文件被修改了,而重新获取;服务端某些文件修改非常频繁,比如在秒以下的时间内进行修改。 - 协商缓存通过设置什么返回?
可以通过设置两种 HTTP Header实现:Last-Modified和ETag。
- 两者区别:
- ①强缓存不发送请求到服务器,协商缓存发送请求到服务器 ②强缓存资源更新浏览器不知道,因为没有发送请求到服务器;协商缓存资源更新浏览器都知道,因为发送了请求到服务器③大部分web默认用协商缓存.
内存泄漏
1. 内存泄漏
- 定义: JS程序中已动态分配的内存由于某种原因未释放或无法释放而引发的各种问题称为内存泄露。
- 怎样会引发内存泄漏: 意外的全局变量、闭包、未清除的定时器、控制台日志、dom清空了,还存在引用等。
- 意外的全局变量: JS中对没有声明的变量会默认定义在全局变量windoow上,只有关闭窗口或者刷新页面的时候,全局变量才会被释放,如果一个没有声明的变量上保存了大量的数据,这些数据就会保存在全局变量身上,如果这些数据没有及时释放就会引起内存泄露。
- 全局变量多产生的问题: 生存周期长,越多消耗内存越大、容易引发命名冲突、不利于排查错误和调试。
- 如何避免: 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;注意程序逻辑,避免“死循环”之类的;避免创建过多的对象,原则:不用了的东西要及时归还。
- 如何检查: 在performance 面板 和 memory 面板可以找到泄露的现象和位置。
2. setTimeout为什么会造成内存泄露?如何防止setTimeout内存泄露?
- 原因: 当任何对象绑定到计时器回调时,它不会被释放,直到超时发生。在这种情况下,计时器会自行重置并永远运行,直到超时完成,因为不允许垃圾收集器删除内存,最终就会导致内存泄漏。
- 如何防止: 在 setInterval() 或 setTimeout() 中提供引用,以便在执行垃圾回收之前需要执行函数,一旦不再需要函数,就直接调用删除函数。(调用clearinterval或者cleartimeout清除定时器)。
浏览器安全 (前端安全?)
1. XSS
-
概念: 通过跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息,如 cookie 等。
-
攻击获取的内容: 获取页面的数据,如DOM、cookie、localStorage;DOS攻击,发送合理请求,占用服务器资源,从而使用户无法访问服务器;破坏页面结构;流量劫持(将链接指向某网站);
-
攻击类型:
存储型、反射型和DOM 型
1. 存储型XSS- 概念: 指的是恶意脚本会存储在目标服务器上,当浏览器请求数据时,脚本从服务器传回并执行。这种攻击常⻅于带有⽤户保存数据的⽹站功能,如论坛发帖、商品评论、⽤户私信等。
- 攻击步骤:
- 攻击者将恶意代码提交到⽬标⽹站的数据库中。
- ⽤户打开⽬标⽹站时,⽹站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- ⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
2. 反射型XSS- 概念: 指的是攻击者诱导用户访问一个带有恶意代码的 URL 后,服务器端接收数据后处理,然后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终完成 XSS 攻击。(反射型 XSS 漏洞 常⻅于通过 URL 传递参数的功能,如⽹站搜索、跳转等。 由于需要⽤户主动打开恶意的 URL 才能⽣效,攻击者往往会结合多种⼿段诱导⽤户点击)。
- 攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- ⽤户打开带有恶意代码的 URL 时,⽹站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
- ⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
3. DOM型XSS- 概念: - DOM 型指的通过修改页面的 DOM 节点形成的 XSS。
- 攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- ⽤户打开带有恶意代码的 URL。
- ⽤户浏览器接收到响应后解析执⾏,前端 JavaScript 取出 URL 中的恶意代码并执⾏。
- 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。
4. 三者区别:- 反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库⾥,反射型 XSS 的恶意代码存在 URL ⾥。
- DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执⾏恶意代码由浏览器端完成,属于前端JavaScript ⾃身的安全漏洞,⽽其他两种 XSS 都属于服务端的安全漏洞。
-
如何防御XSS攻击?
预防核心: 对输入的数据做必要的过滤处理。- 对一些敏感信息进行保护,比如 对cookie 设置 http-only属性,使得脚本无法获取。也可以使用验证码,避免脚本伪装成用户执行一些操作。
- 服务器对输入脚本进行过滤或者编码,过滤是将标签内的内容过滤掉,这样恶意的JavaScript代码也就无法执行了,转码是将"<",">"进行转码。
- 充分利用CSP等策略。csp是内容安全策略,核心思想在于让服务器决定浏览器能够加载哪些资源,所以,浏览器请求资源的时候,服务器会告诉浏览器哪些文件可以执行,哪些不可以执行。(通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的方式)。
2. CSRF
-
概念: 指的是 跨站请求伪造攻击,攻击者诱导用户进入一个第三方网站,然后该网站向被攻击网站发送跨站请求,如果用户在被攻击网站中保存了登录状态,那么攻击者就可以利用这个登录状态,绕过后台的用户验证,冒充用户向服务器执行一些操作。本质 是利用 cookie 会在同源请求中携带,发送给服务器的特点,以此来实现用户的冒充。
-
攻击类型:
- GET 类型的 CSRF 攻击: 比如在网站中的一个 img 标签里构建一个请求,当用户打开这个网站的时候就会自动发起提交。
- POST 类型的 CSRF 攻击: 比如构建一个表单,然后隐藏它,当用户进入页面时,自动提交这个表单。
- 链接类型的 CSRF 攻击: 比如在 a 标签的 href 属性里构建一个请求,然后诱导用户去点击。
-
如何防御:
- 进行同源检查: 服务器根据 http 请求头中 origin 或者 referer 信息来判断请求是否为允许访问的站点,从而对请求进行过滤。当 origin 或者 referer 信息都不存在的时候,直接阻止请求。这种方式的缺点是有些情况下 referer 可以被伪造,同时还会把搜索引擎的链接也给屏蔽了。所以一般网站会允许搜索引擎的页面请求,但是相应的页面请求这种请求方式也可能被攻击者给利用。(Referer 字段会告诉服务器该网页是从哪个页面链接过来的)。
- 使用 CSRF Token 进行验证: 服务器向用户返回一个随机数 Token ,当网站再次发起请求时,在请求参数中加入服务器端返回的 token ,然后服务器对这个 token 进行验证。这种方法解决了使用 cookie 单一验证方式时,可能会被冒用的问题,但是这种方法存在一个缺点就是,我们需要给网站中的所有请求都添加上这个 token,操作比较繁琐。还有一个问题是一般不会只有一台网站服务器,如果请求经过负载平衡转移到了其他的服务器,但是这个服务器的 session 中没有保留这个 token 的话,就没有办法验证了。这种情况可以通过改变 token 的构建方式来解决。
- 对 Cookie 进行双重验证: - 服务器在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串,然后当用户再次向服务器发送请求的时候,从 cookie 中取出这个字符串,添加到 URL 参数中,然后服务器通过对 cookie 中的数据和参数中的数据进行比较,来进行验证。使用这种方式是利用了攻击者只能利用 cookie,但是不能访问获取 cookie 的特点。并且这种方法比 CSRF Token 的方法更加方便,并且不涉及到分布式访问的问题。这种方法的缺点是如果网站存在 XSS 漏洞的,那么这种方式会失效。同时这种方式不能做到子域名的隔离。
- 在设置 cookie 属性的时候设置 Samesite ,限制 cookie 不能作为被第三方使用: 从而可以避免被攻击者利用。Samesite 一共有两种模式,一种是严格模式,在严格模式下 cookie 在任何情况下都不可能作为第三方 Cookie 使用,在宽松模式下,cookie 可以被请求是 GET 请求,且会发生页面跳转的请求所使用。
3. 什么是中间人攻击?如何防范中间人攻击?
- 概念: 中间⼈ (Man-in-the-middle attack, MITM) 是指攻击者与通讯的两端分别创建独⽴的联系, 并交换其所收到的数据, 使通讯的两端认为他们正在通过⼀个私密的连接与对⽅直接对话, 但事实上整个会话都被攻击者完全控制。在中间⼈攻击中,攻击者可以拦截通讯双⽅的通话并插⼊新的内容。
- 攻击过程:
- 客户端发送请求到服务端,请求被中间⼈截获。
- 服务器向客户端发送公钥。
- 中间⼈截获公钥,保留在⾃⼰⼿上。然后⾃⼰⽣成⼀个伪造的公钥,发给客户端。
- 客户端收到伪造的公钥后,⽣成加密hash值发给服务器。
- 中间⼈获得加密hash值,⽤⾃⼰的私钥解密获得真秘钥,同时⽣成假的加密hash值,发给服务器。
- 服务器⽤私钥解密获得假密钥,然后加密数据传输给客户端。
- 如何防范: 增加一个安全通道来传输信息。HTTPS 就可以用来防御中间人攻击,但是并不是说使用了 HTTPS 就可以不管了,因为如果没有完全关闭 HTTP 访问的话,攻击方可以通过某些方式将 HTTPS 降级为 HTTP 从而实现中间人攻击。
5. 有哪些可能引起前端安全问题
- 跨站脚本XSS
- iframe的滥⽤ iframe中的内容是由第三⽅来提供的,默认情况下他们不受控制,他们可以在iframe中运⾏JavaScirpt脚本、Flash插件、弹出对话框等等,这可能会破坏前端⽤户体验。
- 跨站点请求伪造CSRF
- 恶意第三⽅库
6. 网络劫持有哪几种?如何防范?
- DNS劫持: (输⼊京东被强制跳转到淘宝这就属于dns劫持)
- DNS强制解析: 通过修改运营商的本地DNS记录,来引导⽤户流量到缓存服务器。
- 302跳转的⽅式: 通过监控⽹络出⼝的流量,分析判断哪些内容是可以进⾏劫持处理的,再对劫持的内存发起302跳转的回复,引导户获取内容。
- HTTP劫持: (访问⾕歌但是⼀直有贪玩蓝⽉的⼴告)
- 由于http明⽂传输,运营商会修改http响应内容(即加⼴告) DNS劫持由于涉嫌违法,已经被监管起来,现在很少会有DNS劫持,⽽http劫持依然⾮常盛⾏,最有效的办法就是全站HTTPS,将HTTP加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容。
7. HTTP
- 概念: 超文本传输协议(hypertext transfer prototal) 是客户端和服务器端互相通信时必须遵守的协议。HTTP协议是应用层协议,底层是基于TCP协议,默认是用80端口。
- 请求方法:
- GET: 向服务器获取数据;
- POST:将实体提交到指定的资源,通常会造成服务器资源的修改;
- PUT:上传文件,更新数据;
- DELETE:删除服务器上的对象;
- HEAD:获取报文首部,与GET相比,不返回报文主体部分;
- OPTIONS:询问支持的请求方法,用来跨域请求;
- CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信;
- TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。
- GET和POST请求区别:
- 应用场景: 一般 get 请求用于对服务器资源不会产生影响的场景,比如说请求一个网页的资源;post 请求一般用于对服务器资源会产生影响的情景,比如注册用户这一类的操作。
- 是否缓存: 因为两者应用场景不同,浏览器一般会对 get 请求缓存,但很少对 post 请求缓存。
- 发送的报文格式: get 请求的报文中实体部分为空,post 请求的报文中实体部分一般为向服务器发送的数据。
- 安全性: get 请求可以将请求的参数放入 url 中向服务器发送,这样的做法相对于 post 请求来说是不太安全的,因为请求的 url 会被保留在历史记录中。
- 请求长度: 浏览器由于对 url 长度的限制,所以会影响 get 请求发送数据时的长度。这个限制是浏览器规定的,并不是 RFC 规定的。
- 参数类型: post 的参数传递支持更多的数据类型。
- post和put请求的区别
- put请求是向服务器端发送数据,从而修改数据的内容,但是不会增加数据的种类等。(更新数据)
- post请求是向服务器端发送数据,该请求会改变数据的种类等资源,它会创建新的内容。(创建数据)
- 常见的HTTP请求头和响应头
- HTTP Request Header 常见的请求头:
- Accept:浏览器能够处理的内容类型
- Accept-Charset:浏览器能够显示的字符集
- Accept-Encoding:浏览器能够处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Connection:浏览器与服务器之间连接的类型
- Cookie:当前页面设置的任何Cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的页面的URL
- User-Agent:浏览器的用户代理字符串
- HTTP Responses Header 常见的响应头:
- Date:表示消息发送的时间,时间的描述格式由rfc822定义
- server:服务器名称
- Connection:浏览器与服务器之间连接的类型
- Cache-Control:控制HTTP缓存
- content-type:表示后面的文档属于什么MIME类型
- 常见的 Content-Type 属性值有以下四种:
- application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。
- multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
- application/json:服务器消息主体是序列化后的 JSON 字符串。
- text/xml:该种方式主要用来提交 XML 格式的数据。
- HTTP Request Header 常见的请求头:
- HTTP 1.0----HTTP 1.1----HTTP 2.0
- HTTP 1.0 与 HTTP 1.1主要区别
- 连接方面: HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP 1.1默认支持长连接,这样减少创建连接的开销,提高了效率。(HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响,因此最好能维持一个长连接,可以用个长连接来发多个请求)。
- 资源请求方面: 在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 缓存方面,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- http1.1 中 新增了 host 字段,用来指定服务器的域名。http1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了 host 字段,这样就可以将请求发往到同一台服务器上的不同网站。
- http1.1 相对于 http1.0 还新增了很多请求方法,如 PUT、HEAD、OPTIONS 等。
- HTTP 1.0 与 HTTP 1.1主要区别
- 二进制协议: HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
- 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
- 数据流: HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
- HTTP 1.0 与 HTTP 1.1主要区别
- HTTP3.0 基于UDP协议实现了类似于TCP的多路复用数据流、传输可靠性等功能,这套功能被称为QUIC协议,流量控制、传输可靠性功能,集成TLS加密功能,多路复用。
- 状态码:
1XX: 服务器端已收到请求
2XX: 成功 200ok
3XX: 重定向/缓存 301永久重定向 302临时重定向 304资源未更改
4XX: 客户端错误 403请求页面禁止访问 404not found资源不存在,比如输入错误的url
5XX: 服务器端错误 500服务器代码问题 - keep-alive
- 出现原因: HTTP1.0 中默认是在每次请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接,这就是短连接。当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接,这就是长连接。
- 使用方法:
- HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送
Connection: keep-alive字段。若想断开keep-alive连接,需发送Connection:close字段; - HTTP1.1规定了默认保持长连接,数据传输完成了保持TCP连接不断开,等待在同域名下继续用这个通道传输数据。如果需要关闭,需要客户端发送
Connection:close首部字段。
- HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送
- Keep-Alive的建立过程:
- 客户端向服务器在发送请求报文同时在首部添加发送Connection字段
- 服务器收到请求并处理 Connection字段
- 服务器回送Connection:Keep-Alive字段给客户端
- 客户端接收到Connection字段
- Keep-Alive连接建立成功
- 服务端自动断开过程(也就是没有keep-alive):
- 客户端向服务器只是发送内容报文(不包含Connection字段)
- 服务器收到请求并处理
- 服务器返回客户端请求的资源并关闭连接
- 客户端接收资源,发现没有Connection字段,断开连接
- 客户端请求断开连接过程:
- 客户端向服务器发送Connection:close字段
- 服务器收到请求并处理connection字段
- 服务器回送响应资源并断开连接
- 客户端接收资源并断开连接
- 开启Keep-Alive的优点:
- 较少的CPU和内存的使⽤(由于同时打开的连接的减少了);
- 允许请求和应答的HTTP管线化;
- 降低拥塞控制 (TCP连接减少了);
- 减少了后续请求的延迟(⽆需再进⾏握⼿);
- 报告错误⽆需关闭TCP连;
- 开启Keep-Alive的缺点:
- 长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。
8. HTTPS
- 概念: 是超文本传输安全协议,一种通过计算机网络进行安全通信的传输协议,HTTPS经由HTTP进行通信,利用SSL/TLS来加密数据包。(安全层:对发起的HTTP请求的数据进行加密操作 和 对接收到的HTTP的内容进行解密操作。)
- 主要目的: 是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
- 特点: 可以进行加密传输、身份认证,通信更加安全,防止数据在传输过程中被窃取、修改,确保数据安全性;可以认证用户和服务器,确保数据发送到正确的客户端和服务器;需要做服务器和客户端双方的加密和解密处理,耗费更多服务器资源,过程复杂;SSL证书是收费的,功能越强大的证书费用越高。
- TLS/SSL的工作原理
- 概念: 安全传输层协议(Transport Layer Security), 是介于TCP和HTTP之间的一层安全协议,不影响原有的TCP协议和HTTP协议,所以使用HTTPS基本上不需要对HTTP页面进行太多的改造。
- TLS/SSL实现: TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash (验证信息的完整性)、对称加密算法(采用协商的秘钥对数据加密)、非对称加密算法 (实现身份认证和秘钥协商)。
- HTTPS加密过程:分为证书验证和数据传输阶段
证书验证阶段--->非对称加密数据内容阶段--->对称加密。具体过程
- 客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。
- 服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。
- 客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服 务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。
- 服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。
- 客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。
- HTTPS是如何保证安全的?
- 结合两种加密⽅式,将对称加密的密钥使⽤⾮对称加密的公钥进⾏加密,然后发送出去,接收⽅使⽤私钥进⾏解密得到对称加密的密钥,然后双⽅可以使⽤对称加密来进⾏沟通。
- 此时⼜带来⼀个问题,中间⼈问题: 如果此时在客户端和服务器之间存在⼀个中间⼈,这个中间⼈只需要把原本双⽅通信互发的公钥,换成⾃⼰的公钥,这样中间⼈就可以轻松解密通信双⽅所发送的所有数据。
- 所以这个时候需要⼀个安全的第三⽅颁发证书(CA),证明身份的身份,防⽌被中间⼈攻击。 证书中包括:签发者、证书⽤途、使⽤者公钥、使⽤者私钥、使⽤者的HASH算法、证书到期时间等。
- 但是问题来了,如果中间⼈篡改了证书,那么身份证明是不是就⽆效了?这个证明就⽩买了,这个时候需要⼀个新的技术,数字签名。
- 数字签名就是⽤CA⾃带的HASH算法对证书的内容进⾏HASH得到⼀个摘要,再⽤CA的私钥加密,最终组成数字签名。当别⼈把他的证书发过来的时候,我再⽤同样的Hash算法,再次⽣成消息摘要,然后⽤CA的公钥对数字签名解密,得到CA创建的消息摘要,两者⼀⽐,就知道中间有没有被⼈篡改了。这个时候就能最⼤程度保证通信的安全了。
9. 对称加密、非对称加密
- 对称加密:
- 原理: 双方使用同一个秘钥对数据进行加密和解密。因为秘钥是会通过网络传输的,那么需要保证秘钥传输的安全性,一旦秘钥被其他人获取到,那么整个加密过程就毫无作用了。(常见的对称加密算法有AES-CBC、DES、3DES、AES-GCM等)。。
- 特点: 算法简单,加密解密容易,效率高,执行快,相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译。
- 应用场景: 可以用来传递一些隐秘的信息,因为只有双方有密钥,比如客户端和服务端。
- 非对称加密:
- 原理: 拥有两个秘钥,一个是公钥,一个是私钥。公钥是公开的,私钥是保密的。用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。(可以将公钥公布出去,任何想和我们通信的客户,都可以使用我们提供的公钥对数据进行加密,这样我们就可以使用私钥进行解密,这样就能保证数据的安全了)。
- 特点: 安全,即使密文被拦截、公钥被获取,但是无法获取到私钥,也就无法破译密文。作为接收方,务必要保管好自己的密钥。缺点 加密算法及其复杂,安全性依赖算法与密钥,而且加密和解密效率很低,加密的过程很慢,因此如果每次通信都使用非对称加密的方式的话,反而会造成等待时间过长的问题。
- 应用场景: 签名(服务端加签、客户端解签验证)、秘钥交换,证书等场景。
10. 数字证书
- 出现原因: 因为没有办法确定得到的公钥就一定是安全的公钥。可能存在一个中间人,截取了对方发给我们的公钥,然后将他自己的公钥发送给我们,当我们使用他的公钥加密后发送的信息,就可以被他用自己的私钥解密。然后他伪装成我们以同样的方法向对方发送信息,这样我们的信息就被窃取了,然而自己还不知道。为了解决这样的问题,可以使用数字证书。
- 概念: 使用 Hash 算法来对公钥和其他信息进行加密,生成一个信息摘要,然后让有公信力的认证中心(简称 CA )用它的私钥对消息摘要加密,形成签名。最后将原始的信息和签名合在一起,称为数字证书。
11.HTTP和HTTPS的区别?
- HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以避免此类问题发生。HTTP通常运行在TCP之上,HTTPS存在于HTTP和TCP之间,HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,https需要申请CA证书,付费;http默认端口号80,https默认端口号443;
浏览器同源策略和跨域
1. 同源策略
- 概念: protocol(协议)、domain(域名)、port(端口)三者必须一致。
- 限制方面:
- 当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。
- 当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。
- 当前域下 ajax 无法发送跨域请求。
- 目的 主要是为了保证用户的信息安全,它只是对 js 脚本的一种限制,并不是对浏览器的限制,对于一般的 img、或者script 脚本请求都不会有跨域的限制,这是因为这些操作都不会通过响应结果来进行可能出现安全问题的操作。
2. 跨域 其他认证方式?
- 产生原因: 就是因为浏览器的同源策略造成的。
- 解决方式:
- CORS
- JSONP
- postMessage 跨域
- nginx代理跨域
- nodejs 中间件代理跨域
- document.domain + iframe跨域
- location.hash + iframe跨域
- window.name + iframe跨域
- WebSocket协议跨域
浏览器的事件机制
1. 事件:
- 事件的概念: 是用户操作页面时发生的交互动作,比如click/move等,事件除了用户触发的动作外,还可以是文档加载、窗口滚动和大小调整。事件被封装为一个event对象,包含了事件的属性和方法。
- 事件流: 事件的流向,先捕获,再到事件源,最后再冒泡,在DOM2级事件模型中,事件流分为三个阶段:事件捕获、事件处理、事件冒泡。
- 事件模型:
- DOM0级事件模型: 可以在网页中直接定义监听函数,也可以通过js来指定监听函数,直接在DOM对象上注册事件。
- IE事件模型: 该事件模型共有两个过程:事件处理阶段和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
- DOM2级事件模型: 一共三个过程:事件捕获阶段:事件从document一直向下传播到目标元素,依次检查经过的结点是否绑定了事件监听函数,如果绑定则执行。后两个阶段与IE事件模型相同。
- 事件捕获:
- 概念: 在捕获的过程中,最外层(根)元素的事件先被触发,然后依次向内执行,直到触发最里面的元素(事件源),自顶向下的过程。
- 事件冒泡:
- 概念: 在冒泡过程中,自子元素冒泡向父元素。(自底向上),当子元素(事件源)事件触发,事件会沿着包含关系,依次往上级传递,每一级都可以感知到事件,直到触发根元素(根源)。
- 阻止冒泡:
- 普通浏览器使用:event.stopPropagation(),不让事件向documen上蔓延。
- IE浏览器独有,设置:event.cancelBubble = true;
- 也可以封装一个取消冒泡的函数stopBubble(event),主要是将以上两种方法合并兼容,对于任何浏览器都调用函数来使用。
- 事件代理(事件委托)
- 概念: 事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件委托(事件代理)。
- 事件委托的优点:
- 可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件。
- 可以实现当新增子对象时无需再次对其绑定(动态绑定事件)。
- 使用场景: 如果我们有⼀个列表,列表之中有⼤量的列表项,我们需要在点击列表项的时候响应⼀个事件,如果给每个列表项⼀⼀都绑定⼀个函数,那对于内存消耗是⾮常⼤的,这时候就可以事件委托,把点击事件绑定在⽗级元素 ul 上⾯,然后执⾏事件的时候再去匹配⽬标元素。
2. 事件循环
- JS是一个单线程的脚本语言,一般情况下代码是同步执行的,所以js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个异步事件放到任务队列里面,继续执行执行栈中的其他任务。任务队列里面存放两种任务,又分为宏任务和微任务。
- 宏任务: setTimeout,setInterval
- 微任务: Promise.then那些,process.nextTick
- 当前执行栈执行完毕时,主线程会查看微任务队列有没有事件等待执行,如果有就将其压入执行栈中执行,如果没有,就查看宏任务队列有无事件。如此反复循环。
- 执行的顺序是:主线程->微任务队列 ->宏任务队列
- 任务队列: 任务队列是一个先进先出的队列,它里面存放着各种任务回调。
- 事件轮询: 事件轮询是指主线程重复从任务队列中取任务、执行任务的过程。
3. 同步和异步的区别
- 同步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,那么这个进程会一直等待下去,直到消息返回为止再继续向下执行。
- 异步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,这个时候进程会继续往下执行,不会阻塞等待消息的返回,当消息返回时系统再通知进程进行处理。
4. 操作系统
- 堆: 存放引用类型,是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定,动态分配的内存,大小不定也不会自动释放,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。可以简单理解为存储代码块。
- 栈
- 队列
- 时间循环
- 执行顺序
- 宏任务
- 微任务
- 进程
- 线程
- 多线程