问题
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.
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;
Where/how can I access the headers when using THTTPReqResp
or THTTPReqResp.HTTP
?
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
has
OnRequestError 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
.
Notes:
- 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.
回答1:
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).
In this new implementation none of THTTPReqResp
methods (Get
, Execute
) and events (OnBeforePost
, OnReceivingData
) expose Request
or Response
objects.
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;
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.
Eagle eye: Have you noticed character case inconsistency between THTTPReqResp
(THTTPClient
, ESOAPHTTPException
) and SetOnHttpError
(TSOAPHttpErrorEvent
, TSOAPHttpErrorAction
)?
来源:https://stackoverflow.com/questions/59666531/how-to-get-at-response-headers-from-thttpreqresp