HTTP

Http(Hyper Text Transfer Protocol),Web应用程序使用的应用协议,它使用TCP作为传输层协议

Http是无状态的协议,意思是Http不会保存任何请求的任何信息

持续性连接和非持续性连接

  • 持续性连接:客户端与服务端每次交互请求/响应通过一个单独的TCP连接发送
  • 非持续性连接:客户端与服务端每次交互请求/响应都通过同一个TCP连接发送

HTTP默认采用的是持续性连接

当采用非持续性连接时一个HTTP请求的执行过程

假设Url为:http://www.google.com/index.php,并且该网页上有6张jpg格式的图片

  • HTTP客户端进程在端口号80发起一个到服务器www.google.comTCP连接80端口为HTTP的默认端口号
  • HTTP客户端通过socket向服务器发送一个HTTP请求报文,请求其index.php这个HTML资源
  • HTTP服务器通过socket接收到该请求报文,然后在磁盘中检索到对应的资源文件,封装一个HTTP响应报文,并通过socket向客户端回送响应报文
  • HTTP服务器进程通知TCP断开该连接,当TCP确认客户端已经收到响应之后,连接断开
  • HTTP客户端接收响应报文,TCP连接关闭,提取出HTML文件,得到6个jpg图片的引用
  • HTTP客户端对每个引用的jpg图片重复前面4个步骤

这里一个HTTP请求需要建立7个TCP连接(1个HTML + 6张图片资源),TCP连接之间可以是串行或者是并行,浏览器默认打开5-10个并行的TCP连接,使用并行连接可以缩短响应时间

这个HTTP请求花费了多少时间?

这里需要知道往返时间(RTT, Round-Trip Time),意思是一个短分组(packet)从客户端到服务器然后再返回客户端的时间,RTT包括了分组传播时延,分组在路由器和交换机上的排队时延以及分组处理时延

当用户输入网址,按下回车后,首先会使得浏览器(客户端)和Web服务器之间建立一个TCP连接,三次握手:

  1. 客户端发送建立TCP连接请求到Web服务器
  2. Web服务器回送响应
  3. 客户端向Web服务器发送HTTP请求报文

步骤1、2消耗了一个RTT,步骤3加上服务器回送响应也消耗了一个RTT,总耗时为(2 * RTT + HTML文件传输的时间)

缺点

  • 为每个请求的对象都建立一次TCP连接,在客户端和服务端都需要分配TCP缓冲区后台保持TCP变量,增加了Web服务器的压力,因为一台Web服务器会同时面对多个客户端的请求
  • 每个对象都需要消耗2*RTT的交付时延

采用持续性连接

采用HTTP1.1持续连接,服务器在回送响应后会保持该TCP连接打开,后续如果相同的客户端再次发送请求,那么还可以重复使用该TCP连接,当一定时间内TCP连接未被使用,则该连接会被HTTP服务器关闭

HTTP请求报文

# 请求行
GET /mmcrhead/Q1Y0/0 HTTP/1.1 
# 首部行
Connection: Keep-Alive  # 持续连接
Host: wx.qlogo.cn       # 请求对象所在主机
User-Agent: MicroMessenger Client   # 用户代理(浏览器类型)
# 实体体,本例中请求方法为GET,实体行为空

一个HTTP请求报文由3部分组成:

  • 请求行:由3个部分组成,请求方法,URL地址,HTTP版本,请求方法可以是GET/POST/PUT/DELETE/HEAD等等
    • GET方法通常用于获取服务器中的对象
    • POST通常用于新增对象到服务器,比如提交表单时
    • PUT通常用于更新服务器中的对象
    • DELETE通常用于删除服务器中的对象
    • HEAD与GET类似,HTTP服务器正常响应该请求,但不回送请求对象
  • 首部行:
  • 实体体(非GET请求时不为空)

HTTP响应报文

# 状态行
HTTP/1.1 200 OK
# 首部行
Date: Mon, 27 Jul 2020 13:49:36 GMT     # 时间
# 服务器版本
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.7 mod_perl/2.0.11 Perl/v5.16.3
X-Powered-By: PHP/7.4.7 
# 实体体的长度
Content-Length: 6963
# 实体体的类型
Content-Type: text/html; charset=UTF-8
# 实体体
(data...)

一个HTTP响应报文由3部分组成:

  • 初始状态行:由3部分组成,从左到右分别为协议版本号,状态码,状态信息
  • 首部行
  • 实体体:报文体,包含了请求对象本身

常见的HTTP状态码

  • 200:服务器正常响应
  • 301:请求对象被永久转移,新的URL定义在响应报文的首部行Location字段中
  • 304:请求对象未被修改
  • 400:请求不能被服务器理解,通常是参数错误
  • 404:请求的对象不在服务器上
  • 500:服务器内部异常

Web缓存

又称为代理服务器,能够代表Web服务器来满足HTTP请求,Web缓存器有自己的磁盘,磁盘中保留了最近请求过的对象副本,当配置了Web缓存器后,用户的HTTP请求首先指向该缓存器,其访问过程为

  1. 浏览器创建一个到Web缓存器的TCP连接,并向Web缓存器中的对象发出HTTP请求
  2. Web缓存器检查自身磁盘中是否有该对象的副本,如果有,直接封装该对象到HTTP响应报文并回送该响应报文
  3. 如果Web缓存器中没有该对象,则它会创建一个到HTTP服务器的TCP连接,并发送一个该对象的HTTP请求
  4. 当HTTP服务器回送响应报文后,将对象缓存一份到Web缓存器的磁盘中,并将其返回给浏览器

在这个过程中,Web缓存器即充当了服务端,又充当了客户端

部署Web缓存器的好处:

  • 能够减少对客户请求的响应时间,因为一部分对象已经存储在Web缓存器自己的磁盘中了
  • 能够减少接入到因特网的通信量,意味着带宽成本的减少
  • 能够从整体上减少因特网的Web流量,改善所有应用的性能

CDN(Content Distribution Network,内容分发网络)公司就大量使用了Web缓存器,使大量的流量实现本地化

条件GET方法

部署了Web缓存器能够减少用户请求的响应时间,但是如何保证Web缓存器中的对象一定是最新的呢?

HTTP协议中有一种机制,允许缓存器确认它的对象是最新的,即条件GET方法:

  • 请求方法为GET
  • 并且请求报文中包含If-Modified-Since首部行

满足以上两个条件的HTTP请求报文,就是条件GET请求报文

当Web缓存器向HTTP服务器发送的请求后,HTTP服务器会将包含被请求对象的响应报文回送给Web缓存器,并在响应报文的首部行中添加一个Last-Modified字段,表示对象最后的修改时间

当下一次用户再次给Web缓存器发送对该对象的HTTP请求时,Web缓存器首先发送一个携带首部行If-Modified-Since字段的HTTP请求给HTTP服务器,接着服务器会查询该对象是否改变,如果没有改变,则返回带有该请求对象的HTTP响应报文,并且该响应的状态行的状态码被置为304 NotModified,表示Web缓存器仍然可以直接使用其缓存的对象