delphi – TRestClientTRestRequest错误地解码gzip响应

delphi – TRestClientTRestRequest错误地解码gzip响应,第1张

概述我试图读取一个REST API,它是gzip编码的.确切地说,我试图阅读StackExchange API. 我已经找到了问题Automatically Decode GZIP In TRESTResponse?,但由于某种原因,这个答案并没有解决我的问题. 测试设置 在XE5中,我添加了TRestClient,TRestRequest和具有以下相关属性的TRestResponse.我设置了客户端 @H_403_4@ 我试图读取一个REST API,它是gzip编码的.确切地说,我试图阅读StackExchange API.

我已经找到了问题Automatically Decode GZIP In TRESTResponse?,但由于某种原因,这个答案并没有解决我的问题.

测试设置

在XE5中,我添加了TRestClIEnt,TRestRequest和具有以下相关属性的TRestResponse.我设置了客户端的BaseURL,请求的资源和参数,并将请求的AcceptEnCoding设置为gzip,deflate,这应该使它自动解码gzipped响应.

object RESTClIEnt1: TRESTClIEnt    BaseURL = 'https://API.stackexchange.com/2.2'  end  object RESTRequest1: TRESTRequest    AcceptEnCoding = 'gzip,deflate'    ClIEnt = RESTClIEnt1    Params = <      item        Kind = pkURLSEGMENT        name = 'ID'        Options = [poautocreated]        Value = '511529'      end      item        name = 'site'        Value = 'stackoverflow'      end>    Resource = 'users/{ID}'    Response = RESTResponse1  end  object RESTResponse1: TRESTResponse  end

这导致url:

07001

我调用这样的请求,有两个消息框来显示url和请求的结果:

ShowMessage(RESTRequest1.GetFullRequestURL());RESTRequest1.Execute; // Actual callShowMessage(RESTResponse1.Content);

如果我在浏览器中调用该URL,我会得到一个正确的结果,这是一个Json对象,其中包含我的一些用户信息.

问题

但是,在Delphi中,我没有得到JsON响应.实际上,我得到了一堆字节,这似乎是一个错误的gzip响应.我尝试使用TIDCompressorZlib.DecompressGZipStream()解压缩它,但它失败并出现Zlib错误(-3).当我自己检查响应的字节时,我看到它从#1F#3F#08开始.这特别奇怪,因为gzip标题应该是#1F#8B#08,所以#8B转换为#3F,这是一个问号.

所以在我看来,RESTClIEnt试图将gzip流解码为好像是UTF-8响应,并且用问号替换了无效序列(#8B本身不是有效的UTF-8字符).

尝试(表面)

我做了很多实验,比如

>使用RESTResponse.RawBytes并尝试解码它.我注意到这个字节数组中的字节已经无效. TRESTResponse来源中的评论告诉我’RawBytes’已经被解码,所以这是有道理的.
>将RESTResponse.RawBytes保存在一个文件中,并尝试使用7zip和几个在线gzip解压缩程序对其进行解压缩.当然,它们都失败了,因为即使是gzip标头也是错误的.
>将值’gzip,deflate’分配给TRESTClIEnt.AcceptEnCoding,TRESTResponse.AcceptEnCoding及其组合.还尝试将其附加到每个组件的预填充Accept属性.
>从经过身份验证的请求切换到未经身份验证的请求.我有整个oAuth部分工作,但我认为这会使问题过于复杂.我在这个问题中使用的匿名API也有同样的问题.

不幸的是它仍然无效,我仍然得到了错误的回应.

尝试(深入VCL)

最后,我挖了一点,然后潜入TRestRequest.Execute.我不会在这里粘贴所有代码,但最终它会通过调用来执行请求

FClIEnt.httpClIEnt.Get(LURL,LResponseStream);

FClIEnt是链接到请求的TRESTClIEnt,LResponseStream是TMemoryStream.我将LResponseStream.Savetofile(‘…’)添加到手表中,因此它会保存这个未经处理的结果,等等,它给了我一个有效的gz文件,我可以解压缩以获取我的JsON.

解决方案中的错误?

但是,接下来几行,我看到这段代码:

if FClIEnt.httpClIEnt.Response.CharSet > '' then  begin    LResponseStream.position := 0;    S := FClIEnt.httpClIEnt.ReadStringAsCharset(LResponseStream,FClIEnt.httpClIEnt.Response.CharSet);    LResponseStream.Free;    LResponseStream := TStringStream.Create(S);  end;

根据此块上面的注释,这样做是因为内存流的内容“未根据可能存在的EnCoding或Content-Type Charset参数进行编码”,这被VCL代码的编写者认为是Indy中的错误.

所以基本上,这里发生了什么:原始响应被视为一个字符串并转换为’正确’编码. FClIEnt.httpClIEnt.Response.CharSet是’UTF-8′,它确实是JsON的编码,但不幸的是,这种转换只能在解压缩流之后才能完成,但尚未完成.所以我认为这是一个错误. 总结

以上是内存溢出为你收集整理的delphi – TRestClient / TRestRequest错误地解码gzip响应全部内容,希望文章能够帮你解决delphi – TRestClient / TRestRequest错误地解码gzip响应所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1265336.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存