I'm using Delphi 10.4 (with patches 1, 2 and 3) on Windows 10 64bit to build a VCL Web Client application.
I have an API running on RAD Server, and I can get information from it using the below VCL Webclient application with no trouble. However, when I try to insert data into the API resources through a POST
method, I got the following error message from the TRESRequest.Execute()
method call:
No mapping for the Unicode character exists in the target multi-byte code page
Though I got this error message, the JSON data is being sent to the API and is saved to the database correctly. It seems that at a certain point of the Execute()
method, an error is generated after the data has been sent to the server.
I've already tried TEncoding.UTF8.GetBytes()
, TEncoding.ASCII.GetBytes()
, and Unicode
, without success.
This is my code:
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;
SERVER SIDE code:
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;
Configuration of REST components is as follows :
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, text/plain; q=0.9, text/html;q=0.8,'
RestRequest1.AcceptCharset := 'utf-8;q=0.8';
RestResponse1.ContentEncoding := '';
RestResponse1.ContentType := '';
New Server Side Code (worked fine):
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;
So now, new questions arise :
Why does this same program work fine in Delphi 10.3.1 Tokyo under Windows 7, but now in Delphi 10.4 Sydney (patches 1,2,3) on Windows 10 it requires UTF-8 encoding? Is it a Delphi 10.4 issue? Is it a Windows 10 issue?
In my original server side code, I have many Endpoints sending responses using the command
AResponse.Body.SetValue(myJSONObject, True);
Should I replace all of them by the two new commands?Strm := TStringStream.Create(jo.ToJSON, TEncoding.UTF8); AResponse.Body.SetStream(Strm, 'application/json', true);
Code of REST.Client unit where the error is occuring :
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;
...