使用Indy进行HTTP Post

12

我在我的web服务器上有一个简单的php脚本,我需要使用HTTP POST上传文件,我正在使用Delphi进行操作。

这是我的Indy代码,但显然它不起作用,我无法弄清楚我做错了什么。是否有这样一种工具可以查看我在服务器上发送的内容?

procedure TForm1.btn1Click(Sender: TObject);
var
  fname : string;
  MS,dump : TMemoryStream;
  http  : TIdHTTP;

const
  CRLF = #13#10;
begin
  if PromptForFileName(fname,'','','','',false) then
  begin
    MS := TMemoryStream.Create();
    MS.LoadFromFile(fname);
    dump := TMemoryStream.Create();
    http := TIdHTTP.Create();
    http.Request.ContentType:='multipart/form-data;boundary =-----------------------------7cf87224d2020a';
    fname := CRLF + '-----------------------------7cf87224d2020a' + CRLF + 'Content-Disposition: form-data; name=\"uploadedfile\";filename=\"test.png"' + CRLF;
    dump.Write(fname[1],Length(fname));
    dump.Write(MS.Memory^,MS.Size);
    fname := CRLF + '-----------------------------7cf87224d2020a--' + CRLF;
    dump.Write(fname[1],Length(fname));
    ShowMessage(IntToStr(dump.Size));
    MS.Clear;
    try
    http.Request.Method := 'POST';
    http.Post('http://posttestserver.com/post.php',dump,MS);
    ShowMessage(PAnsiChar(MS.Memory));
    ShowMessage(IntToStr(http.ResponseCode));
    except
    ShowMessage('Could not bind socket');
    end;
  end;
end;

2
当调试某些东西时,“它不起作用”是最没有用的短语。它指什么不起作用?它做错了什么? - Mason Wheeler
如果我知道答案,我可能就不会问这个问题了。它没有上传到Web服务器,这是问题所在,我猜测提交的标头格式错误,但我不知道我错在哪里。 - opc0de
为什么在 http.Post( URL, MS ) 之前要调用 MS.Clear;? - user497849
1
所以你没有收到任何错误消息或其他提示,只是默默地失败了?这就是“不起作用”的意思。否则,请说“我收到了这个错误代码”或其他类似的信息。 - Warren P
3个回答

21

Indy有TIdMultipartFormDataStream来实现这个目的:

procedure TForm1.SendPostData;
var
  Stream: TStringStream;
  Params: TIdMultipartFormDataStream;
begin
  Stream := TStringStream.Create('');
  try
   Params := TIdMultipartFormDataStream.Create;
   try
    Params.AddFile('File1', 'C:\test.txt','application/octet-stream');
    try
     HTTP.Post('http://posttestserver.com/post.php', Params, Stream);
    except
     on E: Exception do
       ShowMessage('Error encountered during POST: ' + E.Message);
    end;
    ShowMessage(Stream.DataString);
   finally
    Params.Free;
   end;
  finally
   Stream.Free;
  end;
end;

1
使用Wireshark比较你的代码和Indy生成的报头。 - whosrdaddy
这太明显了,当然是TIdMultipartFormDataStream这个组件可以上传文件,我一直在找它,怎么会错过呢? :) - Toby Allen
@TobyAllen:每天学习新东西是开发者职业生涯的一部分 :) - whosrdaddy
提醒一下,对于不熟悉 PHP 或 Indy 的人:在此示例中,File1 是您在 PHP 中的 $_FILES[""] 变量的名称。我花了一些时间才明白这一点!感谢您的好答案。 - Aaron

2

从Indy调用PHP可能会因为User-Agent而失败,这时会收到403错误。

尝试以下方法,对我来说解决了问题:

var Answer: string;
begin
  GetHTML:= TIdHTTP.create(Nil);
  try
    GetHTML.Request.UserAgent:= 'Mozilla/3.0';
    Answer:= GetHTML.Get('http://www.testserver.com/test.php?id=1');
  finally
    GetHTML.Free;
  end;
end;

-1

你丢失了 2 个连字符 '--'。最好这样做:

http.Request.ContentType:='multipart/form-data;boundary='+myBoundery;
fname := CRLF + '--' + myBoundery + CRLF + 'Content-Disposition: form-data; name=\"uploadedfile\";filename=\"test.png"' + CRLF;

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