AEM開発者ブログ by YAMATO

アドビ社のデリバリーパートナー大和株式会社のAEM開発者ブログです。

AEMサイトにおけるリダイレクト/リライト手法 <前編>

こんにちは。大和株式会社の牧野です。

AEMサイトにおけるリダイレクト/リライト手法の一覧があると便利だと思いブログに纏めてみました。かなりのボリュームになってしまったので前編と後編に分けました。今回は前編となります。

AEMサイトにおけるリダイレクト/リライトの主な目的として以下が挙げられます。

URLのリダイレクトとリソース名変更の理由

1. ユーザビリティ

ユーザーがURLを直接入力することもあるため、URLは直感的で覚えやすいものであることが望ましいです。そのため、リソース名を変更してURLをわかりやすくすることがあります。

2. コンテンツの再編成

ウェブサイトの構造を変更すると、URLも変わることがあります。この場合、古いURLから新しいURLへのリダイレクトを設定することで、リンク切れを防ぎます。

3. マーケティング

特定のキャンペーンやプロモーションに対して独自のURLを設定し、そのアクセス数や効果を測定することがあります。このような場合、元のコンテンツとは別のリソース名で管理することがあります。

4. セキュリティ

特定のリソースに対するアクセスを制限するために、URLのリダイレクトやリソース名の変更を行うことがあります。

リダイレクト/リライト手法一覧

プロジェクトコードとして管理/展開 マーケティング/コンテンツチームによる運用
1. Apache mod_rewrite
2. /etc/map
3. ACS Commons Redirect Manager
4. LocationHeaderAdjuster
5. Alias
6. Vanity URL
7. ACS Commons Redirect Map Manager
8. Redirect Page Property
9. URL Mapping
10. Apache Sling Servlet
11. Vanity Path Rewrite Mapper

上記の表は異なるリダイレクトやURLマッピングの方法を、それらがプロジェクトコードとして管理・展開されるか、マーケティングやコンテンツチームによって運用されるかという観点で比較しています。

前編では1番のApache mod_rewriteから5番のAliasまでを紹介しています。

1. Apache mod_rewrite

Apacheでリダイレクトを設定する方法です。 Apacheに以下のモジュールを追加をしてください。

LoadModule rewrite_module modules/mod_rewrite.so

次にリダイレクトの設定をしていきます。

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^/$ /content/we-retail/us/en/men.html [R,L]
</IfModule>

RewriteEngineをOnにすることでRewriteRuleが有効になりURLのリダイレクトが行われるようになります。

RewriteRuleのシンタックスは以下になります。

RewriteRule Pattern Substitution [flags]
  • Pattern: リクエストURIに適用される正規表現
  • Substitution: マッチングするリクエストURIのリダイレクト先
  • flags (オプション): ルールの動作を制御するためのフラグ

flagsですが、こちらは複数指定することができ、今回の設定ではRとLが指定されています。Rはredirectを意味し、flagsにRを指定することでリダイレクトが行われるようになります。[R=305]のようにステータスコードも指定出来ます。Lはlastを意味し、RewriteRuleがマッチした段階で処理をストップします。この他にPというflagsもあり、これはproxyを意味します。P flagはL flagも含んでおり、P flagの処理が行われた段階で処理がストップするようになっています。P flagを使うことにより、クライエントにリダイレクトが行われたことを隠蔽することが出来ます。

リダイレクトが行われているか確認します。

$ curl -I http://localhost
HTTP/1.1 302 Found
Location: http://localhost/content/we-retail/us/en/men.html

Apacheの設定どおりにリダイレクトが行われていました。

ErrorDocumentを使用することでリクエストのステータスコードに応じてリライトの設定ができます。 ErrorDocumentのシンタックスは以下になります。

ErrorDocument <3-digit-code> <action>
  • 3-digit-code: ステータスコード
  • action: リライト先の内部/外部のURL,またはエラーメッセージを指定

ErrorDocumentを使用するためにDispatcherPassErrorを1に設定します。

DispatcherPassError 1

この設定でDispatcherでエラーレスポンスを処理せず、エラーステータスコードをApacheへ返します。

ErrorDocumentを以下のように設定します。

ErrorDocument 404 /content/myproject/us/404.html

存在しないページへリクエストを送ります。

curl http://localhost/doesNotExist.html

設定したリライトが反映されていることが確認できました。

[rid#10b4118/initial] (2) init rewrite engine with requested uri /doesNotExist.html
[rid#10b4118/initial] (1) pass through /doesNotExist.html
[rid#10b5b78/initial/redir#1] (2) init rewrite engine with requested uri /content/myproject/us/404.html
[rid#10b5b78/initial/redir#1] (1) pass through /content/myproject/us/404.html

2. /etc/map

OSGi Configuration (Resource Resolver Factory)

Property Description
Mapping Location ResourceResolverマッピングを設定し、構成するための設定のルートディレクトリへのパスを指しています。デフォルトでは、このパスは /etc/map となっています。

/etc/map配下にsling:Mappingの設定を行うことでリダイレクト* が設定できます。

以下は任意の[ドメイン名]:[ポート番号]/["/"を除く任意の文字列].htmlを/content/we-retail/us/en/["/"を除く任意の文字列]へリダイレクト*する設定になります。

- etc
  - map
    - http
      - localhost_any
        + jcr:primaryType = "sling:Mapping"
        + sling:redirect = "/content/we-retail/us/en/$1.html"
        + sling:match = "[^/]+/([^/]+)\.html$"
sling:match - リダイレクトをするリクエスト
sling:internalRedirect - リダイレクト先

localhost_anyのノード名を特定のドメイン名、例えばwww.exmaple.comに設定すると、www.exmple.comのリクエストにのみsling:match,sling:redirectが適用されます。

$ curl -w "%{redirect_url}" http://localhost:4503/men.html
http://localhost:4503/content/we-retail/us/en/men.html

上記の設定でリダイレクト*がされていることが確認できました。

次に以下のような設定にします。

- etc
  - map
    - http
      - localhost_any
        + sling:match = "localhost.[0-9]*"
        - redirect
          - example
            + sling:match = "(.*)"
            + sling:internalRedirect = "/content/we-retail/us/en/$1"
      - reverse
        + sling:match = "localhost.4502/redirect/$1"
        + sling:internalRedirect = "/content/we-retail/us/en/(.*)"

localhost:4502/redirect/women.htmlというリクエストを送ると、localhost_anyノードの設定通りlocalhost:4502/content/we-retail/us/en/women.htmlページを取得できます。

/content/we-retail/us/en/women.html

次にこのページからPRODUCTSリンクをクリックします。

reverseノードの設定通りlocalhost:4502/content/we-retail/us/en/products.htmlの外部リンクがlocalhost:4502/redirect/products.htmlになっています。

/content/we-retail/us/en/products.html

* etc/mapでリクエストをリダイレクトする方法は現在ほとんど使われておらず「Apache mod_rewriteでRewriteして、/etc/mapでページ内リンクをExternalizeする」という組み合わせで利用するのが主流となっています。

3. ACS Commons Redirect Manager

ACS AEM CommonsはAEMプラットフォームのデプロイを手助けするためのオースンソースライブラリです。

この中にRedirect Managerというものがあり、これを利用することで簡単にリダイレクトの設定が出来るようになります。

Maange Redirectsを開くとOSGi CONFIGURATION MISSINGと表示されます。

下記の設定を追加後に使用できるようになります。

PID: com.adobe.acs.commons.redirects.filter.RedirectFilter
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="sling:OsgiConfig"
          enabled="{Boolean}true"/>

/conf/globalがデフォルトの設定場所になります。

今回は以下のように設定しました。

Property Required Description
Source Path リダイレクト元。AEMのパスまたは正規表現で指定可能
Target Path リダイレクト先。外部URLと後方参照も可能
Status Code 301, 302, 307, 308から一つ選択
On Time リダイレクトを開始する時刻
Off Time リダイレクトの動作を停止する時間

設定を反映させるためにPublishを行います。

Publishが完了したら、リダイレクトの設定が反映されているか確認します。

$ curl -I http://localhost/content/we-retail/ch/de
HTTP/1.1 302 Found
Location: /content/we-retail/de/de

設定したステータスコードとリダイレクト先のパスが表示されていることが確認できました。

次に/conf/we-retailの中にも同様にリダイレクトの設定を行います。

以下のようにTarget Pathのみを変更してPublishをした後に、リダイレクトの設定が反映されているか確認します。

$ curl -I http://localhost/content/we-retail/ch/de
HTTP/1.1 302 Found
Location: /content/we-retail/us/en/men

/conf/we-retailのリダイレクト設定が優先されていることが確認できました。

リダイレクトの設定をエクセルシートでExport,Import出来るためエクセル上でリダイレクトの設定を変更することも出来ます。

4. LocationHeaderAdjuster

OSGi Configuration (ACS Commons Redirect Filter)

Property Description
Enable Redirect Filter リダイレクトフィルタが有効かどうかを示します。
Rewrite Location Header LocationヘッダーにSlingリソースマッピング(/etc/map)を適用します。LocationヘッダーがResourceResolver#mapを使って書き換えられるべき場合に使用します。
Request Extensions リダイレクトが許可されている拡張子のリスト。
Request Paths リダイレクトが許可されているパスのリスト。
Preserve Query String リダイレクトでクエリ文字列を保持するかどうか。
Preserve Extension 拡張子を保持するかどうか。このフラグがチェックされている場合(デフォルト)、リダイレクトフィルタはリクエストから拡張子を保持。
Evaluate Selectors (非推奨)リダイレクトルールでURIモードを評価してセレクタを取得するために使用します。
Additional Response Headers デリバリー時に適用するname:value形式のオプションのレスポンスヘッダー。例:Cache-Control: max-age=3600
Configuration bucket name リダイレクトルールを保存する親フォルダの名前。デフォルトはsettings。
Configuration Name リダイレクト設定を保存するノードの名前。デフォルトは'redirects'で、これはリダイレクトを保存するデフォルトのパスが/conf/global/settings/redirectsであることを意味します。ここで'settings'はバケットで、'redirects'は設定名です。

先程説明したRedirect Managerのリダイレクト先をカスタマイズできるLocationHeaderAdjusterというインターフェイスがACS AEM Commonsで用意されており、バックエンドでリダイレクトを設定することができます。

LocationHeaderAdjusterインターフェイスを使うには下記をpom.xmlに追加する必要があります。

<dependency>
  <groupId>com.adobe.acs</groupId>
  <artifactId>acs-aem-commons-bundle</artifactId>
  <version>6.0.8</version>
  <scope>provided</scope>
</dependency>

今回は以下の通りに実装します。

package com.example.myproject.core.service;

import com.adobe.acs.commons.redirects.LocationHeaderAdjuster;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.osgi.service.component.annotations.Component;
import java.util.Optional;

@Component(service = LocationHeaderAdjuster.class)
public class MyLocationAdjuster implements LocationHeaderAdjuster {

    private final String PRODUCTS = "products";
    private final String SERVICES = "services";
    private final String WE_RETAIL = "/content/we-retail/ca/en/";
    private final String PRODUCTS_WE_RETAIL = "https://products.we-retail.com/";
    private final String SERVICES_WE_RETAIL = "https://services.we-retail.com/";

    @Override
    public String adjust(final SlingHttpServletRequest request, final String location) {

        return Optional.of(location)
                .filter(loc -> loc.startsWith(WE_RETAIL))
                .map(loc -> StringUtils.substringAfter(loc, WE_RETAIL))
                .map(this::modifyLocation)
                .orElse(location);
    }

    private String modifyLocation(final String loc) {
        if (loc.startsWith(PRODUCTS)) return PRODUCTS_WE_RETAIL + loc;
        if (loc.startsWith(SERVICES)) return SERVICES_WE_RETAIL + loc;
        return WE_RETAIL + loc;
    }
}

Redirect Managerの設定を下記に変更しリクエストを送信します。

Source Path : /content/we-retail/us/en/(.*)
Target Path : /content/we-retail/ca/en/$1

リクエストを送信してみます。

$ curl -I http://localhost/content/we-retail/us/en/women.html
HTTP/1.1 302 Found
Location: /content/we-retail/ca/en/women.html
$ curl -I http://localhost/content/we-retail/us/en/products.html
HTTP/1.1 302 Found
Location: https://products.we-retail.com/products.html
$ curl -I http://localhost/content/we-retail/us/en/services.html
HTTP/1.1 302 Found
Location: https://services.we-retail.com/services.html

インターフェイスの実装通りにリダイレクトされたことが確認できました。

5. Alias

OSGi Configuration (Resource Resolver Factory)

Description
Mapping Observation このパス配下のaliasの追加、変更がリアルタイムでシステムに反映されます。
Optimize alias resolution 有効にするとalias解決を内部キャッシュを利用して最適化します。1万以上のaliasが設定されている場合はスタートアップの時間に影響が生じる可能性があります。

ページのリソース名をAliasを利用して変更することが出来ます。 ページプロパティのAdvancedタブのAliasから設定することが出来ます。

元のパスは/content/we-retail/us/en/menですが、/content/we-retail/us/en/menAliasでも同様のリソースにアクセスすることが出来ます。

最後に

いかかだったでしょうか。6番以降は"AEMサイトにおけるリダイレクト/リライト手法 <後編>"という記事で公開中です。

最後までご覧いただき、ありがとうございました。