2017-03-13

GAE(Python 2.7) + Django 1.5 + SSLのcron jobsで301エラー

独自ドメインを使ってGoogle App Engineで運用しているサイトがあって、cronがうまく動かずにかなりハマりました。なんとか解決できたので、私がやった解決法を書いておきます。

同じような症状でエラーが出ている人はあまりいないと思いますが、もし当てはまったら参考にして下さい。

環境はだいたい以下のとおり。

  • Google App Engine
  • Python 2.7
  • 独自ドメイン(カスタムドメイン)で運用
  • SSL対応
  • Django 1.5

設定はうまくできてるはずなのにcron jobsが起動すると失敗するという症状が出ました。

ブラウザで直接URLを入力すると問題なく動いているのに、cronで動かすとなぜか失敗になってしまいます。

ログを調べてみるとcronでのアクセスのHTTPステータスコードが301になっている。他方でブラウザでURLを入力してアクセスした場合には200になっている。

GAEのcron jobsは、HTTPステータスコードを200番台で返さないとエラーになるということは知ってたので、301が返ってきている以上は失敗するというのは分かります。

でも、なぜ301リダイレクトになるのかが全く分かりませんでした。

かなり苦労して分かった原因は、Djangoのsettings.pyのMIDDLEWARE_CLASSESに設定していたSSLRedirectの設定でした。

そんな設定をしてたのをすっかり忘れてたけど、グーグルが全てのサイトでSSL対応することを推奨し始めた数年前に自分で設定してたのです。

せっかくSSL対応したのだからセキュリティのためとSEOのためにhttpに来たアクセスを自動で全てhttpsに301リダイレクトするために、sslmiddlewareを設定していたのです。

参考URL

具体的にはDjangoのsettings.pyのこの部分です。


MIDDLEWARE_CLASSES = (
    .........
    .........
    'appname.middles.sslmiddleware.SSLRedirect',
)

cron.yamlにターゲットを設定をしてない場合、cronが起動するとデフォルトのバージョンのURLにアクセスが発生します。

このデフォルトのバージョンというのは、ログを見てみると独自ドメインで運用している場合でも、最初に与えられるドメインであるappspot.comの方です。

しかも、httpsではなく、httpの方にアクセスが発生します。

例えば、以下のような設定で独自ドメインを使っている場合。

  1. デフォルトのドメイン(http) -> http://appname.appspot.com/
  2. デフォルトのドメイン(https) -> https://appname.appspot.com/
  3. 独自ドメイン(http) -> http://www.appname.com/
  4. 独自ドメイン(https) -> https://www.appname.com/

1と2は最初にデフォルトで与えられるドメインで、httpでもhttpsでもどちらでもアクセスできるようになっていると思います。

私の場合はそれに独自ドメインを設定して、SSL対応しているので4を中心に運用しています。

先ほどのsslmiddlewareを使って、3のhttpへのアクセスを全て自動的に4のhttpsの方に301リダイレクトしていました。

この様な設定の状態の時にcronが起動すると、1の指定したパスにアクセスが発生します。

するとsslmiddlewareによって自動的に2のhttpsの方に301リダイレクトが発生してしまうのです。

これが原因で、cronが失敗していたのです。

これを解決するためには、cronで起動するパスに対してだけ301リダイレクトをさせないという設定をする必要があります。

urls.pyにcronで起動させるパスを記述して、新たに別のssl_urls.pyというファイル作って残りを全て分離してそちらに移しました。

そして、分離したssl_urls.pyをincludeで呼び出し、それに{'SSL':True}を設定しました。

これでcronで起動させるパスに対しては301リダイレクトが生じずに、それ以外のパスに対しては301リダイレクトが生じるという設定になります。

このように設定してようやくcronで動かしても200が返ってきて無事に動きました。

urls.pyはこんな感じです。


urlpatterns = patterns('',
    # Cron
    (r'^cron/example/$', cron_example),
    (r'^cron/........),
                       
    # SSL
    (r'^.*?', include(appname.ssl_urls), {'SSL':True}),
)

注意が必要なのは「r'^.*?',」の部分です。最後に$が要りません。最後に$をつけるとどこのパスにアクセスしてもトップページが表示されるというおかしな事になってしまいました。

結局、すごく簡単で単純な事が原因だったので、同じような失敗をしている人はほとんどいないと思いますが、参考にしてみて下さい。

0 件のコメント:

コメントを投稿