IdHTTP how to send raw body

强颜欢笑 提交于 2020-02-21 02:55:50

问题


How i can use IdHTTP to send message as PostMan dos below:

My first attempt was as follow:

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;

The second attempt i try it this way

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;

Both attempts gives HTTP/1.1 400 Bad Request.

Can any advice my what i', doing wrong?


回答1:


In your first example, your "raw" MIME data is not formatted correctly:

  • You are missing a bunch of required line breaks. And don't use the sLineBreak constant, as its value is platform-specific. MIME expects line breaks to use CRLF specifically. Indy has an EOL constant for that value.

  • You have an erroneous semicolon on the end of the closing boundary line.

You are also not setting the Request.AcceptEncoding property correctly. DO NOT enable encodings manually, unless you are prepared to actually handle them manually in responses (which your code is not). TIdHTTP handles gzip and deflate encodings for you, if you assign a TIdZLibCompressorBase-derived component, like TIdCompressorZLib, to the TIdHTTP.Compressor property. Don't worry about the br encoding, it is not widely used. In short, leave the Request.AcceptEncoding at its default and let TIdHTTP manage it for you.

You are also not setting the Request.AcceptLanguage property correctly. You should be setting it to 'en-US,en;q=0.8', not to 'Accept-Language'.

Your first example should work if you make these fixes, eg:

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;

Alternatively:

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;

Alternatively:

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;

In your second example, your "raw" data is just the JSON by itself, not any MIME wrapping it. You are putting MIME headers in the HTTP headers, where they don't belong. This example will not work if the server expects MIME data and not just raw JSON data.

You are also making the same mistakes with the Request.AcceptEncoding and Request.AcceptLanguage properties.


Since you are posting data in MIME format, an easier way to handle this would have been to use Indy's TIdMultipartFormDataStream class instead, and let it handle the MIME formatting for you. However, that class does not currently support:

  • setting the stream's RequestContentType property to a custom value (in this case, 'multipart/mixed' instead of 'multipart/form-data'). Though, you can use an accessor class to accomplish this, since the FRequestContentType member is protected.

  • omitting the Content-Disposition: form-data header on individual fields. This might trip up servers that are not expecting form-data submissions.

  • specifying the Content-Description MIME header at all (see Add support for user-defined MIME headers in TIdMultipartFormDataStream in Indy's issue tracker on GitHub).

So you will have to continue resorting to formatting the MIME data manually. You just have to make sure you get it right.



来源:https://stackoverflow.com/questions/44665349/idhttp-how-to-send-raw-body

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!