Как получить заголовки ответа от THTTPReqResp? - PullRequest
1 голос
/ 09 января 2020

У меня есть старый код, использующий THTTPReqResp, это вызывает Execute для SOAP запросов к веб-службам Exchange. Я изменяю его, чтобы (также) использовать логин OAuth. Это работает нормально, но у меня возникают проблемы с обнаружением, когда срок действия маркера доступа истек.

В тестовом приложении, использующем компонент TipwHTTP из nSoftware IP * Работает, я могу go через заголовки ответа, чтобы обнаружить тот, который указывает токен с истекшим сроком действия:

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?

Этот компонент содержит HTTP свойство типа THTTPClient но с этим я не справлюсь. Документация Использование HTTP-клиента гласит, что THTTPClient имеет OnRequestError и OnRequestcompleted события, но их нет в коде для THTTPClient или его помощник класса. Документация по этим событиям относится к System.Net.HttpClientComponent.TNetHTTPRequest, а не System.Net.THTTPClient, и , в System.Net нет HttpClientComponent.

Примечания:

  • Это Delphi 10.3.1 Рио; в 10.3 были внесены значительные изменения кода в THTTPReqResp.
  • System.Net.HttpClientComponent имеет TNetHTTPClient с этими двумя событиями, и в комментарии говорится, что это Компонент для управления HTTPClient , но этот код, по-видимому, не связан (т. е. HttpClientComponent никогда не используется)
  • С этим может быть связано то, что в палитре компонентов есть TNetHTTPClientTNetHTTPRequest, это единственные два в папке Net), но не THTTPClient. Кажется, это указывает на то, что THTTPClient предназначен только для использования «под капотом». TNetHTTPClient также имеет свойство HTTP (THTTPClient), например THTTPReqResp, но между ними нет наследования.

1 Ответ

1 голос
/ 10 января 2020

Как вы узнали, THTTPReqResp перенес операцию дробовика в Delphi 10.3. Первоначально он использовал Win INet на Windows и Indy на Linux под капотом, но они изменили его на THTTPClient (для поддержки мобильных платформ, я думаю).

В этой новой реализации ни один из THTTPReqResp методов (Get, Execute) и событий (OnBeforePost, OnReceivingData) не выставляет Request или Response объекты.

Однако, есть шанс получить доступ к объекту Response через глобальный обработчик OnHttpError, если сервер ответит ошибочным кодом состояния HTTP (> = 300). Используйте процедуру Soap.SOAPHTTPTrans.SetOnHttpError для установки глобального обработчика. Он имеет HTTPResponse: IHTTPResponse в качестве второго параметра, который позволяет вам проверять возвращаемые заголовки. Если сервер отвечает статусом 1xx или 2xx, то вам не повезло, и вам следует рассмотреть возможность реализации пользовательского потомка THTTPReqResp или перехода на более подходящую реализацию HTTP-клиента (например, THTTPClient напрямую или подобное).

{ 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;

По моему личному мнению, это довольно уродливый способ обработки таких случаев, и я просто не могу понять, почему они ввели глобальный обработчик в новый код, который затрагивает все экземпляры THTTPReqResp. Я совсем не впечатлен этим новым дизайном.

Eagle eye : Вы заметили несоответствие регистра символов между THTTPReqResp (THTTPClient, ESOAPHTTPException) и SetOnHttpError (TSOAPHttpErrorEvent, TSOAPHttpErrorAction)?

...