RESTRequest.Execute错误-目标多字节代码页中不存在Unicode字符的映射

问题描述

我正在Windows 10 64bit上使用Delphi 10.4(带有补丁1、2和3)来构建VCL Web客户端应用程序。

我有一个在RAD Server上运行的API,使用下面的VCL Webclient应用程序可以毫无问题地从中获取信息。但是,当我尝试通过POST方法将数据插入API资源时,从TRESRequest.Execute()方法调用中收到以下错误消息:

目标多字节代码页中不存在Unicode字符的映射

尽管我收到此错误消息,但JSON数据正在发送到API,并正确保存到数据库中。似乎在Execute()方法的某个点上,将数据发送到服务器后会生成错误

我已经尝试过TEncoding.UTF8.GetBytes()TEncoding.ASCII.GetBytes()Unicode,但没有成功。

这是我的代码

procedure TForm1.BTPostClick(Sender: TObject);
var
  strjson : string;
  jo      : TJSONObject;
begin
  strjson :=
    '{'                                 +
      '"CUST_ID": 1500,'                +
      '"CUST_NAME": "John Doe Max",'    +
      '"CUST_COUNTERTOTAL": "500",'     +
      '"CUST_DETAILS": "This is just a test"' +
    '}';    

  //    jo := TJSONObject.ParseJSONValue(TEncoding.Unicode.GetBytes(Strjson),0) as TJSONObject;
  //    jo := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(Strjson),0) as TJSONObject;
  jo := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(Strjson),0) as TJSONObject;    

  Memo1.Clear;
  Memo1.Lines.Add(jo.ToString);

  RestRequest1.ClearBody;
  RestRequest1.Method := rmPost;
  RestResponse1.ResetToDefaults;
  RestRequest1.AddBody(jo);
  RestRequest1.Execute;   // ==> error: No mapping for the Unicode character exists in the target multi-byte code page
end;

服务器端代码

procedure TMytestResource1.MytestPost(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  s : string;
  i : integer;
  jo : TJSONObject;
begin
  jo := TJSONObject.Create;
  jo.AddPair('Response Line 1','Apple is maçã');
  jo.AddPair('Response Line 2','Foot is pé ');
  jo.AddPair('Response Line 3','There is lá');
  jo.AddPair('Exceção  Line 3',TJsonString.Create('Exception is exceção'));
  //s := jo.ToString;  at this point the characters has accents
  AResponse.Body.SetValue(jo,True);
end;

REST组件的配置如下:

RestClient1.Accept          := 'application/json,text/plain; q=0.9,text/html;q=0.8,';
RestClient1.AcceptCharset   := 'utf-8;q=0.8';
RestClient1.AcceptEnconding := 'utf-8';
RestClient1.FallbackCharsetEncoding := 'utf-8';
RestClient1.ContentType    := 'application/json'
    
RestRequest1.Accept          := 'application/json,'
RestRequest1.AcceptCharset   := 'utf-8;q=0.8';
    
RestResponse1.ContentEncoding := '';
RestResponse1.ContentType := '';

新服务器端代码(工作正常)

procedure TMytestResource1.CadastraUser(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  s : string;
  i : integer;
  jo : TJSONObject;
  Strm : TStringStream;
begin
  jo := TJSONObject.Create;
  jo.AddPair('Response Line 1','Apple  is maçã');
  jo.AddPair('Response Line 2','Foot   is pé');
  jo.AddPair('Response Line 3','There  is lá');
  jo.AddPair('Response Line 4','Useful is útil');

  //AResponse.Headers.SetValue('Content-Type','application/json; charset=utf-8');  ==> This line does not make any effect on response

  try
    // Strm := TStringStream(jo.ToJSON,TEncoding.UTF8); ==> does not work.
    Strm := TStringStream.Create(jo.ToJSON,TEncoding.UTF8);
    // AResponse.Body.SetStream(Strm,'application/json; charset=utf-8',true); ==> This line causes an error on VCL WebClient during RestRequest.Execute() method,error is "Invalid enconding name."

    AResponse.Body.SetStream(Strm,'application/json',true); // this works fine.
  finally
    jo.Free;
  end;   
end;

所以现在出现了新问题:

  1. 为什么相同的程序在Windows 7下的Delphi 10.3.1 Tokyo中也能正常工作,但是现在在Windows 10的Delphi 10.4 Sydney(补丁1,2,3)中,它却需要UTF-8编码?是Delphi 10.4问题吗?是Windows 10问题吗?

  2. 在我原来的服务器端代码中,我有许多端点使用命令AResponse.Body.SetValue(myJSONObject,True);发送响应,我是否应该用两个新命令替换所有端点?

    Strm := TStringStream.Create(jo.ToJSON,TEncoding.UTF8);
    AResponse.Body.SetStream(Strm,true);
    

发生错误的REST.Client单元的代码

Procedure TCustomrestRequest.Execute 

...
              if LMimeKind <> TMimeTypes.TKind.Binary then
              begin
                LEncoding := TEncoding.GetEncoding(FClient.FallbackCharsetEncoding);  //==> This line is returning nil,though FClient.FallbackCharsetEncoding is filled with 'utf-8'
                LContentIsstring := True;
              end;
            end
            else
            begin
              // Even if no fallback,handle some obvIoUs string types
              if LMimeKind = TMimeTypes.TKind.Text then
                LContentIsstring := True;
            end;
          end;
          if LContentIsstring then
            LContent := FClient.HTTPClient.Response.ContentAsstring(LEncoding); // ==> this line is generating the error 
        finally
          LEncoding.Free;
        end;
...

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)