如何让TDownloadURL.DownloadRawBytes在无ContentType头时跳过字符串转换?
尝试使用Rest.Client单元中的TDownloadURL.DownloadRawBytes从Amazon S3存储桶下载PDF文件,遇到以下问题:
- 服务器返回的ContentType为空,且无法控制服务器端设置正确的ContentType
TRESTRequest.Execute会因ContentType为空,强制将MimeKind设为TMimeTypes.TKind.Text,导致返回的字节被强制转换为字符串- 执行请求时抛出异常:
Project raised exception class EEncodingError with message 'No mapping for the Unicode character exists in the target multi-byte code page'.
疑问:
- 是否有其他更合适的方法可以使用?
- 是否遗漏了强制二进制模式或跳过字符串转换的方式?
- 是否存在不会失败的TEncoding选项?曾寻找可编码所有内容的十六进制编码,但未找到。
1. 使用更直接的HTTP客户端方法
绕过TDownloadURL,改用Delphi自带的THTTPClient(XE8及以上版本支持)处理二进制下载,它不会因ContentType为空触发字符串转换逻辑:
var HttpClient: THTTPClient; ResponseStream: TMemoryStream; begin HttpClient := THTTPClient.Create; ResponseStream := TMemoryStream.Create; try HttpClient.Get('你的S3文件URL', ResponseStream); // 保存或处理二进制流 ResponseStream.SaveToFile('downloaded.pdf'); finally ResponseStream.Free; HttpClient.Free; end; end;
THTTPClient默认以二进制模式处理响应,直接保留原始字节,完全适配PDF这类二进制文件。
2. 强制Rest.Client以二进制模式处理响应
如果必须使用Rest.Client组件,可通过以下方式绕过字符串转换:
- 执行请求前手动设置
TRESTResponse的ContentType为通用二进制类型:
RESTResponse1.ContentType := 'application/octet-stream'; RESTRequest1.Execute; // 直接读取RawBytes属性,避免触发字符串转换 var RawBytes: TBytes; RawBytes := RESTResponse1.RawBytes; TFile.WriteAllBytes('downloaded.pdf', RawBytes);
注意:必须读取RawBytes而非Content属性,Content会触发内部编码转换逻辑,RawBytes直接保留服务器返回的原始字节。
- 也可通过
OnResponseReceived事件提前干预响应类型:
procedure TForm1.RESTRequest1ResponseReceived(Sender: TCustomRESTRequest; Response: TCustomRESTResponse); begin Response.ContentType := 'application/octet-stream'; end;
3. 关于无失败的编码选项
不存在能完美编码任意二进制字节的TEncoding——文本编码是为字符设计的,二进制数据中的非字符字节会破坏编码规则,必然触发异常。
你提到的十六进制编码不属于TEncoding范畴,可通过TNetEncoding.Hex实现字节与十六进制字符串的互转,但会额外增加数据体积,不如直接操作字节流高效。若非要用字符串中转,Base64编码(TNetEncoding.Base64)是更通用的选择,但同样属于额外处理,远不如直接操作二进制流便捷。
内容的提问来源于stack exchange,提问作者Mark Elder

