如何从THTTPReqResp获取响应头?
我有一些使用如何从THTTPReqResp获取响应头?,http,delphi,http-headers,delphi-10.3-rio,Http,Delphi,Http Headers,Delphi 10.3 Rio,我有一些使用THTTPReqResp的旧代码,这将调用Execute来执行针对Exchange Web服务的SOAP请求。 我将其修改为(也)使用OAuth登录。这工作正常,但我无法检测访问令牌何时过期 在使用nSoftware IP*Works的TipwHTTP组件的测试应用程序中,我可以通过响应头来检测指示过期令牌的响应头: with ipwHTTP do try PostData := ABody; Post(cBaseURL); except on
THTTPReqResp
的旧代码,这将调用Execute
来执行针对Exchange Web服务的SOAP请求。我将其修改为(也)使用OAuth登录。这工作正常,但我无法检测访问令牌何时过期 在使用nSoftware IP*Works的
TipwHTTP
组件的测试应用程序中,我可以通过响应头来检测指示过期令牌的响应头:
with ipwHTTP do
try
PostData := ABody;
Post(cBaseURL);
except
on e:Exception do
begin
// A special header is returned when the token has expired:
// Header x-ms-diagnostics: 2000002;reason="The token has expired.";error_category="invalid_lifetime"
for l := 0 to ParsedHeaders.Count-1 do
if (Pos('x-ms-diagnostics',ParsedHeaders[l].Field) <> 0)
and (Pos('2000002',ParsedHeaders[l].Value) <> 0) then
begin
FTokenExpired := true;
Break;
end;
...
end;
end;
带ipwHTTP do
尝试
PostData:=ABody;
Post(cBaseURL);
除了
关于e:Exception-do
开始
//令牌过期时将返回一个特殊标头:
//标题x-ms-diagnostics:2000002;原因=“令牌已过期。”;错误\u category=“无效\u生存期”
对于l:=0到ParsedHeaders.Count-1 do
if(位置('x-ms-diagnostics',解析标题[l]。字段)0)
和(Pos('2000002',ParsedHeaders[l].Value)0)然后
开始
FTokenExpired:=真;
打破
结束;
...
结束;
结束;
使用THTTPReqResp
或THTTPReqResp.HTTP
时,在哪里/如何访问标题?
该组件包含类型为THTTPClient
的HTTP
属性,但我对此毫无进展。
文档说明THTTPClient
具有
和事件,但在THTTPClient
或其类助手的代码中找不到这些事件。
这些事件的文档参考了System.Net.HttpClientComponent.tnethttpprequest
而不是System.Net.THTTPClient
,并且System.Net
中没有HttpClientComponent
注:
- 这是Delphi 10.3.1 Rio;在10.3中,
发生了显著的代码更改THTTPReqResp
有一个带有这两个事件的System.Net.HttpClientComponent
,一条评论说它是一个用于管理HTTPClient的组件,但该代码似乎没有链接(即,TNetHTTPClient
从未使用)HttpClientComponent
- 可能相关的是,组件调色板中有一个
(和TNetHTTPClient
,它们是网络文件夹中仅有的两个),但没有TNetHTTPRequest
。这似乎表明THTTPClient
仅用于“发动机罩下”THTTPClient
也有一个HTTP(TNetHTTPClient
)属性,如THTTPClient
,但两者之间没有继承关系THTTPReqResp
THTTPReqResp
在Delphi 10.3中接受了鸟枪手术。最初它在Windows上使用WinINet,在Linux上使用Indy,但他们将其改为THTTPClient
(我想是为了支持移动平台)
在这个新的实现中,THTTPReqResp
方法(Get
,Execute
)和事件(OnBeforePost
,OnReceivingData
)都没有公开请求
或响应
对象
但是,如果服务器以错误HTTP状态代码(>=300)响应,则有机会通过全局OnHttpError
处理程序访问Response
对象。使用过程Soap.SOAPHTTPTrans.SetOnHttpError
安装全局处理程序。它的第二个参数是HTTPResponse:IHTTPResponse
,用于检查返回的头。如果服务器以1xx或2xx状态响应,那么您就不走运了,应该考虑实现自定义<代码> TTTPREQRESP< <代码>子孙或迁移到更合适的HTTP客户端实现(例如,代码> THTTPlient < /C> >,或类似)。
在我个人看来,这是一种非常丑陋的处理此类情况的方式,我只是不明白为什么他们在新代码中引入了全局处理程序,这会影响THTTPReqResp
的所有实例。我对这个新设计一点也不感兴趣
鹰眼:你注意到
THTTPReqResp
(THTTPClient
,esoaphttpeexception
)和SetOnHttpError
(tsoaphttperroevent
,tsoaphttperroaction
)之间的字符大小写不一致吗?令牌过期时的状态码是什么?@Peter这是401,因此,我无法在此基础上区分其他错误。我只是想确定globalOnHttpError
handler是否适用于您的场景。这是服务器返回非2xx状态代码时的情况-请参阅答案。相关:谢谢。是的,很难看。我要么尝试这个,要么重写所有内容以使用TNetHTTPClient(或者更好,因为我们已经有了TipwHTTP),而不是THTTPReqResp。但这是相当多的工作,因为我必须收集所有返回数据并将其组装成XML文件。好的,漂亮的鹰眼,麦格弗。比我的hhtp或htpp打字错误要好;-)更新:我确实重写了代码,用TipwHTTP替换了THTTPReqResp。
{ assuming HTTPReqResp1: THTTPReqResp is a component on TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
SetOnHttpError(HTTPReqRespError);
end;
procedure TForm1.HTTPReqRespError(const HTTPReqResp: THTTPReqResp;
const HTTPResponse: IHTTPResponse; const Error: ESOAPHTTPException;
var Action: TSOAPHttpErrorAction);
begin
if (HTTPReqResp = HTTPReqResp1) and StartsText('2000002', HTTPResponse.HeaderValue['x-ms-diagnostics']) then
begin
FTokenExpired := True;
Action := TSOAPHttpErrorAction.heaAbort; { or whatever }
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FTokenExpired := False;
try
{ ... }
{ HTTPReqResp1.Get or HTTPReqResp1.Execute or whatever }
{ ... }
except
if not FTokenExpired then
raise;
{ handle token expiration here }
end;
end;