HTTP Header
1. HTTP报文结构
用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。
HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行(CR+LF)来划分。通常,并不一定要有报文主体。
闲篇:\r是回车符,\n是换行符
计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。
这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。 后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。Unix 系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“<回车><换行>”,即“ \r\n”;Mac系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
HTTP请求报文
HTTP响应报文
2. HTTP首部分类
HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号“:” 分隔。
例如,在 HTTP 首部中以 Content-Type 这个字段来表示报文主体的 对象类型。Content-Type: text/html
HTTP首部字段类型
通用首部字段(General Header Fields)请求报文和响应报文两方都会使用的首部。
请求首部字段(Request Header Fields)
从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
响应首部字段(Response Header Fields)
从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
实体首部字段(Entity Header Fields)
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
3. HTTP缓存机制的介绍(为了学习相关字段)
Web缓存是可以自动保存常见文档副本的HTTP设备。当web请求抵达缓存的时候,要是本地有了已经缓存的副本,就可以从本地获取这个资源,而不是原始服务器来获取。
(1) 缓存规则
静态资源默认会使用缓存
Ajax get请求,浏览器可以使用缓存(当然还要看服务器的Cache-Control/Expires/Last-Modified/ETag头的设置)。
Ajax post请求,浏览器都不会缓存。
Https的请求,浏览器不会缓存(绝大数情况如此,但是也有例外,据说FF浏览器是例外)。
(2) 缓存服务器
当客户端发送请求到server并返回数据的时候,可以存在缓存服务器(中间代理、CDN),它的工作方式由服务端决定,因为服务端设置允许缓存的请求,在缓存服务器中就有,在客户端则是浏览器私有缓存,至于客户端是否取用,就由客户端自己决定了。
(3) 使用缓存的优点
减少了数据的数据传输,节省了网络费用;缓解了网络瓶颈的问题,不需要更多的带宽就能更快地加载页面;
降低了原始服务器的要求,服务器可以更快地响应、避免过载出现;
降低了距离时延,因为比较远的地方加载页面会慢一些;
(4) 命中和未命中
缓存未命中:缓存没有这个请求的副本,这个请求就会被转发给原始服务器。
(5) 再验证
原始服务器的内容发生变化,缓存需要对自身的数据进行检测,看看保存的副本是不是和服务器最新的副本一致。这种检测的机制并不是从服务器上获取整个对象,而是通过一些特殊的头部设置来去确定副本是否是最新。这种检测的机制叫做“新鲜度检测”,被称为HTTP再验证(revalidation)缓存服务器对于缓存的副本进行再验证时,会向原始服务器发送一个小的验证请求。如果内容没有变化,服务器会以一个小的304 Not Modified进行响应。然后缓存服务器知道副本还是有效的,就会将副本表示为暂时新鲜的,并将副本提供给客户端,这种称为再验证命中或缓慢命中
再验证的三种情况
再验证命中
服务器向客户端发送一个小的 HTTP 304 Not Modified 响应;
再验证未命中
服务器向客户端发送一条普通的、带有完整内容的 HTTP 200OK 响应;
对象被删除
服务器回送一个 404 Not Found 响应,缓存将其副本删除;
(6) 共有缓存和私有缓存
缓存可是是单个用户专用的,也可以是数千名用户共享的。私有缓存
私有缓存单个用户专享的,这里的用户不是指系统中的用户,而是具体的终端,比如你的电脑就属于单个用户,电脑上的浏览器会将常用的文档缓存在电脑的磁盘或者内存中,但是至于你在这个终端上登录多少个系统用户与私有缓存没有关系。
共有缓存
共有缓存如图中的b所示,会看到多个终端同时使用一个缓存服务器,最常用的是代理服务器和cdn。
(7) 缓存的处理步骤
解析:缓存对报文进行解析,提取出URL和各种首部;
查找:缓存查看是否有本地副本可用,如果没有,就获取一份副本(并将其保存在本地);
新鲜度检测:缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有更新;
创建响应:缓存会同新的首部和已缓存的主体来构建一条响应报文;
发送:缓存通过网络将响应发回给客户端;
日志:缓存可选地创建一个日志文件条目来描述这个事物;
缓存处理流程图
(8) 保持副本的新鲜
可能不是所有的已缓存副本斗鱼服务器一致,如果没有检测机制的话,那么可能会存在副本在很久的时间里都没有变化,直接自己处理请求(后面会有具体的首部字段学习)。如果缓存的数据总是老的数据,就会变得很危险,已缓存的数据要与服务器数据保持一致,具体的还是要看项目的需求,如果部署环境的开发人员可以确保某些请求在很长的时间里不会变化,那么可以不适使用新鲜度检测。HTTP有一些简单的机制可以在不要求服务器去记住那些文档已经被缓存的情况下,保持已缓存数据与服务器数据之间充分一致。HTTP将这种机制称为文档过期(document expiration)和服务器再验证(server revalidation)。
文档过期
通过特殊的HTTP Cache-control首部和Expires首部,HTTP让原始服务器向每一个文档附加了一个“过期时间”。在缓存文档过期之前,缓存可以随时访问副本,而不需要与服务器联系。除非客户端不接受缓存或者必须服务器验证资源。只有当缓存文档过期,缓存就必须与服务器进行新鲜度检测。
过期时间和文档使用期
过期时间如何去计算呢,先看一个简单的表面使用期date,注意这里的使用期,是当前缓存的使用期,也就是获取当前缓存时请求服务器返回的时间,在缓存没有过期期间,客户端多次的访问,这个值是不会变化的。如图,红色框内的date,就是当前缓存文档的使用期。然后max-age就是以这个为基准去计算的相对时间。而对于Expires就是一个绝对的时间了。
(9) 服务器再验证
仅仅是缓存文档过期并不意味着它和原始服务器上目前最新的文档有实际的区别,只是说当前需要将副本和服务器上的文档进行核对,这种情况被称为“服务器在验证”,说明缓存需要询问原始服务器文档是否发生了变化。如果再验证显示内容发生了变化,缓存会获取一份新的文档副本,并将其存储在就文档的位置上,然后将文档发送给客户端。
如果再验证显示内容没有发生变化,缓存会获取新的首部,包括一个新的过期日期,并且对缓存中的首部进行更新就行了。
用条件方法进行在验证
对于服务器在验证,HTTP定义了5个条件请求首部,后面我们都会学习,先来看IF-Modified-Since和If-None-Match。
If-Modified-Since:Date再验证
这里先说一下和last-modified的合作使用,last-modified是作用在响应首部的。先看案例:首先服务器设置
response.setHeader("Cache-Control", "max-age=30"); //表示从最新一次服务端返回文档到当前缓存文档过期的时长为30s
response.setHeader("Last-Modified", "Wed, 19 Apr 2018 14:26:37 GMT"); //服务端最新一次修改的时间。
如图有五条请求:
第一条请求为第一次访问,所以返回为200,此时浏览器私有缓存缓存当前副本。
第二/三条数据为在max-age=30没有过期的时间段请求的,可以看到红色框内的size为 from disk cache,而且所用时间非常短。
第四条数据此时已经超过了maxa-age=30,所以此时缓存未命中,需要服务器在验证。这里贴出来具体的request和resposne。而且请看绿色框服size没有第一条数据那么大,而且花费时间也较短。这里也表明当前发生的请求是一个简单的条件请求,只是为了验证缓存是否是最新的。
如图可以看到,此时客户端自动带上If-Modified-Since:Date(与last-modified一样)。
第五条数据,请看黑色框中的时间是我修改到了后面一天,有这样当下一次服务器再验证的时候,就会发现当前的文档已经修改了,所以这一条请求也是完全的请求文档的请求。
看了这个例子是不是感觉了解了当前的运作,max-age是用于新鲜度检测的,而last-modified是用于服务器再验证的。IF-Modified-Since首部和Last-Modified服务器响应首部的合作方式:当缓存要对以缓存文档进行再验证时,请求中(上面例子中的第四条)就会自动包含一个If-Modified-Slice首部,日期值为最后修改以缓存副本的日期,也就是last-modified。如果验证中发现last-modified的时间改了,自然会返回全新的文档,如果没有修改,则只返回更新缓存的新鲜度,也就是date,以为重置了date,那么max-age就会重新开始了。
IF-None-Match实体标签再验证
这个例子其实和上面的了类似。因为有些情况下仅仅使用最后修改日期进行验证是不够的。*有些文档可能会被周期性地重写,但实际包含的数据常常是一样的,尽管内容没有变化,但是修改日期发生了变化。
*有些页面无法判定其页面的最后修改日期。
为了解决这些问题,HTTP允许用户对被称为实体标签(ETag)的“版本标识符”进行比较。实体标签附加到文档上的任意标签(引用字符串:这里的引用字符串是中文版出现的,但是我想可能是翻译出错了,原文是quoted strings,意思应该是引号包含的字符串),这个字符串可能包含了文档的***或版本号,或者是文档内容的校验。每当发布者需要更新文档,可以修改文档的尸体标签来说明新的版本产生。然后客户端通过IF-None-Match条件首部来GET文档的新副本。
测试:服务端设置:Etag
response.setHeader("Cache-Control", "max-age=30");
response.setHeader("Etag", "\"v2.0\""); //这样的方式才可以起到作用,这也是为什么我说上面引用字符串翻译的出错了。
当我们在服务端设置Etag,当前客户端文档过期之后进行服务再验证的时候,请求会自动带上If-None-Match。
* Etag:W/"v1.0" 表示弱验证器。这里只是了解有这样的概念。没有W的是强验证器。
4. 通用首部字段(此处基本上以ajax的形式去测试)
(1) Pragma (HTTP 1.0)
Pragma 是HTTP/1.1之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义。当该字段值为“no-cache”的时候(事实上现在RFC中也仅标明该可选值),会知会客户端不要对该资源读缓存,即每次都得向服务器发一次请求才行。先给大家看一下在没有对客户端和服务端进行设置的情况下:服务端和请求段的header设置。服务端存在Cache-control(http 1.1中对于缓存控制的header), pragma的header,客户端则没有。
cache-control: no-cache, no-store, max-age=0, must-revalidate(这里的每个值的含义先不多说,因为后面还要学习cache-control,只说一下no-store为不缓存相应的任何内容)
pragma: no-cache也是不缓存请求。
为什么先说这个首部字段呢,因为http 1.0的这个header字段很有意思,会对cache-control的控制产生影响。
Pragma的优先级是高于Cache-Control 的。也就是说就算我这个地方对于cache-control进行了可缓存的设置,只要含有pragma: no-cache的情况下,还是没作用。测试一下:
如图现在我设置了Cache=Control: mxx-age=640800 表示当服务器返回的响应中包含 max-age(640800表示一周)指令时,缓存服务器将不对资源的有效性再作确认,而 max-age 数值代表资源保存为缓存的最长时间。 但是整个请求还是没有从缓存中拿,因为现在还是存在Pragma:no-cache,优先级高,也是对现在的请求结果不进行缓存的主要原因。
所以为了验证Pragram的作用,我在server设置如下,设置Pragma的值为空。
response.setHeader("Cache-Control", "max-age=604800");
response.setHeader("Pragma", "");
然后我们再看一下下面的请求结果,如图可以看到现在ajax get请求的结果是从缓存中拿到的。刚才说的是服务端,那么现在在服务段支持缓存的情况下,我们再去client设置pragma: no-cache的话,整个请求又要去访问服务端取新的数据,也不会从缓存中取。从这里也看到,请求的是否缓存不仅依赖于服务端,也依赖于客户端。
为什么先说这个,因为接下来学习Cache-control,如果不先将Pragma的影响去掉,着实会影响一大片。
(2) Cache-control
我们的请求 通过指定首部字段 Cache-Control 的指令,就能操作缓存的工作机制。
指令的参数是可选的,多个指令之间通过“,”分隔。首部字段 Cache-Control 的指令可用于请求及响应时。
Cache-Control: private, max-age=0, no-cache
缓存请求/响应指令的表格
缓存请求指令:
a. public (仅使用服务端)
表示该响应可以被任何中间人(比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定影响状态码的页面),将会被其缓存。Cache-Control: public
但是如果只使用这个指令的话,客户端还是不能够使用缓存,因为还没有启用缓存机制。所以我使用下面的方式启用缓存,并且设置缓存的使用者为所有人(或者使用last-modified启用)。
response.setHeader("Cache-Control", "public, max-age=604800");
response.setHeader("Pragma", "");
b. private (仅使用服务端)
当指定 private 指令后,响应只以特定的用户作为对象,这与 public指令的行为相反。而 "private" 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。
Cache-Control: private
c. no-cache (服务端,客户端)
no-cache的情况还是比较不一样的。客户端
客户端发送的请求中如果包含 no-cache 指令, 则表示客户端将不会接收缓存过的响应。 于是, “中间”的缓存服务器必须把客户端请求转发给源服务器。服务端
从字面意思上很容易把 no-cache 误解成为不缓存, 但事实上 no-cache 代表不缓存过期的资源, 缓存会向源服务器进行有效期确认后处理资源, 也许称为 do-notserve-from-cache-without-revalidation 更合适。 no-store 才是真正地不进行缓存。这里的意思是说,会缓存,但是每一次客户端的请求都会去服务端确认一下,如果没有修改,则返回304,然后客户端读取缓存。设置Last-Modified(时间为前一天),用来验证文件是否过期的条件。
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Last-Modified", "Wed, 17 Apr 2018 14:26:37 GMT");
response.setHeader("Pragma", "");
此时看一下页面的效果:可以看到页面上的get请求还是可以从缓存中读取,只是这个请求每一次都要去服务端验证。d. no-store (服务端,客户端)
当使用no-store指令时,暗示请求(和对应的响应)或响应中包含机密信息。no-store是真正的不进行缓存。Cache-Control: no-store
e. max-age (服务端,客户端)
先介绍几个日期,如图,当前的设置为服务端允许缓存,并且max-age为10s,然后看到第二个红色框的date。那么现在我们的缓存机制是什么呢?
那就是,客户端在一次访问请求的时候,会从缓存服服务器或者浏览器私有服务器去到当前的返回值,然后通过date + 10s与当前的时间进行对比,如果当前时间没有超过date + 10,那么当前的缓存还会被继续使用,而且不会向源服务器验证,反之则会发送全新的请求。
服务端:
当服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再作确认,而max-age数值代表资源保存为缓存的最长时。具体的例子就是前面的例子。客户端
我在客户端测试的时候发现max-age有值(不包含0)的时候没有作用,因为服务端的缓存控制着什么时候缓存服务端请求,但是如果是0的话,那么请求会发送到服务端请求。* 应用 HTTP/1.1版本的缓存服务器遇到同时存在 Expires 首部字段的情况时,会优先处理max-age指令,而忽略掉Expires首部字段。而HTTP/1.0 版本的缓存服务器的情况却相反,max-age指令会被忽略掉。
f. min-refresh(客户端)
图解http的解释: min-fresh 指令要求缓存服务器返回至少还未过指定时间的缓存资源。比如, 当指定 min-fresh 为 60 秒后, 过了 60 秒的资源都无法作为响应返回了。HTTP权威指南中的解释:至少<s>内文档保持新鲜。
我在这里的理解是:在指定的时间内保持新鲜。那么这个时间是什么呢?类似于max-age,再第一次访问原服务器返回的date时间开始就算缓存时间的新鲜度。现在我们假如min-refresh < max-age。那么这个时间内缓存文档是新鲜的。如果min-refresh > max-age,请求的时候,缓存服务器已经从新到服务器取回新的数据或者更新首部文档信息(304)。那么返回的还是保存新鲜度的文档。那么这个min-refresh好像没有任何的效果,感觉它的规则是其他缓存规则的子集。而且我在测试的时候没有发现有什么不同。
demo: (服务端)max-age = 20, (客户顿)min-refresh = 10, 在10s中以内缓存直接返回200(from disk cache), 10s ~ 20s 缓存还是直接返回200(from disk cache)。
对于这个的应用,真是没有发现它的精华是什么?如果有知道的,可以说一下,最好说一下测试的步骤。
g. max-stale(客户端)
如果指令未指定参数值, 那么无论经过多久, 客户端都会接收响应;如果指令中指定了具体数值, 那么即使过期, 只要仍处于 max-stale指定的时间内, 仍旧会被客户端接收。同样的测试没有成功,文档如果设置了过去时间,那么缓存文档过期,原服务器就会重新获取资源或者服务器在验证文档是否有更新。那么max-stale就没有任何效果,设置不设置,缓存的规则都没有任何变化。
f. only-if-cached
使用 only-if-cached 指令表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。 换言之, 该指令要求缓存服务器不重新加载响应, 也不会再次确认资源有效性。 若发生请求缓存服务器的本地缓存无响应, 则返回状态码 504 Gateway Timeout。g. must-revalidate
使用 must-revalidate 指令, 代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理无法连通源服务器再次获取有效资源的话, 缓存必须给客户端一条 504(Gateway Timeout) 状态码。另外, 使用 must-revalidate 指令会忽略请求的 max-stale 指令(即使已经在首部使用了 max-stale, 也不会再有效果) 。h. proxy-revalidate
Cache-Control: proxy-revalidateproxy-revalidate 指令要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前, 必须再次验证缓存的有效性。
i. no-transform
Cache-Control: no-transform使用 no-transform 指令规定无论是在请求还是响应中, 缓存都不能改变实体主体的媒体类型。这样做可防止缓存或代理压缩图片等类似操作。
(3) Connection
控制不再转发给代理的首部字段(作用与中间体)
在客户端发送请求和服务器返回响应内, 使用 Connection 首部字段, 可控制不再转发给代理的首部字段(即 Hop-by-hop 首部) 。管理持久连接
提高HTTP的链接性能将管理持久链接之前,先看集中可以提高HTTP的链接性能的方法
并行连接
通过多条TCP连接发起的并发HTTP请求,
持久链接
重用TCP链接,已消除链接及关闭时延。
管道化链接
通过共享的TCP链接发起并发的HTTP请求(上面两种方式合体)。
复用的链接(试验阶段)
交替传送请求和响应报文
Keep-Alive
HTTP 1.0 keep-alive实现客户端通过包含Connection: keep-alive首部请求将一条链接保持在打开状态。Connection: Keep-Alive
Keep-Alive: max=5, timeout=120
Max: 估计服务器还希望为多少个事物保持此链接的活跃状态。这并不是一个承诺值。timeout: 估计了服务器希望将连接保持在活跃状态的时间,这并不是一个承诺值。
HTTP 1.1 持久链接
HTTP 1.1没有对keep-alive有具体的说明,用一种名为持久链接的改进型设计取代了它。持久链接的目的与keep-alived的目的相同,但工作机制更优一些。HTTP 1.1持久链接默认情况下是**的。除非说明不适用持久链接,Connection: close
(4) Date
Date: Tue, 03 Jul 2012 04:40:59 GMT
首部字段 Date 表明创建 HTTP 报文的日期和时间。这个之前我们也曾提及到,这个表明生成当前文档的时间,也是缓存的新鲜度开始时间(表面上的)。首部字段 Date 表明创建 HTTP 报文的日期和时间。
(5) Trailer
首部字段 Trailer 会事先说明在报文主体后记录了哪些首部字段。 该首部字段可应用在 HTTP/1.1 版本分块传输编码时。以上用例中, 指定首部字段 Trailer 的值为 Expires, 在报文主体之后(分块长度 0 之后) 出现了首部字段 Expires。
(6) Transfer-Encoding
Transfer-Encoding: chunked
首部字段 Transfer-Encoding 规定了传输报文主体时采用的编码方式。HTTP/1.1 的传输编码方式仅对分块传输编码有效。有时候,Web服务器生成HTTP Response是无法在Header就确定消息大小的,这时一般来说服务器将不会提供Content-Length的头信息,而采用Chunked编码动态的提供body内容的长度。
(7) Upgrade
首部字段 Upgrade 用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。Upgrade 首部字段产生作用的 Upgrade 对象仅限于客户端和邻接服务器之间。因此,使用首部字段 Upgrade 时,还需要额外指定Connection:Upgrade。
对于附有首部字段 Upgrade 的请求,服务器可用 101 SwitchingProtocols 状态码作为响应返回。
(8) Via
使用首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径。Via 首部是为了追踪传输路径,所以经常会和 TRACE 方法一起使用。比如,代理服务器接收到由 TRACE 方法发送过来的请求(其中Max-Forwards: 0)时,代理服务器就不能再转发该请求了。这种情况下,代理服务器会将自身的信息附加到 Via 首部后,返回该请求的响应。
(9) Warning
HTTP/1.1 的 Warning 首部是从 HTTP/1.0 的响应首部(Retry-After)演变过来的。该首部通常会告知用户一些与缓存相关的问题的警告。Warning 首部的格式如下。最后的日期时间部分可省略。
Warning: [警告码][警告的主机:端口号]“[警告内容]”([日期时间])
HTTP/1.1 中定义了 7 种警告。警告码对应的警告内容仅推荐参考。
5. 请求首部字段
请求首部字段是从客户端往服务器端发送请求报文中所使用的字段,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容。(1) Accept
Accept: text/html,application/xhtml+xml
Accept 首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用 type/subtype 这种形式,一次指定多种媒体类型。
文本文件
text/html, text/plain, text/css ...
application/xhtml+xml, application/xml ...
图片文件
image/jpeg, image/gif, image/png ...
视频文件
video/mpeg, video/quicktime ...
应用程序使用的二进制文件
application/octet-stream, application/zip ...
若想要给显示的媒体类型增加优先级,则使用 q= 来额外表示权重值1,用分号(;)进行分隔。权重值 q 的范围是 0~1(可精确到小数点后 3 位),且 1 为最大值。不指定权重 q 值时,默认权重为 q=1.0。
Accept: text/html;q=0.1,application/xhtml+xml
当服务器提供多种内容时,将会首先返回权重值最高的媒体类型。(2) Accept-Charset
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。另外,可一次性指定多种字符集。与首部字段 Accept 相同的是可用权重 q 值来表示相对优先级。该首部字段应用于内容协商机制的服务器驱动协商。这里的权重规则与上面相同。(3) Accept-Encoding
Accept-Encoding: gzip, deflate
Accept-Encoding 首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码。
gzip
由文件压缩程序 gzip(GNU zip)生成的编码格式(RFC1952),采用 Lempel-Ziv 算法(LZ77)及 32 位循环冗余校验(Cyclic Redundancy Check,通称 CRC)。
compress
由 UNIX 文件压缩程序 compress 生成的编码格式,采用 Lempel-Ziv-Welch 算法(LZW)。deflate
组合使用 zlib 格式(RFC1950)及由 deflate 压缩算法(RFC1951)生成的编码格式。identity
不执行压缩或不会变化的默认编码格式*这里也可以使用权重,并且权重规则与上面相同
(4) Accept-Language
Accept-Language: zh-cn,zh;q=0.7,en-us,en;q=0.3
首部字段 Accept-Language 用来告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级。可一次指定多种自然语言集。和 Accept 首部字段一样,按权重值 q 来表示相对优先级。(5) Authorization
Authorization: Basic dWVub3NlbjpwYXNzd29yZA==
首部字段 Authorization 是用来告知服务器,用户代理的认证信息(证书值)。具体的认证还需要后面的学习。process:
客户端发送http请求,服务器发现配置了http auth,于是检查request里面有没有"Authorization"的http header如果有,则判断Authorization里面的内容是否在用户列表里面,Authorization header的典型数据为"Authorization: Basic jdhaHY0=",其中Basic表示基础认证, jdhaHY0=是base64编码的"user:passwd"字符串。如果没有,或者用户密码不对,则返回http code 401页面给客户端。
标准的http浏览器在收到401页面之后,应该弹出一个对话框让用户输入帐号密码;并在用户点确认的时候再次发出请求,这次请求里面将带上Authorization header
(6) Expect
Expect: 100-continue
客户端使用首部字段 Expect 来告知服务器,期望出现的某种特定行为。因服务器无法理解客户端的期望作出回应而发生错误时,会返回状态码 417 Expectation Failed。客户端可以利用该首部字段,写明所期望的扩展。虽然 HTTP/1.1 规范只定义了 100-continue(状态码 100 Continue 之意)。等待状态码 100 响应的客户端在发生请求时,需要指定 Expect:100-continue。
(7) From
首部字段 From 用来告知服务器使用用户代理的用户的电子邮件地址。通常,其使用目的就是为了显示搜索引擎等用户代理的负责人的电子邮件联系方式。(8) Host
首部字段 Host 会告知服务器,发送请求的互联网主机名和端口号。Host 首部字段在 HTTP/1.1 规范内是唯一一个必须被包含在请求内的首部字段。(9) If-Match
If-Match: "123456"
形如If-xxx这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。我们前面介绍过If-None-Match.
首部字段 If-Match,属附带条件之一,它会告知服务器匹配资源所用的实体标记(ETag)值。这时的服务器无法使用弱 ETag 值。服务器会比对 If-Match 的字段值和资源的 ETag 值,仅当两者一致时,才会执行请求(这里的执行请求是如果我们服务端设置Etag,客户端设置If-Match的值与Etag相同,那么每一次的请求都是访问服务端,不会走缓存)。反之,则返回状态码
412 Precondition Failed 的响应。
还可以使用星号(*)指定 If-Match 的字段值。针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。
(10) If-Modified-Since
If-Modified-Since: Thu, 15 Apr 2004 00:00:00 GMT
前面提到Last-Modified的时候已经提到过了。首部字段 If-Modified-Since,属附带条件之一,它会告知服务器若 If-Modified-Since 字段值早于资源的更新时间,则希望能处理该请求。而在指定 If-Modified-Since 字段值的日期时间之后,如果请求的资源都没有过更新,则返回状态码 304
Not Modified 的响应。If-Modified-Since 用于确认代理或客户端拥有的本地资源的有效性。获取资源的更新日期时间,可通过确认首部字段 Last-Modified 来确定。
(11) If-None-Match
首部字段 If-None-Match 属于附带条件之一。它和首部字段 If-Match作用相反。用于指定 If-None-Match 字段值的实体标记(ETag)值与请求资源的 ETag 不一致时,它就告知服务器处理该请求。(12) If-Range
If-Range是另一个起条件判断的请求头(我们之前讲过If-Match/If-None-Match,If-Modified-Since).If-Range头用来避免客户端在下载了某资源(比如图片)的一部分后,下次重新下载又从头开始下载。(这对于某些慢速网络来说,也许一辈子也下载不了某完整文件)。使用If-Range之后,客户端每次可以从上次下载的部分之后继续开始下载。If-Range的使用格式为:If-Range: Etag|Http-Date也就是说If-Range后面可以使用Etag或者Last-Modified返回的值:
If-Range: "df6b0-b4a-3be1b5e1"
If-Range: Tue, 8 Jul 2008 05:05:56 GMT
逻辑上来讲,上面2种方式分别和If-Match,If-Unmodified-Since的工作原理一样,他们的值正是服务器返回的Etag和Last-Modified值。Range
Range: bytes=5001-10000对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。上面的示例表示请求获取从第 5001 字节至第10000 字节的资源。
接收到附带 Range 首部字段请求的服务器,会在处理请求之后返回状态码为 206 Partial Content 的响应。无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源。
Range是另外一个Request Header,也就是由客户端发给服务器的,如果没有发送,客户端发送的If-Range会被忽略。同样,如果服务器端根本不支持断点续传,If-Range也一样被忽略。总之,离开了Range,If-Range的存在没有任何意义。
Accept-ranges
Accept-ranges是一个响应头,服务器发送这个头来告诉客户端它支持Range(范围)请求,后面的值,可以是bytes那么客户端发回来的:Ranges: bytes=2400- 就表示请求2400字节到文件末尾的这些数据。
Content-Range
这是一个响应头,说明了服务器提供的内容的字节范围和整个资源的长度。(13) If-Unmodified-Since
首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回。(14) Proxy-Authorization
Proxy-Authorization: Basic dGlwOjkpNLAGfFY5
接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段Proxy-Authorization 的请求,以告知服务器认证所需要的信息。
这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。客户端与服务器之间的认证,使用首部字段 Authorization 可起到相同作用。有关 HTTP 访问认证,后面的章节会作详尽阐述。
(15) Referer
首部字段 Referer 会告知服务器请求的原始资源的 URI。(16) TE
TE: gzip, deflate;q=0.5
首部字段 TE 会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码。(17) User-Agent
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101
首部字段 User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。6. 响应首部字段
(1) Accept-Ranges
Accept-Ranges: bytes
首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。可指定的字段值有两种,可处理范围请求时指定其为 bytes,反之则指定其为 none。(2) Age
Age: 600
首部字段 Age 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。若创建该响应的服务器是缓存服务器,Age 值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段Age。(3) ETag
ETag: "82e22293907ce725faf67773957acd12"
首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值。另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。
强ETag值和弱Tag值
强 ETag 值不论实体发生多么细微的变化都会改变其值。
ETag: "usagi-1234"
弱 ETag 值
只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/。
ETag: W/"usagi-1234"
(4) Location
Location: http://www.usagidesign.jp/sample.html
使用首部字段 Location 可以将响应接收方引导至某个与请求 URI 位置不同的资源。基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的URI。几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。(5) Proxy-Authenticate
Proxy-Authenticate: Basic realm="Usagidesign Auth"
首部字段 Proxy-Authenticate 会把由代理服务器所要求的认证信息发送给客户端。它与客户端和服务器之间的 HTTP 访问认证的行为相似,不同之处在于其认证行为是在客户端与代理之间进行的。而客户端与服务器之间进行认证时,首部字段 WWW-Authorization 有着相同的作用。(6) Retry-After
Retry-After: 120
首部字段 Retry-After 告知客户端应该在多久之后再次发送请求。主要配合状态码 503 Service Unavailable 响应,或 3xx Redirect 响应一起使用。字段值可以指定为具体的日期时间(Wed, 04 Jul 2012 06:34:24GMT 等格式),也可以是创建响应后的秒数。
(7) Server
Server: Apache/2.2.17 (Unix)
首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。Server: Apache/2.2.6 (Unix) PHP/5.2.5
(8) Vary
Vary: Accept-Language
服务器通过vary首部通知客户端,在服务器端的协商中会使用哪些来自客户端的请求的首部。它的值是一个首部列表,服务器回去查看这些首部,已确定将什么内容发回给客户端。如果服务端缓存了中文和英文的文档,Vary使用的 Accept-Language 字段,中国地区发送请求的时候判断到是中文,那么就直接从缓存返回中文响应。
(9) WWW-Authenticate
WWW-Authenticate: Basic realm="Usagidesign Auth"
首部字段 WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。状态码 401 Unauthorized 响应中,肯定带有首部字段 WWW-Authenticate。7. 实体首部字段
(1) Allow
首部字段 Allow 用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。当服务器接收到不支持的 HTTP 方法时,会以状态码405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。(2) Content-Encoding
Content-Encoding: gzip
首部字段 Content-Encoding 会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。主要采用4 种内容编码的方式gzip compress deflate identity
(3) Content-Language
Content-Language: zh-CN
首部字段 Content-Language 会告知客户端,实体主体使用的自然语言(指中文或英文等语言)。(4) Content-Length
Content-Length: 15000
首部字段 Content-Length 表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length首部字段。(5) Content-Location
Content-Location: http://www.hackr.jp/index-ja.html
首部字段 Content-Location 给出与报文主体部分相对应的 URI。和首部字段 Location 不同,Content-Location 表示的是报文主体返回资源对应的 URI。(6) Content-Type
Content-Type: text/html; charset=UTF-8
首部字段 Content-Type 说明了实体主体内对象的媒体类型。和首部字段 Accept 一样,字段值用 type/subtype 形式赋值。参数 charset 使用 iso-8859-1 或 euc-jp 等字符集进行赋值。(7) Expires
Expires: Wed, 04 Jul 2012 08:26:05 GMT
首部字段 Expires 会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段 Expires 的响应后,会以缓存来应答请求,在Expires 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。
源服务器不希望缓存服务器对资源缓存时,最好在 Expires 字段内写入与首部字段 Date 相同的时间值。但是,当首部字段 Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age 指令。
(8) Last-Modified
Last-Modified: Wed, 23 May 2012 09:59:55 GMT
首部字段 Last-Modified 指明资源最终修改的时间。一般来说,这个值就是 Request-URI 指定资源被修改的时间
上一篇: 算法篇:树之树的层次遍历
推荐阅读
-
ASP 中使用 HTTP 协议发送参数详解
-
详解android 用webview加载网页(https和http)
-
CentOS安装Nginx 报错“configure: error: the HTTP rewrite module requires the PCRE library”解决办法
-
Tomcat源码分析 (九)----- HTTP请求处理过程(二)
-
HTTP响应头的管理 提升网站访问速度
-
HttpUtils 发送http请求工具类(实例讲解)
-
Asp.Net服务器发送HTTP标头后无法设置内容类型的问题解决
-
在IE浏览器中网页出现http 500错误的原因查看方法
-
HTTP_HOST 和 SERVER_NAME 的区别详解
-
C#如何解析http报文