如何使用TIdHttp GET请求发送内容?

时间:2019-01-23 15:07:14

标签: http delphi indy idhttp

我正在尝试访问一个REST服务器,该服务器的端点使用GET动词,同时还需要在体内发送json数据

我正在尝试使用Get方法使用TIdHttp类来实现这一目标。

现在,我使用json数据创建一个TStringStream,然后将该流分配给TIdHttp对象的Request.Source属性。

但是,服务器将以错误代码响应,指示它未接收到正文。

如何使用TIdHttp发送带有GET请求的正文?

2 个答案:

答案 0 :(得分:3)

正如雷米(Remy)所建议的,您可以破解' 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便捷方法(当时)并未涵盖我们的所有用例,而不仅仅是GET ,尤其是涉及REST Api的时候。请注意,以上不是我们当时的实际代码,我不再可以访问它。

我们使用TIdHttp(不是真实名称)而不是直接使用TOurHttp类,而是使用了许多对我们有用的便利方法。我们还发现我们必须对IgnoreReplies行为进行更改并扩展其他方面,以适应各种“流氓” REST Api服务器行为(并非所有行为均符合HTTP标准),而您又不会在大多数用例中都可以找到。

当然,您可以尝试要求Api或HTTP服务器的提供者更改其结尾,而不是固定客户端的行为。祝你好运。 ;)

背景阅读

HTTP协议规范确实允许GET请求提交请求正文,但是绝大多数实现不允许(或只是忽略任何此类内容)。这也许是因为历史上绝大多数实现都是针对浏览器行为或由其驱动的,再加上HTTP规范不幸地在该区域允许了一些“麻烦的空间”。

这导致我们今天的现状,在撰写本文时(2019年1月),HTTP规范RFC7231 has this to say about content in a GET request的相关部分:

  

GET请求消息中的有效负载没有定义的语义;   在GET请求上发送有效内容正文可能会导致一些现有内容   拒绝请求的实现。

即允许请求内容 ,因为它没有明确禁止,并且其使用被确认为可能,并且有时是预期的(有时只是拒绝)。但是,您不能依靠服务器对这种请求采用任何特定的解释(甚至接受)。

这当然不会帮助客户端处理已经决定其特定解释的特定服务器。通过以这种方式放弃实践,HTTP规范的这种迭代没有用。它只是描述了实践中的差异,而没有提供一个规范,可以根据该规范对实现的合规性/准确性进行测试。

答案 1 :(得分:1)

分配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;