1. 说一下 GET 和 POST 的区别?

  • GET 在浏览器回退时是 无害的,而 POST再次提交 请求

  • GET 请求只能进行 url 编码,而 POST 支持 多种编码 方式

  • GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会保留

  • GET 请求参数通过 URL 传递 且参数是 有长度限制 的(2083 字符,中文字符的话只有 2083/9=231 个字符),而 POST 参数放在 Request body 中是没有限制的

    注意HTTP 协议 未规定 GETPOST 的长度限制;GET 的最大长度显示是因为 浏览器web 服务器 限制了 URI 的长度。不同的 浏览器WEB 服务器,限制的最大长度不一样,要支持 IE,则最大长度为 2083byte,若只支持 Chrome,则最大长度 8182byte

  • 对参数的数据类型,GET 只接受 ASCII 字符(如果非 ASCII 字符会进行 转码),而 POST 没有限制

  • GETPOST 本质上就是 TCP 连接, GET 产生 一个 TCP 数据包POST 产生 两个 TCP 数据包

    注意:并不是所有浏览器都会在 POST 中发送两次包,Firefox 就只发送一次

    1. 对于 GET 方式的请求,浏览器会把 http headerdata 一并发送出去,服务器响应 200(返回数据)
    2. 对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)

2. HTTP1.0、HTTP1.1、HTTP2、HTTP3 的区别?

HTTP 1.0(1996 年)

  • 任意数据类型都可以发送
  • GETPOSTHEAD 三种方法
  • 无法复用 TCP 连接(长连接)
  • 有丰富的请求响应头信息。以 header 中的 Last-Modified/If-Modified-SinceExpires 作为缓存标识

HTTP 1.1(1997 年)

  • 引入更多的请求方法类型 PUTPATCHDELETEOPTIONSTRACECONNECT
  • 引入 长连接,就是 TCP 连接 默认不关闭,可以被多个请求复用,通过请求头 connection: keep-alive 设置
  • 引入 管道 连接机制,可以在同一 TCP 连接里,同时发送多个请求
  • 强化了缓存管理和控制 Cache-ControlETag/If-None-Match
  • 支持 分块响应断点续传,利于大文件传输,能过请求头中的 Range 实现

HTTP 2.0(2015 年)

  • 使用新的 二进制协议,不再是纯文本,避免文本歧义,缩小了请求体积
  • 多路复用,同域名下所有通信都是在单链接(双向数据流)完成,提高连接的复用率,在拥塞控制方面有更好的能力提升
  • 允许服务端主动推送数据给客户端
  • 使用 HPACK 算法将 头部压缩,用 哈夫曼编码 建立索表,传送索引大大节约了带宽

HTTP 3.0/QUIC

缺点:主要是连接缓慢,服务器只能按顺序响应,如果某个请求花了很长时间,就会出现请求 队头阻塞

HTTP1 和 HTTP2

  • HTTP2 是一个 二进制协议HTTP1超文本协议,传输的内容都不是一样的
  • HTTP2 报头压缩,可以使用 HPACK 进行头部压缩,HTTP1 则不论什么请求都会发送
  • HTTP2 服务端推送(Server push),允许服务器预先将网页所需要的资源 push 到浏览器的内存当中
  • HTTP2 遵循 多路复用,代替同一域名下的内容,只建立一次连接,HTTP1.x 不是,对域名有 6~8 个连接限制

HTTP 请求方法(9 种)

HTTP1.0GETPOSTHEAD

HTTP1.1PUTPATCHDELETEOPTIONSTRACECONNECT

HTTP 全称 Hyper Text Transfer Protocol,即超文本传输协议。HTTP 是一个 应用层协议

HTTP 的报文结构:请求行 + 请求头 + 请求体

Accept 字段与 Content-type 字段:

  • Accept: 用于客户端向服务器发送报文时表示自己可接收的响应内容类型,如:Accept: text/plain (文本类型)
    1. Accept-Charset: 表示可接收的字符集
    2. Accept-Encoding: 表示可接受的响应内容的压缩方式
    3. Accept-Language: 表示可接受的响应内容语言列表
    4. Accept-Datetime: 表示可接受的按照时间来表示的响应内容版本
  • Content-Type: 字段用于服务器回应时,告诉客户端,本次数据的格式是什么
    1. Content-Encoding: 表示服务器返回的数据使用什么压缩格式
  • Host 字段: 用于客户端发送请求时,用来指定服务器的域名。例如:Host: www.baidu.com
  • Connection 字段: 最常用于客户端要求服务器使用 TCP 持久连接,以便其他请求复用 keep-alive
  • Content-Length 字段: 表明本次回应的数据长度

HTTP 存在的问题

  • 性能问题

    HTTP/1.0 中,每次发起一个 HTTP 请求,都需要去建立一次 TCP 连接,而且还是串行请求,这使得 HTTPTCP 的连接 建立上花费了大量的开销。对于这种问题,HTTP/1.1 中提出了长连接的通信方式,也叫持久连接好处: 在于减少了 TCP 连接 的重复建立和断开所造成的额外开销,减轻了服务器端的负载

    HTTP/1.1 采用了 长连接 的方式,使得管道(Pipeline)网络传输成为了可能。即在同一个 TCP 连接 里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。但是 服务器还是按照顺序,先回应第一个请求,完成后再回应第二个请求,以此类推。要是前面的请求回应得特别慢,后面就会有许多请求阻塞着,这就是所谓的【队头阻塞

总结HTTP/1.0 或是 HTTP/1.1 性能都不是很完美

  • 安全问题

    HTTP 的内容是 明文传输 的,明文数据会经过 中间代理服务器路由器WIFI热点通信服务运行商 等多个物理节点,如果信息在传输过程中被劫持,传输的内容久完全暴露了,劫持者还可以篡改传输的信息且不被双方察觉,这就是 中间人攻击

    总结一下,HTTP 在安全方面有以下三个问题:

    1. 使用明文通信,一些重要的内容会被窃听
    2. 不能验证对方身份,可能是伪造的信息
    3. 无法验证报文的完整性,有可能被修改

HTTP/2 有哪些改进?

  1. 头部压缩
  2. 多路复用
  3. 服务器推送
  4. 二进制传输

HTTP 的特点和缺点

  • 特点:无连接 (请求完就断开,不保持连接)、无状态 (每个请求都是独立的)、灵活 (http 协议中头部的 Content-Type 标记,可以传输任意数据类型的数据对象(文本、图像、视频等。比较灵活))、简单快速 (请求访问某个资源时,只需传送请求方法和 URL 就可以了,使用简单)

  • 缺点:无状态不安全 (明文传输可能被窃听不安全,缺少身份认证也可能遭遇伪装,还有缺少报文完整性验证可能遭到篡改)、明文传输队头阻塞 (一个TCP连接,同一时刻只能处理一个请求,那么当请求耗时过长时,其他请求就只能阻塞状态)

  • 什么是 持久连接/长连接?

    http1.0 协议采用的是 "请求-应答" 模式,每个请求/应答客户与服务器都要新建一个连接,完成之后立即断开连接(http 协议为无连接的协议)

    http1.1 版本支持 长连接,即请求头添加 Connection: Keep-Alive,使用 Keep-Alive 模式(又称 持久连接连接复用)建立一个 TCP 连接后使客户端到服务端的连接持续有效,可以发送/接受多个 http 请求/响应,当出现对服务器的后续请求时,Keep-Alive 功能避免了建立或者重新建立连接

    • 长连接优缺点?
      • 优点
        1. 减少 CPU 及内存的使用,因为不需要经常建立和关闭连接
        2. 支持管道化的请求及响应模式
        3. 减少网络堵塞,因为减少了 TCP 请求
        4. 减少了后续请求的响应时间,因为不需要等待建立 TCP、握手、挥手、关闭 TCP 的过程
        5. 发生错误时,也可在不关闭连接的情况下进行错误提示
      • 缺点
        1. 一个长连接建立后,如果一直保持连接,对服务器来说是多么的浪费资源呀,而且长连接时间的长短,直接影响到服务器的并发数
        2. 还有就是可能造成 队头堵塞
    • 如何避免长连接资源浪费?
      1. 客户端请求头声明:Connection: close,本次通信后就关闭连接
      2. 服务端配置:如 Nginx,设置 keepalive_timeout 设置 长连接超时时间keepalive_requests 设置 长连接请求次数上限
  • 什么是 管线化(管道化)?

    请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3

    请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3

    管线化: 是在同一个 TCP 连接发一个请求后不必等其回来就可以继续发请求出去,这可以减少整体的响应时间,但是服务器还是会按照请求的顺序响应请求,所以如果有许多请求,而前面的请求响应很慢,就产生一个著名的问题 队头堵塞

    • 管线化 的特点:
      1. 管线化 机制通过 持久连接 完成,在 http1.1 版本才支持
      2. 只有 GET 请求和 HEAD 请求才可以进行管线化,而 POST 有所限制
      3. 管线化 不会影响响应到来的顺序,响应返回的顺序就是请求的顺序
      4. 初次创建连接时不应启动管线化机制,因为服务器不一定支持 http1.1 版本的协议
  • 如何解决 HTTP队头阻塞 问题?

    1. 并发连接 (现在的浏览器标准中一个域名并发连接可以有 6~8 个,记住是 6~8 个,不是 6 个(Chrome6 个/Firefox8 个))

    2. 域名分片 (一个域名最多可以并发 6~8 个,那咱就多来几个域名,多准备几个二级域名,可以让不同的资源从不同的二域名中获取,而它们都指向同一台服务器,这样能够并发更多的长连接了)

      注意:在 HTTP2.0 下,可以一瞬间加载出来很多资源,因为支持 多路复用,可以在一个 TCP 连接中发送多个请求

3. DNS 解析过程及原理?回源是什么?DNS 劫持听说过吗?

  • 解析域名的查找过程:

    浏览器的 DNS 缓存 -> 操作系统的 DNS 缓存 -> 本地域名服务器(递归查询 自己的 DNS 缓存) -> 上级域名服务器(进行迭代查询)【本地域名服务器 -> 根域名服务器(会返回顶级域名的服务器地址); 本地域名服务器 -> 顶级域名服务器(返回权威域名服务器地址,全球 13 台) 】 -》解析到的 IP 地址返回给操作系统,并缓存起来。-》操作系统将 IP 地址返回给浏览器,并缓存起来,供下次使用。

DNS 劫持,是指通过 攻击域名解析服务器(DNS)或 伪造域名解析服务器(DNS)的方法,把目标网站域名解析到错误的 IP 地址从而实现用户无法访问目标网站的目的或者蓄意或恶意要求用户访问指定 IP 地址(网站)的目的。

  • 通常来说存在三种情况:
    1. 路由器 被入侵
    2. DNS 服务器 被入侵
    3. 运营商流量劫持

4. TCP 和 UDP 区别是什么?

TCP 是一个面向连接的(需要三次握手)、可靠的、基于字节流的传输层协议。而UDP 是一个面向无连接(无需建立连接)的传输层协议。(就这么简单,其它 TCP 的特性也就没有了)。

  • UDP 相比,TCP 有三大核心特性:

    1. 面向连接。所谓的连接,指的是客户端和服务器的连接,在双方互相通信之前,TCP 需要三次握手建立连接,而 UDP 没有相应建立连接的过程。

    2. 可靠性TCP 花了非常多的功夫保证连接的可靠,这个可靠性体现在哪些方面呢?一个是 有状态,另一个是 可控制

      TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是 有状态

      当意识到 丢包了 或者 网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的 发送速度 或者 重发。这是 可控制

      相应的,UDP 就是无状态, 不可控的

      • 为什么可靠?
        1. 顺序编号(tcp 在传输文件的时候,会将文件拆分为多个 tcp 数据包,会将这些数据包顺序编号)
        2. 确认机制(当数据包成功的被发送方发送给接收方,接收方会根据 tcp 协议反馈给发送方一个成功接收的 ACK 信号,信号中包含了当前包的序号)
        3. 超时重传(当发送方发送数据包给接收方时,会为每一个数据包设置一个定时器,当在设定的时间内,发送方仍没有收到接收方的 ACK 信号,会再次发送该数据包,直到收到接收方的 ACK 信号或者连接已断开)
        4. 校验信息(tcp 首部校验信息较多,udp 首部校验信息较少)
    3. 面向字节流UDP 的数据传输是基于数据包的,这是因为仅仅只是继承了 IP 层的特性,而 TCP 为了维护状态,将一个个 IP 包变成了 字节流

    4. tcp 连接过程中出现的延时增加了被攻击的可能,安全性不高,而 udp 不需要连接,安全性较高

    5. tcp 是可靠的,保证数据传输的正确性,不易丢包,udp 是不可靠的,易丢包

    6. tcp 传输速率较慢,实时性差,udp 传输速率较快

    7. tcp字节流 模式,udp数据包 模式

  • UDP 的特点:

    1. 无连接 : 不需要握手和挥手就可以直接发送数据
    2. 不可靠性
      • 为什么不可靠?
        1. 传输数据之前不需要先建立连接
        2. 不保证消息交付,远程主机的传输层在接收到 UDP 报文后,不需要确认
        3. 不保证将会顺序,不设置包序号、不重排、不会发生队首阻塞
        4. 不进行拥塞控制,没有内置反馈机制,不重传、无超时
    3. 支持广播
    4. 首部开销小: (tcp 建立连接需要耗时,并且 tcp 首部信息太多,每次传输的有用信息较少,实时性差)
    5. 是面向报文的
    6. 无拥塞控制
  • tcp/udp 的使用场合?

    1. 对数据可靠性的要求。tcp 适用于可靠性高的场合,udp 适用于可靠性低的场合
    2. 应用的实时性。tcp 有延时较大,udp 延时较小
    3. 网络的可靠性。网络不好的情况下使用 tcp,网络条件好的情况下,使用 udp

    UDP 适用于 实时应用,例如:视频会议、直播等。TCP 适用于要求 可靠性传输 的应用,例如:文件传输等。

5. 如何理解 TCP/IP 五层模型 OSI 七层模型?

TCP/IP 五层模型(应、传、网、数、物)

  1. 应用层:最高层,提供特定于应用程序的协议,运行在该层的协议有 HTTP、FTP、SSH、WebSocket 等
  2. 传输层:为两个主机进程通信提供通用的数据传输协议,如 TCP、UDP
  3. 网络层:负责寻址和路由功能,将数据包发送到特定的计算机,主要协议是 IP 协议,路由器就是在这一层
  4. 数据链路层:负责将二进制数据包和网络信号相互转换,交换机、网卡就是在这一层(PPP 协议)
  5. 物理层:主要有接收器、发送器、中继器、光纤电缆等

OSI 七层模型(应、表、会、传、网、数、物)

  1. 应用层
  2. 表示层
  3. 会话层
  4. 传输层
  5. 网络层
  6. 数据链路层
  7. 物理层

6. 为什么 HTTPS 比 HTTP 安全?HTTPS 是如何保证安全的?

HTTPS 在 HTTP 的基础上增加了加密处理认证机制完整性保护,我们可以将  HTTPS = HTTP + 加密 + 认证 + 完整性保护

  • 加密

    因为 HTTP 使用明文传输,中间会经过多个物理节点,可能会被劫持窃听,针对这一问题,HTTPS 采用了加密的方式解决

    1. 对称加密

      就是拥有一个密钥,在内容被进行加密后,需要用同一个密钥对加密内容进行解密,才能看到原本的内容。可以看作我们日常生活中的钥匙。注意:密钥在浏览器和服务器之间传输时,可能被截取,因此引入非对称加密

    2. 非对称加密

      非对称加密有两把密钥,通常一把叫做公钥,另外一把叫做私钥。用公钥加密的内容必须用私钥才能解开,同样的,私钥加密的内容需要用公钥才能解开。公钥加密私钥解密(数据加密) 也可用私钥加密公钥解密(签名)

    3. 改良版非对称加密

      通过一组公钥、私钥已经能保证单个方向传输的安全性,那用两组公钥私钥是不是就能保证双向传输都安全了(HTTPS 的加密却没有使用这种方案)。注意:原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心。相反,对称加密就要快很多。

    4. 混合加密(HTTPS 采用这种方式加密)

      思路:我们在传递过程把我们的 对称加密 中的 密钥非对称加密 的方式去传递

      • 对称加密 + 非对称加密”结合的形式来实现对 HTTP 的加密

        1. 客户端生成 会话秘钥 就是我们 对称加密生成的密钥
        2. 它用 公钥加密 之后进行传递(这个时候被加密的不是数据 是这个会话秘钥 等于把钥匙加密了) 这里的 公钥 就是 非对称加密中的公钥 他是由服务器传递过去的(对外公开
        3. 服务端用 非对称加密私钥解密 拿到我们的 会话秘钥
        4. 客户端和服务端都能用同一个会话秘钥进行加解密了

    就算传输过程被攻击者截取到了被加密的会话秘钥 他没有服务器的私钥是无法得到会话秘钥的。上一步我们已经解决了 数据加密 的问题 虽然攻击者无法 解密数据 但是他可以篡改数据 我们怎么知道数据没被动过呢?

  • 认证

    1. 中间人攻击
      1. 某网站拥有用于 非对称加密公钥 A私钥 A
      2. 浏览器向网站服务器发起请求,服务器把 公钥 A 明文给传输浏览器;
      3. 中间人劫持到公钥 A,保存下来,把数据包中的公钥 A 替换成自己伪造的公钥 B(它当然也拥有公钥 B 对应的私钥 B’);
      4. 浏览器随机生成一个用于 对称加密密钥 X,用 公钥 B(浏览器不知道公钥被替换了)加密后传给服务器;
      5. 中间人劫持后用私钥 B’ 解密得到密钥 X,再用公钥 A 将 X 加密后传给服务器;
      6. 服务器拿到后用 私钥 A 解密得到 密钥 X

    在双方都不会发生异常的情况下,中间人得到了 密钥 X,这其中的根本原因就是浏览器无法确认自己收到的公钥是不是网站的, 如何解决这一问题呢? - 数字证书

    1. 数字证书(解决 身份伪装 问题)

      如何证明浏览器收到的公钥一定是该网站的公钥?

      这里就需要有一个 公信机构 给网站颁发一个“身份证”了。网站在使用 HTTPS 前,需要向 “CA 机构” 申请颁发一份 数字证书,数字证书里有 证书持有者证书持有者的公钥 等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如同身份证一样,可以证明“该公钥对应该网站”。

      然而到这里还是有一个问题,如何保证证书在传输的过程不会被篡改身份证本身有防伪的技术,那么如何保证证书的防伪呢?

    2. 数字签名(解决 数据篡改 问题)

      • 如何保证证书不被篡改?

        我们把证书内容生成一份“签名”,比对 证书内容签名 是否一致就能察觉是否被修改,这种技术就称为: 数字签名

      • 数字签名的制作过程?

        1. CA 拥有 非对称加密私钥公钥
        2. CA 对证书明文信息进行 Hash
        3. Hash 后的值用 私钥 加密,得到 数字签名 S

        将明文和数字签名共同组成数字证书,这样一份证书就可以颁发给网站了。

      • 浏览器得到证书后如何验证这份证书的真实性?

        1. 拿到服务器发送过来的证书,得到 明文 T数字签名 S
        2. CA 机构公钥S 解密(由于是浏览器信任的机构,所以浏览器保有 CA 的公钥),得到 S‘;
        3. 浏览器用证书说明的 Hash 算法明文 T 进行 Hash 得到 T
        4. 比较 S 是否等于 T,等于则代表证书可信。
      • 浏览器如何得到权威机构的公钥?

        上面提到,如何要对服务器发过来的证书进行解密,那么就需要到 CA 的公钥,因为其被 CA 的私钥给加密了。那么浏览器是如何拥有 CA 的公钥呢?

        实际上权威机构的公钥并不需要传输,因为权威机构会和主流的浏览器或操作系统合作,将他们的公钥内置在浏览器或操作系统环境中。客户端收到证书之后,只需要从证书中找到权威机构的信息,并从本地环境中找到权威机构的公钥,就能正确解密 CA 公钥。

      • 中间人有可能篡改证书吗?(不可以)

  • HTTPS 的请求流程

    1. 客户端向服务器发起 HTTPS 请求,连接到服务器的 443 端口
    2. 服务器端有一个密钥对,即 公钥私钥,是用来进行非对称加密使用的,服务器端保存着 私钥,不能将其泄露,公钥 可以发送给任何人
    3. 服务器将自己的 公钥 包含在 权威机构发布的证书 中发送给客户端
    4. 客户端收到服务器端的 证书 之后,会对证书进行检查,验证其合法性,如果发现发现证书有问题,那么 HTTPS 传输就无法继续。严格的说,这里应该是验证服务器发送的 数字证书 的合法性,关于客户端如何验证数字证书的合法性。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行 对称加密密钥,我们将该密钥称之为 client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS 中的第一次 HTTP 请求结束;
    5. 客户端会发起 HTTPS 中的第二个 HTTP 请求,将被公钥所加密之后的客户端密钥发送给服务器
    6. 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是 客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文
    7. 然后服务器用对称加密的密钥(即客户端密钥)对报文进行加密,并将加密后的报文发送给客户端
    8. 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样 HTTPS 中的第二个 HTTP 请求结束,整个 HTTPS 传输完成

7. HTTP 常见的状态码有哪些?适用的场景?

  • 1.xx: 信息类
  • 2.xx: 成功类
    1. 【200 OK】:请求成功
    2. 【204 No Content】: 与 200 基本相同,但响应头没有 body 数据
    3. 【206 Partial Content】: 应用于 HTTP 分块下载断点续传。表示响应返回的 body 数据并不是资源的全部,而是其中的一分部
  • 3.xx: 重定向
    1. 【301 Moved Permanently】:永久重定向,说明请求资源不存在了,需改用新的 URL 再次访问
    2. 【302 Found】:临时重定向,说明请求资源还在,但暂时需要用另一个 URL 来访问
  • 4.xx: 客户端错误
    1. 【400 Bad Request】:表示客户端请求报文有错误
    2. 【403 Forbidden】: 表示服务器禁止访问资源,并不是客户端请求出错
    3. 【404 Not Found】:表示请求资源在服务器上不存在或未找到
  • 5.xx: 服务端错误
    1. 【500 Internal Server Error】:与 400 类似,是个笼统的错误码,表示服务器发生了错误
    2. 【501 No Implement】: 表示客户端请求的功能还不支持
    3. 【502 Bad Gatwy】:通常服务器作为网关或代理时返回的错误码
    4. 【503 Service Unavailable】: 表示服务器当前很忙,暂时无法响应

8. 知道 HTTP 的缓存吗?(浏览器强缓存和协商缓存)

强缓存: 是利用 Expireshttp1.0)和 Cache-Controlhttp1.1)这两个字段来控制的,控制资源缓存的时间,在有效期内不会去向服务器请求了,同时存在,优先 Cache-Control

  • Expires 的值为一个 绝对时间(由于 Expires 是依赖于客户端系统时间,当修改了本地时间后,缓存可能会失效)
  • Cache-Control 设置 max-age ,表示缓存的最长时间是多少秒,是一个 相对时间
  • Catch-Control 的值:public 都缓存;private 客服端缓存,服务器不缓存;no-cache:表示不进行强缓存,发送 HTTP 请求,用协商缓存来验证;no-store 所有内容都不缓存;s-maxage:这和 max-age 长得比较像,但是区别: 在于 s-maxage 是针对 代理服务器 的缓存时间

协商缓存: 是由服务器来确定缓存资源是否可用,是利用 Last-Modifiedhttp1.0)(表示被请求资源在服务器端的最后一次修改时间)/ If-Modified-SinceETag(每次文件修改后服务端那边会生成一个新的 ETag)/if-None-Match 来控制的,同时存在,优先 ETag

  • Last-Modified/if-Modified-Since缺点:(文件有可能在 1s 内修改内容、文件内容修改后又复原)

  • ETag 性能上的不足, 只要文件发生改变,ETag就会发生改变. ETag需要服务器通过算法来计算出一个 hash 值

  • 缓存位置

    1. Service Worker Service Worker 借鉴了 Web Worker 的 思路,即让 JS 运行主线程 之外,由于它脱离了浏览器的窗体,因此无法直接访问 DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如 离线缓存消息推送网络代理 等功能。其中的离线缓存就是 Service Worker Cache
    2. Memory Cache
    3. Disk Cache
    4. Push Cache(HTTP2)

浏览器的本地存储主要分为 CookieWebStorageIndexedDB, 其中 WebStorage 又可以分为 localStoragesessionStorage

9. 前端错误的分类有哪些?

  • 前端错误类型:
    1. SyntaxError (语法错误)
    2. ReferenceError (引用错误)
    3. TypeError (类型错误)
    4. RangeError (范围越界错误)
  • 前端错误分类:
    1. 代码执行的错误
    2. 资源加载的错误
  • 前端错误捕获:
    1. try...catch 能捕获 同步运行时 错误。不能捕获 语法错误异步任务错误promise资源加载错误
    2. window.onerror 能捕获所有同步错误、普通的异步错误。不能捕获语法、async 任务、promise 错误和资源加载错误等(例如:iframe)
    3. window.addEventListener('error', function() {}) 可捕获资源加载错误(如果资源加载错误,说明跨域,添加 crossorigin)
    4. window.addEventListener('unhandledrejection', function() {}) 捕获 promise 错误(没有写 catchPromise 中抛出的错误无法被 onerrortry-catch 捕获到。为了防止有漏掉的 Promise 异常,建议在全局增加一个对 unhandledrejection 的监听,用来全局监听 Uncaught Promise Error
    5. Vue 项目异常:Vue.config.errorHandler = (err, vm, info) => {}
    6. 崩溃和卡顿:利用 window 对象的 loadbeforeunload 事件
  • 总结:
    1. 可疑区域使用: Try...Catch
    2. 全局监控 JS 异常使用:window.onerror
    3. 全局监控静态资源异常使用:window.addEventListener
    4. 捕获没有 catch 的 Promise 异常使用:unhandledrejection
    5. Vue errorHandlerReact componentDidCatch
    6. 监控网页崩溃和卡顿使用:window 对象的 loaderbeforeunload
    7. 跨域:添加 crossOrigin
  • 上报方式有哪些:
    1. XMLHttpRequest 有跨域限制,携带 cookie 问题;上报请求可能会阻塞业务;请求容易丢失
    2. Image 可跨域、get 请求,大小限制
    3. SendBean

10. 说说为什么前端会有跨域?如何解决跨域?知道 option 请求吗?

不同域之间相互请求资源,称为”跨域“;浏览器的 同源策略(同源:url 是由协议、域名、端口和路径等组成。如果两个路径的协议、域名、端口都相同则表示再同一个域上)

在浏览器上 scriptimglinkiframe 等标签都可以加载跨域资源 且不受同源限制

  • 非同源限制:

    1. 无法读取非同源网页的 Cookie、LocalStorage、IndexedDB
    2. 无法接触非同源网页的 DOM
    3. 无法向非同源地址发起 ajax 请求
  • 解决跨域的方式:

    1. 设置 document.domain 解决无法读取非同源网页的 Cookie 问题

    浏览器是通过 document.domain 属性来检查两个页面是否同源,因此只要通过设置相同的 document.domain,两个页面就可以共享 Cookie。

    缺点:此方案仅限主域相同,子域不同的跨域应用场景

    1. JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本 IE),

    缺点:是只支持 get 请求, 需要后台配合,将返回结果包装成 callback(res)的形式。原理是利用 script 元素的跨域能力

    核心思想:网页通过添加一个script元素,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来

    • 原生 js 实现【请求地址后面添加?callback="xxx",然后在 script 中添加 xxx 方法其参数返回结果】

    • jQuery 的 ajax【dataType: 'jsonp', 请求方式为 jsonp;jsonpCallback: 'handleCallback' 自定义回调函数】

      扩展:

      1. scriptsrcimgsrc 跨域的区别?

      原理上都是利用标签的 src 可绕过同源限制,跨域请求的特点;区别在于:img 只能单向发送 get 请求,不可访问响应内容(只是展现),而 script 可对其进行解析

      1. 如果黑客植入 script 脚本通过 jsonp 的方式对服务器进行攻击,怎么办?

      可以通过页面设置的内容安全协议 csp 进行防范

      1. 为什么 jsonp 只支持 get 请求?

      JSONP 是一种【请求一段 JS 脚本,把执行这段脚本的结果当做数据】的玩法。

      JSONP 的实现原理就是 document.createElement('script') 生成一个 script 标签,然后插 body 里而已。在这里根本没有设置请求格式的余地). 所以 jsonp 不会对服务器端代码或者内容做更改

    1. H5 提供的 postMessage

      postMessage 事件发送消息,message 事件接受消息

    2. 跨域资源共享 CORS【常用】

      浏览器将 CORS 请求分成两类:简单请求非简单请求;当发出简单请求,只需要在头信息之中增加一个 Origin 字段。当发出 CORS 非简单请求,会在正式通信之前,增加一次 OPTIONS 查询请求,称为"预检"请求(preflight)。

      设置响应头的 Access-Control-Allow-Origin: *

      • 扩展:简单请求同时满足的三个条件?
        1. 请求方式只能是:GETPOSTHEAD
        2. HTTP 请求头限制这几种字段:AcceptAccept-LanguageContent-LanguageContent-TypeLast-Event-ID
        3. Content-type 只能取:application/x-www-form-urlencoded(是 Jquery 的 Ajax 请求默认方式)、multipart/form-datatext/plain

      预检请求(preflight):浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。

      重点:服务端如何避免每次都发出预检请求?(缓存

      1. Access-Control-Max-Age 该字段可选,用来指定本次预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求(全局和局部方式)【常用】
      2. @CrossOrigin 注解,可细粒度精确到单个请求级别
    3. window.name

      name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

    4. vueproxy 配置本地代理

      扩展:说说 Webpack Proxy 工作原理?

      proxy 工作原理实质上是利用 http-proxy-middleware 这个 http 代理中间件,实现请求转发给其他服务器

    5. H5 中的 websocket

    6. Nginx 代理

扩展:跨域请求如何携带 Cookie?

  1. 前端请求时在 request 对象中配置:withCredentials: true
  2. 服务端在 responseheader 中配置:Access-Control-Allow-Origin: "http://xxx.com"
  3. 服务器在 responseheader 中配置:Access-Control-Allow-Credentials: true

11. TCP 三次握手 & 四次挥手(短连接 & 长连接)?

三次握手的主要作用,需要确认双方的两样能力: 发送的能力接收的能力

从最开始双方都处于 CLOSED 状态。然后服务端开始监听某个端口,进入了 LISTEN 状态。

  1. 客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 seq。此时客户端处于 SYN_SEND 状态。
  2. 服务端接收到,返回 SYNACK(对应客户端发来的 SYN),确认号 ack,自己变成了 SYN-REVD
  3. 之后客户端再发送 确认应答 ACK 报文 给服务端,自己变成了 ESTABLISHED 状态;服务端收到 ACK 之后,也变成了 ESTABLISHED 状态。
  • 为什么不是两次?

    根本原因: 无法确认客户端的接收能力。

    1. 第一次握手:客户端发送网络包,服务端收到了。服务端就能得出结论:客户端的发送能力服务端的接收能力是正常的
    2. 第二次握手:服务端发包,客户端收到了。客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。注意:此时服务器并不能确认客户端的接收能力是否正常
    3. 第三次握手:客户端发包,服务端收到了。服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
  • 为什么不是四次?

    三次握手的目的: 是确认双方发送接收的能力,四次也可以。没必要

  • 什么是半连接队列?

    三次握手前,服务端的状态从 CLOSED 变为 LISTEN, 同时在内部创建了两个队列:半连接队列全连接队列,即 SYN 队列ACCEPT 队列

    半连接队列: 当客户端发送 SYN 到服务端,服务端收到以后回复 ACKSYN,状态由 LISTEN 变为 SYN_RCVD,此时这个连接就被推入了 SYN 队列,也就是 半连接队列

    全连接队列: 就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现 丢包 现象。

    补充一点 关于 SYN-ACK 重传次数的问题:

    服务器发送完 SYN-ACK 包,如果未收到客户确认包,服务器进行 首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

  • 三次握手过程中可以携带数据么?

    第三次握手的时候,可以携带。前两次握手不能携带数据

    (假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。这会让服务器花费很多时间、内存空间来接收这些报文。原因就是会让服务器更加容易受到攻击了)

  • SYN 攻击 是什么?

    SYN 攻击: 就是 Client 在短时间内伪造大量不存在的 IP 地址,并向 Server 不断地发送 SYN 包Server 则回复确认包,并等待 Client 确认,由于源地址不存在,因此 Server 需要不断重发直至超时,这些伪造的 SYN 包 将长时间占用未连接队列,导致正常的 SYN 请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击 是一种典型的 DoS/DDoS 攻击

    Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击netstat -n -p TCP | grep SYN_RECV

    • 常见的防御 SYN 攻击 的方法有如下几种:
      1. 缩短超时(SYN Timeout)时间
      2. 增加最大半连接数
      3. 过滤网关防护
      4. SYN cookies 技术
  • TCP 的半关闭(half-close

    所谓的半关闭,其实就是 TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。

刚开始双方处于 ESTABLISHED 状态

  • 客户端要断开了,向服务器发送 FIN 报文,发送后客户端变成了 FIN-WAIT-1 状态。 注意, 这时候客户端同时也变成了 half-close(半关闭)状态,即无法向服务端发送报文,只能接收。

    • 关闭 TCP 连接的挥手,客户端和服务端都可以发起关闭操作,以客户端发起为例:
      1. 浏览器先发送 FIN 报文Seq 初始化序列号给服务器,并停止发送数据,但仍可以接受服务端响应的数据
      2. 服务器收到后,发送 ACK=浏览器序列号+1 给浏览器,表明收到
      3. 服务器数据都发完了,给浏览器发送 FIN 报文Seq 序列号给浏览器
      4. 浏览器收到后,发送 ACK=服务器序列号+1 给服务器,表明收到
  • 为什么是 四次挥手 而不是 三次

    因为服务端在接收到 FIN, 往往不会立即返回 FIN, 必须等到服务端所有的报文都发送完毕了,才能发 FIN。因此先发一个 ACK 表示已经收到客户端的 FIN,延迟一段时间才发 FIN。这就造成了 四次挥手

    • 如果是 三次挥手 会有什么问题?

    (等于说服务端将 ACKFIN 的发送合并为一次挥手,这个时候 长时间的延迟 可能会导致客户端误以为 FIN 没有到达客户端,从而让客户端不断的重发 FIN。)

  • 等待 2MSL 的意义(为什么要等一段时间再关闭,不等不行吗?)

    这是为了防止发送给服务器的确认报文段 丢失 或者 出错,从而导致服务端不能正常关闭。等待时间是 2MSL,这也是报文在网络上的最大生存时间,超过这个时间就会被丢弃。RFC793 中规定 MSL 为 2 分钟,如果超过这个时间,那么主动关闭者就会发送一个 RST 状态位的包,表示 重置连接,这时候被关闭者就知道对方已经关闭了连接。

  • cookie 由哪些部分组成:

    1. Name: 这个属性就表示 cookie 的名字,每个 cookie 的名字都是唯一的
    2. Value: 这个属性表示 cookie 的值
    3. Domain: 就是 cookie 所在的域名,如果没有设置 domain 的话,那么 cookie 会自动绑定到执行语句的当前域
    4. Path: 这个属性的默认值是/,匹配的是路由,这里匹配的是路由的意思就是比如你的域名是 www.xxx.xyz,那么路由如果是 www.xxx.xyz/auth/,那么实际上 cookie 绑定的是这个 /auth
    5. Max-age: 这个属性是 http1.1 新增的属性,用来替代 expires 的,单位是秒,用来表示 cookie 在多少秒之后会失效
    6. Secure: 因为 http 是无状态协议,而且 http 在传输数据的过程中是以明文传输的,因此很容易遭到第三方网站的窃取,如果我们使用 secure 的话,就能够确保 cookie 是在 https 协议下进行传输的,但是这不代表会将 cookie 加密
    7. HttpOnly: 只能通过 HTTP 协议传输,不能通过 JS 访问。这个属性表示不能够被 js 脚本访问,因为 js 能够通过 document.cookie 来获取 cookie,所以使用 HttpOnly 就能够阻止这种情况,在一定程度上防止 xss 攻击,也就是 跨站脚本攻击
    8. SameSite: 用于限制第三方网站的 cookie 发送机制(cookie 每次随着请求会自动发送到服务器去的,这就给了其他站点发起 CSRF 攻击 和用户追踪的机会) 具体如下
      1. Strict: 最严格的模式,完全禁止跨站点请求时携带 cookie,设置为 strict 之后,跨站行为都不会再携带 cookie
      2. Lax: 相对 strict 模式 会宽松一点儿,允许导航到三方网站时携带 cookie,即 a 标签跳转form 表单的 get 提交,以及 link 标签的 prerender
      3. None: 使用 None 显示的关闭 SameSite 模式控制,但是需要注意的是还需要加上 secure,即 cookie 只会在 HTTPS 中发送,如果只是设置了 SameSite=None 是没有效果的
  • Cookie 的分类:

    第一方 Cookie第三方 Cookie,这两类 Cookie 都是网站保存在用户电脑上的一个文件,它们都由某个特定的域创建,并且只能被这个域访问

    第一方 Cookie 是由地址栏中列出的网站域设置的 Cookie,而 第三方 Cookie 来自在网页上嵌入广告或图片等项的其他域来源。都是网站在客户端上存放的一小块数据。他们都由某个域存放,只能被这个域访问。

    他们的区别其实并不是技术上的区别,而是使用方式上的区别。

  • Cookie 的特性:

    1. 生命周期: Expires(过期时间) 和 Max-Age(单位秒)设置
    2. 作用域: DomainPath 设置。注意/表示域名下的任何路径都允许使用 Cookie
    3. 安全相关
      1. 如果带上 Secure,说明只能通过 HTTPS 传输 cookie
      2. 如果 cookie 字段带上 HttpOnly,说明只能通过 HTTP 协议传输,不能通过 JS 访问。也是预防 XSS 攻击 重要手段
      3. SameSite 属性有 StrictLaxNone(默认)。也是预防 CSRF 攻击 的重要手段
  • Cookie 的缺点:

    1. 容量缺陷Cookie 的体积上限只有 4KB,只能用来存储少量的信息
    2. 性能缺陷Cookie 紧跟域名,不管域名下面的某一个地址需不需要这个 Cookie ,请求都会携带上完整的 Cookie,这样随着请求数的增多,其实会造成巨大的性能浪费的,因为请求携带了很多不必要的内容。但可以通过 DomainPath 指定 作用域 来解决。
    3. 安全缺陷。由于 Cookie纯文本 的形式在浏览器和服务器中传递,很容易被非法用户截获,然后进行一系列的篡改,在 Cookie 的有效期内重新发送给服务器,这是相当危险的。另外,在 HttpOnlyfalse 的情况下,Cookie 信息能直接通过 JS 脚本 来读取。

13. CSRF 和 XSS 、SSRF 的攻击原理 与防御措施?

CSRFCross-site request forgery):跨站请求伪造: 是一种劫持受信任用户向服务器发送非预期请求的攻击方式

  • CSRF 的攻击原理

从上图可以看出,要完成一次 CSRF 攻击,受害者必须满足 两个必要的条件

  1. 登录受信任 网站 A,并在本地生成 Cookie。(如果用户没有登录 网站 A,那么网站 B 在诱导的时候,请求网站 Aapi 接口 时,会提示你登录)
  2. 在不登出 A 的情况下,访问危险网站 B(其实是利用了 ∂网站 A 的漏洞)

温馨提示一下cookie 保证了用户可以处于登录状态,但网站 B 其实拿不到 cookie

  • CSRF 如何防御

    1. 方法一、Token 验证:(用的最多)

      服务器发送给客户端一个 token;客户端提交的表单中带着这个 token。如果这个 token 不合法,那么服务器拒绝这个请求。

    2. 方法二、隐藏令牌

      token 隐藏在 httphead 头中。方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。

    3. 方法三、Referer 验证:

      Referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截。

XSSCross Site Scripting):跨域脚本攻击: 是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式

  • XSS 的攻击原理

    XSS 攻击核心原理是:不需要你做任何的登录认证,它会通过合法的操作(比如在 url 中输入、在 评论框中输入),向你的页面注入脚本(可能是 jshtml 代码块等)。导致:盗用 Cookie、破坏页面的正常结构,插入广告等恶意内容、D-doss 攻击

  • XSS 的攻击方式

    1. 反射型

      发出请求时,XSS 代码 出现在 url 中,作为输入提交到服务器端,服务器端解析后响应,XSS 代码 随响应内容一起传回给浏览器,最后浏览器解析执行 XSS 代码。这个过程像一次反射,所以叫反射型 XSS

    2. 存储型

      存储型 XSS反射型 XSS差别在于,提交的代码会存储在服务器端(数据库内存文件系统等),下次请求时目标页面时不用再提交 XSS 代码

  • XSS 的防范措施(encode + 过滤

    1. 方法一、编码

      对用户输入的数据进行 HTML Entity 编码;把字符转换成 转义字符

    2. 方法二、过滤

      移除用户输入的和事件相关的属性。如 onerror 可以自动触发攻击,还有 onclick 等。(总而言之,过滤掉一些不安全的内容) 移除用户输入的 Style 节点Script 节点Iframe 节点。(尤其是 Script 节点,它可是支持跨域的呀,一定要移除)

    3. 方法三、校正

      避免直接对 HTML Entity 进行解码; 使用 DOM Parse 转换,校正不配对的 DOM 标签

  • CSRFXSS 的区别:

    1. CSRF:需要用户先登录 网站 A,获取 cookie; XSS:不需要登录
    2. CSRF:是利用网站 A 本身的漏洞,去请求 网站 Aapi;XSS:是向 网站 A 注入 JS 代码,然后执行 JS 里的代码,篡改 网站 A 的内容
  • SSRF

扩展v-html 的弊端?(利用 innerHTML

  1. 可能会导致 xss 攻击
  2. v-html 会替换掉标签内部的子元素

14. V8 中执行一段 JS 代码的整个过程

  1. 首先通过 词法分析语法分析 生成 AST
    • 词法分析分词,它的工作就是将一行行的代码分解成一个个 token
    • 语法分析 ,将生成的这些 token 数据,根据一定的语法规则转化为 AST
  2. AST 转换为 字节码
  3. 解释器 逐行执行 字节码 ,遇到热点代码启动编译器进行编译,生成对应的机器码, 以优化执行效率 (现在不用一次性将全部的字节码都转换成机器码,而是通过解释器来逐行执行字节码,省去了生成二进制文件的操作,这样就大大降低了内存的压力。)

注意:因为机器码相比字节码的体积太大,引发了严重的内存占用问题。机器只认识机器码

JS 运行可以分为 编译阶段执行阶段

  • 函数体内编译 四步曲,发生在函数 执行之前:

    1. 创建 AO 对象, (activation object)
    2. 形参变量声明,将形参和变量声明作为 AO 对象的属性名,值为 undefined
    3. 实参形参相统一
    4. 在函数体里找函数声明,将函数名作为 AO 对象的属性名,值赋予函数体
  • 全局下编译 三步曲,发生在代码 最前面:

    1. 创建 GO 对象
    2. 找变量声明,将变量声明作为 GO 对象的属性名,值赋予 undefined
    3. 找全局里的函数声明,将函数名作为 GO 对象的属性名,值赋予函数体

14. 从输入 URL 到页面展示经历了什么?

  • 总体流程如下:

    1. URL 解析 完整的 URL:协议 + 主机 + 端口 + 路径 + 参数 + 锚点。如果为非 url 结构的字符串,交给浏览器默认引擎去搜索改字符串;若为 url 结构的字符串,浏览器主进程会交给 网络进程 ,开始干活。

      • encodeURI 和 encodeURIComponent 的区别? encodeURI 是编码整个URL,而 encodeURIComponent 编码的是参数部分
    2. 检查资源缓存 在有效期内的缓存资源直接使用,称之为强缓存。返回 200,size 为 memory cache(资源从内存中取出)和 disk cache(资源从磁盘中取出)。当超过有效期的,则携带缓存的资源标识向服务器发起请求。返回 304,走协商缓存;返回 200,向服务器发起请求,将结果缓存起来,为下一次使用 通常来说:刷新页面会使用内存缓存; 关闭后重新打开会使用磁盘缓存

    3. DNS 解析:将域名解析成 IP 地址 如果没有成功使用本地缓存,则需要发起网络请求,发起之前要做 DNS 解析,会依次搜索:浏览器DNS缓存 -> 操作系统DNS缓存 -> 路由器DNS缓存 -> 服务商DNS服务器查询 -> 全球13台根域名服务器查询

      解析域名的查找过程:浏览器的 DNS 缓存 -> 操作系统的 DNS 缓存 -> 本地域名服务器(递归查询自己的 DNS 缓存) -> 上级域名服务器(进行迭代查询)【本地域名服务器 -> 根域名服务器(会返回顶级域名的服务器地址); 本地域名服务器 -> 顶级域名服务器(返回权威域名服务器地址,全球 13 台) 】 -》解析到的 IP 地址返回给操作系统,并缓存起来。-》操作系统将 IP 地址返回给浏览器,并缓存起来,供下次使用。

      为了节约时间,可以在 HTML 头部做 DNS 的预解析:

      <!-- 在HTTPS下开启 -->
      <meta http-equiv="x-dns-prefetch-control" content="on" />
      <link rel="dns-prefetch" href="http://www.baidu.com" />
      

      为了保证响应的及时,DNS 解析使用的是 UDP 协议。浏览器根据自定义的规则,提前去解析后面可能用到的域名,来加速网站的访问速度。

      注意:a 标签的 href 是可以在 chrome。firefox 包括高版本的 IE,但是在 HTTPS 下面不起作用,需要 meta 来强制开启功能。

    4. TCP 连接:TCP 三次握手

      • 三次握手过程:

        1. 客户端发送一个带 SYN=1, Seq=X 的数据包到服务器(第一次握手,由浏览器发起,告诉服务器,我要发送请求了)
        2. 服务器返回一个带 SYN=1, Ack=X+1, Seq=Y 的响应包确认信息给浏览器(第二次握手,由服务器发起,告诉浏览器我准备好了,你发吧)
        3. 客户端回传一个带 ACK=Y+1, Seq=Z 的数据包,代表”握手结束“(第三次握手,由浏览器发起,告诉浏览器,我马上就发了,准备接受吧)

        扩展:为啥要三次握手?目的:为了防止已失效的连接请求报文突然又传送到服务器,因而产生错误。

    5. 发送 HTTP 请求

    6. 服务器处理请求并返回 HTTP 报文

    7. 浏览器解析并渲染页面

    8. 断开 TCP 连接:TCP 四次挥手

      • 四次挥手过程:
        1. 主动方发送一个 Fin=1 结束标志位,Ack=Z 组成的报文,并发送 Seq=X 序列号。并进入到 FIN_WAIT_1 状态(第一次挥手:由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧)
        2. 被动方发送 ACK=X+1 确认标志位报文,并发送 Seq=Z 的序列号。表示同意关闭请求。此时主机发起方进入 FIN_WAIT_2 阶段。(第二次挥手:由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧)
        3. 被动方发送 Fin=1 结束标志位,Ack=X 组成的报文,并发送 Seq=Y 的序列号。进入 LAST_ACK 状态(第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧)
        4. 发送方发送 ACK=Y 确认标志位报文,并发送 Seq=Z 的序列号。进入等待 TIME_WAIT 状态。被动方收到发起方的报文段以后关闭连接。发起方等待一定时间未收到回复,则正常关闭。(第四次挥手:由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧)

15. 说说浏览器渲染原理?

整个渲染流程,从 HTMLDOM样式计算布局图层绘制光栅化合成显示

  • 解析 HTML,生成 DOM 树。解析 CSS,生成 CSSOM

    浏览器从磁盘或网络读取 HTML 的原始字节,并根据文件的指定编码(例如 UTF-8)将它们转换成字符串。

    DOM 树构建步骤字节数据 =》字符串 =》 Token => Node(节点对象) =》 DOM

    生成节点对象并构建 DOM,每个 Token 被生成后,会立刻消耗这个 Token 创建出节点对象。注意:带有结束标签标识的 Token 不会创建节点对象。

    • 关于 CSS 样式,它的来源一般是三种:

      1. link 标签 引用
      2. style 标签 中的样式
      3. 元素的内嵌 style 属性
    • 格式化样式表:首先,浏览器是无法直接识别 CSS 样式文本的,因此渲染引擎接收到 CSS 文本 之后第一件事情就是将其转化为一个结构化的对象,即 styleSheets

    • 标准化样式属性:有一些 CSS 样式 的数值并不容易被渲染引擎所理解,因此需要在计算样式之前将它们标准化,如 em->px,red->#ff0000, bold->700 等等。

    • 计算每个节点的具体样式:样式已经被 格式化标准化, 接下来就可以计算每个节点的具体样式信息了。计算的方式也并不复杂,主要就是两个规则: 继承层叠

      1. 每个子节点都会默认 继承父节点 的样式属性,如果父节点中没有找到,就会采用 浏览器默认样式,也叫 UserAgent 样式。这就是 继承规则
      2. 然后是 层叠规则CSS 最大的特点在于它的层叠性,也就是最终的样式取决于各个属性共同作用的效果 注意:在计算完样式之后,所有的样式值会被挂在到 window.getComputedStyle 当中,也就是可以通过 JS 来获取计算后的样式
  • DOM 树CSS 树 结合,生成 渲染/布局树Render Tree) Chrome 团队已经做了大量的重构,已经没有生成 Render Tree 的过程了。而布局树的信息已经非常完善,完全拥有 Render Tree 的功能。

    • 布局树 生成的大致工作如下:
      1. 遍历生成的 DOM 树 节点,并把他们添加到布局树中。
      2. 计算布局树节点的坐标位置。
  • Layout (回流):根据生成的渲染树,进行 回流(Layout),得到节点的几何信息(位置、大小)

  • Painting (重绘):根据渲染树以及回流得到节点的几何信息,从而得到节点的绝对像素

  • Display:将像素发送给 GPU。展示在页面上

注意:渲染树只包含可见的节点

扩展:为了构建渲染树,浏览器主要完成了以下工作:

  1. DOM 树 的根节点开始遍历每个 可见节点

  2. 对于每个可见的节点,找到 CSSOM 树 中对于的规则,并应用它们

  3. 根据每个可见节点以及其对应的样式,组合生成渲染树

    • 不可见的节点包括:
      1. 一些不会渲染输出的节点:如:scriptlinkmeta
      2. 一些通过 CSS 进行隐藏的节点:如:display: none

注意:利用 visibleopacity 隐藏节点,还是会显示在渲染树上的

分层:渲染引擎给页面分了很多图层,这些图层按照一定顺序叠加在一起,就形成了最终的页面。完成图层树的构建后,渲染引擎会对图层树中的每个图层进行绘制,为图层绘制。然后进行栅格化(raster)操作(绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的),最后合成与显示。

扩展:CSS 加载会阻塞页面显示吗?

  1. css 加载不会阻塞 DOM 树的解析
  2. css 加载会阻塞 DOM 树的渲染
  3. css 加载会阻塞后面 js 语句的执行

so, 为了防止 css 阻塞,引起页面白屏,可以提高页面加载速度:

  1. 使用 cdn
  2. 对 css 进行压缩
  3. 合理利用缓存
  4. 减少 http 请求,将多个 css 文件合并

16. 前端需要注意哪些 SEO?

  1. 合理的 titledescriptionkeywords
  2. 语义化 HTML 代码
  3. 重要内容 HTML 代码 放在前面(搜索引擎抓取 HTML 顺序是从上到下),不要用 js 输出(爬虫不会执行 js)
  4. 少用 iframe(搜索引擎不会抓取 `iframe 中的内容)
  5. 非装饰性图片必须加 alt
  6. 提高网站速度(网站速度是搜索引擎排序的一个重要指标)

17. 什么是堆?什么是栈?它们之间有什么区别和联系?

堆和栈的概念存在于数据结构中和操作系统内存中。

  • 在数据结构中,栈中数据的存取方式为 先进后出。而堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。完全 二叉树是堆的一种实现方式。
  • 在操作系统中,内存被分为栈区堆区。栈区内存由编译器自动分 配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆区内存一般由程序员分配释放,若程序员不释放,程序结束时可能由垃圾回收机制回收