当前位置:   article > 正文

2024年Web前端最全计算机网络面试题汇总_5xxcom(1),头条三面hr面会挂人吗_前端环境和网络相关面试图

前端环境和网络相关面试图

最后

基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

HTTP1.0 和 HTTP1.1之间的区别

1. 长连接(Persistent Connection)
HTTP1.1支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启长连接keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。HTTP1.0需要使用keep-alive参数来告知服务器端要建立一个长连接。

2. 节约带宽
HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401,客户端就可以不用发送请求body了节约了带宽。

3. HOST域
在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname),HTTP1.0没有host域。随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都支持host域,且请求消息中如果没有host域会报告一个错误(400 Bad Request)。

4. 缓存处理
在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

5. 错误通知的管理
在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

https为什么要采用对称和非对称加密结合的方式

虽然说非对称加密安全,但是由于和对称加密比较来说,速度较慢(指的是加密和解密的速度而言),故我们https采用了将对称加密和非对称加密结合的方式,即我们将对称加密的秘钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用非对称的私钥进行解密得到对称加密的秘钥,此时双方就可以使用对称加密的秘钥进行通信沟通了,这样既保证了安全性,又增加了通信的速度,即加密和解密的速度.

在这里插入图片描述

对称加密和非对称加密的区别

对称加密:快速简单,加密和解密都使用同样的秘钥

非对称加密:安全,使用一对密钥,公钥/私钥。私钥由一方安全保管,公钥可以发给任何请求他的人,发送请求时通过公钥对消息进行加密,只有拥有私钥的人才能对你的消息进行解密,安全性大大提高。

SSL加密过程:

1.客户端向服务端发送请求

2.服务端返回给客户端公钥

3.客户端使用公钥对信息加密后在想服务端发送请求

4.服务端通过私钥对信息解密

公钥私钥加密原理

RSA加密算法:

一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 RSA的这一对公钥、私钥都可以用来加密和解密,并且一方加密的内容可以由并且只能由对方进行解密。

  • 对称加密与非对称加密结合

在这里插入图片描述

  • 判别公钥是否属于客户端

在这里插入图片描述
在这里插入图片描述

  • 数字签名

为了防止证书颁发过程中被人修改,出现了数字签名。

CA机构将证书内容用hash算法生成hash字符串1,并用CA私钥加密发送给服务端

服务端用CA公钥解密得到hash字符串1,同时也将证书内容用hash算法生成hash字符串2,如果hash字符串1与hash字符串2相同,说明证书没被修改过

在这里插入图片描述

HTTP1.1 和 HTTP2.0之间的区别

1.多路复用

HTTP2.0使用了多路复用的技术,做到**同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。**HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。

在这里插入图片描述

2. 头部数据压缩

HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

3. 服务器推送

服务端推送是一种在客户端请求之前发送数据的机制。网页使用了许多资源:HTML、样式表、脚本、图片等等。在HTTP1.1中这些资源每一个都必须明确地请求。这是一个很慢的过程。浏览器从获取HTML开始,然后在它解析和评估页面的时候,增量地获取更多的资源。因为服务器必须等待浏览器做每一个请求,网络经常是空闲的和未充分使用的.

为了改善延迟,HTTP2.0引入了server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前,免得客户端再次创建连接发送请求到服务器端获取。这样客户端可以直接从本地加载这些资源,不用再通过网络。

在这里插入图片描述

下面这张图是由TMX总结 :

在这里插入图片描述

HTTP0.9 /HTTP1.0/HTTP1.1 /HTTP2.0/HTTP3.0

超文本传输协议,基于TCP/IP通信协议来传递数据

1.HTTP0.9

HTTP/0.9是第一个版本的HTTP协议,已过时。它的组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,造成了HTTP/0.9协议只支持一种内容,即纯文本

HTTP/0.9具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。由此可见,HTTP协议的无状态特点在其第一个版本0.9中已经成型。一次HTTP/0.9的传输首先要建立一个由客户端到Web服务器的TCP连接,由客户端发起一个请求,然后由Web服务器返回页面内容,然后连接会关闭。如果请求的页面不存在,也不会返回任何错误码

2.HTTP1.0

相对于HTTP/0.9增加了如下主要特性:

  • 开始支持客户端通过POST方法向Web服务器提交数据,支持GET、HEAD、POST方法
  • 请求与响应支持头域
  • 响应对象不只限于超文本
  • 响应对象以一个响应状态行开始
  • 支持长连接(但默认还是使用短连接),缓存机制,以及身份认证
3.HTTP1.1

是目前使用最广泛的协议版本。相对于HTTP/1.0新增了以下内容:

3.1 默认为长连接

HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection:keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

3.2 宽带优化

提供了范围请求功能,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。这是支持文件断点续传的基础。

3.3 提供了HOST域

提供了虚拟主机的功能在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

3.4 多了一些缓存处理字段

HTTP/1.1在1.0的基础上加入了一些cache的新特性,引入了实体标签,一般被称为e-tags,新增更为强大的Cache-Control头

3.5 错误通知的管理

在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

4.HTTP2.0

相对于HTTP/1.1新增了以下内容:

4.1 二进制分帧

HTTP 2.0 的所有帧都采用二进制编码

  • 帧:客户端与服务器通过交换帧来通信,帧是基于这个新协议通信的最小单位。
  • 消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
  • 流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2 … N);
4.2 多路复用

在这里插入图片描述

多路复用允许同时通过单一的HTTP/2.0 连接发起多重的请求-响应消息。有了新的分帧机制后,HTTP/2.0不再依赖多个TCP 连接去处理更多并发的请求。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级。最后再在另一端根据每个帧首部的流标识符把它们重新组合起来。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。

4.3 头部压缩

HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。HTTP/2.0 要求通讯双方各自缓存一份首部字段表从而避免了重复传输

4.4 请求优先级

浏览器可以在发现资源时立即分派请求,指定每个流的优先级,**让服务器决定最优的响应次序。**这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。

4.5 服务端推送Server Push

把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。

5.http3.0(QUIC)

快速UDP互联网连接

2个主要特征:

5.1 解决阻塞问题

基于TCP的HTTP/2,尽管从逻辑上来说,不同的流之间相互独立,不会相互影响,但在实际传输方面,数据还是要一帧一帧的发送和接收**,一旦某一个流的数据有丢包,则同样会阻塞在它之后传输的流数据传输**。而基于UDP的QUIC协议则可以更为彻底地解决这样的问题,让不同的流之间真正的实现相互独立传输,互不干扰。

5.2切换网络时的连接保持

当前移动端的应用环境,用户的网络可能会经常切换,比如从办公室或家里出门,WiFi断开,网络切换为3G或4G。基于TCP的协议,由于切换网络之后,IP会改变,因而之前的连接不可能继续保持。而基于UDP的QUIC协议,则可以内建与TCP中不同的连接标识方法从而在网络完成切换之后,恢复之前与服务器的连接

HTTP的请求

  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送’*'的请求来测试服务器的功能性。
  • HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
  • GET:向特定的资源发出请求。
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URI所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
get /post请求的区别(字节)
  1. get参数包含在URL中,长度有限制,会保留在历史记录里,post通过request body传递参数,长度没有限制,不会保留
  2. 回退时,get请求会从缓存中读取数据,而post会重新发送请求
  3. get请求的URL地址可以被收藏,post不可以
  4. get请求只能进行url编码,post支持多种编码方式

GET和POST本质上没有区别

HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司,他们对get/post请求的数据处理不同。

GET和POST还有一个重大区别

GET产生一个TCP数据包;POST产生两个TCP数据包

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

HTTP常见的状态码

状态码类别原因短语
1XXInformational(信息性状态码,服务器给客户端的信息)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法进行处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错
状态码描述
200 OK请求已正常处理
301 Moved Permanently永久性重定向 : 请求的资源已经被分配了新的URI,以后应使用资源现在所指的URI
302 Found临时性重定向 : 和301相似,但302代表的资源不是永久性移动,只是临时性性质的。换句话说,已移动的资源对应的URI将来还有可能发生改变
303 See Other303状态码和302状态码有着相同的功能,但303状态码明确表示客户端应当采用GET方法获取资源,这点与302状态码有区别
304 Not Modified该状态码表示客户端发送附带条件的请求时(采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部)服务端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304.。
400 Bad Request服务器端无法理解客户端发送的请求,请求报文中可能存在语法错误((前端提交到后台的数据应该是json字符串类型,但是前端没有将对象JSON.stringify转化成字符串))
401 Unauthorized该状态码表示发送的请求需要有通过HTTP认证(BASIC认证,DIGEST认证)的认证信息
403 Forbidden不允许访问那个资源。该状态码表明对请求资源的访问被服务器拒绝了。(权限,未授权IP等)
404 Not Found服务器上没有请求的资源。路径错误等
500 Internal Server Error该状态码表明服务器端在执行请求时发生了错误。也有可能是web应用存在bug或某些临时故障
503 Service Unavailable服务器暂时处于超负载或正在停机维护,现在无法处理请求
502作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应
504作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应
HTTP的only(美团优选)

如果在cookie中设置了HttpOnly,那么通过程序(js脚本)将无法读取到cookie信息,这样能有效防止XSS攻击

HTTP的Referer

表示来源,正确英语拼法是Referrer,为了向后兼容,将错就错

在www.google.com里有一个www.baidu.com链接,那么点击这个www.baidu.com,它的header信息里就有:Referer=http://www.google.com,可以利用这个来防止盗链了,比如我只允许我自己的网站访问我自己的图片服务器,那我的域名是www.google.com,那么图片服务器每次取到Referer来判断一下是不是我自己的域名www.google.com,如果是就继续访问,不是就拦截。

直接在地址栏中输入URL的地址是不会包含referer字段的,因为他不是藏一个地方链接过去的

允许 Referer 为空,意味着你允许比如浏览器直接访问,就是空

请求转发(Redirect)和重定向(Forward)之间的区别

  • 地址栏信息 : 重定向会显示转向以后的地址,而请求转发不会显示转向的地址
  • 请求次数 : 重定向至少提交了两次请求
  • 数据 : 请求转发对request对象的信息不会丢失,因此可以在多个页面交互过程中实现请求数据的共享; 而重定向之前request域信息将丢失
  • 原理 : 请求转发是在服务器内部控制权的转移,是由服务器区请求,客户端并不知道是怎样转移的,因此客户端的地址不会显示出转向的地址; 重定向则是服务器告诉客户端要转向哪个地址,客户端再自己去请求转向的地址,因此会显示转向后的地址,也可以理解为浏览器至少进行了两次的访问请求
  • 速度 : 请求转发的速度远远快于重定向
请求转发和重定向的应用场景
  • 1、重定向的速度比转发慢,因为浏览器还得发出一个新的请求,如果在使用转发和重定向都无所谓的时候建议使用转发。
  • 2、因为转发只能访问当前WEB的应用程序,所以不同WEB应用程序之间的访问,特别是要访问到另外一个WEB站点上的资源的情况,这个时候就只能使用重定向了。

RPC和HTTP的区别

RPC(Remote Produce Call) 远程过程调用

是一个计算机通信协议,该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程.它是建立在Socket之上

RPC实现远程调用的策略:

(1) 采用何种网络通讯协议?
比较流行的RPC框架,采用的都是TCP作为底层传输协议

(2)数据传输的格式是怎么样的?

不同于HTTP,RPC远程过程调用需要让调用者和被调用者采用相同的数据传输格式,就好比两个人使用同一种语言进行交流沟通一样.

下面是RPC的调用流程图:

在这里插入图片描述

HTTP(HyperText Transport Protocol)

HTTP称为超文本传输协议,是一种应用层的协议,规定了网络传输的请求格式、响应格式、资源定位和操作的方式等。但是底层采用什么网络传输协议,并没有规定,不过现在都是采用TCP协议作为底层传输协议.

客户端通过HTTP向服务器端发送请求,并接受响应的流程:

在这里插入图片描述

比较RPC和HTTP
  • RPC通过Thrift二进制进行传输,而HTTP的json序列化更消耗性能 (即在序列化和反序列化方式上的区别)
  • RPC自带负载均衡,而HTTP需要自己设置负载均衡
  • RPC可以自定义TCP协议,报文相对来说较小
  • RPC是一种API,HTTP是一种无状态的网络协议。RPC可以基于HTTP协议实现,也可以直接在TCP协议上实现
  • RPC主要是用在大型网站里面,因为大型网站里面系统繁多,业务线复杂,而且效率优势非常重要的一块,这个时候RPC的优势就比较明显了.HTTP主要是用在中小型企业里面,业务线没那么繁多的情况下
  • HTTP需要事先通知,修改Nginx/HAProxy配置。RPC能做到自动通知,不影响上游

常用的RPC框架: webservie(cxf)、dubbo

HTTP客户端工具: HTTPClient

Socket是什么?

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket建立网络通信连接至少要一对端口号(Socket)。Socket本质是编程接口(API).

当然我们也可以理解为: Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

在这里插入图片描述

Socket中的time-wait状态多,如何解决

在高并发短连接的server端,当server处理完client的请求后立刻close socket此时会出现time_wait状态,然后如果client再并发2000个连接,此时部分连接就连接不上了,用linger强制关闭可以解决此问题,但是linger会导致数据丢失,linger值为0时是强制关闭,无论并发多少多能正常连接上,如果非0会发生部分连接不上的情况!(可调用setsockopt设置套接字的linger延时标志,同时将延时时间设置为0。)

TIME_WAIT是TCP连接断开时必定会出现的状态。是无法避免掉的,这是TCP协议实现的一部分。

在WINDOWS下,可以修改注册表让这个时间变短一些,time_wait的时间为2msl,默认为4min.你可以通过改变TcpTimedWaitDelay的量,把它缩短到30s.TCP要保证在所有可能的情况下使得所有的数据都能够被投递。当你关闭一个socket时,主动关闭一端的socket将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态,这的确能够保证所有的数据都被传输。但是这样也会给我们带来两个问题 :

(1) 我们没有任何机制保证最后的一个ACK能够正常传输

(2) 网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理

解决方案 :

由于TIME_WAIT状态所带来的相关问题,我们可以通过设置SO_LINGER标志来避免socket进入TIME_WAIT状态,这可以通过发送RST而取代正常的TCP四次握手的终止方式。但这并不是一个很好的主意,TIME_WAIT对于我们来说往往是有利的,下面我们来谈谈TIME_WAIT的作用

TIME_WAIT的作用 :

1. 可靠地实现TCP全双工连接的终止;

如果服务器最后发送的ACK因为某种原因丢失了,那么客户一定会重新发送FIN,这样因为有TIME_WAIT的存在,服务器会重新发送ACK给客户,如果没有TIME_WAIT,那么无论客户有没有收到ACK,服务器都已经关掉连接了,此时客户重新发送FIN,服务器将不会发送ACK,而是RST,从而使客户端报错。也就是说,TIME_WAIT有助于可靠地实现TCP全双工连接的终止。

2. 允许老的重复分节在网络中消逝。

如果没有TIME_WAIT,我们可以在最后一个ACK还未到达客户的时候,就建立一个新的连接。那么此时,如果客户收到了这个ACK的话,就乱套了,必须保证这个ACK完全死掉之后,才能建立新的连接。也就是说,TIME_WAIT允许老的重复分节在网络中消逝

为什么TIME_WAIT 状态需要保持2MSL这么长的时间?

ACK包到达服务器需要MSL时间,服务器重传 FIN 包也需要MSL时间,2MSL 是数据包往返的最大时间,通常为2min,如果2MSL后还未收到服务器重传的FIN 包,就说明服务器已经收到了ACK包,此时由TIME_WAIT状态转变为CLOSED状态.

如果 TIME_WAIT 状态保持时间不足够长(比如小于2MSL),第一个连接就正常终止了。第二个拥有相同相关五元组的连接出现,而第一个连接的重复报文到达,干扰了第二个连接。TCP实现必须防止某个连接的重复报文在连接终止后出现,所以让TIME_WAIT状态保持时间足够长(2MSL),连接相应方向上的TCP报文要么完全响应完毕,要么被丢弃。建立第二个连接的时候,不会混淆。

进程和线程有什么关系与区别(美团)

进程

每个应用程序都是一个进程,每个进程都有自己独立的一块内存空间,一个进程可以有多个线程。

进程的三种状态:就绪态(以获得除cpu外的所有资源),阻塞态,执行态

在这里插入图片描述

线程

进程中的一个执行任务(控制单元)。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可以共享数据。

区别
  1. 根本区别:进程是操作系统分配资源的基本单位,线程是处理器任务调度和执行的基本单位
  2. 资源开销:每个进程都有独立的代码和数据空间,程序之间切换开销大;线程是轻量级的线程,切换开销少
  3. 内存分配:进程的地址空间和资源是相互独立的,线程共享本进程的地址空间和资源

进程间的通信方式有哪些?(美团)

1.管道

1.1匿名管道(半双工,数据只能单向移动,面向字节流,允许具有血缘关系的进程通信)

两个文件描述符指向管道的两端

在这里插入图片描述

1.2有名管道(半双工,允许无亲缘关系的进程通信)

2.消息队列

(发送进程添加消息到队列的末尾,接收进程在队列头部接收消息,消息一旦被接收就会从队列中删除,类似FIFO)

在这里插入图片描述

3.信号量

信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。

信号量工作原理 :

由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

  1. P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
  2. V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

在信号量进行PV操作时都为原子操作(因为它需要保护临界资源)

4.共享内存

共享内存就是允许两个或多个进程共享一定的存储区共享内存没有任何的同步与互斥机制,所以要使用信号量来实现对共享内存的存取的同步

5.套接字

可用于不同机器间的进程通信

输入一个网址,执行过程是怎样的

在这里插入图片描述

如上图所示,在浏览器的地址栏中输入url : 此时执行过程简单地介绍如下所示

第一步 : 我们的DNS域名解析器会对url进行域名解析,找到对应的IP节点进行返回

第二步 : 拿到我们访问的IP,我们就要与对应的服务器建立TCP连接(三次握手)

第三步 : TCP连接建立成功,我们就可以向服务器发送HTTP请求了,当服务器获取我们的请求,进行处理,然后将请求的响应返回给我们

第四步 : 关闭TCP连接(四次挥手)

1.DNS域名解析(找到ip地址)

DNS是进行域名和与之相对应的IP地址转换的服务器

浏览器会首先搜索浏览器自身的DNS缓存,如果浏览器自身的缓存里面没有找到对应的条目,

那么浏览器会搜索操作系统自身的DNS缓存,操作系统域名解析的过程是读取hosts文件(位于C:\Windows\System32\drivers\etc),如果在hosts文件中也没有找到对应的条目,

浏览器就会找TCP/IP参数中设置的首选DNS服务器(本地DNS服务器)发起一个DNS的系统调用(运营商dns-->根(13台)域名服务器-->顶级域名服务器-->域名注册商服务器)

从客户端到本地DNS服务器是属于递归查询,而DNS服务器之间就是的交互查询就是迭代查询

在这里插入图片描述

2.发起TCP三次握手,建立连接

在这里插入图片描述

3.发起http请求,服务器响应给浏览器html代码
4.浏览器解析html代码,并请求html代码中的资源(如js,css,图片等)
5.浏览器对页面进行渲染呈现给用户

将URL对应的各种资源,通过浏览器渲染引擎,输出可视化的图像

渲染引擎主要包括:html解析器,css解析器,布局,js引擎

html引擎:将html文本解释成DOM树文档对象模型

css解释器:为dom中的各个元素对象加上样式信息CSS对象模型

布局:将dom和css样式信息结合起来,计算他们的大小及位置信息,构建(渲染树

js引擎:解释js代码并把代码逻辑对应的dom和css改动信息应用到布局中去

输入一个网址之后会发生什么,用到了哪些协议

输入一个网址以后,首先会进行DNS域名解析,找到目标的IP地址,然后和目标地址建立TCP连接,连接成功以后,发送HTTP请求,目标服务器处理完请求以后,返回响应结果,最后关闭TCP连接

在这里插入图片描述

网络间两个主机通信过程,用到了哪些设备

设存在两个主机 : 主机A和主机B,网络间主机A和主机B的通信过程分为两种情况
情况1 : 主机A和主机B位于同一个二层网络中,此时直接走二层交换机

主机A首先查看自己的ARP缓存,检查是否含有主机B的IP到MAC地址的映射,如果存在映射,则构造报文,目的IP为主机B的IP,源IP为主机A的IP,目的MAC为主机B的MAC,源MAC为主机A的MAC,将报文发送给交换机C.交换机C进行MAC地址表学习,将主机A和MAC和报文入端口号记录下来,然后交换机C查看自己的MAC转发表,检查是否含有主机B的MAC到端口的映射,如果有对应的端口,则获取对应的端口,将报文从此端口转发出去,报文到达主机B.如果交换机C没有主机B的MAC转发映射表,则采用洪泛的形式广播报文,主机B收到报文后向主机A进行回复,交换机C进行MAC表学习,将主机B的MAC和报文入端口号记录下来

如果主机A没有主机B的ARP映射,主机A需要发送ARP请求,以获取主机B的MAC,将报文发往交换机C,交换机C采用洪泛的形式广播报文,主机B收到广播报文后,在自己的ARP缓存表中写入主机A的IP到MAC的映射,将自己的MAC封装到ARP回复报文中,单播给主机A,主机A获取到主机B的MAC后,在自己的ARP缓存表中写入主机B的IP到MAC的映射,构造报文发送给主机B,过程同上。

主机B向主机A回复报文的过程类似。

在这里插入图片描述
在这里插入图片描述

情况2 : 主机A和主机B不在同一层网络中,需要走三层路由器 + 二层交换机

主机A查看自己的ARP缓存表,检查是否有路由器E的IP到MAC的映射,如果有映射,获取路由器E的MAC,构造报文,目的IP为主机B的IP,源IP为主机A的IP,目的MAC为路由器E的MAC,源MAC为主机A的MAC,将报文通过交换机C发往路由器E,过程同上。 如果主机A没有路由器E的IP到MAC的映射,需要发送ARP请求,获取路由器E的MAC,过程同上。路由器E收到主机A的报文后,剥离报文的MAC帧头,查询路由表,发现目标主机B所在的网络是直连的,查看自己的ARP缓存表,如果有主机B的IP到MAC的映射关系,获取主机B的MAC,封装报文MAC帧头,目的MAC为主机B的MAC,源MAC为路由器E的MAC,将报文通过交换机D发往主机B,如果路由器E没有主机B的IP到MAC的映射关系,需要发送ARP请求,获取主机B的MAC,过程同上。

主机B向主机A回复报文的过程类似。

注意 :

  • 路由器上的路由表一般是配置静态路由或者通过路由协议自动学习的

在这里插入图片描述

ARP协议和ARP攻击

ARP协议

ARP协议指的是地址解析协议(Address Resolution Protocol),是根据**IP地址获取物理地址(MAC地址)**的一个TCP/IP协议.

在计算机间通信的时候,计算机要知道目的计算机是谁(就像我们人交流一样,要知道对方是谁),这中间需要涉及到MAC地址,而MAC是真正的电脑的唯一标识符。

我们通过两个主机之间的ping连接,来看一下简单的ARP请求应答

在这里插入图片描述

PC1依据OSI模型 :

① 依次从上至下对数据进行封装,包括对ICMP Date加IP包头的封装,但是到了封装MAC地址的时候

② PC1首先查询自己的ARP缓存表,发现没有IP2和他的MAC地址的映射,这个时候MAC数据帧封装失败。我们使用ping命令的时候,是指定PC2的IP2的,计算机是知道目的主机的IP地址,能够完成网络层的数据封装,因为设备通信还需要对方的MAC地址,但是PC1的缓存表里没有,所以在MAC封装的时候填入不了目的MAC地址。

那么PC1为了获取PC2的MAC地址 :

③ PC1要发送询问信息,询问PC2的MAC地址,询问信息包括PC1的IP和MAC地址、PC2的IP地址,这里我们想到一个问题,即使是询问信息,也是需要进行MAC数据帧的封装,那这个询问信息的目的MAC地址填什么呢,规定当目的MAC地址为ff-ff-ff-ff-ff-ff时,就代表这是一个询问信息,也即使后面我要说的广播。

PC2收到这个询问信息后,将这里面的IP1和MAC1(PC1的IP和MAC)添加到本地的ARP缓存表中,然后 :

④ PC2发送应答信息,对数据进行IP和MAC的封装,发送给PC1,因为缓存表里已经有PC1的IP和MAC的映射了呢。这个应答信息包含PC2的IP2和MAC2。PC1收到这个应答信息,理所应当的就获取了PC2的MAC地址,并添加到自己的缓存表中。

经过这样交互式的一问一答,PC1和PC2都获得了对方的MAC地址,值得注意的是,目的主机先完成ARP缓存,然后才是源主机完成ARP缓存。之后PC1和PC2就可以真正交流了。

ARP攻击

在这里插入图片描述

对于交换机而言,它也具有记忆功能,会基于源MAC地址建立一个CAM缓存表(记录MAC对应接口的信息),理解为当PC1发送消息至交换机的Port1时,交换机会把源MAC(也就是MAC1)记录下来,添加一条MAC1和Port1的映射,之后交换机可以根据MAC帧的目的MAC进行端口转发

ICMP协议

它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

路由器和交换机的区别

(1)外形上:

交换机通常端口比较多看起来比较笨重,而路由器的端口就少得多体积也小得多

(2)工作层次不同:

最初的交换机工作在数据链路层,而路由器则工作网络层

(3)数据的转发对象不同:

交换机是根据MAC地址转发数据帧,而路由器则是根据IP地址来转发IP数据

(4)”分工“不同

交换机主要是用于组建局域网,而路由器则是负责让主机连接外网

(5)冲突域和广播域

交换机分割冲突域,但是不分割广播域,而路由器分割广播域。

(6)工作原理

交换机的原理比较简单,一般都是采用硬件电路实现数据帧的转发

路由器工作在网络层,肩负着网络互联的重任,要实现更加复杂的协议,具有更加智能的转发决策功能,一般都会在在路由器中跑操作系统,实现复杂的路由算法,更偏向于软件实现其功能。

(7)安全性能

路由器一般有防火墙的功能,能够对一些网络数据包选择性过滤。现在的一些路由器都具备交换机的功能,一些交换机具备路由器的功能,被称为3层交换机,广泛使用。相比较而言,路由器的功能较交换机要强大,但是速度也较慢,价格昂贵,三层交换机既有交换机的线性转发报文的能力,又有路由器的良好的路由功能因此得到广泛的使用

cdn (网易云音乐)(字节)

由于我们使用本地域名解析器进行解析,获取源服务器IP导致每一次获取数据,都要去源服务器进行访问获取,造成性能的损失的降低,故我们在网络各处部署节点服务器,构建CDN系统,当我们使用本地DNS域名系统进行解析的时候,DNS系统会将域名解析交给CNAME指向的专用的DNS服务器,通过CDN的DNS服务器获取到一台合适的缓存服务器IP给我们,这里的合适性指的是(服务器距离我们的距离位置,该服务器上是否存在我们需要的内容等等…),此时我们就与该缓存服务器建立TCP连接,已经后续的HTTP请求获取数据,得到响应等过程,如果该节点服务器不能满足我们的需求,我们会层层向它的上级服务器进行访问,直到源服务器为止.

cdn(内容分发网络)

(Content Delivery Network)

就近访问原理:采用各种缓存服务器将这些缓存服务器分布到用户访问相对集中的地区或网络,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求cdn就是用来加速的,他能让用户就近访问数据,这样就更更快的获取到需要的数据。

举个例子,现在服务器在北京,深圳的用户想要获取服务器上的数据就需要跨越一个很远的距离,这显然就比北京的用户访问北京的服务器速度要慢。但是现在我们在深圳建立一个cdn服务器,上面缓存住一些数据,深圳用户访问时先访问这个cdn服务器,如果服务器上有用户请求的数据就可以直接返回,这样速度就大大的提升了。

代售点优势:大部分请求在CDN边缘完成,起到了分流的作用,减轻源站的负载。

dns(域名解析)

我们怎么知道用户的所在位置从而给他分配最佳的cdn节点呢。这就需要dns服务来进行定位了。

当我们在浏览器中输入一个域名时,首先需要将域名转换为ip地址,再将ip地址转换为mac地址,这样才能在网络上找到该服务器。当我们向dns服务器发起解析域名的请求时,dns服务器首先会查询自己的缓存中有没有该域名,如果缓存中存在该域名,则可以直接返回ip地址。如果缓存中没有,服务器则会以递归的方式层层访问。例如,我们要访问www.baidu.com,首先我们会先向全球13个根服务器发起请求,询问com域名的地址,然后再向负责com域名的名称服务器发送请求,找到baidu.com,这样层层递归,最终找到我们需要的ip地址。

在这里插入图片描述

dns劫持

DNS劫持又称为域名劫持,是一种恶意攻击,黑客或其他方通过使用流氓DNS服务器或其他策略来重定向用户,该策略更改了Internet用户被重定向到的IP地址。

防范DNS污染

DNS污染最常见的就是篡改host主机文件,通过篡改DNS主机文件ip地址和网址将不再一一对应,打开的网站将不是最初想要访问的网站。

  1. 53端口为DNS服务器所开放,主要用于域名解析。如果开放DNS服务,黑客可以通过分析DNS服务器而直接获取web服务器等主机的ip地址,在利用53端口突破某些不稳定的防火墙,从而实施攻击。如果不用于提供域名解析服务,建议关闭该端口。
  2. 使用RNDC加密,存根区域,减少DNS的生命周期(RNDC是一种控制域名服务器的工具,通过网络与DNS服务器进行连接,实现不停止DNS服务器工作的情况下进行数据更新)
  3. 检查授权名称服务器是否和主机上的解析一致。早期的互联网连接需要进行反向地址解析,至今SMTP右键服务器还在使用。
DNS使用什么协议

DNS区域传输的时候使用TCP协议

辅域名服务器会定时向主域名服务器进行查询以便了解数据是否变动。如有变动,会执行一次区域传送,进行数据同步。

域名解析时使用UDP协议

客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过三次握手,这样DNS服务器负载更低,响应更快。

cdn缓存的两种方式

cdn中缓存了服务器上的部分资源。

  1. 服务器主动去更新缓存,cdn节点被动接受
  2. 另一种方式是当用户请求的资源不存在时,cdn服务器向上游服务器发起请求,更新缓存,然后将数据返回给用户,这种方式是cdn服务器主动,源站服务器被动。(一般采用这种方式)

Nginx反向代理

当我们与DNS域名解析器解析的IP服务器建立TCP连接以后,此时向其发送请求时,我们可以在其中建立Nginx反向代理,可以实现负载均衡,屏蔽真实地址,安全管理,解决跨域问题,节约有效的IP资源,减少web服务器压力,提高响应速度

Nginx是一个轻量级/高性能的反向代理Web服务器,他实现非常高效的反向代理、负载均衡.

使用Nginx的好处
  • 保护了真实的web服务器,使得web服务器对外不可见。外网只能看到反向代理服务器,而反向代理服务器上并没有真实数据,因此保护了web服务器的资源安全。
  • 节约了有限的IP地址资源

企业内部所有的网站共享一个在Internet中注册的IP地址,这些服务器分配私有地址,采用虚拟主机的方式对外提供服务。

  • 减少web服务器压力,提高响应速度

反向代理就是通常所说的web服务器加速,它是一种通过在繁忙的web服务器和外部网络之间增加一个高速的web缓冲服务器来降低实际的web服务器的负载的一种技术。反向代理服务器会强制将外部网络对要代理的服务器的访问经过它,它会将从源服务器上获取到的静态内容缓存到本地,以便日后再收到同样的信息请求时,直接将本地缓存的内容发给客户端,减少后端web服务器的压力,提高响应速度。

  • 其他优点

请求的统一控制,包括设置权限,过滤规则等。

区分动态和静态可缓存内容。

实现负载均衡,内部可以采用多台服务器来组成服务器集群,外部还是可以采用一个地址访问。

解决ajax跨域问题

作为真实服务器的缓存,解决瞬间负载量大的问题。

配置简单

占内存小,可实现高并发连接,处理响应快

Nginx的缺点

处理动态页面很慢

为什么Nginx的性能这么高?

因为他的事件处理机制:异步非阻塞事件处理机制(运用了epoll模型,提供了一个队列,排队解决)

Nginx怎么处理请求的?

nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址

    server {            						# 第一个Server区块开始,表示一个独立的虚拟主机站点
        listen       80;      					# 提供服务的端口,默认80
        server_name  localhost;       			# 提供服务的域名主机名
        location / {            				# 第一个location区块开始
            root   html;       				# 站点的根目录,相当于Nginx的安装目录
            index  index.html index.htm;      	# 默认的首页文件,多个用空格分开
        }          								# 第一个location区块结果

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
什么是正向代理和反向代理?
  1. 正向代理类似一个跳板机,代理访问外部资源。(正向代理就是一个人发送一个请求直接就到达了目标的服务器)

比如我们国内访问谷歌,直接访问访问不到,我们可以通过一个正向代理服务器,请求发到代理服,代理服务器能够访问谷歌,这样由代理去谷歌取到返回数据,再返回给我们,这样我们就能访问谷歌了

在这里插入图片描述

2.反向代理(Reverse Proxy)对外就表现为一个服务器。(反方代理就是请求统一被Nginx接收,nginx反向代理服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了)

实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器

在这里插入图片描述

Nginx的应用场景
  • http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
  • 虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。
  • 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。
  • Nginx 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。
Nginx目录结构有哪些?
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf                             # Nginx所有配置文件的目录
│   ├── fastcgi.conf                 # fastcgi相关参数的配置文件
│   ├── fastcgi.conf.default         # fastcgi.conf的原始备份文件
│   ├── fastcgi_params               # fastcgi的参数文件
│   ├── fastcgi_params.default       
│   ├── koi-utf
│   ├── koi-win
│   ├── mime.types                   # 媒体类型
│   ├── mime.types.default
│   ├── nginx.conf                   # Nginx主配置文件,很重要!!!
│   ├── nginx.conf.default
│   ├── scgi_params                  # scgi相关参数文件
│   ├── scgi_params.default  
│   ├── uwsgi_params                 # uwsgi相关参数文件
│   ├── uwsgi_params.default
│   └── win-utf
├── fastcgi_temp                     # fastcgi临时数据目录
├── html                             # Nginx默认站点目录
│   ├── 50x.html                     # 错误页面优雅替代显示文件,例如当出现502错误时会调用此页面
│   └── index.html                   # 默认的首页文件
├── logs                             # Nginx日志目录
│   ├── access.log                   # 访问日志文件
│   ├── error.log                    # 错误日志文件
│   └── nginx.pid                    # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp                       # 临时目录
├── sbin                             # Nginx命令目录
│   └── nginx                        # Nginx的启动命令
├── scgi_temp                        # 临时目录
└── uwsgi_temp                       # 临时目录

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

其他计算机网络问题

1. 你怎么理解认证和权限的,为什么使用jwt不使用session、cookie?

答: 首先当前我们的网络存在很多的恶意攻击,例如XSS,CSRF等等,我们客户端给服务器发送请求,访问服务器时,服务器需要对我们的请求进行相应的认证,同时对于我们客户端授予不同的权限,拥有相应的权限才能访问服务器,发送相应的请求信息。

1.1 对于jwt,我们首先需要了解它是什么?

jwt(Json web token) : 是为了在网络应用环境中传递声明而执行的一种基于JSON的开放标准(RFC 7519)

其中对应生成的token被设计成紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景

JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token可直接被用于认证,也可被加密

在这里插入图片描述

1.2 JWT的组成

在这里插入图片描述

JWT生成编码以后是以下的样子:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

  • 1
  • 2

JWT由三个部分组成:

  • 头部(header)
  • 载荷(payload)
  • 签证(signature)

头部(header):

  • 声明类型,这里是jwt
  • 声明加密的算法,通常为HMAC算法
HMAC算法介绍:


  • 1
  • 2
  • 3

完整的头部head信息就像下面的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

  • 1
  • 2
  • 3
  • 4
  • 5

然后我们会对头部信息进行加密,构成第一部分:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

  • 1
  • 2

载荷(payload):

载荷是存放有效信息的地方,有效信息包括三个部分:

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

其中,标准中注册的声明(建议但是不强制使用) :

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明:

  • 可以添加任何信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有声明:

  • 提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

我们这里定义一个payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

进行加密处理以后,构成第二部分:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

  • 1
  • 2

签证(signature):

jwt的第三部分是一个签证信息,一般由三个部分组成:

  • header(加密以后的)
  • payload(加密以后的)
  • secret
UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

  • 1
  • 2

其中密钥是保存在服务端的,服务端会根据这个密钥生成token和验证,所以必须要保存好!!!

在这里插入图片描述

1.3 签名的目的:

最后一步签名的过程,实际上是对头部以及载荷内容进行签名。一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小.

所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的.

服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用alg字段指明了我们的加密算法了。

如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应

在这里插入图片描述

注意:

  • 在JWT中不应该在载荷中存放任何敏感的信息,比如用户的密码等等
1.4 JWT如何使用?

一般会在请求头中加入Authoriation,并加入Bearer标注:

fetch('api/user/1', {
  headers: {
    'Authorization': 'Bearer ' + token
  }
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

服务端会验证token,如果验证通过就会返回相应的资源!

1.5 JWT的安全相关
  • 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
  • 保护好secret私钥,该私钥非常重要。
  • 如果可以,请使用https协议
1.6 对Token认证的五点认识:
  • 一个Token就是一些信息的集合;
  • 在Token中包含足够多的信息,以便在后续请求中减少查询数据库的几率;
  • 服务端需要对cookie和HTTP Authrorization Header进行Token信息的检查;
  • 基于上一点,你可以用一套token认证代码来面对浏览器类客户端和非浏览器类客户端;
  • 因为token是被签名的,所以我们可以认为一个可以解码认证通过的token是由我们系统发放的,其中带的信息是合法有效的;

2. JWT认证和传统的Session认证的比较

2.1 传统的session认证

我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。

2.2 基于session认证所显露的问题

Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

2.3 基于token的鉴权机制

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

它的流程如下所示:

  • 用户使用用户名和密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附上这个token值
  • 服务端验证token值,并返回数据

这个token值必须在每次请求时传递给服务端,它应该保存在请求头中,另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了(Access-Control-Allow-Origin)

2.4 token方式的优点
  • 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输。
  • 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息。
  • 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可。
  • 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可。
  • 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
  • CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范
  • 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多。
  • 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理。
  • 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)。
  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展。
2.5 java实现JWT


  • 1
  • 2
2.6 JWT和SpringSecurity的比较
JWT的优点:
  • 无需再服务端存储用户数据,减轻服务端压力
  • 轻量级,json风格,比较简单
  • 跨语言
JWT的缺点:
  • token一旦签发,无法修改
  • 无法更新token有效期,用户登录状态刷新难以实现
  • 无法销毁一个token,服务端不能对用户状态进行绝对控制
  • 不包含权限控制
SpringSecurity的优点:
  • 用户信息保存在服务端,服务端可以对用户状态绝对控制
  • 基于Spring,无缝整合,修改登录逻辑,其实就是添加过滤器
  • 整合权限管理
SpringSecurity的缺点:
  • 实现复杂,基于一连串的过滤器链
  • 需要再服务端保存用户信息,增加服务端压力
2.7 使用JWT做登录认证,如何解决token的注销问题

方案1 : 适当减短token的有效期,让token尽快失效

方案2 : 使用redis (即使用JWT还要使用redis的场景)

(1) 我们在用户登录时,生成JWT

(2) 把JWT的id存储到redis中,只有redis数据库中有id的JWT,才是有效的JWT

(3) 退出登录时,将对应的id从redis中删除,即间接解决了token的注销问题

2.8 如何解决异地登录问题?

答:JWT设计为了实现无状态的登录,因此token无法修改,难以实现异地登录的判断,或者强制让登录token失效。

因此如果有类似需求, 就不应选择JWT作为登录方案,而是使用传统session登录方案。
但是,如果一定要用JWT实现类似要过,就需要在Redis中记录登录用户的JWT的token信息,这样就成了有状态的登录,但是这样还不如一开始就选择Session方案.

2.9 你觉得在微服务中是在微服务中实现认证和登录好还是在网关中实现好,为什么?

我们一般选择在网关中实现认证和登录.

我们的微服务隐藏在网关的后面,而且整个服务被Nginx反向代理,用户只能看到nginx的地址,微服务暴露的可能性很低。
然后,即便真的暴露了,我们的微服务都做了严格的服务间鉴权处理,任何对微服务的访问都会被验证是否有授权,如果没有则会被拦截。具体实现:

  • 会有一张表记录每个微服务的id,和密钥信息
  • 服务启动时,需要去授权中心,认证身份,携带id和secret
  • 授权中心认证通过,会颁发一个JWT给微服务
  • 微服务访问其它服务时,需要携带JWT
  • 被访问的服务,需要验证JWT,如果没有携带,或token时伪造的直接拦截请求即可

3. Session和Cookie的面试题

3.1 会话

当一个用户打开一个浏览器或者访问一个网站时,只要不关闭这个浏览器,不管该用户点击多少个超链接,访问多少个资源,直到该用户关闭浏览器或者服务器关闭.这样一个过程称为一个会话.

那么在会话过程中需要解决一些问题 : 主要就是保存用户在访问过程中产生的数据

3.2 Cookie(浏览器端会话技术)
  • 当浏览器第一次访问服务器,给服务器发送请求时,服务器端会创建一个键值对形式的Cookie,该Cookie中会包含当前用户的信息,然后通过响应(响应头set-cookie)返回给浏览器端,cookie会保存在浏览器端
  • 下次访问的时候,浏览器会携带服务器端创建的cookie(请求头cookie),服务器端就可以拿到这些cookie携带的数据区分不同的用户,并拿到对应的信息

在这里插入图片描述

注意:

  • cookie不能跨浏览器
  • cookie不支持中文
3.3 Session(服务器端会话技术)
  • 浏览器端第一次发送请求到服务器端,服务器端会创建一个Session,同时会创建一个特殊的Cookie(name: JSESSIONID ,value: sessionid),然后将该cookie发送给浏览器端
  • 当浏览器端下次访问服务器端时,都会携带这份JSESSIONID的Cookie对象
  • 服务器端会根据对应的sessionid会查询Session对象,从而区分不同的用户

在这里插入图片描述

session的生命周期

  • 创建 : 第一次访问服务器,调用getSession()方法获取session会话的时候
  • 销毁 : (1) 服务器非正常关闭 (2) 设置超时时间(默认tomat服务器是30分钟) (3)浏览器关闭(手动销毁)
3.4 Cookie和Session的区别
  • 数据保存的位置不同 : Cookie数据保存在客户端,而Session数据保存在服务器端
  • 安全性不同 : cookie信息一般是以明文的方式存放在客户端的,安全性比较低,可以通过一个加密算法进行加密存放;session信息存放在服务器的内存中,安全性较好(所以我们一般将用户密码等安全级别较高的信息存放在session中)
  • 存储大小的限制 : 单个cookie在客户端的限制为4k,就是说一个站点在客户端存放的cookie不能超过3k;session一般没有限制,存放在服务器端的内存中,但是访问过多,会增加服务器的内存和性能.
  • cookie为多个用户浏览器共享; session为一个用户浏览器独享
3.5设置失效时间

session:

关闭浏览器,只会使浏览器中的sessionid消失,但不会使服务端的session对象消失。因此服务端需要设置一个过期时间,当距离客户上一次使用session的时间超过了这个失效时间时就认为客户端已经停止了活动,从而删除session。session.setMaxInactiveInterval(3600);

cookie:

  1. 当设置失效时间大于1天时
Cookies.set('name', 'value', {
  expires: 7, //设置失效时间为7天
});

  • 1
  • 2
  • 3
  • 4
  1. 当设置失效时间小于1天时,需要在当前时间上加上失效时间
var millisecond = new Date().getTime();
var expiresTime = new Date(millisecond + 60 \* 1000 \* 15); //设置过期时间为15分钟后
 
Cookies.set('name', 'value', {
  expires: expiresTime, //如果设置一个过去的时间点会直接删除
});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.sessionStorage和localStorage的区别

sessionStorage和localStorage均用于客户端本地存储数据

localStroage

不能设置过期时间。生命周期是永久性的,即使关闭浏览器也不会让数据消失,除非主动去删除数据。

if(window.localStroage){ //判断浏览器是否支持localstroage
  window.localStroage.setItem('name','zs') //存储数据
  window.localStroage.getItem('name') //获取数据
  window.localStroage.removeItem('name') //移除数据
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
sessionStroage

生命周期是在浏览器关闭前,在浏览器关闭前,其数据一直存在。使用方法与localStroage一致。

  1. 页面刷新不会消除数据
  2. 只有在当前页面打开的链接,才可以访问sessionStroage

5.垃圾回收机制(招银网络)

标记清除

当变量进入环境时,例如:在一个函数中声明一个变量,就将这个变量标记为“进入环境”;当变量离开时,则将其标记为离开环境。

(从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能还会用到它们)

引用计数

跟踪记录每个值被引用的次数。

当申明了一个变量并将一个引用类型值A赋给该变量时,则这个引用类型值A的引用次数就是1。如果同一个引用类型值A被赋给另一个变量,则这个引用类型值A的引用次数+1;相反,如果包含这个引用类型值A的变量又取得了另外一个引用类型值B,则这个引用类型值A的引用次数-1;当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。

循环引用

function circularReference() {
  	let obj1 = {
	};
	let obj2 = {
 	 b: obj1
	};
	obj1.a = obj2;
}
//当obj1这个变量指向obj1这个对象时,obj1这个对象的引用计数为1
//当obj2这个变量指向obj2这个对象时,obj2这个对象的医用计数为1;obj2中的b属性指向obj1,obj1这个对象的引用计数变为2
//obj1的a属性指向obj2,obj2这个对象的引用计数变为2

//当代码执行完毕,会将obj1和obj2赋值为null,但此时obj1对象和obj2对象的引用计数仍为1,不为0,所以不会进行垃圾回收,造成垃圾泄露。
//这两个对象已经没什么作用了,在函数外部也访问不到他们。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
深拷贝如何解决循环引用(腾讯)

解决问题的关键也就是可以将这些引用存储起来并在发现引用时返回被引用过的对象,从而结束递归的调用。

原理:

利用uniqueList存储拷贝过的对象,如果之前拷贝过就把他的拷贝结果返回,否则遍历该对象的各个属性,是对象的话继续深拷贝,不是对象就直接赋值

	//arr中存储了多个对象
	//[{source:xxx, target:xxx},{source:xxx, target:xxx},]
	function find(arr,item){
        for(var i=0; i<arr.length; i++){
            if(arr[i].source === item){
                return arr[i] //返回的是这整个对象{source:xxx, target:xxx}
            }
        }
        return null;
    }
    function isObject(obj) {
        return typeof obj === 'object' && obj != null;
    }
 
    function deepClone(source,uniqueList){
        //被拷贝的source必须是对象
        if(!isObject(source)) return source;
        if(!uniqueList) uniqueList = [];    //初始化数据
        //存储结果
        var target = Array.isArray(source) ? [] : {};
        var uniqueData = find(uniqueList,source);    //在初始化数据中查看是否存在source
        if(uniqueData) return uniqueData.target;
        uniqueList.push({
            source:source, //拷贝源
            target:target  //拷贝结果
        });
 
        for(var key in source){
            if(Object.prototype.hasOwnProperty.call(source,key)){
                if(isObject(source[key])){
                    target[key] = deepClone(source[key], uniqueList)      // 传入数组
                }else{
                    target[key] = source[key];
                }
            }
        }
        
        return target;
    }
    var a = {
        name:"key1",
        eat:[
            "苹果",
            "香蕉"
        ]
    }
    a.eat[2] = "桃";
    a.d = a;
    console.log(a);
//{name: "key1", eat: Array(3), d: {
// {name: "key1", eat: Array(3), d: {…}}
//}}
    b = deepClone(a);
    console.log(b);
//{name: "key1", eat: Array(3), d: {
// {name: "key1", eat: Array(3), d: {…}}
//}}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

6.跨域

同源策略是浏览器最核心也是最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

JsonP

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

缺点:只能实现get一种请求

 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);

    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

服务端返回如下(返回时即执行全局函数):

handleCallback({"status": true, "user": "admin"})

  • 1
  • 2

后端node.js代码示例:

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    var params = qs.parse(req.url.split('?')[1]);
    var fn = params.callback;

    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');

    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
跨域资源共享CORS

主要是后端设置,如果前端发送请求需要携带cookie,前端才需要设置

前端设置:

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端设置是否带cookie
xhr.withCredentials = true;

xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

后端设置

/\*
 \* 导入包:import javax.servlet.http.HttpServletResponse;
 \* 接口参数中定义:HttpServletResponse response
 \*/

// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 

// 允许前端带认证cookie:启用此项后,上面的域名不能为'\*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 

// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
nginx代理

同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

前端请求:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

代理服务器处理请求:

#proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;

    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为\*
        add_header Access-Control-Allow-Credentials true;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

后台:

var http = require('http');
var server = http.createServer();
var qs = require('querystring');

server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));

    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });


### 最后

基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/936982
推荐阅读
相关标签
  

闽ICP备14008679号