GAE のサイトがモバイルフレンドリーテストにパスしなかった件【追記あり】

2015年4月23日 21:39

Google は2015年4月21日から検索エンジンに新アルゴリズムを導入し、スマートフォンで検索した際にスマホ対応ページが用意されている(=モバイルフレンドリー)サイトを優遇するようになった。逆に言えば、スマホ対応がなされていないサイトは検索時のランクが落ちてしまうという、結構シビアなアルゴリズム変更であったわけだ。

当サイトもなんとかランク落ちを避けたい一心で、3月中旬ぐらいにあわててスマホ対応を行なった。ところが、Google の モバイルフレンドリーテスト を試したところ、「要求された url を取得できませんでした」というエラーが表示されテストをパスできなかった。当サイトは Google App Engine(GAE)にて作成・運用しているが、同じく GAE で作った他のサイトをモバイルフレンドリーテストにかけてみると、問題なくパスするものとエラーになるものがあった。そしてこの原因が、/robots.txt にアクセスした際に返すステータスコードが 404 か 500 かによることを突き止めたわけである。もちろん、パスしなかったのは 500 を返すほうだ。

……と、ここまではツイートに書いたとおりだが、この後あれこれ追試していてさらにややこしい事態が発生した。404 を返すサイトでもモバイルフレンドリーテストで同様のエラーになってパスしないものがあったのだ。

しばらく悩んだが、ログを精査してみて妙なことに気づいた。

192.168.0.1 - - [23/Apr/2015:02:52:37 -0700] "GET /robots.txt HTTP/1.1" 404 188 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" "test1.appspot.com" ms=4 cpu_ms=2 cpm_usd=0.000021 app_engine_release=1.9.19 instance=00c61b117cc896dc47429eaf4c4c88a12ecdd7
192.168.0.1 - - [23/Apr/2015:02:52:53 -0700] "GET /robots.txt HTTP/1.1" 404 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" "test2.appspot.com" ms=81 cpu_ms=0 app_engine_release=1.9.19

上がパスしないほうで、下がパスするほうのアクセスログ(一部改変)だ。よくよく見ると、上は 188 バイトのデータ転送を行なっており、且つインスタンスの情報まで記録されている。おそらく Google の bot がこれを通常の 404 だと解釈しなかったのが原因ではないか、と。

あまり引っ張っるのもアレなので結論を先に言うと、パスしなかったほうのサイトは webapp2.Router オブジェクトに登録されたどのルートにもマッチせずに Not Found となっているケース。パスしたほうは、マッチした先に robots.txt が存在しなかったケースである。もうちょっと具体的に説明すると、パスしなかったほうはこんな感じ(app.yaml と main.py の例)。

- url: /.*
  script: main.app
app = webapp2.WSGIApplication([
    ('/', 'HomeHandler'),
], debug=true)

一方、パスしたほうはといえば、こんな感じ(こちらは app.yaml のみ)。

- url: /
  static_dir: htdocs

試したわけではないが、webapp2.Router を使う場合も適宜エラーハンドラを登録して正規の 404 を返すようにしておけば問題ない気がする。

def handle_404(request, response, exception):
    response.write('Oops! I could swear this page was here!')
    response.set_status(404)

app = webapp2.WSGIApplication([
    ('/', 'HomeHandler'),
], debug=true)
app.error_handlers[404] = handle_404

2015/04/25 追記

telnet で直接ブラウズしてみたところ、明らかな違いが判明した。モバイルフレンドリーテストにパスしなかったサイトの /robots.txt へのアクセスはこんな感じになっていた。

$ telnet xxxxx.appspot.com 80
Trying 74.125.23.141...
Connected to appspot.l.google.com.
Escape character is '^]'.
GET robots.txt HTTP/1.0

HTTP/1.0 302 Found
Location: http://www.google.com/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Fri, 24 Apr 2015 07:33:19 GMT
Server: sffe
Content-Length: 219
X-XSS-Protection: 1; mode=block
Alternate-Protocol: 80:quic,p=1

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
Connection closed by foreign host.

要は 404 ではなく 302 を返していたのだ。302(Found)はリクエストしたリソースが一時的にそのURLに存在せずに別の URL にある場合に使用するステータスコードだが、独自ドメインが設定されていてなお且つ appspot.com の URL でアクセスした場合にもこれを返すようだ。

念のため、割り当てた独自ドメインの URL でアクセスしてみたところ、こちらは以下のとおり 404 となった(ヘッダ部のみ記載)。そして、モバイルフレンドリーテストも問題なくパスした。

$ telnet hogehoge.fugafuga.com 80
Trying 173.194.72.121...
Connected to ghs.googlehosted.com.
Escape character is '^]'.
GET robots.txt HTTP/1.0

HTTP/1.0 404 Not Found
Date: Fri, 24 Apr 2015 07:35:47 GMT
Content-Type: text/html; charset=UTF-8
Server: ghs
Content-Length: 1425
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic,p=1

蛇足ながらというか当初、ニーモニックのサイトは独自ドメインの URL でテストしたにもかかわらずパスしなかった理由も分かった。じつはリクエストしたリソースが見つからない場合に Internal Server Error になっていたのが原因であった。お恥ずかしながら。