iOS/Android上でRestAPIの実行が非常に遅い

解決


のぶ  2022-04-07 07:21:41  No: 150144  IP: [192.*.*.*]

インターネット上のDataSnapサーバへRestAPI(httpsではなくhttp)を発行する
下記のとおり簡単なサンプルプログラムをFMXで作成したのですが、
iOS及びAndroidの場合、RESTRequest.Executeを実行後、10KB程度のJSONデータを取得するのに
8秒もかかってしまいます。(NetHTTPRequest.Getでも同様)

同じサンプルプログラムでターゲットプラットフォームを
Windowsに切り替えて実行すると1秒もかからず、取得できます。

Wi-Fiの問題ではないかと思い、「HTTPBot」というiOSアプリのRestAPIクライアントで
実行するとWindowsと同様1秒もかからず、取得できました。

Delphiのバージョンは最新の「Embarcadero® Delphi 11 バージョン 28.0.44500.8973」です。

ちなみに自社のホームページのURLで実行するとHTMLは47KB程度ですが
1秒程度で取得できました。

状況的にDataSnap側の問題ではないように思うのですが、
FMXのマルチデバイスアプリで何か通信の問題があるのでしょうか?


<サンプルプログラム抜粋(URLは伏せてあります)>

procedure TForm1.Button1Click(Sender: TObject);
var
  RESTClient: TRESTClient;
  RESTRequest: TRESTRequest;
  RESTResponse: TRESTResponse;
begin
  RESTClient := TRESTClient.Create(nil);
  RESTRequest := TRESTRequest.Create(nil);
  RESTResponse := TRESTResponse.Create(nil);
  RESTRequest.Client := RESTClient;
  RESTRequest.Response := RESTResponse;
  try
    RESTClient.BaseURL := 'http://xxx.xxx.xxx.xxx:8080/';
    RESTClient.Params.AddHeader('Content-Type', 'application/json; charset=utf-8');
    RESTClient.Params.AddHeader('ID', '1');
    RESTClient.Params.AddHeader('Password', '1');
    RESTRequest.Method := rmGET;
    RESTRequest.Resource := 'api/v1/test/datalist';
    RESTRequest.Response := RESTResponse;
    RESTRequest.Execute;
   memo1.Lines.Add(RESTRequest.Response.JSONValue.ToString);
  finally
    RESTResponse.Free;
    RESTClient.Free;
    RESTRequest.Free;
  end;
end;

編集 削除
take  2022-04-07 23:50:40  No: 150145  IP: [192.*.*.*]

TRESTClientは使ったことがないのですが
HTMLではなくてJSON形式のデータを要求する場合は
コンテンツタイプを指定するパラメータに

application/json

を指定する必要があるかと思います。
指定しない場合はHTML形式のデータが返ってくると思って
待機してしまうので時間がかかっているものと思われます。

編集 削除
mam  2022-04-08 00:11:06  No: 150146  IP: [192.*.*.*]

追加情報ですが
RESTRequest.AcceptEncoding:='gzip, deflate, br';
を入れると圧縮されて、速くなるみたいです。

編集 削除
のぶ  2022-04-08 01:21:21  No: 150147  IP: [192.*.*.*]

takeさん、mamさん
ご回答大変ありがとうございます。

残念ながら、下記のContetType、AcceptEncodingのロジックを
それぞれ入れて試しましたが、現象は変わらずでした。
DataSnap側の問題の可能性も考えてみたいと思います。


    RESTClient.ContentType := 'application/json';

    RESTClient.Params.AddHeader('Content-Type', 'application/json');

    RESTRequestParameter := RESTRequest.Params.AddItem;
    RESTRequestParameter.ContentType := ctAPPLICATION_JSON;
    RESTRequestParameter.name := 'Content-Type';
    RESTRequestParameter.Value := 'application/json';

    RESTRequest.AcceptEncoding:='gzip, deflate, br';

編集 削除
のぶ  2022-04-08 01:24:43  No: 150148  IP: [192.*.*.*]

チェックした覚えがないのに解決になってしまいました。
まだ未解決の状態です。

編集 削除
take  2022-04-08 03:41:46  No: 150149  IP: [192.*.*.*]

この辺は参考になりませんか?
RESTデバッガが付いてるの知らなかった・・・

Delphi Community Edition Meet up ! - REST 編
https://qiita.com/CYonezawa/items/e20c3018c6eb6e1200a0

【Delphi】REST クライアントライブラリを使う
https://qiita.com/ht_deko/items/eb3f987c50012109e781

編集 削除
のぶ  2022-04-08 05:26:37  No: 150150  IP: [192.*.*.*]

takeさん、ありがとうございます。
参考にはなりませんでした。
DataSnap側から問題切り分けをしてみたいと思います。
解決するまで経過報告させていただきます。

編集 削除
のぶ  2022-04-08 07:46:32  No: 150151  IP: [192.*.*.*]

経過報告なります。

DataSnap側ではOracleDBからデータを取得し、JSON形式で返却していました。

問題切り分けのため、下記メソッドのとおり、返却するJSONデータを予めファイルに保存しておき、
APIのリクエストを受信時に当該ファイルの中身をそのまま戻り値に設定して試しましたが、
やはり8秒ほど時間がかかりました。

今後、下記を試してみたいと思います。
①RestAPIのリクエスト時のパラメータ等に違いがないかどうかをサーバ側で確認する。
②httpではなくhttpsで通信してみる。

※最初のご質問に一部訂正がありました。申し訳ございません。
10KB程度のJSONデータではなく、116KBでした。ファイルを抜き出したとき、欠けていました。


<DataSnap側のRestAPIのメソッド>
function test.datalist(Key: String): TJSONValue;
begin
  Result := TJSONValue(TJSONObject.ParseJSONValue(TFile.ReadAllText(ExtractFilePath(Application.ExeName) +  'datalist.json')));
end

編集 削除
のぶ  2022-04-08 10:05:52  No: 150152  IP: [192.*.*.*]

経過報告なります。
②httpではなくhttpsで通信してみる。
⇒nginx経由ですが現象同じでした。遅いです。

編集 削除
take  2022-04-10 23:25:03  No: 150154  IP: [192.*.*.*]

レスポンスヘッダの内容や返り値にエラーを示すものが含まれていませんか?
タイムアウトかなにかが起きているものと思われます。

編集 削除
のぶ  2022-04-11 02:32:33  No: 150155  IP: [192.*.*.*]

tateさん
エラーを示すものは含まれていません。
DataSnap側では遅延なく処理を終えていますので、
クライアント側に問題があるのだと思います。
エンバカデロ・テクノロジーズ社に問い合わせてみます。

編集 削除
take  2022-04-11 02:42:35  No: 150156  IP: [192.*.*.*]

海外の掲示板ですが
https://stackoverflow.com/questions/58686047/how-to-force-trestrequest-contenttype-to-be-ctapplication-json

下記の様に書かれていました。

  AParameter := RESTRequest.Params.AddItem;
  AParameter.ContentType := ctAPPLICATION_JSON;
  AParameter.name := 'Content-Type';
  AParameter.Value := 'application/json';

JSON取得に この方法でだめなら

RESTRequest.Params.AddHeader('Content-Type', 'application/json');

はどうですか?

さらに強制的にしていする場合は
 
 RESTRequest.Body.Add(AJSONString, ctAPPLICATION_JSON);
 
 のようにしましょう
 
 RESTRequest.AddParameter('Content-Type'、'application / json'、TRESTRequestParameterKind.pkHTTPHEADER、[poDoNotEncode]); 

編集 削除
のぶ  2022-04-11 06:54:34  No: 150157  IP: [192.*.*.*]

tateさん
何れも試してみましたが、だめでした。
色々とお調べいただいて、本当にありがとうございます。
感謝いたします。
エンバカデロ・テクノロジーズ社には問い合せをしました。
何らか結果が出ましたら、ご報告いたします。

編集 削除
のぶ  2022-04-11 08:45:57  No: 150158  IP: [192.*.*.*]

取り急ぎ、ご報告ですが、
問題切り分けのため、jsonファイルにhtmlタグをつけて、HTMLファイルにし、WEBサーバ上で
直接ダウンロードするだけに単純化しました。

RESTRequest.Executeは速く、
memo1.Lines.Addの実行でやたらと遅いことがわかりました。
http通信ではなく、TStream系の問題がありそうです。
ただし、jpgなど画像をダウンロードし、700KBの画像をTImageに表示するのは速いです。

   RESTClient.BaseURL := 'http://xxx.xxx.xxx.xxx:8080/';
   RESTRequest.Resource := 'datalist.html';
   RESTRequest.Execute;
  memo1.Lines.Add(RESTRequest.Response.JSONValue.ToString);

編集 削除
のぶ  2022-05-09 05:32:33  No: 150191  IP: [192.*.*.*]

エンバカデロ・テクノロジーズ社からはまだ返答がない状態です。
ただ、RESTRequestの問題ではなく、下記のTMemoのLines.Addで遅いことがはっきりしました。
通常そのような使い方はしませんので、本件、CLOSEさせていただきます。

memo1.Lines.Add(RESTRequest.Response.JSONValue.ToString);

実際は、RESTRequestでJSONデータを取得後、TGridPanelLayoutへの表示で非常に時間が掛かっていたのですが、
描画前後にBeginUpdate、EndUpdateを実行すると問題ない速度になりました。

RESTRequest実行前後でどこで時間が掛かるのか、TMemoでログを表示して遅い部分を判断していたのですが、
実行イベントが一通り完了してから、ログが表示されていたので、RESTRequestの実行に問題があると
誤認したことが問題でした。お騒がせ致しました。

編集 削除