问题描述
我有一些使用THTTPReqResp
的旧代码,它针对针对Exchange Web Services的SOAP请求调用Execute
.
我正在将其修改为(也)使用OAuth登录.效果很好,但是我无法检测访问令牌何时过期.
I have some old code using THTTPReqResp
, this calls Execute
for SOAP requests against Exchange Web Services.
I'm modifying it to (also) use OAuth login. This works fine, but I'm having trouble detecting when an access token has expired.
在使用nSoftware IP * Works中的TipwHTTP
组件的测试应用程序中,我可以遍历响应标头来检测指示令牌已过期的标头:
In a test app using a TipwHTTP
component from nSoftware IP*Works I can go through the response headers to detect the one indicating an expired token:
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;
使用THTTPReqResp
或THTTPReqResp.HTTP
时,我在哪里/如何访问标头?
Where/how can I access the headers when using THTTPReqResp
or THTTPReqResp.HTTP
?
该组件包含类型为THTTPClient
的HTTP
属性,但我对此一无所知.文档使用HTTP客户端指出THTTPClient
具有 OnRequestError 和 OnRequestcompleted 事件,但是在THTTPClient
或其班级助手.这些事件的文档指的是System.Net.HttpClientComponent.TNetHTTPRequest
而不是System.Net.THTTPClient
,,并且在System.Net
中没有HttpClientComponent
.
That component contains a HTTP
property of type THTTPClient
but I'm getting nowhere with that.The documentation Using an HTTP Client states that THTTPClient
hasOnRequestError and OnRequestcompleted events but those are nowhere to be found in the code for THTTPClient
or its class helper.The documentation for these events refer to System.Net.HttpClientComponent.TNetHTTPRequest
not System.Net.THTTPClient
, and there is no HttpClientComponent
in System.Net
.
注意:
- 这是Delphi 10.3.1 Rio;在10.3中,对
THTTPReqResp
的代码进行了重大更改. -
System.Net.HttpClientComponent
有一个包含这两个事件的TNetHTTPClient
,并且注释说它是管理HTTPClient的组件,但是该代码似乎没有链接(即HttpClientComponent
从未使用过) - 可能与此相关的是,组件面板中有一个
TNetHTTPClient
(而TNetHTTPRequest
,这是Net文件夹中仅有的两个),而不是一个THTTPClient
.这似乎表明THTTPClient
仅旨在在幕后"使用.TNetHTTPClient
也具有HTTP(THTTPClient
)属性,例如THTTPReqResp
,但是两者之间没有继承.
- This is Delphi 10.3.1 Rio; in 10.3 significant code changes were made to
THTTPReqResp
. System.Net.HttpClientComponent
has aTNetHTTPClient
with those two events, and a comment says it's a Component to Manage an HTTPClient, but that code does not seem to be linked in (i.e.HttpClientComponent
is never used)- What may be related is that there is a
TNetHTTPClient
in the component palette (andTNetHTTPRequest
, those are the only two in the Net folder), but not aTHTTPClient
. This seems to indicate thatTHTTPClient
is only meant to be used 'under the hood'.TNetHTTPClient
also has a HTTP (THTTPClient
) property, likeTHTTPReqResp
, but there is no inheritance between the two.
推荐答案
您已经发现THTTPReqResp
在Delphi 10.3中进行了shot弹枪手术.最初它是在Windows上使用WinINet,在Linux上是Linux上使用Indy,但是他们将其更改为THTTPClient
(我想是为了支持移动平台).
As you have found out THTTPReqResp
underwent shotgun surgery in Delphi 10.3. Originally it was using WinINet on Windows and Indy on Linux under the hood, but they changed it to THTTPClient
(to support mobile platforms, I guess).
在此新实现中,THTTPReqResp
方法(Get
,Execute
)和事件(OnBeforePost
,OnReceivingData
)都不会暴露Request
或Response
对象.
In this new implementation none of THTTPReqResp
methods (Get
, Execute
) and events (OnBeforePost
, OnReceivingData
) expose Request
or Response
objects.
但是,如果服务器以错误的HTTP状态代码(> = 300)进行响应,则有机会通过全局OnHttpError
处理程序获得对Response
对象的访问.使用过程Soap.SOAPHTTPTrans.SetOnHttpError
安装全局处理程序.它的第二个参数是HTTPResponse: IHTTPResponse
,它使您可以检查返回的标头.如果服务器以1xx或2xx状态进行响应,则说明您不走运,应该考虑实现自定义THTTPReqResp
后代或迁移到更合适的HTTP客户端实现(例如,直接使用THTTPClient
或类似的方式).
There, however, is a chance to gain access to Response
object via global OnHttpError
handler, if server responds with an error HTTP status code (>= 300). Use procedure Soap.SOAPHTTPTrans.SetOnHttpError
to install the global handler. It has HTTPResponse: IHTTPResponse
as its second parameter, which lets you inspect returned headers. If the server responds with 1xx or 2xx status then you're out of luck and should consider implementing custom THTTPReqResp
descendant or migrating to more appropriate HTTP client implementation (e.g. THTTPClient
directly, or similar).
{ 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;
我个人认为这是处理此类情况的非常丑陋的方式,我只是不明白为什么它们在 new 代码中引入了全局处理程序,从而影响了THTTPReqResp
的所有实例.我对这个新设计完全没有印象.
In my personal opinion this is pretty ugly way to handle such cases and I just can't understand why they introduced global handler in new code, which affects all instances of THTTPReqResp
. I'm not impressed with this new design at all.
鹰眼:您是否注意到THTTPReqResp
(THTTPClient
,ESOAPHTTPException
)和SetOnHttpError
(TSOAPHttpErrorEvent
,TSOAPHttpErrorAction
)之间的字符大小写不一致?
Eagle eye: Have you noticed character case inconsistency between THTTPReqResp
(THTTPClient
, ESOAPHTTPException
) and SetOnHttpError
(TSOAPHttpErrorEvent
, TSOAPHttpErrorAction
)?
这篇关于如何从THTTPReqResp获取响应头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!