Доступ к данным JSON после Indy POST - PullRequest
0 голосов
/ 01 февраля 2019

Мне трудно узнать, как получить доступ к ответу на запрос Indy POST.Я публикую данные в формате JSON или paramstring.Мой код при использовании JSON выглядит следующим образом.

params := TStringList.Create;
try
  params.Text :=
    '{'
    + format ('"client_secret":"%s",', [FilesFrm.ClientSecret])
    + format ('"client_id":"%s",', [FilesFrm.ClientId])
    + '"grant_type":"authorization_code",'
    + '"redirect_uri":"http://localhost:8080",'
    + format ('"code":"%s"', [fCode])
    + '}';
  idLogFile1.Active := true;
  // Make sure it uses HTTP 1.1, not 1.0
  IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol];
  IdHTTP1.Request.ContentType := 'application/json';
  IdHttp1.Request.Accept := 'application/vnd.hmrc.1.0+json';

  try
    result := IdHTTP1.Post (
      'https://test-api.service.hmrc.gov.uk/oauth/token',
      params);
  except
    on E: Exception do
    memo1.lines.add (E.ClassName + ': ' + E.message);
    end;

  memo1.Lines.add (result);
  memo1.Lines.add (idHTTP1.ResponseText);
finally
  params.free;
  end;

Результат печати результата и RepsonseText просто

EIdHTTPProtocolException: HTTP/1.1 400 Bad Request

HTTP/1.1 400 Bad Request

Однако, поскольку у меня есть компонент TidLogFile, присоединенный к TidHTTP,Я вижу, что на самом деле приходит, а именно:

Recv 2/1/2019 7:56:07 AM: HTTP/1.1 400 Bad Request<EOL>
Content-Type: application/json<EOL>
Content-Length: 72<EOL>
Cache-Control: no-cache,no-store,etc, etc...
; Secure; HTTPOnly<EOL><EOL>
{"error":"invalid_request","error_description":"grant_type is required"}

Помимо того факта, что grant_type присутствует в исходных данных запроса, я хотел бы иметь возможность получить доступ к ответу JSON в конце, поскольку "grant_type_is_required" гораздо более полезен, чем "Плохой запрос", но я не могу найти, где он находится.

Впоследствии я обнаружил Response.ContentLength, который содержит значение 72, и Response.ContentStream, который должентеоретически содержит 72 байта данных, но выдает нарушения доступа при попытке извлечь данные.

len := idHTTP1.Response.ContentLength;
memo1.Lines.Add(format ('Length = %d', [len]));
if assigned (idHTTP1.Response.ContentStream) then
  begin
  //idHTTP1.Response.ContentStream.Position := 0;
  result := ReadStringFromStream (idHTTP1.Response.ContentStream, len);
  end;
memo1.lines.add (result);

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

В дополнение к ответу mjn42, который является технически правильным, TIdHTTP также имеет необязательные флаги hoNoProtocolErrorException и hoWantProtocolErrorContent в свойстве HTTPOptions, которые можно включить, чтобы избежать поднятия EIdHTTPProtocolException и заполнитьВаша result переменная с данными об ошибках соответственно:

params := TStringStream.Create(
  '{'
  + format ('"client_secret":"%s",', [FilesFrm.ClientSecret])
  + format ('"client_id":"%s",', [FilesFrm.ClientId])
  + '"grant_type":"authorization_code",'
  + '"redirect_uri":"http://localhost:8080",'
  + format ('"code":"%s"', [fCode])
  + '}',
  TEncoding.UTF8);
try    
  IdLogFile1.Active := true;

  // Make sure it uses HTTP 1.1, not 1.0, 
  // and disable EIdHTTPProtocolException on errors
  IdHTTP1.ProtocolVersion := pv1_1;
  IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol, hoNoProtocolErrorException, hoWantProtocolErrorContent];

  IdHTTP1.Request.ContentType := 'application/json';
  IdHTTP1.Request.Accept := 'application/vnd.hmrc.1.0+json';

  try
    result := IdHTTP1.Post('https://test-api.service.hmrc.gov.uk/oauth/token', params);
  except
    on E: Exception do begin
      Memo1.Lines.Add(E.ClassName + ': ' + E.message);
      raise;
    end;
  end;

  Memo1.Lines.Add(result);
finally
  params.Free;
end;
0 голосов
/ 01 февраля 2019

Вот пример , который показывает, как можно получить доступ к телу HTTP.

К телу можно получить доступ, если вы перехватите исключение EIdHTTPProtocolException.

  on E: EIdHTTPProtocolException do
  begin
    WriteLn(E.Message);
    WriteLn(E.ErrorMessage);
  end;

Полный пример кода :

program JSONPostExample;

{$APPTYPE CONSOLE}

uses
  IdHTTP, IdGlobal, SysUtils, Classes;

var
  HTTP: TIdHTTP;
  RequestBody: TStream;
  ResponseBody: string;
begin
  HTTP := TIdHTTP.Create;
  try
    try
      RequestBody := TStringStream.Create('{"日本語":42}',
        TEncoding.UTF8);
      try
        HTTP.Request.Accept := 'application/json';
        HTTP.Request.ContentType := 'application/json';
        ResponseBody := HTTP.Post('https://httpbin.org/post',
          RequestBody);
        WriteLn(ResponseBody);
        WriteLn(HTTP.ResponseText);
      finally
        RequestBody.Free;
      end;
    except
      on E: EIdHTTPProtocolException do
      begin
        WriteLn(E.Message);
        WriteLn(E.ErrorMessage);
      end;
      on E: Exception do
      begin
        WriteLn(E.Message);
      end;
    end;
  finally
    HTTP.Free;
  end;
  ReadLn;
  ReportMemoryLeaksOnShutdown := True;
end.

Обратите внимание, что нельзя использовать TStringList для тела POST.Эта версия TIdHTTP.Post () форматирует данные в соответствии с типом носителя application / x-www-form-urlencoded, который не подходит для JSON, и повредит их.

...