Skip to the content.

届かない、断られる、分からない——ゲームプランナーのためのネットワーク入門⑥

ボタンの先には、要求と応答がある

ログインする。報酬を受け取る。購入を確定する。ランキングを開く。スマホゲームの多くの操作は、端末からサーバーへ要求を送り、その応答を受け取ることで進む。

第5回「途中で変わる回線を前提にする」では、移動や回線の切り替えによって、通信の通り道と品質が変わることを扱った。今回は、その上を通る要求と応答が、どのように失敗するかを考える。第1回の5段の地図では、ゲームの具体的なやり取りを受け持つアプリケーション層の話である。

本編最終回の判断軸は、 HTTPの失敗は「届かなかった」「エラーが返ってきた」「結果が分からない」の3つに分け、それぞれの画面と再試行を仕様で決める ことだ。とりわけ、報酬や購入では、端末に結果が表示されなかったときにも、サーバー側の処理は終わっている可能性がある。


HTTPは、要求と応答の決まり

HTTP(Hypertext Transfer Protocol)は、要求(リクエスト)と応答(レスポンス)をやり取りする決まりである。端末のアプリは要求を出すクライアントとなり、サーバーがそれに応答する。HTTPの意味と基本的な振る舞いを定めるRFC 9110に沿って、まずは応答の読み方を整理しよう。RFC(Request for Comments)は、インターネットの技術仕様などを公開する文書群である。[1]

ステータスコードで、応答の大枠を読む

HTTPの応答には、結果の分類を表す3桁のステータスコードが付く。先頭の数字を見ると、大枠が分かる。次の表はRFC 9110の第15節から、今回使う3分類をまとめたものだ。[1]

分類 意味 仕様を考えるときの読み方
2xx:成功 要求を正常に受信し、理解し、受け入れた 応答内容に従って次の画面へ進めるか判断する
4xx:クライアント側の誤り 要求の書き方に問題がある、または要求を満たせない 要求内容、認証状態、アプリの対応条件などに応じた案内を考える
5xx:サーバー側の失敗 正しいと思われる要求を、サーバーが処理できなかった 待機や復旧の案内、再試行の条件を考える

4xxの「クライアント側」は、プレイヤーの操作ミスを意味する言葉ではない。画面にそのまま「あなたの要求が間違っています」と出すのではなく、アプリが何を直せるか、プレイヤーが次に何をできるかへ翻訳する必要がある。

また、HTTP上の成功と、ゲーム内で目的を達成したことは、応答内容も含めて判断する。画面の分岐には、ステータスコードと、ゲーム側が定めた結果の両方が必要になる。

同じ要求を送り直せるかには、性質の違いがある

HTTPでは、何を求めるかを示す要求の種類を メソッド と呼ぶ。GET、POST、PUT、DELETEなどがあり、RFC 9110の9.2節は、その性質を整理している。[1]

冪等でも、応答が毎回同じになるとは限らない。たとえば、同じ対象の削除を再度求めたときに「すでに存在しない」と返っても、対象が削除された状態になるという効果は変わらない。

RFC 9110は、冪等なメソッドについて、クライアントが応答を読む前に通信が失敗した場合、自動で要求を繰り返せると説明する。一方、POSTは同RFCが冪等とするメソッドの一覧に含まれない。POSTによる処理を再試行できるかは、その処理自体に冪等性があると分かっているなどの条件を確認する必要がある。[1]

プランナーがエンジニアと確認したいのは、「この操作は、応答が失われても同じ要求を送り直せるか」である。API(Application Programming Interface、プログラム同士が機能を呼び出す窓口)の名前だけで判断せず、ランキングの取得と報酬の確定を、それぞれの性質で扱う。

スマホでは、暗号化したHTTPを前提にする

スマホゲームでは、HTTPS、すなわちTLS(Transport Layer Security)で通信路を暗号化して保護するHTTPを前提に考える。

AppleのATS(App Transport Security)は、標準の通信機構を使う接続にTLSによる保護などを求め、最低限の安全要件を満たさない接続を拒否する。iOS 9以降のSDK(Software Development Kit、アプリ開発用の道具一式)にリンクしたアプリでは既定で働く。[2] Androidでも、Android 9(APIレベル28)以降を対象にするアプリでは、暗号化しない通信であるcleartextが既定で無効になる。[3] いずれも例外設定はあるが、通常の設計では暗号化された接続を使う。

HTTP/2・HTTP/3でデータの運び方がどう変わるかは、第4回で扱った。ここでは、その上にある要求の結果と、画面の対応に集中しよう。


ライブラリの結果を、プレイヤーへの対応へつなぐ

UnityのUnityWebRequestは、サーバーへの要求と応答を扱う通信機能である。そのResultは、結果や進行状態を次のように分ける。表は公式説明の大意である。[4]

Result 意味
InProgress 要求がまだ終わっていない
Success 要求が成功した
ConnectionError サーバーと通信できなかった。接続できない、安全な通信路を確立できないなど
ProtocolError サーバーとの通信はできたが、通信の決まりに照らしてエラーとなる応答を受け取った
DataProcessingError 通信はできたが、受信データの処理に失敗した。データの破損や形式の不一致など

この分類を受け取った後、画面と再試行を決めるには、要求が届いたか、処理結果を把握できたかも考える必要がある。本稿では、失敗時の判断を次の3つに整理する。

本稿の整理 起きたこと 次の判断
届かなかった 要求がサーバーに届いていない 接続できる条件を整え、再送の条件を判断する
エラーが返ってきた サーバーが4xxや5xxで失敗を伝えた コードや応答内容に合う案内と待機を選ぶ
結果が分からない 要求は届いたかもしれないが、応答を受け取る前に途切れた 処理結果を確認するか、安全に再試行できるかを判断する

「結果が分からない」は、UnityのResultにある名前ではなく、プレイヤーへの対応を考えるための本稿の整理である。 ConnectionErrorという結果だけで、「要求は届かなかった」とは断定できない。 接続前に失敗したのか、送った後で途切れたのかによって、サーバー側で起きたことは違う。送信前の失敗と確認できなければ、結果不明として扱う判断が必要になる。

この3つは、端末がすべての失敗を機械的に判別できるという分類でもない。DataProcessingErrorのように応答を受け取っても内容を利用できない場合は、別途、データ処理のエラーとして記録し、報酬や購入の結果を把握できたかを確認する。4xxや5xxを受け取った場合にも、そのコードだけから処理途中の変更が一切なかったと決めつけず、APIごとの約束に従う。

スマホとサーバーのHTTPの往復に、要求が届かない例、4xx・5xxの応答を受け取る例、帰りの応答が途切れる例を示した概念図。3つは別々の失敗例で、結果不明の場合はサーバー側の処理が完了したかも不明である。端末だけで失敗位置を特定できるとは限らない。

報酬を確定した直後に帰りの通信が途切れると、端末は成功を知らないままになる。このとき、送り直してよいかの軸になるのが冪等性だ。二重処理を防ぎ、再開時に結果を確かめる設計は、「『受け取る』を一度だけにする――ゲームプランナーのための連打と通信再試行の話」で扱っている。ここでは、結果不明の画面から無条件に同じ購入をやり直させない、という判断を持ち帰ってほしい。


どれだけ待つかを、遊びの仕様にする

タイムアウトとは、通信を待つ時間の上限に達したとして、待機を打ち切ることである。ただし、「何を待つ時間か」は設定によって違う。

AppleのURLSessionは、アプリのデータ送受信を担う仕組みである。その設定には、次の違いがある。

設定 何を待つか 既定値・動作
timeoutIntervalForRequest 次のデータが届くまでの時間 60秒。新しいデータが届くたびにタイマーを数え直す [5]
timeoutIntervalForResource 1つの要求全体にかけてよい時間 7日。要求開始から完了または上限まで数える [6]
waitsForConnectivity 接続できる条件が整うまで待つか オンなら接続できるまで待つ。オフなら接続できない時点ですぐにエラーになる [7]

60秒は、要求全体が必ず60秒で打ち切られるという意味ではない。また、7日という既定値を、そのままログイン画面でプレイヤーを待たせる時間にする必要もない。

waitsForConnectivityが関わるのは接続を確立するときである。確立後に接続が切れた場合はエラーになる。さらに、バックグラウンドセッションではこの設定は無視され、常に接続を待つ。[7] 「待つをオンにすれば、途中で切れてもすべて解決する」という性質ではない。

一方、UnityWebRequest.timeoutは、応答がないときに要求の中断を試みるまでの秒数で、既定値は0である。0はタイムアウトを適用せず、応答を受け取るまで待つ指定だ。[8] 他の原因で失敗することまでなくなるわけではない。

第4回では、配送の確実さに関する既定値がエンジンによって逆になる例を見た。待ち時間も同様に、何も決めなければ、採用した通信機能の既定値が体験を左右する。

プランナーが決めたいのは、たとえば「ランキングは長く待たせず、後でもう一度開ける」「購入は待機を打ち切った後も結果確認へ進める」といった操作ごとの方針である。待っている間の表示、画面を離れられるか、どこで待機を終えるかを決め、エンジニアと設定へ落とし込む。

タイムアウトは、端末が待つのをやめたという結果であり、サーバーの処理が取り消された証拠ではない。 結果が分からない可能性を残したまま、確認中の表示や、次回起動時の確認へつなぐ必要がある。

なお、端末側のタイムアウトと、HTTPの408 Request Timeoutは別である。408は、サーバーが待てる時間内に完全な要求を受け取れなかったことを表す。504 Gateway Timeoutは、中継役のサーバーが必要な上流の応答を時間内に得られなかったことを表す。どちらもHTTPの応答であり、端末が応答を受け取れず待機を打ち切ることと区別する。[1]


サーバーが「今は無理」と伝える

503 Service Unavailableは、一時的な過負荷や予定されたメンテナンスのため、サーバーが現在、要求を処理できないことを示す。RFC 9110の15.6.4節に定められた応答である。[1]

サーバーは、応答に付ける補助情報であるヘッダーのRetry-Afterで、再試行まで待つ時間を示せる。503と一緒に送る場合は、サービスがあとどれくらい利用できないと見込まれるかを伝える。値には日時か秒数を使う。これは同RFCの10.2.3節に定められている。[1] 復旧の見込みなので、画面でも再試行できる時刻と、必ず利用可能になる時刻を混同しないようにしたい。

429 Too Many Requestsは、一定時間に要求を送りすぎたことを表す。要求の頻度を制限することをレート制限といい、このコードを定めるRFC 6585は、429にもRetry-Afterを付けられるとしている。[9]

ゲームのメンテナンス画面や「混み合っています」という案内は、こうした応答をアプリがどう受け止めるかの仕様になる。503だけでメンテナンスと過負荷を区別できるわけではないので、案内を分けるなら、応答内容なども含めて区別する約束が必要だ。Retry-Afterがある場合とない場合も決めておく。

メンテナンス中に何を残し、どの機能や期限を止めるかは、「止まっている間、何を残し、どの時計を止めるか」で扱っている。本稿では、応答を受け取って案内へ進むところまでを考える。


再試行を、一斉に重ねない

再試行は、一時的な失敗から復帰する手段になる。その一方で、過負荷で応答できないサーバーへ要求を増やせば、状況をさらに悪化させうる。

Amazon Builders’ Libraryの「Timeouts, retries, and backoff with jitter」で、Marc Brookerはこの問題を説明し、再試行の待ち時間を指数的に延ばす 指数バックオフ、待ち時間にばらつきを加える ジッター、再試行回数の上限を扱っている。また、状態を変更するなど副作用のあるAPIは、冪等性を備えなければ安全に再試行できないと述べる。[10]

ゲームでの例として、メンテナンス終了直後を考えよう。待っていた多数の端末が一斉に再接続すると、復旧したサーバーに再び要求が集中しうる。待ち時間を延ばしても、全員が同じ間隔で試せば集中は残る。ジッターは、各端末の再試行の時刻を散らす役割を持つ。

仕様としては、「どの失敗なら再試行するか」「間隔をどう延ばすか」「何回で自動再試行を終えるか」「Retry-Afterがあればどう反映するか」をそろえて決める。数値は、操作の緊急度やサーバーの受け入れ能力を踏まえ、エンジニアと相談する。

プレイヤーが押す「再試行」ボタンにも同じ問題がある。連打のたびに新しい要求を出せば、自動再試行を抑えても要求は増える。通信中に押せるか、次に押せるまでどれだけ待つか、手動操作で再試行の上限を無制限にやり直せるかも仕様になる。


エラー画面の表を、結果確認まで含めて作る

次の表は 架空の仕様例 である。特定のゲームの挙動や、HTTPが画面表示を定めていることを示すものではない。自動再試行は、再試行してよい処理だと確認できたものに限る。

「サーバー側の記録」欄には、調査や結果確認のために残したい情報を記した。要求が届いていない場合は、端末側の記録も手掛かりになる。

失敗の種類 画面の文言の方向 自動で再試行するか プレイヤーにできること サーバー側の記録
圏外・通信できない 「通信できません。接続を確認してください」 接続前の失敗と確認できた場合などに、接続待機または上限付きで再試行 接続環境を変える、戻る、間隔を置いて再試行 未到達なら受信記録はない。端末の発生時刻・接続段階と照合
4xx:この例では、ゲーム側の応答内容が更新必須を示す場合 「アプリを更新してください」 同じ要求の繰り返しは止める ストアへ進み、更新する 応答コード、更新必須と判断した理由、アプリの版
503:メンテナンス・過負荷 応答内容に応じて「メンテナンス中」「混み合っています」 Retry-Afterなどに従って待ち、上限付きで再試行 お知らせを見る、待つ、戻る 応答コード、停止理由、返した待ち時間
429:要求が多すぎる 「しばらく待ってからお試しください」 指定の待ち時間などに従い、連続送信を抑える 待つ。待機中は再試行ボタンを押せない 制限の判定理由、返した待ち時間
タイムアウト:結果が分からない 「処理結果を確認しています」 更新処理を無条件に再送せず、結果確認や安全な再試行へ進む 確認を待つ、後で結果を確認する 要求を受けたか、処理が完了したか、結果確認と突き合わせる情報

4xx全般に「更新してください」と表示するわけではない。上の行では、ゲーム側が更新必須と伝える応答を定めている。認証のやり直しが必要な場合などには、別の分岐を設ける。

また、受信記録を見つけられなかったことだけで、未到達を証明できるとは限らない。どの段階で記録を残し、どの情報で照合するかは、エンジニアと決めておく。プレイヤーへの案内と、問い合わせを受けた後の調査を同じ仕様につなげたい。

待機中と、待機を終えた後の行き先

待ち時間には、画面上の出口が必要だ。読み込み中の表示をいつ出すか、長引いたときに案内を変えるか、戻る操作を許すか、画面を閉じた後も結果確認を続けるかを決める。

自動再試行は、短い中断から操作を保ったまま復帰したい場合に向く。手動再試行は、接続環境を変えた後など、プレイヤーが改めて操作するきっかけにできる。どちらにも、再送の安全性、待ち間隔、上限が要る。更新必須のように条件を変える必要がある失敗は、条件を直す案内へ進める。

QAでは、行きと帰りを分けて確かめる

QA(Quality Assurance、品質保証)の計画では、「通信エラーを出す」から一歩進め、次の条件を分けて再現する。


5段の地図から、画面の仕様へ

第1回では、「通信エラー」を5段の地図で切り分けた。各回で見てきた場所を、最後に並べておこう。

回 地図のどこを扱ったか 仕様へ持ち帰る視点
第2回:ケーブルか、電波か 物理層・データリンク層 つなぎ方によって、機材・台数・場所の条件が変わる
第3回:なぜ友だちとつながらないのか ネットワーク層と、トランスポート層の入口 宛先と通信の窓口、双方の接続環境を考える
第4回:届くこと、順番、新しさのどれを守るか トランスポート層を中心とする配送の約束 確実さ・順序・新しさのどれを優先するかを決める
第5回:途中で変わる回線を前提にする 電波や接続の切り替え、事業者側のアドレス変換など、複数の層 移動中に回線の経路と品質が変わる前提で、中断と復帰を作る
第6回:本稿 アプリケーション層 要求の結果、待ち時間、画面、再試行を決める

IPA(Information-technology Promotion Agency、情報処理推進機構)の基本情報技術者試験シラバスでも、アプリケーション層の用語例にHTTP・HTTP/2・HTTP/3、Webの用語例にHTTP over TLS(HTTPS)が挙げられている。[11] 教科書の層の地図は、プレイヤーに見せる画面までつながっている。

プランナーが通信のすべてを実装できる必要はない。「どこで失敗したと分かっているか」「処理結果は確定しているか」「次に何をしてよいか」をエンジニアと共有できれば、仕様書の「通信エラー時は再試行する」を具体化できる。

本編は今回で一区切りとなる。番外編では、 「データ量と通信時間」 を扱う予定だ。何をどれだけ送るのかを、ダウンロードや待ち時間の体験へつなげて考える。

References

1. R. Fielding、M. Nottingham、J. Reschke編「HTTP Semantics(RFC 9110)」 — RFC Editor、2022年6月。9.2節、10.2.3節、15節、15.5.9節、15.6.4〜15.6.5節を参照。本稿の説明は原文の大意による。

2. Apple「Preventing Insecure Network Connections」 — Apple Developer Documentation、日付記載なし。ATSの既定の有効条件と適用範囲を参照。2026年11月2日確認。

3. Android Developers「Network security configuration」 — Android Developers、日付記載なし。「Cleartext traffic」「Configuration inheritance behavior」を参照。既定値はアプリが対象とするAPIレベルに依存する。2026年11月2日確認。

4. Unity「UnityWebRequest.Result」 — Unity 6 Scripting API、6000.6。表は公式説明の大意を訳したもの。2026年11月2日確認。

5. Apple「timeoutIntervalForRequest」 — Apple Developer Documentation、日付記載なし。2026年11月2日確認。

6. Apple「timeoutIntervalForResource」 — Apple Developer Documentation、日付記載なし。2026年11月2日確認。

7. Apple「waitsForConnectivity」 — Apple Developer Documentation、日付記載なし。接続確立時の動作とバックグラウンドセッションの例外を参照。2026年11月2日確認。

8. Unity「UnityWebRequest.timeout」 — Unity 6 Scripting API、6000.6。2026年11月2日確認。

9. M. Nottingham、R. Fielding「Additional HTTP Status Codes(RFC 6585)」 — RFC Editor、2012年4月。4節の429とRetry-Afterを参照。

10. Marc Brooker「Timeouts, retries, and backoff with jitter」 — Amazon Builders’ Library/AWS Builder Center、2019年12月5日。再試行による負荷、指数バックオフ、ジッター、回数上限、冪等性を参照。ページの著者表示はMarc。

11. IPA「基本情報技術者試験(レベル2)シラバス Ver.9.2」 — 情報処理推進機構、2026年1月8日掲載。中分類「ネットワーク」の用語例を参照。


この文書は、Perplexity、Claude、ChatGPT の3つのAIの支援を受けて著述されたものです。引用画像を除き、MIT License にて提供されています。