开篇诗两句:

借问江潮与海水,何似君情与妾心。

相恨不如潮有信,相思始觉海非深。 ——白居易《浪淘沙》



HTTP协议发展历史

版本 描述 功能演进
HTTP/0.9 20世纪90年代,纯文本格式,只允许GET动作 纯文本,仅支持GET动作
HTTP/1.0 1996年正式发布,在0.9版本上增强很多,形式上与当前正在使用的HTTP差别不大 (1)增加HEAD、POST等方法
(2)增加响应状态码,标记可能的错误原因
(3)引入协议版本号概念
(4)引入HTTP Header头部
(5)传输数据不再仅限于文本
HTTP/1.1 1999年发布RFC文档,对1.0版本进行小幅修改,成为正式的标准 (1)增加PUT、DELETE等方法
(2)增加缓存管理
(3)增加连接管理,允许持久连接
(4)支持响应数据分块,大文件传输
(5)强制要求Host头
HTTP/2 2015年发布RFC文档,2.0版本正式发布 (1)二进制协议,不再是纯文本
(2)可发起多个请求,废弃1.1版本的管道
(3)使用专用算法压缩头部,减少传输数据量
(4)服务器可以主动向客户端推数据
(5)加密通信
HTTP/3 2018年基于QUIC协议的3.0版本进入标准化制定阶段  

HTTP协议概述

HTTP协议(HyperText Transfer Protocol,超文本传输协议),

HTTP协议的特点:

(1)灵活可扩展:HTTP报文格式采用header+body的方式,并且用户可以根据自己需要定义字段,具有非常高的灵活性和扩展性。

(2)可靠传输:底层采用TCP/IP协议,具有一定的可靠性保证,也正是采用了TCP/IP协议,所以性能方面并不是HTTP协议的优势。

(3)应用广泛:软硬件环境都非常成熟

(4)无状态:即是优点也是缺点,不用记录状态信息,实现起来会非常简单。缺点就是没有办法执行需要多步的事务操作,为了实现多步请求的事务操作,需要在每次请求中携带全部的状态信息,增加很多数据传输量。(Cookie能够缓解此类问题)

(5)明文传输:明文的好处就是方便用户理解使用,但是带来的问题就是不安全,通过拦截HTTP报文可以很容易的获取到传入的内容信息。

网络分层模型

TCP/IP网络分层模型:(1)链接层(2)网际层(3)传输层(4)应用层

OSI网络分层模型:(1)物理层(2)数据链路层(3)网络层(4)传输层(5)会话层(6)表示层(7)应用层

报文内容

HTTP协议的请求报文和响应报文结构基本相同,由三部分组成:

(1)起始行(start line):描述请求或相应的基本信息

(2)头部(header):使用key-value形式记录头部字段

(3)消息正文(body):实际传输的数据,不一定是纯文本,可以是图片视频等二进制数据

请求行和状态行

(1)请求报文中的起始行也叫做请求行,主要由三部分组成:(a)请求方法(b)请求目标(c)版本号

例如:GET / HTTP/1.1, GET是请求方法,/ 是请求目标,通常是URI,HTTP/1.1是版本号

(2)响应报文种的起始行叫做状态行,主要由三部分组成:(a)版本号(b)状态码(c)原因

例如:HTTP/1.1 200 OK

头部字段

头部字段采用key-value的形式,并且请求报文和响应报文的头部字段格式基本一致,这里仅按照请求报文进行介绍:

字段名不区分大小写,不允许空格,不能使用下划线”_“,字段名后必须紧接着”:”,”:”后可以有多个空格。字段的顺序没有意义。

请求方法

HTTP/1.1中规定了八种方法:

(1)GET和HEAD:GET和HEAD方法都是从服务器获取数据,不同点是HEAD不会传输body数据

(2)POST和PUT:POST和PUT基本相同,一般情况认为POST是创建数据,PUT是更新数据

下面方法没用过,文字搬运,仅用于了解

(3)DELETE:用于服务器删除资源。由于风险较高,一般服务器只标记资源删除状态,不会真正执行删除逻辑,或者服务器根本不处理DELETE请求

(4)CONNECT:要求服务器为客户端和另一台远程服务器建立一条特殊的连接隧道,这时Web服务器在中间充当了代理的角色

(5)OPTIONS:要求服务器列出可对资源实行的操作方法,在响应头的Allow字段里返回

(6)TRACE:用于对HTTP链路的测试或诊断,可以显示出请求-响应的传输路径。它的本意是好的,但存在漏洞,会泄漏网站的信息,所以Web服务器通常也是禁止使用

响应状态码

RFC标准把状态码分为5类:

  • 1XX:提示信息,表示目前是协议处理的中间状态,还需要后续操作

    状态码 描述
    101 偶尔能见到101 Switching Protocols,要求在HTTP协议的基础上改成其他协议通信
  • 2XX:成功,报文已经被成功收到并且成功处理

    状态码 描述
    200 200 OK是最常见的状态码
    204 204 No Content200 OK基本相同,但是响应头后没有body数据
    206 206 Partial Content是HTTP分块下载或断点续传的基础,与200一样,表示服务器正确处理了请求,但是body里不只是资源的部分数据
  • 3XX:重定向,资源位置发生变动,需要客户端重新发送请求

    状态码 描述
    301 301 Moved Permanently表示永久重定向,表示资源不存在了,需要使用新的URI访问
    302 302 Found表示临时重定向
    304 304 Not Modified表示缓存重定向,用于缓存控制,没有通常跳转的含义
  • 4XX:客户端错误,请求报文有误,服务器无法处理

    状态码 描述
    400 400 Bad Request是一个通用状态码,表述请求报文有误,但是没有表明具体是什么错误(尽量避免返回400)
    403 403 Forbidden表示服务器禁止访问资源
    404 404 Not Found原意表示请求的资源在服务端没有找到
    405 405 Method Not Allowed不允许某些方法操作资源,例如不允许POST只允许GET
    406 406 Not Acceptable资源无法满足客户端请求的条件
    408 408 Request Timeout请求超时
    409 409 Conflict多个请求发生了冲突
    413 413 Request Entity Too Large表示请求报文里的body太大
    414 414 Request-URI Too Long表示请求行里的URI太大
    429 429 Too Many Requests表示客户端的请求数量太多,通常取决于服务端的限流策略
    431 431 Request Header Fields Too Large表示请求头中某个字段或者整体太大
  • 5XX:服务器错误,服务器在处理请求时内部发生错误

    状态码 描述
    500 500 Internal Server Error与400类似,一个通用的错误码,但是没有说明具体错误是什么
    501 501 Not Implemented表示客户端请求的功能还不支持
    502 502 Bad Gateway通常表示服务器作为网关或者代理时返回的错误码,表示自身工作正常,但是访问后端服务器时出错,同样不知道错误的具体原因
    503 503 Service Unavailable表示服务器当前很忙,暂时无法响应请求

连接管理

短连接和长连接

最初HTTP(0.9/1.0)采用的是短链接,因为HTTP底层使用的是TCP/IP协议,在每次发送请求时会与服务器建立链接,通信完成会立即关闭链接。因为TCP链接的建立和关闭都是非常占用资源的操作,导致短链接的缺点非常明显。

HTTP/1.1中会默认使用长连接,但是链接长时间不关同样会导致服务端资源浪费,并且通常情况下服务端是不会主动要求关闭长连接的。通常关闭长连接的方式(1)设置链接超时间(2)设置链接能够发送的请求数量(3)客户端主动要求关闭链接

队头阻塞

队头阻塞产生的原因与长连接还是短连接没有关系,而是由HTTP基本的”请求-应答”模式导致的。

HTTP报文必须是”一发一收”,如果队首的报文处理时间过长,后面的报文就要一直等待。

关于队头阻塞的问题,采用的优化方式是”并发连接“的方式,但是HTTP协议和浏览器会限制并发连接的数量。有些还会使用”域名分片“的技术摆脱HTTP协议和浏览器的限制,简单来说就是多开几个域名指向同一个服务器。

缓存管理

主要通过请求头字段Cookie和响应头字段Set-Cookie实现。

服务端通过响应头中Set-Cookie字段将身份信息发送给客户端(浏览器),当需要保存的信息比较多时,Set-Cookie字段可有有多个。服务器通过这种方式来委托浏览器保存身份信息,并且可以设置Cookie的有效期和作用域的属性。

浏览器下次请求时,在请求头字段Cookie中携带这些身份信息,服务端就可以根据这些身份信息进行一些个性化处理。对于多条身份信息,不需要多个Cookie字段,只要在Cookie字段中通过分号隔开即可。

缓存控制

服务端缓存控制

服务端通过在响应头字段中增加”Cache-Control“字段来通知浏览器缓存控制,常用的字段主要有:

字段名 描述
max-age 缓存控制最常用的字段,表示缓存的有效时间(从服务端响应开始算起)
no-store 不允许缓存,通常用于变化非常频繁的数据
no-cache 可以缓存,但是使用之前必须从服务器验证缓存是否过期
must-revalidate 缓存不过期就可以使用,但是如果过期了就必须去服务器验证

客户端缓存控制

浏览器同样可以发送带有”Cache-Control“字段的请求

字段名 描述
max-age 请求max-age设置的缓存时间的数据,如果本地缓存数据的时间超过该值,会从服务端请求数据
no-cache 与max-age=0的含义基本一致,具体看服务器怎么处理
if-Modified-Since 条件请求,当前数据如果不是最新的,发送最新的数据。
If-None-Match 条件请求,如果当前数据不匹配发送的条件(一般是判断ETag),则发送新的数据
If-Unmodified-Since 条件请求,如果数据没有修改过,发送当前的数据
If-Match 条件请求,如果数据匹配条件,发送最新的数据
If-Range 条件请求,如果数据满足指定范围,发送最新的数据

第一次响应的报文中需要预先提供”Last-modified“和”ETag“。

Last-modified:文件的最后修改时间

ETag(Entity Tag):资源的唯一标识

条件请求一般会带上这两个数据,用于条件判断和规则匹配,如果不需要发送新数据,会返回304(缓存重定向)

缓存代理

服务端缓存控制

前面缓存控制中介绍的字段对于缓存代理同样生效,因为缓存代理相对于服务端来说就是客户端。(这里只介绍代理相关的缓存控制字段)

字段名 描述
private/public private表示缓存只能保存在客户端,不能存在代理。public表示缓存谁都可以用
proxy-revalidate must-revalidate表示缓存过期必须回源服务器进行验证,proxy-revalidate表示只需要验证到代理即可,但是代理服务器缓存过期需要回源服务器验证
s-maxage 代理上缓存有效时间,客户端仍然使用max-age
no-transform 代理有时会对数据做一些优化,该字段表示代理不允许对数据进行处理

客户端缓存控制

同样缓存控制中介绍的字段对于缓存代理同样有效。(这里只介绍缓存代理相关的缓存控制字段)

字段名 描述
max-stale 代理上缓存保存时间超过客户端的max-age,也同样可以接受,但是不能超过max-stale设置的时间
min-flesh 代理上的缓存必须有效,并且min-flesh设置的时间之后仍然有效
only-if-cached 只接受代理缓存,不接收源服务器响应。如果代理上没有缓存或者缓存过期,会返回504(Gateway Timeout)