第1章 — Dispatcher概念、模式和反模式

概覽

本章簡要介紹了Dispatcher的歷史和機制,並討論了這對開發人員設計其元件AEM的方式有何影響。

開發商為何應該關心基礎架構

Dispatcher是大多數安裝(如果不是所有安裝)中必不可少AEM的部分。 您可以找到許多線上文章,討論如何配置Dispatcher以及提示和技巧。

但是,這些細節資訊總是從非常技術性的層面開始 — 假定您已經知道自己想做什麼,因此只提供有關如何實現自己想要的細節。 我們從未發現任何描述 是什麼,為什麼 是指您可以和不能對調度程式執行的操作。

反圖案:Dispatcher作為事後思考

由於缺乏基本資訊,我們在一些項目中看到了一些反AEM模式:

  1. 由於Dispatcher安裝在Apache Web伺服器中,因此在項目中配置它是「Unix gods」的作業。 "凡人的java開發者"不必關心它。

  2. Java開發人員需要確保他的代碼工作……以後調度員會神奇地快速完成。 調度員總是事後考慮。 但是,這並不奏效。 開發人員必須在設計代碼時考慮到調度員。 他需要知道它的基本概念來做到。

「先讓它起作用 — 然後讓它快速起作用」並非總是正確的

你可能聽過寫程式建議 「首先讓它起作用,然後讓它迅速起作用。」. 這並非完全錯誤。 但是,如果沒有適當的上下文,則往往被誤解和不正確應用。

建議應防止開發人員過早地優化代碼,因為代碼可能永遠不會運行,或者很少運行,因此優化不會產生足夠的效果來證明投入優化的努力是合理的。 此外,優化還會導致代碼更複雜,從而引入錯誤。 所以,如果你是開發者,不要花太多時間去微優化每一行代碼。 只需確保您選擇了正確的資料結構、算法和庫,並等待Profiler的熱點分析,以瞭解更徹底的優化可以提高整體效能。

建築決策與文物

然而,「先讓它起作用 — 然後讓它迅速起作用」的建議在「建築」決策方面完全是錯誤的。 什麼是建築決策? 簡言之,這些決策成本高、難度大,而且/或是以後不可能改變。 請記住,"昂貴"有時與"不可能"相同。 例如,當項目預算不足時,無法實施昂貴的更改。 基礎設施的改變是大多數人腦中第一種改變。 但還有另一種「建築」藝術品,它們可能變得非常難以改變:

  1. 應用程式「中心」中的代碼片段,而許多其他元件都依賴於這些代碼片段。 更改這些依賴項時,需要立即更改並重新測試所有依賴項。

  2. 在一些非同步、與時間相關的場景中涉及的偽像,在這些場景中,輸入 — 因此系統的行為可能會非常隨機地變化。 變化可能產生不可預知的效果,而且很難test。

  3. 在系統的所有部件中反複使用和重新使用的軟體模式。 如果軟體模式被證明為次優,則需要重新編碼使用該模式的所有偽像。

記憶? 在本頁的頂部,我們說, Dispatcher是應用程式的重要部AEM分。 訪問Web應用程式是非常隨機的 — 用戶在不可預知的時間來來去。 最後,所有內容都將(或應該)快取到Dispatcher中。 因此,如果你密切注意,你可能已經意識到,快取可以被看作一種「建築」工件,因此應該被團隊的所有成員、開發人員和管理員所理解。

我們不是說開發人員應該實際配置Dispatcher。 他們需要瞭解這些概念 — 特別是邊界 — 以確保他們的代碼也能被調度程式利用。

Dispatcher不會神奇地提高代碼的速度。 開發人員需要在建立元件時考慮Dispatcher。 因此,他需要知道它是如何運作的。

Dispatcher快取 — 基本原則

Dispatcher as Caching Http — 負載平衡器

什麼是Dispatcher ,它最初為什麼稱為「Dispatcher」?

調度程式

  • 首先也是最重要的是快取

  • 反向代理

  • Apache httpd webserver的模組,為AEMApache的通用性添加相關功能,並與所有其他Apache模組(如稍後將看到的SSL甚至SSI)一起平穩地工作

在網路的早期,你可以期待有幾百個訪問者訪問一個網站。 一個Dispatcher的設定,即「已調度」或平衡了對多個發佈伺服器的請求AEM的負載,這通常就足夠了,因此稱為「Dispatcher」。 但是現在這個裝置已經不常用了。

本文稍後將看到不同的調度器和發佈系統設定方法。 首先,讓我們從一些http快取基礎知識開始。

Dispatcher快取的基本功能

Dispatcher快取的基本功能


此處說明了調度程式的基本資訊。 調度程式是一個簡單的快取反向代理,能夠接收和建立HTTP請求。 正常的請求/響應週期如下:

  1. 用戶請求頁面
  2. Dispatcher將檢查(如果它已具有該頁的已呈現版本)。 假設這是此頁的第一個請求,而Dispatcher找不到本地快取副本。
  3. Dispatcher從發佈系統請求該頁
  4. 在「發佈」系統中,頁面由JSP或HTL模板呈現
  5. 該頁將返回給Dispatcher
  6. Dispatcher將快取該頁
  7. Dispatcher將頁面返回到瀏覽器
  8. 如果再次請求同一頁,則無需在發佈實例上重新呈現該頁,即可直接從Dispatcher快取中提供該頁。 這可節省Publish實例上用戶和CPU週期的等待時間。

我們在最後一節討論"頁面" 但同樣的方案也適用於其他資源,如影像、CSS檔案、PDF下載等。

資料如何快取

Dispatcher模組利用托管Apache伺服器提供的設施。 資源(如HTML頁、下載和圖片)作為簡單檔案儲存在Apache檔案系統中。 就這麼簡單。

檔案名由所請求資源的URL派生。 如果您請求檔案 /foo/bar.html 它儲存在例如/var/cache/docroot/foo/bar.html

原則上,如果所有檔案都被快取並因此靜態儲存在Dispatcher中,則可以拔出Publish系統的插件,而Dispatcher將充當簡單的Web伺服器。 但這只是說明了原則。 現實生活更複雜。 您無法快取所有內容,而且由於渲染過程的動態性質,資源數量可能是無限的,因此快取永遠不會完全「完全」。 靜態檔案系統的模型有助於生成調度程式功能的粗略圖片。 它有助於解釋調度程式的局限性。

URL結AEM構與檔案系統映射

要更詳細地瞭解Dispatcher ,讓我們重新查看簡單示例URL的結構。 讓我們看下面的例子,

http://domain.com/path/to/resource/pagename.selectors.html/path/suffix.ext?parameter=value&otherparameter=value#fragment

  • http 表示協定

  • domain.com 是域名

  • path/to/resource 是資源儲存在CRX中的路徑,隨後儲存在Apache伺服器的檔案系統中

從這裡看,檔案系統和Apache文AEM件系統之間的情況有些不同。

在AEM,

  • pagename 是資源標籤

  • selectors 表示Sling中使用的多個選擇器,以確定資源的呈現方式。 URL可以具有任意數目的選擇器。 他們被隔一段時間。 例如,選擇器節可能類似於"french.mobile.fancy"。 選擇器應僅包含字母、數字和短划線。

  • html 作為「選擇器」的最後一個,稱為擴展。 在AEM/Sling中,它也部分地確定了渲染指令碼。

  • path/suffix.ext 是類路徑表達式,可以是URL的尾碼。 它可用於腳AEM本中,以進一步控制資源的呈現方式。 我們稍後將提供有關此部分的整節。 目前,只需知道您可以將其用作附加參數即可。 尾碼必須具有副檔名。

  • ?parameter=value&otherparameter=value 是URL的查詢節。 它用於將任意參數傳遞給AEM。 無法快取帶參數的URL,因此參數應限於絕對必要的情況。

  • #fragment,URL的片段部分沒有傳遞給它AEM,只在瀏覽器中使用;在JavaScript框架中作為「路由參數」或跳轉到頁面上的某個部分。

在Apache中(參考下圖)

  • pagename.selectors.html 用作快取檔案系統中的檔案名。

如果URL具有尾碼 path/suffix.ext 那麼,

  • pagename.selectors.html 建立為資料夾

  • path 資料夾 pagename.selectors.html 資料夾

  • suffix.extpath 的子菜單。 注:如果尾碼沒有副檔名,則不快取該檔案。

從Dispatcher獲取URL後的檔案系統佈局

從Dispatcher獲取URL後的檔案系統佈局


基本限制

URL、資源和檔案名之間的映射非常簡單。

你可能注意到一些陷阱,

  1. URL可能變長。 添加路徑部分 /docroot 本地檔案系統上的檔案系統可能會輕鬆超過某些檔案系統的限制。 在Windows上的NTFS中運行Dispatcher可能是個難題。 但是, Linux是安全的。

  2. URL可以包含特殊字元和摘要。 這通常不是調度程式的問題。 但請記住,URL在應用程式的許多位置都被解釋。 我們經常看到應用程式的奇怪行為 — 只是為了發現一個很少使用的(自定義)代碼沒有經過針對特殊字元的徹底測試。 如果可以的話,你應該避開他們。 如果你做不到,就計畫徹底測試。

  3. 在CRX中,資源具有子資源。 例如,一個頁面將包含多個子頁面。 檔案系統中無法匹配此項,因為檔案系統具有檔案或資料夾。

未快取沒有副檔名的URL

URL始終必須具有副檔名。 雖然您可以在中提供沒有副檔名的URLAEM。 這些URL將不會快取在Dispatcher中。

示例

http://domain.com/home.html快取

http://domain.com/home無法快取

當URL包含尾碼時,同樣的規則也適用。 尾碼需要有可快取的擴展。

示例

http://domain.com/home.html/path/suffix.html快取

http://domain.com/home.html/path/suffix無法快取

你也許會問,如果資源部分沒有副檔名,但尾碼有一個,會發生什麼? 那麼,在這種情況下,URL根本沒有尾碼。 看下一個示例:

範例

http://domain.com/home/path/suffix.ext

/home/path/suffix 是資源的路徑……因此URL中沒有尾碼。

結論

始終向路徑和尾碼添加擴展。 瞭解SEO的人有時會說,這會讓你在搜索結果中排名靠後。 但是,一個未被開啟的頁面會非常緩慢,排名會更低。

衝突的尾碼URL

考慮您有兩個有效的URL

http://domain.com/home.html

http://domain.com/home.html/suffix.html

這在里絕對有效AEM。 您不會在本地開發電腦上看到任何問題(沒有Dispatcher)。 在UAT或負載測試中,您很可能也不會遇到任何問題。 我們面臨的問題非常微妙,以至於它在大多數test中溜走了。 當您處於高峰時段時,它會給您帶來沈重的打擊,並且您的解決時間會受到限制,可能沒有伺服器訪問權限,也沒有修復它的資源。 我們去過那裡……

所以……什麼問題?

home.html 檔案系統中可以是檔案或資料夾。 不是同時發AEM生。

如果您請求 home.html 首先,將建立為檔案。

後續請求 home.html/suffix.html 返回有效結果,但作為檔案 home.html "阻止"檔案系統中的位置, home.html 無法再次建立為資料夾,因此 home.html/suffix.html 未快取。

檔案系統中的檔案阻止位置阻止子資源被快取

檔案系統中的檔案阻止位置阻止子資源被快取


如果你反過來,首先請求 home.html/suffix.html 然後 suffix.html 快取在資料夾下 /home.html 一開始。 但是,此資料夾將被刪除並替換為檔案 home.html 當以後 home.html 作為資源。

將父項作為資源讀取時刪除路徑結構

將父項作為資源讀取時刪除路徑結構


因此,快取結果完全是隨機的,取決於傳入請求的順序。 更棘手的是,你通常有不止一個調度員。 而且,效能、快取命中率和行為可能會因調度程式的不同而有所不同。 如果要瞭解您的網站為什麼沒有響應,您需要確保查看的是正確的Dispatcher,快取順序不正確。 如果您在查看Dispatcher ,但幸運的是,它的請求模式更為有利,您將迷失於尋找問題。

避免衝突的URL

當您為資源使用不同的副檔名(具有尾碼)時,可以避免「衝突的URL」,即資料夾名稱和檔案名「競爭」檔案系統中的相同路徑。

範例

  • http://domain.com/home.html

  • http://domain.com/home.dir/suffix.html

兩者都完全可快取,

請求尾碼或避免完全使用尾碼時,為資源選擇專用擴展「dir」。 在很少的例子中,它們有用。 而且很容易正確地實施這些案例。 正如我們在下一章中討論快取失效和刷新時看到的。

無法處理的請求

讓我們回顧一下最後一章的簡短摘要,以及一些其他例外。 如果URL被配置為可快取,並且是GET請求,則Dispatcher可以快取它。 無法在以下異常之一下快取它。

可快取請求

  • 請求配置為在Dispatcher配置中可快取
  • 請求是純GET請求

不可快取的請求或響應

  • 按配置拒絕快取的請求(路徑、模式、MIME類型)
  • 返回「 Dispatcher:無快取"標頭
  • 返回「Cache-Control:無快取|私有」標頭
  • 返回「Pragma:無快取"標頭
  • 具有查詢參數的請求
  • 無副檔名的URL
  • 帶尾碼且沒有副檔名的URL
  • 返回200以外的狀態代碼的響應
  • POST請求

取消驗證和刷新快取

概覽

最後一章列出了Dispatcher無法快取請求時的大量異常。 但還有更多事情需要考慮:就因為調度員 快取請求,這不一定意味著 應該

重點是:快取通常很容易。 Dispatcher只需儲存響應的結果,並在下次傳入完全相同的請求時返回。 右? 錯!

難的是 失效 快取。 Dispatcher需要查明資源發生更改時的情況,並需要重新呈現。

乍一看,這似乎是件微不足道的事……但事實並非如此。 進一步閱讀,您會發現單個資源和簡單資源以及依賴高度網狀結構的多個資源的頁面之間有一些棘手的區別。

簡單資源和刷新

我們已設定系統AEM,以在使用特殊的「拇指」選擇器請求時為每個影像動態建立縮略圖格式副本:

/content/dam/path/to/image.thumb.png

當然,我們還提供一個URL,用一個無選擇器的URL為原始影像服務:

/content/dam/path/to/image.png

如果我們同時下載縮略圖和原始影像,最後會出現,

/var/cache/dispatcher/docroot/content/dam/path/to/image.thumb.png

/var/cache/dispatcher/docroot/content/dam/path/to/image.png

在Dispatcher的檔案系統中。

現在,用戶將上載並激活該檔案的新版本。 最終,失效請求從調度AEM器發送,

GET /invalidate
invalidate-path:  /content/dam/path/to/image

<no body>

失效很簡單:對調度程式上的特殊「/無效」URL的簡單GET請求。 不需要HTTP-body,「payload」只是「invalidate-path」標頭。 另請注意,報頭中的無效路徑是知道的資源,AEM而不是Dispatcher快取的檔案或檔案。 只AEM知道資源。 請求資源時,運行時會使用擴展、選擇器和尾碼。 不AEM會執行任何關於資源上使用了哪些選擇器的記帳,因此在激活資源時,資源路徑是它所確信的全部。

就我們而言,這就足夠了。 如果某個資源已更改,我們可以安全地假設該資源的所有格式副本也已更改。 在本例中,如果影像已更改,則還會呈現新的縮略圖。

Dispatcher可以安全地刪除資源及其已快取的所有格式副本。 它會起到類似的作用,

$ rm /content/dam/path/to/image.*

刪除 image.pngimage.thumb.png 和所有與該模式匹配的格式副本。

非常簡單……只要您只使用一個資源來響應請求。

參照和網格化內容

網格化內容問題

與上傳到的影像或其他二進位檔案相AEM比,HTML頁面不是孤獨的動物。 他們生活在群居中,他們通過超連結和引用彼此高度相互聯繫。 簡單的連結是無害的,但當我們談論內容引用時,它會變得棘手。 頁面上無處不在的頂部導航或預告是內容引用。

內容引用及其原因

讓我們來看一個簡單的例子。 一家旅行社的網頁上宣傳去加拿大旅遊。 此促銷活動在另外兩頁的預告部分、「首頁」頁和「冬季特別計畫」頁中進行。

由於兩頁都顯示相同的預告,因此不必要求作者為應顯示的每頁建立預告多次時間。 相反,目標頁面「加拿大」保留頁面屬性中的一個部分,以提供預告資訊,或者最好提供呈現該預告的URL:

<sling:include resource="/content/home/destinations/canada" addSelectors="teaser" />

<sling:include resource="/content/home/destinations/canada/jcr:content/teaser" />

僅AEM在這個實例上,它就像魅力一樣,但如果在「發佈」實例上使用Dispatcher,就會發生奇怪的情況。

想像一下,你已經發佈了你的網站。 您的加拿大頁上的標題是「加拿大」。 當訪問者請求您的首頁時,「加拿大」頁面上的元件會呈現類似的內容

<div class="teaser">
  <h3>Canada</h3>
  <img …>
</div>

首頁。 首頁由Dispatcher儲存為靜態.html檔案,包括預告和該首頁的標題。

現在,營銷人員已經明白,「誘惑」標題應該是可操作的。 於是,他決定把標題從"加拿大"改為"訪問加拿大",並更新圖片。

他出版編輯後的「加拿大」頁面,並重新訪問先前發佈的首頁,以查看他的更改。 但是,那裡沒什麼變化。 它仍然顯示舊的預告。 他兩次檢查《冬日特別》。 以前從未請求過該頁,因此不會在Dispatcher中靜態快取該頁。 因此,本頁由Publish新呈現,此頁現在包含新的「訪問加拿大」預告。

在首頁中儲存陳舊包含內容的調度程式

在首頁中儲存陳舊包含內容的調度程式


怎麼回事? Dispatcher儲存頁面的靜態版本,該頁面包含在呈現時從其他資源中繪製的所有內容和標籤。

Dispatcher只是一個基於檔案系統的Web伺服器,速度快,但也相對簡單。 如果包含的資源發生更改,它不會意識到這一點。 它仍然會與呈現包含頁時的內容保持關聯。

「冬季特殊」頁尚未呈現,因此Dispatcher上沒有靜態版本,因此將隨新預告一起顯示,因為新預告將在請求時重新呈現。

您可能認為,當資源發生更改時, Dispatcher將跟蹤它所觸及的每個資源,同時呈現和刷新已使用此資源的所有頁。 但Dispatcher不會呈現這些頁。 呈現由發佈系統執行。 調度程式不知道哪些資源會進入呈現的.html檔案中。

還不信嗎? 你可能認為 「必須有一種方法來實現某種依賴性跟蹤」。 有,或者更準確地說 。 公報三,曾曾祖父在2012年12月AEM1日 會話 用於呈現頁面。

在請求期間,通過此會話獲取的每個資源都被跟蹤為當前正在呈現的URL的依賴項。

但事實證明,追蹤這些依賴項非常昂貴。 人們很快發現,如果完全關閉依賴項跟蹤功能,並依賴於在更改一個html頁面後重新呈現所有html頁面,網站的速度會更快。 此外,這個計畫也並不完美 — 在路上有許多陷阱和例外。 在某些情況下,您沒有使用請求預設會話來獲取資源,而是使用管理會話來獲取一些幫助資源來呈現請求。 這些依賴項通常沒有被跟蹤,並導致頭痛,並致電ops-team要求手動刷新快取。 你很幸運,如果他們有標準程式。 路上還有很多人在追我,但是……別再回憶了。 這可以追溯到2005年。 最終,這一特徵在第四公報中被預設取消,但並沒有讓它回到後來的第五號公報AEM中。

自動失效

當完全刷新比依賴項跟蹤更便宜時

由於CQ5,因此我們完全依賴於在只更改其中一個頁面時使整個站點失效。 此功能稱為「自動失效」。

但是,拋棄並重繪數百頁,比進行適當的依賴性跟蹤和部分重繪要便宜得多,這怎麼可能?

原因有二:

  1. 在普通網站上,只經常請求頁面的一小部分。 因此,即使你扔掉所有已呈現的內容,事後實際上也只會要求幾打。 當實際請求頁面時,長尾頁的呈現可以隨時間分佈。 實際上,渲染頁面的負載沒有你預期的那麼高。 當然,總有例外……我們稍後將討論一些技巧,如何在具有空Dispatcher快取的較大網站上處理均勻分佈的負載。

  2. 所有頁面仍由主導航連接。 所以幾乎所有的頁面最終都是互相依賴的。 這意味著,即便是最聰明的依賴關係跟蹤者也會發現我們已經知道的:如果其中一個頁面發生更改,則必須使其他所有頁面失效。

你不相信? 讓我們來說明最後一點。

我們使用的參數與上一個示例中的參數相同,預告引用遠程頁面的內容。 直到現在,我們才用了一個更極端的例子:自動呈現主導航。 與預告一樣,導航標題從連結或「遠程」頁面中提取為內容引用。 遠程導航標題未儲存在當前呈現的頁面中。 您應該記住,導航是在您網站的每個頁面上呈現的。 因此,一個頁面的標題在所有具有主導航的頁面上反複使用。 如果要更改導航標題,則只要在遠程頁面上執行一次,而不是在引用該頁面的每個頁面上執行一次。

因此,在本例中,導航使用目標頁的「NavTitle」在導航中呈現名稱,從而將所有頁面網格化在一起。 "冰島"的導航標題從"冰島"頁中提取,並呈現到具有主導航的每一頁。

主導航通過拉動其「NavTitles」不可避免地將所有頁面的內容相互嚙合

主導航通過拉動其「NavTitles」不可避免地將所有頁面的內容相互嚙合


如果您將冰島頁面上的NavTitle從「冰島」更改為「美麗的冰島」,則標題會立即在所有其他頁面主菜單上更改。 因此,在更改之前呈現和快取的頁面都變得陳舊,需要使其失效。

如何實現自動失效:.stat檔案

現在,如果您有一個擁有數千頁的大型網站,則需要相當長的時間來循環瀏覽所有頁面並實際刪除這些頁面。 在此期間, Dispatcher可能會無意中提供陳舊內容。 更糟的是,在訪問快取檔案時可能會發生一些衝突,可能是在頁面剛剛被刪除時請求,或者由於立即進行後續激活後發生的第二次無效而再次刪除頁面。 想想會有多糟。 幸運的是,事情並非如此。 Dispatcher使用一種巧妙的技巧來避免這種情況:它不會刪除成百上千個檔案,而是在發佈檔案時將一個簡單的空檔案放入檔案系統的根目錄中,因此所有相關檔案都被視為無效。 此檔案稱為「statfile」。 statfile是空檔案 — 關於statfile的關鍵是其建立日期。

調度程式中建立日期早於statfile的所有檔案在上次激活(和無效)之前都已呈現,因此被視為「無效」。 它們仍然在檔案系統中實際存在,但Dispatcher忽略它們。 它們「過時」。 每當向過時資源發出請求時,Dispatcher會要求AEM系統重新呈現頁面。 然後,新呈現的頁面將儲存在檔案系統中 — 現在具有新的建立日期,並且該頁面再次刷新。

.stat檔案的建立日期定義哪些內容已過時和哪些內容新鮮

.stat檔案的建立日期定義哪些內容已過時和哪些內容新鮮


你可能會問它為什麼叫"。stat"? 也許不是"無效"? 您可以想像,將該檔案放在您的檔案系統中有助於Dispatcher確定哪些資源可以 靜態 服務 — 就像從靜態Web伺服器中一樣。 這些檔案不再需要動態呈現。

然而,這個名字的真正本質並不是暗喻。 它源於Unix系統調用 stat(),它返回檔案的修改時間(除其他屬性外)。

混合簡單驗證和自動驗證

但等等……之前我們說過,單個資源被物理刪除。 現在,我們說,在Dispatcher眼中,一個更新的靜態檔案實際上會使這些檔案無效。 那麼,為什麼首先刪除物理內容?

答案很簡單。 您通常並行使用這兩種策略,但是對於不同的資源。 二進位資產,如影像是自包含的。 它們與其他資源之間沒有聯繫,因為它們需要提供其資訊。

而HTML頁面則高度相互依存。 所以,你會對這些應用自動失效。 這是Dispatcher中的預設設定。 屬於無效資源的所有檔案都被物理刪除。 此外,以"。html"結尾的檔案會自動失效。

調度程式決定是否應用自動無效方案。

可配置用於自動失效的檔案結尾。 理論上,可以包括自動失效的所有擴展。 但請記住,這是一個非常高的代價。 您不會無意中看到已交付的陳舊資源,但交付效能會因過度失效而嚴重降級。

例如,假設您實施了一種方案,其中PNG和JPG是動態呈現的,並且依賴於其他資源來實現。 您可能希望將高解析度影像重新縮放到更小的Web相容解析度。 在它的同時,還會更改壓縮率。 本示例中的解析度和壓縮率不是固定常數,而是使用影像的元件中的可配置參數。 現在,如果更改了此參數,則需要使影像無效。

沒問題 — 我們剛剛瞭解到,我們可以將影像添加到自動失效中,並始終在發生任何更改時提供新渲染的影像。

把嬰兒和洗澡水一起扔掉

沒錯,這是個大問題。 再讀一遍最後一段。 "。…只要有任何變化,就新渲染影像。" 正如你所知,一個好網站會不斷變化;在此處添加新內容,在此處更正拼寫錯誤,在其他位置調整預告。 這意味著您的所有影像都會不斷失效,需要重新渲染。 別小看。 在本地開發電腦上動態呈現和傳輸影像資料的工作時間(毫秒)。 您的生產環境需要更頻繁地執行此操作 — 每秒。

在這裡,我們要清楚,當html頁面發生更改時,需要重新呈現您的jpg。 只有一個檔案「儲存桶」可自動失效。 整體衝了一下。 沒有辦法細細分。

預設情況下,自動失效保持為「.html」有充分的理由。 目標是盡可能小。 不要把嬰兒和洗澡水一起扔掉,只是讓一切都變得無效 — 只是為了在安全的一邊。

應在該資源的路徑上提供自給自足的資源。 這對失效有很大幫助。 保持簡單,不要建立映射方案,如「resource /a/b/c」是從「/x/y/z」提供的。 使您的元件使用預設的Dispatcher自動失效設定。 不要嘗試修復Dispatcher中設計不當且失效過度的元件。

自動失效例外:僅資源失效

Dispatcher的無效請求通常由複製代理從發佈系統觸發。

如果您對依賴關係非常有信心,可以嘗試構建自己的無效複製代理。

要詳細說明,本指南可能有些不足,但我們想至少給您一些提示。

  1. 真的知道你在做什麼。 要正確處理失效是非常困難的。 這就是自動失效如此嚴格的原因之一;避免傳送陳舊內容。

  2. 如果代理髮送HTTP頭 CQ-Action-Scope: ResourceOnly,這表示該單個失效請求不會觸發自動失效。 此( https://github.com/cqsupport/webinar-dispatchercache/tree/master/src/refetching-flush-agent/refetch-bundle)該代碼可能是您自己的複製代理的良好起點。

  3. ResourceOnly,僅防止自動失效。 要實際執行必要的依賴關係解決和無效,您必須自己觸發無效請求。 您可能要檢查包Dispatcher刷新規則(https://adobe-consulting-services.github.io/acs-aem-commons/features/dispatcher-flush-rules/index.html),以獲得關於如何實現這一目標的啟發。

我們不建議您構建依賴關係解決方案。 你只是付出了太多努力,收效甚微 — 正如前面所說,你會犯錯的事情太多了。

相反,您應該瞭解哪些資源不依賴於其他資源,並且可以在不自動失效的情況下使其失效。 不過,您不必為此使用自定義複製代理。 只需在Dispatcher配置中建立一個自定義規則,將這些資源排除在自動失效之外。

我們說主導航或預告是依賴項的來源。 那麼,如果您非同步載入導航和預告,或在Apache中將其與SSI指令碼一起載入,則您將沒有要跟蹤的該依賴關係。 在本文檔稍後介紹「Sling Dynamic Includes」時,我們將詳細介紹非同步載入元件。

同樣適用於載入到光箱中的彈出窗口或內容。 這些部分也很少具有導航(即,"依賴項"),並且可以作為單個資源無效。

以調度程式為中心構建元件

調度機理在現實案例中的應用

在最後一章中,我們介紹了Dispatcher的基本機制、它的一般工作原理以及限制。

現在,我們希望將這些力學應用到您很可能在項目要求中找到的一類元件中。 我們故意選取元件來演示您遲早也會面臨的問題。 不要害怕 — 並非所有組成部分都需要我們將提出的這樣多的考慮。 但是,如果你認為有必要建立這樣一個元件,你就很清楚後果,並知道如何處理後果。

假離線元件(反)模式

響應影像分量

讓我們說明一個元件的通用模式(或反模式),該元件具有互連的二進位檔案。 我們將建立一個「響應」元件 — 用於「響應影像」。 此元件應能夠將顯示的影像調整到其所顯示的設備。 在台式電腦和平板電腦上,它顯示了影像的完整解析度,在手機上顯示了較小的版本,有一條窄幅的紋路,甚至可能有完全不同的主題(在反應世界中,這被稱為「藝術方向」)。

這些資產上載到DAM區AEM域 引用 在響應影像分量中。

響應元件處理標籤的渲染和提供二進位影像資料。

我們在這裡實施它的方式是我們在許多項目中看到的一種常見模式,甚至其中一個核AEM心元件都基於這種模式。 因此,作為開發者,你很可能會改變這種模式。 在封裝方面,它有其最佳點,但要使它準備好Dispatcher,需要花費大量精力。 我們稍後將討論如何緩解該問題的幾種選擇。

我們把這裡使用的模式稱為「假離線模式」,因為問題可以追溯到3號公報的早期,當時有一種方法「假離線」,可以調用一個資源將二進位原始資料流入響應。

原始術語「假離線」實際上是指共用的慢速離線外圍設備,如打印機,因此在此處不能正確應用。 但我們還是喜歡這個詞,因為在網路世界中,這個詞很少能被區分。 而且每個模式都應該有一個可區分的名字,對吧? 這是一種模式還是一種反模式,由你決定。

實施

以下是如何實現響應映像元件:

該構件分為兩部分:第一部分呈現影像的HTML標籤,第二部分「線軸化」所引用影像的二進位資料。 因為這是一個具有響應性設計的現代網站,我們不是在描繪一個 <img src"…"> 標籤,但是 <picture/> 標籤。 對於每個設備,我們將兩個不同的影像上傳到DAM中,並從我們的影像元件中參考它們。

該元件有三個呈現指令碼(在JSP、HTL中實現,或作為Servlet實現),每個指令碼都使用專用選擇器定址:

  1. /respi.jsp — 沒有選擇器可呈現HTML標籤
  2. /respi.img.java 呈現案頭版本
  3. /respi.img.mobile.java 顯示移動版本。

該元件被放在首頁的參數中。 CRX中的結果結構如下所示。

CRX中響應影像的資源結構

CRX中響應影像的資源結構


元件標籤呈現為這樣,

  #GET /content/home.html

  <html>

  …

  <div class="responsive-image>

  <picture>
    <source src="/content/home/jcr:content/par/respi.img.mobile.jpg" …/>
    <source src="/content/home/jcr:content/par/respi.img.jpg …/>

    …

  </picture>
  </div>
  …

然後……我們用封裝得很精美的元件完成了。

響應性影像元件正在執行

現在,用戶通過Dispatcher請求頁面和資產。 這將導致Dispatcher檔案系統中的檔案,如下所示,

封裝的響應影像元件的快取結構

封裝的響應影像元件的快取結構


考慮用戶將兩個花卉影像的新版本上載並激活到DAM。 將根據AEM無效請求發送

/content/dam/flower.jpg

/content/dam/flower-mobile.jpg

調度員。 不過,這些要求是徒勞的。 內容已快取為元件子結構下的檔案。 這些檔案現在已過時,但仍可應要求提供。

結構不匹配導致內容陳舊

結構不匹配導致內容陳舊


這種方法還有另外一個警告。 請考慮在多頁上使用相同的flower.jpg。 然後,您將在多個URL或檔案下快取同一資產,

/content/home/products/jcr:content/par/respi.img.jpg

/content/home/offers/jcr:content/par/respi.img.jpg

/content/home/specials/jcr:content/par/respi.img.jpg

…

每次請求新的和未快取的頁面時,都會從不同的URLAEM中提取資產。 沒有Dispatcher快取和瀏覽器快取可以加快交付速度。

假離線圖案放在哪裡

有一個自然的例外,即使這種模式形式簡單,也是有用的:如果二進位檔案儲存在元件本身中,而不是儲存在DAM中。 但是,這僅對網站上使用過一次的影像有用,而不將資產儲存在DAM中意味著您很難管理資產。 想像一下您對特定資產的使用許可證已用完。 如何瞭解您使用了該資產的哪些元件?

你看? DAM中的「M」代表「管理」 — 如數字資產管理。 你不想洩露這個功能。

結論

從開AEM發者的角度看,這種圖案看上去非常優雅。 但是,當Dispatcher考慮到這個等式時,你可能會同意,天真的方法可能是不夠的。

現在,這是一種模式還是一種反模式,由你決定。 也許你已經有了一些好的想法,想如何減輕上面解釋的問題? 很好。 那麼你就會急切地想看看其他項目是如何解決這些問題的。

解決常見調度程式問題

概覽

讓我們來談談如何實現更加方便的快取。 有幾種選擇。 有時你無法選擇最好的解決方案。 也許你進入了一個已經在運行的項目,你的預算有限,只是解決手頭的「快取問題」,而不足以完成完全的重構。 或者你面臨一個問題,那比示例影像元件要複雜。

我們將在以下幾節中概述這些原則和注意事項。

同樣,這是基於現實生活經驗。 我們已經在野外看到了所有這些規律,所以它不是學術性的練習。 這就是為什麼我們給你們展示一些反模式,因此你們有機會從別人已經犯的錯誤中吸取教訓。

快取殺手

警告

這是反模式。 別用。 永遠。

您有沒有看到過類似 ?ck=398547283745? 它們被稱為快取殺手(「ck」)。 其思想是,如果添加任何查詢參數,則不會快取資源。 此外,如果添加隨機數作為參數值(如「398547283745」),則URL將變得唯一,並且您確保,系統和螢幕之間沒有其他快取AEM也能夠快取。 通常,在可疑對象之間會有一個「清漆」快取,位於Dispatcher、CDN甚至瀏覽器快取前面。 再次:別這樣。 您確實希望盡可能多地快取您的資源。 快取是你的朋友。 別殺朋友。

自動失效

警告

這是反模式。 避免將其用於數字資產。 嘗試僅保留Dispatcher的預設配置(>對於「.html」檔案自動無效)

短期而言,您可以將「.jpg」和「.png」添加到Dispatcher中的自動失效配置中。 這意味著,每當出現失效時,都需要重新呈現所有「.jpg」、「.png」和「.html」。

如果企業主抱怨他們的變化在現場站點上實現得不夠快,這種模式就非常容易實施。 但這只能為你爭取一些時間,讓你想出更複雜的解決方案。

確保您瞭解對效能的巨大影響。 這將顯著降低您的網站的速度,甚至會影響穩定性 — 如果您的網站是高負載、頻繁更改的網站,例如新聞門戶。

URL指紋

URL指紋看起來像是快取殺手。 但事實並非如此。 它不是隨機數,而是表示資源內容的值。 這可以是資源內容的哈希,也可以是上載、編輯或更新資源時的時間戳。

Unix時間戳對於實際實現來說足夠好。 為了更好地閱讀,我們在本教程中使用了更易讀的格式: 2018 31.12 23:59 or fp-2018-31-12-23-59

指紋不能用作查詢參數,因為無法快取具有查詢參數的URL。 您可以為指紋使用選擇器或尾碼。

假設,檔案 /content/dam/flower.jpgjcr:lastModified 2018年12月31日,23:59。 具有指紋的URL為 /content/home/jcr:content/par/respi.fp-2018-31-12-23-59.jpg

只要引用的資源(flower.jpg)檔案未更改。 因此,它可以無限期地快取,而且它不是快取殺手。

注意,需要由響應影像元件建立並提供該URL。 它不是現成的功AEM能。

這是基本概念。 不過,有些細節可能很容易被忽視。

在本例中,元件在23:59處呈現並快取。 現在影像已經更改,例如00:00。 元件 在其標籤中生成新的指紋URL。

你可能會認為 應該…但事實並非如此。由於僅更改了影像的二進位,且未觸及包含頁面,因此不需要重新呈現HTML標籤。 因此, Dispatcher使用舊指紋為頁面服務,從而為舊版本的影像服務。

影像元件比參考影像更新,未呈現新的指紋。

影像元件比參考影像更新,未呈現新的指紋。


現在,如果重新激活首頁(或該站點的任何其他頁),則會更新statfile, Dispatcher將考慮home.html過時,並在影像元件中使用新指紋重新呈現它。

但是我們沒有激活首頁,對吧? 為什麼我們要激活一個我們根本沒有觸及的頁面? 此外,我們可能沒有足夠的權限來激活頁面,或者審批工作流過於耗時長,以至於我們無法在短時間內完成。 那麼,該怎麼辦?

懶惰管理員的工具 — 降低狀態檔案級別

警告

這是反模式。 只在短期內使用它,以贏得一些時間,並提出更複雜的解決方案。

懶惰的管理員通常為"將自動失效設定為jpgs,將statfile級別設定為零 — 這始終有助於處理各種快取問題" 在技術論壇中,您會發現這一建議,它有助於解決您的失效問題。

到目前為止,我們還沒有討論靜態檔案級別。 基本上,自動失效只適用於同一子樹中的檔案。 然而,問題是頁面和資產通常不在同一子樹中。 頁面在下面 /content/mysite 而資產則低於 /content/dam

「statfile level」定義子樹的根節點深度的位置。 在上面的示例中,級別為"2"(1=/content, 2=/mysite,dam)

將靜態檔案級別「降低」到0的基本思想是將整個/content樹定義為一個並且只有一個子樹,使頁面和資產處於相同的自動失效域中。 因此,我們只能在大樹上(在docroot "/")。 但是,這樣做會自動使伺服器上所有站點在發佈內容時失效 — 甚至在完全不相關的站點上。 相信我們:從長遠看,這是個壞主意,因為您會嚴重降低總快取命中率。 您只能希望您的伺服器AEM擁有足夠的火力,可以在沒有快取的情況下運行。

稍後,您將瞭解更深入的狀態檔案級別所帶來的全部好處。

實現自定義無效代理

總之,我們需要以某種方式告訴調度程式,如果「.jpg」或「.png」更改為允許使用新URL重新呈現,則HTML頁將失效。

我們在項目中看到的是發佈系統上的特殊複製代理,這些代理在發佈站點映像時向該站點發送無效請求。

在這裡,如果您能夠通過命名約定從資產路徑中導出站點路徑,則它會有很大幫助。

通常來說,最好將站點和資產路徑進行匹配:

範例

/content/dam/site-a
/content/dam/site-b

/content/site-a
/content/site-b

這樣,當您的自定義Dispatcher Flushing代理遇到更改時,可以輕鬆地將請求發送到/content/site-a /content/dam/site-a

實際上,不管您告訴調度程式使哪條路徑失效 — 只要它位於同一站點,位於同一「子樹」中。 您甚至不必使用真正的資源路徑。 它也可以是「虛擬」的:

GET /dispatcher-invalidate
Invalidate-path /content/mysite/dummy

  1. 當DAM中的檔案更改時,會觸發發佈系統上的偵聽器

  2. 監聽器向調度程式發送無效請求。 由於自動無效,因此在自動無效中發送的路徑並不重要,除非它位於站點首頁下面,或者更精確地位於站點靜態檔案級別。

  3. 狀態檔案已更新。

  4. 下次請求首頁時,將重新呈現首頁。 新的指紋/日期從影像的lastModified屬性中提取為附加選擇器

  5. 這將隱式建立對新影像的引用

  6. 如果實際請求了影像,則會建立新格式副本並將其儲存在Dispatcher中

清理的必要性

噢。 已完成. 太棒了!

還不是。

路,

/content/mysite/home/jcr:content/par/respi.img.fp-2018-31-12-23-59.jpg

與任何無效資源無關。 記憶? 我們只是使一個「虛擬」資源失效,並依靠自動失效來認為「家庭」無效。 影像本身可能永遠 身體 已刪除。 因此,快取會增長並增長。 當更改並激活映像時,它們會在Dispatcher的檔案系統中獲取新的檔案名。

在物理上刪除快取檔案並無限期保留它們時存在三個問題:

  1. 您正在浪費儲存容量 — 這很明顯。 是的 — 儲存在過去幾年中變得更便宜。 但過去幾年,影像解析度和檔案大小也在增加 — 視網膜樣顯示器的出現,它們渴望獲得清晰銳利的影像。

  2. 儘管硬碟已變得更便宜,但「儲存」可能並未變得更便宜。 我們看到一種趨勢,即沒有(廉價)裸機HDD儲存,而是由您的資料中心提供商在NAS上租用虛擬儲存。 這種儲存比較可靠和可擴展,但也比較昂貴。 你可能不想浪費它,因為你存了過時的垃圾。 這不僅與主儲存有關,還考慮備份。 如果您有現成的備份解決方案,則可能無法排除快取目錄。 最後,您還在備份垃圾資料。

  3. 更糟的是:您可能只在有限的時間內購買某些映像的使用許可證 — 只要您需要。 現在,如果您在許可證過期後仍然儲存影像,則這可能被視為版權侵權。 你可能不再在網頁中使用影像了,但Google仍然會找到它們。

最後,您將提出一些整理cronjob來清理所有早於……的檔案我們就花一週時間來控制這種亂七八糟的東西吧。

濫用URL指紋進行拒絕服務攻擊

但是,等等,這個解決方案還有一個缺陷:

我們正在濫用選擇器作為參數:fp-2018-31-12-23-59作為某種「快取殺手」動態生成。 但也許有些無聊的孩子(或者搜索引擎爬蟲已經瘋了)開始請求網頁:

/content/mysite/home/jcr:content/par/img.fp-0000-00-00-00-00.jpg
/content/mysite/home/jcr:content/par/img.fp-0000-00-00-00-01.jpg
/content/mysite/home/jcr:content/par/img.fp-0000-00-00-00-02.jpg

…

每個請求都將繞過Dispatcher,導致對Publish實例載入。 而且 — 更糟的是 — 在Dispatcher上建立一個相應的檔案。

因此……您必須檢查jcr:lastModified映像日期,如果它不是預期日期,則返回404。 在發佈系統上需要一些時間和CPU週期……這是您最初想要阻止的。

高頻發佈中URL指紋的注意事項

您不僅可以對來自DAM的資產使用指紋架構,還可以對JS和CSS檔案及相關資源使用指紋架構。

版本控制客戶端 是使用此方法的模組。

但在這裡,你可能會面臨另一個警告:它將URL與內容關聯。 如果不更改URL(亦即,更新修改日期),則無法更改內容。 這是指紋最初的設計。 但請考慮,您正在推出新版本,新的CSS和JS檔案以及新的具有新指紋的URL。 所有HTML頁仍引用舊的指紋URL。 因此,要使新版本始終有效,您需要一次使所有HTML頁失效,以強制重新呈現新的指紋檔案。 如果您有多個站點依賴於同一庫,則可能需要大量重新呈現 — 在此,您無法利用 statfiles。 因此,請準備好在部署後看到發佈系統上的負載峰值。 您可能會考慮使用藍綠部署來預熱快取,或在Dispatcher前面使用基於TTL的快取……可能性無窮無盡。

短暫休息

哇,這可是很多細節要考慮,對吧? 它拒絕被輕易理解、測試和調試。 而這一切都是為了一個看似優雅的解決方案。 誠然,它很優雅 — 但只AEM從一個角度。 和調度員一起,事情變得很糟。

但是,它並不能解決一個基本的警告,如果在不同的頁面上多次使用影像,則會在這些頁面下快取影像。 快取的協同作用不大。

通常,URL指紋識別是工具包中的一個好工具,但您需要小心地應用它,因為它可能導致新問題,而只解決現有的幾個問題。

所以……那是篇長篇大論。 但是我們經常看到這種模式,我們覺得有必要給你全貌,有利有弊。 URL指紋解決了後台處理模式中的一些固有問題,但實施工作量很大,您還需要考慮其他更簡單的解決方案。 我們的建議是,始終檢查您是否可以將URL建立在服務資源路徑上,而且沒有中間元件。 下一章我們將討論這個問題。

運行時依賴關係解析

運行時依賴關係解決是我們在一個項目中考慮的概念。 但是想到它,我們變得相當複雜,我們決定不實施它。

這裡是基本思路:

Dispatcher不知道資源的依賴關係。 只是一堆檔案,沒有什麼語義。

也AEM對依賴性知之甚少。 它缺乏正確的語義或「依賴追蹤器」。

AEM瞭解一些參考。 當您嘗試刪除或移動引用的頁面或資產時,它會使用此知識警告您。 它通過在刪除資產時查詢內部搜索來實現。 內容引用確實有一種非常特殊的形式。 它們是以「/content」開頭的路徑表達式。 因此,它們可以輕鬆地被全文索引 — 並在需要時查詢。

在本例中,我們需要發佈系統上的自定義複製代理,該代理在路徑更改時觸發對特定路徑的搜索。

假設

/content/dam/flower.jpg

在發佈時已更改。 代理將啟動對「/content/dam/flower.jpg」的搜索並查找引用這些影像的所有頁面。

然後,它可以向調度程式發出許多無效請求。 每個包含資產的頁面一個。

理論上,這應該行得通。 但只適用於第一級依賴項。 您不希望將該方案應用於多級依賴關係,例如,在頁面上使用的體驗片段上使用影像時。 事實上,我們認為這種方法過於複雜 — 並且可能會出現運行時問題。 通常最好的建議是不要在事件處理程式中進行昂貴的計算。 尤其是搜索會變得非常昂貴。

結論

我們希望我們已充分討論了Spooler模式,以幫助您決定何時在實施中使用它,而不是使用它。

避免調度程式問題

基於資源的URL

解決依賴問題的一個更優雅的方法是根本沒有依賴。 避免使用一個資源僅代理另一個資源時發生的人工依賴關係 — 正如我們在上例中所做的那樣。 盡量將資源視為"單獨"實體。

我們的示例很容易解決:

使用綁定到映像而不是元件的servlet假離線映像。

使用綁定到映像而不是元件的servlet假離線映像。


我們使用資產原始資源路徑來呈現資料。 如果需要按原樣呈現原始影像,則只能使用。默AEM認呈現器來呈現資產。

如果需要對特定的元件執行一些特殊處理,我們會在該路徑上註冊一個專用的servlet,並選擇器代表該元件執行轉換。 我們以"。respi"為榜樣。 選擇器。 最好跟蹤全局URL空間上使用的選擇器名稱(如 /content/dam),並有良好的命名約定,以避免命名衝突。

順便說一下,我們沒有看到任何與代碼一致性有關的問題。 Servlet可以與元件sling模型在同一Java包中定義。

我們甚至可以在全局空間中使用其他選擇器,例如,

/content/dam/flower.respi.thumbnail.jpg

輕鬆,對吧? 那為什麼人們會想出一些複雜的圖案,比如勺子?

那麼,可以解決由於外部元件對內部資源的繪製增加的值或資訊很少而避免內部內容引用的問題,它很容易被編碼成控制孤立資源表示的靜態選擇器集合。

但是,有一類情況是您無法通過基於資源的URL輕鬆解決的。 我們將此類案例稱為「參數注入元件」,並在下一章中討論它們。

參數注入元件

概覽

最後一章中的Spooler只是資源周圍的一個薄包裝。 它帶來的麻煩比幫助解決問題要多。

通過使用簡單選擇器,我們可以輕鬆地替換該包裝,並添加一個相應的servlet來滿足這些請求。

但如果「respi」元件不僅僅是一個代理,那會怎樣? 如果元件真正有助於元件的繪製,會如何?

讓我們介紹一個"respi"部分的小擴展,這有點改變遊戲規則。 我們首先會提出一些天真的解決方案,來應對新挑戰,並展示新挑戰的不足之處。

Respi2元件

響應2元件是顯示響應影像的元件,響應元件也是。 但有個附加項,

CRX結構:respi2元件向交貨添加質量屬性

CRX結構:respi2元件向交貨添加質量屬性


影像是jpegs,可以壓縮jpegs。 壓縮jpeg影像時,需要將質量與檔案大小進行權衡。 壓縮定義為從"1"到"100"的數字「質量」參數。 「1」表示「小但質量差」,「100」表示「質量好但檔案大」。 那麼,哪個是完美價值?

與所有IT事務一樣,答案是:「這要看情況。」

這取決於主題。 具有高對比度邊緣的圖案,如文字、建築照片、插圖、草圖或產品盒照片(輪廓清晰,上面寫有文字),通常屬於這一類。 具有更柔和的顏色和對比度轉變的圖案,如景觀或肖像,可以更加壓縮,而不會出現可見的質量損失。 自然照片通常屬於這一類。

此外,根據影像的使用位置,您可能希望使用其他參數。 在預告器中,一個小縮略圖可能比在螢幕範圍的英雄橫幅中使用的相同影像承受更好的壓縮。 這意味著質量參數不是影像固有的而是影像和上下文固有的。 也符合作者的品味。

簡言之:沒有適合所有圖片的完美設定。 沒有一刀切。 作者最好決定。 他將調整「質量」參數作為元件中的屬性,直到他對質量感到滿意,並且不會進一步犧牲頻寬。

現在,DAM中有一個二進位檔案和一個元件,它提供了quality屬性。 URL應該是什麼樣? 哪個元件負責假離線?

天真的方法1:將屬性作為查詢參數傳遞

警告

這是反模式。 別用。

在最後一章中,元件呈現的影像URL如下所示:

/content/dam/flower.respi.jpg

所缺少的只是質量的價值。 該元件知道作者輸入了什麼屬性……當呈現標籤時,它可以作為查詢參數輕鬆傳遞給影像呈現servlet,如 flower.respi2.jpg?quality=60:

  <div class="respi2">
  <picture>
    <source src="/content/dam/flower.respi2.jpg?quality=60" …/>
    …
  </picture>
  </div>
  …

這是個壞主意。 記憶? 具有查詢參數的請求不可快取。

天真的方法2:將附加資訊作為選擇器傳遞

警告

這可能會成為一種反模式。 小心用。

將元件屬性作為選擇器傳遞

將元件屬性作為選擇器傳遞


這是最後一個URL的略微變化。 只是這一次,我們使用選擇器將屬性傳遞給servlet,以便結果可快取:

/content/dam/flower.respi.q-60.jpg

這要好得多,但還記得上一章那個討厭的劇本小子嗎? 他會看到,在價值上走圈可以走多遠:

  /content/dam/flower.respi.q-60.jpg
  /content/dam/flower.respi.q-61.jpg
  /content/dam/flower.respi.q-62.jpg
  /content/dam/flower.respi.q-63.jpg
  …

這再次繞過快取並在發佈系統上建立負載。 所以,這可能是個壞主意。 只過濾一小部分參數,可以緩解這種情況。 您只允許 q-20, q-40, q-60, q-80, q-100

使用選擇器時篩選無效請求

減少選擇器的數量是一個良好的開端。 作為經驗法則,您應始終將有效參數的數量限制為絕對最小值。 如果您做到這一點,您甚至可以在不深入瞭解底層系統的情況下AEM,使用一組靜態篩選器在外部利用Web應用程式防火牆來保護您AEM的系統:

Allow: /content/dam/(-\_/a-z0-9)+/(-\_a-z0-9)+
       \.respi\.q-(20|40|60|80|100)\.jpg

如果沒有Web應用程式防火牆,則必須在Dispatcher中或其本身進AEM行篩選。 如果你在裡面AEM,請確保

  1. 該濾波器實現得非常高效,而不會過多地訪問CRX,並且浪費儲存器和時間。

  2. 篩選器響應「404 — 未找到」錯誤消息

我們再強調一下最後一點。 HTTP對話的外觀如下:

  GET /content/dam/flower.respi.q-41.jpg

  Response: 404 – Not found
  << empty response body >>

我們還看到了一些實現,它們確實過濾了無效參數,但在使用無效參數時返回了有效的回退呈現。 假設我們只允許20-100的參數。 中的值映射到有效值。 所以,

q-41, q-42, q-43, …

將始終響應與q-40相同的映像:

  GET /content/dam/flower.respi.q-41.jpg

  Response: 200 – OK
  << flower.jpg with quality = 40 >>

這種方法毫無幫助。 這些請求實際上是有效請求。 它們消耗處理能力並佔用Dispatcher上快取目錄中的空間。

最好還是 301 – Moved permanently:

  GET /content/dam/flower.respi.q-41.jpg

  Response: 301 – Moved permanently
  Location: /content/dam/flower.respi.q-40.jpg

這AEM是告訴瀏覽器。 「我沒有 q-41。 但是,你可以問我 q-40

這會為會話增加一個額外的請求 — 響應循環,這有點開銷,但比在 q-41。 您可以利用已快取的檔案 q-40。 但是,您必須瞭解, Dispatcher中沒有快取302個響應,我們討論的是中執行的邏AEM輯。 一遍又一遍。 所以你最好把它修得苗條快。

我們個人最喜歡404 它讓事情變得非常明顯。 並幫助在分析日誌檔案時檢測網站上的錯誤。 301可以用於設計,其中應始終分析並消除404。

安全性 — 偏移

篩選請求

最佳篩選位置

最後,我們指出了過濾已知選擇器傳入流量的必要性。 這就引出了問題:實際上,我應該在何處篩選請求?

那要看情況。 越快越好。

Web應用程式防火牆

如果您有專為Web安全而設計的Web應用程式防火牆裝置或「WAF」,則您絕對應利用這些功能。 但您可能會發現, WAF由對內容應用程式瞭解有限的人員操作,他們要麼過濾有效請求,要麼讓過多有害請求。 您可能會發現,WAF的運營人員被指派到具有不同班次和發佈時間安排的不同部門,溝通可能不像與直接隊友那樣緊密,而且您並不總能及時得到更改,這意味著您的開發和內容速度最終會受到影響。

你最終可能會有一些一般規則,甚至有一個禁區,你的直覺認為,這個禁區可能會收緊。

Dispatcher和Publish篩選

下一步是在Apache核心和/或Dispatcher中添加URL過濾規則。

您只能訪問URL。 您只能使用基於陣列的濾鏡。 如果您需要設定更基於內容的篩選(例如,只允許檔案使用正確的時間戳),或希望作者控制某些篩選 — 您最終將編寫類似自定義servlet篩選器的內容。

監視和調試

在實踐中,您將在每個級別上擁有一些安全性。 但請確保您有辦法瞭解請求被過濾掉的級別。 確保您直接訪問發佈系統、調度程式和WAF上的日誌檔案,以查找鏈中哪個篩選器正在阻止請求。

選擇器和選擇器擴散

最後一章採用"選擇器參數"的方法快速、簡便,可加快新零件的開發時間,但有局限性。

設定"quality"屬性只是一個簡單的示例。 但是,Servlet還希望「width」的參數更多用。

您可以通過減少可能的選擇器值數來減少有效URL的數量。 您也可以使用寬度執行同樣操作:

質量= q-20、q-40、q-60、q-80、q-100

寬度= w-100、w-200、w-400、w-800、w-1000、w-1200

但所有組合現在都是有效的URL:

/content/dam/flower.respi.q-40.w-200.jpg
/content/dam/flower.respi.q-60.w-400.jpg
…

現在,我們已為一個資源提供了5x6=30個有效URL。 每個附加屬性都增加了複雜性。 也許有一些屬性,這些屬性不能降到合理的數值。

所以,這個方法也有局限性。

無意中暴露API

這裡發生了什麼? 如果我們仔細觀察,我們會發現,我們正在逐漸從靜態呈現到高度動態的網站。 我們無意中向客戶的瀏覽器顯示了一個影像渲染API,實際上它只供作者使用。

設定影像的質量和大小應由作者編輯頁面來完成。 Servlet所暴露的相同功能可被視為拒絕服務攻擊的特徵或向量。 它到底是什麼,取決於背景。 網站的業務關鍵性如何? 伺服器上的負載是多少? 還剩多少頭部空間? 您有多少預算用於實施? 你必須平衡這些因素。 你應該知道利弊。

後發者模式 — 再認識與修復

假離線程式如何避免暴露API

我們在最後一章中有點懷疑斯波勒模式。 是時候改造它了。

後台處理模式通過公開我們在上一章中討論的API來防止問題。 屬性被儲存並封裝在元件中。 訪問這些屬性所需的只是元件的路徑。 我們不必將URL用作在標籤和二進位呈現之間傳輸參數的工具:

  1. 當在主請求循環中請求元件時,客戶端將呈現HTML標籤

  2. 元件路徑用作從標籤到元件的回參照

  3. 瀏覽器使用此反向引用請求二進位檔案

  4. 當請求命中元件時,我們手中擁有所有屬性來調整、壓縮和緩衝二進位資料

  5. 影像通過元件傳輸到客戶端瀏覽器

Spooler模式畢竟並不那麼糟糕,這就是它如此受歡迎的原因。 如果只有在快取失效方面不那麼麻煩……

倒置後台處理器 — 兩個世界中最好的?

這就引出了問題。 為什麼我們不能兩全其美? 假離線模式的良好封裝和基於資源的URL的良好快取屬性?

我們必須承認,我們在一個真實的項目中還沒有看到。 不過,讓我們大膽嘗試一下這裡的想法吧 — 作為你自己解決方案的起點。

我們將這種模式稱為 倒置假離線程式… 倒排假離線程式必須基於影像資源,才能擁有所有好的快取無效屬性。

但是,它不能公開任何參數。 所有屬性都應封裝在元件中。 但是,我們可以將元件路徑公開為對屬性的不透明引用。

這將導致URL的形式:

/content/dam/flower.respi3.content-mysite-home-jcrcontent-par-respi.jpg

/content/dam/flower 是映像資源的路徑

.respi3 是選擇正確的servlet以傳送映像的選擇器

.content-mysite-home-jcrcontent-par-respi 是其他選擇器。 它將路徑編碼到儲存影像轉換所需屬性的元件。 選擇器的字元範圍比路徑少。 這裡的編碼方案就是一個範例。 它用"-"替換"/"。 路徑本身也可以包含「 — 」,這並不考慮。 在現實世界中,將建議採用一種更複雜的編碼方案。 Base64應該可以。 但它讓調試變得更加困難。

.jpg 是檔案尾碼

結論

對勺子的討論比預期的更長,也更複雜。 我們欠你個藉口。 但是,我們覺得有必要向您介紹很多方面 — 好的和壞的 — 以便您能夠對Dispatcher-land中哪些方面是好的,哪些方面不是好的形成一些直覺。

Statfile和Statfile級

基礎

簡介

我們已經簡略地提到 statfile 。 它與自動失效有關:

如果Dispatcher檔案系統中所有配置為自動失效的快取檔案的上次修改日期早於 statfile's 上次修改日期。

注意

我們討論的上次修改日期是快取檔案的日期,它是從客戶端瀏覽器請求檔案並最終在檔案系統中建立的日期。 不是 jcr:lastModified 資源的日期。

statfile的上次修改日期(.stat)是在Dispatcher上收到來AEM自無效請求的日期。

如果您有多個Dispatcher,這可能會帶來奇怪的效果。 您的瀏覽器可以有一個更新版本的調度程式(如果您有多個調度程式)。 或者, Dispatcher可能認為由其他Dispatcher發佈的瀏覽器版本已過時,因此不必要地發送了新副本。 該等影響對表現或功能要求並無重大影響。 當瀏覽器有最新版本時,它們會逐漸平衡。 但是,當您優化和調試瀏覽器快取行為時,可能會有點混亂。 所以要警告。

使用/statfileslevel設定無效域

當我們介紹自動失效和靜態檔案時我們說 全部 如果發生任何更改,並且所有檔案仍相互依存,則檔案被視為無效。

這不太準確。 通常,共用共同主導航根的所有檔案都是相互依賴的。 但一AEM個實例可以承載多個網站。 獨立 的子菜單。 不共用公共導航 — 事實上,不共用任何內容。

因為站點A有更改,所以使站點B無效不是浪費嗎? 是的。 而且不一定非得這樣。

Dispatcher提供了一種簡單的方法來將站點彼此分離:的 statfiles-level

它是一個數字,它定義了檔案系統中的哪個級別,兩個子樹被視為「獨立」。

讓我們看一下預設情況,其中statfilelevel為0。

/statfileslevel "0":_ .stat 在docroot中建立(_S)。 失效域涵蓋整個安裝,包括所有站點

/statfileslevel "0":.stat 檔案在docroot中建立。 失效域涵蓋整個安裝,包括所有站點。

無論檔案失效, .stat 始終更新調度程式docroot頂部的檔案。 所以當你宣佈 /content/site-b/home,也是所有檔案 /content/site-a 也是無效的,因為他們現在比 .stat 檔案。 顯然不是你需要的,當你宣佈無效 site-b

在此示例中,您寧可將 statfileslevel1

現在,如果您發佈 — 因此無效 /content/site-b/home/content/site-b,也請參見Wiki頁。 .stat 檔案建立於 /content/site-b/

以下內容 /content/site-a/ 不受影響。 此內容將與 .stat 檔案 /content/site-a/。 我們建立了兩個獨立的無效域。

靜態檔案級別「1」建立不同的無效域

靜態檔案級別「1」建立不同的無效域


大型安裝通常結構更複雜、更深。 一個共同的方案是按品牌、國家和語言來構建網站。 在這種情況下,可以將statfileslevel設定得更高。 1 會建立每個品牌的失效域, 2 每個國家/地區 3 每種語言。

同質場地結構的必要性

靜態檔案級別同樣應用於設定中的所有站點。 因此,必須使所有站點都遵循同一結構,從同一層開始。

考慮一下,您投資組合中的某些品牌只在少數幾個小市場銷售,而其他品牌則在全球銷售。 小市場碰巧只有一種本地語言,而在全球市場上,有些國家說的不止一種語言:

  /content/tiny-local-brand/finland/home
  /content/tiny-local-brand/finland/products
  /content/tiny-local-brand/finland/about
                              ^
                          /statfileslevel "2"
  …

  /content/tiny-local-brand/norway
  …

  /content/shiny-global-brand/canada/en
  /content/shiny-global-brand/canada/fr
  /content/shiny-global-brand/switzerland/fr
  /content/shiny-global-brand/switzerland/de
  /content/shiny-global-brand/switzerland/it
                                          ^
                                /statfileslevel "3"
  ..

前者需要 statfileslevel2,而後者需要 3

不是理想情況。 如果您將其設定為 3​這樣,子分支之間較小的站點就無法自動失效 /home/products/about

將其設定為 2 也就是說,在大的站點上 /canada/en/canada/fr 依附,而他們可能不是。 因此, /en 也會失效 /fr。 這將導致快取命中率略微降低,但仍比提供陳舊的快取內容好。

當然,最好的解決辦法是讓所有網站的根基都同樣深:

/content/tiny-local-brand/finland/fi/home
/content/tiny-local-brand/finland/fi/products
/content/tiny-local-brand/finland/fi/about
…
/content/tiny-local-brand/norway/no/home
                                 ^
                        /statfileslevel "3"

站點間連結

哪個是合適的級別? 這取決於您在站點之間的依賴關係數。 您為呈現頁面而解析的包含被視為「硬依賴項」。 我們證明 當我們介紹 預告 元件。

超連結 是更軟的依賴形式。 很可能,你會在一個網站中超連結……而且你的網站之間也不可能有連結。 簡單超連結通常不會在網站之間建立依賴關係。 想想你從網站到facebook的外部連結……如果facebook發生任何變化,你就不必呈現頁面,反之亦然。

從連結資源(例如導航標題)讀取內容時,會發生依賴關係。 如果僅依賴本地輸入的導航標題而不是從目標頁面中繪製這些標題(如使用外部連結時那樣),則可避免此類依賴項。

意外的依賴關係

但是,你的設定可能會有一部分,在這裡 — 據說是獨立的 — 網站會聚在一起。 讓我們看看我們在一個項目中遇到的真實世界情景。

客戶有一個類似於上一章所介紹的站點結構:

/content/brand/country/language

例如,

/content/shiny-brand/switzerland/fr
/content/shiny-brand/switzerland/de

/content/shiny-brand/france/fr

/content/shiny-brand/germany/de

每個國家都有自己的領域,

www.shiny-brand.ch

www.shiny-brand.fr

www.shiny-brand.de

語言站點之間沒有可導航的連結,並且沒有明顯的包含,因此我們將statfilelevel設定為3。

所有網站基本上都提供了相同的內容。 唯一的主要區別是語言。

像Google這樣的搜索引擎考慮在不同的URL上使用相同的內容是「欺騙的」。 用戶可能希望通過建立提供相同內容的場來嘗試獲得更高的排名或更頻繁地列出。 搜索引擎能夠識別這些嘗試,並實際將僅回收內容的頁面排序得更低。

通過透明化、實際上有多個具有相同內容的頁面以及您沒有嘗試對系統進行「遊戲」(請參閱 “告訴Google有關您頁面的本地化版本”) <link rel="alternate"> 標籤到每頁標題部分中的每個相關頁:

# URL: www.shiny-brand.fr/fr/home/produits.html

<head>

  <link rel="alternate"
        hreflang="fr-ch"
        href="http://www.shiny-brand.ch/fr/home/produits.html">
  <link rel="alternate"
        hreflang="de-ch"
        href="http://www.shiny-brand.ch/de/home/produkte.html">
  <link rel="alternate"
        hreflang="de-de"
        href="http://www.shiny-brand.de/de/home/produkte.html">

</head>

----

# URL www.shiny-brand.de/de/home/produkte.html

<head>

  <link rel="alternate"
        hreflang="fr-fr"
        href="http://www.shiny-brand.fr/fr/home/produits.html">
  <link rel="alternate"
        hreflang="fr-ch"
        href="http://www.shiny-brand.ch/fr/home/produits.html">
  <link rel="alternate"
        hreflang="de-ch"
         href="http://www.shiny-brand.ch/de/home/produits.html">

</head>

全部連結

全部連結


一些SEO專家甚至認為,這可能會將名聲或「連結」從一種語言的高級網站轉移到另一種語言的同一網站。

該方案不僅產生了許多連結,還產生了一些問題。 所需的連結數 pn 語言 p x(n)2-n):每個頁面連結到彼此的頁面(n),除自身(-n)。 此方案應用於每頁。 如果我們有一個4種語言的小站點, 20頁,每頁都相當於 240 連結。

首先,您不希望編輯器必須手動維護這些連結 — 這些連結必須由系統自動生成。

第二,它們應該準確。 每當系統檢測到新的「相對」時,您都希望將其從具有相同內容(但使用不同語言)的所有其它頁面連結。

在我們的項目中,新的相對頁頻繁出現。 但它們並未成為「替代」連結。 例如,當 de-de/produkte 頁面是在德國網站上發佈的,其他網站上則不能立即看到。

原因是,在我們的設定中,網站應該是獨立的。 因此,德國網站上的一個變化並沒有觸發法國網站上的失效。

你已經知道一個解決方案如何解決這個問題。 只需將statfileslevel降到2即可擴展失效域。 當然,這也降低了快取命中率 — 特別是當發佈時 — 因此無效更頻繁地發生。

就我們而言,情況更加複雜:

儘管我們有相同的內容,但實際上不同的品牌在每個國家都不同。

shiny-brand 調用 marque-brillant 在法國和 blitzmarke 德國:

/content/marque-brillant/france/fr
/content/shiny-brand/switzerland/fr
/content/shiny-brand/switzerland/de
/content/blitzmarke/germany/de
…

那本該讓 statfiles 級到1級 — 這將導致失效域過大。

重組網站就能解決這個問題。 將所有品牌合併到一個共同的根下。 但那時我們還沒有能力,而且 — 那只會讓我們達到2級。

我們決定堅持採用第3級,並支付不總是具有最新「備用」連結的價格。 為了減輕問題,我們在Dispatcher上運行了「收紙機」cron作業,它將清除1週以前的檔案。 所以最終所有的頁面都在某個時間點重新呈現。 但這是一個取捨,需要在每個項目中單獨決定。

結論

我們介紹了Dispatcher一般工作方式的一些基本原則,並給出了一些示例,在這些示例中,您可能需要投入更多的實施工作來使其正確,並且您可能希望在哪些方面做出權衡取捨。

我們沒有詳細說明在Dispatcher中如何配置。 我們希望您首先瞭解基本概念和問題,而不要太早地將您丟到控制台。 而且 — 實際配置工作已有詳細記錄 — 如果您瞭解基本概念,您應知道各種交換機的用途。

Dispatcher提示和技巧

在本書的第一部分,我們將隨機收集各種提示和技巧,這些提示和技巧在某種情況下可能有用。 正如我們以前所做的那樣,我們不是在展示解決方案,而是展示這個想法,以便您有機會瞭解這個想法和概念,並連結到描述實際配置的文章,這些文章將更加詳細。

正確的無效計時

如果安裝了AEM Author(AEM作者)並將其發佈出框,則拓撲會有點奇怪。 作者將內容發送到發佈系統,同時將失效請求發送給調度員。 由於「發佈」系統和「調度程式」都與「作者」分離,因此隊列的時間可能有點不順。 在發佈系統上更新內容之前, Dispatcher可以從作者接收無效請求。

如果客戶端同時請求該內容,則Dispatcher將請求並儲存陳舊內容。

一個更可靠的設定正在從發佈系統發送失效請求 他們收到了內容。 文章「從發佈實例中使Dispatcher快取無效」描述詳細資訊。

引用

helpx.adobe.com — 從發佈實例中取消驗證Dispatcher快取

HTTP頭和頭快取

以前, Dispatcher只是在檔案系統中儲存普通檔案。 如果需要將HTTP標頭交付給客戶,請根據您從檔案或位置獲得的少量資訊配置Apache來完成此操作。 當您在嚴重依賴HTTP標頭的Web應用程式AEM中實施時,這尤其令人討厭。 在唯一實例AEM中,一切正常,但使用Dispatcher時不是。

通常,您已開始將丟失的標頭重新應用到Apache伺服器中的資源 mod_headers 通過使用資源路徑和尾碼可以派生的資訊。 但這並不總是足夠。

特別煩人的是,就算調度員 對瀏覽器的響應來自具有完整標題範圍的發佈系統,而後續響應則由具有有限標題集的調度程式生成。

從Dispatcher 4.1.11開始,Dispatcher可以儲存由發佈系統生成的標頭。

這樣,您就不必在Dispatcher中複製頭邏輯,並釋放了HTTP和的完全表達能AEM力。

引用

單個快取異常

通常,您可能希望快取所有頁面和影像 — 但在某些情況下會發生異常。 例如,您希望快取PNG影像,但不希望快取顯示驗證碼的PNG影像(假設每個請求都會更改)。 調度員可能不會把驗證碼識別為驗證碼,但AEM肯定。 它可以通過發送相應的報頭以及響應來要求調度程式不要快取該請求:

  response.setHeader("Dispatcher", "no-cache");

  response.setHeader("Cache-Control: no-cache");

  response.setHeader("Cache-Control: private");

  response.setHeader("Pragma: no-cache");

Cache-Control和Pragma是正式的HTTP頭,它們傳播到高級快取層(如CDN)並由其解釋。 的 Dispatcher 標頭只是Dispatcher不快取的提示。 它可用於告訴Dispatcher不要快取,同時仍允許上層快取層執行快取。 事實上,很難找到有用的案例。 但是我們肯定有一些,某處。

引用

瀏覽器快取

最快的http-response是瀏覽器本身給出的響應。 當請求和響應不必在高負載下通過網路傳到Web伺服器時。

通過設定資源的過期日期,您可以幫助瀏覽器決定何時向伺服器詢問檔案的新版本。

通常,您使用Apache mod_expires 或者,如果需要更單獨的控制項,則儲存從AEM快取控制和過期標頭。

瀏覽器中快取的文檔可以具有三個最新級別。

  1. 保證新鮮 — 瀏覽器可以使用快取的文檔。

  2. 可能過時 — 瀏覽器應首先詢問伺服器快取的文檔是否仍是最新的,

  3. 過時 — 瀏覽器必須要求伺服器提供新版本。

第一個由伺服器設定的到期日保證。 如果資源未過期,則無需再次詢問伺服器。

如果文檔已到達到到期日期,則仍可以是新文檔。 在交付文檔時設定到期日期。 但是,你通常不會提前知道新內容何時可用 — 因此這只是一種保守的估計。

要確定瀏覽器快取中的文檔是否仍與新請求中傳遞的文檔相同,瀏覽器可以使用 Last-Modified 的子菜單。 瀏覽器詢問伺服器:

"我有6月10日的版本,需要更新嗎?"伺服器可以響應

"304 — 您的版本仍為最新"不重新傳輸資源,或伺服器可以通過

"200 — 這是更新的版本"和HTTP正文中實際的較新內容。

要使第二部分工作,請確保 Last-Modified 更新到瀏覽器,因此它具有要求更新的參考點。

我們之前解釋說,當 Last-Modified 日期由Dispatcher生成,它可能因不同請求而異,因為當瀏覽器請求檔案時會生成快取檔案及其日期。 另一種選擇是使用「e-tags」 — 這些數字標識實際內容(例如,通過生成散列代碼)而不是日期。

"Etag支援ACS公域包 用這個方法。 然而,這是有代價的:由於E-Tag必須作為報頭髮送,但哈希代碼的計算需要完全讀取響應,因此響應必須在主記憶體中完全緩衝,才能傳送。 當您的網站更可能擁有未快取的資源,並且您當然需要關注系統佔用的記憶體時,這可能會對延遲產AEM生負面影響。

如果使用URL指紋,則可以設定很長的過期日期。 您可以在瀏覽器中永久快取指紋資源。 新版本會用新URL標籤,舊版本永遠不必更新。

我們在介紹假離線模式時使用了URL指紋。 來自的靜態檔案 /etc/design (CSS、JS)很少被更改,也使它們成為用作指紋的好候選。

對於常規檔案,我們通常會設定一個固定的方案,如每30分鐘重新檢查一次HTML,每4小時進行影像檢查等。

瀏覽器快取對Author系統有極大的幫助。 您希望盡可能地在瀏覽器中快取以增強編輯體驗。 遺憾的是,最昂貴的資產,無法快取html頁面……這些頁面應在作者中經常更改。

組成UI的花崗岩AEM庫可快取相當長的時間。 您還可以在瀏覽器中快取站點靜態檔案(字型、CSS和JavaScript)。 連影像 /content/dam 通常可以快取大約15分鐘,因為它們不會像頁面上的複製文本那樣頻繁更改。 不以交互方式編輯圖AEM像。 在將它們上載到之前,先對它們進行編輯和審AEM批。 因此,您可以假設它們不像文本那樣頻繁地更改。

快取UI檔案、站點庫檔案和影像可以在處於編輯模式時顯著加快頁面的重新載入。

引用

*developer.mozilla.org — 快取

正在截斷URL

您的資源儲存在

/content/brand/country/language/…

當然,這不是您想向客戶顯示的URL。 出於美學、可讀性和SEO原因,您可能希望截斷已在域名中表示的部件。

如果您有域

www.shiny-brand.fi

通常沒有必要把品牌和國家放在前面。 而不是,

www.shiny-brand.fi/content/shiny-brand/finland/fi/home.html

你會想要的,

www.shiny-brand.fi/home.html

您必須在上實現該映AEM射 — 因AEM為需要知道如何根據截斷的格式呈現連結。

但不要只AEM依賴。 如果你這樣做,你會有 /home.html 的根目錄中。 那是Finish的"家"還是德語或加拿大網站? 如果有檔案 /home.html 在Dispatcher中, Dispatcher如何知道,當對 /content/brand/fi/fi/home 進來。

我們看到一個項目,每個域都有單獨的多克羅。 調試和維護是場噩夢 — 事實上,我們從未看到它完美運行。

通過重構快取結構,可以解決這些問題。 對於所有域,我們只有一個域,失效請求可以處理1:1,因為伺服器上的所有檔案都以 /content

截短部分也很容易。 由AEM於中的配置而生成的截斷鏈路 /etc/map

現在,當請求 /home.html 是命中Dispatcher ,首先要應用一個在內部擴展路徑的重寫規則。

該規則是在每個vhost配置中靜態設定的。 簡而言之,規則是這樣的,

  # vhost www.shiny-brand.fi

  RewriteRule "^(.\*\.html)" "/content/shiny-brand/finland/fi/$1"

在檔案系統中,我們現在有 /content基於路徑,在「作者」和「發佈」中也可找到,這幫助調試了很多。 更別提正確的失效了 — 這已經不是問題了。

注意,我們僅對瀏覽器的URL插槽中顯示的「可見」URL和URL執行此操作。 例如,影像的URL仍然是純「/content」 URL。 我們認為,美化"主"URL在搜索引擎優化方面是足夠的。

一個普通的渡越器也有另一個好的特點。 當調度程式出現任何問題時,我們可以執行

rm -rf /cache/dispatcher/*

(在高負載峰值時,你可能不想做的事)。

引用

錯誤處理

在AEM類中,您將學習如何在Sling中寫程式錯誤處理程式。 這和寫一個通常的模板沒有太大區別。 您只需在JSP或HTL中編寫模板,對吧?

是的,但這隻AEM是部分。 記住 — Dispatcher不快取 404 – not found500 – internal server error 響應。

如果您在每個(失敗的)請求上動態呈現這些頁面,則在發佈系統上將承受不必要的高負載。

我們發現,在出現錯誤時,不要呈現完整錯誤頁面,而只是呈現該頁面的超簡小版本,甚至是靜態版本,不需要任何裝飾或邏輯。

這當然不是客戶看到的。 在調度員里,我們註冊了 ErrorDocuments 如此:

ErrorDocument 404 "/content/shiny-brand/fi/fi/edocs/error-404.html"
ErrorDocument 500 "/content/shiny-brand/fi/fi/edocs/error-500.html"

現在,AEM系統可以通知調度程式出了問題,而調度程式可以提供一個漂亮的錯誤文檔版本。

這裡應該注意兩點。

首先, error-404.html 總是同一頁。 所以,沒有"你的搜索"這樣的單個消息​生產"未產生結果"。 我們很容易接受。

其次……如果我們看到內部伺服器錯誤,或者更糟的是,我們AEM遇到系統中斷,則無法要AEM求呈現錯誤頁,對吧? 在中定義的必要後續請求 ErrorDocument 指令也會失敗。 我們通過運行cron-job來解決此問題,該cron-job將定期從其定義的位置通過 wget 並將它們儲存到在 ErrorDocuments 指令。

引用

快取受保護的內容

預設情況下,Dispatcher在傳遞資源時不檢查權限。 這樣實施是為了加快公共網站的速度。 如果要通過登錄來保護一些資源,基本上有三個選項,

  1. 在請求命中快取之前的Protect資源 — 例如,通過Dispatcher前面的SSO(單一登錄)網關,或作為Apache伺服器中的模組

  2. 不要快取敏感資源,因此始終從發佈系統中為敏感資源提供即時服務。

  3. 在Dispatcher中使用對權限敏感的快取

當然,你可以用你自己的三種方法。

選項1。 無論如何,您的組織可能會強制使用「SSO」網關。 如果您的訪問方案是非常粗糙的,則您可能不需要AEM來自的資訊來決定是授予還是拒絕對資源的訪問。

注意

此模式需要 網關攔截 並執行實際 授權 — 授予或拒絕Dispatcher請求。 如果您的SSO系統是 驗證,它僅建立必須實現選項3的用戶的標識。 如果您在SSO系統手冊中閱讀了「SAML」或「OAauth」等術語 — 這是您必須實施選項3的強有力指標。

選項2。 「不快取」通常是個壞主意。 如果您這樣做,請確保已排除的通信量和敏感資源數量較小。 或者確保在發佈系統中安裝了一些記憶體快取,發佈系統可以處理所產生的負載 — 更多有關此系列第三部分中的內容。

選項3。 「權限敏感快取」是一種有趣的方法。 Dispatcher正在快取資源,但在交付資源之前,它會詢問AEM系統是否可以快取資源。 這會建立從Dispatcher到Publish的額外請求 — 但是,如果已快取了Publish系統,它通常會阻止它重新呈現頁面。 但是,這種方法需要一些定製的實施。 在文章中查找詳細資訊 權限敏感快取

引用

設定寬限期

如果您經常在短時間內連續失效 — 例如,通過樹激活或出於保持內容最新的簡單需要,則可能會發生您不斷刷新快取,並且您的訪問者幾乎總是碰到空快取。

下圖說明了訪問單頁時可能的時間。 當請求的不同頁數增加時,問題當然會變得更嚴重。

頻繁的激活導致快取在大多數時間內無效

頻繁的激活導致快取在大多數時間內無效


要緩解此「快取無效風暴」的問題,您可以不那麼嚴格地 statfile 詮釋。

您可以將調度程式設定為 grace period 自動失效。 這將在內部為 statfiles 修改日期。

比如說, statfile 修改時間為今天12:00,您 gracePeriod 設定為2分鐘。 然後,所有自動失效的檔案將在12:01和12:02被視為有效。 12點02分之後將重新渲染。

參考配置建議 gracePeriod 兩分鐘,理由很充分。 你會想"兩分鐘? 那幾乎沒什麼。 我可以輕鬆地等待10分鐘,讓內容顯示……」 因此,你可能會忍不住設定一個更長的時間段 — 比如說10分鐘,假設你的內容至少在這10分鐘後出現。

警告

這不是 gracePeriod 工作。 寬限期是 在保證檔案失效之後,不發生失效的時間幀。 每個後續失效都屬於此幀內 延長 時間框架 — 這可以無限期地拖長。

讓我們說明一下 gracePeriod 實際上是在用一個示例:

比方說,您正在運行媒體站點,而您的編輯人員每5分鐘提供一次定期內容更新。 考慮您將gracePeriod設定為5分鐘。

12:00,我們先來一個簡單的例子。

12:00 - Statfile設定為12:00。 所有快取檔案均視為在12:05之前有效。

12:01 — 出現失效。 將爐排時間延長到12:06

12:05 — 另一位編輯發表他的文章 — 將寬限期延至12:10。

等等,內容永遠不會失效。 每個失效 gracePeriod有效地延長了寬限期。 的 gracePeriod 是為了抵御失效風暴……但你最終必須下雨……所以,保持 gracePeriod 要短得多,才能防止永遠躲在庇護所里。

確定性寬限期

我們想再介紹一下如何抵御失效風暴。 這只是個主意。 我們還沒有在生產中嘗試過,但我們發現這個概念非常有趣,可以和大家分享這個想法。

gracePeriod 如果常規複製間隔短於您的 gracePeriod

另一個想法是:僅在固定時間間隔內失效。 介於兩者之間的時間始終意味著提供陳舊內容。 失效最終會發生,但是許多失效會被收集到一個「批量」失效,這樣調度程式就有機會同時提供一些快取的內容,並給發佈系統一些喘息的空氣。

實施情況如下:

您使用的「自定義無效指令碼」(請參閱參考)將在無效後運行。 此指令碼將讀取 statfile's 上次修改日期並將其捨入到下一個間隔停止。 Unix shell命令 touch --time,讓您指定時間。

例如,如果將寬限期設定為30秒,則調度程式會將statfile的上次修改日期捨入到接下來的30秒。 在兩個時間之間發生的失效請求只設定相同的下一個完整30秒。

將失效延遲到下一個30秒全速,將提高命中率。

將失效延遲到下一個30秒全速,將提高命中率。


在失效請求和下一輪30秒時隙之間發生的快取命中被視為失效;發佈上有更新 — 但Dispatcher仍提供舊內容。

這種方法有助於定義更長的寬限期,而不必擔心隨後的請求會無限期延長寬限期。 儘管如我們之前所說,這只是一個想法,我們沒有機會test它。

引用

helpx.adobe.com - Dispatcher配置

自動重取

您的站點具有非常特定的訪問模式。 您的來話流量負載很大,而且大多數流量都集中在您頁面的一小部分上。 首頁、促銷活動登錄頁和最特色的產品詳細資訊頁面將獲得90%的流量。 或者,如果你運營一個新網站,較新文章的流量數比較舊。

現在,這些頁面很可能會在Dispatcher中快取,因為它們的請求非常頻繁。

任意失效請求會發送到調度程式,導致所有頁面(包括您最常用的一頁)無效。

隨後,由於這些頁面非常流行,因此會出現來自不同瀏覽器的新傳入請求。 以首頁為例,

與現在一樣,快取無效,所有同時進入首頁的請求都會轉發到發佈系統,生成高負載。

空快取上對同一資源的並行請求:請求將轉發到「發佈」

空快取上對同一資源的並行請求:請求將轉發到「發佈」

通過自動重取,您可以在一定程度上緩解這種情況。 自動失效後,大多數失效的頁面仍實際儲存在調度程式上。 只是 過時。 自動重取 意味著您在啟動時仍會為這些陳舊頁面提供幾秒鐘 請求發佈系統重新獲取陳舊內容:

在後台重取時傳遞陳舊內容

在後台重取時傳遞陳舊內容


要啟用重取,您必須告訴Dispatcher在自動失效後要重取哪些資源。 請記住,您激活的任何頁面都會自動使所有其它頁面失效,包括常用頁面。

重新獲取實際上意味著在每個(!)中通知調度程式 失效請求您要重新獲取最受歡迎的,以及最受歡迎的。

這是通過在無效請求主體中放置資源URL(實際URL — 而不僅僅是路徑)清單來實現的:

POST /dispatcher/invalidate.cache HTTP/1.1

CQ-Action: Activate
CQ-Handle: /content/my-brand/home/path/to/some/resource
Content-Type: Text/Plain
Content-Length: 207

/content/my-brand/home.html
/content/my-brand/campaigns/landing-page-1.html
/content/my-brand/campaigns/landing-page-2.html
/content/my-brand/products/product-1.html
/content/my-brand/products/product-2.html

當Dispatcher看到此請求時,它將像往常一樣觸發自動失效,並會立即將請求排入隊列,以便從發佈系統重新獲取新內容。

與現在一樣,我們使用的是請求正文,我們還需要根據HTTP標準設定內容類型和內容長度。

Dispatcher還在內部標籤按照URL,以便它知道即使這些資源被自動無效視為無效,也可以直接傳遞這些資源。

所有列出的URL都被逐個請求。 因此,您無需擔心在發佈系統上建立過高負載。 但您也不想將太多URL放在該清單中。 最後,需要在有界的時間內處理隊列,以便不在太長時間內提供陳舊內容。 只需包括您10個最常訪問的頁面。

如果查看Dispatcher的快取目錄,您將看到標籤有時間戳的臨時檔案。 這些是當前正在後台載入的檔案。

引用

helpx.adobe.com — 取消驗證快取頁AEM面

屏蔽發佈系統

Dispatcher通過保護發佈系統免受僅用於維護目的的請求的影響,提供了一些額外的安全性。 例如,您不想公開 /crx/de/system/console 公共的URL。

在系統中安裝Web應用程式防火牆(WAF)不會造成任何傷害。 但這會為您的預算增加很多,而且並非所有項目都處於一種他們負擔得起、並且 — 不要忘記 — 運營和維護WAF的境地。

我們經常看到的是Dispatcher配置中的一組Apache重寫規則,這些規則可防止訪問更易受攻擊的資源。

但你也可以考慮另一種方法:

根據Dispatcher配置, Dispatcher模組綁定到特定目錄:

<Directory />
  SetHandler dispatcher-handler
  …
</Directory>

但是,當你需要在之後過濾掉時,為什麼要將處理程式綁定到整個操作程式?

可以首先縮小處理程式的綁定範圍。 SetHandler 只需將處理程式綁定到目錄,即可將處理程式綁定到URL或URL模式:

<LocationMatch "^(/content|/etc/design|/dispatcher/invalidate.cache)/.\*">
  SetHandler dispatcher-handler
</LocationMatch>

<LocationMatch "^/dispatcher/invalidate.cache">
  SetHandler dispatcher-handler
</LocationMatch>

…

如果執行此操作,請不要忘記始終將dispatcher-handler綁定到Dispatcher的無效URL,否則您將無法將無效請求從發送器發AEM送到Dispatcher。

使用Dispatcher作為篩選器的另一個替代方案是在 dispatcher.any

/filter {
  /0001  { /glob "\*" /type "deny" }
  /0002  { /type "allow"  /url "/content\*"  }

我們不是要求使用一個指令而不是另一個指令,而是建議適當混合所有指令。

但我們確實建議您考慮盡可能早地在鏈中縮小URL空間,並盡可能以最簡單的方式縮小。 但要記住,這些技術並不能取代高度敏感網站上的WAF。 有人稱這些技術為「窮人的防火牆」 — 這是有原因的。

引用

apache.org-sethandler指令

helpx.adobe.com — 配置對內容篩選器的訪問

使用規則運算式和Globs進行篩選

早期,您只能使用「globs」(簡單佔位符)在Dispatcher配置中定義篩選器。

幸運的是,在Dispatcher的後期版本中,這一點已經改變。 現在,您也可以使用POSIX規則運算式,並且可以訪問請求的各個部分來定義篩選器。 對於剛剛開始調度員的人,這可能是理所當然的。 但如果你過去只有全球杯,那就有點意外,很容易被忽視。 除了globs和regexes的語法太相似了。 讓我們比較兩個相同的版本:

# Version A

/filter {
  /0001  { /glob "\*" /type "deny" }
  /0002  { /type "allow"  /url "/content\*"  }

# Version B

/filter {
  /0001  { /glob "\*" /type "deny" }
  /0002  { /type "allow"  /url '/content.\*'  }

看到區別了嗎?

版本B使用單引號 ' 標籤 規則運算式。 「任意字元」通過使用 .*

環形圖案,相反,使用雙引號 " 只能使用簡單的佔位符 *

如果您知道這一區別,那將是微不足道的,但如果不知道,您可以輕鬆地將引文混為一談,花一個陽光明媚的下午調試配置。 現在你被警告了。

「我認得 '/url' 在配置中……但那是什麼 '/glob' 你會問的過濾器?

該指令表示整個請求字串,包括方法和路徑。 它可以

"GET /content/foo/bar.html HTTP/1.1"

這是您的模式將與之進行比較的字串。 初學者會忘記第一部分, method (GET,POST,…) 所以,一個模式

/0002 { /glob "/content/\*" /type "allow" }

將始終失敗,因為「/content」與「GET…」不匹配 請求。

所以當你想用Globs

/0002 { /glob "GET /content/\*" /type "allow" }

是對的。

對於初始拒絕規則,例如

/0001 { /glob "\*" /type "deny" }

沒事。 但是,對於後續的允許,使用請求的各個部分會更好、更清晰、更安全:

/method
/url
/path
/selector
/extension
/suffix

就這樣:

/005  {

  /type "allow"
  /method "GET"
  /extension '(css|gif|ico|js|png|swf|jpe?g)' }

注意,可以在規則中混合規則運算式和全局表達式。

關於"行號"的最後一句 /005 在每個定義之前,

根本沒意義! 可以為規則選擇任意分母。 使用數字並不需要花太多精力去考慮一個方案,但要記住,順序很重要。

如果你有數百條這樣的規則:

/001
/002
/003
…
/100
…

而且您想在/001和/002之間插入一個,後續數字會發生什麼情況? 你是在增加他們的人數嗎? 是否在數字之間插入?

/001
/001a
/002
/003
…
/100
…

或者,如果您更改為重新排序/003和/001,您是要更改名稱及其身份,還是要更改

/003
/002
/001
…
/100
…

編號,雖然一開始看起來是簡單的選擇,但從長遠來看,它達到了極限。 老實說,選擇數字作為標識符是一種糟糕的寫程式風格。

我們想提出一種不同的方法:很可能,您不會為每個單獨的篩選器規則提供有意義的標識符。 但它們可能有更大的用途,所以它們可以按照目的以某種方式分組。 例如,「基本設定」、「應用程式特定例外」、「全局例外」和「安全性」。

然後,您可以相應命名和分組規則,並提供配置的讀取器(您親愛的同事),檔案中的某些方向:

  # basic setup:

  /filter {

    # basic setup

    /basic_01  { /glob "\*"             /type "deny"  }
    /basic_02  { /glob "/content/\*"    /type "allow" }
    /basic_03  { /glob "/etc/design/\*" /type "allow" }

    /basic_04  { /extension '(json|xml)'  /type "deny"  }
    …


    # login

    /login_01 { /glob "/api/myapp/login/\*" /type "allow" }
    /login_02 { … }

    # global exceptions

    /global_01 { /method "POST" /url '.\*contact-form.html' }

您很可能會向其中一個組添加新規則,甚至可能會建立新組。 在這種情況下,要更名/重新編號的項數將限於該組。

警告

更複雜的設定將過濾規則拆分為多個檔案,這些檔案由主檔案包括 dispatcher.any 配置檔案。 但是,新檔案不會引入新的命名空間。 因此,如果一個檔案中有規則「001」,另一個檔案中有規則「001」,則會出錯。 更有理由用語義上強的名字來命名。

引用

helpx.adobe.com — 為全局屬性設計模式

協定規範

最後一個小費不是真的小費,但我們覺得還是值得和你分享。

而AEM調度員在大多數情況下都是開箱即用。 因此,您找不到有關無效協定的全面的Dispatcher協定規範,無法在上面構建您自己的應用程式。 這些資訊是公開的,但有些分散在許多資源上。

我們試圖在這裡在一定程度上填補空白。 這是無效請求的外觀:

POST /dispatcher/invalidate.cache HTTP/1.1
CQ-Action: <action>
CQ-Handle: <path-pattern>
[CQ-Action-Scope]
[Content-Type: Text/Plain]
[Content-Length: <bytes in request body>]

<newline>

<refetch-url-1>
<refetch-url-2>

…

<refetch-url-n>

POST /dispatcher/invalidate.cache HTTP/1.1 — 第一行是Dispatcher控制項終結點的URL,您可能不會更改它。

CQ-Action: <action> — 發生什麼。 <action> 為:

  • Activate: 刪除 /path-pattern.*
  • Deactive: 刪除 /path-pattern.*
    和刪除 /path-pattern/*
  • Delete: 刪除 /path-pattern.*
    和刪除
    /path-pattern/*
  • Test: 返回"ok"但不執行任何操作

CQ-Handle: <path-pattern> — 要失效的內容資源路徑。 注意, <path-pattern> 其實是"路",不是"模式"

CQ-Action-Scope: ResourceOnly — 可選:如果設定此標題, .stat 檔案。

[Content-Type: Text/Plain]
[Content-Length: <bytes in request body>]

如果定義自動重取URL清單,請設定這些標題。 <bytes in request body> 是HTTP正文中的字元數

<newline> — 如果您有請求正文,則必須將其與標題分隔為空行。

<refetch-url-1>
<refetch-url-2>
…
<refetch-url-n>

列出在失效後要立即重新提取的URL。

其他資源

Dispatcher快取概述和簡介: https://helpx.adobe.com/tw/experience-manager/dispatcher/using/dispatcher.html

已說明包含所有指令的Dispatcher文檔: https://helpx.adobe.com/tw/experience-manager/dispatcher/using/dispatcher-configuration.html

一些常問問題: https://helpx.adobe.com/tw/experience-manager/using/dispatcher-faq.html

記錄有關Dispatcher優化的網路研討會 — 強烈建議: https://my.adobeconnect.com/p7th2gf8k43?proto=true

2018年波茨坦會議"內容失效的低估力"、"適應()" https://adapt.to/2018/en/schedule/the-underappreciated-power-of-content-invalidation.html

從以下位置取消驗證快取AEM頁: https://helpx.adobe.com/tw/experience-manager/dispatcher/using/page-invalidate.html

下一步

本頁內容