计网基础-HTTP综合

loading 2023年01月28日 108次浏览

HTTP,超文本传输协议,是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」

1. 状态码

  • 1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
    • 100 Continue 表明目前为止,所有的请求内容都是可行的,客户端应该继续请求,如果完成,则忽略它。
    • 101 Switching Protocol 这个状态码表示服务器正在根据客户端的请求切换协议。服务器会在响应中发送一个Upgrade响应头,表明即将切换的协议。
    • 103 Early Hints 表示服务器还在准备响应的过程中,允许用户代理开始预加载资源。
  • 2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
    • 200 OK 最常见的成功状态码,代表一切正常,服务器返回的响应头有body数据
    • 204 NO Content 和200区别在于响应头没有body数据
    • 206 Partial Content 应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分
  • 3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
    • 301 Moved Permanently 表示永久重定向,请求的资源已经不存在了
    • 302 Found 表示临时重定向,请求的资源还在,但要用另一个URL来访问
    • 304 Not Modified 表示缓存重定向,资源并未修改,但是重定向到缓存文件,告诉客户端可以使用缓存资源,用于缓存控制 (协商缓存)
  • 4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
    • 400 Bad Request 客户端请求报文出错,但只是个笼统的错误
    • 401 Unauthorized 这个状态码表示请求需要用户验证。换句话说,客户端必须先验证自己的身份(通常是通过用户名和密码),然后才能继续请求。例如,当你试图访问一个需要登录的网页,但你没有提供正确的用户名和密码时,服务器就会返回401状态码。
    • 403 Forbidden 这个状态码表示服务器理解了客户端的请求,但是拒绝执行。这通常是因为客户端没有足够的权限。换句话说,即使客户端已经通过了身份验证,但是它仍然没有权限访问请求的资源。例如,当你试图访问一个只有管理员才能访问的网页,而你并非管理员时,服务器就会返回403状态码。
    • 404 Not Found 客户端请求的资源在服务器上没找到
  • 5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
    • 500 Internal Server Error 类似于400,笼统的服务器错误码
    • 501 Not Implemented 表示客户端请求的功能还不支持,例如,如果你发送了一个服务器不支持的HTTP方法,比如TRACE或CONNECT,服务器就可能返回501状态码
    • 502 Bad Gateway 通常是作为网关或代理的服务器时返回的错误码,表示服务器自身工作正常,但访问后端服务器时收到无效的响应
    • 503 Service Unavailable 表示当前服务器正在停机维护或者过载,无法响应客户端

2. HTTP常见字段

(1) HOST
客户端发送请求时,用来指定服务器的域名,有了 Host 字段,就可以将请求发往「同一台」服务器上的不同网站。

(2) Content-Length
服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度

HTTP 协议通过设置回车符、换行符作为 HTTP header 的边界,通过 Content-Length 字段作为 HTTP body 的边界,这两个方式都是为了解决“粘包”的问题。

(3) Connection
Connection 字段最常用于客户端要求服务器使用「HTTP 长连接」机制,以便其他请求复用。

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。开启了 HTTP Keep-Alive 机制后, 连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个连接,一直持续到客户端或服务器端提出断开连接。

HTTP/1.1 版本的默认连接都是长连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为 Keep-Alive。

(4) Accept / Content-Type
客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式。

Content-Type 字段用于服务器回应时,告诉客户端,本次数据是什么格式。

上面的字段表明,客户端声明自己可以接受任何格式的数据,服务器发送的是网页,而且编码是UTF-8。

(5) Accept-Encoding / Content-Encoding
客户端在请求时,用 Accept-Encoding 字段说明自己可以接受哪些压缩方法。

Content-Encoding 字段表示服务器返回的数据使用了什么压缩方法。

Accept-Encoding: gzip, deflate
Content-Encoding: gzip

3. HTTP1.1相较于1.0的性能优化

3.1 长连接

HTTP/1.0一个很大的性能问题在于每发起一次请求,都需要新建立一次TCP连接(三次握手),大大增加了开销。

为了解决上述 TCP 连接问题,HTTP/1.1 提出了长连接的通信方式,也叫持久连接。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态

这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。

当然,如果某个 HTTP 长连接超过一定时间没有任何数据交互,服务端就会主动断开这个连接。

3.2 管道网络传输

知道有这个功能即可,实际开发中大部分浏览器并不提供相应的支持

HTTP/1.1 采用了长连接的方式,这使得管道(pipeline)网络传输成为了可能。

管道传输:在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

以前客户端必须等来服务器的回应之后才能发出下一个请求,现在管道机制允许客户端哪怕在等到回应前也能发出多个请求。

但是服务器必须按照接受请求的顺序来进行响应

如果服务端在处理 A 请求时耗时比较长,那么后续的请求的处理都会被阻塞住,这称为「队头堵塞」。
所以,HTTP/1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞

3.3 缓存

  • HTTP1.0 主要使⽤ If-Modified-Since/Last-Modified 和 Expires 来做为缓存判断的标准
  • HTTP1.1 则引⼊了更多的缓存控制策略例如 E-tag / If-None-Match 和 Cache-Control 等更多可供选择的缓存头来控制缓存策略。

3.4 带宽优化

  • HTTP1.0 中,存在⼀些浪费带宽的现象,例如客户端只是需要某个对象的⼀部分,⽽服务器却将整个对象送过来了,并且不⽀持断点续传功能。
  • HTTP1.1 则在请求头引⼊了 range 头域,它允许只请求资源的某个部分,即返回码是 206。

3.5 优化HTTP1.1

我们可以从下面这三种优化思路来优化 HTTP/1.1 协议:

  1. 避免发送HTTP
    通过强缓存和协商缓存来避免发送HTTP请求。

  2. 减少发送HTTP

  • 通过将重定向工作交给代理服务器实现减少重定向次数
  • 合并请求可以减少重复发送的HTTP头部,也可以减少TCP连接的数量,具体案例比如雪碧图
  • 延迟发送请求,思路类似于懒加载
  1. 减少HTTP响应数据大小
    通过无损压缩(Accept-Encoding / Content-Encoding)和有损压缩(Accept: q=0.2)实现

4. HTTP2、HTTP3相较于1.1的性能优化

4.1 HTTP2

HTTP2是基于HTTPS的,因此也保证了安全性。

HTTP2相较于HTTP1.1作了如下改进:

4.1.1 头部压缩

HTTP/2 会请求压缩头部(Header),如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分

这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

4.1.2 二进制格式

HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧,增加了数据传输的效率

4.1.3 多路复用

HTTP1.1的实现是基于请求-响应模型的,存在上面提到的队头阻塞问题。

HTTP2并没有完全解决队头阻塞问题,详情见下面写的缺陷。

HTTP/2引入了 Stream 概念,一条TCP连接中复用了多路stream:

针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是HTTP/2可以并行交错地发送请求和响应

4.1.4 服务器推送

HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务端不再是被动地响应,可以主动向客户端发送消息,客户端和服务器双方都可以建立 Stream。

缺陷:
HTTP2在HTTP层面解决了队头阻塞问题,但在TCP层面并未解决。

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用。
那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
在TCP连接中,数据包必须按照发送的顺序到达接收方。如果网络中的某个数据包丢失,那么TCP会停止数据的发送,直到丢失的数据包被重新发送并成功接收。这就可能导致HTTP/2的多路复用在遇到网络丢包时效果并不理想。

而且,在实际中,TCP的连接buffer有限,一个响应又慢又大的请求可能会把连接buffer完全占满,导致buffer阻塞,从而产生类似于队头阻塞的效果。

4.2 HTTP3

从上面我们知道,HTTP/1.1 中的管道虽然解决了请求的队头阻塞,但是没有解决响应的队头阻塞; HTTP2在HTTP层面解决了队头阻塞问题,但在TCP层面并未解决.

4.2.1 改用UDP

HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP

UDP 发送是不管顺序,也不管丢包的,所以不会出现像 HTTP/2 队头阻塞的问题。大家都知道 UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。

4.2.2 QUIC

QUIC具有以下三个特点:

  • 无队头阻塞: QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。
  • 更快的连接建立: 对于HTTP1和2,TCP和TLS是分层的,要建立两次连接,而QUIC协议内部就包含了TLS,简化为一次QUIC连接。
  • 连接迁移: 基于TCP的HTTP当设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接,显得卡顿;而QUIC可以实现无缝的连接迁移。