Topics & News
マピオンラボリニューアルしました。

Mapion マピオンラボ Java Google App Engine for Java、Slim3のWEBアプリを独自ドメインに切り替えるとき

Google App Engine for Java、Slim3のWEBアプリを独自ドメインに切り替えるとき

nowmapion_iwazer.png

休日に「なうまぴおん」のサーバ側をしこしこ作った岩澤(Twitterアカウントは@iwazer)です。

うらなんとかディレクターからはGoogle App Engine for Java(GAE/j) そのものやSlim3の使い方的なエントリーキボンヌ言われたんですが、どちらもたいへん使いやすく公式ドキュメントを読むだけでやりたい事がすぐ実装できてしまう!なので公開直前に慌ててやった修正について書きます。

開発中やプレビューリリース中にはGAE/jからデフォルトで与えられるドメイン (name.appspot.com) を使えるので、面倒な設定なしにアプリをアップロードするだけですぐに公開することができます。

その後、正式リリースする際には独自ドメインを取得して、そこでサービスすることになると思います。その際ドメイン変更する前に作られたデータ内に含まれるURLはバッチ処理を書いて直すこともできますが、Twitterなど外部サービスに連携してポストした中に埋め込んだURLまでは変えることができません。

gaeredirect001.png

こういう場合、HTTP REDIRECT 301 Moved Permanently を使って新しいドメインのURLにアクセスしなおしてもらいます。(つうかブラウザが自動でやります)

なうまぴおんはフレームワークにSlim3を使っていますので、Slim3上での実装方法の紹介です。

まず最初、すべてのコントローラのrun()メソッドの最初に埋め込もうかと思ったのですが、小さいアプリケーションとはいえコントローラが10個はあり、機能追加で増える可能性もありますし、だいいちカコワルイ(笑)

共通の親クラスを作ってそのrun()メソッドに書いても、サブクラスのメソッドでsuper.run()を呼び出し忘れると漏れが出ます。

とりあえずrun()メソッドがどうやって呼び出されているか調べようとSlim3のソースコードを除いたところ、ControllerクラスのrunBare()というメソッド内で

  1. setUp()
  2. run()
  3. tearDown()

を呼び出すTemplate Methodパターンとなっています。

setUp()を共通の親クラスでオーバライドしてあげればできそうかと思ったのですが、コードを見るとnull以外を返さないとrun()メソッドが呼ばれてしまうため、GAEのCPU時間がもったいない(笑) リダイレクト先に飛ぶNavigationオブジェクトを返しても、実装を追っていくと最後にresponse.sendRedirect()が呼ばれているため「Moved Temporarily」でリダイレクトされてしまいます。

そこでrunBare()メソッドそのものをオーバーライドして、リダイレクト対象でなければ、super.runBare() すればいいじゃんと気付いたのです。

全てのControllerで次の抽象クラスを継承すれば、旧ドメインから新ドメインへのリダイレクトを全てのURLで行えます。

Slim3RailsのようなURL mappingの仕組みも最初から用意されていて、パラメトリックなURLを綺麗にできるのですが、そこでリライトされたURLでコントローラが呼ばれるため、リダイレクトする前のURLに復元する処理も含まれています。

public abstract class ControllerBase extends Controller {

    @Override
    public Navigation runBare() {
        if (!servletContext.getServerInfo().contains("Development")) {
            String prevPath = BlankUtil.valueOf(
                (String)request.getAttribute("javax.servlet.forward.servlet_path"));
            StringBuffer sb = request.getRequestURL();
            String target = "http://now-mapion.appspot.com";
            if (sb.indexOf(target) == 0) {
                redirectToNewUrl(sb, target, prevPath);
                return null;
            }
        }
        return super.runBare();
    }
    
    private void redirectToNewUrl(StringBuffer sb, String target, String prevPath) {
        String replace = "http://now.mapion.co.jp";
        if (BlankUtil.isBlank(prevPath)) {
            sb.replace(0, target.length(), replace);
        } else {
            sb.setLength(0);
            sb.append(replace).append(prevPath);
        }
        response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
        response.setHeader("Location", sb.toString());
    }

}

ただコレ、慌てて作ったので、他にもっといい方法があったら是非教えて下さい〜

comment
ニックネーム 

はじめまして、cb nanashiと申します。
deployするアプリケーション数に余裕がある、かつデータの移行が容易に行えるという前提条件付きなら、次のような方法が使えるかと思います。

1. 対象のアプリケーションを別のGAEアプリケーションとしてdeployする。このときのapp-idは適当でよい。
2. データを移行する。
3. 独自ドメインに1.のアプリケーションを割り当てる。
4. 元のアプリケーションにリダイレクト専用アプリケーションを(別バージョンとして)deployする。

当方のサイトはこの方法で移行いたしました。新アプリケーションの*.appspot.comのURLは非公開になります。
詳細は以下をご覧頂ければと思います。
http://blog.livedoor.jp/cbnanashi/archives/929483.html

cb nanashi:2010.2.12 20:47

なるほど。この方法ですと、現在本番で動いているGAEの*.appspot.comを知られないので、
独自ドメイン以外で新規に飛んでこられる事がないですね。
あと、本番アプリに本来関係のないリダイレクト処理も必要ないですし、Quota的にも
リダイレクトは別カウントになるのも魅力的。

貴重な情報、ありがとうございました!

岩澤:2010.2.15 20:22

trackback

この記事のトラックバックURLhttp://labs.mapion.co.jp/mtos/mt-tb.cgi/37

Mashup Awards 7 (#MA7)
ユーザーアーカイブ