You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从THTTPReqResp获取响应头以检测OAuth令牌过期?

在Delphi 10.3.1 Rio中检测EWS OAuth令牌过期(THTTPReqResp/TNetHTTPRequest方案)

针对你遇到的问题——用THTTPReqResp做EWS OAuth请求时无法检测令牌过期,我结合Delphi 10.3的版本特性给你两个可行的方案:

核心背景说明

首先要理清一个关键混淆点:Delphi 10.3里的THTTPClient分两种:

  • 底层类System.Net.HttpClient.THTTPClient:无可视化界面,没有你在文档里看到的OnRequestError/OnRequestCompleted事件
  • 可视化组件System.Net.HttpClientComponent.TNetHTTPRequest:就是组件面板Net文件夹里的那个,它才带有事件和便捷的响应处理API

而10.3对THTTPReqResp做了重大重构,现在它内部依赖的是底层THTTPClient,但功能受限,官方更推荐直接使用TNetHTTPClient + TNetHTTPRequest组合来处理HTTP请求。


方案一:改用TNetHTTPClient + TNetHTTPRequest(推荐)

这是最灵活的方式,能直接捕获响应头并检测令牌过期:

步骤1:组件准备

在窗体上拖放TNetHTTPClient和TNetHTTPRequest,将TNetHTTPRequest.Client属性指向你的TNetHTTPClient实例。

步骤2:检测令牌过期的两种实现方式

方式A:通过OnResponseReceived事件实时检测

给TNetHTTPRequest绑定OnResponseReceived事件,在响应到达时直接遍历头信息:

procedure TYourForm.NetHTTPRequest1ResponseReceived(Sender: TObject;
  AResponse: IHTTPResponse);
var
  LHeader: TNameValuePair;
begin
  FTokenExpired := False;
  // 遍历所有响应头
  for LHeader in AResponse.Headers do
  begin
    // 匹配目标头字段
    if SameText(LHeader.Name, 'x-ms-diagnostics') then
    begin
      // 检查过期标识
      if (Pos('2000002', LHeader.Value) > 0) and 
         (Pos('The token has expired', LHeader.Value) > 0) then
      begin
        FTokenExpired := True;
        Break;
      end;
    end;
  end;
end;

方式B:请求完成后直接访问响应对象

如果不需要实时处理,也可以在执行请求后直接从响应对象中提取头信息:

procedure TYourForm.SendEWSSOAPRequest(const ABaseURL, ABody: string);
var
  LResponse: IHTTPResponse;
begin
  try
    // 配置请求参数
    NetHTTPRequest1.Method := rmPOST;
    NetHTTPRequest1.URL := ABaseURL;
    NetHTTPRequest1.ContentType := 'text/xml; charset=utf-8'; // EWS要求的Content-Type
    // 设置SOAP请求体
    NetHTTPRequest1.Body.Clear;
    NetHTTPRequest1.Body.Add(ABody);
    
    // 执行请求并获取响应
    LResponse := NetHTTPRequest1.Execute;
    
    // 手动检查令牌过期
    CheckTokenExpired(LResponse);
  except
    on E: Exception do
    begin
      // 注意:EWS令牌过期通常不会抛出异常,而是返回200 OK但带错误头,所以不要只在异常块处理
      ShowMessage('请求异常: ' + E.Message);
    end;
  end;
end;

// 单独封装检查逻辑
procedure TYourForm.CheckTokenExpired(AResponse: IHTTPResponse);
var
  LHeader: TNameValuePair;
begin
  FTokenExpired := False;
  for LHeader in AResponse.Headers do
  begin
    if SameText(LHeader.Name, 'x-ms-diagnostics') then
    begin
      if (Pos('2000002', LHeader.Value) > 0) and 
         (Pos('The token has expired', LHeader.Value) > 0) then
      begin
        FTokenExpired := True;
        Break;
      end;
    end;
  end;
end;

方案二:继续使用THTTPReqResp(兼容旧代码)

如果你不想替换旧的THTTPReqResp代码,也可以通过它的Execute方法返回的IHTTPResponse对象访问响应头:

procedure TYourForm.UseOldTHTTPReqResp(const ABaseURL, ABody: string);
var
  LHTTPReqResp: THTTPReqResp;
  LResponse: IHTTPResponse;
  LHeader: TNameValuePair;
begin
  LHTTPReqResp := THTTPReqResp.Create(nil);
  try
    LHTTPReqResp.URL := ABaseURL;
    LHTTPReqResp.Method := rmPOST;
    LHTTPReqResp.ContentType := 'text/xml; charset=utf-8';
    LHTTPReqResp.PostData := ABody;
    
    // 执行请求并获取响应
    LResponse := LHTTPReqResp.Execute;
    
    // 检查令牌过期
    FTokenExpired := False;
    for LHeader in LResponse.Headers do
    begin
      if SameText(LHeader.Name, 'x-ms-diagnostics') then
      begin
        if (Pos('2000002', LHeader.Value) > 0) and 
           (Pos('The token has expired', LHeader.Value) > 0) then
        begin
          FTokenExpired := True;
          Break;
        end;
      end;
    end;
  finally
    LHTTPReqResp.Free;
  end;
end;

注意事项

EWS的令牌过期行为比较特殊:它通常不会返回4xx/5xx的错误状态码,而是返回200 OK,但在响应头中携带x-ms-diagnostics错误标识。所以不要只在异常块中检查过期,一定要在请求成功后遍历响应头。

内容的提问来源于stack exchange,提问作者Jan Doggen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 07:57:44