简介 intro
流量通过CDN传输到Apache Web服务器层,该层支持包括Dispatcher在内的模块。 为了提高性能,Dispatcher主要用作缓存,以限制发布节点上的处理。
可以将规则应用于Dispatcher配置以修改任何默认缓存过期设置,从而在CDN上产生缓存。 在以下情况下,Dispatcher还遵循生成的缓存过期标头: enableTTL
会在Dispatcher配置中启用,这意味着它会在重新发布内容之外刷新特定内容。
本页还介绍了Dispatcher缓存如何失效以及缓存如何在浏览器级别上工作与客户端库有关。
缓存 caching
HTML/文本 html-text
- 默认情况下,浏览器会根据
cache-control
Apache层发出的标头。 CDN也遵循此值。 - HTML可以通过定义
DISABLE_DEFAULT_CACHING
中的变量global.vars
:
Define DISABLE_DEFAULT_CACHING
例如,当您的业务逻辑需要微调页面标头(具有基于日历天的值)时,此方法非常有用,因为默认情况下,页面标头设置为0。 话虽如此, 关闭默认缓存时请务必小心。
-
HTML可以通过定义
EXPIRATION_TIME
中的变量global.vars
使用AEMas a Cloud ServiceSDK Dispatcher工具。 -
可以在更细粒度级别覆盖,包括独立控制CDN和浏览器缓存,并使用以下Apache
mod_headers
指令:code language-none <LocationMatch "^/content/.*\.(html)$"> Header set Cache-Control "max-age=200" Header set Surrogate-Control "max-age=3600" Header set Age 0 </LocationMatch>
note note NOTE Surrogate-Control标头适用于Adobe托管的CDN。 如果使用 客户管理的CDN,根据您的CDN提供商,可能需要不同的标头。 在设置与宽正则表达式匹配的全局缓存控制标头或类似缓存标头时,请务必谨慎,以免将它们应用于必须保持私密的内容。 请考虑使用多个指令,以确保以细粒度应用规则。 这样一来,如果AEMas a Cloud Service检测到缓存标头已应用于它检测到可被Dispatcher不可缓存的内容,则会删除该缓存标头,如Dispatcher文档中所述。 要强制AEM始终应用缓存标头,可以添加
always
选项如下所示:code language-none <LocationMatch "^/content/.*\.(html)$"> Header unset Cache-Control Header unset Expires Header always set Cache-Control "max-age=200" Header set Age 0 </LocationMatch>
确保位于以下位置的文件:
src/conf.dispatcher.d/cache
具有以下规则(默认配置中):code language-none /0000 { /glob "*" /type "allow" }
-
防止缓存特定内容 在CDN,将Cache-Control标头设置为 私有. 例如,以下语句将阻止在名为的目录下存在html内容 secure 从CDN中缓存:
code language-none <LocationMatch "/content/secure/.*\.(html)$">. // replace with the right regex Header unset Cache-Control Header unset Expires Header always set Cache-Control "private" </LocationMatch>
-
虽然未在CDN中缓存设置为私有的HTML内容,但可以在以下情况下在Dispatcher中缓存该内容 权限敏感型缓存 进行配置,确保只能为授权用户提供内容。
note note NOTE 其他方法,包括 Dispatcher-ttl AEM ACS Commons项目,不会成功覆盖值。 note note NOTE Dispatcher仍可能会根据其自身的缓存来缓存内容 缓存规则. 要使内容真正为私有,请确保Dispatcher未缓存该内容。
客户端库(js,css) client-side-libraries
- 使用AEM客户端库框架时,生成JavaScript和CSS代码的方式使得浏览器可以无限期地缓存它,因为任何更改都会显示为具有唯一路径的新文件。 换句话说,会根据需要生成引用客户端库的HTML,以便客户可以在发布新内容时体验这些内容。 对于不遵循“不可变”值的旧版浏览器,缓存控制设置为“不可变”,或者为30天。
- 请参阅部分 客户端库和版本一致性 以了解更多详细信息。
足够大的图像及任何内容可存储在Blob存储中 images
2022年5月中旬之后创建的程序(特别是高于65000的程序ID)的默认行为是默认缓存,同时还要考虑请求的身份验证上下文。 默认情况下,旧版程序(程序ID等于或小于65000)不会缓存Blob内容。
在这两种情况下,都可以通过使用Apache在Apache/Dispatcher层的更细粒度级别覆盖缓存标头 mod_headers
指令,例如:
<LocationMatch "^/content/.*\.(jpeg|jpg)$">
Header set Cache-Control "max-age=222"
Header set Age 0
</LocationMatch>
在Dispatcher层修改缓存标头时,请小心不要缓存太广。 请参阅HTML/文本部分中的讨论 以上. 此外,还应确保原本应保持私有(而非缓存)的资产不属于 LocationMatch
指令过滤器。
AEM通常将存储在Blob存储中的JCR资源(大于16KB)用作302重定向。 截获这些重定向后,CDN将跟随,内容将直接从blob存储中交付。 只能对这些响应自定义有限的一组标头。 例如,要自定义 Content-Disposition
您应按如下方式使用Dispatcher指令:
<LocationMatch "\.(?i:pdf)$">
ForceType application/pdf
Header set Content-Disposition inline
</LocationMatch>
可以在Blob响应中自定义的标头列表包括:
content-security-policy
x-frame-options
x-xss-protection
x-content-type-options
x-robots-tag
access-control-allow-origin
content-disposition
permissions-policy
referrer-policy
x-vhost
content-disposition
cache-control
vary
新的默认缓存行为 new-caching-behavior
AEM层根据是否已设置缓存标头和请求类型的值来设置缓存标头。 如果未设置缓存控制标头,则会缓存公共内容,并且经过身份验证的流量会设置为private。 如果设置了缓存控制标头,则缓存标头保持不变。
虽然不推荐,但可以通过设置Cloud Manager环境变量来更改新的默认行为,以遵循旧行为(程序id等于或小于65000) AEM_BLOB_ENABLE_CACHING_HEADERS
为false。
较旧的默认缓存行为 old-caching-behavior
默认情况下,AEM层不缓存blob内容。
现在,无法使用将Blob存储中标记为私有的图像缓存在调度程序中 权限敏感型缓存. 始终会从AEM源请求图像,并在用户获得授权时提供图像。
节点存储中的其他内容文件类型 other-content
- 无默认缓存
- 不能使用设置默认值
EXPIRATION_TIME
用于html/文本文件类型的变量 - 通过指定适当的正则表达式,可以使用html/text部分中描述的相同LocationMatch策略设置缓存过期时间
进一步优化 further-optimizations
-
避免使用
User-Agent
作为Vary
标题。 旧版本的默认Dispatcher设置(在原型版本28之前)包含该变量,Adobe建议您使用以下步骤将其删除。- 在中找到vhost文件
<Project Root>/dispatcher/src/conf.d/available_vhosts/*.vhost
- 移除或注释掉该行:
Header append Vary User-Agent env=!dont-vary
来自所有vhost文件,但default.vhost是只读的
- 在中找到vhost文件
-
使用
Surrogate-Control
标头,用于独立于浏览器缓存控制CDN缓存 -
考虑应用
stale-while-revalidate
和stale-if-error
指令允许后台刷新并避免缓存丢失,从而让用户能够快速刷新您的内容。- 有许多种方法可以应用这些指令,但添加30分钟即可
stale-while-revalidate
对于所有缓存控制标头来说,这是一个很好的起点。
- 有许多种方法可以应用这些指令,但添加30分钟即可
-
下面是各种内容类型的示例,在设置自己的缓存规则时,可参考这些示例。 请仔细考虑并测试您的特定设置和要求:
-
缓存可变的客户端库资源达12小时,12小时后进行后台刷新。
code language-none <LocationMatch "^/etc\.clientlibs/.*\.(?i:json|png|gif|webp|jpe?g|svg)$"> Header set Cache-Control "max-age=43200,stale-while-revalidate=43200,stale-if-error=43200,public" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
通过后台刷新缓存不可变的客户端库资源长期(30天)以避免丢失。
code language-none <LocationMatch "^/etc\.clientlibs/.*\.(?i:js|css|ttf|woff2)$"> Header set Cache-Control "max-age=2592000,stale-while-revalidate=43200,stale-if-error=43200,public,immutable" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
在浏览器上缓存5分钟HTML页,后台刷新一小时,在CDN上缓存12小时。 将始终添加Cache-Control标头,因此请务必确保在/content/*下与html页面匹配的页面是公共的。 如果不能,请考虑使用更具体的正则表达式。
code language-none <LocationMatch "^/content/.*\.html$"> Header unset Cache-Control Header always set Cache-Control "max-age=300,stale-while-revalidate=3600" "expr=%{REQUEST_STATUS} < 400" Header always set Surrogate-Control "stale-while-revalidate=43200,stale-if-error=43200" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
将内容服务/Sling模型导出程序json响应缓存五分钟,在浏览器上后台刷新一小时,在CDN上后台刷新十二小时。
code language-none <LocationMatch "^/content/.*\.model\.json$"> Header set Cache-Control "max-age=300,stale-while-revalidate=3600" "expr=%{REQUEST_STATUS} < 400" Header set Surrogate-Control "stale-while-revalidate=43200,stale-if-error=43200" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
通过后台刷新来缓存核心图像组件中的不可变URL,以使其保持长期(30天)不变,从而避免MISS。
code language-none <LocationMatch "^/content/.*\.coreimg.*\.(?i:jpe?g|png|gif|svg)$"> Header set Cache-Control "max-age=2592000,stale-while-revalidate=43200,stale-if-error=43200,public,immutable" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
将来自DAM的可变资源(如图像和视频)缓存24小时,并在12小时后进行后台刷新以避免遗漏。
code language-none <LocationMatch "^/content/dam/.*\.(?i:jpe?g|gif|js|mov|mp4|png|svg|txt|zip|ico|webp|pdf)$"> Header set Cache-Control "max-age=43200,stale-while-revalidate=43200,stale-if-error=43200" "expr=%{REQUEST_STATUS} < 400" Header set Age 0 </LocationMatch>
-
分析CDN缓存命中率 analyze-chr
请参阅 缓存命中率分析教程 有关使用仪表板下载CDN日志和分析网站缓存命中率的信息。
HEAD请求行为 request-behavior
当在AdobeCDN收到针对以下资源的HEAD请求时 非 缓存后,该请求将进行转换,并作为GET请求由Dispatcher和/或AEM实例接收。 如果响应可缓存,则从CDN提供后续HEAD请求。 如果响应不可缓存,则后续HEAD请求将在一段时间内传递给Dispatcher或AEM实例,或者同时传递到两者,具体时间取决于 Cache-Control
总计
营销活动参数 marketing-parameters
网站URL通常包括用于跟踪营销活动成功的营销活动参数。
对于在2023年10月或之后创建的环境,为了更好地缓存请求,CDN将删除与营销相关的常见查询参数,特别是与以下正则表达式模式匹配的参数:
^(utm_.*|gclid|gdftrk|_ga|mc_.*|trk_.*|dm_i|_ke|sc_.*|fbclid)$
如果您希望禁用此行为,请提交支持票证。
对于在2023年10月之前创建的环境,建议配置Dispatcher配置的 ignoreUrlParams
属性为 此处记录.
忽略营销参数有两种可能性。 (其中首选方法是通过查询参数忽略缓存无效):
- 忽略所有参数并选择性地允许使用的参数。
仅在以下示例中page
和product
不会忽略参数,请求将转发到发布者。
/ignoreUrlParams {
/0001 { /glob "*" /type "allow" }
/0002 { /glob "page" /type "deny" }
/0003 { /glob "product" /type "deny" }
}
- 允许除营销参数之外的所有参数。 文件 marketing_query_parameters.any 定义将忽略的常用营销参数的列表。 Adobe不会更新此文件。 用户可以对其进行扩展,具体取决于其营销提供商。
/ignoreUrlParams {
/0001 { /glob "*" /type "deny" }
$include "../cache/marketing_query_parameters.any"
}
Dispatcher缓存失效 disp
通常,无需使Dispatcher缓存失效。 相反,您应该依赖Dispatcher在重新发布内容时刷新其缓存,并且CDN遵循缓存过期标头。
Dispatcher缓存在激活/停用期间失效 cache-activation-deactivation
与以前版本的AEM一样,发布或取消发布页面会从Dispatcher缓存中清除内容。 如果怀疑存在缓存问题,应重新发布有问题的页面,并确保有可用的虚拟主机与 ServerAlias
Dispatcher缓存失效所需的localhost。
当发布实例从作者那里收到新版本的页面或资产时,它使用刷新代理使其Dispatcher上的相应路径失效。 更新的路径及其父级一起从Dispatcher缓存中删除,最多可达到一个级别(您可以使用 statfileslevel)。
明确使Dispatcher缓存失效 explicit-invalidation
Adobe建议您依赖标准缓存标头来控制内容交付生命周期。 但是,如果需要,可以直接使Dispatcher中的内容失效。
以下列表包含可能想要显式使缓存失效的情况(同时可以选择侦听失效的完成):
- 发布体验片段或内容片段等内容后,使引用这些元素的已发布和缓存的内容失效。
- 在引用的页面成功失效时通知外部系统。
有两种方法可明确使缓存失效:
- 首选方法是使用Author的Sling内容分发(SCD)。
- 另一种方法是使用复制API调用发布Dispatcher刷新复制代理。
这些方法在层可用性、消除重复事件的能力和事件处理保障方面有所不同。 下表总结了这些选项:
与缓存失效直接相关的两个操作是Sling内容分发(SCD) API失效和复制API停用。
此外,从表中可以看到:
-
当必须保证每个事件时(例如,与需要准确知识的外部系统同步),需要SCD API。 如果在失效调用时存在发布层升级事件,则当每个新发布处理失效时,将引发一个额外事件。
-
使用复制API不是常见用例,但可用于以下情况:使缓存失效的触发器来自发布层,而不是创作层。 如果配置了Dispatcher TTL,此方法可能很有用。
总之,如果您希望使Dispatcher缓存失效,则推荐的选项是使用来自创作实例的SCD API失效操作。 此外,您还可以监听事件,以便随后触发后续操作。
Sling内容分发(SCD) sling-distribution
使用来自创作实例的SCD操作时,实施模式如下所示:
- 在作者中,编写自定义代码以调用sling内容分发 API,使用路径列表传递失效操作:
@Reference
private Distributor distributor;
ResourceResolver resolver = ...; // the resource resolver used for authorizing the request
String agentName = "publish"; // the name of the agent used to distribute the request
String pathToInvalidate = "/content/to/invalidate";
DistributionRequest distributionRequest = new SimpleDistributionRequest(DistributionRequestType.INVALIDATE, false, pathToInvalidate);
distributor.distribute(agentName, resolver, distributionRequest);
- (可选)侦听一个事件,该事件反映所有Dispatcher实例正在失效的资源:
package org.apache.sling.distribution.journal.shared;
import org.apache.sling.discovery.DiscoveryService;
import org.apache.sling.distribution.journal.impl.event.DistributionEvent;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.sling.distribution.DistributionRequestType.INVALIDATE;
import static org.apache.sling.distribution.event.DistributionEventProperties.DISTRIBUTION_PATHS;
import static org.apache.sling.distribution.event.DistributionEventProperties.DISTRIBUTION_TYPE;
import static org.apache.sling.distribution.event.DistributionEventTopics.AGENT_PACKAGE_DISTRIBUTED;
import static org.osgi.service.event.EventConstants.EVENT_TOPIC;
@Component(immediate = true, service = EventHandler.class, property = {
EVENT_TOPIC + "=" + AGENT_PACKAGE_DISTRIBUTED
})
public class InvalidatedHandler implements EventHandler {
private static final Logger LOG = LoggerFactory.getLogger(InvalidatedHandler.class);
@Reference
private DiscoveryService discoveryService;
@Override
public void handleEvent(Event event) {
String distributionType = (String) event.getProperty(DISTRIBUTION_TYPE);
if (INVALIDATE.name().equals(distributionType)) {
boolean isLeader = discoveryService.getTopology().getLocalInstance().isLeader();
// process the OSGi event on the leader author instance
if (isLeader) {
String[] paths = (String[]) event.getProperty(DISTRIBUTION_PATHS);
String packageId = (String) event.getProperty(DistributionEvent.PACKAGE_ID);
invalidated(paths, packageId);
}
}
}
private void invalidated(String[] paths, String packageId) {
// custom logic
LOG.info("Successfully applied package with id {}, paths {}", packageId, paths);
}
}
- (可选)在中执行业务逻辑
invalidated(String[] paths, String packageId)
方法。
复制 API replication-api
下面显示了使用复制API停用操作时的实施模式:
- 在发布层上,调用复制API以触发发布Dispatcher刷新复制代理。
刷新代理端点不可配置,而是预配置为指向Dispatcher,与随刷新代理运行的发布服务匹配。
刷新代理通常可以由基于OSGi事件或工作流的自定义代码触发。
String[] paths = …
ReplicationOptions options = new ReplicationOptions();
options.setSynchronous(true);
options.setFilter( new AgentFilter {
public boolean isIncluded (Agent agent) {
return agent.getId().equals("flush");
}
});
Replicator.replicate (session,ReplicationActionType.DELETE,paths, options);
客户端库和版本一致性 content-consistency
页面由HTML、JavaScript、CSS和图像组成。 我们鼓励客户使用 客户端库(clientlibs)框架 要将JavaScript和CSS资源导入HTML页,请考虑JS库之间的依赖关系。
clientlibs框架提供自动版本管理。 这意味着开发人员可以在源代码管理中检查对JS库的更改,并且在客户推送其版本时提供最新版本。 如果没有此工作流,开发人员必须手动更改引用库新版本的HTML,如果同一库共享许多HTML模板,则更改操作会非常繁重。
将库的新版本发布到生产环境后,将会更新引用HTML页面,并包含指向这些已更新库版本的新链接。 在给定HTML页面的浏览器缓存过期后,无需担心旧库会从浏览器缓存中加载。 原因是现在,刷新页面(来自AEM)必定会引用库的新版本。 即,刷新的HTML页面包含所有最新库版本。
这种能力背后的机制是序列化哈希,该哈希会附加到客户端库链接中。 它确保浏览器拥有唯一的版本化URL来缓存CSS/JS。 仅当客户端库的内容更改时,才会更新序列化哈希。 这意味着即使进行了新部署,如果发生不相关的更新(即不更改客户端库的基础css/js),引用将保持不变。 反过来,它可以确保减少浏览器缓存的中断。
启用客户端库的Longcache版本 — AEMas a Cloud Service开发工具包快速入门 enabling-longcache
HTML页面上默认的clientlib include类似于以下示例:
<link rel="stylesheet" href="/etc.clientlibs/wkndapp/clientlibs/clientlib-base.css" type="text/css">
启用严格的clientlib版本控制后,会向客户端库添加一个长期哈希键作为选择器。 因此,clientlib引用如下所示:
<link rel="stylesheet" href="/etc.clientlibs/wkndapp/clientlibs/clientlib-base.lc-7c8c5d228445ff48ab49a8e3c865c562-lc.css" type="text/css">
默认情况下,所有AEMas a Cloud Service环境中都启用严格的clientlib版本控制。
要在本地SDK快速入门中启用严格的clientlib版本控制,请执行以下操作:
-
导航到OSGi配置管理器
<host>/system/console/configMgr
-
查找AdobeGraniteHTML库管理器的OSGi配置:
- 选中复选框,以便启用严格版本控制
- 在标记为的字段中 长期客户端缓存密钥,输入值/。*;哈希
-
保存更改。 无需在源代码管理中保存此配置,因为AEMas a Cloud Service会自动在开发、暂存和生产环境中启用此配置。
-
无论何时改变客户端库的内容,都生成新的散列密钥并更新HTML引用。