如何从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
    有一个带有这两个事件的
    TNetHTTPClient
    ,一条评论说它是一个用于管理HTTPClient的组件,但该代码似乎没有链接(即,
    HttpClientComponent
    从未使用)
  • 可能相关的是,组件调色板中有一个
    TNetHTTPClient
    (和
    TNetHTTPRequest
    ,它们是网络文件夹中仅有的两个),但没有
    THTTPClient
    。这似乎表明
    THTTPClient
    仅用于“发动机罩下”
    TNetHTTPClient
    也有一个HTTP(
    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,因此,我无法在此基础上区分其他错误。我只是想确定global
OnHttpError
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;