跳到主要内容

互联网、浏览器相关知识点

关于浏览器相关知识点总结, 持续更新中……

文章主要包含以下内容:

  • 互联网相关知识
  • 浏览器相关知识

互联网相关知识

HTTP 是什么?

  • HTTP 是超文本传输协议,也就是HyperText Transfer Protocol。主要包含超文本、传输、协议。具体就不多介绍,网上资料还是很多的。
  • HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」(协议)。

HTTP 的状态码有哪些?

  • 1XX
    • 接受,继续处理, 实际用到的很少
    • 【101】 切换请求协议
  • 2XX
    • 表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
    • 【200】是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。
    • 【204】也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
    • 【206】是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
  • 3XX
    • 这类状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
    • 【301】表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
    • 【302】表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
    • 【304】不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
    • 【307】临时重定向,和302的唯一区别在于307 状态码会保证请求方法和消息主体不会改变
  • 4XX
    • 这类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
    • 【400】请求语法错误
    • 【401】没权限,未授权
    • 【403】拒绝请求
    • 【404】资源不存在
  • 5XX
    • 【500】服务器报错
    • 【501】表示客户端请求的功能服务端还不支持,类似『开发中,敬请期待』的意思
    • 【502】通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
    • 【503】表示服务器当前很忙,暂时无法响应服务器,类似『网络服务正忙,请稍后重试』的意思。

HTTP 请求方式

  • GET 对服务器资源获取的简单请求
  • POST 用于发送包含用户提交数据的请求
  • PUT 向服务器提交数据, 以修改数据
  • DELETE 删除服务器上的某些资源
  • HEAD 请求页面的头部,获取资源的元信息
  • OPTIONS 返回所有可用的方法,常用于跨域
  • CONNECT 用于ssl隧道的基于代理的请求
  • TRACE 追踪请求-响应传输的路径

常见HTTP 请求头和响应头

  • 请求头
    • Accept 浏览器能够处理的内容类型
    • Accept-Charset 浏览器能够显示的字符集
    • Accept-Encoding 浏览器能够处理的压缩编码
    • Accept-Language 浏览器当前设置的语言
    • Connection 浏览器和服务器之间的链接类型
      • keep-alive 是保证我们的http请求能建立一个持久连接, 也就是说建立一次TCP连接即可进行多次「请求和响应的交互。它的特点就是只要有一方没有明确提出断开连接,则保持TCP连接状态,减少TCP连接和断开造成的额外开销。
    • Cookie 当前页面设置的cookie
    • Host 发出请求页面的域
    • Referer 发出请求页面的URL
    • User-Agent 浏览器的用户代理字符串
  • 响应头
    • Date 表示消息发送的时间,时间的描述格式由 rfc822 定义
    • server 服务器名称
    • Connection 浏览器与服务器之间连接的类型
    • Cache-Control 控制http 缓存
    • content-type 文档类型
      • application/json 服务器返回序列化厚的 JSON 字符串
      • application/x-www-form-urlencoded 浏览器原生 form表单,注意是按照key=val&key=value 的格式
      • multipart/form-data 通常用于 post 请求上传文件时
      • text/xml xml格式数据

常用了解的端口对应的服务

  • 21 FTP 文件传输协议
  • 22 ssh
  • 23 Telnet 远程登录服务
  • 25 SMTP 简单邮件传输协议
  • 53 DNS 域名服务器
  • 80 HTTP 超文本传输协议
  • 110 POP3 邮件传输协议3
  • 443 HTTPS
  • 1080 Sockets
  • 1521 Oracle 数据库默认端口
  • 3306 Mysql 数据库默认端口

HTTP 演变过程

早期 HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无畏的 TCP 连接建立和断开,增加了通信开销。

下图为 HTTP/1.0 短链接 和 HTTP/1.1 长连接 keep-alive 的图解:

一张图来概括 HTTP 的演变过程,包括 HTTP/1.1、HTTPS、HTTP/2、HTTP/3 的区别

由上图可以看出,HTTP 和 HTTPS 的主要区别:

  • 在HTTP和TCP中插入了 SSL/TLS 安全协议;
  • HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输;
  • 除此之外,HTTP 的端口号是 80,HTTPS 的端口号是 443;
  • HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

HTTP 的演变过程:

  • HTTP/1.0
    • 无法复用链接,完成即断开,重新慢启动和 TCP 3次握手
    • head of line blocking: 线头阻塞,导致请求之间互相影响
  • HTTP/1.1
    • keep-alive 长连接 可复用,
    • 管道 pipeline 只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。当然管道是必须基于 keep-alive 确认之后才可以使用。
    • 新增了 断点续传 Content-Range 头、身份认证、状态管理、cache缓存(这点下面我们会仔细讲下HTTP的缓存)
    • host 字段指定对应的虚拟站点
  • HTTP/2.0
    • 多路复用
      • HTTP/2 是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。
      • 多个请求也就造就了HTTP/2 的缺点,丢包现象发生,一旦丢包,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
      • 移除了 HTTP/1.1 中的串行请求,不需要排队等待,也就不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接的利用率。
    • 二进制分帧层:应用层、传输层
    • 首部压缩
      • HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的分
      • 这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
    • 服务端推送
      • HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。
      • 举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push,也叫 Cache Push)。
  • HTTP/3.0
    • 基于2.0 出现的丢包现象,不过这都是基于 TCP 传输层的问题,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!
    • UDP 发生是不管顺序,也不管丢包的,所以不会出现 HTTP/1.1 的队头阻塞 和 HTTP/2 的一个丢包全部重传问题。
    • 大家都知道 UDP 是不可靠传输的,但基于 UDPQUIC 协议 可以实现类似 TCP 的可靠性传输。QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响。
    • TL3 升级成了最新的 1.3 版本,头部压缩算法也升级成了 QPack
    • HTTPS 要建立一个连接,要花费 6 次交互,先是建立三次握手,然后是 TLS/1.3 的三次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数。

计算机网络体系结构

从输入 url 到展示的过程

  • DNS 解析

  • TCP 三次握手

  • 发送请求,分析 url,设置请求报文(头,主体)

  • 服务器返回请求的文件 (html)

  • 浏览器渲染

    • HTML parser --> DOM Tree

      • 标记化算法,进行元素状态的标记
      • dom 树构建
    • CSS parser --> Style Tree

      • 解析 css 代码,生成样式树
    • attachment --> Render Tree

      • 结合 dom树 与 style树,生成渲染树
    • layout: 布局

    • GPU painting: 像素绘制页面

  • TCP 四次挥手

这里涉及到的就是一些面试中常用的 TCP 三次握手、四次挥手:

TCP 三次握手:

建立连接前,客户端和服务端需要通过握手来确认对方:

  • 客户端发送 syn(同步序列编号) 请求,进入 syn_send 状态,等待确认;
  • 服务端接收并确认 syn 包后发送 syn+ack 包,进入 syn_recv 状态;
  • 客户端接收 syn+ack 包后,发送 ack 包,双方进入 established 状态

TCP 四次挥手:

所谓四次挥手,实际就是客户端和服务器连接结束之后,互相拆台,解除连接的这么一个过程

  • 客户端 -- FIN --> 服务端, FIN—WAIT;
  • 服务端 -- ACK --> 客户端, CLOSE-WAIT;
  • 服务端 -- ACK,FIN --> 客户端, LAST-ACK;
  • 客户端 -- ACK --> 服务端,CLOSED

推荐这篇文章,讲三次握手和四次挥手

WebSocket

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输, 用来弥补http协议在持久通信能力上的不足。

优点:

  • 支持双向通信,实时性更强。
  • 更好的二进制支持。
  • 较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
  • 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)

nodejs 的包 ws,或者使用socket.io

浏览器相关知识点

浏览器下事件循环(Event Loop)

由于js 是单线程运行,在代码执行是,通过将不同的执行上下文压入执行栈来确保有序执行。在执行过程中,如果遇到异步事件,js并不会一直等待返回结果,而是会将这个事件挂起,继续执行其他执行栈中的任务,当异步执行栈完成后,js会将异步执行的回调放入一个任务队列中等待执行。这里也就意味着任务队列分为了 宏任务,微任务。

事件循环是指:执行一个宏任务,然后执行清空微任务列表,循环再执行宏任务,再清微任务列表

  • 微任务:microtask(jobs): promise / ajax 等
  • 宏任务:macrotask(task): setTimout / script / IO / UI Rendering 等

重绘与回流

  • 重绘 重绘是指:当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少。
  • 回流 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。所以只要回流那必定会触发重绘,但是重绘不一定会触发回流,因此回流的代价比较大。 此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。会触发回流的操作:
    • 页面初始化,首次加载
    • 浏览器窗口发生变化
    • 元素的尺寸、位置、内容、字体大小等发生改变
    • 添加,删除可见dom 元素
    • 激活 CSS 伪类,如::hover, :active
    • 查询某些属性,或者调用一些方法
      • clientWidth、clientHeight、clientTop、clientLeft
      • offsetWidth、offsetHeight、offsetTop、offsetLeft
      • scrollWidth、scrollHeight、scrollTop、scrollLeft
      • getComputedStyle(), getBoundingClientRect(), scrollTo()

浏览器存储

我们经常需要对业务中的一些数据进行存储,通常可以分为 短暂性存储 和 持久性储存。

  • 短暂性的时候,我们只需要将数据存在内存中,只在运行时可用
  • 持久性存储,可以分为 浏览器端 与 服务器端
    • 浏览器:cookiesessionStoragelocalStorageindexDB
      • cookie 通常用于存储用户身份,登录状态等
      • localStorage/sessionStorage 长久储存/窗口关闭删除, 体积限制为 4~5M
    • 服务器:分布式 redis、直接存储到数据库

Web Worker

现代浏览器为 JavaScript 创造的 多线程环境。可以新建并将部分任务分配到 worker 线程并行运行,两个线程可 独立运行,互不干扰,可通过自带的 消息机制 相互通信。

// 创建 worker
const worker = new Worker('work.js');

// 向 worker 线程推送消息
worker.postMessage('Hello World');

// 监听 worker 线程发送过来的消息
worker.onmessage = function (event) {
console.log('Received message ' + event.data);
}

当然使用 worker 也是存在限制的:

  • 同源限制
  • 无法使用 document / window / alert / confirm
  • 无法加载本地资源

V8垃圾回收机制

垃圾回收: 将内存中不再使用的数据进行清理,释放出内存空间。V8 将内存分成 新生代空间 和 老生代空间。

  • 新生代空间: 用于存活较短的对象,又分成两个空间: from 空间 与 to 空间

    • Scavenge GC算法: 当 from 空间被占满时,启动 GC 算法

    • 存活的对象从 from space 转移到 to space

    • 清空 from space

    • from space 与 to space 互换

    • 完成一次新生代GC

  • 老生代空间: 用于存活时间较长的对象

    • 从 新生代空间 转移到 老生代空间 的条件

      • 经历过一次以上 Scavenge GC 的对象
      • 当 to space 体积超过25%
    • 标记清除算法: 标记存活的对象,未被标记的则被释放

      • 增量标记: 小模块标记,在代码执行间隙执,GC 会影响性能
      • 并发标记(最新技术): 不阻塞 js 执行
    • 压缩算法: 将内存中清除后导致的碎片化对象往内存堆的一端移动,解决 内存的碎片化

内存泄露

  • 意外的全局变量: 无法被回收
  • 定时器: 未被正确关闭,导致所引用的外部变量无法被释放
  • 事件监听: 没有正确销毁 (低版本浏览器可能出现)
  • 闭包: 会导致父级中的变量无法被释放
  • dom 引用: dom 元素被删除时,内存中的引用未被正确清空

可用 chrome 中的 timeline 进行内存标记,可视化查看内存的变化情况,找出异常点。

浏览器缓存

所谓缓存,就是当我们第一次访问网站的时候,比如 torli.top,电脑会把网站上的图片和数据下载到电脑上,当我们再次访问该网站的时候,网站就会从电脑中直接加载出来,这就是缓存。

浏览器缓存分为: 强缓存、协商缓存

浏览器缓存位置一般分为四类: Service Worker --> Memory Cache --> Disk Cache --> Push Cache。

二者区别

  1. 强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,所以资源是否更新,服务器肯定知道。
  2. 大部分web服务器都默认开启协商缓存。 目前的项目大多使用这种缓存方案的: HTML: 协商缓存;css、js、图片:强缓存,文件名带上hash。
  • 强缓存

    强缓存是当我们访问URL的时候,不会向服务器发送请求,直接从缓存中读取资源,但是会返回200的状态码。

    我们第一次进入页面,请求服务器,然后服务器进行应答,浏览器会根据response Header来判断是否对资源进行缓存,如果响应头中expires、pragma或者cache-control字段,代表这是强缓存,浏览器就会把资源缓存在memory cache 或 disk cache中。

    这里的 expires 是HTTP/1.0 中的,不过存在的问题是,缓存时间是根据浏览器客户端的时间来判断缓存是否过期,但是本地的时间呢是可以修改的;

    pragma 是 HTTP/1.0 中的不可使用缓存,值为 no-cache,和 cache-control: no-cache 一样的效果

    cache-control 是 HTTP/1.1 中控制网页缓存的字段,当Cache-Control都存在时,Cache-Control优先级更高,属性值有:

    • public 资源客户端和服务器都可以缓存。
    • privite 资源只有客户端可以缓存。
    • no-cache 客户端缓存资源,但是是否缓存需要经过协商缓存来验证。
    • no-store 不使用缓存。
    • max-age 缓存保质期。使用它,解决了 expires 的问题

    第二次请求时,浏览器判断请求参数,如果符合强缓存条件就直接返回状态码200,从本地缓存中拿数据。否则把响应参数存在request header请求头中,看是否符合协商缓存,符合则返回状态码304,不符合则服务器会返回全新资源。

  • 协商缓存

    协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程。主要有以下两种情况:

    • 协商缓存生效,返回304
    • 协商缓存失效,返回200和请求结果

    设置协商缓存

    • Last-Modified / If-Modified-Since
      • Last-Modified 是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
      • If-Modified-Since 则是客户端再次发起该请求时,携带上次请求返回的 Last-Modified 值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。 服务器收到该请求,发现请求头含有 If-Modified-Since 字段,则会根据 If-Modified-Since 的字段值与该资源在服务器的最后被修改时间做对比, 若服务器的资源最后被修改时间大于 If-Modified-Since 的字段值, 则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。
    • Etag / If-None-Match
      • Etag Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
      • If-None-Match If-None-Match 是客户端再次发起该请求时,携带上次请求返回的唯一标识 Etag 值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match ,则会根据 If-None-Match 的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。

    刷新对于强缓存和协商缓存的影响

    • 当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。
    • 当f5刷新网页时,跳过强缓存,但是会检查协商缓存。
    • 浏览器地址栏中写入URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

跨域

什么是同源策略

同源策略是指协议、端⼝、域名相同,也就是在同⼀个域中。

⾮同源受到的限制:

cookie⽆法读取、dom⽆法获取、ajax请求⽆法发送。

什么是跨域:

两个不同域(协议、端⼝、域名不同)之间进⾏请求。

解决跨域的⽅法:

  • JSONP,通过动态创建⼀个script标签,script标签的src属性是没有跨域的限制的。
  • CORS,服务端在response时增加⼀些头信息: Access-Control-Allow-Origin: "".
  • Nginx做反向代理
  • 开发环境跨域使⽤ webpack-dev-server 的 proxy
  • postMessage

一般常用的是 CORS 和 Nginx 代理的方式

安全

  • XSS攻击: 注入恶意代码

  • 常用防范措施:

    • cookie 设置 httpOnly
    • 转义页面上的输入内容和输出内容
  • CSRF: 跨站请求伪造,防护

  • 常用防范措施:

    • get 不修改数据
    • 不被第三方网站访问到用户的 cookie
    • 设置白名单,不被第三方网站请求
    • 请求校验
  • SQL 注入攻击 来自用户的数据(GET、POST、Cookie 等)最好做到以下两种过滤校验:

    • 检查输入的数据是否具有所期望的数据格式。这种在参数是数字的时候特别有效,如果攻击者选择在参数中插入内容的话则会被转换成 NaN 导致攻击失败。
    • 使用数据库特定的敏感字符转义函数把用户提交上来的非数字数据进行转义。
    • 严格限制 Web 应用的数据库的操作权限,给此用户提供仅仅能够满足其工作的最低权限,从而最大限度的减少注入攻击对数据库的危害。
    • 日志处理,当数据库操作失败的时候,尽量不要将原始错误日志返回,比如类型错误、字段不匹配等,把代码里的 SQL 语句暴露出来,以防止攻击者利用这些错误信息进行 SQL 注入。
  • DDoS 攻击 这个就不具体讲了,类型种类以及编种太多了。一言难尽呐!

    不过这类攻击判断方式也很简单: 服务器 CPU 占用率很高;出现大量的 SYN_RECEIVED 的网络连接状态;网络恢复后,服务器负载瞬时变高。网络断开后瞬时负载下降。

点击刷新按钮或者F5,按CTRL+ F5(强制刷新),地址栏回车三种方式的区别

  • 点击F5 刷新,浏览器会对本地的缓存文件过期,但是会带上 If-Modifed-Since,If-None-Match, 相当于服务器会对文件检查新鲜度,如果更新则请求返回200,如果没更新,则继续使用缓存,返回304。
  • 强制刷新,浏览器不会对本地文件过期,而且不会带上面的判断参数,相当于第一次请求,返回结果是200。
  • 地址栏回车,浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。

单点登录

单点登录是一个身份验证机制,英文全称 Single Sign On,简称 SSO。它的定义是:在多个应用系统中,用户只需要登录一次,即可访问所有相互信任的应用系统,就像健康保一样,为你的身份做担保。

单点登录 SSO 可以安全地确保员工只需要一组账号与密码,或通过标准协议认证、第三方身份源认证,就可以登录所有被授权的应用系统。例如,员工只需要登录个人 OA 系统的账号密码就可以访问飞书、销售易、客户系统等应用程序,无需再次输入账号和密码。

SSO 一般都需要一个独立的认证中心(passport),子系统的登录均得通过 passport,子系统本身将不参与登录操作,当一个系统成功登录以后,passport 将会颁发一个令牌给各个子系统,子系统可以拿着令牌会获取各自的受保护资源,为了减少频繁认证,各个子系统在被 passport 授权以后,会建立一个局部会话,在一定时间内可以无需再次向 passport 发起认证。

具体流程是:

  • 用户访问系统 1 的受保护资源,系统 1 发现用户未登录,跳转至 sso 认证中心,并将自己的地址作为参数
  • sso 认证中心发现用户未登录,将用户引导至登录页面
  • 用户输入用户名密码提交登录申请
  • sso 认证中心校验用户信息,创建用户与 sso 认证中心之间的会话,称为全局会话,同时创建授权令牌
  • sso 认证中心带着令牌跳转会最初的请求地址(系统 1)
  • 系统 1 拿到令牌,去 sso 认证中心校验令牌是否有效
  • sso 认证中心校验令牌,返回有效,注册系统 1
  • 系统 1 使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
  • 用户访问系统 2 的受保护资源
  • 系统 2 发现用户未登录,跳转至 sso 认证中心,并将自己的地址作为参数
  • sso 认证中心发现用户已登录,跳转回系统 2 的地址,并附上令牌
  • 系统 2 拿到令牌,去 sso 认证中心校验令牌是否有效
  • sso 认证中心校验令牌,返回有效,注册系统 2
  • 系统 2 使用该令牌创建与用户的局部会话,返回受保护资源