All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wl4g.component.common.remoting.standard.CacheControl Maven / Gradle / Ivy

/*
 * Copyright 2017 ~ 2025 the original author or authors. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wl4g.component.common.remoting.standard;

import java.util.concurrent.TimeUnit;

import com.wl4g.component.common.lang.StringUtils2;

/**
 * A builder for creating "Cache-Control" HTTP response headers.
 *
 * 

* Adding Cache-Control directives to HTTP responses can significantly improve * the client experience when interacting with a web application. This builder * creates opinionated "Cache-Control" headers with response directives only, * with several use cases in mind. * *

    *
  • Caching HTTP responses with * {@code CacheControl cc = CacheControl.maxAge(1, TimeUnit.HOURS)} will result * in {@code Cache-Control: "max-age=3600"}
  • *
  • Preventing cache with {@code CacheControl cc = CacheControl.noStore()} * will result in {@code Cache-Control: "no-store"}
  • *
  • Advanced cases like * {@code CacheControl cc = CacheControl.maxAge(1, TimeUnit.HOURS).noTransform().cachePublic()} * will result in * {@code Cache-Control: "max-age=3600, no-transform, public"}
  • *
* *

* Note that to be efficient, Cache-Control headers should be written along HTTP * validators such as "Last-Modified" or "ETag" headers. * * @see rfc7234 * section 5.2.2 * @see * HTTP caching - Google developers reference * @see Mark Nottingham's cache * documentation */ public class CacheControl { private long maxAge = -1; private boolean noCache = false; private boolean noStore = false; private boolean mustRevalidate = false; private boolean noTransform = false; private boolean cachePublic = false; private boolean cachePrivate = false; private boolean proxyRevalidate = false; private long staleWhileRevalidate = -1; private long staleIfError = -1; private long sMaxAge = -1; /** * Create an empty CacheControl instance. * * @see #empty() */ protected CacheControl() { } /** * Return an empty directive. *

* This is well suited for using other optional directives without * "max-age", "no-cache" or "no-store". * * @return {@code this}, to facilitate method chaining */ public static CacheControl empty() { return new CacheControl(); } /** * Add a "max-age=" directive. *

* This directive is well suited for publicly caching resources, knowing * that they won't change within the configured amount of time. Additional * directives can be also used, in case resources shouldn't be cached * ({@link #cachePrivate()}) or transformed ({@link #noTransform()}) by * shared caches. *

* In order to prevent caches to reuse the cached response even when it has * become stale (i.e. the "max-age" delay is passed), the "must-revalidate" * directive should be set ({@link #mustRevalidate()} * * @param maxAge * the maximum time the response should be cached * @param unit * the time unit of the {@code maxAge} argument * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.8 */ public static CacheControl maxAge(long maxAge, TimeUnit unit) { CacheControl cc = new CacheControl(); cc.maxAge = unit.toSeconds(maxAge); return cc; } /** * Add a "no-cache" directive. *

* This directive is well suited for telling caches that the response can be * reused only if the client revalidates it with the server. This directive * won't disable cache altogether and may result with clients sending * conditional requests (with "ETag", "If-Modified-Since" headers) and the * server responding with "304 - Not Modified" status. *

* In order to disable caching and minimize requests/responses exchanges, * the {@link #noStore()} directive should be used instead of * {@code #noCache()}. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.2 */ public static CacheControl noCache() { CacheControl cc = new CacheControl(); cc.noCache = true; return cc; } /** * Add a "no-store" directive. *

* This directive is well suited for preventing caches (browsers and * proxies) to cache the content of responses. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.3 */ public static CacheControl noStore() { CacheControl cc = new CacheControl(); cc.noStore = true; return cc; } /** * Add a "must-revalidate" directive. *

* This directive indicates that once it has become stale, a cache MUST NOT * use the response to satisfy subsequent requests without successful * validation on the origin server. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.1 */ public CacheControl mustRevalidate() { this.mustRevalidate = true; return this; } /** * Add a "no-transform" directive. *

* This directive indicates that intermediaries (caches and others) should * not transform the response content. This can be useful to force caches * and CDNs not to automatically gzip or optimize the response content. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.4 */ public CacheControl noTransform() { this.noTransform = true; return this; } /** * Add a "public" directive. *

* This directive indicates that any cache MAY store the response, even if * the response would normally be non-cacheable or cacheable only within a * private cache. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.5 */ public CacheControl cachePublic() { this.cachePublic = true; return this; } /** * Add a "private" directive. *

* This directive indicates that the response message is intended for a * single user and MUST NOT be stored by a shared cache. * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.6 */ public CacheControl cachePrivate() { this.cachePrivate = true; return this; } /** * Add a "proxy-revalidate" directive. *

* This directive has the same meaning as the "must-revalidate" directive, * except that it does not apply to private caches (i.e. browsers, HTTP * clients). * * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.7 */ public CacheControl proxyRevalidate() { this.proxyRevalidate = true; return this; } /** * Add an "s-maxage" directive. *

* This directive indicates that, in shared caches, the maximum age * specified by this directive overrides the maximum age specified by other * directives. * * @param sMaxAge * the maximum time the response should be cached * @param unit * the time unit of the {@code sMaxAge} argument * @return {@code this}, to facilitate method chaining * @see rfc7234 * section 5.2.2.9 */ public CacheControl sMaxAge(long sMaxAge, TimeUnit unit) { this.sMaxAge = unit.toSeconds(sMaxAge); return this; } /** * Add a "stale-while-revalidate" directive. *

* This directive indicates that caches MAY serve the response in which it * appears after it becomes stale, up to the indicated number of seconds. If * a cached response is served stale due to the presence of this extension, * the cache SHOULD attempt to revalidate it while still serving stale * responses (i.e. without blocking). * * @param staleWhileRevalidate * the maximum time the response should be used while being * revalidated * @param unit * the time unit of the {@code staleWhileRevalidate} argument * @return {@code this}, to facilitate method chaining * @see rfc5861 * section 3 */ public CacheControl staleWhileRevalidate(long staleWhileRevalidate, TimeUnit unit) { this.staleWhileRevalidate = unit.toSeconds(staleWhileRevalidate); return this; } /** * Add a "stale-if-error" directive. *

* This directive indicates that when an error is encountered, a cached * stale response MAY be used to satisfy the request, regardless of other * freshness information. * * @param staleIfError * the maximum time the response should be used when errors are * encountered * @param unit * the time unit of the {@code staleIfError} argument * @return {@code this}, to facilitate method chaining * @see rfc5861 * section 4 */ public CacheControl staleIfError(long staleIfError, TimeUnit unit) { this.staleIfError = unit.toSeconds(staleIfError); return this; } /** * Return the "Cache-Control" header value. * * @return {@code null} if no directive was added, or the header value * otherwise */ public String getHeaderValue() { StringBuilder ccValue = new StringBuilder(); if (this.maxAge != -1) { appendDirective(ccValue, "max-age=" + Long.toString(this.maxAge)); } if (this.noCache) { appendDirective(ccValue, "no-cache"); } if (this.noStore) { appendDirective(ccValue, "no-store"); } if (this.mustRevalidate) { appendDirective(ccValue, "must-revalidate"); } if (this.noTransform) { appendDirective(ccValue, "no-transform"); } if (this.cachePublic) { appendDirective(ccValue, "public"); } if (this.cachePrivate) { appendDirective(ccValue, "private"); } if (this.proxyRevalidate) { appendDirective(ccValue, "proxy-revalidate"); } if (this.sMaxAge != -1) { appendDirective(ccValue, "s-maxage=" + Long.toString(this.sMaxAge)); } if (this.staleIfError != -1) { appendDirective(ccValue, "stale-if-error=" + Long.toString(this.staleIfError)); } if (this.staleWhileRevalidate != -1) { appendDirective(ccValue, "stale-while-revalidate=" + Long.toString(this.staleWhileRevalidate)); } String ccHeaderValue = ccValue.toString(); return (StringUtils2.isNoneBlank(ccHeaderValue) ? ccHeaderValue : null); } private void appendDirective(StringBuilder builder, String value) { if (builder.length() > 0) { builder.append(", "); } builder.append(value); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy