无法使用 RestResponse 接收 contentType "application/pdf"
Cannot receive contentType "application/pdf" using RestResponse
我的应用程序使用 "application/json" 发送数据(个人信息)。如果数据有效,则服务器通过 "application/pdf" 向我发回 PDF 文件。但是当 RestResponse 到达时,会弹出一个异常:"No mapping for the unicode character exists in the target multibyte code page"。我不知道发生了什么。在过去的 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;
您确定错误是在 RRequest.Execute()
调用中发生的吗?当您阅读 RResponse.Content
属性 时,您正在尝试将 PDF 数据作为 String
接收,因此我希望该调用会出现 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;
我的应用程序使用 "application/json" 发送数据(个人信息)。如果数据有效,则服务器通过 "application/pdf" 向我发回 PDF 文件。但是当 RestResponse 到达时,会弹出一个异常:"No mapping for the unicode character exists in the target multibyte code page"。我不知道发生了什么。在过去的 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;
您确定错误是在 RRequest.Execute()
调用中发生的吗?当您阅读 RResponse.Content
属性 时,您正在尝试将 PDF 数据作为 String
接收,因此我希望该调用会出现 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;