- 知道哪些计算机网络模型?OSI 和 TCP/IP
OSI模型一共有七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP/IP模型有四层:应用层(HTTP协议、DNS协议、FTP协议)、传输层(TCP协议、UDP协议)、网络层(IP协议)、网络接口层
1、应用层:应用层主要提供两个终端设备上的应用程序之间信息交换的服务,它定义了信息交换的格式,消息会交给下一层传输层进行传输。我们把应用层传输的数据单元叫做报文。
2、传输层:传输层的主要任务就是负责向两台终端设备进程之间的通信提供通用的数据传输服务,利用该服务传送应用层报文。
主要使用以下两种协议:
TCP协议:提供面向连接的、可靠的数据传输服务
UDP协议:提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)
3、网络层:网络层负责为分组交换网上的不同主机提供通信服务。在发送数据时,网络层把运输层产生的报文或用户数据封装成分组或包进行传送。网络层还有一个任务就是选择合适的路由,使源主机运输层所传下来的分组,能够通过网络层中的路由器找到目的主机。
4、网路接口层:可以看做是数据链路层与物理层的合体。
数据链路层的作用是将网络层交下来的IP数据包组装成帧,在两个相邻节点的链路上传送帧,每一帧包括数据和必要的控制信息。
物理层的作用是 实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉传输介质与物理设备之间的差异。
- 为什么网络要分层:
1、各层之间相互独立。只需要知道自己如何调用下层提供好的功能就可以了。、
2、提高了整体灵活性。每一层都可以使用最合适的技术来实现,只需要保证提供的功能以及暴露的接口规则没有改变就可以了。
3、大问题化小。分层可以将复杂的网络问题分解为很多比较小的、界线比较清晰简单的小问题来处理和解决。这样使得复杂的计算机网络变得易于设计,实现与标准化。
- 浏览器是单进程还是多进程的,为什么:
浏览器是多进程的,浏览器每一个标签页都代表一个独立的进程(多个空白的标签页会合并成一个进程)。
每个进程有多个线程,主要包括:
1、GUI渲染线程:负责渲染页面,负责渲染页面,解析html、css构成DOM树,当页面重绘或者由于某种操作引起回流都会调用该进程。与JS引擎线程是互斥的,当js引擎线程工作时,该线程会被挂起,GUI更新被放在js任务队列中,等待js引擎线程空闲的时候继续执行。
2、js引擎线程:负责解析js脚本,js运行耗时过长 就会导致页面阻塞
3、事件触发线程:当事件符合触发条件被触发时,该线程会把对应的事件回调函数添加到任务队列的队尾,等待js引擎处理。
4、定时器触发线程
5、http请求线程:http请求的时候会开启一个请求线程,请求完成有结果之后将请求的回调函数添加到任务队列中。
- TCP协议与UDP协议的区别:

- 为什么UDP有时候比TCP有优势:
UDP以其简单、传输快的优势,在越来越多的场景下取代了TCP如实时游戏
1、网速的提升给UDP 的稳定性提供了可靠的网络保障,丢包率很低,如果使用应用层重传,能够保证传输的可靠性
2、TCP为了实现网络通信的可靠性使用了复杂的拥塞控制算法,建立了繁琐的握手过程,由于是在TCP内置的系统协议栈中,所以极难对其进行改进。
采用TCP一旦发生丢包会将后续的包缓存起来,等前面的包重传并接收后再继续发送,延时会越来越大,基于UDP对实时性要求较为严格的情况下采用自定义重传机制能够把丢包产生的延迟降低到最低,尽量减少网络问题对游戏造成影响。
- UDP协议为什么不可靠:
1、不保证信息交付:不确认、不重传、无超时
2、不保证交付顺序:不设置包序号,不重排,不会发生队首堵塞
3、不跟踪连接状态:不必建立连接或重启状态机
4、不进行拥塞控制:不内置客户端或网络反馈机制
- TCP三次握手:
浏览器先向服务器发送一个SYN包以及seq序列号,此时浏览器进入SYN_SENT状态,然后服务器接收到SYN包后进入SYN_RECV状态,也向浏览器发送一个SYN包以及ACK确认应答(seq+1),然后浏览器接收到服务器发来的包后再向服务器发送一个确认应答ACK(服务器seq+1),进入EATABLISHED状态,服务器接收后也进入EATABLISHED状态。此时客户端与服务器连接成功,三次握手结束。
- 为什么初始序号是随机的:
因为如果初始序号是一个固定的值,那么恶意者就可以通过这个已知的序号来伪装发送方或者是接收方其中的一方,并造成 一些破坏。
- 为什么是三次握手而不是四次或者两次:
如果我们仅仅进行了两次握手,则服务器端发送了SYN、ACK报文段后不会接收到客户端的确认,也就是说只能自动认为客户端收到了SYN、ACK报文段。
如果进行了四次握手,显然第二步的发送ACK与发送SYN报文段的过程在数据来说没有交叉,并且时间几乎连续,因此是可以合并的,于是便成为了三次握手。
- 三次握手中SYN、ACK丢包如何处理:
一旦超时,服务端会重发该报文段,但如果重发了超过设定的次数服务端仍未收到ACK报文段的话服务端会自动关闭该连接。但此时客户端仍无法感知到连接的关闭,因此服务端还会向客户端发送RST报文段,让客户端感知并重置该连接。
- seq与ACK分别是什么:
seq是表示发送方发送数据包部分的第一位应该在整个数据流中所在的位置;
ACK是表示期望接收方下一次seq是多少。
- 泛洪攻击:
在三次握手中当服务器发送SYN-ACK包给客户端之后,可能不会接收到客户端回应的ACK包,这个就是半开放连接,服务器需要消耗一定数量的系统内存来等待这个连接。攻击者通过创建很多的半开放连接来发动泛洪攻击。
防御:
1、增加TCP backlog队列
由于泛洪攻击原理是依赖于终端主机连接套接字的backlog溢出,因此一个显然的基于终端主机的解决方案是增加backlog队列的大小,通常是修改应用的listen函数调用和一个操作系统内核参数SOMAXCONN,它用于设置一个应用程序能够接收的backlog上限值。
2、减少SYN-RECEIVE的时间
缩短一个TCB(包含了数据发送双方对应的socket信息以及拥有装载数据的缓冲区。)从进入SYN-RECEIVED状态到因为进入下一个状态而被回收之间的时间。
3、SYN缓存
在采用SYN缓存的主机中,一个带有被限制大小的HASH表空间被用于存放那些将被分配给TCB的数据的子集,如果当握手完成的ACK接收到了,这些数据将被复制到一个完成的TCB中,否则超出存活时间的HASH值将会在需要时被回收。
4、SYN Cookies
对比SYN缓存的方法,该方法做到了接收到一个SYN时完全不需要分配空间,因为构成连接的最基本数据都被编码压缩进SYN-ACK的序列号比特位里。对于一个合法连接,服务端将受到一个带有序列号的ACK报文段,然后基本的TCB数据将被重新生成,一个完整的TCB通过解压确认数据将被安全的实例化。其不足之处就是不是所有的TCB数据都能被添加到32位的序列号段中,所以一些高性能要求的TCP选项不能被编码。
5、混合方式
将上述的两种或更多防御方式联合起来使用。
- TCP四次挥手:
- 客户端进程发出连接释放报文,并且停止发送数据。释放报文首部FIN=1,序列号seq等于前面传送过来的数据最后一个字节的序号+1,此时客户端进入FIN_WAIT1状态。
- 服务器收到连接释放报文后发出确认应答ACK,并且带上自己的序列号,然后服务器进入FIN_WAIT2状态
- 客户端收到服务器的确认应答后客户端进入FIN_WAIT2状态,等待服务器发送连接释放报文
- 服务器将最后的数据发送完毕后向客户端发送连接释放报文,此时服务器进入LAST_ACK状态,等待客户端的确认
- 客户端收到服务器的连接释放报文后向服务器发送确认应答,此时客户端进入TIME_WAIT状态,等待一段时间后才进入CLOSED状态
- 服务器收到客户端的确认应答后立即进入CLOSED状态,服务器结束TCP连接的时间要比客户端早一些
- 为什么需要四次挥手:
因为当服务器接收到客户端的连接释放报文后需要发送确认应答ACK与FIN包,但是由于服务器接收到报文之后还有数据需要传输,所以先发送一个确认应答,等到数据全部发送完了才能够发送FIN报文。(FIN报文是终结连接请求)
- TCP第四次挥手为什么要等待2MSL:
1、为了保证客户端最后发送的ACK报文能够到达服务器,因为ACK有可能丢失触发超时重传,假设直接断开一旦ACK丢失则服务器无法正常进入关闭连接状态。
2、再经过2MSL时间可以使本连接中所产生的所有报文段都从网络中消失,保证在关闭连接后不会有还在网络中滞留的报文段去骚扰服务器。
- TCP如何实现可靠性:
TCP通过序列号(报文所发送的数据的第一个字节的序号)、检验和、确认应答信号(期望收到对方的下一个报文段的数据的第一个字节的序号)、重发控制、连接管理、窗口控制、流量控制。拥塞控制实现可靠性。
- TCP的重传机制(针对数据包丢失或者定时器超时):
由于TCP的下层网络层可能出现丢失、重复或者失序的情况,为保证数据传输的正确性,TCP会重传认为已丢失的包。TCP在发送一个数据之后会开启一个定时器,若是在这个时间内没有收到发送数据的确认应答,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。TCP使用两套独立的机制来完成重传,一个是基于时间,一个是基于确认信息。
超时重传(RTO):超时重传时间应该略大于报文往返的RRT值。实际上RTO是经常变化的,因为我们的网络也是经常变化的。
快速重传:不以时间为驱动,而是以数据为驱动重传。快速重传的工作方式就是当收到三个相同的ACK报文时吗,会在定时器过期之前,重传丢失的报文。为了解决是重传之前的一个还是重传所有的问题,于是有了SACK方法。
选择性确认(SACK):这种方式只需要在TCP头部字段中加一个SACK的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据接收到了,然后重传丢失的数据。
D-SACK:可以让发送方知道是发出去的包丢了还是接收方回应的ACK包丢了,还可以知道是不是发送方的数据包被网络延迟了;还可以知道网络中是不是把发送方的数据包复制了。
- TCP协议的流量控制(针对避免网络拥堵):
流量控制就是为了让发送方发送数据的速度不要太快,TCP采用大小可变的滑动窗口进行流量控制。
当一个连接建立时,连接的每一端会分配一个缓冲区来保存输入的数据并将缓冲区的大小发送给另一端;当数据到达时接收方发送确认其中包含自己剩余的缓冲区大小(即自己的接收窗口大小rwnd)。如果接收方应用程序读数据的速度能够与数据到达的速度一样快,接收方将在每一确认中发送一个正的窗口通告;如果发送方操作的速度快于接收方,接收到的数据最终将充满接收方的缓冲区,导致接收方通告一个零窗口,发送方收到一个零窗口通告的时候必须停止发送,直到接收方重新通告一个正的窗口。但有两种情况除外,一个是可以发送紧急数据;一个是发送方可以发送一个1字节的数据包来通知接收方重新声明它希望接收的下一字节及发送方的滑动窗口大小。
- 流量控制与拥塞控制的区别:
流量控制解决的是发送方和接收方速率不匹配的问题,发送方发送过快接收方来不及接收和处理,采用的机制是滑动窗口的控制,控制的是发送了但未被ACK的包数量。
拥塞控制是避免网络资源被耗尽的问题,通过双方自律的采取避让的措施,来避免网络有限资源被用尽,当出现丢包时控制发送的速率达到降低网络负载的目的。
- 拥塞控制中接收窗口与拥塞窗口的区别:
接收窗口由接收方管理,接收方将窗口大小发送给发送方,窗口大小表示接收方缓冲区仍然空闲的字节数。拥塞窗口是发送方的窗口,它的实现是为了避免网络路径中间的一些路由器溢出,拥塞窗口是发送方允许自己发送更多未完成的数据而出现,当发送方检测到数据丢失时对将窗口切成两半,背后的原理是发送方假设数据包丢失是因为某个地方的缓冲区溢出而发生的,因此发送方希望保持较少的数据“在运行中”,以避免将来进一步包的丢失。
- TCP的拥塞控制(避免刚开始启动时避免一下子发送大量数据导致网络瘫痪):
TCP的拥塞控制算法包含了:慢启动,拥塞避免,快速重传,快速恢复
慢启动:开始的时候不要发送大量数据,先测试一下网络的拥塞程度,由小到大增加拥塞窗口(cwnd)的大小。为了防止拥塞窗口增长过大引起网络拥塞,设置一个慢开始门限(sssthresh)。
1 | 当cwnd<sssthresh时,使用慢开始算法 |
拥塞避免:让拥塞窗口缓慢的增大,每经过一个返回时间RRT就把发送方的拥塞控制窗口加一。无论是慢开始阶段还是拥塞避免阶段,只要发送方判断网络出现拥塞,就把慢开始门限设置为拥塞时发送窗口大小的一半,然后拥塞窗口设置为1,执行慢开始算法。
快速重传:要求接收方在收到一个失序的报文段后就立即发出重复确认,发送方只要一连续收到三个重复的确认应发就立即重传对方尚未收到的报文段,而不必等待设置的重传计时器时间到期。
快速恢复:当发送方连续收到三个重复确认就执行乘法减小算法,将门限减半,然后接下去并不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
- TCP的停止等待协议:
停止等待协议是为了实现可靠传输的,它的原理是每发送完一个分组就停止发送,等待对方确认,在收到确认后再发送下一个分组。每个分组发送完会开启一个超时计时器,如果超时则自动重传数据,这种重传方式叫做自动重传请求ARQ。在停止等待协议中若收到重复分组就丢弃该分组,但同时还要再发送确认。连续ARQ协议可提高信道利用率,发送维持一个发送窗口,凡位于发送窗口内的分组可连续发送出去,而不需要等待对方确认。接收方一把采用累积确认,对按序到达的最后一个分组发送确认,表明这个分组位置的所有分组都已经正确收到了。
确认丢失和确认迟到:
1、确认丢失:确认信息在传输过程中丢失。
当A发送M1消息,B收到后,B向A发送了一个M1确认消息,但却在传输过程中丢失。而A并不知道,在超时计时过后,A重传M1消息,B再次收到该消息后采取以下两点措施:
丢弃这个重复的M1消息,不向上层交付;
向A发送确认消息。(不会认为已经发送过了,就不再发送。A能重传,就证明B的确认消息丢失)。
2、确认迟到 :确认消息在传输过程中迟到
A发送M1消息,B收到并发送确认。在超时时间内没有收到确认消息,A重传M1消息,B仍然收到并继续发送确认消息(B收到了2份M1)。此时A收到了B第二次发送的确认消息。接着发送其他数据。过了一会,A收到了B第一次发送的对M1的确认消息(A也收到了2份确认消息)。处理如下:
A收到重复的确认后,直接丢弃。
B收到重复的M1后,也直接丢弃重复的M1。
- 为什么四次握手发送最后一次报文之后需要等待2MSL的时间:
1、为了保证A发送的最后一个确认报文能够到达B,如果A不等待2MSL,若A返回的最后确认报文段丢失,则B不能进入正常状态,而此时A已经关闭,不能再重传。
2、防止出现“已失效的连接请求报文段”,在A发送完最后一个确认报文段后再经过2MSL可保证本连接持续的时间内所产生的所有报文从网络中消失。
- 为什么超时事件发生时cwnd设置为1,而受到三个重复的ACK时cwnd只是减半:
超时事件发生时网络拥塞更严重,说明网络可能已经拥塞得连ACK报文都传输不了了;而受到三个重复的ACK时,虽然网络拥塞但是至少ACK报文能被正确交付,网路拥塞相对不是很严重。
- 是否TCP和UDP都需要计算往返时间RRT:
TCP需要根据RRT来动态设置超时计时器的超时时间,UDP没有确认和重传机制,因此RRT对UDP没有什么意义。
- 为什么TCP在建立连接时不能每次都选择相同的、固定的序列号:
1、假如A和B频繁的建立连接,传送一些TCP报文段后再释放连接,然后又不断建立新的连接,传送报文段和释放连接;
2、假如每一次建立连接时主机A都选择相同的固定的初始序号1
3、若主机A发送出的某些TCP报文在网络中会滞留较长的时间,以致造成主机A超时重传这些TCP报文段
4、若有一些网络中滞留较久的TCP报文最后终于到达了主机B,但这是传送该报文段的连接早已释放了,而在此时到达主机B的TCP连接时一条新的连接
以上情况可能会导致在新的TCP连接中的主机B有可能会接收在旧的连接传送的已经没有意义的过时的TCP报文段(因为这个TCP报文段的序号有可能正好处于新的链接所使用的序号范围内)。因此必须使得迟到的TCP报文段中的序号不在新的连接中使用的序号范围内。不同的TCP连接不能使用相同的初始序号。
- 在使用TCP传输数据时如果有一个确认报文段丢失了,也不一定会引起与该确认报文段相对应的数据的重传:
因为发送方可能还未重传时就收到了更高序号的确认。例如主机A连续发送两个报文段,均正确到达主机B。B连续发送两个确认ACK1和ACK2(ACK2的序号比ACK1的序号高)。但前一个确认帧在传输时丢失了。若在超时前,ACK2被A接收,更高的序号代表该序号之前的所有字节都被接收了,所以A知道前一个报文也被正确的接收了,这种情况下A不会重传第一个报文段。
- Cookie Session Token的原理
cookie的原理:
- 客户端第一次发送请求时发送数据到服务器
- 服务器返回响应消息的同时传回一个cookie
- 客户端接收到服务器的响应后将cookie存放在一个统一的地方
- 客户端再次向服务器发送请求时会把cookie写进请求头然后发给服务器
session的原理:
- 服务器在处理客户端请求过程中会创建session,并为session生成一个唯一的ID
- 服务器将sessionID发送给客户端
- 当客户端再次发送请求时会带上这个sessionID
- 服务器接收到请求之后会根据ID找到相对应的session,完成请求
token的原理:
- 客户端第一次请求时,发送用户信息到服务器,服务器对用户信息使用加密算法和密钥进行签名,再将这个签名和数据一起作为token返回给客户端
- 服务端不再保存token,客户端保存token
- 当客户端再次发送请求时在请求信息中将token一起发送给服务器
- 服务器使用相同的加密算法和密钥对数据再进行一次签名,和token的签名作比较
- 如果相同则知道客户端登录过
- 跨域:
同源:指域名、协议、端口相同
跨域就是指浏览器不能执行其他网站的脚本,是浏览器对Javascript实施的安全限制。之所以有同源策略是浏览器对于用户安全的考虑,会导致Cookie、LocalStorage无法读取,DOM和JS对象无法获取、Ajax请求发送不出去。
解决跨域的方法:
1、jsonp是利用script脚本不受同源策略的限制
(1)前端设置好回调函数,并把回调函数作为请求url携带的参数
(2)后端接收到请求之后,返回回调函数和需要的数据
(3)后端响应并返回数据后,返回的数据传入回调函数中并执行
1 | //通过原生使用script标签 |
也可以使用AJAX的GET方法来跨域请求
1 | <script> |
2、CORS(跨域资源共享)
对于简单请求(GET/POST/HEAD)的跨域,只需要在服务端设置Access-Control-Allow-Origin即可,在发送请求时客户端会自动在请求头中添加origin字段,当请求到达服务端时如果origin指定的源在服务器许可范围内就会返回一个正常的响应,否则返回一个错误。
对于复杂请求的跨域,由于复杂请求在发送之前会使用options方法发起一个预检请求以获取服务器是否允许该请求。所以首先需要对options方法的请求添加这些响应头,它会告诉浏览器根据这些属性进行跨域限制,随后我们对正式请求添加跨域响应头:
1 | app.use(function (req, res, next) { |
3、代理跨域请求
前端发送请求经过代理,请求需要的服务器资源
4、HTML5 postMessage方法
允许来自不同源的脚本采用异步方式进行有限的通信
5、基于HTML5的websocket协议
基于该协议可以做到浏览器与服务器全双工通信,允许跨域请求
- 窗口之间的数据通信跨域怎么解决:
1、location.hash + iframe
具体流程如下:
(1)不同域的a页面与b页面进行通信,在a页面通过iframe嵌入b页面,并给iframe的src添加一个hash值
(2)b页面接收到了hash值后,确定a页面在尝试向自己通信,然后通过parent.location.hash的值,将要通信的数据传递给a页面的hash
(3)但由于IE与Chrome下不允许子页面直接修改父页面的hash值,所以需要一个代理页面,通过与a页面同域的c页面开传递数据
(4)同样的在 b页面中通过iframe嵌入c页面,将要传递的数据通过iframe的src链接的hash值传递给c页面,由于a页面与c页面同域,c页面可以直接修改a页面的hash值或者调用a页面中的全局函数

2、document.domain + iframe
只限于主域相同子域不同的资源跨域解决方案
3、window.name + iframe
window.name的独特之处在于在页面设置window.name的值,其实就是相当于给这个窗口设置了名称,而后在这个窗口加载其他页面(甚至不同域的页面),window.name的值依然存在,并且window.name的值支持比较大的存储(2MB)
4、window.postMessage
这是HTML5的新特性,用于页面之间跨域通信,接收两个必要的参数,一个是需要传的数据,一个是数据传递的目标窗口域名,值可以是具体的域名或者是通配符*
- 说说跨域请求头有哪些:
Access-Control-Allow-Origin:在预检请求与正常请求告知浏览器被允许的源,支持通配符但是不支持用逗号分隔的多源填写方式,也可以采用下面的方式进行添加:
1 | const origin = req.headers.origin |
Access-Control-Allow-Methods:被允许的HTTP方法,由于判断简单请求之一的HTTP方法默认为GET/POST/HEAD,所以这些方法即使不声明浏览器也是支持的。
Access-Control-Allow-Headers:在预检请求告知客户端允许的请求头,像 简单请求 约定的请求头默认支持: Accept 、 Accept-Language 、 Content-Language 、 Content-Type (text/plain、multipart/form-data、application/x-www-form-urlencoded)
Access-Control-Max-Age:定义预检请求告知客户端允许的请求头可以缓存多久,在这段时间内只需要发送一次预检请求即可。
- HTTP缓存:
有效减少网络请求的体积和数量
强缓存:在第一次请求返回的响应头中添加cache-control,设置max-age有效时间,这样当发送下一次请求时如果在有效期内则直接在缓存中获取资源。
协商缓存:服务器端缓存策略,在第一次发送请求的响HTTP应头中加入资源标识,如果第二次请求发现资源并没有修改过则返回304状态码直接从缓存中获取资源。如果资源已经修改则返回200状态码和最新的资源以及最新的资源标识。资源标识有last-modified和etag,last-modified对应需要在第二次请求的请求中添加if-modified-since;etag对应需要在第二次请求的请求中中添加if-none-match。
etag优先级更高,因为last-modified只能精确到秒,而且文件如果隔一段时间重复生成即使内容相同last-modified会每次返回资源文件,而etag可以判断内容相同则返回304从缓存中获取资源。
- JS如何清除缓存:
1、meta方法
1 | <meta http-equiv="pragma" content="no-cache"> |
2、清除form表单的临时缓存
1 | <body onLoad="javascript:document.yourFormName.reset()"></body> |
3、在请求头加上”If-Modified-Since”:”0”以及”Cache-Control”:”no-cache”
4、在url后面加上随机数或者随机事件来避免缓存,因为增加了一个随机参数后,每次请求都不一样,服务器会将其作为一个新的请求,重新返回结果,而不会使用缓存
1 | js文件,路径加上一个随机数 |
- GET 和 POST 的区别:
GET是通过URl传递参数,post是通过请求体传递参数
GET请求在url中是有长度限制的,而post没有
get比post不安全,因为参数是直接暴露在url中的,所以不能传递敏感信息
get是一个幂等的请求不会产生对服务器资源产生影响,post不是一个幂等的请求一般用以对服务器资源产生影响的情景,如注册用户
get请求参数会被完整地保留在浏览器的历史记录里,而post不会
- post请求与put请求的区别:
put请求是向服务器端发送数据,从而修改数据的内容,但是不会更新数据的种类,可以理解为更新数据
post请求是向服务器发送数据,该请求会改变数据的种类等资源,它会创建新的内容。
- 常见http请求头:
Accept:浏览器可处理的内容类型
Accept-Charset:浏览器能够显示的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Connection:浏览器与服务器之间连接的类型
Cookie:当前页面设置的任何Cookie
Host:发出请求页面所在的域
Referer:发出请求的页面的URL
User-Agent:浏览器的用户代理字符串
- 常见http响应头:
Date:发送消息的时间
server:服务器名称
Cache-Control:控制http缓存
content-type:表示后面的文档属于什么MIME类型
- 常见的conten-type有哪些:
1、text开头:
(1)text/html:HTML格式
(2)text/plain:纯文本格式
(3)text/xml:xml格式
2、图片格式:
(1)image/gif:图片格式
(2)image/jpeg:jpeg格式
(3)image/png:png格式
3、application开头
(1)application/xhtml+xml:XHTML格式
(2)application/xml:xml数据格式
(3)application/json:JSON数据格式
(4)application/pdf:pdf格式
(5)application/octet-stream:二进制格式
(6)application/x-www-form-urlencoded:表单发送默认格式
4、媒体文件
(1)audio/x-wav:wav文件
(2)audio/x-ms-wma:w文件
(3)audio/mp3:mp3文件
(4)video/x-ms-wmv:wmv文件
(5)video/mpeg4:mp4文件
(6)video/avi:avi文件
- http码是304多好还是不好?
304是协商缓存中服务器向客户端返回,允许客户端调用缓存内容的状态码,它不是一种错误。
但是当304状态码多了之后,搜索引擎蜘蛛可能会降低对网站的抓取次数,相反如果每次抓取都能获取新内容,回访率也会增加。
- options的主要用途:
获取服务器支持的所有http请求方法
用来检查访问权限,例如在进行CORS进行跨域资源共享时,对于复杂请求(除了GET/POST/HEAD之外的请求)就是使用options方法发送嗅探请求,以判断是否有对指定资源的访问权限
- HTTP/1.0及以前:
由于TCP连接的数据之间没有数据边界从而容易导致数据包粘连,无法处理,因此在HTTP/1.0及以前,采用了一种非常暴力的方式进行解决:
每进行一次HTTP通信就要先建立一条TCP连接,在通信结束后,就需要断开一次TCP连接,这非常浪费资源。
- http1.0与http1.1之间的区别:
1、新增多个响应状态码:100(在请求大量资源前的预热请求)、206(范围请求的标识码)、409(请求与当前资源的规定冲突)…
2、连接方面:1.0默认使用非持久连接,1.1默认使用持久长连接,支持多个http请求使用同一个tcp连接。在1.0中,提供了长连接选项,即在请求头中加入Connection:Keep-alive;同样在1.1中如果不希望使用长连接,也可以在请求头中加入Connection:close,这样会通知服务器不需要长连接,请求结束后即可关闭。
3、缓存方面:缓存技术通过避免用户与源服务器的频繁交互节约了大量的网络带宽,降低了用户接受信息的延迟。1.1则引入了Etag、if-Modified-Since、If-Match、If-None-Match等更多缓存头来控制缓存策略。
4、域名系统(DNS)允许多个主机名绑定到同一个IP地址中,但是1.0没有考虑到这个问题,假设我们有一个资源URL是http://example1.org/home.html,HTTP/1.0的请求报文中,将会请求的是`GET /home.html HTTP/1.0`.也就是不会加入主机名。这样的报文送到服务器端,服务器是理解不了客户端想请求的真正网址。1.1新增了host字用来指定服务器的域名,这样服务器就可以确定客户端想要请求的真正的网址。同时新增了许多请求方法,如PUT、HEAD等
5、带宽优化:1.1可以在请求中加入Range头部以请求数据的一部分,服务器端可以忽略Range头部,也可以返回若干Range响应,响应码是206。在范围响应中,Content-Range头部标志指示出了该数据块的偏移量与数据块的长度。
粘包问题:
HTTP/1.1是通过Content-Length这个请求头解决的,它标明了数据部分所占用的大小从而可以通过它来确定这个数据包的边界,避免粘包。
分块编码:
在某些动态的场景下,发送方是无法预知数据的大小的因此无法返回一个确切的Content-Length请求头信息,此时采用Transfer-Encoding:chunked这个请求头,允许服务端将数据分为多个部分。如果使用了分块编码,则请求及响应有以下特点:
1、在Headers中加入了Transfer-Encoding:chunked表示使用分块编码
2、在每个分块每一行都以/r/n结尾。第一行表示这个分块的数据长度,是一个十六进制的数,第二行则是这个分块的具体数据。
3、最后一个分块长度是0,且数据没有内容,表示这个数据的结束。
- HTTP/1.1的问题:
1、如果客户端想要发起并行的请求,则必须建立多个TCP连接,这对网络资源的消耗是十分严重的
2、不会对请求及响应的请求头进行压缩,造成了网络流量的浪费
3、不支持资源优先级导致TCP连接利用率低下
- 1.1与2.0的区别:
二进制分帧:流式连接中的一个虚拟信道,可以承载双向消息传输,每个流有唯一整数标识符,为了防止两端流ID冲突,客户端发起的流具有奇数ID。服务器发起的流具有偶数ID一个独立的双向的帧存在于客户端和服务器之间的http2连接中。一个http2连接上可以包含多个并发打开的流,这个并发的数量由客户端设置。在二进制分帧层上http2会将所有传输信息分割为更小的消息或帧,并对他们采用二进制格式的编码进行封装。
多路复用:多路复用允许同时通过一个单一的http2连接发起多重的请求-响应消息,有了新的分帧机制后,http2可以不再依赖多个TCP连接。每个数据流都拆分为很多互不依赖的帧,而这些帧可以交错,还可以分优先级发送,最后在另一端重新组合。
头部压缩:由于1.1协议不带状态,每次请求都必须附上全部信息,所以请求的很多字段都是重复的,这既浪费带宽也影响速度。http2使用encoder来减少需要传输的请求头大小,通讯双方各自缓存一份头部字段表,既避免了重复请求头的传输,也减小了需要传输的大小。对于相同的数据,不再需要每次请求和响应发送,通信期间几乎不会改变通用键值对。如果首部发生了变化则只需将变化的部分加入到请求头中,改变的部分会加入到头部字段表中。
请求优先级:把http消息分为很多独立帧之后可以通过优化这些帧的交错与传输顺序进一步优化性能,每个流可以带有优先值。服务器根据流的优先级控制资源分配,而在响应数据准备好之后优先将最高优先级的帧发送给客户端。一般html文件优先级最高,css文件次之,之后是js文件等资源。
服务端推送:服务器可以对一个客户端请求发送多个响应,服务器向客户端推送资源无需客户端明确的请求,服务器能把客户端需要的资源伴随着index.html一起发送给客户端。这种服务器推送的是基于客户端的请求响应确定的。
- 资源缓存:
1、Expires:
Expires是1.0所提供的对缓存的支持,通过这个请求头服务端可以告诉客户端缓存的过期时间,表示在过期时间内该资源都不会被更改,可以不用再向自己请求了。它记录了一个具体的时间,浏览器等客户端应用会根据本地的时间与该具体时间进行对比,那么如果我们对本地的时间进行了修改,则Expires的功能显然会受影响。
2、Cache-Control:
由于Expires存在上述的问题,因此在1.1中引入了Cache-Control机制,通过这个Headers可以在服务端与客户端之间沟通缓存信息。对于请求头,存在一种请求缓存指令,对于响应头,则存在一种响应缓存指令:
同时出现了max-age以及Expires会以max-age为准。
3、Last-Modified / If-Modified-Since:
这两个字段需要配合Cache-Control进行使用,Last-Modified 位于响应头,If-Modified-Since位于请求头,它们的含义分别是
Last-Modified :该响应资源最后的修改时间,服务器在响应请求的时候可以填入这个字段
If-Modified-Since:客户端缓存过期时间(max-age到达),发现该资源具有Last-Modified字段可以在请求头中填入If-Modified-Since字段并填入当前时间。服务端收到该时间后会与资源的最后修改时间进行比较。若修改则对这个资源响应,否则返回304告知客户端可以使用缓存的资源。
4、Etag / If-None-Match:
同样需要配合Cache-Control使用,Etag位于响应头,If-None-Match位于请求头,并且它们的优先级高于Last-Modified / If-Modified-Since。他们的含义分别是:
Etag :请求的资源在服务器中的唯一标识,规则由服务器决定,通过修改时间与文件大小生成。
If-None-Match:若客户端在缓存过期时(max-age到达),发现该资源具有Etag字段,就可以添加If-None-Match请求头,并传入Etag中的值,之后服务器就会根据这个唯一标识来寻找对应的资源,根据其更新与否情况返回给客户端200或304
- http协议与https协议的区别:
https协议需要ca证书,费用较高,而http协议不需要
http协议是超文本传输协议,信息是明文传输;https协议是具有安全性的ssl加密传输协议
使用不同的连接方式,端口也不同,http协议是80端口,https协议是443
http协议连接时无状态的,https协议是有ssl和http协议构建的可进行加密传输 、身份认证的网络协议,更加安全
- 对keep-alive的理解:
keep-alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后续请求时,可以避免建立或者重新建立连接,这就会长连接
1.0默认是没有keep-alive的要想连接得到保持需要手动配置connection:keep-allive字段,关闭则发送connection:close字段
1.1规定了默认保持长连接
- keep-alive的建立过程:
- 客户端向服务器在发送请求报文同时在首部添加connection字段
- 服务器收到请求并处理connection字段
- 服务器回送connection:keep-alive字段给客户端
- 客户端收到connection字段
- keep-alive建立成功
- 开启keep-alive的优点:
较少的CPU和内存的使用(由于同时打开的连接少了)
允许请求和应答的http管线化
降低拥塞控制(tcp连接少了)
减少了后续请求的延迟(无需再进行握手)
- 缺点:
长时间的连接容易导致系统资源无效占用,浪费系统资源
- http状态码:
2开头:请求成功处理(200:请求成功处理,一般用于get与post请求;201:已创建,成功请求并创建了新的资源;202:已接受,已经接受请求但是未处理成功;204:成功处理请求但是无内容返回)
3开头:重定向相关(301:永久性重定向,返回信息会包括新的url,浏览器会自动定向到新的url;302:暂时性重定向;304:协商缓存时返回的状态码,当允许从本地读取缓存时返回)
4开头:客户端错误(400:客户端请求的语法错误,服务器无法理解;401:请求要求用户的身份认证;403:服务端理解用户客户端请求但是拒绝执行;404:服务器无法根据客户端请求找到资源)
5开头:服务端错误(500:服务器不支持请求的功能,无法完成请求;505:服务器不支持此请求http版本,无法完成处理)
- 同样是重定向,307,302,303的区别:
302是http1.0的状态码,在http1.1版本中为了细化302状态码多出了303与307。303表示客户端应当采用get方法获取资源,它会把post请求变为get请求进行重定向;307表示遵照浏览器标准,不会从post变为get方法。
- JS数据为什么分别存在栈和堆:
在JS中栈是用来存储基本类型数据的,如boolean、number、string等,这些数据类型在栈内存中分别占有固定大小的空间,我们通过值来对数据进行访问,基本数据类型在当前执行环境结束时就会在栈中销毁;由于引用类型大小不固定所以不能保存在栈中,所以使用堆来对引用数据类型进行保存,而在栈中保存这些引用类型的地址,这样当查询引用数据类型的变量时就会先从栈中读取内存地址然后再去堆中找到相应的值。堆中的数据是不会对执行环境结束而销毁的,只有当所有引用它的变量不存在时这个对象才会被回收机制回收。
- 如何设置httponly:
在服务器返回响应头的cookie中添加http only属性为true
- 浏览器渲染过程:
1、解析HTML,构建DOM树。网络中传输的内容其实是字节数据,先将字节转换为字符串然后转换为token(标识起始标签与结束标签的作用),一边生成token一边消耗token来生成节点对象。
2、解析CSS,构建stylesheet
3、将DOM树与stylesheet合并为渲染树(render tree)
4、回流:根据生成的渲染树,进行回流,得到节点的几何信息(位置,大小)
5、重绘:根据渲染树以及回流得到的几何信息,得到节点的绝对像素
6、Display绘制:将像素发给GPU,最后调用操作系统Native GUI线程的API绘制,展示在页面上。这步其实还有很多内容,比如会将多个合成层合并为一个层,并展示在页面中。而css3硬件加速的原理则是新建合成层。
- 在浏览器输入baidu.com并且按下回车之后发生了什么:
1、解析url:首先对url进行解析,分析所需要的传输协议和请求的资源路径,如果输入的url中的协议或者主机名不合法将会把地址栏输入的内容传递给搜索引擎。如果没问题就会检查url中是否出现了非法字符,如果存在非法字符则对非法字符进行转义后再进行下一过程。
2、缓存判断:浏览器会判断所请求的资源是否在缓存里,如果在缓存里并且没有失效,就直接使用,否则向服务器发起新的请求。
3、DNS解析:下一步首先需要获取输入的url的域名的ip地址,首先会先判断浏览器是否有该域名的ip地址的缓存,如果有则使用,没有则继续所搜操作系统的DNS缓存,如果没有再向本地DNS服务器发起请求。本地的服务器会先检查是否存在缓存,没有就会向根域名服务器发起请求,获得负责的顶级域名服务器的地址后再向顶级域名服务器发起请求,然后获得负责的权威域名服务器地址后再向权威域名服务器发起请求最终获得域名的IP地址,本地DNS服务器再将这个ip地址返回给请求的用户。
4、获得MAC地址:当浏览器得到ip地址后,数据传输还需要知道目的主机MAC地址,因为应用层下发数据给传输层,TCP协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的ip地址作为目的地址然后下发给数据链路层,数据链路层的发送需要加入通信双方的MAC地址,本机的MAC作为源MAC地址,目的MAC地址需要分情况处理。通过将IP地址与本机的子网掩码相比较可以判断是否与请求主机在同一子网中,如果在同一子网中可以使用APR协议获取到目的主机的MAC地址,如果不在一个子网中那么请求应该转发给网关,由它代为转发,此时同样可以通过APR协议来获取网关的Mac地址,此时目的主机的MAC地址应该为网关的地址
5、TCP三次握手:首先客户端向服务器发送一个SYN连接请求报文段和一个随机序列号,服务器接收到请求后向客户端发送一个SYN ACK报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收到确认应答后进入连接建立状态,同时向服务器发送一个ACK确认报文段,服务器接收到确认后,也进入连接建立状态,此时双方连接就建立起来了
6、https握手:如果使用的是https协议,在通信前还存在一个TLS的四次握手过程。首先客户端向服务器发送使用协议的版本号、一个随机数和可以使用的加密方法。服务器接收到之后确认加密的方法,也向客户端发送一个随机数和自己的数字证书。客户端接收到之后首先检查数字证书是否有效,如果有效则再生成一个随机数并使用证书中的公钥对随机数加密,然后发送给服务器,并且还会提供一个前面所有内容的hash值给服务器进行检验。服务器接收后使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的hash值给客户端检验,这个时候双方都有了三个随机数,按照之前所约定的加密方法使用这三个随机数生成一把密钥以后双方通信前就使用这个密钥对数据进行加密后再传输
7、返回数据:当页面请求发送到服务器后,服务器会返回一个html文件作为响应,浏览器接收到响应后开始对文件进行解析,开始页面的渲染过程
8、页面渲染:浏览器首先会根据html文件构建DOM树,根据解析到的css文件构建 CSSOM树,如果遇到script标签则判断是否含有defer或者async属性,不然script标签的加载和执行会造成页面的渲染的阻塞。当DOM数和CSSOM树建立好之后根据他们来构建渲染树。渲染树构建好之后会根据渲染树进行布局。布局完成后最后使用浏览器的ui接口对页面进行绘制,这个时候页面就显示出来了。
9、TCP四次挥手:最后一步是TCP断开连接的四次挥手过程。若客户端认为数据发送完毕需要向服务器发送连接释放请求,服务器收到连接释放请求后会告诉应用层要释放TCP连接,然后发送ACK包,并进入CLOSE_WAIT状态,此时表明客户端到服务器的连接已经释放不再接受客户端发来的数据。因为TCP连接是双向的所以服务器仍旧可以发送数据给客户端。服务器如果此时还有没发完的数据会继续发送完毕后向客户端发送释放连接请求,然后服务器进入LAST-ACK状态,客户端收到释放请求后向服务器发送确认应答,此时客户端进入TIME-WAIT状态,该状态会持续2MSL(最大段生存期,指报文段在网络中生存的时间超时会被抛弃)时间。若时间段内没有服务器的重发请求的话就进入CLOSED状态,当服务器收到确认应答后也进入CLOSED状态。
- DNS的解析形式:
1、主机向本地域名服务器的查询一般采用递归查询
如果主机所询问的本地服务器不知道被查询的域名的IP地址,那么本地域名服务器就会以DNS客户的身份向其他根域名服务器继续发出查询请求报文,而不是让主机自己进行下一步查询。因此,递归查询返回的查询结果要么是所要查询的IP地址要么是报错,表示无法查到所需的IP地址。
2、本地域名服务器向根域名服务器的查询一般采用迭代查询
当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出要查询的IP地址,要么告诉服务器下一步该往哪个域名服务器进行查询。然后让本地服务器进行后续的查询,根域名服务器通常是把自己知道的顶级域名服务器的IP地址告诉本地域名服务器,让本地服务器再向顶级域名服务器查询。
顶级域名服务器在收到本地域名服务器的查询请求后,要么给出所查询的IP地址,要么告诉本地服务器应当向哪一个权威服务器进行查询。
最后知道了所要解析的IP地址或报错就把这个结果返回给发起查询的主机。
- 为什么DNS默认情况下使用UDP协议进行传输,什么情况下会用到TCP:
主要原因还是DNS解析并不是那么在意数据传输的可靠性而是需要以更快的速度获取到域名对应的IP地址,即使出现了丢包,只需要重新发起一个DNS请求就可以了。
用到TCP的情况:
1、UDP报文不足以承载对应的响应资源(UDP被限制了最大512字节)
2、进行DNS区域传输时(对DNS数据迁移),要保证可靠的数据交付
- 页面中有多张图片,http是怎样加载的:
在http1下,浏览器对一个域名下最大TCP连接数是6,可以使用多域名部署解决,这样可以提高同时请求的数目,加快页面图片的获取速度
在http2下,可以一瞬间加载出来很多资源因为http2支持多路复用,可以在一个TCP连接中发送多个http请求
- http2的头部压缩算法是怎样的:
http2的头部压缩算法是HPCK算法,在客户端与服务器两端建立字典,用索引表示重复的字符串,采用哈弗曼编码来压缩整数和字符串可以达到50%~90%的压缩率
具体来说:
在客户端与服务器使用首部表来跟踪和存储之前发送的键值对,对于相同的数据不再通过每次请求和响应发送
首部表在http2的连接存续期内始终存在,由客户端与服务器共同渐近的更新
每个新的首部键值要么被追加到当前表的末尾要么替换表中之前的值
- 说说QUIC协议:
QUIC是基于UDP实现的,HTTP3.0就是基于QUIC实现的。
为什么选择QUIC:
1、网络环境的不适应:TCP协议在网络流行的早期推出是因为当时的网络不像现在这么发达,丢包率高,所以需要一个协议来保证数据传输的可靠性。但是现在的网络环境相对来说非常可靠,更需要网络协议能带来更高的性能
2、TCP的更新成本更高:TCP协议中的一些对网络的优化其实并不是最优解,但是如果要修改TCP协议的代价很大,因为它的实现往往存在于操作系统的内核中,要对它进行修改依赖操作系统内核的更新。
QUIC相对于HTTPS:
1、减少了TCP三次握手以及TLS握手的时间,相对于HTTPS的3RRT握手,可以实现0RRT握手
2.引入QUIC连接以及Stream的概念,相对于HTTP2的多路复用进行了改进,每条stream对应一个请求,stream之间互不影响
3、对拥塞控制机制进行了改进,实现了TCP的拥塞控制算法并引入了更多的算法,同时由于位于应用层,修改、配置更加方便。
4、RRT计算更为精准,PackNumber单调递增解决了TCP重传导致的RRT计算的歧义性,并且RRT的计算考虑了ACK延迟机制。
5、通过connectionID唯一标识标示了一条QUIC连接,从而实现了两端的IP等信息变化仍能维持同一条QUIC连接
6、通过引入StreamOffset字段实现了一条Stream上的按序传输能力
7、引入了前向纠错机制,实现了纠错功能
- 说一下http3.0:
http2的多路复用在丢包场景下会出现队头堵塞问题。http3采用UDP作为传输层协议重新实现了无需连接,并在此基础上通过有序的QUIC Stream提供了多路复用。
http3是基于udp协议实现类似于tcp的多路复用数据流,传输可靠等功能,这套功能被称为QUIC协议
1、流量控制。传输可靠性功能:QUIC在UDP的基础上增加了一层来保证数据传输可靠性,它提供了数据包重传、拥塞控制以及其他tcp中的特性。
2、集成TCP加密功能:目前QUIC使用TLS1.3减少了握手所花费的RTT数
3、多路复用:同一物理连接上可以有多个独立的逻辑数据流,实现了数据流的单独传输,解决了TCP的队头堵塞问题
4、快速握手:由于基于UDP可以实现使用0~1个RRT来建立连接
- 队头堵塞:
http传输的报文必须是一发一收,但是里面的任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会堵塞后面的请求的处理,这就是队头堵塞
队头阻塞的解决方案:
1、并发连接:对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其他所有任务
2、域名分片:将域名分出很多二级域名,他们都指向同样的一台服务器,能够并发的长连接数量变多,解决了队头堵塞的问题
- TLS/SSL的工作原理:
TLS/SSL称为安全传输层协议,是介于TCP与HTTP之间的一层安全协议,不影响原有的TCP协议和HTTP协议所以使用HTTPS基本上不需要对HTTP页面进行太多的改造。
TLS/SSL的功能主要依赖三类基本算法:散列函数hash、对称加密和非对称加密,作用如下:
基于散列函数验证信息的完整性;对称加密算法采用协商的密钥对数据加密;非对称加密实现身份认证和密钥加密
散列函数:常见的散列函数有MD5、SHA1、SHA256,该函数的特点是单向不可逆,对输入数据非常敏感,输出的长度固定,任何数据的修改都会改变散列函数的结果,可以防止信息篡改并验证信息的完整性。
对称加密:对称加密的方法是双方使用同一个密钥对数据进行加密和解密,但是对称加密的一个问题就是如何保证密钥传输的安全性,因为密钥还是会通过网络传输,一旦密钥被其他人获取到,那么整个加密过程就毫无作用了,这就要用到非对称加密
非对称加密:我们拥有两个密钥一个是私钥一个是公钥,公钥是公开的,私钥是保密的,用私钥加密的数据只有对应的公钥才能解密,用公钥加密的数据只有对应的私钥才能解密。我们可以将公钥公布出去,任何想和我们通信的客户都可以使用我们提供的公钥对数据进行加密然后我们使用私钥进行解密,这样就能保证数据的安全了。掌握公钥的不同客户端之间不能相互解密信息,只能和服务器进行加密通信。但是有一个缺点就是加密的过程很慢。
TLS/SSL的工作方式就是客户端使用非对称加密与服务器进行通信,实现身份的验证并协商对称加密使用的密钥,对称加密算法采用协商密钥对信息以及信息摘要进行加密通信。
- 数字证书是什么:
因为没有办法确定得到的公钥就一定是安全的,可能存在一个中间人,截取了对方发给我们的公钥然后将它自己的公钥发送给我们,当我们使用它的公钥加密后发送的信息,就可以被他用自己的私钥解密。然后伪装成我们以同样的方法向对方发送信息这样我们的信息就被窃取了。为了解决这个问题可以使用数字证书。
首先使用一种hash算法对公钥和其他信息进行加密,生成一个消息摘要,然后让有公信力的认证中心(CA)用它的私钥对消息摘要进行加密形成签名,最后将原始信息与签名合成在一起,称之为数字证书。当接收方接收到证书时,先根据原始信息使用同样的hash算法生成一个摘要,然后使用公证处的公钥对数字证书中的摘要进行解密,最后将解密的摘要和生成的摘要进行对比,就能发现得到的信息是否被更改了。
一般浏览器会内置一些顶层的认证中心的证书,相当于我们自动信任了他们,只有这样才能保证数据的安全。
- https的通信过程(握手过程):
1、客户端向服务器发起请求,请求中包含使用的协议版本号,生成的一个随机数,以及客户端支持的加密方法
2、服务器接收到请求后,确认双方使用的加密方法,并给出服务器的证书,以及一个服务器生成的随机数
3、客户端确认服务器的证书有效后,生成一个新的随机数,并使用数字证书中的公钥加密这个随机数,然后发给服务器,并且还会提供一个前面所有内容的hash值,用来供服务器检验
4、服务器使用自己的私钥,来解密客户端发送过来的随机数,并提供前面所有内容的hash值来供客户端检验
5、客户端和服务器根据自己约定的加密方法使用前面三个随机数,生成对话密钥,以后的对话过程都使用这个密钥进行加密信息。
- DNS协议是什么:
DNS是域名系统,提供一种主机名到IP地址的转换服务,它是由一个分层的DNS服务器组成的 分布式数据库,定义了主机如何查询这个分布式数据库的方式的应用层协议。
作用:将域名解析为IP地址,客户端向DNS服务器发送域名查询请求,DNS服务器告知客户端服务器的IP地址。
- DNS同时使用TCP与UDP协议:
1、在区域传输的时候使用TCP协议:辅域名服务器会定时向主域名服务器查询以便了解数据是否有变动,如有变动会执行一次区域传送,进行数据同步。TCP是一种可靠连接,保证了数据的准确性。
2、在域名解析的时候使用UDP协议:客户端向DNS服务器查询域名,一般返回的内容不超过512字节,用UDP协议传送即可。因为不用经过三次握手所以响应DNS服务器负载更低,响应更快。
- DNS完整的查询过程:
1、首先会在浏览器缓存中查找对应的IP地址,找到则返回,否则进入下一步
2、将请求发送给本地DNS服务器,在本地域名服务器缓存中查询,找到则返回,否则进入下一步
3、本地DNS服务器向根域名服务器发送请求,根域名服务器会返回一个所查询域的顶级域名服务器地址
4、本地DNS服务器向顶级域名服务器发送请求,接收请求的服务器查询自己的缓存,如果有记录则返回查询结果,否则返回 相关的下一级的权威服务器的地址
5、本地DNS服务器向权威服务器发送请求,域名服务器返回对应的结果
6、本地DNS服务器将返回的结果保存在缓存中便于下次使用
7、本地DNS服务器将返回结果返回给浏览器、、
- DNS解析是包含递归查询与迭代查询的过程:
递归查询:查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果,使用递归查询用户只需要发出一次查询请求
迭代查询:查询请求后,域名服务器返回单次查询的结果,下一级查询由用户自己请求,使用迭代查询用户需要发起多次的查询请求
一般我们向本地DNS服务器发送请求的方式是递归查询,而本地服务器向其他域名服务器请求的过程是迭代请求的过程。
- URL有哪些组成部分:
协议部分、域名部分、端口部分、虚拟目录部分、文件名部分、参数部分(从?到#之间的部分都是参数部分,参数之间用&作为分隔符)、锚部分(从#开始到最后都是锚部分)。
- HTTPS的特点:
优点:
1、可以认证用户和服务器,确保数据发送到正确的客户端和服务器
2、可以进行加密传输、身份认证,通信更加安全,防止数据在传输过程中被窃取,修改,保证数据的安全性
3、不是绝对安全的但是大幅增加了中间人攻击的成本
缺点:
1、需要做服务器与客户端双方的加密解密处理,耗费更多的服务器资源,过程复杂
2、握手阶段比较费时,增加页面加载时间
3、SSL证书是收费的,功能越强大的证书费用越高
4、连接服务器资源占用高很多,支持访客稍多的网站需要投入更多的成本
5、需要绑定IP,不能在同一个IP绑定多个域名
- 说一说什么是大端、小端,如何判断大端和小端
1、字节序
字节顺序,又称端序或尾序(英语:Endianness)。在计算机科学计算机科学”)领域中,是跨越多字节的程序对象的存储规则。
在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如在C语言中,一个类型为int的变量x地址为0x100,那么其对应地址表达式&x的值为0x100。且x的四个字节将被存储在存储器的0x100, 0x101, 0x102, 0x103位置。
2、大小端
在计算机中一般讲字节序分为两类:Big-Endian(大端字节序) 和Little-Endian。
a) Little-Endian 高位字节在前,低位字节在后。
b) Big-Endian 低位字节在前,高位字节在后。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
- XSS攻击是什么?
XSS是跨站脚本攻击(Cross Site Scripting),攻击者可以通过向Web页面里面插入script代码,当用户浏览这个页面时,就会运行被插入的script代码,达到攻击者的目的。XSS的危害一般是泄露用户的登录信息cookie,攻击者可以通过cookie绕过登录步骤直接进入站点。XSS的分类分为反射型和存储型。反射型需要欺骗用户去点击才能触发XSS代码。存储型就是将恶意代码以留言的形式保存在服务器数据库,任何访问网站的人都会受到攻击。
一切用户可控并且能够输出在页面代码中的地方都可能出现XSS漏洞,比如评论区、留言区等。
预防:
1、输入
输入指客户端请求参数,具体包括用户输入,url参数,post参数。针对HTML代码的以下六个字符进行实体转义(&,>,<,”,’,/);除此之外,富文本的输入需要额外注意:
(1)首先例行进行输入检查,保证用户输入的是完整的HTML代码,而不是有拼接的代码
(2)通过htmlParser解析出HTML代码的标签、属性、事件
(3)富文本的事件需要被禁止,以及一些危险的标签需要禁止
(4)利用白名单机制,只允许安全的标签嵌入
(5)过滤用户CSS,检查是否有危险代码
2、输出
所有需要输出到HTML页面中的变量,全部需要使用编码或者转义来防御,包括在HTML/CSS/JS/URL中输出。
3、其他的CSS防御方式
(1)JSONP XSS防御方式:callback做长度限制、检测callback中的字符、过滤callback以及JSON数据输出
(2)HTTP-only Cookie:禁止页面的JS访问带有HttpOnly属性的Cookie
(3)添加验证码机制:防止脚本冒充用户提交危险的操作
- 说说CSRF:
CSRF是跨站请求伪造,可以在用户毫不知情的情况下以用户的名义伪造请求发送给攻击站点,从而在未授权的情况下进行权限保护内的操作,比如以用户的名义发送邮件,购买商品等。
预防:
同源检测:验证http Referer字段,http头中的字段Referer中记录了http请求的来源地址,可以通过对每一个请求验证其Referer值,如果是其他网站则拒绝请求;
随机数一致性检测:令牌同步模式:CSRF token:用户登录后生成随机的token值,用户提交的操作类请求中,提交的表单中携带CSRF token值,服务器判断CSRF token值是否正确。
- XSS攻击与CSRF攻击的区别:
CSRF不需要将恶意代码注入用户的页面,仅仅是利用服务器的漏洞和用户的登录状态来实施攻击;
CSRF攻击成本比XSS低。
- 说说SSRF :
很多web应用都提供了从其他的服务器上获取数据的功能。使用指定的URL,web应用便可以获取图片,下载文件,读取文件内容等。SSRF的实质是利用存在缺陷的web应用作为代理攻击远程和本地的服务器。一般情况下, SSRF攻击的目标是外网无法访问的内部系统,黑客可以利用SSRF漏洞获取内部系统的一些信息(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)。
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。
SSRF的主要攻击方式:攻击者想要访问主机B上的服务,但是由于存在或者主机B是属于内网主机等原因导致攻击者无法直接访问主机B。而服务器A存在SSRF,漏洞,这时攻击者可以借助服务器A来发起SSRF攻击,通过服务器A向主机B发起请求,从而获取主机B的一些信息。
- 合法的IPv4 或 IPv6 地址
1 | 1. 合法的IPv4: |
1 | 2. 合法的IPv6: |
- 说一说进程通信的方式有哪些?
进程间通信主要包括:管道、命名管道、信号、消息队列、共享内存、内存映射、信号量、Socket:
管道
管道也叫无名(匿名)管道,它是是 UNIX 系统 IPC(进程间通信)的最古老形式,所有的 UNIX 系统都支持这种通信机制。管道本质其实是内核中维护的一块内存缓冲区,Linux 系统中通过 pipe() 函数创建管道,会生成两个文件描述符,分别对应管道的读端和写端。无名管道只能用于具有亲缘关系的进程间的通信。
命名管道
匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道、FIFO文件。有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。
信号
信号是 Linux 进程间通信的最古老的方式之一,是事件发生时对进程的通知机制,有时也称之为软件中断,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。
消息队列
消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级,对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程则可以从消息队列中读走消息,消息队列是随内核持续的。
共享内存
共享内存允许两个或者多个进程共享物理内存的同一块区域(通常被称为段)。由于一个共享内存段会称为一个进程用户空间的一部分,因此这种 IPC 机制无需内核介入。所有需要做的就是让一个进程将数据复制进共享内存中,并且这部分数据会对其他所有共享同一个段的进程可用。与管道等要求发送进程将数据从用户空间的缓冲区复制进内核内存和接收进程将数据从内核内存复制进用户空间的缓冲区的做法相比,这种 IPC 技术的速度更快。
内存映射
内存映射(Memory-mapped I/O)是将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件。
信号量
信号量主要用来解决进程和线程间并发执行时的同步问题,进程同步是并发进程为了完成共同任务采用某个条件来协调它们的活动。对信号量的操作分为 P 操作和 V 操作,P 操作是将信号量的值减 1,V 操作是将信号量的值加 1。当信号量的值小于等于 0 之后,再进行 P 操作时,当前进程或线程会被阻塞,直到另一个进程或线程执行了 V 操作将信号量的值增加到大于 0 之时。
Socket
套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。Socket 一般用于网络中不同主机上的进程之间的通信。
- UDP(用户数据报协议)是什么?
UDP是OSI参考模型中的传输层协议,是一种面向无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
UDP协议有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说UDP协议不能得知报文是否安全完成到达,由于UDP协议只负责将应用程序给IP层的数据报发送出去,不用在客户端与服务器之间建立连接且没有超时重发等机制,所以UDP协议的传输速度很快。
绝大部分UDP应用都不需要可靠机制,甚至可能因为引入可靠机制降低性能,比如流媒体、即时多媒体游戏等应用。如果一个应用需要很高的可靠性可以选择TCP协议。
- 进程与线程
进程是操作系统资源分配的基本单位;线程是进程的一个执行单元,是处理器任务调度和执行的基本单位。
线程共享本进程的地址空间和资源,但进程之间是独立的地址空间;
在一个进程中一个线程奔溃会导致整个进程都死掉,但是多进程中一个进程奔溃不会影响其他进程;
每个独立的进程有程序运行的入口、执行顺序和程序出口;但线程是依存在应用程序中的,由应用程序提供多个线程执行控制,两者均可并发执行。
- 线程切换为什么比进程切换容易?
操作系统需要保存进程运行所需要的所有状态信息,也就是进程的上下文。在任何时刻,单处理器系统只能执行一个进程,所以当操作系统将控制权从一个进程切换到另一个进程时,需要保存原先进程的上下文,并恢复新进程的上下文,然后将控制权传递给新进程。
但是对线程而言,进程内的所有线程共享进程的虚拟地址空间,在线程进行切换时不会涉及虚拟地址空间的切换。
- 计算机的原码、反码、补码
原码就是符号位加上真值的绝对值
反码的话,正数的反码是它本身,负数的反码就是符号位不变,其余各个位取反
补码的话,正数的补码是它本身,负数的补码就是符号位不变,其余各个位取反,最后+1
- 请描述一下cookies,sessionStorage和localStorage的区别:
sessionStorage 和 localStorage 是HTML5 Web Storage API 提供的,可以方便的在web请求之间保存数据。有了本地数据,就可以避免数据在浏览器和服务器间不必要地来回传递。
sessionStorage、localStorage、cookie都是在浏览器端存储的数据,sessionStorage 是在同源的同窗口(或tab)中,始终存在的数据。也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在。关闭窗口后,sessionStorage 即被销毁。同时“独立”打开的不同窗口,即使是同一页面,sessionStorage 对象也是不同的。
由于webstorage容易受到xss攻击,所以不建议在其中保存比较敏感的信息,避免xss攻击可能通过提前对保存进webstorage中的数据进行加密,以及在读取数据后对数据进行编码、转义。
cookies会发送到服务器端。其余两个不会。
Cookie
- 每个域名存储量比较小(各浏览器不同,大致4K)
- 所有域名的存储量有限制(各浏览器不同,大致4K)
- 有个数限制(各浏览器不同)
- 会随请求发送到服务器
LocalStorage
- 永久存储
- Localstorage可以跨窗口与选项卡共享
- 单个域名存储量比较大(推荐5MB,各浏览器不同)
- 总体数量无限制
SessionStorage
- 只在 Session 内有效
- Sessionstorage可以跨窗口与选项卡共享
- 存储量更大(推荐没有限制,但是实际上各浏览器也不同)
如果要保存的cookie数据大于4k,又不想保存在webstorage中怎么办:
可以对cookie数据进行压缩,将cookie中多个键值对看成文本,用文本压缩的方式进行压缩,可以使用gzip或者deflate算法,由于cookie中key,value必须是ascii字符,不能是Unicode字符,所以需要将压缩后的数据进行base64或者base32编码。
- 如何在浏览器中存储大量数据:
使用indexDB,它是浏览器提供的本地数据库(非关系型),允许存储大量数据,提供查询接口还能创建索引。
1、键值对存储:indexDB内部采用对象仓库存放数据,所有类型的数据都可以直接存入,主键不能有重复,否则会抛出错误。
2、异步:indexDB操作时不会锁死浏览器,这是为了防止大量数据的读写拖慢网页的表现。
3、支持事务。indexDB支持事务,这意味着一系列事务中有一步失败整个事务就会取消。
4、同源限制:每一个数据库对应创建它的域名,网页只能访问自身域下的数据库不能访问跨域的数据库。
5、存储空间:一般来说大于250mb甚至没有上限。
6、支持二进制储存
或者是使用webSQL(内嵌在浏览器的关系型数据库)
- 并发与并行的区别:
并发:分别有任务A与B,在一段时间内通过任务间的切换完成了这两个任务,这种情况称为并发
并行:假设CPU存在两个核心,那么可以同时完成任务A、B,同时完成多个任务的情况就是并行。
- 说说TCP粘包,如何处理:
TCP粘包就是指发送方的若干数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因如下:
(1)发送方原因:
TCP默认使用Nagle算法减少网络中报文段的数量,在数据发送之前缓存他们. 如果短时间有多个数据发送, 会缓冲到⼀起作⼀次发送
(2)接收方原因:
TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层不会立即处理,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组,这样一来如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个收尾相黏连在一起的包
1、什么时候需要处理粘包的现象:
(1)如果发送方发送的多组数据本来就是同一块数据下的不同部分,不需要处理
(2)如果多个分组毫不相干,甚至是并列关系,那么这时候就要处理
2、处理方法:
(1)多次发送之前间隔一个等待时间
(2)关闭Nagle算法
(3)进行封包
- 为什么UDP不会粘包:
TCP是面向流的协议,UDP是面向消息的协议,UDO端都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据
UDP具有保护消息边界,在每个UDP包中就有消息头,这样对于接收端来说就容易进行区分处理,传输协议把一条独立的消息在网上传输,接收端只能接收到独立的消息,接收端一次只能接受发送端发出的一个数据包,如果一次接受数据的大小小于发送端一次发送的数据大小就会丢失一部分数据,即使丢失接收端也不会分两次去接受
- 说说websoket是怎么连接的以及为什么它为什么以HTTP为桥梁:
websoket通信的双方在TCP三次握手之后还需要额外进行一次握手,该握手始于一个HTTP请求,通过HTTP协议传送Websoket支持的协议号,协议的字版本号,原始地址、主机地址等一系列字段给服务器。
1 | GET /chat HTTP/1.1 |
该处的upgrade首部是用来将当前的HTTP请求升级到websoket协议,这是HTTP为了扩展支持其他的通讯协议,如果服务器支持新的协议,则返回101.
之所以基于HTTP是因为Websoket设计上本来就是为HTTP增强通信,所以在HTTP协议基础上连接是很自然的一件事,也可以因此获取HTTP的诸多便利。第二,基于HTTP连接将获得最大的一个兼容支持,比如即使服务器不支持Websoket也能建立HTTP通信,只不过返回的是error,这比服务器无响应好很多。
- websoket的安全问题:
实际上,几乎所有的Web漏洞都有可能出现在WebSocket中。因为,WebSocket本质上就是一个通过HTTP建立连接的双向全双工的通信协议而已,但由于其相比HTTP多了一“工”的特性,可能会出现一些新的攻击场景。
常见的攻击场景如下:
- 用户的输入被服务器以不安全的方式进行处理,导致了例如SQL注入、XXE等注入攻击。
- 一些盲注漏洞可能会通过WebSocket引起,可以利用带外技术 (opens new window)进行探测。
- 如果攻击者控制的数据通过WebSocket传输到了其它用户的客户端处,这可能会引起XSS或者其它客户端类型的漏洞。
如何预防WebSocket的安全问题:
- 将通过 WebSocket 接收的数据在两个方向都视为不可信的。在服务器端和客户端安全地处理数据,以防止基于输入的漏洞,如 SQL 注入和跨网站脚本。
- 使用CSRF Token、请求头令牌等方案保护WebSocket握手流程,防止WebSocket握手流程被CSRF攻击所利用。
- 使用
wss://协议,(基于TLS的Websockets) - 硬编码WebSockets的URL接口,以保证用户的输入无法篡改此URL。
- 说说主流的服务器推送技术有哪些:
1、短连接轮询
前端用定时器,每间隔一段时间发送请求来获取数据是否更新,这种方式兼容ie与高级浏览器。
2、长轮询
客户端像传统轮询一样从服务器请求数据,服务器端会阻塞请求不会立刻返回,直到有数据或超时才返回给客户端,然后关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
3、iframe流
在页面中插入一个隐藏的iframe,利用其src属性在服务器与客户端之间创建一条长连接,服务器向iframe传输数据,来实时更新页面
前端实现步骤:
(1)Iframe设置为不显示。
(2)src设为请求的数据地址。
(3)定义个父级函数用户让iframe子页面调用传数据给父页面。
(4)定义onload事件,服务器timeout后再次重新加载iframe。
后端输出内容:
当有新消息时服务端会向iframe中输入一段js代码.:println("<script>父级函数('" + 数据 +"<br>')</script>”);用于调用父级函数传数据。
4、websocket
5、SSE长连接
sse与长轮询类似,但是区别是每个连接不止发送一个消息,客户端发送一个请求,服务端保持这个连接直到有新消息发送给客户端,仍然保持着连接,这样连接就可以支持消息的再次发送,由服务器单向发送给客户端。

- 说说CDN:
CDN指的是一组分布在各个地区的服务器。这些服务器存储着数据的副本,因此服务器可以根据哪些服务器与用户距离更近,来满足数据的请求,提高请求的响应速度。
CDN的两个核心功能分别是缓存与回源:
1、缓存:把资源推送备份到CDN服务器上的过程
2、回源:发现CDN上的资源已经过期,向根服务器或上层服务器请求资源的过程。一般是源站内容有更新的时候源站主动把内容推送到CDN节点,CDN不会主动向源站拿。
静态资源本身具有访问频率高、承接流量大的特点,因此静态资源加载速度始终是前端性能的一个非常关键的指标。CDN 是静态资源提速的重要手段。
- 如何实现定时器同步执行:
可以通过promise的链式调用来实现,在promise中创建一个定时器,将改变promise状态的resolve函数或者是reject函数放在定时器的回调函数中,这样就可以实现先执行前面的定时器,然后再在then回调函数中开启下一个定时器。
1 | async function delayFn(delay) { |
- no-cache与no-store的区别:
no-store表示永远不在客户端存储资源,每一次都去跟服务器去获取资源
no-cache表示协商缓存,可以在客户端存储资源,但是每一次需要去询问服务器当前存储资源是否在有效期内。