应用层协议定义了应用进程间的交互和通信规则,不同主机的应用进程间如何相互传递报文,比如传递的报文的类型、格式、 有哪些字段等等

一、HTTP 协议

1. 概况

HTTP (HyperText Transfer Protocol) 是超文本传输协议,是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」
它定义了客户端和服务器之间交换报文的格式和方式,默认使用 80 端口。
它使用 TCP 作为传输层协议,保证了数据传输的可靠性

「文本」,在互联网早期的时候只是简单的字符文字 但现在「文本」的涵义已经可以扩展为图片、视频、压缩包等,在 HTTP 眼里这些都算做「文本」

「超文本」,它就是超越了普通文本的文本,它是文字、图片、视频等的混合体最关键有超链接,能从一个超文本跳转到另外一个超文本。

HTTP 是一个无状态的协议,HTTP 服务器不会保存关于客户的任何信息
HTTP 有两种连接模式

  • 非持续连接
    • 指的是服务器必须为每一个请求的对象建立和维护 一个全新的连接
      • HTTP1.0 以前使用的非持续的连接,但是可以在请求时,加上Connection: keep-a live来要求服务器不要关闭 TCP 连接
  • 持续连接
    • TCP 连接默认不关闭,可以被多个请求复用
      • HTTP1.1 以后默认采用的是持续的连接。目前对于同一个域,大多数浏览器支持同时建立 6 个持久连接
    • 优点:可以避免每次建立 TCP 连接三次握手时所花费的时间

HTTP报文有两种

  • HTTP请求报文
  • HTTP响应报文

2. HTTP 请求报文

HTTP 请求报文格式如下

  1. GET / HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
  3. Accept: */*

image.png
图:HTTP请求报文的组成
HTTP 请求报文的组成

  • 请求行
    • 其包含三个字段:方法字段、URL 字段和 HTTP 版本字段
  • 首部行(请求头部)
  • 空行(回车符+换行符),这个空行不能省略,它用来划分首部与实体
  • 实体主体(请求数据)

3. HTTP 响应报文

  • HTTP 响应报文格式如下 ```http HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 137582 Expires: Thu, 05 Dec 1997 16:00:00 GMT Last-Modified: Wed, 5 August 1996 15:55:28 GMT Server: Apache 0.84

Hello World ``` image.png
图:HTTP相应报文组成

  • HTTP 响应报文的组成
    • 状态行
      • 其包含三个字段:HTTP 协议版本字段、状态码、状态码的描述文本
        • 状态码
          • 1xx:提示信息、表示目前是协议处理的中间状态,还需要后续的操作
          • 2xx:成功,报文已经收到并被正确处理
          • 3xx:重定向,资源位置发生变动,需要客户端重新发送请求
          • 4xx:客户端错误,请求报文有误,服务器无法处理
          • 5xx:服务器错误,服务器在处理请求时内部发送了错误
    • 首部行(响应头部)
    • 空行(回车符+换行符),这个空行不能省略,它用来划分首部与实体
    • 实体主体(响应数据)

4. 说说状态码

  • 1xx
    • 属于提示信息,是协议处理中的一种中间状态,实际用到的比较少
  • 2xx
    • 表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态
      • 「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据
      • 「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据
      • 「206 Partial Content」是应用于 HTTP 分块下载或断电续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态
  • 3xx
    • 表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向
      • 「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问
        • 301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL
      • 「302 Moved Permanently」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问
      • 「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制
  • 4xx
    • 表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义
      • 「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误
      • 「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错
      • 「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端
  • 5xx
    • 表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码
      • 「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道
      • 「501 Not Implemented」表示客户端请求的功能还不支持,类似『即将开业,敬请期待』的意思
      • 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误
      • 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似『网络服务正忙,请稍后重试』的意思

        5. HTTP/1.0 和 HTTP/1.1

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

为了解决上述 TCP 连接问题,HTTP/1.1 提出了 长连接 的通信方式,也叫 持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。

持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态

image.png
图:短连接和长连接
5.2 管道网络传输
HTTP/1.1 采用了 长连接 的方式,发展出了 管道网络传输,即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以 减少整体的响应时间

举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照 顺序 ,先回应 A 请求,完成后再回应 B 请求。

image.png
图:管道网络传输

这就引出 HTTP/1.1 的性能问题:要是前面的回应特别慢,后面就会有许多请求排队等着。这称为『队头阻塞』

5.2 队头阻塞
当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是 队头阻塞
image.png
图:队头阻塞

6. 说说首部行

报文首部包含了请求行、首部行。
首部行是由一个个字段组成的。
使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容

若 HTTP 首部字段重复了会如何? 这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,结果可能并不一致。有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段

6.1 HTTP 首部字段类型
HTTP 首部字段根据实际用途被分为以下 4 种类型:
6.1.1 通用首部字段
请求报文和响应报文两方都会使用的首部
6.1.2 请求首部字段
从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
6.1.3 响应首部字段
从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息
6.1.4 实体首部字段
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息

image.png
图:请求报文
image.png
图:响应报文
6.2 HTTP 首部字段结构
HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号 : 分隔。若有多个字段值,通过 , 分隔

Cache-Control: private, max-age=0, no-cache

6.3 HTTP/1.1 首部字段
HTTP/1.1 规范定义了如下 47 种首部字段

首部字段名 字段值 说明
Cache-Control 通用首部字段的值的详细介绍 控制缓存行为
Connection (1) 控制不再转发给代理的首部字段
(2) 管理持久连接
Date 创建报文的日期
Pragma 历史遗留字段,只用在客户端发送的请求中。
客户端会要求所有的中间服务器不返回缓存的资源
Upgrade 升级为其他协议
via 代理服务器的相关信息
Wraning 错误和警告通知
Trailer 事先说明在报文主体后记录了哪些首部字段
Transfor-Encoding 规定了传输报文主体时采用的编码方式

表1:通用首部字段

首部字段名 字段值 说明
Accept 请求首部字段的值的详细介绍 客户端或者代理能够处理的媒体类型
Accept-Encoding 优先可处理的编码格式
Accept-Language 优先可处理的自然语言
Accept-Charset 优先可以处理的字符集
Authorization web的认证信息
If-Modified-Since 比较资源更新时间(Last-Modified)
User-Agent 客户端程序信息
Referer 对请求中 URI 的原始获取方
Host 请求资源所在服务器
Proxy-Authorization 代理服务器要求客户端的认证信息
Max-Forwards 最大传输逐跳数
From 用户的邮箱地址
Expect 期待服务器的特定行为
Range 实体的字节范围请求

表2:请求首部字段

首部字段名 字段值 说明
Accept-Ranges 响应首部字段的值的详细介绍 能接受的字节范围
Location 令客户端重定向的URI
Age 告知客户端,源服务器在多久前创建了响应
vary 代理服务器的缓存信息
ETag 能够表示资源唯一资源的字符串
Server 服务器的信息
Proxy-Authenticate 代理服务器要求客户端的验证信息
WWW-Authenticate 服务器要求客户端的验证信息
Retry-After 告知客户端应该在多久之后再次发送请求

表3:响应首部字段

首部字段名 字段值 说明
Allow 实体首部字段的值的详细介绍 资源可支持http请求的方法
Content-Language 实体的资源语言
Content-Encoding 实体的编码格式
Content-Length 实体的大小
Content-Type 实体媒体类型
Content-MD5 实体报文的摘要
Content-Ranges 告知客户端作为响应返回的实体的哪个部分符合范围请求
Last-Modified 资源最终修改的时间
Expires 资源失效的日期告知客户端

表4:实体首部字段

二、HTTP/2 协议

2009 年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。
这个协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。2015 年,HTTP/2 发布。

1. HTTP/2 的特性

1.1 二进制协议
HTTP/2 是一个二进制协议。
在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。
在 HTTP/2 是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为『帧』,可以分为头信息帧和数据帧。
帧的概念是它实现多路复用的基础
image.png
图:报文区别

1.2 多路复用
HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了『队头堵塞』的问题

image.png
图:多路复用

1.3 数据流
HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流 ID ,用来区分它属于哪个数据流

每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数

客户端还可以 指定数据流的优先级。优先级高的请求,服务器就先响应该请求

1.4 头信息压缩
HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度

HTTP/2 对这一点做了优化,引入了头信息压缩机制。如果你同时发出多个请求,他们的头是一样的或是相似的,那么,HTTP/2 协议会帮你 消除重复的部分

  1. 头信息使用 gzip 或 compress 压缩后再发送
  2. 客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了 —— 这就是所谓的 HPACK 算法

1.5 服务器推送
HTTP/2 还在一定程度上改善了传统的『请求 - 应答』工作模式,服务不再是被动地响应,也可以 主动 向客户端发送消息

举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push,也叫 Cache Push)

2. HTTP/2 的缺陷

HTTP/2 主要的缺陷在于:多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。
所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的 所有的 HTTP 请求都必须等待这个丢了的包被重传回来

3. HTTP/3 协议

HTTP/2 问题的根源:是基于 TCP 传输层的出错重传而出现的问题。
HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP,UDP 发生是不管顺序,也不管丢包的,所以不会出现 HTTP/1.1 的『队头阻塞』 和 HTTP/2 的一个『丢包全部重传』问题

image.png
图:HTTP/1.1 ~ HTTP/3

总所周知,UDP 是不可靠传输的

  • QUIC 协议 是一个在 UDP 之上的 伪 TCP + TLS + HTTP/2 的多路复用的协议,使得 UDP 可以实现类似 TCP 的可靠性传输
    • QUIC协议 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响
    • HTTPS 要建立一个连接,要花费 6 次交互,先是建立三次握手,然后是 TLS/1.3 的三次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互 合并成了 3 次,减少了交互次数

另外,TLS 升级成了最新的 1.3 版本,头部压缩算法也升级成了 QPack

image.png
图:TCP HTTPS 和 QUIC HTTP/3

三、HTTPS协议

四、DNS协议

零碎知识

1. Get 请求和 POST 请求的区别

与协议相关的

  1. GET 请求的参数放在 URL 中,而 POST 请求的参数放在请求体中

    按照 HTTP 协议要求,GET 请求的参数,应该拼接在报文的 URL 上 按照 HTTP 协议要求,POST 请求的参数,放在请求体中

    这并不意味着 GET 请求没有请求体,如果用 node 的 net 模块获取 HTTP GET 请求的请求体,如果有,可以拿到的。

    每个浏览器 XMLHttpRequest 实现不一样,GET 请求报文 URL 最大长度限制就不一样

  2. GET 请求只能进行 URL 编码,而 POST 请求支持多种编码方式

  3. GET 产生一个 TCP 数据包,POST 产生两个 TCP 数据包

    对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200 而对于 POST,浏览器先发送 header,服务器响应100 continue,浏览器再发送 data,服务器响应200

与浏览器相关的

  1. GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。

    缓存失效前,发起同一个 GET 请求(报文相同),浏览器会从缓存中获取结果,直接返回。 解决方式:xhr.open(url)时,给 url 添加随机数参数