ネットはつながっている。Wi-Fiも4本立っている。
しかし、アプリの画面には「接続エラー」。
■ 状況
アプリの得点公開機能は、Googleのスプレッドシートにスコアを保存しています。
専用のサーバーを借りずに済むので、重宝しています。
そのランキングが、ある日から取得できなくなりました。
画面には「接続エラー」とだけ表示されます。
■ まず疑ったこと
エラーメッセージが「接続エラー」なので、当然ネットワークを疑います。
しかし機内モードでもなく、他の通信は問題なく動く。ここで手が止まりました。
そこで、アプリが内部で出しているログを順番にたどることにしました。
■ ログをたどる
調べていくと、こういう順番で分かってきました。
- サーバーに問い合わせる処理は、ちゃんと実行されている
- 3秒ほどで「終わった」と返ってきている
- しかし受け取ったデータが空っぽ
つまり「つながっていない」のではなく「つながったのに、中身が空で返ってきている」。エラーメッセージが実態を表していませんでした。
さらに深く見ると、サーバーからの返事の中身が出てきました。
「Page Not Found(ページが見つかりません)」
■ ここで一度、間違えた
私はここで「保存先のURLが無効になったのでは」と考えました。設定を消してしまったか、デプロイ(公開設定)が外れたか。
しかし実際にそのURLをブラウザで開いてみると、正常に生きていました。この推測は外れです。
■ 本当の原因
Googleの仕組みには、少し変わった作法があります。
データを送ると、Googleはその場で結果を返さず、
「結果は別の場所に置いてあります。そちらへどうぞ」
と案内を返してきます。郵便の転送届のようなものです。
普通は、この案内を受け取ったら「その場所を見に行く(=取りに行く)」のが正しい振る舞いです。
ところが今回、アプリは案内を受け取ったあと、転送先に対してもう一度「これを保存してください」と、同じ荷物を送りつけていました。
転送先は受け取り窓口ではなく、ただの保管棚です。荷物を持ち込まれても困る。だから拒否した ─ これが400エラーの正体でした。
家に届いた転送届を見て、転送先の家に元の手紙をもう一度投函しに行っているようなものです。当然、受け取ってもらえません。
■ 直し方
「案内を受け取ったら、そこへは取りに行くだけにする」
これだけです。コードにすると10行ほどの追加で、あっさり動きました。
■ 学んだこと
エラーメッセージを信じすぎない
「接続エラー」と書いてあったのは、単に自分がそう書いたからです。実際は接続できていました。エラー表示は、開発者が想定した原因しか表示してくれません。
ログは面倒でも仕込んでおく
今回、決め手になったのは「サーバーからの返事の中身をそのまま出力する」ログでした。これが無ければ何日かかったか分かりません。
外部サービスは、無料で便利な代わりに、相手の作法に合わせる必要があります。
今回のような「転送」の作法は、公式ドキュメントを読んでいても気づきにくい部分でした。
■ 補足:原因は「Googleの仕様変更」なのか
正直に書くと、分かりません。
同じような報告は他にもあるようですが、確認しきれていません。「いつから壊れたのか」を私自身が把握できていない以上、Googleの仕様変更だと断定するのは違うと思っています。
もともと自分のコードに弱い部分があって、たまたま今まで表面化していなかっただけ、という可能性も残ります。
■ おわりに
原因が分かってしまえば10行の修正でした。それでも、そこにたどり着くまでが調査の本体です。