C++ ときどき ごはん、わりとてぃーぶれいく☆

Wonder Rabbit Projectのなかのひとのブログ。主にC++。

UE4/C++: http(s) リクエストに FHttpModule 系を使う場合の OnProcessRequestComplete/FHttpRequestCompleteDelegate の成否フラグの注意どころ

UE4FHttpModuleOnProcessRequestComplete / FHttpRequestCompleteDelegate には若干、罠どころがある💀

// UE4/C++ でフレームワークに用意された方法で HTTP リクエストを発行し、
// HTTP レスポンスを得て何かしたい場合のコード例

auto http = &FHttpModule::Get();
auto req = http->CreateRequest();

// ↓罠どころ
req->OnProcessRequestComplete().BindLambda( []( auto req, auto res, auto suc ) { /* ... do something ...*/ } );

// ... URLやメソッドの設定が続き ...

// リクエストを処理
req->ProcessRequest();

「罠どころ」とコメントを付けた OnProcessRequestComplete / FHttpRequestCompleteDelegate へ束縛するラムダ式( or 束縛可能なオブジェクト)の第3引数が注意の必要なところ。

// OnProcessRequestComplete/FHttpRequestCompleteDelegate の関数としての型(の擬似コード)
void OnProcessRequestComplete
( FHttpRequestPtr HttpRequest
, FHttpResponsePtr HttpResponse
, bool bSucceeded // <-- これ💀
);

↑のようになっているので、例えば GET でコンテントを拾ってくるような場合に、束縛するファンクター内で bSucceeded を見ればコンテントの取得成否を確認できそうな気がする。実際間違いではなく、コンテントの取得に成功している場合には、このフラグは true で呼ばれる。

では、この第3引数の何が罠かと言うと、「 HTTP レスポンスが帰って来ればレスポンスのステータスコードがエラー系であっても true となる可能性がある」点が罠どころ。接続先のホストが存在しないとか、応答しないとか、そういう場合は false となるのでコンテント取得の成否として期待通りの false を得られる。しかし、オシャレなエラーページなどのコンテントの乗ったレスポンスは帰って来るが、 HTTP ステータスコードが 404 や 500 あるいは 302 などの場合にも bSucceededtrue となり得て、それは大抵の場合は "リクエストにおいて期待したコンテント" の取得に対しては偽陽性的な応答で、そのような場合にも実装者は false がこのフラグに与えられる事を期待してしまいかねない罠がある。

// 例えば適当なポエムのテキストデータを HTTP で GET リクエストし、
// ポエムのテキストデータが得られた場合にはポエムを表示、
// 得られなかった場合には失敗の表示を行いたい的な擬似コード
[] ( auto, auto res, auto suc )
{
  if ( suc )
  {
    // 404, 500, 302 などのレスポンスステータスコードの場合も 200 と一緒にこちらへ分岐してしまう
    UE_LOG( LogTemp, Log, *res->GetContentAsString() )
  }
  else
  {
    // こちらへ来るのは接続がそもそも失敗したなどの場合
    UE_LOG( LogTemp, Log, TEXT( "FAILED!" ) )
  }
}

"リクエストにおいて期待したコンテント" の取得の成否の判定は次のように行う必要がある。

[] ( auto, auto res, auto suc )
{
  if ( suc && res->GetResponseCode() >= 200 && res->GetResponseCode() < 300 )
  {
    // "リクエストにおいて期待したコンテント" が得られた場合にのみここへ分岐する
  }
}

参考

  1. IHttpResponse | Unreal Engine
  2. IHttpRequest::OnProcessRequestComplete | Unreal Engine
  3. Http-requests - Epic Wiki