#tjhttp 七、《图解HTTP》- HTTP首部和HTTP协作服务器(一)
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第十八天,点击查看活动详情
#知识点
- 请求头部字段分类比较多,本章介绍了下面的首部,内容非常多,熟悉常见的请求首部即可。
- 首部字段介绍
- 非HTTP1.1 首部字段
- 通用首部
- 请求首部
- 响应首部
- 负载首部(实体首部)
- 其他首部字段
- 协作服务器指的是为了HTTP加速访问而架设的一些中间件介绍,内容介绍比较匮乏,个人也没有补充,简单浏览即可
7-1. HTTP首部
虽然平时感受不到,但是却是互联网天天在用的东西,这本书花了50多页的内容介绍它,可见它的重要性。
HTTP 首部包含三个部分,报文首部,空行和报文主体,报文首部包含了客户端重要的传输信息,而报文体则是“负荷数据”,包含获取服务器信息需要传递的数据。
HTTP 报文由方法、URI、HTTP 版本、HTTP 首部字段等部分构成。
下面是请求报文的案例信息:
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"
7.0 首部字段介绍
首部字段是HTTP的重要组成部分。
HTTP 首部字段结构
首部字段由key/value的字段名和字段值组成,通过冒号进行分隔,字段值可以是单个值,也可以是多个值,对于多个值会使用逗号进行分隔。
如果首部字段出现重叠怎么办?在规范当中并没有进行明确规定,取决于浏览器和实现方是如何处理的,比如有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段。
首部字段分类
- 通用首部字段(General Header Fields):请求和响应通用首部。
- 请求首部字段(Request Header Fields):从客户端向服务器端发送请求报文时使用的首部。
- 响应首部字段(Response Header Fields):从服务器端向客户端返回响应报文时使用的首部。
- 负载~~(实体)~~首部字段(Entity Header Fields):在负载的部分使用的首部信息,客户端和服务端都有可能存在。
HTTP/1.1 首部字段
下面是几张关于首部字段的表,包首部字段分类对应的四个分类:
通用首部字段
请求首部字段
响应首部字段
负载首部字段
7.1 非 HTTP/1.1 首部字段
在HTTP协议通信中使用的首部字段除了上面定义的之外,非正式的首部字段统一归纳在 RFC4229 HTTP Header Field Registrations 中,感兴趣可以直接进网页看看相关的白皮书信息。
缓存代理行为
缓存代理行为通过两个字段:端到端首部(End-to-end Header)和逐跳首部(Hop-by-hop Header)
对于第一个端到端首部(End-to-end Header)会转发请求和响应信息给最终目标并且必须存在于由缓存生成的响应,要求是同时必须被转发。
第二个逐跳首部(Hop-by-hop Header)则只对单次转发有效,如果通过了缓存或者代理则不会进行转发。另外使用逐跳首部需提供 Connection 首部字段需要包含下面的内容:
Connection Keep-Alive Proxy-Authenticate Proxy-Authorization Trailer TE Transfer-Encoding Upgrade
7.2通用首部字段
通用首部字段信息包含下面的内容:
7.2.1 Cache-Control
顾名思义,用于操作缓存的首部字段,案例Cache-Control: private, max-age=0, no-cache
,缓存首部字段基本存在下面的值,需要指定最大响应age和缓存最大的有效时间,防止缓存过久有效和过短失效。
缓存请求指令表和响应指令参考表如下:
public 指令(Cache-Control: public)
Cache-Control: public
,这样的首部声明表明其他的用户也可以使用这份缓存,意味着这是公用的缓存信息。
private 指令(Cache-Control: private)
Cache-Control: private
和public命令正好相反,只能给特定用户作为对象,缓存服务器会为特定的用户缓存数据,其他用户则没用此行为。
no-cache 指令(Cache-Control: no-cache)
目的是为了防止从缓存中返回过期的资源。表示每次请求将不会接受缓存过的数据,如果请求中携带这个指令表明返回的内容不能是缓存过的数据。
注意⚠️:从字面意思上很容易把 no-cache 误解成为不缓存,但事实上 no-cache 代表不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源。
Cache-Control: no-cache=Location
如果在cache-Control当中指定具体的参数值,则客户端接收到这个被指定参数值的首部对应报文之后就不能缓存,这个指令的区别是由服务器指定客户端不允许进行缓存操作。
控制可执行缓存的对象的指令
no-store 指令(Cache-Control: no-store)
表示请求或者响应有机密信息。该指令规定缓存不能在本地存储请求或响应的任一部分。
s-maxage 指令(Cache-Control: s-maxage=604800(单位 :秒)
和max-age指令相同,它们的不同点是 s-maxage 指令只适用于供多位用户使用的公共缓存服务器,同一个用户重复返回响应此字段是无效的。
注意⚠️:使用s-maxage之后会忽略
Expire
字段。
max-age 指令
客户端:指定接受最大缓存时间的资源,高于该时间的资源不接受缓存数据,如果为0则表示每次都需要请求源服务器。
max-stale 指令(Cache-Control: max-stale=3600(单位:秒))
max-stale 指示缓存资源,过期也要照常接受。如果指令没有指定参数值,客户端会接收响应。如果指定参数即使过期,只要处于这个指定值之内依然可以被客户端接收。
only-if-cached 指令(Cache-Control: only-if-cached)
表示只在缓存服务器上获取目标服务器被缓存的资源,如果缓存服务器也没有数据则返回504状态码。
504 网关超时:服务器充当网关或者代理的时候,没有收到响应。和408的区别是408是服务端接受客户端超时,504是代理接收服务端超时。
must-revalidate 指令(Cache-Control: must-revalidate)
表示代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效,如果是无效的,要求缓存服务器返回504的状态码。
注意⚠️:must-revalidate 指令会忽略请求的 max-stale 指令。
proxy-revalidate 指令(Cache-Control: proxy-revalidate)
要求所有缓存服务器收到客户端带有指令的请求返回响应之前验证缓存有效性。
no-transform 指令(Cache-Control: no-transform)
请求和响应不能接受改变负载的媒体类型。
Cache-Control 扩展 cache-extension token
Cache-Control: private, community="UCI"
这种写法表示通过token标记扩展改首部字段的命令, 比如community
这个指令是不存在的,但是通过这样的扩展实现兼容。但是这种兼容只能是理解它的缓存服务器才会回应,其他的缓存服务器会直接忽略掉。
7.2.2 Connection
这个首部字段的作用如下:
- 控制不转发给代理的首部字段。
- 管理持久连接。
控制不再转发给代理的字段
可控制不再转发给代理的首部字段(即 Hop-by-hop 首部)。
管理持久连接
如果当服务器端想明确断开连接时,通过指定Connection 首部字段的值为 Close完成这项操作。但是需要注意HTTP1.1默认都是Keep-Alive
的持久连接。
反之,在此之前的版本都是非持久的连接,如果想要实现和HTTP1.1一样的效果需要Connection:Keep-Alive
完成这项操作。
7.2.3 Date(Date: Tue, 03 Jul 2012 04:40:59 GMT)
表明HTTP报文创建的日期和时间。
HTTP/1.1 协议默认会使用在 RFC1123 中规定的日期时间的格式:
Date: Tue, 03 Jul 2012 04:40:59 GMT
HTTP1.1之前的版本使用下面的内容,使用的协议是RFC850,主要内容如下所示:
Date: Tue, 03-Jul-12 04:40:59 GMT
除此之外还有一种方式是使用C 标准库内的 asctime() 函数
的输出格式一致:
Date: Tue Jul 03 04:40:59 2012
7.2.3 Pragma(Pragma: no-cache)
Pragma 是 HTTP/1.1
之前版本的历史遗留字段,为了HTTP1.0之后向后兼容,规范的内容形式唯一而存在着,比如下面的内容:Pragma: no-cache
主要用于客户端告知服务器不接受缓存内容,这种字段和Cache-Control:no-cache
指定缓存处理最为理想。
Cache-Control: no-cache Pragma: no-cache
7.2.4 Trailer(Trailer: Expires)
表明报文主体之后记录了什么样的首部字段,主要用于HTTP1.1 的分块传输编码使用。
HTTP/1.1 200 OK Date: Tue, 03 Jul 2012 04:40:56 GMT Content-Type: text/html ... Transfer-Encoding: chunked Trailer: Expires ...(报文主体)... 0 Expires: Tue, 28 Sep 2004 23:59:59 GMT
上面的案例使用了Expires字段指定资源的失效日期。
7.2.5 Transfer-Encoding(Transfer-Encoding: chunked)
规定传输报文的时候使用的编码方式,HTTP1.1的传输编码只能够作用于分块传输编码。
7.2.6 Upgrade
表示尝试使用更高版本的协议和服务器之间进行通信,但是不一定是HTTP协议,可以指定完全不同的协议。
书中的例子使用了TLS的协议仅限验证,注意传输报文的细节部分,比如Connection里面指定了Upgrade,能够产生作用范围的是客户端以及相邻的服务器,所以需要指定Connection: Upgrade
才能生效。
另外服务遇到带有 Upgrade 的请求,可以使用返回码101作为响应码返回。
Upgrade经典使用场景是WebSocket升级协议。
7.2.7 Via
主要用于最终客户端到服务器之间的请求和响应报文到传输路径,报文经过了代理和网关时候,会在Via当中附加服务器信息然后再进行转发。首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。
请求每一次经过代理服务器,首部的Via字段就会增加一次,VIa字段用于追踪传播路径,通常会和TRACE
方法一起使用,如果Max-Forward
变为0,则会停止代理服务器之间的转发操作。
7.2.8 Warning
HTTP/1.1 的 Warning 首部是从 HTTP/1.0 的响应首部(Retry-After)演变过来的。
下面是对应的组成格式:
Warning: [警告码][警告的主机:端口号]“[警告内容]”([日期时间])
在HTTP1.1中定义了7种警告码,警告码通常只能作为参考,之后可能进行扩展。