캐싱이란 서버의 접속빈도와 통신횟수를 줄이기 위해 프론트엔드에서 획득한 데이터 정보를 저장해 두었다가 다시 필요할 때 저장된 데이터를 사용하는 것을 의미합니다.
캐싱은 사용자 경험과 통신 비용에 큰 영향을 미치므로 캐싱 메커니즘은 최대한 유연하게 사용해야 합니다.
HTTP
캐시는 시간을 차원으로 하는 캐시입니다. HTTP
缓存是一个以时间为维度的缓存。
浏览器在第一次请求中缓存了响应,而后续的请求可以从缓存提取第一次请求的响应。从而达到:减少时延而且还能降低带宽消耗,因为可能压根就没有发出请求,所以网络的吞吐量也下降了。
浏览器发出第一次请求,服务器返回响应。如果得到响应中有信息告诉浏览器可以缓存此响应。那么浏览器就把这个响应缓存到浏览器缓存中。
如果后续再发出请求时,浏览器会先判断缓存是否过期。如果没有过期,浏览器压根就不会向服务器发出请求,而是直接从缓存中提取结果。
比如:访问掘金站点
从Size
中可以看出,disk cache
브라우저가 첫 번째 요청을 하고 서버가 응답을 반환합니다. 응답에 응답을 캐시할 수 있음을 브라우저에 알리는 정보가 있는 경우. 그런 다음 브라우저는 이 응답을 브라우저 캐시에 캐시합니다.
다음 요청이 이루어지면 브라우저는 먼저 캐시가 만료되었는지 여부를 확인합니다. 만료되지 않은 경우 브라우저는 서버에 전혀 요청하지 않고 캐시에서 직접 결과를 가져옵니다.
🎜예: Nuggets 사이트를 방문하세요🎜🎜크기
에서 알 수 있듯이 디스크 캐시
는 하드 디스크에서 추출한 캐시 정보입니다. 🎜🎜캐시가 만료되었습니다🎜🎜캐시가 만료된 경우 서버는 반드시 첫 번째 요청처럼 직접 응답을 반환하지는 않습니다. 🎜🎜브라우저의 캐시 시간이 만료되면 캐시 태그와 함께 요청이 서버로 전송됩니다. 이때 서버에서 캐시가 아직 사용 가능한 것으로 판단되면 304 응답 코드를 반환합니다. 브라우저는 이 캐시를 계속 사용합니다. 🎜예: 위 그림의 캐시 파일 중 하나를 선택하고 copy
는 url
을 요청하고 curl
에 ="lazyload" src="https://img.php.cn/upload/article/000/000/052/ae32126dc9ee893cffdb71d59665b5a9-1.png" data-width="800" data- style="max-width:90%"/> 원본 요청을 가져오려면 먼저 -I
를 추가하고 etag
또는 last-modified
헤더를 확인하세요. copy
请求url
在curl
中展示
首先加-I
获取原始请求,查看etag
或last-modified
头部。
因为浏览器缓存过期之后,请求就会带上这些头部一起发送给服务器,让服务器判断是否还能用。
针对etag
头部,加一个if-none-match
头部带上etag
的值询问服务器。当然也可以针对last-modified
头部,加一个if-modified-since
头部询问。
返回的是304。304的好处就是不携带包体,也就是说content-length
为0,这样就节省了大量的带宽。
浏览器缓存是私有缓存,只提供给一个用户使用的。
而共享缓存是放在服务器上的,可以提供多个用户使用。比如说某个比较热点的视频等热点资源就会放在代理代理服务器的缓存中,以减低源服务器的压力,提升网络效率。
怎么分辨这个资源是代理服务器的缓存还是源服务器发送的呢?
仍然使用掘金的例子
从图中看出这个请求的Response Headers
中的age
头部,单位是秒。
说明这个缓存是共享缓存返回的,age
说明了它在共享缓存存在的时间,图中是327784,也就是在共享缓存中存在了327784秒。
共享缓存也有过期的时候,下面看看共享缓存的工作原理。
如图所示:
1、当client1
发起请求时,Cache
也就是代理服务器(共享缓存),转发这条请求给源服务器。源服务器返回响应,并在Cache-Control
头部中设定可以缓存100秒。接着在Cache
中就会开启一个定时器Age
,将响应带上Age:0
头部返回给client1
。
2、过了10秒后,client2
发送相同的请求,Cache
中的缓存还没有过期,就带上Age:10
头部返回缓存中的响应给client2
。
3、过了100秒后,client3
发送同样的请求,这时Cache
中的缓存已经过期了,就像前面说到那样用条件请求头部If-None-Match
带上缓存的指纹发给源服务器。当源服务认为此缓存还能用,就返回304状态码给Cache
。Cache
就重新计时,从缓存中找出响应带上Age:0
头部返回给Client3
。
HTTP
协议中存在相关的缓存机制,API
中也可以直接使用这些机制来管理缓存。HTTP
的缓存机制在RFC7234
中进行了详细的定义,分为:过期模型(Expiration Model)
和验证模型(Validation Model)
两类
在HTTP
中,缓存处于可用的状态时称为fresh
(新鲜)状态,而处于不可用的状态时则称为stale
(不新鲜)状态。
过期模型可以通过服务器的响应消息里包含何时过期的信息来实现。HTTP1.1
中定义了两种实现方法:一个方法是用Cache-Control
响应消息首部,另一个方法就是用Expires
响应消息首部。
// 1 Expires: Fri, 01 Oct 2020 00:00:00 GMT // 2 Cache-Control: max-age=3600复制代码
Expires
首部从HTTP1.0
就已经存在了,它是用绝对时间来表示到期,并使用RFC1123
中定义的时间格式来描述。Cache-Control
则是HTTP1.1
etag
헤더의 경우 etag
값과 함께 if-none-match
헤더를 추가하여 서버를 쿼리합니다. 물론 if-modified-since
헤더를 추가하여 last-modified
헤더를 요청할 수도 있습니다. content-length
는 0입니다. , 이는 많은 비용을 절약합니다. 🎜응답 헤더
에서 age
를 볼 수 있습니다. 이 요청입니다. 단위는 초입니다. 🎜🎜이 캐시가 공유 캐시에 의해 반환되었음을 나타냅니다. age
는 공유 캐시에 존재하는 시간을 나타냅니다. 이는 327784초 동안 공유 캐시에 존재했음을 의미합니다. 🎜🎜공유 캐시도 만료됩니다. 공유 캐시가 어떻게 작동하는지 살펴보겠습니다. client1
가 요청을 시작하면 캐시
는 프록시 서버(공유 캐시)는 이 요청을 원본 서버로 전달합니다. 원본 서버는 응답을 반환하고 Cache-Control
헤더에 캐시 시간을 100초로 설정합니다. 그런 다음 타이머 Age
가 캐시
에서 시작되고 응답이 Age: 0
와 함께 client1
에 반환됩니다. > 헤더 >. 🎜🎜2. 10초 후에 client2
가 동일한 요청을 보냅니다. Cache
의 캐시가 만료되지 않았으므로 Age: 10
>이 됩니다. 헤더는 캐시된 응답을 client2
에 반환합니다. 🎜🎜3. 100초 후에 client3
가 동일한 요청을 보냅니다. 이때 Cache
의 캐시가 만료되었습니다. If-None-Match 부분은 캐시된 지문을 담아 원본 서버로 보냅니다. 원본 서비스는 캐시가 여전히 사용 가능하다고 판단하면 Cache
에 304 상태 코드를 반환합니다. 캐시
는 시간을 재조정하여 캐시에서 응답을 찾아 Age: 0
헤더와 함께 Client3
에 반환합니다. 🎜HTTP
프로토콜에는 관련 캐싱 메커니즘이 있으며 API 캐시를 관리하는 메커니즘입니다. <code>HTTP
의 캐싱 메커니즘은 RFC7234
에 자세히 정의되어 있으며 만료 모델(Expiration Model)
과 검증 모델( 검증 모델)
두 가지 유형🎜HTTP
에서는 캐시가 사용 가능한 상태일 때를 fresh
(신선한) 상태라고 하고, 사용할 수 없는 상태를 stale
(신선하지 않음)이라고 합니다. 🎜HTTP1.1
에는 두 가지 구현 방법이 정의되어 있습니다. 한 가지 방법은 Cache-Control
을 사용하여 메시지 헤더에 응답하는 것이고, 다른 방법은 Expires를 사용하는 것입니다.
를 사용하여 메시지 헤더에 응답합니다. 🎜Expires: Fri, 01 Oct 2021 00:00:00 GMT复制代码
Expires
헤더는 HTTP1.0
부터 존재했으며 만료를 나타내기 위해 절대 시간을 사용하며 설명하기 위해 RFC1123
시간 형식으로 정의됩니다. . Cache-Control
은 HTTP1.1
에 정의되어 있으며 현재 시간 이후 경과된 시간(초)을 나타냅니다. 🎜这两个首部该使用哪个,则是由返回的数据的性质决定的。对于一开始就知道在某个特定的日期会更新的数据,比如天气预报这种每天在相同时间进行更新的数据,可以使用Expires
首部来指定执行更新操作的时间。对于今后不会使用更新的数据或静态数据等,可以通过指定一个未来非常遥远的日期,使得获取的缓存数据始终保存下去。但根据HTTP1.1
的规定,不允许设置超过1年以上的时间,因此未来非常遥远的时间最多也只能是1年后的日期了。
Expires: Fri, 01 Oct 2021 00:00:00 GMT复制代码
而对于不是定期更新,但如果更新频率在某种程度上是一定的,或者虽然更新频率不低但不希望频繁访问服务器端,对于这种情况可以使用Cache-Control
首部。
如果Expires
和Cache-Control
首部同时使用时,Cache-Control
首部优先判断。
上面Cache-Control
示例中使用到了max-age
关键字,max-age
计算会使用名为Date
的首部。该首部用来显示服务器端生成响应信息的时间信息。从该时间开始计算,当经过的时间超过max-age
值时,就可以认为缓存已到期。
Date: Expires: Fri, 30 Sep 2020 00:00:00 GMT复制代码
Date
首部表示服务器端生成响应信息的时间信息。根据HTTP
协议的规定,除了几个特殊的情况之外,所有的HTTP
消息都要加上Date
首部。
Date
首部的时间信息必须使用名为HTTP
时间的格式来描述。在计算缓存时间时,会用到该首部的时间信息,这时就可以使用Date
首部信息来完成时间的同步操作,做到即便客户端擅自修改日期等配置信息。
与到期模型只根据所接收的响应信息来决定缓存的保存时间相对,验证模型采用了询问服务器的方式来判断当前时间所保存的缓存是否有效。
验证模型在检查缓存的过程中会不时地去访问网络。在执行验证模型时,需要应用程序服务器支持附带条件地请求。附带条件地请求是指前端向服务器端发送地“如果现在保存地信息有更新,请给我更新后地信息”。在整个处理的过程中,前端会发送同“过去某个时间点所获得的数据”有关的信息,随后只有在服务器端的数据发生更新时,服务器端才会返回更新的数据,不然就只会返回304(Not Modified)
状态码来告知前端当前服务器端没有更新的数据。
要进行附带条件的请求,就必须向服务器端传达“前端当前保存的信息的状态”,为此需要用到最后更新日期或实体标签(Entity Tag)
作为指标。顾名思义,最后更新日期表示当前数据最后一次更新的日期:而实体标签则是表示某个特定资源版本的标识符,十一串表示指纹印(Finger Print)
的字符串。例如响应数据的MD5散列值等,整个字符串会随着消息内容的变化而变化。这些信息会在服务器端生成,并被包含在响应信息的首部发送给前端,前端会将其缓存一同保存下来,用于附带条件的请求。
最后更新日期和实体标签会被分别填充到Last-Modified
和ETag
响应消息首部返回给前端
Last-Modified: Fri, 01 Oct 2021 00:00:00 GMT ETag: 'ff568sdf4545687fadf4dsa545e4f5s4f5se45'复制代码
前端使用最后更新日期执行附带条件的请求时,会用到Modified-Since
首部。在使用实体标签时,会用到If-None-Match
首部
GET /v1/user/1 If-Modified-Since: Fri, 01 Oct 2021 00:00:00 GMT GET /v1/user/1 If-None-Match: 'ff568sdf4545687fadf4dsa545e4f5s4f5se45'复制代码
服务器端会检查前端发送过来的信息和当前信息,如果没有发生更新则返回304状态码。如果有更新,则会同应答普通请求一样,在返回200状态码的同时将更新内容一并返回给前端,这时也会带上新的最后更新日期和实体标签。当服务器返回304状态码时,响应消息为空,从而节约了传输的数据量。
在HTTP
协议中,ETag
有强验证与弱验证两个概念。
执行强验证的ETag
ETag: 'ffsd5f46s12wef13we2f13dsd21fsd32f1'
执行弱验证的ETag
ETag: W/'ffsd5f46s12wef13we2f13dsd21fsd32f1'
强验证是指服务器端同客户端的数据不能有一个字节的差别,必须完全一样;而弱验证是指即使数据不完全一样,只要从资源意义的角度来看没有发生变化,就可以视为相同的数据。例如广告信息,虽然每次访问时这些广告的内容都会有所改变,但它们依然是相同的资源,这种情况下便可以使用弱验证。
HTTP1.1
에서는 서버가 명확한 만료 시간을 제공하지 않으면 클라이언트가 캐시된 데이터를 저장해야 하는 기간을 결정할 수 있다고 언급했습니다. 이때 클라이언트는 서버의 업데이트 빈도, 특정 조건 및 기타 정보를 기반으로 캐시 만료 시간을 결정해야 합니다. 이 방법을 휴리스틱 만료라고 합니다. HTTP1.1
里提到了当服务器端没有给出明确的过期时间时,客户端可以决定大约需要将缓存数据保存多久。这时客户端就要根据服务器端的更新频率、具体状况等信息,自行决定缓存的过期时间,这个方法称为启发式过期。
例如前端通过观察Last-Modified
,如果发现最后一次更新是在1年前,那就意味着再将缓存数据保存一段时间也不会有什么问题;如果发现到目前为止访问的结果是1天只有1次更新,那就意味着将缓存保存半天的时间或许可行。像这样,前端能通过独立判断来减少访问次数。
虽然API
是否允许使用启发式过期的方法取决于API的特性,但由于服务端对缓存的更新和控制理解最为深刻,因此服务器端通过Cache-Control
、Expires
等准确无误地向前端返回“将缓存数据保存多久”的信息,对于交互双方而言都是比较理想的做法。但如果不返回,服务器端就需要通过Last-Modified
等首部信息来告知前端
Vary
指定缓存单位在实施缓存时可能还需要同时指定Vary
首部。在实施缓存时,Vary
用于指定除URI
外使用哪个请求首部项目来确定唯一的数据。使用Vary
是因为即使URI
相同,获取的数据有时也会因请求首部内容的不同而发生变化。只有vary
头部指定的头部必须与请求中的头部相匹配才能使用缓存。
vary
的定义:
field-name
:指定的头部必须与请求中的头部相匹配才能使用缓存如图所示:
1、 当Client1
携带Accept-Encoding:*
头部的GET
请求发送给server
。server
返回的是gzip
编码的响应,以及vary:Content-Encoding
头部,表示着编码方式一样的时候才能使用缓存。
2、当Client2
携带Accept-Encoding:br
头部的GET
请求发送给server
,这时请求的是br
编码。所以Cache
不能使用缓存,因为不匹配vary
的中的值,只能转发请求给源服务器server
。
3、当Client3
携带Accept-Encoding:br
头部的GET
请求发送给server
,这时Cache
有br
编码的缓存,能匹配vary
头部的值,所以能使用缓存返回。
一般而言,Vary
首部用于HTTP经由代理服务器进行交互的场景,特别是在代理服务器拥有缓存功能时。但是有时服务端无法得知前端的访问是否经由代理服务器,这种情况下就需要用到服务器驱动的内容协商机制,Vary
首部也就成了必选项。
Cache-Control
头部取值范围非常复杂。
Cache-Control
的定义是:
token
值Cache-Control
既可以在请求中使用,也可以在响应是使用。而且相同的值在请求和响应中的含义是不一样的。
Cache-Control
值有三种用法:
token
token
值+ '=' + 十进制数字token
值+ '=' + 相应的头部 / 直接使用token
值在请求中Cache-Control
Last-Modified
를 관찰하여 마지막 업데이트가 1년 전이라는 것을 알게 되면 캐시 데이터를 한동안 저장해도 문제가 없다는 뜻입니다. 현재까지 찾아낸 경우 현재까지 접속한 결과 하루에 한 번만 업데이트가 되는 것으로 나타나 반나절 정도는 캐시를 저장하는 것이 가능할 수도 있다는 뜻입니다. 이처럼 프런트 엔드에서는 독립적인 판단을 통해 방문 횟수를 줄일 수 있습니다. 🎜🎜API
에서 경험적 만료 방법의 사용을 허용하는지 여부는 API의 특성에 따라 다르지만, 서버 측에서는 캐시 업데이트 및 제어에 대해 가장 깊이 이해하고 있으므로 서버 측에서는 Cache- Control, <code>Expires
등은 "캐시된 데이터를 저장하는 데 걸리는 시간"에 대한 정보를 프런트 엔드에 정확하게 반환하는데, 이는 상호 작용에 대한 양측 모두에게 이상적인 접근 방식입니다. 하지만 반환되지 않으면 서버는 Last-Modified
🎜Vary
사용 등의 헤더 정보를 통해 프런트엔드에 알려야 합니다. code>를 사용하여 캐시 단위 🎜🎜를 지정하려면 캐싱을 구현할 때 Vary
헤더를 지정해야 할 수도 있습니다. 캐싱을 구현할 때 Vary
는 URI
외에 어떤 요청 헤더 항목을 사용하여 고유한 데이터를 결정하는지 지정하는 데 사용됩니다. Vary
를 사용하는 이유는 URI
가 동일하더라도 요청 헤더의 내용이 다르기 때문에 얻은 데이터가 변경되는 경우가 있기 때문입니다. vary
헤더에 지정된 헤더만 사용할 캐싱 요청의 헤더와 일치해야 합니다. 🎜🎜vary
정의: 🎜필드 이름
: 캐싱을 사용하려면 지정된 헤더가 요청의 헤더와 일치해야 합니다.Client1
일 때 >는 Accept-Encoding:*
헤더를 포함하는 GET
요청을 서버
로 보냅니다. server
는 gzip
인코딩된 응답과 vary: Content-Encoding
헤더를 반환하며, 이는 인코딩 방법이 동일한 경우에만 캐싱을 사용할 수 있음을 나타냅니다. . 🎜🎜2. Client2
가 Accept-Encoding: br
헤더의 GET
요청을 전달하여 서버
로 보내는 경우, this 요청된 인코딩은 br
입니다. 따라서 캐시
는 vary
의 값과 일치하지 않기 때문에 캐싱을 사용할 수 없으며 원본 서버 서버
로만 요청을 전달할 수 있습니다. 🎜🎜3. Client3
가 Accept-Encoding: br
헤더의 GET
요청을 전달하여 서버
로 보내는 경우, this Cache
에 br
로 인코딩된 캐시가 있는 경우 vary
헤더의 값과 일치할 수 있으므로 캐시를 사용하여 반환될 수 있습니다. 🎜🎜일반적으로 Vary
헤더는 HTTP가 프록시 서버를 통해 상호 작용하는 시나리오, 특히 프록시 서버에 캐싱 기능이 있는 경우에 사용됩니다. 그러나 프런트엔드 액세스가 프록시 서버를 통해 이루어졌는지 여부를 서버가 알 수 없는 경우도 있습니다. 이 경우 서버 기반 콘텐츠 협상 메커니즘을 사용해야 하며 Vary
헤더는 필수 옵션이 됩니다. . 🎜Cache-Control
헤더의 값 범위는 매우 복잡합니다. 🎜🎜Cache-Control
은 다음과 같이 정의됩니다: 🎜토큰
값Cache-Control
은 요청과 응답 모두에 사용할 수 있습니다. 그리고 동일한 값이라도 요청과 응답에서는 다른 의미를 갖습니다. 🎜🎜Cache-Control
값에는 세 가지 용도가 있습니다: 🎜token
token값 + '=' + 십진수
토큰
값 + '=' + 해당 헤더/ 토큰
값을 직접 사용 li>Cache-Control
의 값, 사용법 및 의미: @ 다음은 용도🎜Age
가 max-age
초를 초과하는 캐시를 클라이언트가 수신하지 않을 것이라고 서버에 알립니다. Age
超出max-age
秒的缓存max-stale
时,客户端仍打算使用。若max-stale
后没有值,则表示无论过期多久,客户端都可使用。Age
至少经过min-fresh
秒后缓存才可使用在响应中Cache-Control
的取值及其含义:
Age
超出max-age
秒后则缓存过期max-age
类似,但仅针对共享缓存,且优先级高于max-age
和expires
must-revaildate
类似,但它仅对代理服务器的共享缓存有效no-cache
后指定头部,则若客户端的后续请求及响应中不含有这些头部则可直接使用缓存priate
max-stale
을 초과하지 않는 경우에도 마찬가지입니다. max-stale
뒤에 값이 없으면 만료 기간에 관계없이 클라이언트가 사용할 수 있다는 의미입니다. min-fresh@2: 캐시를 사용하려면응답 Cache-Control 값 및 의미: 🎜🎜🎜max-age@2: 클라이언트에게Age
가 최소min-fresh
초를 통과해야 한다고 서버에 알립니다.no-cache@1: 알립니다. 직접 사용할 수 없는 서버는 기존 캐시를 응답으로 사용합니다. 캐싱 조건이 있는 업스트림 서버에 가서 304 상태 코드를 받지 않으면 기존 캐시를 사용할 수 있습니다. no-store@1: 각 프록시 서버에 이 요청에 대한 응답을 캐시하지 말라고 지시합니다. no-transform@1: 프록시 서버에 메시지 본문의 내용을 수정하지 말라고 지시합니다. only-if-cached@1 : 서버에 캐시된 응답만 반환할 수 있다고 알려주세요. 캐시가 없으면 504 오류 코드가 반환됩니다
애플리케이션 응답
Age
가 max-age초 🎜🎜s -maxage@2: <code>max-age
와 유사하지만 공유 캐시에만 해당되며 max-age
및 expires
🎜🎜 must-revaldate@1: 캐시가 만료되면 서버에 인증해야 사용할 수 있음을 클라이언트에 알립니다. 🎜🎜proxy-revalidate@1: must-와 유사합니다. revaildate
이지만 프록시 서버만 공유합니다. 캐시가 유효합니다🎜🎜no-cache@3: 1. 클라이언트에게 캐시된 응답을 직접 사용할 수 없다고 알려주세요. 사용하기 전에 304 반환 코드를 확인하세요. 2. no-cache
뒤에 헤더가 지정된 경우 클라이언트의 후속 요청 및 응답에 이러한 헤더가 포함되어 있지 않으면 캐시를 직접 사용할 수 있습니다. 🎜🎜no-store@1: 모든 다운스트림 서버에 알립니다. 하지만 응답을 캐시할 수 없습니다🎜🎜no-transform: 메시지 본문의 내용을 수정할 수 없다고 프록시 서버에 알립니다🎜🎜public@1: 개인 캐시 또는 공유 캐시에 관계없이 응답을 캐시할 수 있음을 나타냅니다🎜🎜private@ 3: 1. 이 응답을 프록시 서버에서 공유 캐시로 사용할 수 없음을 나타냅니다. 2. priate
뒤에 헤더가 지정되면 지정된 헤더를 캐시할 수 없고 다른 헤더도 캐시할 수 있음을 프록시 서버에 알립니다🎜🎜🎜🎜🎜관련 무료 학습 권장 사항: 🎜🎜🎜javascript🎜🎜 🎜(동영상)🎜🎜🎜위 내용은 '캐싱'을 해결하는 기사 1개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!