Etag & If-None-Match 專題


 

 

一、概述
緩存通俗點講,就是將已經得到的‘東東’存放在一個相對於自己而言,盡可能近的地方,以便下次需要時,不會再二筆地跑到起始點(很遠的地方)去獲取,而是就近解決,從而縮短時間和節約金錢(坐車要錢嘛)。Web緩存,也是同樣的道理,說白了,就是當你第一次訪問網址時,將這個東東(representations),如html頁面、圖片、JavaScript文件等,存在一個離你較近的地方,當你下次還需要它時,不用再一次跋山涉水到服務器(origin servers)去獲取。繼而,web緩存的優勢也就很明顯了:

  1、 減少了網絡延遲,加快了頁面響應速度,增強了用戶體驗嘛。(因為我是就近獲取的,路程縮短了,所以響應速度當然比到遙遠的服務器去獲取快哦);

  2、 減少了網絡帶寬消耗嘛。(就近獲取);

  3、 通過緩存,我們都不用到服務器 (origin servers)去請求了,從而也就相應地減輕了服務器的壓力。

那web緩存將這些東東放在哪兒呢?下面我就看看有哪些緩存種類,從而了解放在哪吧。

二、Web緩存的種類

--數據庫緩存--:

當web應用關系復雜,數據表蹭蹭蹭往上漲時,可以將查詢后的數據放到內存中進行緩存,下次再查詢時,就直接從內存緩存中獲取,從而提高響應速度。

--CDN緩存--:

CDN通俗點,就是當我們發送一個web請求時,會先經過它一道手,然后它幫我們計算路徑,去哪得到這些東東(representations)的路徑短且快。這個是網站管理員部署的,所以他們也可以將大家經常訪問的representations放在CDN里,這樣,就響應就更快了。

--代理服務器緩存--:

代理服務器緩存,其實跟下面即將講的瀏覽器緩存性質差不多,差別就是代理服務器緩存面向的群體更廣,規模更大而已。即,它不只為一個用戶服務,一般為大量用戶提供服務,同一個副本會被重用多次,因此在減少相應時間和帶寬使用方面很有效。

--瀏覽器緩存--:

簡而言之,就是,每個瀏覽器都實現了 HTTP 緩存,我們通過瀏覽器使用HTTP協議與服務器交互的時候,瀏覽器就會根據一套與服務器約定的規則進行緩存工作。當我們點擊瀏覽器上‘后退’或者‘前進’按鈕時,顯得特別有用。

三、Web緩存的執行機制

所謂機制就是一些雙方的約定,清晰地告訴對方,什么時候該做什么事。web緩存也一樣,你總得告訴我(請求)什么時候到緩存中去獲取,什么到服務器去獲取representations吧。So,也得有一套相應的機制,web 緩存機制分為兩大部分http協議(HTTP1.0和HTTP1.1)和網站管理人員制定的協議。拋開網站內部制定的協議,我們來看看http協議中定義的緩存機制。

By the way,我們可以在HTML文檔中的<head>中通過<meta>來緩存,如下:

<meta http-equiv="Pragma" content="no-cache"/>

但,它只有部分瀏覽器可以用,並且代理服務器也不會鳥它。(因為meta在html中,代理服務器幾乎不回去讀它滴)。

--http緩存機制--

1、 Expires

http緩存機制主要在http響應頭中設定,響應頭中相關字段為Expires、Cache-Control、Last-Modified、If-Modified-Since、Etag。

HTTP 1.0協議中的。簡而言之,就是告訴瀏覽器在約定的這個時間前,可以直接從緩存中獲取資源(representations),而無需跑到服務器去獲取。

另:Expires因為是對時間設定的,且時間是Greenwich Mean Time (GMT),而不是本地時間,所以對時間要求較高。

2、 Cache-Control

HTTP1.1協議中的,因為有了它,所以可以忽略上面提到的Expires。因為Cache-Control相對於Expires更加具體,細致。

且,就算同時設置了Cache-Control和Expires,Cache-Control的優先級也高於Expires。

下面就來看看,Cache-Control響應頭中常用字段的具體含義:

  (1)、max-age:用來設置資源(representations)可以被緩存多長時間,單位為秒;

  (2)、s-maxage:和max-age是一樣的,不過它只針對代理服務器緩存而言;

  (3)、public:指示響應可被任何緩存區緩存;

  (4)、private:只能針對個人用戶,而不能被代理服務器緩存;

  (5)、no-cache:強制客戶端直接向服務器發送請求,也就是說每次請求都必須向服務器發送。服務器接收到請求,然后判斷資源是否變更,是則返回新內容,否則返回304,未變更。這個很容易讓人產生誤解,使人誤以為是響應不被緩存。實際上Cache-Control: no-cache是會被緩存的,只不過每次在向客戶端(瀏覽器)提供響應數據時,緩存都要向服務器評估緩存響應的有效性。

  (6)、no-store:禁止一切緩存(這個才是響應不被緩存的意思)。

3、 Etag & If-None-Match

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Content-Length: 1040
Content-Type: text/html

Etag是屬於HTTP 1.1屬性,它是由服務器生成返回給前端,

當你第一次發起HTTP請求時,服務器會返回一個Etag

並在你第二次發起同一個請求時,客戶端會同時發送一個If-None-Match,而它的值就是Etag的值(此處由發起請求的客戶端來設置)。

然后,服務器會比對這個客服端發送過來的Etag是否與服務器的相同

如果相同,就將If-None-Match的值設為false,返回狀態為304,客戶端繼續使用本地緩存,不解析服務器返回的數據(這種場景服務器也不返回數據,因為服務器的數據沒有變化嘛)

如果不相同,就將If-None-Match的值設為true,返回狀態為200,客戶端重新解析服務器返回的數據

說白了,
ETag 實體標簽: 一般為資源實體的哈希值
即ETag就是服務器生成的一個標記,用來標識返回值是否有變化

且Etag的優先級高於Last-Modified

溫馨提示【If-None-Match頭中的ETag必須和返回的ETag值一樣,有雙引號】:

 

生成ETag的邏輯:
org.springframework.web.filter.ShallowEtagHeaderFilter#generateETagHeaderValue

    /**
     * Generate the ETag header value from the given response body byte array.
     * <p>The default implementation generates an MD5 hash.
     * @param inputStream the response body as an InputStream
     * @param isWeak whether the generated ETag should be weak
     * @return the ETag header value
     * @see org.springframework.util.DigestUtils
     */
    protected String generateETagHeaderValue(InputStream inputStream, boolean isWeak) throws IOException {
        // length of W/ + " + 0 + 32bits md5 hash + "
        StringBuilder builder = new StringBuilder(37);
        if (isWeak) {
            builder.append("W/");
        }
        builder.append("\"0");
        DigestUtils.appendMd5DigestAsHex(inputStream, builder);
        builder.append('"');
        return builder.toString();
    }


3xx
301 Move Permanently
302 Found
304 Not Modified

4、 Last-Modified & If-Modified-Since

Last-Modified與Etag類似。不過Last-Modified表示響應資源在服務器最后修改時間而已。與Etag相比,不足為:

  (1)、Last-Modified標注的最后修改只能精確到秒級,如果某些文件在1秒鍾以內,被修改多次的話,它將不能准確標注文件的修改時間;

  (2)、如果某些文件會被定期生成,當有時內容並沒有任何變化,但Last-Modified卻改變了,導致文件沒法使用緩存;

  (3)、有可能存在服務器沒有准確獲取文件修改時間,或者與代理服務器時間不一致等情形。

然而,Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加准確的控制緩存。

四、擴展閱讀

[1]、"Caching Tutorial"

RFC 7232              HTTP/1.1 Conditional Requests            June 2014
This method relies on the fact that if two different responses were sent by the origin server during the same second, but both had the same Last-Modified time, then at least one of those responses would have a Date value equal to its Last-Modified time. The arbitrary 60-second limit guards against the possibility that the Date and Last-Modified values are generated from different clocks or at somewhat different times during the preparation of the response. An implementation MAY use a value larger than 60 seconds, if it is believed that 60 seconds is too short.

2.3. ETag

 The "ETag" header field in a response provides the current entity-tag for the selected representation, as determined at the conclusion of handling the request. An entity-tag is an opaque validator for differentiating between multiple representations of the same resource, regardless of whether those multiple representations are due to resource state changes over time, content negotiation resulting in multiple representations being valid at the same time, or both. An entity-tag consists of an opaque quoted string, possibly prefixed by a weakness indicator.  ETag = entity-tag entity-tag = [ weak ] opaque-tag weak = %x57.2F ; "W/", case-sensitive opaque-tag = DQUOTE *etagc DQUOTE etagc = %x21 / %x23-7E / obs-text ; VCHAR except double quotes, plus obs-text
 Note: Previously, opaque-tag was defined to be a quoted-string ([RFC2616], Section 3.11); thus, some recipients might perform backslash unescaping. Servers therefore ought to avoid backslash characters in entity tags. An entity-tag can be more reliable for validation than a modification date in situations where it is inconvenient to store modification dates, where the one-second resolution of HTTP date values is not sufficient, or where modification dates are not consistently maintained.
 Examples: ETag: "xyzzy" ETag: W/"xyzzy" ETag: "" 

 

 https://tools.ietf.org/html/rfc7232#section-2.3

 

The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for web cache validation, which allows a client to make conditional requests. This allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed. ETags can also be used for optimistic concurrency control,[1] as a way to help prevent simultaneous updates of a resource from overwriting each other.

 

An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL. If the resource representation at that URL ever changes, a new and different ETag is assigned. Used in this manner ETags are similar to fingerprints, and they can be quickly compared to determine whether two representations of a resource are the same.
https://en.wikipedia.org/wiki/HTTP_ETag

17.13 ETag support
An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL. It can be considered to be the more sophisticated successor to the Last-Modified header. When a server returns a representation with an ETag header, the client can use this header in subsequent GETs, in an If-None-Match header. If the content has not changed, the server returns 304: Not Modified.

Support for ETags is provided by the Servlet filter ShallowEtagHeaderFilter. It is a plain Servlet Filter, and thus can be used in combination with any web framework. The ShallowEtagHeaderFilter filter creates so-called shallow ETags (as opposed to deep ETags, more about that later).The filter caches the content of the rendered JSP (or other content), generates an MD5 hash over that, and returns that as an ETag header in the response. The next time a client sends a request for the same resource, it uses that hash as the If-None-Match value. The filter detects this, renders the view again, and compares the two hashes. If they are equal, a 304 is returned. This filter will not save processing power, as the view is still rendered. The only thing it saves is bandwidth, as the rendered response is not sent back over the wire.

You configure the ShallowEtagHeaderFilter in web.xml:

<filter>
  <filter-name>etagFilter</filter-name>
    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>etagFilter</filter-name>
  <servlet-name>petclinic</servlet-name>
</filter-mapping>

https://docs.spring.io/spring-framework/docs/3.2.0.M2/reference/html/mvc.html#mvc-exceptionhandlers

 http://www.spring4all.com/article/1553
java config方式配置:

@Configuration
public class WebConfig {

  @Bean
  public Filter shallowEtagHeaderFilter() {
    return new ShallowEtagHeaderFilter();
  }
}

https://stackoverflow.com/questions/26151057/add-a-servlet-filter-in-a-spring-boot-application
https://stackoverflow.com/questions/30350137/generating-etag-using-spring-boot
https://javadeveloperzone.com/spring-boot/spring-boot-etag-header-example/

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM