今更ながらの、HttpURLConnection 障害処理編

障害処理

ネットワークで接続されている相手と通信する場合、仮にプログラムに不具合がなかったとしても、外的要因による何らかの障害が発生することは避けられません。

そのため、障害対策の方針も、障害を無くすというよりは、障害の原因をなるべく早く判明する、という方向に注力することが重要になります。

検知できる例外と、考えられる要因

ネットワーク絡みの障害の原因は非常に多岐に渡るため、全てを並べるのは到底不可能です。よくありそうなものの抜粋と思ってください。

(1)ホスト名が解決できない

発生する例外java.net.UnknownHostException
メッセージ例[ホスト名]
HTTP Status-
発生要因

URLのホスト名が間違っている。

DNSサーバがダウンしている。

(2)サーバとの接続が出来ない(コネクトタイムアウト)

発生する例外java.net.SocketTimeoutException
メッセージ例connect timed out
HTTP Status-
発生要因

URLのIPアドレスが正しくない。

ホストがダウンしている。

ネットワークケーブルが抜けている。

Wi-Fiが接続されていない。

圏外。

(3)ポートでサービスが提供されていない

発生する例外java.net.ConnectException
メッセージ例Connection refused
HTTP Status-
発生要因

URLのポート番号が正しくない。

Webサーバがダウンしている。

(4)URLに該当するリソースが存在しない

発生する例外java.io.FileNotFoundException
メッセージ例[URL]
HTTP Status404
発生要因

間違ったホストに接続している。

URLのディレクトリ名やファイル名が正しくない。

サーバに必要なディレクトリやファイルが存在しない。

(5)応答なし(レスポンスタイムアウト)

発生する例外java.net.SocketTimeoutException
メッセージ例Read timed out
HTTP Status-
発生要因

サーバの負荷が高い。

(6)URLへのアクセスが禁止されている

発生する例外java.io.IOException
メッセージ例Server returned HTTP response code: 403 for URL: [URL]
HTTP Status403
発生要因

URLが正しいリソースを示していない。

認証したユーザが正しくない。

(7)サーバー内部エラー

発生する例外java.io.IOException
メッセージ例Server returned HTTP response code: 500 for URL: [URL]
HTTP Status500
発生要因

サーバプログラムの不具合。

上記障害の中で、よく問題になるのが(自戒の念も込めて)「(5)応答なし(レスポンスタイムアウト)」です。

タイムアウトは、あくまでもクライアント側で検知するものなので、ホスト側の処理は続行している可能性があります。

タイムアウトだからといって、安易にリトライなどを行うと、サーバ側でのセッション管理に影響して、障害となる可能性があります。

また、更新処理の場合、二重更新となってしまう可能性もあります。

障害発生時の継続処理の切り分けについて

正常に結果を読み込めたケース以外は、全てエラーとするのであれば、例外が発生したケースは全てエラーとしてしまえば、それで終わりです。

しかし、「コネクトタイムアウト」の場合、一時的な場合もあるのでリトライにより解決する可能性もあります。何秒かおきに数回リトライしてみるのは、悪くない考えです。

そこで問題となるのが、障害発生原因の切り分けが難しいという事実です。

「コネクトタイムアウト」と「レスポンスタイムアウト」は、GETメソッドの場合、発生する箇所も発生する例外も同じなので、切り分けるすべがありません。

HTTP固有の問題で処理を切り分ける場合も同様です。

認証が必要なケースでは、ユーザに入力を促す必要がありますが、認証が必要なケースもサーバ内部エラーも、発生する箇所も発生する例外も同じなので、切り分けるすべがありません。

違いは例外のメッセージだけですが、メッセージはVMの実装により変わる可能性があるので、メッセージで切り分けを行うのは、かなりリスキーです。

そのあたりを切り分ける必要が生じた場合、やっとHttpURLConnectionの出番です。

もう一つ、どうしてもHttpURLConnectionを使わなければならないケースが、リダイレクトの対応です。

URLConnectionは、サーバがリダイレクトを返した場合、自動的にリダイレクトを行い、その結果のみを返します。プログラム側からは、リダイレクトが発生したかどうかを検知できないので、時により問題となります。

HttpURLConnectionを使うことにより、必要に応じてリダイレクトを抑止することが出来ます。

他の関連ドキュメント

1.今更ながらの、HttpURLConnection Get編

2.今更ながらの、HttpURLConnection Post編

3.今更ながらの、HttpURLConnection 障害処理編

4.今更ながらの、HttpURLConnection (やっと)HttpURLConnectionを使う編