本文介绍了如何从THTTPReqResp获取响应头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用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;

使用THTTPReqRespTHTTPReqResp.HTTP时,我在哪里/如何访问标头?

Where/how can I access the headers when using THTTPReqResp or THTTPReqResp.HTTP?

该组件包含类型为THTTPClientHTTP属性,但我对此一无所知.文档使用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 a TNetHTTPClient 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 (and TNetHTTPRequest, those are the only two in the Net folder), but not a THTTPClient. This seems to indicate that THTTPClient is only meant to be used 'under the hood'. TNetHTTPClient also has a HTTP (THTTPClient) property, like THTTPReqResp, 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方法(GetExecute)和事件(OnBeforePostOnReceivingData)都不会暴露RequestResponse对象.

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(THTTPClientESOAPHTTPException)和SetOnHttpError(TSOAPHttpErrorEventTSOAPHttpErrorAction)之间的字符大小写不一致?

Eagle eye: Have you noticed character case inconsistency between THTTPReqResp (THTTPClient, ESOAPHTTPException) and SetOnHttpError (TSOAPHttpErrorEvent, TSOAPHttpErrorAction)?

这篇关于如何从THTTPReqResp获取响应头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-09 02:23