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;
...