# 网络相关

1. 从输入 URL 到页面呈现出来的过程
   * [计算机基础 / HTTP / 输入 URL 按下回车之后](https://anjia1.gitbook.io/cs/http/after-enter-url)
2. TCP 的三次握手和四次挥手
   * [计算机基础 / HTTP / TCP 的三次握手](https://anjia1.gitbook.io/cs/http/after-enter-url#1.3-tcp-de-san-ci-wo-shou)
   * [计算机基础 / HTTP / TCP 的四次挥手](https://anjia1.gitbook.io/cs/http/after-enter-url#4.-tcp-de-si-ci-hui-shou)
3. ...

## \~\~\~\~\~\~\~ 基础知识 \~\~\~\~\~\~

<details>

<summary>URL 和 URI 的区别</summary>

URI: Uniform Resource Identifier, 统一资源标识符

* 用唯一的标识来确定一个资源，是一种抽象的定义
* 即不管用什么方法来定义，只要能唯一地标识一个资源，就可以称为 URI

URL 和 URN 是 URI 的子集。

* URL: Uniform Resource Location, 统一资源定位符
  * 可以理解为使用地址来标识资源
* URN: Uniform Resource Name, 统一资源名称

</details>

<details>

<summary>跨域</summary>

1. 同源 vs 跨域
   * origin: 协议+域名+端口
2. 同源策略的限制 （???）
   * cookie, localStorage, IndexDB 无法读取
   * DOM 和 JS 对象无法获得
   * AJAX 请求不能发送
3. 跨域解决方案
   * JSONP, postMessage
   * CORS
   * document.domain
   * ....

P20

跨域，是指浏览器不能执行其它网站的脚本。它是由浏览器的同源策略造成的，是浏览器对 JavaScript 实施的安全限制，那么只要协议、域名、端口有任何一个不同，都被当作是不同的域。 跨域原理，即是通过各种方式，避开浏览器的安全限制。

JS 实现跨域的方法，<https://segmentfault.com/a/1190000011145364>

</details>

<details>

<summary>JSONP</summary>

JSONP 能实现跨域，它是利用标签不受同源策略限制的特性（这算是一个漏洞）。

1. 浏览器用 JavaScript 代码动态创建一个 `<script>` 标签，其 `src` 属性引用第三方的 API 地址，并提供一个回调函数的 function name
   * 比如 <https://www.smartstudy.com/api/?callback=functionName>
   * 其中的 query 都是约定好了，比如 `callback` 和 `functionName`
2. 后端通过 query 取到函数名，然后把需要的数据以参数的形式传递给该函数，返回给浏览器
3. 浏览器解析服务器返回的数据，执行该回调函数

JSONP 并不使用 XMLHttpRequest 对象加载数据，而是通过 `<script>` 标签把资源当做普通的 JavaScript 脚本来加载，所以不存在跨域的问题，也不是真正的 AJAX。

</details>

<details>

<summary>CORS vs JSONP</summary>

CORS 可以用作 JSONP 模式的现代替代方案：

* JSONP 仅支持 GET 方法，而 CORS 还支持其它类型的 HTTP 请求
* CORS 让程序员可以使用常规的 XMLHttpRequest，它支持比 JSONP 更好的错误处理
* JSONP 可能会导致跨站点脚本 XSS 问题（在外部站点受到威胁时），而 CORS 允许网站手动解析响应以提高安全性

JSONP 的主要优点是兼容 CORS 出现之前的老版浏览器。现在大多数现代 Web 浏览器都支持 CORS。

</details>

<details>

<summary>客户端存储</summary>

cookie, sessionStorage, localStorage, indexdDB

共同点：都保存在浏览器端，且都是同源的

1. 是否在 HTTP 中携带
   1. cookie 数据会始终在同源的 HTTP 请求中携带（即使不需要），即在浏览器和服务器之间来回传递
      * 所以它的容量较小，大约 4K 左右
      * 所以只适合保存很小的数据，比如会话标识
      * 初衷就是为了弥补 HTTP 的无状态
   2. sessionStorage 和 localStorage 仅在本地保存，不参与和服务器的通信
2. 是否持久化保存
   1. cookie：在设置的 cookie 过期时间之前一直有效（即使窗口或浏览器关闭了），否则默认为关闭浏览器后失效
      * cookie 还可以限制只属于某个 path 下
   2. sessionStorage：仅在当前“浏览器”窗口关闭前有效（不持久）
      * session，会话，两个页签打开同一个页面，也被视为同一个会话
   3. localStorage：持久化存储（即使窗口或浏览器关闭了），除非被手动清除
3. 存储空间
   1. cookie，4K 左右
   2. sessionstorage 和 localStorage，5M 左右
4. 易用性
   1. cookie 原生的接口不太友好，需要自己封装
   2. 其它：可采用原生接口，也可自己封装
5. 应用场景
   1. cookie

</details>

<details>

<summary>Web 性能优化</summary>

检测页面的加载时间，一般有两种方式：

1. 被动去测：在被检测的页面置入脚本或探针，当用户访问网页时，探针自动采集数据并传回数据库进行分析（数据更真实）
2. 主动监测：主动搭建分布式受控环境，模拟用户发起页面访问请求，主动采集性能数据并分析。在检测的精准度上，专业的第三方工具效果更佳，比如说性能极客

优化手段：

1. 内存溢出
2. 降低请求量：合并资源，减少 HTTP 请求数，minify/gzip 压缩，webP，lazyLoad
3. 加快请求速度：预解析 DNS，减少域名数，并行加载，CDN 分发，避免重定向
4. 缓存：HTTP 协议缓存请求，离线缓存 manifest，离线数据缓存 localStorage
5. 渲染：JS/CSS 优化，动画绘制频率，加载顺序，服务端渲染，pipeline

</details>

<details>

<summary>&#x3C;script> 的 async 和 sync</summary>

</details>

## \~\~\~\~\~\~ HTTP 相关 \~\~\~\~\~

<details>

<summary>HTTP 请求的方法</summary>

最常见：

1. `GET` 从指定的资源请求数据
2. `POST` 向指定的资源提交要被处理的数据

次常见：

1. `HEAD`：类似于 GET 请求，只是返回的响应中没有具体内容，客户端读取响应的 Headers
2. `OPTIONS`：允许客户端查看服务器的性能，比如服务器支持的请求方式等

不太常见的：

1. `PUT`
2. `DELETE`
3. `TRACE`
4. `CONNECT`

</details>

<details>

<summary>get 和 post 的区别</summary>

GET <mark style="background-color:blue;">vs</mark> POST

1. 参数位置：在 URL 里 <mark style="background-color:blue;">vs</mark> 在 request body 中
   * 只能 URL 编码 <mark style="background-color:blue;">vs</mark> 多种编码方式
   * GET 的参数有长度限制，而 POST 没有
     * 一般限制在 2\~8K 之间，常见的是 1K 之内
   * POST 的参数更安全，所以更适合传递一些敏感信息
2. 浏览器的不同处理
   * GET 请求会被浏览器主动 cache
   * GET 请求参数会被完整地保留在浏览历史记录里
3. TCP 数据包
   * GET 请求产生一个 TCP 数据包
     * 浏览器会把 HTTP Header 和 data 一起发出去，服务器响应 200
   * POST 产生两个 TCP 数据包
     * 浏览器先发送 header，服务器响应 100 continue
     * 浏览器再发送 data，服务器响应 200 ok

GET 和 POST 的底层都是 TCP/IP，都是 TCP 连接，并无差别。只是由于 HTTP 的规定以及浏览器和服务器的限制，导致它们在使用上有些不同。

</details>

<details>

<summary>get 请求传参长度的误区</summary>

误区：我们常说 get 请求参数的大小存在限制，而 post 请求的参数大小是无限制的。

* HTTP 协议从未规定 get 和 post 请求的长度限制
* 而是浏览器和 web 服务器限制了 get 请求的参数长度
* 不同的浏览器和 web 服务器，限制的最大长度不一样
  * 要支持 IE，则最大长度为 2083byte
  * 若只支持 Chrome，则最大长度 8182byte

</details>

<details>

<summary>HTTP 返回的状态码</summary>

</details>

<details>

<summary>HTTP Header</summary>

可以将 HTTP Header 分为：

1. 通用首部：表示一些通用信息。比如：
   * `date` 表示报文创建时间
2. 请求首部：请求报文中独有的。比如：
   * cookie 相关的 `if-Modified-Since`
3. 响应首部：响应报文中独有的。比如：
   * `set-cookie`
   * `location` 重定向相关
4. 实体首部：用来描述实体部分。比如：
   * `allow` 用来描述可执行的请求方法
   * `content-type` 描述主题类型
   * `content-Encoding` 描述主体的编码方式

</details>

<details>

<summary>一个 TCP 连接能发几个 HTTP 请求？</summary>

1. HTTP 1.0，一个 TCP 发送一个 HTTP 请求
   * 一般情况，不支持长连接，在每次请求发送完毕之后 TCP 连接会立即断开
   * 在请求头带上 `Connection: Keep-Alive` 也可以发送多条，不过有限制
2. HTTP 1.1，支持长连接，所以只要 TCP 连接不断开，就可以一直发送 HTTP 请求，没有上限
3. HTTP 2.0
   * 支持长连接。所以只要 TCP 连接不断开，就可以一直发送 HTTP 请求，没有上线
   * 支持多路复用，所以一个 TCP 连接可以并发多个 HTTP 请求

</details>

<details>

<summary>TCP 和 UDP</summary>

TCP 是面向连接的可靠性传输，而 UDP 是不可靠的。

TCP <mark style="background-color:blue;">vs</mark> UDP

1. 面向连接的 <mark style="background-color:blue;">vs</mark> 无连接的（发送数据前不需要先建立链接）
2. 提供可靠服务 <mark style="background-color:blue;">vs</mark> 尽最大努力交付（不保证可靠交付）
   * 通过 TCP 连接传送的数据，无差错、不丢失、不重复、且按序到达
   * UDP 即便出现网络拥塞也不会降低发送速率，所以会丢包
     * 比如实时应用（电话和视频会议）
3. 面向字节流 <mark style="background-color:blue;">vs</mark> 面向报文
4. 只能是 1 对 1 的 <mark style="background-color:blue;">vs</mark> 支持 1 对 1, 1 对多
5. 首部大小：20 字节 <mark style="background-color:blue;">vs</mark> 只有 8 字节

</details>

<details>

<summary>WebSocket 的实现和应用</summary>

WebSocket 是 HTML5 中的协议，支持持久性连接。

* HTTP 1.0 和 HTTP 1.1 都不支持持久性的连接
* HTTP 1.1 中的 `keep-alive` 可以将多个 HTTP 请求合并为一个。

HTTP 的生命周期通过 Request-Response 来界定。一个 Request 只能对应一个 Response，而且这个 Response 是被动的，不能主动发起。

* 在 HTTP 1.0 协议中，这次 HTTP 请求就结束了
* 在 HTTP 1.1 中，`connection: Keep-alive`，就可以在一个 HTTP 连接中，发送多个 Request，接收多个 Response

WebSocket 是基于 HTTP 协议的，或者说借用了 HTTP 协议来完成一部分握手，在握手阶段和 HTTP 是相同的。

看一个 websocket 握手协议的实现，基本是 2 个属性 `upgrade`, `connection`。

```
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== 
Sec-WebSocket-Protocol: chat, superchat 
Sec-WebSocket-Version: 13
Origin: http://example.com
```

</details>

<details>

<summary>websocket 和 ajax 轮询</summary>

* websocket，HTML5 的新协议，可以实现服务端和服务器的通信，实现服务器的推送功能
  * 优点：只要建立一次连接，就可以连续不断地得到服务器推送的消息，因此节省带宽、减少服务器端的压力
* ajax 轮询：每隔一段时间（0.5s）就向服务器发起 ajax 请求，以查询服务器是否有数据更新
  * 缺点：每次都要建立 HTTP 连接，因此比较浪费带

</details>

<details>

<summary>HTTP 协议（特征）</summary>

* 基于 TCP/IP 通信协议来传递数据，比如 HTML 文件、图片文件、查询结果
* 属于应用层的、面向对象的协议
* 使用简捷、快速，适用于分布式超媒体信息系统
  * 它于 1990 年提出，经过几年的使用与发展，得到不断地完善和扩展
  * 目前在 WWW 中使用的是 HTTP/1.0 的第六版
  * HTTP/1.1 的规范化工作正在进行之中
  * HTTP-NG(Next Generation of HTTP)的建议已经提出
* HTTP 协议工作于客户端-服务端架构中
  * 浏览器作为 HTTP 客户端，通过 URL 向 HTTP 服务端（WEB 服务器）发送请求
  * Web 服务器根据接收到的请求后，向客户端发送响应信息

</details>

<details>

<summary>HTTP 和 HTTPS 的区别</summary>

HTTP，超文本传输协议。基于 TCP/IP 通信协议，用于从 WWW 服务器传输超文本到本地浏览器，它的模式是“一个请求对应一个响应”。

HTTPS 是 HTTP 的安全版，即在 HTTP 下加入 SSL 层。SSL 是 HTTPS 的安全基础，因为 HTTP 传输的数据是明文的（没有加密），而 SSL 协议可以对其数据进行加密。SSL 加密是在传输层实现的。

所以说，HTTPS 比 HTTP 协议的安全性更高，它能进行加密传输和身份认证。

* SSL 加密
* CA 证书

此外，HTTP 80端口 <mark style="background-color:blue;">vs</mark> HTTPS 443端口

</details>

<details>

<summary>HTTPS 的原理和优缺点</summary>

#### 工作原理

* 客户端使用 HTTPS URL 访问服务器
* 服务器建立 SSL 链接，并将网站的证书（包含了公钥）传给客户端
* 客户端和服务器端开始协商 SSL 链接的安全等级，并建立会话密钥
* 然后通过网站的公钥来加密会话密钥并传送给网站

#### 优点

* 可以认证用户和服务器，确保数据发送到正确的客户机和服务器
* 更安全，可防止数据在传输过程中被窃取、改变
* 是现行架构下最安全的解决方案，虽然不是绝对安全，但它大幅增加了中间人攻击的成本

#### 缺点

* 握手阶段比较费时，会使页面加载时间延长 50%，增加 10%\~20%的耗电
* 缓存不如 HTTP 高效，会增加数据开销
* SSL 证书需要钱，功能越强大的证书费用越高
* SSL 证书需要绑定 IP，不能在同一个 IP 上绑定多个域名，ipv4 资源支持不了这种消耗

</details>

<details>

<summary>HTTP 2.0</summary>

HTTP 2.0 是基于 HTTPS 的，天然具有安全特性，且它还能避免单纯使用 HTTPS 的性能下降。

1. 提升访问速度：HTTP 1.0，请求资源所需时间更少、访问速度更快
2. 多路复用：这相当于是长连接的增强
   * 每个 Request 请求可以随机地混杂在一起，接收方可以根据 Request 的 id 将 Request 再归属到各自不同的服务端请求里面
   * 另外多路复用中也支持了流的优先级，允许客户端告诉服务器那些内容是更优先级的资源，可以优先传输。
   * 在 HTTP 1.1 中，客户端在同一时间针对同一域名下的请求，有数量限制（连接数量），超过限制了会被阻塞
3. 二进制分帧：
   * HTTP 1.X 的解析是基于文本的
   * HTTP 2.0 将所有的传输信息分割为更小的消息和帧，并对它们采用二进制格式编码
   * 基于二进制可以让协议有更多的扩展性，比如用“帧”来传输数据和指令
4. 首部压缩
5. 服务器端推送

</details>

<details>

<summary>cookie, session 区别</summary>

* HTTP 是一个无状态协议，cookie 的最大作用就是存储
* sessionId 用来唯一标识用户

cookie 和 session 都可以用来存储用户信息。

1. 位置不同
   * cookie 存放在客户端（约4K），服务端和客户端都可以设置
   * session 存放在服务器端，可以存文件/数据库/内存中
2. 安全性：cookie < session
   * 可以通过分析存放在本地的 cookie 并进行 cookie 欺骗，不安全
   * 敏感信息通常用 session 存储，比如用户登录信息
3. 性能：cookie > session
   * session 会在一定时间内保存在服务器上，当访问增多，会比较占用服务器的性能
4. 存储大小
   * 单个 cookie 保存的数据不能超过 4K，很多浏览器都限制一个站点最多保存 20 个 cookie

</details>

## \~\~\~\~\~\~\~\~ 缓存 \~\~\~\~\~\~\~\~

<details>

<summary>缓存机制的 4 个方面</summary>

作用：减少网络 IO 消耗，提高访问速度。

浏览器的缓存机制有四个方面，按照获取资源时请求的优先级，依次排列如下：

1. Memory Cache
2. Service Worker Cache
3. HTTP Cache
4. Push Cache

</details>

<details>

<summary>强缓存、协商缓存</summary>

根据响应的 Header 内容来决定：

1. 强缓存：`200` from cache，不发请求到服务器，直接从缓存取
   * 过去用 `expires`，使用的是基于服务器端的绝对时间（会存在时差）
   * 现在用 `Cache-Control`，使用相对时间
     * 是一个通用 Header 字段，可用于 HTTP 请求和响应中
     * 该缓存指令是单向的，常见的取值有
       * `private` 默认
       * `no-cache`
       * `max-age`
       * `must-revalidate`
   * 若两同时存在，则用新的
2. 协商缓存：`304` not modified，发送请求到服务器，通过服务器告知缓存是否可用
   * `Last-Modified` 时间戳
   * `Last-Modified/If-Modified-Since`
   * `Etag/If-None-Match`

在没有命中强缓存的时候，才会走协商缓存。

预期：如果服务器上的资源更新了，那浏览器就请求新资源；否则就用本地缓存。以最大程度地减少因网络请求而产生的资源浪费。

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FAmg147bapKWkRQP3nKJm%2Fimage.png?alt=media\&token=54efb1eb-7f91-47f1-91c9-23fa03af721b)

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FziV76N6pfvzw9X3hgNnu%2Fimage.png?alt=media\&token=b3f1abe0-43a7-4495-bcff-2d9294e111da)

在请求这些有设置缓存的数据时，会先查看是否过期

* 如果没有过期，则直接使用本地缓存
* 否则，就向服务器发起请求，并重新协商有关缓存信息
  * 如果上次响应设置了 `ETag` 值，则会在这次请求的时候作为 `If-None-Match` 的值交给服务器校验
  * 如果上次响应设置了 `Last-Modified` 值，则会在这次请求的时候作为 `If-Modified-Since` 的值交给服务器校验
  * 如果都没有设置，则直接请求
* 而在需要“服务器校验（协商缓存）”时，它会返回 `200` 或 `304`
  * `200` 表示这是全新的数据
  * `304` 表示从缓存取

说明：两次“从缓存取”，第一次是命中强缓存，第二次是经过与服务器协商且确认缓存未过期。

详情参阅：<https://segmentfault.com/a/1190000008956069>

</details>

<details>

<summary>get 和 post 请求在缓存方面的区别</summary>

缓存一般只适用于那些“不会更新服务端数据”的请求。所以：

* 一般会对 get 请求进行缓存
* 很少会对 post 请求进行缓存

</details>

<details>

<summary>cookie 的编码方式</summary>

`encodeURI()`

</details>

<details>

<summary>cookie 可以设置的字段</summary>

1. `name` cookie 的名称
2. `value` cookie 的值
3. `domain` 为可以访问此 cookie 的域名
   * 顶级域名
     * 只能设置 `domain` 为顶级域名，不能设置为二级域名或者三级域名，否则 cookie 无法生成
     * 只能获取到 `domain` 设置为顶级域名的 cookie，其他 domain 设置为二级域名的无法获取
   * 二级域名能读取设置了 `domain` 为顶级域名或者自身的 cookie，但不能读取其他二级域名 `domain` 的 cookie
     * 所以要想 cookie 在多个二级域名中共享，需要设置 domain 为顶级域名，这样就可以在所有二级域名里面或者到这个 cookie 的值了
   * 非顶级域名（如二级域名或者三级域名）设置的 cookie 的 `domain` 只能为顶级域名或二级域名或三级域名本身，不能设置其他二级域名的 cookie，否则 cookie 无法生成
4. `path` 为可以访问此 cookie 的页面路径
   * 比如 domain 是 abc.com,path 是/test，那么只 有/test 路径下的页面可以读取此 cookie。
5. `expires/Max-Age` 为此 cookie 过期时间
   * 若设置其值为一个时间，那么当到达此时间后，此 cookie 失效
   * 不设置的话默认值是 Session，意思是 cookie 会和 session 一起失效。当浏览器关闭(不是浏览器标签页，而是整个浏览器) 后，此 cookie 失效
6. `Size` 此 cookie 大小
7. `http` cookie 的 `httponly` 属性
   * 若此属性为 true，则只有在 HTTP 请求头中会带有此 cookie 的信息，而不能通过 `document.cookie` 来访问此 cookie。
8. `secure` 设置是否只能通过 HTTPS 来传递此条 cookie

</details>

<details>

<summary>cookie 的弊端</summary>

1. 安全性
   * 若被拦截了，就能得到相关的 session 信息
   * 甚至不需要解密，原样转发就能达到目的
2. 有数量和长度的限制
   * 每个 domain 最多 20 条 cookie
   * 每个 cookie 最大长度 4KB
3. 场景有限。比如

</details>

<details>

<summary>ajax 解决浏览器缓存问题</summary>

1. 在 ajax 发送请求前加上 `anyAjaxObj.setRequestHeader("If-Modified-Since","0")`&#x20;
2. 在 ajax 发送请求前加上 `anyAjaxObj.setRequestHeader("Cache-Control","no-cache")`&#x20;
3. 在 URL 后面加上一个随机数: `"fresh=" + Math.random()`&#x20;
4. 在 URL 后面加上时间戳 `"nowtime=" + new Date().getTime()`

如果是使用 jQuery，直接这样就可以了 `$.ajaxSetup({cache:false})`，这样页面的所有 ajax 都会执行这条语句就是不需要保存缓存记录。

</details>

## \~\~\~\~\~\~\~\~ 更多 \~\~\~\~\~\~\~\~

<details>

<summary>Fetch 发送两次请求的原因</summary>

Fetch 发送 POST 请求时，总是发送两次：第一次状态码是 204，第二次才成功。

原因：Fetch 第一次会发送一个 Options 请求，询问服务器是否支持修改的请求头，如果服务器支持，则会在第二次发送真正的请求

</details>

<details>

<summary>CDN</summary>

CDN，Content Delivery Network，内容分发网络。

CDN 是一个智能虚拟网络，构建在现有网络的基础之上的。它依靠部署在各地的边缘服务器，通过中心平台的负载均衡、内容分发、调度等功能模块，让用户就近获取所需内容，从而降低网络阻塞、提高用户访问响应速度和命中率。CDN 的关键技术主要：内容存储和分发技术。

CDN 的主要功能：

1. 节省骨干网带宽，减少带宽请求量
2. 提供服务器端加速，避免由于用户访问量大而造成服务器过载
3. 服务商使用 web cach 技术，在本地缓存“用户访问过的 web 页面和对象”
   * 既避免了占用主干的出口带宽
   * 又能缩短用户访问页面的响应时间
4. 能克服网站分布不均的问题，并且能降低网站自身建设和维护成本
5. 降低“通信风暴”的影响，从而提高网络访问的稳定性

CDN 的基本原理是：广泛采用各种缓存服务器，将这些缓存服务器分布到用户访问相对集中的地区或网络中，在用户访问网站的时候，利用“全局负载技术”将用户的访问指向距离最近、且工作正常的缓存服务器上，由缓存服务器直接响应用户的请求。

</details>

<details>

<summary>图片的懒加载和预加载</summary>

* 预加载：提前加载图片，当用户需要查看时可直接从本地缓存中渲染
* 懒加载：迟缓加载，减少请求数或延迟请求数，主要是作为服务器端的优化

</details>

<details>

<summary>访问图片 URL 后直接下载，如何实现？</summary>

在请求的返回头里，用于浏览器解析的重要参数就是 OSS 的 API 文档里面的返回 HTTP 头，决定用户下载行为的参数。

```
x-oss-object-type: Normal
x-oss-request-id: 598D5ED34F29D01FE2925F41
x-oss-storage-class: Standard
```

</details>
