Caching page variants
Learn how to set up and use AEM as a cloud service to support caching page variants.
Example use cases
-
Any service provider who is offering a different set of service offerings and corresponding pricing options based on the user’s geo location and the cache of pages with dynamic content should be managed at CDN and Dispatcher.
-
A retail customer has stores across the country and each store has different offers based on where they are located and the cache of pages with dynamic content should be managed at CDN and Dispatcher.
Solution overview
-
Identify the variant key and the number of values it may have. In our example, we vary by US state, so the max number is 50. This is small enough to not cause problems with the variant limits at the CDN. Review variant limitations section.
-
AEM code must set the cookie “x-aem-variant” to the visitor’s preferred state (eg.
Set-Cookie: x-aem-variant=NY
) on the initial HTTP request’s corresponding HTTP response. -
Subsequent requests from the visitor send that cookie (eg.
"Cookie: x-aem-variant=NY"
) and the cookie is transformed at the CDN level into a pre-defined header (i.e.x-aem-variant:NY
) which is passed to the dispatcher. -
An Apache rewrite rule modifies the request path to include the header value in the page URL as an Apache Sling Selector (eg.
/page.variant=NY.html
). This allows AEM Publish to serve different content based on the selector and the dispatcher to cache one page per variant. -
The response sent by AEM Dispatcher must contain an HTTP response header
Vary: x-aem-variant
. This instructs the CDN to store different cache copies for different header values.
HTTP request flow
Usage
-
To demonstrate the feature, we will use WKND’s implementation as an example.
-
Implement a SlingServletFilter in AEM to set
x-aem-variant
cookie on the HTTP response, with a variant value. -
AEM’s CDN automatically transforms
x-aem-variant
cookie into an HTTP header of the same name. -
Add an Apache Web server mod_rewrite rule to your
dispatcher
project, that modifies the request path to include the variant selector. -
Deploy the filter and rewrite rules using Cloud Manager.
-
Test the overall request flow.
Code Samples
-
Sample SlingServletFilter to set
x-aem-variant
cookie with a value in AEM.code language-none package com.adobe.aem.guides.wknd.core.servlets.filters; import javax.servlet.*; import java.io.IOException; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.servlets.annotations.SlingServletFilter; import org.apache.sling.servlets.annotations.SlingServletFilterScope; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Invoke filter on HTTP GET /content/wknd.*.foo|bar.html|json requests. // This code and scope is for example purposes only, and will not interfere with other requests. @Component @SlingServletFilter(scope = {SlingServletFilterScope.REQUEST}, resourceTypes = {"cq:Page"}, pattern = "/content/wknd/.*", extensions = {"html", "json"}, methods = {"GET"}) public class PageVariantFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(PageVariantFilter.class); private static final String VARIANT_COOKIE_NAME = "x-aem-variant"; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) servletResponse; SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) servletRequest; // Check is the variant was previously set final String existingVariant = slingRequest.getCookie(VARIANT_COOKIE_NAME).getValue(); if (existingVariant == null) { // Variant has not been set, so set it now String newVariant = "NY"; // Hard coding as an example, but should be a calculated value slingResponse.setHeader("Set-Cookie", VARIANT_COOKIE_NAME + "=" + newVariant + "; Path=/; HttpOnly; Secure; SameSite=Strict"); log.debug("x-aem-variant cookie is set with the value {}", newVariant); } else { log.debug("x-aem-variant previously set with value {}", existingVariant); } filterChain.doFilter(servletRequest, slingResponse); } @Override public void destroy() { } }
-
Sample Rewrite rule in the dispatcher/src/conf.d/rewrite.rules file which is managed as source code in Git, and deployed using Cloud Manager.
code language-none ... RewriteCond %{REQUEST_URI} ^/us/.* RewriteCond %{HTTP:x-aem-variant} ^.*$ RewriteRule ^([^?]+)\.(html.*)$ /content/wknd$1.variant=%{HTTP:x-aem-variant}.$2 [PT,L] ...
Variant limitations
-
AEM’s CDN can manage up to 200 variations. That means the
x-aem-variant
header can have up to 200 unique values. For more information, review the CDN configuration limits. -
Care must be taken to ensure your chosen variant key never exceeds this number. For instance, a user Id is not a good key as it would easily exceed 200 values for most websites, whereas the states/territories in a country are a better fit if there are less than 200 states in that country.