【问题标题】:IdHTTP how to send raw bodyIdHTTP 如何发送原始正文
【发布时间】:2017-06-21 01:14:56
【问题描述】:

我如何使用IdHTTPPostMan 的身份发送消息如下:

我的第一次尝试如下:

function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
  _URL = 'https://URL.com/SendMessage';
var
  Params   : TStringStream;
  Response : string;
  LMsg     : string;
begin
  Result := False;
  LMsg := '-----------------------------13932'+
          'Content-Type: application/json; charset=utf-8'+
          'Content-Description: message'+ sLineBreak+          '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}'+
          '-----------------------------13932--;'+sLineBreak;
  Params := TStringStream.Create(LMsg, TEncoding.UTF8);
  try
    IdHTTP.Request.CustomHeaders.AddValue('authorization', 'Bearer ' + FToken);
    IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
    IdHTTP.Request.UserAgent      := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
    IdHTTP.Request.Accept         := '*/*';
    IdHTTP.Request.Referer        := 'https://www.URL.com/en-us/';
    IdHTTP.Request.Host           := 'URL.com';
    IdHTTP.Request.AcceptEncoding := 'gzip, deflate, br';
    IdHTTP.Request.AcceptLanguage := 'Accept-Language';
    IdHTTP.Request.ContentType    := 'multipart/mixed; boundary="---------------------------13932"';
    Params.Position               := 0;
    try
      Response := IdHTTP.Post(_URL, Params);
      Result := True;
    except
      on E: Exception do
        Writeln('Error on Send Message request: '#13#10, e.Message);
    end;
    Writeln(IdHTTP.Request.RawHeaders.Text);
  finally
    Params.Free;
  end;
end;

第二次尝试这种方式

function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
const
  _URL = 'https://URL.com/SendMessage';
var
  Params   : TStringStream;
  Response : string;
  LMsg     : string;
begin
  Result := False;
  LMsg := '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}';
  Params := TStringStream.Create(LMsg, TEncoding.UTF8);
  try
    IdHTTP.Request.CustomHeaders.AddValue('authorization', 'Bearer ' + FToken);
    IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
    IdHTTP.Request.CustomHeaders.AddValue('Content-Description', 'message'); // I addedd this as on PostMan Body
    IdHTTP.Request.UserAgent      := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
    IdHTTP.Request.Accept         := '*/*';
    IdHTTP.Request.Referer        := 'https://www.URL.com/en-us/';
    IdHTTP.Request.Host           := 'URL.com';
    IdHTTP.Request.AcceptEncoding := 'gzip, deflate, br';
    IdHTTP.Request.AcceptLanguage := 'Accept-Language';
    IdHTTP.Request.ContentType    := 'application/json; charset=utf-8'; // I alos changed this as it shown on PostMan body
    Params.Position               := 0;
    try
      Response := IdHTTP.Post(_URL, Params);
      Result := True;
    except
      on E: Exception do
        Writeln('Error on Send Message request: '#13#10, e.Message);
    end;
    Writeln(IdHTTP.Request.RawHeaders.Text);
  finally
    Params.Free;
  end;
end;

两次尝试都给出HTTP/1.1 400 Bad Request

可以告诉我我做错了什么吗?

【问题讨论】:

    标签: http delphi indy idhttp


    【解决方案1】:

    在您的第一个示例中,您的“原始”MIME 数据格式不正确:

    • 您缺少一堆必需的换行符。并且不要使用sLineBreak 常量,因为它的值是特定于平台的。 MIME 期望换行符专门使用CRLF。 Indy 有一个用于该值的 EOL 常量。

    • 在结束边界线的末尾有一个错误的分号。

    您也没有正确设置Request.AcceptEncoding 属性。不要手动启用编码,除非您准备在响应中实际手动处理它们(您的代码不是)。如果将TIdZLibCompressorBase 派生组件(如TIdCompressorZLib)分配给TIdHTTP.Compressor 属性,TIdHTTP 将为您处理gzipdeflate 编码。不用担心br 编码,它没有被广泛使用。简而言之,将Request.AcceptEncoding 保留为默认值,让TIdHTTP 为您管理。

    您也没有正确设置Request.AcceptLanguage 属性。您应该将其设置为'en-US,en;q=0.8',而不是'Accept-Language'

    如果您进行这些修复,您的第一个示例应该可以工作,例如:

    function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
    const
      _URL = 'https://URL.com/SendMessage';
    var
      Params   : TStringStream;
      Response : string;
      LMsg     : string;
    begin
      Result := False;
      LMsg := '-----------------------------13932' + EOL +
              'Content-Type: application/json; charset=utf-8' + EOL +
              'Content-Description: message' + EOL +
              EOL +
              '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}' + EOL +
              '-----------------------------13932--' + EOL;
      Params := TStringStream.Create(LMsg, TEncoding.UTF8);
      try
        IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
        IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
        IdHTTP.Request.UserAgent      := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
        IdHTTP.Request.Accept         := '*/*';
        IdHTTP.Request.Referer        := 'https://www.URL.com/en-us/';
        IdHTTP.Request.Host           := 'URL.com';
        IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
        IdHTTP.Request.ContentType    := 'multipart/mixed; boundary="---------------------------13932"';
    
        try
          Response := IdHTTP.Post(_URL, Params);
          Result := True;
        except
          on E: Exception do
            Writeln('Error on Send Message request: '#13#10, e.Message);
        end;
        Writeln(IdHTTP.Request.RawHeaders.Text);
      finally
        Params.Free;
      end;
    end;
    

    或者:

    function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
    const
      _URL = 'https://URL.com/SendMessage';
    var
      Params   : TMemoryStream;
      Response : string;
      LMsg     : string;
    begin
      Result := False;
      Params := TMemoryStream.Create;
      try
        WriteStringToStream(Params, '-----------------------------13932' + EOL);
        WriteStringToStream(Params, 'Content-Type: application/json; charset=utf-8' + EOL);
        WriteStringToStream(Params, 'Content-Description: message' + EOL);
        WriteStringToStream(Params, EOL);
        WriteStringToStream(Params, '{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}' + EOL, IndyTextEncoding_UTF8);
        WriteStringToStream(Params, '-----------------------------13932--' + EOL);
        Params.Position := 0;
    
        IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
        IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
        IdHTTP.Request.UserAgent      := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
        IdHTTP.Request.Accept         := '*/*';
        IdHTTP.Request.Referer        := 'https://www.URL.com/en-us/';
        IdHTTP.Request.Host           := 'URL.com';
        IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
        IdHTTP.Request.ContentType    := 'multipart/mixed; boundary="---------------------------13932"';
    
        try
          Response := IdHTTP.Post(_URL, Params);
          Result := True;
        except
          on E: Exception do
            Writeln('Error on Send Message request: '#13#10, e.Message);
        end;
        Writeln(IdHTTP.Request.RawHeaders.Text);
      finally
        Params.Free;
      end;
    end;
    

    或者:

    function TIdFoo.SendIM(const AID, AMessage: string): Boolean;
    const
      _URL = 'https://URL.com/SendMessage';
    var
      Params   : TMemoryStream;
      Response : string;
      LMsg     : string;
    begin
      Result := False;
      Params := TMemoryStream.Create;
      try
        with TStreamWriter.Create(Params, TEncoding.UTF8) do
        try
          NewLine := EOL;
          WriteLine('-----------------------------13932');
          WriteLine('Content-Type: application/json; charset=utf-8');
          WriteLine('Content-Description: message');
          WriteLine;
          WriteLine('{"message":{"Type":1,"body":"'+AMessage+'"},"to":["'+AID+'"]}');
          WriteLine('-----------------------------13932--');
        finally
          Free;
        end;
        Params.Position := 0;
    
        IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FToken);
        IdHTTP.Request.CustomHeaders.AddValue('Origin', 'https://www.URL.com');
        IdHTTP.Request.UserAgent      := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36';
        IdHTTP.Request.Accept         := '*/*';
        IdHTTP.Request.Referer        := 'https://www.URL.com/en-us/';
        IdHTTP.Request.Host           := 'URL.com';
        IdHTTP.Request.AcceptLanguage := 'en-US,en;q=0.8';
        IdHTTP.Request.ContentType    := 'multipart/mixed; boundary="---------------------------13932"';
    
        try
          Response := IdHTTP.Post(_URL, Params);
          Result := True;
        except
          on E: Exception do
            Writeln('Error on Send Message request: '#13#10, e.Message);
        end;
        Writeln(IdHTTP.Request.RawHeaders.Text);
      finally
        Params.Free;
      end;
    end;
    

    在您的第二个示例中,您的“原始”数据只是 JSON 本身,而不是任何包装它的 MIME。您将 MIME 标头放在它们不属于的 HTTP 标头中。如果服务器需要 MIME 数据而不仅仅是原始 JSON 数据,则此示例将不起作用。

    Request.AcceptEncodingRequest.AcceptLanguage 属性也犯了同样的错误。


    由于您以 MIME 格式发布数据,处理这个更简单的方法是改用 Indy 的 TIdMultipartFormDataStream 类,让它为您处理 MIME 格式。但是,该类目前不支持:

    • 将流的RequestContentType 属性设置为自定义值(在本例中为'multipart/mixed',而不是'multipart/form-data')。不过,您可以使用访问器类来完成此操作,因为 FRequestContentType 成员是 protected

    • 省略个别字段的Content-Disposition: form-data 标头。这可能会导致不期待 form-data 提交的服务器出错。

    • 完全指定 Content-Description MIME 标头(请参阅 GitHub 上 Indy 问题跟踪器中的 Add support for user-defined MIME headers in TIdMultipartFormDataStream)。

    因此,您将不得不继续手动格式化 MIME 数据。你只需要确保你做对了。

    【讨论】:

    • 非常感谢您的精彩回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 2011-06-29
    相关资源
    最近更新 更多