Http 重点知识点

参考:

图解 Http 1.5、1.7、第2章、3.1、3.2、第4章
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control

DNS

DNS(Domain Name System)服务是和 HTTP 协议一样位于应用层的 协议。它提供 域名IP地址 之间的解析服务。

URI 和 URL

URI(统一资源标识符)<---> URL(Uniform Resource Locator,统一资源定位符)

URI 就是由某个协议方案表示的资源的定位标识符。协议方案是指访问资源所使用的协议类型名称。

URI 举例

ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2

URI 的格式:

http:// user:pass @www.example.jp: 80 /dir/index.htm ?uid=1 #ch2

协议名 + 登录信息 + 服务器地址 + 服务器端口号 + 带层次的文件路径 + 查询字符串 + 片段标识符

并不是所有的应用程序都符合 RFC

HTTP 协议报文示例

Request <====> Response

请求报文:

GET / HTTP/1.1
Host: hackr.jp
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
If-Modified-Since: Fri, 31 Aug 2007 02:02:20 GMT
If-None-Match: "45bae1-16a-46d776ac"
Cache-Control: max-age=0

响应报文:

HTTP/1.1 304 Not Modified
Date: Thu, 07 Jun 2012 07:21:36 GMT
Server: Apache
Connection: close
Etag: "45bae1-16a-46d776ac"

结构为

Header
CR+LF //空行回车分割
Body

Http 协议特征

HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同,用于客户端和 服务器之间的通信。

HTTP 通过请求和响应的交换达成通信

HTTP 是不保存状态的协议

使用 Cookie (进行状态管理) 和 Session (记录会话状态)

HTTP 使用 方法 下达命令 (一般常用的是 GET 和 POST)

一些其他的方法会引起安全问题, 比如 PUT 和 DELETE , Tomcat 就出现过这种问题

HTTP 通过请求 URI 定位资源

HTTP 的持久连接和管线化

  1. 请求报文(没有 Cookie 信息的状态)
GET /reader/ HTTP/1.1 
Host: hackr.jp 
*首部字段内没有Cookie的相关信息 
  1. 响应报文(服务器端生成 Cookie 信息)
HTTP/1.1 200 OK 
Date: Thu, 12 Jul 2012 07:12:20 GMT 
Server: Apache 
Set-Cookie: sid=1342077140226724; path=/; expires=Wed, 10-Oct-12 07:12:20 GMT; domain=baidu.com;
Content-Type: text/plain; charset=UTF-8 

按时间有效期分类:

  • 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
  • 持久性 Cookie:指定过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。

指定作用域:

Domain 标识指定了哪些主机可以接受 Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了 Domain,则一般包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如 developer.mozilla.org)。

Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。

  1. 请求报文(自动发送保存着的 Cookie 信息)
GET /image/ HTTP/1.1 
Host: hackr.jp 
Cookie: sid=1342077140226724
  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

HTTP 报文详解

用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。

HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。

HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的 空行(CR+LF)来划分。通常,并不一定要有报文主体。

HTTP 状态码

状态码类别含义
1XXInformational(信息性状态码)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错

2XX 成功

200 OK

204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。

206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。

3XX 重定向

301 Moved Permanently :永久性重定向

302 Found :临时性重定向

303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。

注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。

304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。

304 在缓存管理中常用

307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。

4XX 客户端错误

400 Bad Request :请求报文中存在语法错误。

401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。

403 Forbidden :请求被拒绝。

404 Not Found

5XX 服务器错误

500 Internal Server Error :服务器正在执行请求时发生错误。

503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

HTTP 首部字段

有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。

各种首部字段及其含义如下(不需要全记,仅供查阅):

通用首部字段

首部字段名说明
Cache-Control控制缓存的行为
Connection控制不再转发给代理的首部字段、管理持久连接
Date创建报文的日期时间
Pragma报文指令
Trailer报文末端的首部一览
Transfer-Encoding指定报文主体的传输编码方式
Upgrade升级为其他协议
Via代理服务器的相关信息
Warning错误通知

请求首部字段

首部字段名说明
Accept用户代理可处理的媒体类型
Accept-Charset优先的字符集
Accept-Encoding优先的内容编码
Accept-Language优先的语言(自然语言)
AuthorizationWeb 认证信息
Expect期待服务器的特定行为
From用户的电子邮箱地址
Host请求资源所在服务器
If-Match比较实体标记(ETag)
If-Modified-Since比较资源的更新时间
If-None-Match比较实体标记(与 If-Match 相反)
If-Range资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since比较资源的更新时间(与 If-Modified-Since 相反)
Max-Forwards最大传输逐跳数
Proxy-Authorization代理服务器要求客户端的认证信息
Range实体的字节范围请求
Referer对请求中 URI 的原始获取方
TE传输编码的优先级
User-AgentHTTP 客户端程序的信息

响应首部字段

首部字段名说明
Accept-Ranges是否接受字节范围请求
Age推算资源创建经过时间
ETag资源的匹配信息
Location令客户端重定向至指定 URI
Proxy-Authenticate代理服务器对客户端的认证信息
Retry-After对再次发起请求的时机要求
ServerHTTP 服务器的安装信息
Vary代理服务器缓存的管理信息
WWW-Authenticate服务器对客户端的认证信息

实体首部字段

首部字段名说明
Allow资源可支持的 HTTP 方法
Content-Encoding实体主体适用的编码方式
Content-Language实体主体的自然语言
Content-Length实体主体的大小
Content-Location替代对应资源的 URI
Content-MD5实体主体的报文摘要
Content-Range实体主体的位置范围
Content-Type实体主体的媒体类型
Expires实体主体过期的日期时间
Last-Modified资源的最后修改日期时间

HTTP 连接管理

为了避免短链接 TCP 的巨大开销

  • 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 Connection : close
  • 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 Connection : Keep-Alive
  • HTTP 长连接不仅仅减少了 TCP 连接资源的开销,而且这给 HTTP 流水线技术提供了可实现的基础。流水线是在同一条长连接上连续发出请求,而不用立刻等待响应返回,这样可以减少延迟。

Q: Http 和 TCP 的 Keep-Alive 有什么区别?

A:首先这两个是完全不同的机制:

  • HTTP 的 Keep-Alive,是由应用层(用户态)实现的,称为 HTTP 长连接;
  • TCP 的 Keepalive,是由TCP 层(内核态)实现的,称为 TCP 保活机制;

HTTP 的 Keep-Alive 也叫 HTTP 长连接,该功能是由「应用程序」实现的,可以使得用同一个 TCP 连接来发送和接收多个 HTTP 请求/应答,减少了 HTTP 短连接带来的多次 TCP 连接建立和释放的开销。

TCP 的 Keepalive 也叫 TCP 保活机制,该功能是由「内核」实现的,当客户端和服务端长达一定时间没有进行数据交互时,内核为了确保该连接是否还有效,就会发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接。

HTTP 缓存管理

  • 缓解服务器压力;
  • 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。

缓存请求指令

Cache-Control客户端可以在 HTTP 请求中使用的标准指令。

GET /demo/ HTTP/1.1
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache 
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached

缓存响应指令

Cache-Control服务器可以在 HTTP 响应中使用的标准指令。

HTTP/1.1 200 OK
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>

一个问题:缓存在哪?

  • 让代理服务器 CDN 进行缓存。
  • 让客户端浏览器进行缓存。

实现方法:

  • 强制缓存 (服务端响应中使用)

Expires:

HTTP/1.1 200 OK
Expires: Wed, 8 Apr 2020 07:28:00 GMT

最早也最不周全的

Cache-Control:

HTTP/1.1 200 OK
Cache-Control: max-age=600; 

max-ages-maxage:max-age 后面跟随一个以秒为单位的数字,表明相对于请求时间(在 Date Header 中会注明请求时间)多少秒以内缓存是有效的,资源不需要重新从服务器中获取。s-maxage 中的“s”是“Share”的缩写,意味“共享缓存”的有效时间,即允许被 CDN、代理等持有的缓存有效时间,用于提示 CDN 这类服务器应在何时让缓存失效。

smaxage 优先级更高,一般协议规定在多用户共享的资源缓存,先考虑共享再考虑自己私有

publicprivate:指明是否涉及到用户身份的私有资源,如果是 public,则可以被代理、CDN 等缓存,如果是 private,则只能由用户的客户端进行私有缓存。

no-cacheno-store:no-cache 指明该资源不应该被缓存,哪怕是同一个会话中对同一个 URL 地址的请求,也必须从服务端获取,令强制缓存完全失效,但此时下一节中的协商缓存机制依然是生效的;no-store 不强制会话中相同 URL 资源的重复获取,但禁止浏览器、CDN 等以任何形式保存该资源。

  • 协商缓存

一种基于变化检测的缓存机制,在一致性上会有比强制缓存更好的表现,但需要一次变化检测的交互开销,性能上就会略差一些,这种基于检测的缓存机制,通常被称为“协商缓存”。

应注意在 HTTP 中协商缓存与强制缓存并没有互斥性,这两套机制是并行工作的

当强制缓存存在时,直接从强制缓存中返回资源,无须进行变动检查;而当强制缓存超过时效,或者被禁止(no-cache / must-revalidate),协商缓存仍可以正常地工作。协商缓存有两种变动检查机制,分别是根据资源的修改时间进行检查,以及根据资源唯一标识是否发生变化来进行检查,它们都是靠一组成对出现的请求、响应 Header 来实现的:

Last-Modified 和 If-Modified-SinceLast-Modified 是服务器的响应 Header,用于告诉客户端这个资源的最后修改时间。对于带有这个 Header 的资源,当客户端需要再次请求时,会通过 If-Modified-Since 把之前收到的资源最后修改时间发送回服务端。

如果此时服务端发现资源在该时间后没有被修改过,就只要返回一个 304/Not Modified 的响应即可,无须附带消息体,达到节省流量的目的,如下所示:

HTTP/1.1 304 Not Modified
Cache-Control: public, max-age=600
Last-Modified: Wed, 8 Apr 2020 15:31:30 GMT

如果此时服务端发现资源在该时间之后有变动,就会返回 200/OK 的完整响应,在消息体中包含最新的资源,如下所示:

HTTP/1.1 200 OK
Cache-Control: public, max-age=600
Last-Modified: Wed, 8 Apr 2020 15:31:30 GMT
Content-Length: 648

DATA-DTAT-DTAT------

Etag 和 If-None-Match:Etag 是服务器的响应 Header,用于告诉客户端这个资源的唯一标识。HTTP 服务器可以根据自己的意愿来选择如何生成这个标识,譬如 Apache 服务器的 Etag 值默认是对文件的索引节点(INode),大小和最后修改时间进行哈希计算后得到的。对于带有这个 Header 的资源,当客户端需要再次请求时,会通过 If-None-Match 把之前收到的资源唯一标识发送回服务端。

如果此时服务端计算后发现资源的唯一标识与上传回来的一致,说明资源没有被修改过,就只要返回一个 304/Not Modified 的响应即可,无须附带消息体,达到节省流量的目的,如下所示:

HTTP/1.1 304 Not Modified
Cache-Control: public, max-age=600
ETag: "28c3f612-ceb0-4ddc-ae35-791ca840c5fa"

如果此时服务端发现资源的唯一标识有变动,就会返回 200/OK 的完整响应,在消息体中包含最新的资源,如下所示:

HTTP/1.1 200 OK
Cache-Control: public, max-age=600
ETag: "28c3f612-ceb0-4ddc-ae35-791ca840c5fa"
Content-Length: 648

DATA-DTAT-DTAT------

Etag 是 HTTP 中一致性最强的缓存机制,譬如,Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在 1 秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间;又或者如果某些文件会被定期生成,可能内容并没有任何变化,但 Last-Modified 却改变了,导致文件无法有效使用缓存,这些情况 Last-Modified 都有可能产生资源一致性问题,只能使用 Etag 解决。

Etag 却又是 HTTP 中性能最差的缓存机制,体现在每次请求时,服务端都必须对资源进行哈希计算,这比起简单获取一下修改时间,开销要大了很多。Etag 和 Last-Modified 是允许一起使用的,服务器会优先验证 Etag,在 Etag 一致的情况下,再去对比 Last-Modified,这是为了防止有一些 HTTP 服务器未将文件修改日期纳入哈希范围内。

HTTPS 采用的加密方式

对称密钥加密方式的传输效率更高,但是无法安全地将密钥 Secret Key 传输给通信方。而非对称密钥加密方式可以保证传输的安全性,因此我们可以利用非对称密钥加密方式将 Secret Key 传输给通信方。HTTPS 采用混合的加密机制,正是利用了上面提到的方案:

  • 使用非对称密钥加密方式,传输对称密钥加密方式所需要的 Secret Key,从而保证安全性;
  • 获取到 Secret Key 后,再使用对称密钥加密方式进行通信,从而保证效率。(下图中的 Session Key 就是 Secret Key)

具体步骤

第一步:申请证书及证书验证

服务器部署 SSL 证书,证书要通过浏览器厂家的信任认证

第二步:主密钥协商

客户端生成一个随机数,这个是用来生成最后的数据加密密钥的主密钥。客户端使用从证书中拿到的pub_svr对这个随机数加密,传给服务端。服务端用对应的pri_svr私钥进行解密拿到这个随机数pre_master(主密钥)

第三步:最后的数据加密密钥生成,随机数在计算机中都是伪随机数,所以SSL使用三个随机数叠加出来的随机数,这个用到了DH算法。

注意:证书是为了防止中间人劫持伪造公钥与客户端进行通信,主要是通过权威证书机构的私钥对要传输的公钥签名,而对应需要用来验签的公钥是由浏览器预先集成在内核中的,除非破解浏览器,不然是可以防止公钥被篡改的。

公钥由于是透明传输的无法作为对称密钥进行加密,SSL是通过客户端生成随机数,然后用从证书中拿到的公钥进行加密传输给到服务端,服务端用对应的私钥解密拿到随机数。后续的数据传输用这个随机数作为公钥进行加密通信

几个为什么

  1. 为什么不直接用非对称加密?

    速度慢;存在中间人劫持公钥,伪造服务端和客户端通信

  2. 为什么不直接使用对称加密?

    公钥泄露直接完蛋

  3. 为什么要通过证书传递公钥?

    避免中间人劫持,证书是权威第三方机构,通过CA的私钥签名认证机制保证公钥不被篡改以及确认服务端的合法性

  4. 为什么不直接用证书里的公钥进行数据通信加密,而是通过协商出来一个随机数,证书给客户端传递公钥的时候完全可以用CA的私钥加密传给客户端?

    尽可能保证安全,万一加密被破解就完蛋。客户端和服务端之间的加密密钥不应该让任何第三方知道,包括权威机构,并且每次建连后的密钥要尽可能保证不一样。

  5. 为什么要用多个随机数?

    因为生成的是伪随机数,用多个随机数尽可能保证随机性