Как отправить контент с помощью GET-запроса TIdHttp? - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь получить доступ к серверу REST, у которого есть конечная точка, которая использует глагол GET, в то время как для этого также требуется отправка данных json в теле

Я пытаюсь сделать это с помощью класса TIdHttp, используя метод Get.

Сейчас я создаю TStringStream с данными json, а затем назначаю этот поток свойству Request.Source объекта TIdHttp.

Однако сервер отвечает кодом ошибки, указывающим, что он не получил тело.

Как отправить тело с GET-запросом, используя TIdHttp?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Как полагает Реми, вы можете взломать класс ' accessor ', чтобы получить доступ к этому методу с помощью вызова с принудительным типом.

или , вы могли быпросто подкласс TIdHttp и добавьте соответствующий, новый Get () удобный метод, следуя шаблонам, установленным для всех других таких методов.

например что-то вроде:

interface

  type
    TOurHttp = class(TIdHttp)
    public
      procedure Get(aUrl: String; aRequestBody, aResponseContent: TStream);
    end;

implementation

  procedure TOurHttp.Get(aUrl: String; aRequestBody, aResponseContent: TStream);
  begin
    DoRequest(Id_HttpMethodGet, aUrl, aRequestBody, aResponseContent, []);
  end;

Это то, что мы делали в компании, в которой я работал ранее, создавая программное обеспечение интеграции / промежуточного программного обеспечения, поскольку было много примеров, когда предоставляемые удобные методы Indy (в то время) не охватывали все наши варианты использования,не только ПОЛУЧИТЬ, особенно когда дело доходит до REST Api.Обратите внимание, что вышеприведенный код не является нашим реальным кодом с того времени, у меня больше нет доступа к нему.

Вместо непосредственного использования класса TIdHttp мы использовали TOurHttp (не настоящее имя), наделенныймногочисленные дополнительные удобные методы, полезные для нас.Мы также обнаружили, что нам пришлось вносить изменения и расширять аспекты других вещей, таких как поведение IgnoreReplies, чтобы приспособиться к различным «мошенническим» поведениям сервера REST Api (не все из которых были совместимы со стандартами HTTP), которые опять-таки вы не найдете вбольшинство случаев использования.

Конечно, вместо исправления поведения вашего клиента, вы можете попробовать попросить поставщика сервера Api или HTTP изменить их конец.Удачи с этим.;)

Фоновое чтение

Спецификация протокола HTTP позволяет GET-запросу отправлять тело запроса, но подавляющее большинство реализаций этого не делают (или просто игнорируют любой такой контент).Возможно, это связано с тем, что исторически подавляющее большинство реализаций нацелено на поведение браузера или управляется им, в сочетании с тем фактом, что спецификация HTTP, к сожалению, предоставляет некоторую «простор для маневра» в этой области.

где мы находимся сегодня, когда на момент написания (январь 2019 г.) соответствующая часть спецификации HTTP RFC7231 имеет такое же значение для содержимого в запросе GET :

Aполезная нагрузка в сообщении запроса GET не имеет определенной семантики;отправка тела полезной нагрузки по запросу GET может привести к тому, что некоторые существующие реализации отклонят запрос.

то есть содержимое запроса разрешено , поскольку это явно не запрещено, и его использование подтверждаетсянасколько это возможно, а иногда ожидается (и только иногда отвергается).Но вы не можете полагаться на сервер, принимающий какую-либо конкретную интерпретацию (или даже принятие) такого запроса.

Это, конечно, не помогает клиенту, имеющему дело с конкретным сервером, для которого решил на его конкретную интерпретацию.Признавая таким образом плохую практику, эта итерация спецификации HTTP менее чем полезна;он просто описывает отклонения на практике, а не предоставляет спецификацию, в соответствии с которой реализация может быть проверена на соответствие / точность.

0 голосов
/ 23 января 2019

Назначение свойства TIdHTTP.Request.Source не будет работать, поскольку Source будет заменено на nil, когда TIdHTTP.Get() вызовет TIdHTTP.DoRequest() внутренне передавая nil для его параметра ASource.

Итак, чтобы сделать то, что вы просите, вам придется позвонить DoRequest() напрямую. Тем не менее, это метод protected, поэтому для его использования вам понадобится класс доступа.

Например:

type
  TIdHTTPAccess = class(TIdHTTP)
  end;

var
  QueryData, ReplyData: TStream;
begin
  QueryData := TStringStream.Create('... json data here...', TEncoding.UTF8);
  try
    IdHTTP1.Request.ContentType := 'application/json';
    IdHTTP1.Request.CharSet := 'utf-8';

    //Result := IdHTTP1.Get('http://...');
    ReplyData := TMemoryStream.Create;
    try
      TIdHTTPAccess(IdHTTP1).DoRequest(Id_HTTPMethodGet, 'http://...', QueryData, ReplyData, []);
      ReplyData.Position := 0;
      Result := ReadStringAsCharset(ReplyData, IdHTTP1.Response.Charset);
    finally
      ReplyData.Free;
    end;
  finally
    QueryData.Free;
  end;
end;
...