网络通信
HTTP状态码及其含义?
答: 1XX :信息状态码 100 Continue 继续,⼀般在发送 post 请求时,已发送了 http header 之后服务端 将返回此信息,表示确认,之后发送具体参数信息
2XX :成功状态码 200 OK 正常返回信息 201 Created
请求成功并且服务器创建了新的资源 202 Accepted 服务器已接受请求,但尚未处理
3XX :重定向 301 Moved
Permanently 请求的⽹⻚已永久移动到新位置。 302 Found 临时性重定向。 303 See Other 临时性重定向,且总是使⽤ GET 请求新的 URI 。 304 Not Modified ⾃从上次请求后,请求的⽹⻚未修改过。
4XX
:客户端错误 400 Bad Request 服务器⽆法理解请求的格式,客户端不应当尝试再次使⽤相同的内 容发起请求。 401 Unauthorized 请求未授权。 403 Forbidden 禁⽌访问。 404 Not Found 找不到如何与 URI 相匹配的资源。
5XX: 服务器错误 500 Internal Server Error 最常⻅的服务器端错误。 503 Service
Unavailable 服务器端暂时⽆法处理请求(可能是过载或维护)。
HTTP的⼏种请求⽅法⽤途?
答: GET ⽅法 发送⼀个请求来取得服务器上的某⼀资源 POST ⽅法 向 URL 指定的资源提交数据或附加新的数据 PUT ⽅法 跟
POST ⽅法很像,也是想服务器提交数据。但是,它们之间有不同。 PUT 指定了资源在服务器上的位置,⽽ POST 没有 HEAD ⽅法
只请求⻚⾯的⾸部 DELETE ⽅法 删除服务器上的某资源 OPTIONS ⽅法 它⽤于获取当前 URL
所⽀持的⽅法。如果请求成功,会有⼀个 Allow 的头包含类似 “GET,POST” 这样的信息 TRACE ⽅法 TRACE
⽅法被⽤于激发⼀个远程的,应⽤层的请求消息回路 CONNECT ⽅法 把请求连接转换到透明的 TCP/IP 通道
谈一下 WebSocket?
答:由于 http 存在⼀个明显的弊端(消息只能有客户端推送到服务器端,⽽服
务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只 能使⽤轮询,⽽轮询效率过低,并不适合。于是 WebSocket
被发明出来 相⽐与 http 具有以下有点 ⽀持双向通信,实时性更强; 可以发送⽂本,也可以⼆进制⽂件; 协议标识符是 ws ,加密后是
wss ; 较少的控制开销。连接创建后, ws
客户端、服务端进⾏数据交换时,协议控制的数据包头部较⼩。在不包含头部的情况下,服务端到客户端的包头只有 2~10
字节(取决于数据包⻓度),客户端到服务端的的话,需要加上额外的4字节的掩码。⽽ HTTP 协议每次通信都需要携带完整的头部;
⽀持扩展。ws协议定义了扩展,⽤户可以扩展协议,或者实现⾃定义的⼦协议。(⽐如⽀ 持⾃定义压缩算法等) ⽆跨域问题。
实现⽐较简单,服务端库如 socket.io 、 ws ,可以很好的帮助我们⼊⻔。 ⽽客户端也只需要参照 api 实现即可
ajax、axios、fetch区别?
答:jQuery ajax $.ajax({ type: ‘POST’, url: url, data: data, dataType:
dataType, success: function () {}, error: function () {} }); 优缺点:
本身是针对 MVC 的编程,不符合现在前端 MVVM 的浪潮 基于原⽣的 XHR 开发, XHR 本身的架构不清晰,已经有了 fetch
的替代⽅案 JQuery 整个项⽬太⼤,单纯使⽤ ajax 却要引⼊整个 JQuery
⾮常的不合理(采取个性化打包的⽅案⼜不能享受CDN服务 axios axios({ method: ‘post’, url:
‘/user/12345’, data: { firstName: ‘Fred’, lastName: ‘Flintstone’ } })
.then(function (response) { console.log(response); }) .catch(function
(error) { console.log(error); }); 优缺点: 从浏览器中创建 XMLHttpRequest 从
node.js 发出 http 请求 ⽀持 Promise API 拦截请求和响应 转换请求和响应数据 取消请求 ⾃动转换 JSON 数据
客户端⽀持防⽌ CSRF/XSRF fetch try { let response = await fetch(url); let
data = response.json(); console.log(data); } catch(e) {
console.log(“Oops, error”, e); } 优缺点: fetcht 只对⽹络请求报错,对 400 , 500
都当做成功的请求,需要封装去处理 fetch 默认不会带 cookie ,需要添加配置项 fetch 不⽀持 abort
,不⽀持超时控制,使⽤ setTimeout 及 Promise.reject
的实现的超时控制并不能阻⽌请求过程继续在后台运⾏,造成了量的浪费 fetch 没有办法原⽣监测请求的进度,⽽XHR可以
Ajax读取一个xml文档并进行解析的实例?
答案: var xhr = new XMLHttpRequest;//->在IE7以下浏览器中是不兼容的 xhr=new
ActiveXObject(“Microsoft.XMLHTTP”); xhr=new
ActiveXObject(“Msxml2.XMLHTTP”); xhr=new
ActiveXObject(“Msxml3.XMLHTTP”); //->惰性思想 var getXHR = (function () {
//->存放我们需要的几个获取Ajax对象的方法 var ajaxAry = [
function () {
return new XMLHttpRequest;
},
function () {
return new ActiveXObject(“Microsoft.XMLHTTP”);
},
function () {
return new ActiveXObject(“Msxml2.XMLHTTP”);
},
function () {
return new ActiveXObject(“Msxml3.XMLHTTP”);
} ]; //->循环数组,把四个方法依次的执行 var xhr = null; for (var i = 0; i < ajaxAry.length; i++) {
//->标准浏览器:i=0,获取的是第一个函数function(){return new XMLHttpRequest;}(A1),执行的时候没有报错,xhr是它的返回值也是我们的Ajax对象,没有报错不会走catch,执行getXHR
= A1,这样把外面的getXHR重写了,遇到break循环结束
//->IE6浏览器:i=0,获取第一个函数执行,IE6不支持XMLHttpRequest,所以会报错,执行catch中的continue继续下一次的循环,i=1,获取第二个函数
function(){return new
ActiveXObject(“Microsoft.XMLHTTP”);}(A2),执行没有报错,那么开始执行getXHR =
A2,遇到break结束整个循环,此时外面的getXHR = A2
var tempFn = ajaxAry[i];
try {
xhr = tempFn();
} catch (e) {
continue;
}
getXHR = tempFn;
break; } if (!xhr) {
throw new Error(“你的浏览器版本也太LOW了吧,还能不能愉快的玩耍~~”); } return getXHR; })(); var xhr = getXHR(); xhr.open(“get”, “test.txt?_=” +
Math.random(), true); xhr.onreadystatechange = function () { if
(xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
var val = xhr.responseText;
console.log(val); } }; xhr.send(null); 避免返回的数据是乱码的
->前端页面是UTF-8编码,如果我们从服务器请求回来的数据不是UTF-8编码格式,那么获取到的内容中,中文汉字会出现乱码
->需要我们使用”UTF-8到底的原则”:前端页面、JS、CSS、后台代码、数据库、请求传递的数据统一都采用一个编码UTF-8
->[RESPONSE] Content-Type:text/plain(纯文本)、application/json(JSON格式的)…设定响应主体中内容的格式
前端:设置请求头,获取响应头
->在前端的JS中我们可以使用 xhr.setRequestHeader([name],[value]) 设置请求头的信息; 可以使用 xhr.getResponseHeader([name])/xhr.getAllResponseHeaders() 获取响应头信息;
服务器端:获取请求头,设置响应头
->在NODE中我们可以使用 response.writeHead(200, {‘content-type’: ‘application/json’}); 设置响应头信息
->在NODE中我们可以使用 request 这个对象获取到请求信息(起始行、首部、主体) 中的都可以获取到
多路复用与多路分解?
答:将传输层报文段中的数据交付到正确的套接字的工作被称为多路分解。
在源主机上从不同的套接字中收集数据,封装头信息生成报文段后,将报文段传递到网络层,这个过程被称为多路复用。 无连接的多路复用和多路分解指的是
UDP 套接字的分配过程,一个 UDP 套接字由一个二元组来标识,这个二元组包含了一 个目的地址和一个目的端口号。因此不同源地址和端口号的
UDP 报文段到达主机后,如果它们拥有相同的目的地址和目的端 口号,那么不同的报文段将会转交到同一个 UDP 套接字中。
面向连接的多路复用和多路分解指的是 TCP 套接字的分配过程,一个 TCP 套接字由一个四元组来标识,这个四元组包含了 源 IP
地址、源端口号、目的地址和目的端口号。因此,一个 TCP 报文段从网络中到达一台主机上时,该主机使用全部 4 个
值来将报文段定向到相应的套接字
。
UDP 协议?
答:UDP 是一种无连接的,不可靠的传输层协议。它只提供了传输层需要实现的最低限度的功能,除了复用/分解功能和少量的差
错检测外,它几乎没有对 IP 增加其他的东西。UDP 协议适用于对实时性要求高的应用场景。 特点: 使用 UDP
时,在发送报文段之前,通信双方没有握手的过程,因此 UDP 被称为是无连接的传输层协议。因为没有握手 过程,相对于 TCP
来说,没有建立连接的时延。因为没有连接,所以不需要在端系统中保存连接的状态。 UDP 提供尽力而为的交付服务,也就是说 UDP
协议不保证数据的可靠交付。 UDP 没有拥塞控制和流量控制的机制,所以 UDP 报文段的发送速率没有限制。 因为一个 UDP
套接字只使用目的地址和目的端口来标识,所以 UDP 可以支持一对一、一对多、多对一和多对多的交互 通信。 UDP 首部小,只有 8 个字节。
UDP 报文段结构 UDP 报文段由首部和应用数据组成。报文段首部包含四个字段,分别是源端口号、目的端口号、长度和检验和,每个字段的长
度为两个字节。长度字段指的是整个报文段的长度,包含了首部和应用数据的大小。校验和是 UDP 提供的一种差错校验机制。
虽然提供了差错校验的机制,但是 UDP 对于差错的恢复无能为力。
TCP 协议?
答:TCP 协议是面向连接的,提供可靠数据传输服务的传输层协议。 特点: TCP
协议是面向连接的,在通信双方进行通信前,需要通过三次握手建立连接。它需要在端系统中维护双方连接的状态信息。 TCP
协议通过序号、确认号、定时重传、检验和等机制,来提供可靠的数据传输服务。 TCP
协议提供的是点对点的服务,即它是在单个发送方和单个接收方之间的连接。 TCP
协议提供的是全双工的服务,也就是说连接的双方的能够向对方发送和接收数据。 TCP
提供了拥塞控制机制,在网络拥塞的时候会控制发送数据的速率,有助于减少数据包的丢失和减轻网络中的拥塞程度。 TCP
提供了流量控制机制,保证了通信双方的发送和接收速率相同。如果接收方可接收的缓存很小时,发送方会降低发送
速率,避免因为缓存填满而造成的数据包的丢失。 TCP 报文段结构 TCP 报文段由首部和数据组成,它的首部一般为 20 个字节。
源端口和目的端口号用于报文段的多路复用和分解。 32 比特的序号和 32 比特的确认号,用与实现可靠数据运输服务。 16
比特的接收窗口字段用于实现流量控制,该字段表示接收方愿意接收的字节的数量。 4 比特的首部长度字段,该字段指示了以 32 比特的字为单位的
TCP 首部的长度。 6 比特的标志字段,ACK 字段用于指示确认序号的值是有效的,RST、SYN 和 FIN 比特用于连接建立和拆除。设置
PSH 字 段指示接收方应该立即将数据交给上层,URG 字段用来指示报文段里存在紧急的数据。 校验和提供了对数据的差错检测。TCP 三次握手的过程 第一次握手,客户端向服务器发送一个 SYN 连接请求报文段,报文段的首部中 SYN 标志位置为
1,序号字段是一个任选的 随机数。它代表的是客户端数据的初始序号。 第二次握手,服务器端接收到客户端发送的 SYN
连接请求报文段后,服务器首先会为该连接分配 TCP 缓存和变量,然后向 客户端发送 SYN ACK 报文段,报文段的首部中 SYN 和
ACK 标志位都被置为 1,代表这是一个对 SYN 连接请求的确认,
同时序号字段是服务器端产生的一个任选的随机数,它代表的是服务器端数据的初始序号。确认号字段为客户端发送的序号加 一。
第三次握手,客户端接收到服务器的肯定应答后,它也会为这次 TCP 连接分配缓存和变量,同时向服务器端发送一个对服务
器端的报文段的确认。第三次握手可以在报文段中携带数据。 在我看来,TCP
三次握手的建立连接的过程就是相互确认初始序号的过程,告诉对方,什么样序号的报文段能够被正确接收。
第三次握手的作用是客户端对服务器端的初始序号的确认。如果只使用两次握手,那么服务器就没有办法知道自己的序号是否
已被确认。同时这样也是为了防止失效的请求报文段被服务器接收,而出现错误的情况。 TCP 四次挥手的过程 因为 TCP
连接是全双工的,也就是说通信的双方都可以向对方发送和接收消息,所以断开连接需要双方的确认。
第一次挥手,客户端认为没有数据要再发送给服务器端,它就向服务器发送一个 FIN 报文段,申请断开客户端到服务器端的 连接。发送后客户端进入
FIN_WAIT_1 状态。 第二次挥手,服务器端接收到客户端释放连接的请求后,向客户端发送一个确认报文段,表示已经接收到了客户端释放连接的
请求,以后不再接收客户端发送过来的数据。但是因为连接是全双工的,所以此时,服务器端还可以向客户端发送数据。服务 器端进入
CLOSE_WAIT 状态。客户端收到确认后,进入 FIN_WAIT_2 状态。 第三次挥手,服务器端发送完所有数据后,向客户端发送 FIN
报文段,申请断开服务器端到客户端的连接。发送后进入 LAS T_ACK 状态。 第四次挥手,客户端接收到 FIN
请求后,向服务器端发送一个确认应答,并进入 TIME_WAIT 阶段。该阶段会持续一段时间,
这个时间为报文段在网络中的最大生存时间,如果该时间内服务端没有重发请求的话,客户端进入 CLOSED 的状态。如果收到
服务器的重发请求就重新发送确认报文段。服务器端收到客户端的确认报文段后就进入 CLOSED 状态,这样全双工的连接就被 释放了。 TCP
使用四次挥手的原因是因为 TCP 的连接是全双工的,所以需要双方分别释放到对方的连接,单独一方的连接释放,只代
表不能再向对方发送数据,连接处于的是半释放的状态。
最后一次挥手中,客户端会等待一段时间再关闭的原因,是为了防止发送给服务器的确认报文段丢失或者出错,从而导致服务器 端不能正常关闭。
状态转化图ARQ 协议 ARQ 协议指的是自动重传请求,它通过超时和重传来保证数据的可靠交付,它是 TCP 协议实现可靠数据传输的一个很重要的 机制。
它分为停止等待 ARQ 协议和连续 ARQ 协议。 一、停止等待 ARQ 协议 停止等待 ARQ
协议的基本原理是,对于发送方来说发送方每发送一个分组,就为这个分组设置一个定时器。当发送分组的确认
回答返回了,则清除定时器,发送下一个分组。如果在规定的时间内没有收到已发送分组的肯定回答,则重新发送上一个分组。
对于接受方来说,每次接受到一个分组,就返回对这个分组的肯定应答,当收到冗余的分组时,就直接丢弃,并返回一个对冗余
分组的确认。当收到分组损坏的情况的时候,直接丢弃。 使用停止等待 ARQ
协议的缺点是每次发送分组必须等到分组确认后才能发送下一个分组,这样会造成信道的利用率过低。 二、连续 ARQ 协议 连续 ARQ
协议是为了解决停止等待 ARQ 协议对于信道的利用率过低的问题。它通过连续发送一组分组,然后再等待对分组的
确认回答,对于如何处理分组中可能出现的差错恢复情况,一般可以使用滑动窗口协议和选择重传协议来实现。 滑动窗口协议
使用滑动窗口协议,在发送方维持了一个发送窗口,发送窗口以前的分组是已经发送并确认了的分组,发送窗口中包含了已经发
送但未确认的分组和允许发送但还未发送的分组,发送窗口以后的分组是缓存中还不允许发送的分组。当发送方向接收方发送分
组时,会依次发送窗口内的所有分组,并且设置一个定时器,这个定时器可以理解为是最早发送但未收到确认的分组。如果在定
时器的时间内收到某一个分组的确认回答,则滑动窗口,将窗口的首部移动到确认分组的后一个位置,此时如果还有已发送但没
有确认的分组,则重新设置定时器,如果没有了则关闭定时器。如果定时器超时,则重新发送所有已经发送但还未收到确认的分 组。
接收方使用的是累计确认的机制,对于所有按序到达的分组,接收方返回一个分组的肯定回答。如果收到了一个乱序的分组,那
么接方会直接丢弃,并返回一个最近的按序到达的分组的肯定回答。使用累计确认保证了确认号以前的分组都已经按序到达了,
所以发送窗口可以移动到已确认分组的后面。
滑动窗口协议的缺点是因为使用了累计确认的机制,如果出现了只是窗口中的第一个分组丢失,而后面的分组都按序到达的情况
的话,那么滑动窗口协议会重新发送所有的分组,这样就造成了大量不必要分组的丢弃和重传。 选择重传协议
因为滑动窗口使用累计确认的方式,所以会造成很多不必要分组的重传。使用选择重传协议可以解决这个问题。
选择重传协议在发送方维护了一个发送窗口。发送窗口的以前是已经发送并确认的分组,窗口内包含了已发送但未被确认的分组,
已确认的乱序分组,和允许发送但还未发送的分组,发送窗口以后的是缓存中还不允许发送的分组。选择重传协议与滑动窗口协
议最大的不同是,发送方发送分组时,为一个分组都创建了一个定时器。当发送方接受到一个分组的确认应答后,取消该分组的
定时器,并判断接受该分组后,是否存在由窗口首部为首的连续的确认分组,如果有则向后移动窗口的位置,如果没有则将该分
组标识为已接收的乱序分组。当某一个分组定时器到时后,则重新传递这个分组。
在接收方,它会确认每一个正确接收的分组,不管这个分组是按序的还是乱序的,乱序的分组将被缓存下来,直到所有的乱序分
组都到达形成一个有序序列后,再将这一段分组交付给上层。对于不能被正确接收的分组,接收方直接忽略该分组。 TCP 的可靠运输机制 TCP
的可靠运输机制是基于连续 ARQ 协议和滑动窗口协议的。 TCP
协议在发送方维持了一个发送窗口,发送窗口以前的报文段是已经发送并确认了的报文段,发送窗口中包含了已经发送但
未确认的报文段和允许发送但还未发送的报文段,发送窗口以后的报文段是缓存中还不允许发送的报文段。当发送方向接收方发
送报文时,会依次发送窗口内的所有报文段,并且设置一个定时器,这个定时器可以理解为是最早发送但未收到确认的报文段。
如果在定时器的时间内收到某一个报文段的确认回答,则滑动窗口,将窗口的首部向后滑动到确认报文段的后一个位置,此时如
果还有已发送但没有确认的报文段,则重新设置定时器,如果没有了则关闭定时器。如果定时器超时,则重新发送所有已经发送
但还未收到确认的报文段,并将超时的间隔设置为以前的两倍。当发送方收到接收方的三个冗余的确认应答后,这是一种指示,
说明该报文段以后的报文段很有可能发生丢失了,那么发送方会启用快速重传的机制,就是当前定时器结束前,发送所有的已发 送但确认的报文段。
接收方使用的是累计确认的机制,对于所有按序到达的报文段,接收方返回一个报文段的肯定回答。如果收到了一个乱序的报文
段,那么接方会直接丢弃,并返回一个最近的按序到达的报文段的肯定回答。使用累计确认保证了返回的确认号之前的报文段都
已经按序到达了,所以发送窗口可以移动到已确认报文段的后面。 发送窗口的大小是变化的,它是由接收窗口剩余大小和网络中拥塞程度来决定的,TCP
就是通过控制发送窗口的长度来控制报文 段的发送速率。 但是 TCP 协议并不完全和滑动窗口协议相同,因为许多的 TCP
实现会将失序的报文段给缓存起来,并且发生重传时,只会重 传一个报文段,因此 TCP
协议的可靠传输机制更像是窗口滑动协议和选择重传协议的一个混合体。 TCP 的流量控制机制 TCP
提供了流量控制的服务,这个服务的主要目的是控制发送方的发送速率,保证接收方来得及接收。因为一旦发送的速率大
于接收方所能接收的速率,就会造成报文段的丢失。接收方主要是通过接收窗口来告诉发送方自己所能接收的大小,发送方根据
接收方的接收窗口的大小来调整发送窗口的大小,以此来达到控制发送速率的目的。 TCP 的拥塞控制机制 TCP
的拥塞控制主要是根据网络中的拥塞情况来控制发送方数据的发送速率,如果网络处于拥塞的状态,发送方就减小发送的
速率,这样一方面是为了避免继续增加网络中的拥塞程度,另一方面也是为了避免网络拥塞可能造成的报文段丢失。 TCP
的拥塞控制主要使用了四个机制,分别是慢启动、拥塞避免、快速重传和快速恢复。
慢启动的基本思想是,因为在发送方刚开始发送数据的时候,并不知道网络中的拥塞程度,所以先以较低的速率发送,进行试探
,每次收到一个确认报文,就将发动窗口的长度加一,这样每个 RTT 时间后,发送窗口的长度就会加倍。当发送窗口的大小达
到一个阈值的时候就进入拥塞避免算法。 拥塞避免算法是为了避免可能发生的拥塞,将发送窗口的大小由每过一个 RTT 增长一倍,变为每过一个
RTT ,长度只加一。 这样将窗口的增长速率由指数增长,变为加法线性增长。 快速重传指的是,当发送方收到三个冗余的确认应答时,因为 TCP
使用的是累计确认的机制,所以很有可能是发生了报文段的
丢失,因此采用立即重传的机制,在定时器结束前发送所有已发送但还未接收到确认应答的报文段。
快速恢复是对快速重传的后续处理,因为网络中可能已经出现了拥塞情况,所以会将慢启动的阀值减小为原来的一半,然后将拥
塞窗口的值置为减半后的阀值,然后开始执行拥塞避免算法,使得拥塞窗口缓慢地加性增大。简单来理解就是,乘性减,加性增。 TCP
认为网络拥塞的主要依据是报文段的重传次数,它会根据网络中的拥塞程度,通过调整慢启动的阀值,然后交替使用上面四 种机制来达到拥塞控制的目的。
Post 和 Get 的区别?
答:Post 和 Get 是 HTTP 请求的两种方法。 (1)从应用场景上来说,GET 请求是一个幂等的请求,一般 Get
请求用于对服务器资源不会产生影响的场景,比如说请求一个网页。而 Post
不是一个幂等的请求,一般用于对服务器资源会产生影响的情景。比如注册用户这一类的操作。 (2)因为不同的应用场景,所以浏览器一般会对 Get
请求缓存,但很少对 Post 请求缓存。 (3)从发送的报文格式来说,Get 请求的报文中实体部分为空,Post
请求的报文中实体部分一般为向服务器发送的数据。 (4)但是 Get 请求也可以将请求的参数放入 url 中向服务器发送, 这样的做法相对于
Post 请求来说,一个方面是不太安全,因为请求的 url 会被保留在历史记录中。并且浏览器由于对 url 有一个长度上的限制,所以会影响
get 请求发送数据时的长度。这个限制是浏览器规定的,并不是 RFC 规定的。还有就是 post 的参数传递支持更多的数据类型。
DNS 为什么使用 UDP 协议作为传输层协议?
答:DNS 使用 UDP 协议作为传输层协议的主要原因是为了避免使用 TCP 协议时造成的连接时延。 因为为了得到一个域名的 IP
地址,往往会向多个域名服务器查询,如果使用 TCP 协议,那么每次请求都会存在连接时延,这样使 DNS
服务变得很慢,因为大多数的地址查询请求,都是浏览器请求页面时发出的,这样会造成网页的等待时间过长。 使用 UDP 协议作为 DNS
协议会有一个问题,由于历史原因,物理链路的最小MTU = 576,所以为了限制报文长度不超过576,UDP 的报文段的长度被限制在 512
个字节以内,这样一旦 DNS 的查询或者应答报文,超过了 512 字节,那么基于 UDP 的DNS 协议就会被截断为 512
字节,那么有可能用户得到的 DNS 应答就是不完整的。这里 DNS 报文的长度一旦超过限制,并不会像 TCP
协议那样被拆分成多个报文段传输,因为 UDP 协议不会维护连接状态,所以我们没有办法确定那几个报文段属于同一个数据,UDP
只会将多余的数据给截取掉。 为了解决这个问题,我们可以使用 TCP 协议去请求报文。 DNS
还存在的一个问题是安全问题,就是我们没有办法确定我们得到的应答,一定是一个安全的应答,
因为应答可以被他人伪造,所以现在有了 DNS over HTTPS 来解决这个问题。
谈谈 CDN 服务?
答:CDN 是一个内容分发网络,通过对源网站资源的缓存,利用本身多台位于不同地域、不同运营商的服务器,向用户提供资就近访问的
功能。也就是说,用户的请求并不是直接发送给源网站,而是发送给 CDN 服务器,由 CND 服务器将请求定位到最近的含有该资源
的服务器上去请求。这样有利于提高网站的访问速度,同时通过这种方式也减轻了源服务器的访问压力。
什么是正向代理和反向代理?
答:我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的
服务都被代理服务器代替来请求。
反向代理隐藏了真实的服务端,当我们请求一个网站的时候,背后可能有成千上万台服务器为我们服务,但具体是哪一台,我们不知
道,也不需要知道,我们只需要知道反向代理服务器是谁就好了,反向代理服务器会帮我们把请求转发到真实的服务器那里去。反向
代理器一般用来实现负载平衡。
负载平衡的两种实现方式?
答:一种是使用反向代理的方式,用户的请求都发送到反向代理服务上,然后由反向代理服务器来转发请求到真实的服务器上,以此来实 现集群的负载平衡。
另一种是 DNS 的方式,DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一
个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在
每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服
务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解
析仍然返回的是那个 IP 地址,就会造成访问的问题。
即时通讯的实现,短轮询、长轮询、SSE 和 WebSocket 间的区别?
答:短轮询和长轮询的目的都是用于实现客户端和服务器端的一个即时通讯。 短轮询的基本思路就是浏览器每隔一段时间向浏览器发送 http
请求,服务器端在收到请求后,不论是否有数据更新,都直接进行
响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客
户端能够模拟实时地收到服务器端的数据的变化。这种方式的优点是比较简单,易于理解。缺点是这种方式由于需要不断的建立 ht tp
连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。
长轮询的基本思路是,首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将
这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。 客户端
JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。长轮询和短轮询比起来,它的
优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。 SSE
的基本思想是,服务器使用流信息向服务器推送信息。严格地说,http 协议无法做到服务器主动推送信息。但是,有一种变通
方法,就是服务器向客户端声明,接下来要发送的是流信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断
地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。SSE 就是利用这种机
制,使用流信息向浏览器推送信息。它基于 http 协议,目前除了 IE/Edge,其他浏览器都支持。它相对于前面两种方式来说,不
需要建立过多的 http 请求,相比之下节约了资源。 上面三种方式本质上都是基于 http 协议的,我们还可以使用 WebSocket
协议来实现。WebSocket 是 Html5 定义的一个新协 议,与传统的 http
协议不同,该协议允许由服务器主动的向客户端推送信息。使用 WebSocket 协议的缺点是在服务器端的配置 比较复杂。WebSocket
是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息,而 SSE 的方式是单向通信的,只能
由服务器端向客户端推送信息,如果客户端需要发送信息就是属于下一个 http 请求了。
实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案?
答:相较于不同页面的跳转,AJAX可以说大大提高了用户的浏览体验,不用看到页面切换之间的白屏是件很惬意的事情。但是很多早先的AJAX应用是不支持浏览器的前进后退的,这导致了用户不管在网站里浏览到何处,一旦刷新就会立刻回到起初的位置,并且用户也无法通过浏览器的前进后退按钮来实现浏览历史的切换。
对于第一个问题,解决还算容易,只要用cookie或者localStorage来记录应用的状态即可,刷新页面时读取一下这个状态,然后发送相应ajax请求来改变页面即可。但是第二个问题就很麻烦了,先说下现代浏览器的解决方案。