问题: http post 数据到底怎么弄? ( 积分: 100 )
分类: Internet/TCPIP
来自: CJ, 时间: 2002-07-24 22:15:00, ID: 1221113
随便用INDY还是FASTNET,我FORM见下,我现在用STRINGLIST声称临时文件,用WEBBROWSER递交,可以。
但是用FASTNET/INDY的HTTP控件都不行。说有内容为空。
st.Add('<HTML>');
st.Add('<form name=f1 method="POST" action="pwd.asp">');
st.Add(' <td width="87%" height="25"><input type="text" name="userid" value="' + EditUser.Text + '" size="15"></td>');
st.Add(' <td width="87%" height="25"><font size="2"><input type="password" name="userpwd" value = "' + EditPass.Text + '" size="15"> </font> </td>');
st.Add(' <td width="87%" height="94" valign="top"><select size="12" name="zhuanye">');
st.Add(' <option selected value="'+ EditSpecification.Text + '">专升本:计算机科学与技术</option>');
st.Add(' </select> </td>');
st.Add(' <td width="87%" height="18"><input');
st.Add(' type="radio" value="r1" checked name="usertype"><font size="2"> 用户 </font><input');
st.Add(' type="radio" name="usertype" value="r2">管理员</td>');
st.Add(' size="2"> <input type="submit" value="确定" name="B1"> <input type="reset"');
st.Add(' value="放弃" name="B2"> <a href="http://olclass.shtvu.edu.cn/onlineclass1/zhuce_des.htm" target="_blank">网上注册</a> </font>');
st.Add('</form>');
st.Add('</HTML>');
来自: Nizvoo, 时间: 2002-07-24 22:17:00, ID: 1221117
学习~~~~~~~~~~~
来自: SeaSky, 时间: 2002-08-19 23:16:00, ID: 1274691
有你这么弄得吗?
好久不见了,我现在在上海做项目,可能要1个多月。
st.Add('userid='+ UrlEncode(EditUser.Text) + '&userpwd=' + UrlEncode(EditPass.Text) + '&zhuanye='+UrlEncode(EditSpecification.Text)
+'&usertype=r1' + '&B1=确定')
每个表单域用形如 name=value 的方式,每个域之间用"&"隔开"
对 value 部分最好近用UrlEncode对源码进行编码,否则会造成解析中的歧义。
来自: CJ, 时间: 2002-08-20 19:38:00, ID: 1276661
SeaSky啊,真是好久不见啊,我过两天就去北京了。
我现在是用WEBBROWSER.PERFORM...做的,所以,才加到STRINGLIST中。
我试过了,HTTP不是GET而是POST,所以不是在URL上加的,而是加到那个什么东西里(1下想不出来)可用这个方法也不成。
来自: SeaSky, 时间: 2002-08-20 19:48:00, ID: 1276677
POST一样呀,POST部分的文本就是这么编码的呀. (找点协议跟踪的东东你就会发现了)
procedure Post("http://www.someurl.com/poster.asp", aTstring, outputResponestream);
到北京做什么?
有空msn: linxin@msn.com
来自: SeaSky, 时间: 2002-08-20 19:55:00, ID: 1276681
var st : Tstring ;
outputResponestream : Tstream ;
begin
..
..
..
st.Add('userid='+ UrlEncode(EditUser.Text) + '&userpwd=' + UrlEncode(EditPass.Text) + '&zhuanye='+UrlEncode(EditSpecification.Text)
+'&usertype=r1' + '&B1=确定');
idhttp1.Post('http://www.someurl.com/poster.asp', st, outputResponestream);
来自: CJ, 时间: 2002-08-20 21:36:00, ID: 1276842
这个函数我知道,可总是不成功的:(
MSN:CJCJC@ONLINE.SH.CN
来自: 千中元, 时间: 2002-08-20 21:53:00, ID: 1276879
前段时间用到get的时候,查资料写出这个,
如果还不能解决,你将 UrlEncode用getUTF8代替试下。
可能用到别的函数库,如果缺少,发在qq上发消息给我,把unit给你也行
UCS4 = Cardinal;
function TForm1.getUTF8(s: String): String;
var
i: integer;
begin
s:= WideStringToUTF8(s);
Result := '';
for i:=1 to length(s) do
begin
Result:=Result+'%'+inttohex(ord(s
),2);
end;
end;
function WideStringToUTF8(S: WideString): AnsiString;
var
ch: UCS4;
L, J, T,
bytesToWrite: Word;
byteMask: UCS4;
byteMark: UCS4;
begin
if Length(S) = 0 then
begin
Result := '';
Exit;
end;
SetLength(Result, Length(S) * 6); // assume worst case
T := 1;
for J := 1 to Length(S) do
begin
byteMask := $BF;
byteMark := $80;
ch := UCS4(S[J]);
if ch < $80 then
bytesToWrite := 1
else
if ch < $800 then
bytesToWrite := 2
else
if ch < $10000 then
bytesToWrite := 3
else
if ch < $200000 then
bytesToWrite := 4
else
if ch < $4000000 then
bytesToWrite := 5
else
if ch <= MaximumUCS4 then
bytesToWrite := 6
else
begin
bytesToWrite := 2;
ch := ReplacementCharacter;
end;
for L := bytesToWrite downto 2 do
begin
Result[T + L - 1] := Char((ch or byteMark) and byteMask);
ch := ch shr 6;
end;
Result[T] := Char(ch or firstByteMark[bytesToWrite]);
Inc(T, bytesToWrite);
end;
SetLength(Result, T - 1); // assume worst case
end;
调用:
if edtAll.Text<>'' then
begin
All := trim(edtAll.Text);
All := getUTF8(All);
end;
来自: SeaSky, 时间: 2002-08-20 22:20:00, ID: 1276942
还有可能就是你的HTTP request 头没有处理对,好像需要增加一个content-type 声明
为formed data (具体什么记不得了。)
但TCP跟踪一下就知道了。
来自: SeaSky, 时间: 2002-08-20 22:34:00, ID: 1276975
找到了
Content-type: application/x-www-form-urlencoded
delphi :
IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded' ;
IdHTTP1.Request.ContentLength := lenght(st.text)
来自: 千中元, 时间: 2002-09-27 10:57:00, ID: 1348617
2 SeaSky,
D7中我在 Interface下uses IdURI,
,报告说:[Error] Unit1.pas(46): Undeclared identifier: 'UrlEncode'.
最后只有将IdURI.pas加入自己的Application,在Implementation部分 use一下.好痛苦的说.
请问知道解决办法么?
另外,你的帖子中:
var st : Tstring ;
应该是TStrings吧?
var
idURi : TIdURI;
Response : TStringStream ;
st : TStrings;
a : String;
begin
idUri := TidURI.Create();
a := idUri.URLEncode(Edit1.Text);
end;
来自: 千中元, 时间: 2002-09-27 6:04:00, ID: 1348619
这样不能post成功,
[red] idUri := TidURI.Create(); [/red]
会引发下面的异常:
idUri := TidURI.Create();function TIdURI.GetFullURI(
const AOptionalFileds: TIdURIOptionalFieldsSet): String;
Var
LURI: String;
begin
if Length(FProtocol) = 0 then
[red] raise EIdURIException.Create(RSURINoProto); [/red]
来自: 千中元, 时间: 2002-09-27 8:05:00, ID: 1348626
这次用D6测试
uses idglobal;
var
Responses : TStringStream ;
st : TStrings;
PostText : string;
begin
Responses := TStringStream.Create('');
PostText := 'HomeUrl='+UrlEncode(Edit1.text)+'&yourContent=' + UrlEncode(Edit2.text);
st := TStringList.Create;
st.Append(PostText);
try
IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded' ;
IdHTTP1.Request.ContentLength := length(st.text);
[red]idHttp1.Post('http://www.xxtax.gov.cn/delphi/guest.htm',st,Responses);[/red]
-----提交的时候出错,method 405 not allowed
finally
ResPonses.Free;
St.Free;
end;
来自: 千中元, 时间: 2002-09-27 16:22:00, ID: 1349940
2 SeaSky,
D7中不用增加 contenttype的声明
>>还有可能就是你的HTTP request 头没有处理对,好像需要增加一个content-type 声明
>>为formed data (具体什么记不得了。)
procedure TIdCustomHTTP.Post(AURL: string; const ASource: TStrings; const AResponseContent: TStream);
var
LParams: TStringStream;
begin
// Usual posting request have default ContentType is application/x-www-form-urlencoded
if (Request.ContentType = '') or (AnsiSameText(Request.ContentType, 'text/html')) then
Request.ContentType := 'application/x-www-form-urlencoded';
LParams := TStringStream.Create(SetRequestParams(ASource));
try
Post(AURL, LParams, AResponseContent);
finally
LParams.Free;
end;
end;
来自: 千中元, 时间: 2002-09-27 20:59:00, ID: 1350447
初步查到原因,'http://www.xxtax.gov.cn/delphi/guest.htm'
后缀名不能为.htm
来自: 千中元, 时间: 2002-09-28 0:38:00, ID: 1350487
直接将后缀名改为.asp
var
Responses : TStringStream ;
st : TStrings;
PostText : string;
begin
Responses := TStringStream.Create('');
//PostText := 'HomeUrl='+UrlEncode(Edit1.text);
PostText := 'HomeUrl='+Edit1.text+'&yourContent=' + Edit2.text;
st := TStringList.Create;
st.Add(PostText);
try try
IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded' ;
IdHTTP1.Request.ContentLength := length(st.text);
idHttp1.Post('http://169.12.2.27/qian/guest.asp', st, Responses);
Memo1.Text := Responses.DataString;
Except
on E: Exception do
showmessage('Error encountered during POST: ' + E.Message);
end;
finally
ResPonses.Free;
St.Free;
end;
Memo1中显示Responses的DataString如下(未能post上数据):
<HTML>
<HEAD>
<TITLE>资源共享网站列表</TITLE>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</HEAD>
<BODY bgcolor="a4d5ff">
<form method="post" action="../myWebServer.exe/form" >
<P> <LABLE for "HomePage" > 资源共享网站首页地址:</LABLE>
<P><LABLE for "HomePage" ></LABLE>
<td class="row2"><input type="text" style="width:200px" name="HomeUrl" size="25" maxlength="255" id="HomePage" value="" /></td>
<P><BR>
<Lable > 共享内容简介:</LABLE>
<P><Lable ></LABLE>
<input type="text" style="width:200px" name="yourContent" size="25" maxlength="255" id="myContent" value="" />
<P> <BR>
<tr>
<th> </th>
<th> </th>
<p>
<input type="submit" name="pushbutton" value=" Submit ">
<input type="reset" name="resetButton" value=" Clear ">
</P>
</form>
</body>
</HTML>
来自: aimingoo, 时间: 2002-09-28 15:46:00, ID: 1351639
在HTTP发送时, Post是将数据加入到消息体中, 也就是Context部分中, 它不会出现在URL部分(Get是这样),
因而与URL编码是无关的. Post内文的编码是由IE缺省编码负责的, 可以不用管. 如果你真的是自己来处理,
可以往下面看.
form表单有一个属性, 是enctype, 它用于给Context部分的内容编码或表明内容的类型, 如果你要发送超
大的文件(比如大于48K, 注意, 是48K, 而不是64K), 你就需要用多节数据, 这种情况下, 一个简单的表单
应该写成这样:
-----------------------------------------------------------------
<form method="post" enctype="multipart/form-data"
action="http://192.168.0.114/Scripts/DBCenter.dll/add">
<input type="file" name="aFile"><br><br>
<input type="submit" value="发送文件">
<input type="reset" value="取消发送">
</form>
-----------------------------------------------------------------
但是, 这是针对是大数据块, 或文件的, CJ的这个表单没有这样的问题. 所以也与enctype无关.
你的这个错误信息提示是"有内容为空", 那么, 应该是你的表单中有一项或多项的值传到服务器
上时, 是没有值的. 我仔细地查了一下, 这个表单发到服务器上的数据会是这个样子:
userid=abc&userpwd=def&zhuanye=ghi&usertype=r1&B1=%C8%B7%B6%A8
这个数据其实还是正常的, 表单中"放弃"(B2)按钮的值不会被发到服务器上, 这是IE内定的.
所以, 我认为, 这不是你的表单的问题.(你的表单中有些错误, 但不影响这个结果)
这也是你"用WEBBROWSER递交,可以"的原因.
而且Indy等将HTML加入(add)的话, 其实也是最终返回给客户端的WebBrowser处理的, 这个是
一样的. 所以还是与HTML无关.
我想, 这与你操作Indy的那段代码有关系, 也就是说, 你用Indy返回这个表单到客户端的浏览
器, 其中你有用了一个中介, 就是"TStringList", 我在想, 你是不是这段代码写的有问题, 使
Indy的返回的Respones.Context的内容为空, 从而导致上述的错误. 或者类似的原因?
第二点, 是我写完上述内容后才发现的:
TIdHttp.Post()这个方法我没有看过, 我向来不用INDY的. 但是, SeaSkey给出了这个过程的声明:
procedure Post("http://www.someurl.com/poster.asp", aTstring, outputResponestream);
那么, 我想, 你们是不是理解错了?
其实, 一个HttpClient的这两个参数表通常是这样用的:
aTString : 用来提供一个值对, 表示将要Post的数据
outputResponestream : 用来提供一个Context的全文, 表明Post流的Memory.
那么, 什么样的"值对"才是Indy所理解的呢? 其实应该是很简单的, 就是标准的TStringList的用法:
Name=value
这样的值对就可以了.
而不需要象CJ提供的代码那样, 连HTML都放了进去. 那样反倒是错的了. 你想, Indy会从aTString
中去分析一遍HTML的语法吗? ---- 不会吧!
此外, 我想, 如果不通过流来Post, 这个outputResponestream参数是不是可以设成nil?
因此, 我想应该这样用才合理啊:
begin
...
st.Add('userid=abc');
st.Add('zhuanye=ghi');
st.Add('usertype=r1');
idhttp1.Post('http://www.someurl.com/poster.asp', st, nil);
//或
//idhttp1.Post('http://www.someurl.com/poster.asp', st, outputResponestream);
...
end;
来自: 千中元, 时间: 2002-09-28 17:37:00, ID: 1351886
给以给一个地址供大家测试:
http://www.xxtax.gov.cn/delphi/guest.asp
asp页面的代码:
<HTML>
<HEAD>
<TITLE>资源共享网站列表</TITLE>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</HEAD>
<BODY bgcolor="a4d5ff">
<form method="post" action="myWebServer.exe/form" >
<P> <LABLE for "HomePage" > 资源共享网站首页地址:</LABLE>
<P><LABLE for "HomePage" ></LABLE>
<td class="row2"><input type="text" style="width:200px" name="HomeUrl" size="25" maxlength="255" id="HomePage" value="" /></td>
<P><BR>
<Lable > 共享内容简介:</LABLE>
<P><Lable ></LABLE>
<TEXTAREA wrap=logical name="yourContent" ROWS=6 COLS=60 value="This is a test"Swansea, IL></TEXTAREA>
<P> <BR>
<tr>
<th> </th>
<th> </th>
<p>
<input type="submit" name="pushbutton" value=" Submit ">
<input type="reset" name="resetButton" value=" Clear ">
</P>
</form>
</body>
</HTML>
来自: 千中元, 时间: 2002-10-06 21:42:00, ID: 1351892
indy程序是否能post上去
可以通过如下网址查看:
http://www.xxtax.gov.cn/delphi/mywebserver.exe/entries
来自: 千中元, 时间: 2002-09-28 17:45:00, ID: 1351897
测试,仍未能post。
今晚别过诸位,先去沐浴更衣,然后回家休息几天。
这个程序比较重要,几乎是最后的问题了,2天多的时间无结果。
国庆回来仍然不能 post只能嵌入TwebBrowser了[]
aimin你用ics?
来自: aimingoo, 时间: 2002-09-28 18:54:00, ID: 1351980
哈哈,我用Synapse, 只用三行代码:
fHTTP := THTTPSend.Create;
fHTTP.Document.write(...); //写一个流, 是待POST的数据
fHTTP.HTTPMethod('POST', aURL);
//OK啦, 结果被返回到fHTTP.Document中了.
哈哈.
来自: 千中元, 时间: 2002-09-28 18:57:00, ID: 1351985
一会去坐火车,回农村安心修养,indy就拜托你了。呵呵
来自: aimingoo, 时间: 2002-10-07 2:54:00, ID: 1362024
OH...看了一下Indy的代码和帮助, 是这样的:
function Post(AURL: string; const ASource: TStrings): string; overload;
function Post(AURL: string; const ASource: TStream): string; overload;
function Post(AURL: string; const ASource: TIdMultiPartFormDataStream): string; overload;
procedure Post(AURL: string; const ASource: TStrings; const AResponseContent: TStream); overload;
procedure Post(AURL: string; const ASource: TStream; const AResponseContent: TStream); overload;
procedure Post(AURL: string; const ASource: TIdMultiPartFormDataStream; AResponseContent: TStream); overload;
1.
---------------------------------------------------------------
前三个方法和后三个方法是成对的, 意思差不多. function post()的返回值与procedure post()中的AResponseContent入口
参数是相当的, 是这样的一种关系:
Result_for_PostFunctionReturn
=
(Param_AResponseContent_for_PostProcedure as TStringStream).DataString
2.
---------------------------------------------------------------
AResponseContent的真实意义是怎样的?
由于一个POST方法向服务器发出数据后, 服务器会返回数据到Client, 无论这个Client
是你的应用, 或者是IE都是一样. IE将这个结果显示出来, 而在Indy实现的应用的Client
端, 这个返回结果被放在AResponseContent中. 当然, 如果你用Function式的调用, 则
结果会被强制处理成一个String返回.
3.
---------------------------------------------------------------
ASource到底是什么?
ASource很奇怪, 它几乎不符合我对HTTP Client的所有思考(我是说为了编程便捷的思考),
直到我读了它的源代码才发现, 它实际上就是POST数据块的Context(上下文), 也就是说,
你在写Client端时, 需要足够的考虑HTTP协议中POST数据块的结构!
GOD!
ASource的数据类型有三种,
ASource: TStrings;
ASource: TStream;
ASource: TIdMultiPartFormDataStream;
其中, TStrings和TStream是完全一样的, 都是将它们的内容直接作为内文POST到Server,
TStrings这种情况时, 相当于将ASource.SaveToStream的结果作为TStream处理.
通常如果POST的数据较小, 我们可以直接使用TStrings或TStream的ASource, 当然, 这种
情况下, 你需要自己来组织数据块(下一段详述).
而如果数据量比较大的话, 你就需要使用TIdMultiPartFormDataStream这个类型的ASource
了. 但使用这个类型的话, 却比较易用, 并不需要更多的理解POST数据块的结构.
----真奇怪Indy为什么要这样处理, 事实上, 如果三种调用方法都按TIdMultiPartFormDataStream
的方式来处理, 编程会容易得多. 我是指这样可以避免程序员去了解Http Client Data_Block Structure!
使用TIdMultiPartFormDataStream时, 只需要Create一个对象实例, 然后调用以下方法:
AddFile()
AddFormField()
AddObject()
添加表单数据即可. 本例中, 千中元的数据就可以如下处理就OK了.
AObj := TIdMultiPartFormDataStream.Create;
AObj.AddFormField('userid', EditUser.text);
AObj.AddFormField('userpwd', EditPass.Text);
AObj.AddFormField('zhuanye', EditSpecification.Text);
if ARadioGroup.ItemIndex = 0 then
AObj.AddFormField('usertype', 'r1') //用户
else
AObj.AddFormField('usertype', 'r2'); //管理员
s := IdHTTP.Post(AURL, AObj);
在TIdMultiPartFormDataStream中, Indy为自动设定Boundary和RequestContentType两个
属性, 你不能修改它们. 这使得你可以完全忽略"MultiPartFormData"这种HTTP Post数据
块的结构.
但是, 我需要提醒的是, 使用这种方法虽然简单, 但是, 却不是高效的. 介于HTTP协议的
规定, 使用MultiPartFormData将会导致更多次的C/S连接和更多的冗余的数据. 因此, 我
仅建议在大量的数据(超过48K或不定长文件)传输时使用这种方法.
4.
---------------------------------------------------------------
如何使用TStrings作为ASource?
由于使用TStream和Strings是几乎同样的, 因此, 我只需要介绍TStrings.
如上所述, 我们需要先了解Post数据块的结构, 如果你用HttpSpy或者HTTPTracer
一类的工具来查看一个HTTP POST请求, 你会发现, 它实际上是(类似)这样的
-------------------------------------------------------------------------
POST http://127.0.0.1/ HTTP/1.0
User-Agent: Mozilla/4.06 [en] (Win95; I)
Host: 127.0.0.1
Accept: image/gif, image/jpeg, image/pjpeg, image/png, */*
userid=abc&userpwd=def&zhuanye=ghi&usertype=r1&B1=%C8%B7%B6%A8
-------------------------------------------------------------------------
前面一部分被称做HTTP Head, 在indy中, 这一部分是不需要关心的, 因为Indy会比
较智能
来自: aimingoo, 时间: 2002-10-07 2:56:00, ID: 1362026
演示代码就不给你写了, 打开了Delphi, 装完Indy, 分析完上述的问题, 最后一想,
真没什么代码可以写的. 哈哈.
来自: tanghz, 时间: 2003-03-06 9:44:00, ID: 1659055
aimingoo:
有分给你。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1659037
来自: 巡城浪子, 时间: 2003-05-13 20:08:00, ID: 1857958
gz
来自: 人在昆明, 时间: 2003-05-13 20:12:00, ID: 1857975
以前写的,自动登陆站点用的
procedure TFrmUrlCommit.CommitUrlData(vRefererUrl: OleVariant;
UserField, UserValue, PasswordField, PasswordValue: string;
OtherPostData: OleVariant);
// 内部小函数,把提交字符串写入variant;
function GetPostData(Content: string): OleVariant;
var
I: Integer;
begin
Result := VarArrayCreate([0, length(content)], varByte);
for i := 0 to Length(content) - 1 do
begin
Result := Ord(content[i + 1]);
end;
Result[Length(content)] := 0;
end;
// 内部小函数结束
var
vHeaders, vPostData, vFrame, vFlags, vCommitData: OleVariant;
aWBCommit: TWebBrowser;
begin
aWBCommit := TWebBrowser.Create(nil);
vHeaders := 'Content-Type: application/x-www-form-urlencoded' + #10#13#0;
if VarIsNull(OtherPostData) then
vCommitData := UserField + '=' + UserValue + '&' +
PasswordField + '=' + PasswordValue
else
vCommitData := UserField + '=' + UserValue + '&' +
PasswordField + '=' + PasswordValue + '&' + OtherPostData;
vPostData := GetPostData(vCommitData);
vFlags := 31;
TVarData(vPostData).vType := varArray;
aWBCommit.Navigate2(vRefererUrl, vFlags, vFrame, vPostData, vHeaders);
FreeAndNil(aWBCommit);
end;
来自: CJ, 时间: 2004-10-04 20:18:23, ID: 2834503
多人接受答案了。
问题讨论没有结束 ...