IdHTTP如何发送原始请求体

4

如何使用IdHTTP像下面的PostMan一样发送消息:

Headers Body

我的第一次尝试如下:

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

请问我做错了什么?

1个回答

16

在您的第一个示例中,您的“原始”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标头(请参见Indy问题跟踪器上的为TIdMultipartFormDataStream添加用户定义的MIME标头)。
因此,您必须继续手动格式化MIME数据。 您只需要确保正确即可。

1
非常感谢您提供的精彩答案。 - RepeatUntil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接