diff options
-rw-r--r-- | files/zh-tw/web/http/caching/index.html | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/files/zh-tw/web/http/caching/index.html b/files/zh-tw/web/http/caching/index.html index 4c17aacc14..ebf806f89f 100644 --- a/files/zh-tw/web/http/caching/index.html +++ b/files/zh-tw/web/http/caching/index.html @@ -12,11 +12,7 @@ tags: --- <div>{{HTTPSidebar}}</div> -<div>藉由重複使用先前取過的資源,網站與網頁應用程式能夠顯著地提升效能。</div> - -<div>caching可以減少網路傳輸量以降低一個資源可展示的延遲時間。</div> - -<div>善用 HTTP caching可以讓網站可以回應更多請求。</div> +<p class="summary">藉由重複使用先前取過的資源,網站與網頁應用程式能夠顯著地提升效能。caching可以減少網路傳輸量以降低一個資源可展示的延遲時間。善用 HTTP caching可以讓網站可以回應更多請求。</p> <h2 id="不同種類的快取">不同種類的快取</h2> @@ -101,25 +97,29 @@ Cache-Control: public <p>Here is an example of this process with a shared cache proxy:</p> -<p><img alt="Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale." src="https://mdn.mozillademos.org/files/13771/HTTPStaleness.png" style="height: 910px; width: 822px;"></p> +<p><img alt="Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale." src="http_staleness.png"></p> -<p>The freshness lifetime is calculated based on several headers. If a "<code>Cache-control: max-age=N</code>" header is specified, then the freshness lifetime is equal to N. If this header is not present, which is very often the case, it is checked if an {{HTTPHeader("Expires")}} header is present. If an <code>Expires</code> header exists, then its value minus the value of the {{HTTPHeader("Date")}} header determines the freshness lifetime. Finally, if neither header is present, look for a {{HTTPHeader("Last-Modified")}} header. If this header is present, then the cache's freshness lifetime is equal to the value of the <code>Date</code> header minus the value of the <code>Last-modified</code> header divided by 10.<br> - The expiration time is computed as follows:</p> +<p>The freshness lifetime is calculated based on several headers. If a "<code>Cache-Control: max-age=N</code>" header is specified, then the freshness lifetime is equal to N. If this header is not present, which is very often the case, it is checked if an {{HTTPHeader("Expires")}} header is present. If an <code>Expires</code> header exists, then its value minus the value of the {{HTTPHeader("Date")}} header determines the freshness lifetime.</p> -<pre>expirationTime = responseTime + freshnessLifetime - currentAge -</pre> +<h3 id="Heuristic_freshness_checking">Heuristic freshness checking</h3> + +<p>If an origin server does not explicitly specify freshness (e.g. using {{HTTPHeader("Cache-Control")}} or {{HTTPHeader("Expires")}} header) then a heuristic approach may be used.</p> -<p>where <code>responseTime</code> is the time at which the response was received according to the browser.</p> +<p>In this case look for a {{HTTPHeader("Last-Modified")}} header. If this header is present, then the cache's freshness lifetime is equal to the value of the <code>Date</code> header minus the value of the <code>Last-modified</code> header divided by 10. The expiration time is computed as follows:</p> + +<pre>expirationTime = responseTime + freshnessLifetime - currentAge</pre> + +<p>where <code>responseTime</code> is the time at which the response was received according to the browser. For more information see <a href="https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2">RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): 4.2.2. Calculating Heuristic Freshness</a>.</p> <h3 id="Revved_resources">Revved resources</h3> <p>The more we use cached resources, the better the responsiveness and the performance of a Web site will be. To optimize this, good practices recommend to set expiration times as far in the future as possible. This is possible on resources that are regularly updated, or often, but is problematic for resources that are rarely and infrequently updated. They are the resources that would benefit the most from caching resources, yet this makes them very difficult to update. This is typical of the technical resources included and linked from each Web pages: JavaScript and CSS files change infrequently, but when they change you want them to be updated quickly.</p> -<p>Web developers invented a technique that Steve Souders called <em>revving</em><sup><a href="https://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/">[1]</a></sup>. Infrequently updated files are named in specific way: in their URL, usually in the filename, a revision (or version) number is added. That way each new revision of this resource is considered as a resource on its own that <em>never</em> changes and that can have an expiration time very far in the future, usually one year or even more. In order to have the new versions, all the links to them must be changed, that is the drawback of this method: additional complexity that is usually taken care of by the tool chain used by Web developers. When the infrequently variable resources change they induce an additional change to often variable resources. When these are read, the new versions of the others are also read.</p> +<p>Web developers invented a technique that Steve Souders called <em>revving</em><sup><a href="https://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/">[1]</a></sup>. Infrequently updated files are named in a specific way: in their URL, usually in the filename, a revision (or version) number is added. That way each new revision of this resource is considered as a resource on its own that <em>never</em> changes and that can have an expiration time very far in the future, usually one year or even more. In order to have the new versions, all the links to them must be changed, that is the drawback of this method: additional complexity that is usually taken care of by the tool chain used by Web developers. When the infrequently variable resources change they induce an additional change to often variable resources. When these are read, the new versions of the others are also read.</p> <p>This technique has an additional benefit: updating two cached resources at the same time will not lead to the situation where the out-dated version of one resource is used in combination with the new version of the other one. This is very important when web sites have CSS stylesheets or JS scripts that have mutual dependencies, i.e., they depend on each other because they refer to the same HTML elements.</p> -<p><img alt="" src="https://mdn.mozillademos.org/files/13779/HTTPRevved.png"></p> +<p><img alt="How the revved cache mechanism works. With minor typo fix to grammar issue: https://github.com/mdn/sprints/issues/2618" src="http_revved_fix_typo.png"></p> <p>The revision version added to revved resources doesn't need to be a classical revision string like 1.1.3, or even a monotonously growing suite of number. It can be anything that prevent collisions, like a hash or a date.</p> @@ -127,34 +127,63 @@ Cache-Control: public <p>When a cached document's expiration time has been reached, it is either validated or fetched again. Validation can only occur if the server provided either a <em>strong validator</em> or a <em>weak validator</em>.</p> -<p>Revalidation is triggered when the user presses the reload button. It is also triggered under normal browsing if the cached response includes the "<code>Cache-control: must-revalidate</code>" header. Another factor is the cache validation preferences in the <code>Advanced->Cache</code> preferences panel. There is an option to force a validation each time a document is loaded.</p> +<p>Revalidation is triggered when the user presses the reload button. It is also triggered under normal browsing if the cached response includes the "<code>Cache-Control: must-revalidate</code>" header. Another factor is the cache validation preferences in the <code>Advanced->Cache</code> preferences panel. There is an option to force a validation each time a document is loaded.</p> <h3 id="ETags">ETags</h3> <p>The {{HTTPHeader("ETag")}} response header is an <em>opaque-to-the-useragent</em> value that can be used as a strong validator. That means that a HTTP user-agent, such as the browser, does not know what this string represents and can't predict what its value would be. If the <code>ETag</code> header was part of the response for a resource, the client can issue an {{HTTPHeader("If-None-Match")}} in the header of future requests – in order to validate the cached resource.</p> +<h3 id="Last-Modified">Last-Modified</h3> + <p>The {{HTTPHeader("Last-Modified")}} response header can be used as a weak validator. It is considered weak because it only has 1-second resolution. If the <code>Last-Modified</code> header is present in a response, then the client can issue an {{HTTPHeader("If-Modified-Since")}} request header to validate the cached document.</p> -<p>When a validation request is made, the server can either ignore the validation request and response with a normal {{HTTPStatus(200)}} <code>OK</code>, or it can return {{HTTPStatus(304)}} <code>Not Modified</code> (with an empty body) to instruct the browser to use its cached copy. The latter response can also include headers that update the expiration time of the cached document.</p> +<p>When a validation request is made, the server can either ignore the validation request and respond with a normal {{HTTPStatus(200)}} <code>OK</code>, or it can return {{HTTPStatus(304)}} <code>Not Modified</code> (with an empty body) to instruct the browser to use its cached copy. The latter response can also include headers that update the expiration time of the cached document.</p> <h2 id="Varying_responses">Varying responses</h2> -<p>The {{HTTPHeader("Vary")}} HTTP response header determines how to match future request headers to decide whether a cached response can be used rather than requesting a fresh one from the origin server.</p> +<p>The {{HTTPHeader("Vary")}} HTTP response header determines how to match future request headers to decide whether a cached response can be used, or if a fresh one must be requested from the origin server.</p> + +<p>When a cache receives a request that has a <code>Vary</code> header field, it must not use a cached response by default unless all header fields specified in the <code>Vary</code> header match in both the original (cached) request and the new request.</p> -<p>When a cache receives a request that can be satisfied by a cached response that has a <code>Vary</code> header field, it must not use that cached response unless all header fields as nominated by the <code>Vary</code> header match in both the original (cached) request and the new request.</p> +<p><img alt="The Vary header leads cache to use more HTTP headers as key for the cache." src="http_vary.png">This feature is commonly used to allow a resource to be cached in uncompressed and (various) compressed forms, and served appropriately to user agents based on the encodings that they support. For example, a server can set <code>Vary: Accept-Encoding</code> to ensure that a separate version of a resource is cached for all requests that specify support for a particular set of encodings, e.g. <code>Accept-Encoding: gzip,deflate,sdch</code>.</p> -<p><img alt="The Vary header leads cache to use more HTTP headers as key for the cache." src="https://mdn.mozillademos.org/files/13769/HTTPVary.png" style="height: 817px; width: 752px;"></p> +<pre>Vary: Accept-Encoding</pre> -<p>This can be useful for serving content dynamically, for example. When using the <code>Vary: User-Agent</code> header, caching servers should consider the user agent when deciding whether to serve the page from cache. If you are serving different content to mobile users, it can help you to avoid that a cache may mistakenly serve a desktop version of your site to your mobile users. In addition, it can help Google and other search engines to discover the mobile version of a page, and might also tell them that no <a href="https://en.wikipedia.org/wiki/Cloaking">Cloaking</a> is intended.</p> +<div class="notecard note"> + <h4>Note</h4> + <p>Use <code>Vary</code> with care—it can easily reduce the effectiveness of caching! A caching server should use <a href="#normalization">normalization</a> to reduce duplicated cache entries and unnecessary requests to the origin server. This is particularly true when using <code>Vary</code> with headers and header values that can have many values.</p> +</div> + +<p>The <code>Vary</code> header can also be useful for serving different content to desktop and mobile users, or to allow search engines to discover the mobile version of a page (and perhaps also tell them that no <a href="https://en.wikipedia.org/wiki/Cloaking">Cloaking</a> is intended). This is usually achieved with the <code>Vary: User-Agent</code> header, and works because the {{HTTPHeader("User-Agent")}} header value is different for mobile and desktop clients.</p> <pre>Vary: User-Agent</pre> -<p>Because the {{HTTPHeader("User-Agent")}} header value is different ("varies") for mobile and desktop clients, caches will not be used to serve mobile content mistakenly to desktop users or vice versa.</p> +<h3 id="Normalization">Normalization</h3> + +<p>As discussed above, caching servers will by default match future requests <em>only</em> to requests with <em>exactly</em> the same headers and header values. That means a request will be made to the origin and a new cache will be created for every slight variant that might be specified by different user-agents.</p> + +<p>For example, by default all of the following result in a separate request to the origin and a separate cache entry: <code>Accept-Encoding: gzip,deflate,sdch</code>, <code>Accept-Encoding: gzip,deflate</code>, <code>Accept-Encoding: gzip</code>. This is true even though the origin server will probably respond with — and store — the same resource for all requests (a gzip)!</p> + +<p>To avoid unnecessary requests and duplicated cache entries, caching servers should use <strong>normalization</strong> to pre-process the request and cache only files that are needed. For example, in the case of <code>Accept-Encoding</code> you could check for <code>gzip</code> and other compression types in the header before doing further processing, and otherwise unset the header. In "pseudo code" this might look like:</p> + +<pre>// Normalize Accept-Encoding +if (req.http.Accept-Encoding) { + if (req.http.Accept-Encoding ~ "gzip") { + set req.http.Accept-Encoding = "gzip"; + } + // elsif other encoding types to check +else { + unset req.http.Accept-Encoding; + } +} +</pre> + +<p><code>User-Agent</code> has even more variation than <code>Accept-Encoding</code>. So if using <code>Vary: User-Agent</code> for caching mobile/desktop variants of files you'd similarly check for the presence of <code>"mobile"</code> and <code>"desktop"</code> in the request <code>User-Agent</code> header, and then clear it.</p> <h2 id="See_also">See also</h2> <ul> - <li><a href="https://tools.ietf.org/html/rfc7234">RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching</a></li> + <li><a href="https://datatracker.ietf.org/doc/html/rfc7234">RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching</a></li> <li><a href="https://www.mnot.net/cache_docs">Caching Tutorial – Mark Nottingham</a></li> <li><a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching">HTTP caching – Ilya Grigorik</a></li> <li><a href="https://redbot.org/">RedBot</a>, a tool to check your cache-related HTTP headers.</li> |