wp_remote_retrieve_response_code():応答のステータスコードを読む(WordPress)

WordPress

wp_remote_get() などで取得した応答から、ステータスコード(200・404・429 など)を数値で取り出します。相手が 404 や 500 を返しても wp_remote_get() は WP_Error にはならないので、うまく取得できたかはこの関数で見ます。つながらなかったとき(WP_Error)は、空の文字列が返ります。

書き方

wp_remote_retrieve_response_code( array|WP_Error $response ): int|string
  • $response:wp_remote_get()・wp_remote_post() などの戻り値です。
  • 戻り値:ステータスコードの数値(int)です。$response が WP_Error のときなどは、空の文字列('')です。

使い方の例

作業環境(WordPress 7.1.2)で試した結果を、コメントに書いています。

$response = wp_remote_get( home_url( '/' ) );
var_dump( wp_remote_retrieve_response_code( $response ) ); // int(200)
echo wp_remote_retrieve_response_message( $response );     // OK

// ないページ
$response = wp_remote_get( home_url( '/no-such-page-xyz/' ) );
var_dump( is_wp_error( $response ) );                      // bool(false)(404 でも WP_Error ではない)
var_dump( wp_remote_retrieve_response_code( $response ) ); // int(404)
echo wp_remote_retrieve_response_message( $response );     // Not Found

// つながらない URL(今回は作業環境のサイトの :1 番のポート)
$response = wp_remote_get( $unreachable_url, array( 'timeout' => 3 ) );
var_dump( is_wp_error( $response ) );                      // bool(true)
echo $response->get_error_code();                          // http_request_failed
var_dump( wp_remote_retrieve_response_code( $response ) ); // string(0) ""

コードで分けて、429 なら待つ秒数を返す

外の API を呼ぶときは、「つながらなかった」「取得できた」「呼びすぎ(429)」「それ以外の失敗」の順に分けておくと、あとで原因を追いやすくなります。429 と 503 のときは、Retry-After のヘッダーに入った秒数を、待つ時間として返します。

取得してコードで分ける関数
function my_fetch( $url ) {
    $response = wp_remote_get( $url, array( 'timeout' => 10 ) );
    if ( is_wp_error( $response ) ) {
        return array( 'ok' => false, 'retry' => 60, 'error' => $response->get_error_code() );
    }
    $code = wp_remote_retrieve_response_code( $response );
    if ( 200 === $code ) {
        return array( 'ok' => true, 'body' => wp_remote_retrieve_body( $response ) );
    }
    if ( 429 === $code || 503 === $code ) {
        $retry = wp_remote_retrieve_header( $response, 'Retry-After' );
        return array( 'ok' => false, 'retry' => ctype_digit( $retry ) ? (int) $retry : 60 );
    }
    return array( 'ok' => false, 'retry' => 0, 'code' => $code );
}

429 は、pre_http_request のフィルターで「429 と Retry-After: 120 が返った」ことにして試しました。ほかは作業環境のサイトを実際に取得した結果です。

my_fetch( home_url( '/' ) );                  // ok: true(body に本文)
my_fetch( home_url( '/no-such-page-xyz/' ) ); // ok: false, retry: 0, code: 404
my_fetch( $busy_url );                        // ok: false, retry: 120(429・Retry-After: 120)
my_fetch( $unreachable_url );                 // ok: false, retry: 60, error: http_request_failed

返ってきた retry が 0 より大きければ、その秒数のあとに取り直します。WordPress の中なら wp_schedule_single_event() で、あとから動く処理として予約する形が考えられますが、この部分は試していません。Retry-After が日時の形で返るときの扱いは、wp_remote_retrieve_header() のページの例を見てください。

気をつけること

  • 先に is_wp_error() を見る:つながらなかったときは空の文字列が返るので、$code >= 400 のような比べ方では失敗に気づけません。試したところ、WP_Error のときの '' >= 400 は false になりました。
  • 数値で比べる:戻り値は int なので、'200' === $code は合いません(試したところ false)。200 === $code のように数値で比べます。
  • リダイレクトはたどったあとのコード:wp_remote_get() はリダイレクトを自動でたどるので、最後に表示されたページのコードになります。今回検証したサイトの /wp-sitemap.xml は、そのままでは 200、'redirection' => 0 を付けると 302 でした。
  • 説明の言葉(Not Found など)がほしいときは wp_remote_retrieve_response_message() を使います。

関連する関数

  • wp_remote_retrieve_header():取得した応答のヘッダーを読む
  • wp_remote_retrieve_response_message():ステータスコードの説明の言葉を読む
  • wp_remote_retrieve_body():本文を取り出す
  • status_header():自分のページのステータスコードを決める
  • add_query_arg():取得する URL にパラメーターを足す

参考

逆引きリファレンスの一覧へ