DNS 的解析过程
TCP 为什么可靠?
超时重传
就是在发送数据时,设定一个定时器(RTO),当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据。该计时器的时间一般是由当前网络来决定的,一个 RTT 指的是当一个报文从发送到接收所需的时间,RTO 的取值是发送方尝试发送几个报文,然后取平均 RTT 时间来决定的。
TCP 会在以下两种情况发生超时重传:数据包丢失、确认应答丢失。
快速重传
快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
当接收方发现接收到的序列号不对的时候,会发送连续的三个 ACK 标志,告诉发送方这个报文在传输过程中出现了丢包。发送方如果接收到某个相同的序列号的三个 ACK 报文,那么此时立马重发该报文,不会等待计时器的时间结束。
滑动窗口
TCP 引入了窗口这个概念。即使在往返时间较长的情况下,它也不会降低网络通信的效率。
有了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
发送方通过维持一个发送滑动窗口来确保不会发生由于报文发送太快导致接收方无法及时处理的问题。此时发送方的报文分为四类:第一类是已经发送并且得到接收方确认的报文;第二类是已经发送但是没有接收到确认的报文;第三类是发送方还没发送,但是滑动窗口还足够巨大,允许被发送的报文;第四类是还没发送并且窗口已经被占满,不允许发送的报文。
流量控制
发送方不能无脑发数据给接收方,要考虑接收方的处理能力,否则就会导致触发重发机制,从而导致网络流量的无端浪费。
为了解决这种现象,TCP 提供一种机制可以让发送方根据接收方的实际接收能力,控制发送的数据量,这就是所谓的流量控制。
拥塞控制
流量控制是避免发送方的数据填满接收方的缓存,但是并不知道网络中发生了什么。
一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。
网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环,被不断地放大。
所以,TCP 不能忽略网络上发生的事,它被设计成一个无私的协议,当网络发送拥塞时,TCP 会自我牺牲,降低发送的数据量。
于是,就有了拥塞控制,控制的目的就是避免发送方的数据填满整个网络。
为了在发送方调节所要发送数据的量,定义了一个叫做拥塞窗口的概念。
拥塞窗口 cwnd (rwnd 表示接收窗口)是发送方维护的一个状态变量,它会根据网络的拥塞程度动态变化的。
拥塞控制主要是四个算法:慢启动、拥塞避免、拥塞发生、快速恢复。
HTTP 的状态码
GET 和 POST
其他请求方法
TCP/IP 和 HTTP 协议的区别?
对称加密和非对称加密
HTTP 长连接和短连接的区别?
轮询、长轮询、长连接、WebSocket 的区别?
Connection: keep-alive
进行长连接,HTTP/1.1 默认进行持久连接,在一次 TCP 连接中可以完成多个 HTTP 请求,但是每个请求仍然要单独发 HEADERupgrade: WebSocket
表明这是一个申请协议升级的 HTTP 请求,服务器解析这些附加的头信息,然后产生响应信息返回给客户端,客户端和服务器的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由地传递信息,并且这个连接会一直持续到客户端或服务器任意一方主动关闭连接Session、Cookie 和 Application 的区别?
Cookie 是如何工作的?
当客户端访问服务器时,服务器通过 Cookie 构造器构造一个 Cookie 实类,然后服务器在响应信息头中附带 Cookie 实类到客户端,并保存在客户端内存中,在 Cookie 生命周期内,以后的每次请求都会携带这个 Cookie。
Cookie 和 Session 是如何记住登录状态的?
当 Session 启动时,服务器会生成一个唯一值,称为 sessionid,服务器会开辟一块内存,对应该 sessionid,服务器再将该 sessionid 写入浏览器的 Cookie,服务器内有一进程,监视所有 Session 的活动状态,如果有 Session超时或主动关闭,服务器就释放该内存块。当浏览器请求服务器时,服务器会先查看请求头 Cookie 中是否有 seesionid,如果有,就检查该 sessionid 对应的内存是否有效,有效则读取内存中的值,无效则建立新的 Session。
当 Cookie 被禁止时,如何保存登录状态?
保存登陆状态的关键不是 Cookie,而是通过 Cookie 保存和传送 sessionid 的值,我们可以通过 encodeURL 编码 URL,或者 access token,然后将其保存到 localstorage 即可。
什么是死锁以及死锁的解决办法?
Web 安全防范
HttpOnly
,XSS 攻击主要是想获取到 Cookie 中的 sessionid 并劫持对话,而当 Cookie 设置为 HttpOnly
属性时,js 脚本将无法获取到 Cookie 信息;输入输出检查过滤;HTML 代码转译Referer
字段,在 HTTP 请求头中有一个 Referer
字段,它记录了该 HTTP 请求的来源地址,只需要核对 Referer
字段是否是合法来源即可,注意在 IE6 中可以修改 Referer
值;在请求地址中添加 token
,可以在 HTTP 请求中以参数加入一个随机的 token
,并在服务器上建立一个拦截器来验证这个 token
;在 HTTP 头中自定义属性并验证,其方法和 token 差不多,只是将其添加到 HTTP 头自定义属性中为什么浏览器会产生同源策略?
同源策略的目的是为了限制不同源的 document 或者脚本之间互相访问,以免造成干扰和混乱。如果没有限制,那么浏览器中的 Cookie 等数据就可以被任意读取,不同域下的 DOM 任意操作,ajax 任意请求其他网站的数据包括隐私数据。
浏览器的缓存机制
Expires
和 Cache-Control
,Expires
保存的是一个绝对时间,即缓存过期时间,它是相对服务器时间来定的,浏览器会判断本地时间和Expires
来确定是否要访问本地缓存,由于服务器时间和客户端时间在很多时候是不相等的,所以有可能会造成不确定性,现在几乎很少使用 Expires
;Cache-control
保存的是一个相对时间,可以通过设置 max-age
来确定文件的缓存时间,其原理和 Expires
一样,当两者同时存在时,Cache-Control
的优先级高于 Expires
Last-Modify
和 ETag
,Last-Modify
:浏览器第一次访问服务器的时候,会在返回的请求头中加上一个 Last-Modified
字段,它是资源的最后修改时间,当浏览器再次访问时,其请求头中会包含一个 If-Modified-Since
字段,服务器判断它是否相同再确定是返回 304 还是 200;ETag
:其原理和 Last-Modify
几乎一样,只是它返回的是一般是哈希值或是对该资源的 md5 值(生成规则由服务器决定),它会在请求头携带 If-None-Match
字段,如果两者同时存在,ETag
的优先级高于 Last-Modify
,Last-Modified
只能精确到秒,秒内的内容更新只有 ETag
才能检查,文件有时会定时重新生成相同的内容,Last-Modified
不能很好地识别,ETag
每次服务器生成都需要进行读写操作,而 Last-Modified
只需要读取操作,Etage
的消耗更大Etag
或 Last-Modified
返回 304 或 200浏览器从输入 URL 到页面渲染的过程
TCP 建立连接的过程
TCP/IP 三次握手
SYNC_SEND
状态,等待服务器确认SYN_RECV
状态ESTABLISHED
状态如果建立连接之后客户端出现故障
TCP 设有一个 保活计时器
,服务器在每收到一次客户端的请求后都会重置该计时器,时间通常设置为 2 小时,若 2 小时后还没有收到客户端的任何数据,服务器就会发送一个探测报文段,之后每隔 75s 再发送一次,若连续发送 10 个探测报文段都仍未有响应,那么服务器便认为客户端出现故障并主动关闭连接。
TCP/IP 四次挥手
FIN-WAIT-1
状态CLOSE_WAIT
状态LAST_ACK
状态TIME_WAIT
状态,并发送 ACK 确认报文(ack=w+1)给服务器,服务器接收后进入 CLOSED
状态,完成四次挥手为什么客户端发送完最后一个 ACK 包后并不会立刻进入 CLOSED
状态,而是会等待 2MSL(最长报文段寿命)
如果网络是不可靠的,那么有可能最后一个 ACK 会丢失,而服务器将会不断重复地发送 FIN 片段,所以客户端不能立即关闭,它必须确认服务器已经接收到了该 ACK,TIME_WAIT
状态就是用来重发可能丢失的 ACK 报文,客户端会设置一个计时器并等待 2MSL 的时间,如果在该时间内再次收到 FIN,那么客户端就会重新发送一个 ACK 并再次等待 2MSL。所谓的 MSL就是一个片段在网络中的最大存活时间,2MSL 就是发送和回复所需要的最大时间,如果直到 2MSL 时间后客户端都没有再次收到 FIN,那么客户端就判断 ACK 已经被成功接收并结束 TCP 连接。
为什么要三次握手
主要是为了防止失效的连接请求报文段被服务器接收,从而产生错误,如果建立连接只需要两次握手,客户端没有太大改变,还是需要获得服务器的响应后才进入 ESTABLISHED
状态,而服务器则是在接收到连接请求后就进入 ESTABLISHED
状态。此时如果网络阻塞导致客户端发送的连接请求迟迟不到服务器,客户端便会超时重发,这时如果服务器正确接收并响应了,双方便开始通信,通信结束后释放连接。此时如果那个失效的连接请求抵达了服务器,由于只存在两次握手,那么服务器就会再次进入 ESTABLISHED
状态,等待发送数据或主动发送请求,但此时客户端已经进入 CLOSED
状态,那么服务器就会一直等待下去,浪费连接资源。
为什么要四次挥手
四次挥手中的第二次和第三次是分开的,而不是像三次握手那样一起发送,因为服务器发送报文段二的时候只是确认客户端发送的结束报文,并不代表自身的数据已经传输完毕,由于时间是不确定的,如果硬是等到自身数据传输完毕后再将确认报文 ACK 和自身结束报文 FIN 一起发送,可能会导致客户端超时重传等问题,造成资源浪费。
什么是线程,线程和进程的区别?
let、const 和 var 的区别?
介绍一下 promise 相关的东西
js 判断类型的方法
New 一个对象的过程
原型链
_proto_
属性(隐式原型):它的值就是它所对应的原型对象,作用是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的 _proto_
属性所指向的那个对象里找,一直向上找直到 _proto_
属性的终点 null,再往上找相当于在 null 上取值,会报错,通过 _proto_
属性将对象连接起来的这条链路即我们所说的原型链Prototype
属性(显示原型):是函数的原型对象,作用就是让该函数所实例化的对象们可以找到公用的属性和方法Constructor
属性:是指向该对象的构造函数,所有函数的最终构造函数都是 FunctionJSON.parse(JSON.stringify()) 深拷贝的弊端
深拷贝
使用递归的方式实现深拷贝
function deepClone1(obj) {
// 判断要进行深拷贝的是数组还是对象, 是数组的话进行数组拷贝, 对象的话进行对象拷贝
var objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === "object") {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone1(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
通过 JSON 对象实现深拷贝
var _obj = JSON.parse(JSON.stringify(obj))
通过 Jquery 的 extend 方法实现深拷贝
$.extent(true, {}, obj);
通过 Object.assign() 拷贝
// 当对象中只有一级属性没有二级属性的时,此方法为深拷贝, 但是对象中有对象的时候, 此方法在二级属性以后就是浅拷贝
var _obj = Object.assign({}, obj);
Lodash 函数库实现深拷贝
_.CloneDeep()
两个对象比较
function diff(val1, val2) {
var o1 = val1 instanceof Object;
var o2 = val2 instanceof Object;
if (!o1 || !o2) {
return val1 === val2;
}
if (Object.keys(val1).length !== Object.keys(val2).length) {
return false;
}
for (var o in val1) {
var t1 = val1[o] instanceof Object;
var t2 = val2[o] instanceof Object;
if (t1 && t2) {
diff(t1, t2)
} else if (val1[o] !== val2[o]) {
return false;
}
}
return true;
}
HTTPS 的工作流程
这就是 HTTPS 的基本运作原理,使用对称加密和非对称机密配合使用,保证传输内容的安全性。