缓存~~~

201 阅读18分钟

无聊时间总结了一些关于缓存的一些知识点和大家分享一下

缓存解决了那些问题?

·

缓存减少了冗余的数据传输,节省了你的网络费用。

·

缓存缓解了网络瓶颈的问题。不需要更多的带宽就能够更快地加载页面。

·

缓存降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。

·

缓存降低了距离时延,因为从较远的地方加载页面会更慢一些。
缓存处理步骤

1.第一步:接收------缓存从网络中读取抵达的请求报文

缓存检测到一条网络连接上的活动,读取输入数据。高性能的缓存会
同时从多条输入连接上读取数据,在整条报文抵达之前开始对事务进行处理。

2.第二步:解析------缓存对报文进行解析,提取出 URL 和各种首部

接下来,缓存将请求报文解析为片断,将首部的各个部分放入易于操作的数据结构
中。这样,缓存软件就更容易处理首部字段并修改它们了
解析程序还要负责首部各部分的标准化,将大小写或可替换数据格式之类不太重要的区别都看作等
效的。而且,某些请求报文中包含有完整的绝对

URL,而其他一些请求中包含的则是相对 URL 和 Host 首部,所以解析程序通常都要将这些细节隐藏起来 。

3.第三步:查询------缓存查看是否有本地副本可用,如果没有,就获取一份副本(并将其保存在本地)

在第三步中,缓存获取了

URL

,查找本地副本。本地副本可能存储在内存、本地磁盘,甚至附近的另一台计算机中。专业级的缓存会使用快速算法来确定本地缓存中是否有某个对象。如果本地没有这个文档,它可以根据情形和配置,到原始服务器 或父代理中去取,或者返回一条错误信息。
已缓存对象中包含了服务器响应主体和原始服务器响应首部,这样就会在缓存命中时返回正确的服务器首部。已缓存对象中还包含了一些元数据

(metadata)

,用来记 录对象在缓存中停留了多长时间,以及它被用过多少次等 。
复杂的缓存还会保留引发服务器响应的原始客户端响应首部的一份副本,以用于

HTTP/1.1 内容协商。

4.第四步:新鲜度检测------缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有任何更新

HTTP

通过缓存将服务器文档的副本保留一段时间。在这段时间里,都认为文档是
新鲜的
,缓存可以在不联系服务器的情况下,直接提供该文档。但一旦已缓存副 本停留的时间太长,超过了文档的新鲜度限值
(freshness limit)
,就认为对象
过时
了,在提供该文档之前,缓存要再次与服务器进行确认,以查看文档是否发生了变化。客户端发送给缓存的所有请求首部自身都可以强制缓存进行再验证,或者
完全避免验证,这使得事情变得更加复杂了。

HTTP

有一组非常复杂的新鲜度检测规则,缓存产品支持的大量配置选项,以及与非
HTTP
新鲜度标准进行互通的需要则使问题变得更加严重了。

5.第五步:创建响应------缓存会用新的首部和已缓存的主体来构建一条响应报文

我们希望缓存的响应看起来就像来自原始服务器的一样,缓存将已缓存的服务器响
应首部作为响应首部的起点。然后缓存对这些基础首部进行了修改和扩充。
缓存负责对这些首部进行改造,以便与客户端的要求相匹配。比如,服务器返回
的可能是一条

HTTP/1.0

响应
(
甚至是
HTTP/0.9
响应
)
,而客户端期待的是一条
HTTP/1.1
响应,在这种情况下,缓存必须对首部进行相应的转换。缓存还会向其中 插入新鲜度信息
(Cache-Control
Age
以及
Expires
首部
)
,而且通常会包含一 个
Via
首部来说明请求是由一个代理缓存提供的。
注意,缓存不应该调整

Date 首部。Date 首部表示的是原始服务器最初产生这个对象的日期。

6.第六步:发送------缓存通过网络将响应发回给客户端

一旦响应首部准备好了,缓存就将响应回送给客户端。和所有代理服务器一样,代
理缓存要管理与客户端之间的连接。高性能的缓存会尽力高效地发送数据,通常可以避免在本地缓存和网络

I/O

缓冲区之间进行文档内容的复制。

7.第七部:日志------缓存可选地创建一个日志文件条目来描述这个事务

大多数缓存都会保存日志文件以及与缓存的使用有关的一些统计数据。每个缓存事务结束之后,缓存都会更新缓存命中和未命中数目的统计数据

(

以及其他相关的度 量值
)
,并将条目插入一个用来显示请求类型、
URL
和所发生事件的日志文件。

例如:

强缓存

通过特殊的

HTTP Cache-Control

首部和
Expires
首部,
HTTP
让原始服务器向 每个文档附加了一个
过期日期
。就像一夸脱牛奶上的过期日期一样,这些首部说明了在多长时间内可以将这些内容视为新鲜的。
服务器用

HTTP/1.0+

Expires
首部或
HTTP/1.1
Cache-Control: max-age
响应首 部来指定过期日期,同时还会带有响应主体。
Expires
首部和
Cache-Control: max-age
首部所做的事情本质上是一样的,但由于
Cache-Control
首部使用的是 相对时间而不是绝对日期,所以我们更倾向于使用比较新的
Cache-Control
首部。 绝对日期依赖于计算机时钟的正确设置。

Cache-Control优先级更高。

服务器再验证

仅仅是已缓存文档过期了并不意味着它和原始服务器上目前处于活跃状态的文档有
实际的区别

;这只是意味着到了要进行核对的时间了。这种情况被称为“服务器再 验证”,说明缓存需要询问原始服务器文档是否发生了变化。

·

如果再验证显示内容发生了变化,缓存会获取一份新的文档副本,并将其存储在旧文档的位置上,然后将文档发送给客户端。

·

·

如果再验证显示内容没有发生变化,缓存只需要获取新的首部,包括一个新的过期日期,并对缓存中的首部进行更新就行了。

·

我们来看一下

Cache-Control

的头部:(
不一定非要一下子全部记住,每次回想记不清的时候来看一眼,一次记一个,就能全部

get

了!

1

Cache-Control

no-store
禁止一切缓存(这个才是响应不被缓存的意思)。
缓存通常会像非缓存代理服务器一样,向客户端转发一条

no-store 响应,然后删除对象。

2

Cache-Control

no-cache
强制客户端直接向服务器发送请求

,

也就是说每次请求都必须向服务器发送。服务器接收到请求,然后判断资源是否变更,是则返回新内容,否则返回
304
,未变更。这个很容易让人产生误解,使人误以为是响应不被缓存。实际上
Cache-Control: no-cache
是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。

HTTP/1.1 中提供 Pragma: no-cache 首部是为了兼容于 HTTP/1.0+。除了与只理解 Pragma: no-cache 的 HTTP/1.0 应用程序进行交互时,HTTP 1.1 应用程序都应该使用 Cache-Control: no-cache。

从技术上来讲,

Pragma:no-cache 首部只能用于 HTTP 请求,但在实际中它作为扩展首部已被广 泛地用于 HTTP 请求和响应之中。

3

Cache-Control

m

ust-revalidate

在事先没有跟原始服务器进行再验证的情况下,不能提供这个对象的陈旧副本。缓存仍然可以随意提供新鲜的副本。如果在缓存进行

must-revalidate

新鲜度检查时,原始服务器不可 用,缓存就必须返回一条
504 Gateway Timeout
错误。

4

Cache-Control

max-age
首部表示的是从服务器将文档传来之时起,可以认为此
文档处于新鲜状态的秒数。

5

Cache-Control

s-maxage

max-age

是一样的,不过它只针对代理服务器缓存而言。

6

Cache-Control

private
只能针对个人用户,而不能被代理服务器缓存。

7

Cache-Control

public
可以被任何对象缓存,包括发送请求的客户端,代理服务器。

8

Cache-Control

max-stale
缓存可以随意提供过期的文件。如果指定了参数
,在这段 时间内,文档就不能过期。这条指令放松了缓存的规则。

通过HTTP-EQUIV控制HTML缓存

HTML 2.0

定义了
标签。这个可选的标签位于
HTML
文档的顶部,定义了应该与文档有所关联的
HTTP
首部。
My Document

...

复制代码

HTTP 服务器可以用此信息来处理文档。特别是,它可以在为请求此文档的报文所发送的响应中包含一个首部字段:首部名称是从 HTTP-EQUIV 属性值中获取的,首部值是从CONTENT 属性值中获取的。

不幸的是,支持这个可选特性会增加服务器的额外负载,这些值也只是静态的,而
且它只支持

HTML

,不支持很多其他的文件类型,所以很少有
Web
服务器和代理支 持此特性。
**总之,**

标签并不是控制文档缓存特性的好方法。通过配置正 确的服务器发出
HTTP
首部,是传送文档缓存控制请求的唯一可靠的方法。

p1-jj.byteimg.com/tos-cn-i-t2…

If-None-Match:etag

ETag 实体标签: 一般为资源实体的哈希值,即ETag就是服务器生成的一个标记,用来标识返回值是否有变化。且Etag的优先级高于Last-Modified。

服务器可以为文档提供特殊的标签,而不是将其与最近修改日期相匹配,这些标签就像序列号一样。如果已缓存标签与服务器文档中的标签有所不同,
If-None-Match
首部就会执行所请求的方法。
**灵魂拷问,**
为什么有了

If-Modified-Since

还用
If-None-Match

·

有些文档可能会被周期性地重写

(

比如,从一个后台进程中写入
)
,但实际包含的数据常常是一样的。尽管内容没有变化,但修改日期会发生变化。

·

·

有些文档可能被修改了,但所做修改并不重要,不需要让世界范围内的缓存都重装数据

(

比如对拼写或注释的修改
)

·

·

有些服务器无法准确地判定其页面的最后修改日期。

·

·

有些服务器提供的文档会在亚秒间隙发生变化

(

比如,实时监视器
)
,对这些服
务器来说,以一秒为粒度的修改日期可能就不够用了。

·

**当你第一次发起**

HTTP请求时,服务器会返回一个Etag,并在你第二次发起同一个请求时,客户端会同时发送一个If-None-Match,而它的值就是Etag的值(此处由发起请求的客户端来设置)

。缓存中有一个实体标签为

Etag: v2.6 的文档。它会与原始服务器进行再验证,如果标签Etag: v2.6 不再匹配,就会请求一个新对象。假设标签仍然与之 匹配,因此会返回一条 304 Not Modified

响应。
如果服务器上的实体标签已经发生了变化

(可能变成了 Etag: v3.0),服务器会在一个200OK

响应中返回新的内容以及相应的新

Etag。

举个例子:
当你
第一次
发起

HTTP

请求时,
服务器
会返回一个

Etag

并在你
第二次
发起
同一个请求
时,客户端会
同时
发送一个

If-None-Match

,而它的值就是

Etag

的值(此处由发起请求的客户端来设置)。

大部分人都不知道的一点:

有时候,客户端和服务器可能需要采用不那么精确的实体标记验证方法。例如,某服务器可能想对一个很大、被广泛缓存的文档进行一些美化修饰,但不想在缓存服务器再验证时产生很大的传输流量。在这种情况下,该服务器可以在标记前面加上
“W/”
前缀来广播一个
实体标记。对于弱实体标记来说,只有当关联的实体在语义上发生了重大改变时,标记才会变化。而强实体标记则不管关联的实体发生 了什么性质的变化,标记都一定会改变。
下面的例子展示了客户端如何用弱实体标记向服务器请求再验证。服务器仅当文档
的内容从版本

4.0

算起发生了显著变化时,才返回主体
:

GET /announce.html HTTP/1.1

If-None-Match: W/"v4.0"

概括一下,当客户端多次访问同一个资源时,首先需要判断它当前的副本是不是仍然新鲜。如果不再新鲜,它们就必须从服务器获取最新的版本。为了避免在资源没有改变的情况下收到一份相同的副本,客户端可以向服务器发送有条件的请求,说明能唯一标识客户端当前副本的验证码。只在资源和客户端的副本不同的情况下服务器才会发送其副本。
**因为**

csrf可以拿cookie的值,xss可以拿token的值,万一某个网站存在这两个渗透攻击,不就完蛋了

**(**
正好这次看到了一些方法,(实际也不好使

·

承载用户身份信息的

HTTP

首部。

·客户端

IP

地址跟踪,通过用户的
IP
地址对其进行识别。

·

·

用户登录,用认证方式来识别用户。

·

·

URL

,一种在
URL
中嵌入识别信息的技术

From

**_:_**
用户的

E-mail 地址

From 首部包含了用户的 E-mail 地址。每个用户都有不同的 E-mail 地址,所以在理 想情况下,可以将这个地址作为可行的源端来识别用户。但由于担心那些不讲道德 的服务器会搜集这些 E-mail 地址,用于垃圾邮件的散发,所以很少有浏览器会发送 From 首部。实际上,From 首部是由自动化的机器人或蜘蛛发送的,这样在出现问 题时,网管还有个地方可以发送愤怒的投诉邮件。

User-Agent

**_:_**
用户的浏览器软件

User-Agent 首部可以将用户所用浏览器的相关信息告知服务器,包括程序的名称 和版本,通常还包含操作系统的相关信息。要实现定制内容与特定的浏览器及其属 性间的良好互操作时,这个首部是非常有用的,但它并没有为识别特定的用户提供 太多有意义的帮助。

Referer

**_:_**
用户是从这个页面上依照链接跳转过来的

Referer 首部提供了用户来源页面的 URL。Referer 首部自身并不能完全标识用户,但它确实说明了用户之前访问过哪个页面。通过它可以更好地理解用户的浏览行为,以及用户的兴趣所在。

Authorization

**_:_**
用户名和密码
为了使

Web 站点的登录更加简便,HTTP 中包含了一种内建机制,可以用 WWW- Authenticate 首部和 Authorization 首部向 Web 站点传送用户的相关信息。一 旦登录,浏览器就可以不断地在每条发往这个站点的请求中发送这个登录信息了, 这样,就总是有登录信息可用了。

Client-IP

**_:_**
客户端的

IP 地址

X-Forwarded-For

**_: 客户端的_**
**_IP_**
**_地址_**
如果每个用
户都有不同的

IP 地址,IP 地址(如果会发生变化的话)也很少会发生变化,而且 Web 服务器可以判断出每条请求的客户端 IP 地址的话,这种方案是可行的。通常 在 HTTP 首部并不提供客户端的 IP 地址, 但 Web 服务器可以找到承载 HTTP 请求 的 TCP 连接另一端的 IP 地址。

但是,使用客户端

IP

地址来识别用户存在着很多缺点,限制了将其作为用户识别技 术的效能。

·

客户端

IP

地址描述的是所用的机器,而不是用户。如果多个用户共享同一台计 算机,就无法对其进行区分了。

·

·

很多因特网服务提供商都会在用户登录时为其动态分配

IP

地址。用户每次登录 时,都会得到一个不同的地址,因此
Web
服务器不能假设
IP
地址可以在各登录 会话之间标识用户。

·

·

为了提高安全性,并对稀缺的地址资源进行管理,很多用户都是通过网络地址转

(Network Address Translation

NAT)
防火墙来浏览网络内容的。这些
NAT
设备隐藏了防火墙后面那些实际客户端的
IP
地址,将实际的客户端
IP
地址转换 成了一个共享的防火墙
IP
地址
(
和不同的端口号
)

·

·

HTTP

代理和网关通常会打开一些新的、到原始服务器的
TCP
连接。
Web
服务 器看到的将是代理服务器的
IP
地址,而不是客户端的。有些代理为了绕过这个 问题会添加特殊的
Client-IP
X-Forwarded-For
扩展首部来保存原始的
IP
地址
(
参见图
11-1)
。但并不是所有的代理都支持这种行为。

·

**_胖_**

URL

有些

Web

站点会为每个用户生成特定版本的
URL
来追踪用户的身份。通常,会对 真正的
URL
进行扩展,在
URL
路径开始或结束的地方添加一些状态信息。用户浏 览站点时,
Web
服务器会动态生成一些超链,继续维护
URL
中的状态信息。
改动后包含了用户状态信息的

URL

被称为胖
URL(fat URL)
。下面是
Amazon.com
电子商务网站使用的一些胖
URL
实例。每个
URL
后面都附加了一个用户特有的标 识码
(
在这个例子中就是
002-1145265-8016838)
,这个标识码有助于在用户浏览商 店内容时对其进行跟踪。

...

All Gifts

WishList

...

Salute Our Troops

Free Shipping

Easy Returns

...

复制代码
可以通过胖

URL 将 Web 服务器上若干个独立的 HTTP 事务捆绑成一个“会话”或 “访问”。用户首次访问这个 Web 站点时,会生成一个唯一的 ID,用服务器可以识 别的方式将这个 ID 添加到 URL 中去,然后服务器就会将客户端重新导向这个胖 URL。不论什么时候,只要服务器收到了对胖 URL 的请求,就可以去查找与那个用 户 ID 相关的所有增量状态(购物车、简介等),然后重写所有的输出超链,使其成

为胖

URL,以维护用户的 ID。

但这种技术存在几个很严重的问题

:

·

无法共享

URL

URL

中包含了与特定用户和会话有关的状态信息。如果将这个
URL
发送给其 他人,可能就在无意中将你积累的个人信息都共享出去了。

·

·

破坏缓存
为每个

URL

生成用户特有的版本就意味着不再有可供公共访问的
URL
需要缓存了。

·

·

额外的服务器负荷
服务器需要重写

HTML

页面使
URL
变胖。

·

·

逃逸口
用户跳转到其他站点或者请求一个特定的

URL

时,就很容易在无意中
逃离
URL
会话。只有当用户严格地追随预先修改过的链接时,胖
URL
才能工作。 如果用户逃离此链接,就会丢失他的进展
(
可能是一个已经装满了东西的购物 车
)
信息,得重新开始。

·

·

在会话间是非持久的
除非用户收藏了特定的胖

URL

,否则用户退出登录时,所有的信息都会丢失。

·

·

丑陋的

URL

·

浏览器中显示的胖

URL 会给新用户带来困扰。

//多有打扰  走过路过  医药费  点个赞呢~~