我的应用程序使用" application / json"发送数据(个人信息)。如果数据有效,则服务器通过" application / pdf"向我发回PDF文件。但是当RestResponse到达时,会弹出一个异常:"目标多字节代码页"中不存在unicode字符的映射。我不知道发生了什么事。我在过去的4天里正在研究这个问题,我无法解决这个问题。在行中弹出异常:" RRequest.Execute;"。这是我的代码人员:
procedure TThreadBoleto.Execute;
var
RCtx : TRttiContext;
RType : TRttiType;
RProp : TRttiProperty;
I : integer;
PDF : TFile;
begin
try
try
RClient := TRESTClient.Create('');
with RClient do begin
AcceptEncoding := 'identity';
FallbackCharsetEncoding := 'UTF-8';
Accept := 'application/json;text/plain;application/pdf;';
AcceptCharset := 'UTF-8';
BaseURL := 'https://sandbox.boletocloud.com/api/v1/boletos';
ContentType := 'application/x-www-form-urlencoded';
HandleRedirects := true;
RCtx := TRttiContext.Create;
RType := RCtx.GetType(THRBoleto.ClassType);
I := 0;
for RProp in RType.GetProperties do
begin
Params.AddItem;
Params.Items[I].name := LowerCase(RProp.Name.Replace('_','.'));
Params.Items[I].Value := RProp.GetValue(THRBoleto).AsString;
I := I + 1;
end;
end;
RRequest := TRESTRequest.Create(RRequest);
with RRequest do begin
Accept := 'application/json;text/plain;application/pdf;';
Client := RClient;
Method := rmPost;
SynchronizedEvents := false;
AcceptCharset := 'UTF-8';
end;
RResponse := TRESTResponse.Create(RResponse);
RResponse.ContentType := 'application/pdf;*/*;';
RResponse.ContentEncoding := 'UTF-8';
RAuth := THTTPBasicAuthenticator.Create('','');
with RAuth do begin
Username := 'anAPItokenAccess';
Password := 'token';
end;
RClient.Authenticator := RAuth;
RRequest.Response := RResponse;
RRequest.Execute;
PDF.WriteAllBytes(ExtractFilePath(Application.ExeName)+'boleto.pdf',RResponse.RawBytes);
OutputStrings.Add(RResponse.Content);
OutputStrings.Add('');
OutputStrings.Add('');
OutputStrings.AddStrings(RResponse.Headers);
except on E:Exception do
ShowMessage('Error: '+E.Message);
end;
finally
THRBoleto.Free;
end;
end;
答案 0 :(得分:5)
您确定RRequest.Execute()
来电时发生了错误吗?当您阅读String
属性时,您试图以RResponse.Content
的形式接收PDF数据,因此我希望在该调用上出现Unicode错误。 PDF文件不是文本数据,而是二进制数据,因此接收它的唯一安全方法是使用RResponse.RawBytes
属性。
此外,您根本不应设置RResponse.ContentType
或RResponse.ContentEncoding
属性(更不用说您将它们设置为无效值)。它们将根据收到的实际响应填写。
由于您要将RRequest.Accept
属性设置为包含您愿意在响应中接受的3种不同媒体类型,因此您需要查看RResponse.ContentType
属性值以确保实际接收将RawBytes
保存到.pdf
文件之前的PDF文件。如果您收到文本或JSON响应,则无法将其作为PDF处理。
就个人而言,我发现REST组件非常缺陷。你可能会更好地使用Indy的TIdHTTP
,例如:
uses
..., IdGlobal, IdGlobalProtocols, IdHTTP, IdSSLOpenSSL;
procedure TThreadBoleto.Execute;
var
RCtx : TRttiContext;
RType : TRttiType;
RProp : TRttiProperty;
Client: TIdHTTP;
Params: TStringList;
Response: TMemoryStream;
begin
Client := TIdHTTP.Create;
try
with Client.Request do begin
AcceptEncoding := 'identity';
Accept := 'application/json;text/plain;application/pdf';
AcceptCharset := 'UTF-8';
ContentType := 'application/x-www-form-urlencoded';
BasicAuthentication := True;
Username := 'anAPItokenAccess';
Password := 'token';
end;
Client.HandleRedirects := true;
RCtx := TRttiContext.Create;
RType := RCtx.GetType(THRBoleto.ClassType);
Response := TMemoryStream.Create;
try
Params := TStringList.Create;
try
for RProp in RType.GetProperties do
Params.Add(LowerCase(RProp.Name.Replace('_','.')) + '=' + RProp.GetValue(THRBoleto).AsString);
Client.Post('https://sandbox.boletocloud.com/api/v1/boletos', Params, Response);
finally
Params.Free;
end;
Response.Position := 0;
case PosInStrArray(ExtractHeaderMediaType(Client.Response.ContentType), ['application/pdf', 'application/json', 'text/plain'], False) of
0: begin
// save PDF
Response.SaveToFile(ExtractFilePath(Application.ExeName)+'boleto.pdf');
OutputStrings.Add('[PDF file]');
end;
1: begin
// process JSON as needed
OutputStrings.Add(ReadStringAsCharset(Response, Client.Response.Charset));
end;
2: begin
// process Text as needed
OutputStrings.Add(ReadStringAsCharset(Response, Client.Response.Charset));
end;
else
// something else!
OutputStrings.Add('[Unexpected!]');
end;
finally
Response.Free;
end;
OutputStrings.Add('');
OutputStrings.Add('');
OutputStrings.AddStrings(Client.Response.RawHeaders);
finally
Client.Free;
end;
end;
procedure TThreadBoleto.DoTerminate;
begin
if FatalException <> nil then
begin
// Note: ShowMessage() is NOT thread-safe!
ShowMessage('Error: ' + Exception(FatalException).Message);
end;
THRBoleto.Free;
inherited;
end;