简体   繁体   English

Delphi FMX:HTTPClient异步Post在Windows中工作,在Android中失败

[英]Delphi FMX: HTTPClient asynchronous Post works in Windows, Fails in Android

I'm using THTTPClient in Delphi 10.3 to perform a POST operation and bring data from a server. 我在Delphi 10.3中使用THTTPClient执行POST操作并从服务器中获取数据。 Parameters are JSON. 参数是JSON。 Problem is: 问题是:

  • When compiled as a Win32 application, it works perfectly for both when performing a asynchronous call or not. 当编译为Win32应用程序时,无论是否执行异步调用,它都可以完美地工作。
  • When compiled as an Android app, it fails in the async call and works fine in the normal way. 当编译为Android应用程序时,它会在异步调用中失败,并且可以正常方式正常运行。

The failure error indicates that somehow the request is not passing the json parameters (that only happens in async mode). 失败错误表明请求以某种方式未传递json参数(仅在异步模式下发生)。 For example: if the remote server requires to pass two parameters (say, name and age) I'll get the remote error that "name is a mandatory field". 例如:如果远程服务器需要传递两个参数(例如,名称和年龄),我将收到“名称是必填字段”的远程错误。

My code is based on a Delphi download sample. 我的代码基于Delphi下载示例。 Is there something I should change for this to work in Android? 我需要更改一些内容才能在Android中使用它吗? Thanks! 谢谢!

Here is the relevant code: 以下是相关代码:

//the content  of mmoParams.Text is a JSON string:
//{"name":"somebody","salary":"1000","age":"51"}

Params := TStringStream.Create(mmoParams.Text, TEncoding.UTF8);
Params.Position := 0;
// prepare the request
HTTPClient.ContentType := 'application/json';
HTTPClient.Accept      := 'application/json';
if chkAsync.IsChecked then begin
    // prepare the request
    HTTPClient.ContentType := 'application/json';
    HTTPClient.Accept      := 'application/json';
    // make the request and handle in the callback
    HTTPResult:= HTTPClient.BeginPost(DoEndPost,edtURL.Text,Params);
end
else begin
    // make the request
    HTTPResponse       := HTTPClient.Post(edtURL.Text,Params);
    // handle response
    lblStatusCode.Text := HTTPResponse.StatusCode.ToString;
    mmoResult.Text     := HTTPResponse.ContentAsString(TEncoding.UTF8);
end;

and here's the callback procedure for when the async call (BeginPost) is made. 这是进行异步调用(BeginPost)时的回调过程。

procedure TMainForm.DoEndPost(const AsyncResult: IAsyncResult);

begin
  try
    HTTPResponse := THTTPClient.EndAsyncHTTP(AsyncResult);
    TThread.Synchronize(nil,
      procedure
      begin
          // handle result
         lblStatusCode.Text := HTTPResponse.StatusCode.ToString;
         mmoResult.Text     := HTTPResponse.ContentAsString(TEncoding.UTF8);
      end);
  finally
  end;
end;

As suggested by @DaveNottage, an anonymous thread with standard Post was my best solution so far. 正如@DaveNottage所建议的那样,到目前为止,具有标准Post的匿名线程是我最好的解决方案。 This is the function I've been using quite succesfully so far. 到目前为止,这是我一直非常成功使用的功能。

I call it from the main program with the destination url, the params that will be sent as JSON and a Callback Procedure that will handle the HTTPResponse received. 我从主程序中调用它,并带有目标URL,将作为JSON发送的参数以及将处理收到的HTTPResponse的回调过程。

procedure HTTPPostAsync(HTTPClient: TNetHTTPClient; url, params: string; CallBack: HTTPClientProc);

var
  Thread: TThread;

begin

  // define the thread
  Thread := TThread.CreateAnonymousThread (
      procedure
      var
          HTTPResponse: IHTTPResponse;
          JSon        : TStringStream;
      begin
            Json   := TStringStream.Create(Params, TEncoding.UTF8);
            Json.Position := 0;

            HTTPClient.ContentType := 'application/json';
            HTTPClient.Accept      := 'application/json';
            HTTPClient.ConnectionTimeout := 20000;
            HTTPClient.ResponseTimeout   := 20000;
            try
                HTTPResponse:= HTTPClient.Post(url,Json);
                TThread.Synchronize (TThread.CurrentThread,
                    procedure
                    begin
                        Callback(HTTPResponse);
                    end
                );
            finally
                Json.Free;
            end;
      end
  );

  // let it roll
  Thread.start;
end;

Just copy files from {$BDS}/source/rtl/net from 10.2.3 into your project directory and cut non-exist function GetEncodingMIMEName into 'utf-8' everywhere. 只需将文件{10.2.3中的{$ BDS} / source / rtl / net复制到您的项目目录中,然后将不存在的函数GetEncodingMIMEName切成“ utf-8”即可。 This fix works fine, but it will better if Embarcadero will stop make stupid bugs with every release 此修复程序可以正常运行,但如果Embarcadero在每个发行版中都停止制造愚蠢的错误,那就更好了

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM