Iss*_*Ali 5 asp.net delphi indy delphi-2009
我有一个像这个简单的http://issamsoft.com/app2/page1.aspx这样的 Asp .net 页面 ,我想通过使用 TIdHttp 向它发布一些数据并从响应中提取数据。我尝试在 Delphi2009 中这样做:
Procedure TForm1.Button1Click(Sender: TObject);
Const
VIEWSTATE = '/wEPDwUKMjA3NjE4MDczNmRkSxPt/LdmgqMd+hN+hkbiqIZuGUk=';
EVENTVALIDATION = '/wEWAwL40NXEDALs0bLrBgKM54rGBtmtdOYy+U7IFq8B25bYT1d4o1iK';
FORMPARAMS = 'TextBox1=Issam&Button1=Button';
URL = 'http://issamsoft.com/app2/page1.aspx';
var
http: TIdHttp;
lstParams: TStringList;
begin
http := TIdHTTP.Create(self);
lstParams := TStringList.Create;
try
lstParams.Add('__VIEWSTATE='+VIEWSTATE);
lstParams.Add('__EVENTVALIDATION='+EVENTVALIDATION);
lstParams.Add(FORMPARAMS);
http.Request.ContentType := 'application/x-www-form-urlencoded';
Memo1.Lines.Text := http.Post(url,lstParams);
finally
http.Free;
lstParams.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
但是 TIdhttp 总是给出一个错误(HTTP/1.1 500 内部服务器错误。)
目前,当发出 POST 时,IdHTTP 会自动将协议设置为 1.0 版本,而与它最初的值无关,这是因为有些服务器不完全遵守 RFC。特别是,他们不尊重发送/不发送 Expect: 100-Continue 标头。在我们找到不破坏 RFC 的最佳解决方案之前,我们会将 POSTS 限制为 1.0 版。
我的代码有问题还是 TidHttp 错误?如果问题出在 TIdHttp 上,是否有任何解决方法?或者是否有其他使用 Indy 组件的解决方案?
除了。我已经使用 WebClient 在 C# 中制作了一个解决方案,并且效果很好。
private void button1_Click(object sender, EventArgs e)
{
WebClient myClient = new WebClient();
string viewstate = HttpUtility.UrlEncodeUnicode(@"/wEPDwUKMjA3NjE4MDczNmRkSxPt/LdmgqMd+hN+hkbiqIZuGUk=");
string eventvaildation = HttpUtility.UrlEncodeUnicode(@"/wEWAwL40NXEDALs0bLrBgKM54rGBtmtdOYy+U7IFq8B25bYT1d4o1iK");
string postdata = "__VIEWSTATE=" + viewstate + "&" +
"__EVENTVALIDATION=" + eventvaildation + "&TextBox1=Issam&Button1=Button";
myClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
byte[] responce = myClient.UploadData("http://issamsoft.com/app2/page1.aspx", Encoding.ASCII.GetBytes(postdata));
txtResponse.Text = Encoding.ASCII.GetString(responce);
}
Run Code Online (Sandbox Code Playgroud)
我在哪里可以找到(好的/可信的)类,比如 Delphi 中的 WebClient?免费首选:)
编辑:我希望 VIEWSTATE,EVENTVALIDATION 的机制对你来说足够清楚,它们是由服务器生成的哈希值,它们可能会改变(已经改变),我的原始项目有一段代码只是为了提取当前的 VIEWSTATE,EVENTVALIDATION 值,但我省略了这部分只是为了让我的例子简单明了,所以当你想尝试上面的代码时,你必须从当前页面源中获取 VIEWSTATE,EVENTVALIDATION 值。
这很可能是因为在 C# 中,您使用与号 ( & ) 字符来连接 VIEWSTATE、EVENTVALIDATION 和 FORMPARAMS。
但是在 Delphi 中,您使用 TStringList 和 Add。Add 不会在添加之间放置一个和号 ( & ),而是一个 CR+LF。
因此,您在 Delphi 中发送的数据与在 C# 中不同。
如果您更改 Delphi 中的字符串连接逻辑以匹配 C# 中的逻辑,它应该可以工作,无论您在 Delphi 端使用哪种 WebClient。
--杰罗恩
编辑:20090830
此代码有效;使用 Fiddler2 检查 C# 和 IE7 输出,我发现您还需要转义 '/' 和 '=' 字符。
编辑2:20090831
不知何故,网站上的 VIEWSTATE 和 EVENTVALIDATION 自昨天以来发生了变化(尽管我不确定为什么)。我已经更改了代码,它在发布我对此答案的更改时有效。这是从 Internet Explorer 7 中发布页面时按 Fiddler 捕获的新请求内容:
__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button
Run Code Online (Sandbox Code Playgroud)
这是从 Delphi 示例中发布时的新请求:
__VIEWSTATE=%2FwEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0%3D&__EVENTVALIDATION=%2FwEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q%3D&TextBox1=Issam&Button1=Button
Run Code Online (Sandbox Code Playgroud)
下面的示例现在给出了这个结果(注意结果中的“ Issam ”):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
</title></head>
<body>
<form name="form1" method="post" action="page1.aspx" id="form1">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMjA3NjE4MDczNg9kFgICAw9kFgICBQ8PFgIeBFRleHQFDVdlbGNvbWUgSXNzYW1kZGSCDMOkTMjkZJgqLkhpK99twpD5+A==" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAwKr+O/BBQLs0bLrBgKM54rGBlueO5BU/6BAJMZfHNwh5fsQFuAm" />
<div>
<input name="TextBox1" type="text" value="Issam" id="TextBox1" />
<input type="submit" name="Button1" value="Button" id="Button1" />
<br />
<span id="Label1">Welcome Issam</span>
<br />
</div>
</form>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
编辑3:20090831
事实上,VIEWSTATE 和 EVENTVALIDATION 再次发生了变化:不知何故,它们一直在变化:似乎涉及到时间因素。
所以我修改了代码,现在它可以从 GET 请求中提取 VIEWSTATE 和 EVENTVALIDATION,然后将其放入 POST 请求中。
此外,似乎“+”和“:”也需要转义。于是我深入研究了ASP.NET的页面生成逻辑,发现他们使用HttpUtility.UrlEncode来做转义,最终检查HttpUtility.IsSafe哪些字符要转义。所以我改编了把Reflector逆向工程的 Delphi 代码变成了一个 THttpUtility 类。
这是最终的代码:
{$DEFINE FIDDLER}
unit HttpPostExampleFormUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;
type
THttpPostExampleForm = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
procedure Log(const What: string; const Content: string);
procedure LogClear;
end;
var
HttpPostExampleForm: THttpPostExampleForm;
implementation
uses
HttpUtilityUnit;
{$R *.dfm}
procedure AddFormParameter(const StringStream: TStringStream; const ParameterName: string; const ParameterValue: string);
var
EncodedParameterValue: string;
begin
StringStream.WriteString(ParameterName);
StringStream.WriteString('=');
EncodedParameterValue := THttpUtility.UrlEncode(ParameterValue);
StringStream.WriteString(EncodedParameterValue);
end;
procedure AddFormParameterSeparator(const StringStream: TStringStream);
begin
StringStream.WriteString('&');
end;
function ExtractHiddenParameter(const ParameterName: string; const Request: string): string;
//<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMjA3NjE4MDczNg9kFgICAw9kFgICBQ8PFgIeBFRleHQFDVdlbGNvbWUgSXNzYW1kZGSCDMOkTMjkZJgqLkhpK99twpD5+A==" />
const
PrefixMask = 'input type="hidden" name="%s" id="%s" value="';
Suffix = '" />';
var
Prefix: string;
PrefixLength: Integer;
PrefixPosition: Integer;
SuffixPosition: Integer;
begin
Prefix := Format(PrefixMask, [ParameterName, ParameterName]);
PrefixPosition := Pos(Prefix, Request);
if PrefixPosition = 0 then
Result := ''
else
begin
PrefixLength := Length(Prefix);
Result := Copy(Request,
PrefixPosition + PrefixLength,
1 + Length(Request) - PrefixPosition - PrefixLength);
SuffixPosition := Pos(Suffix, Result);
if SuffixPosition = 0 then
Result := ''
else
Delete(Result, SuffixPosition, 1 + Length(Result) - SuffixPosition);
end;
end;
procedure THttpPostExampleForm.Button1Click(Sender: TObject);
const
DefaultVIEWSTATE = '/wEPDwUKMjA3NjE4MDczNmRk5%2FC2iWwvlAB3L1wYzRpm3KZhRC0=';
DefaultEVENTVALIDATION = '/wEWAwLXzuATAuzRsusGAoznisYGSYOqDGy4vMunY6A8xi6ahQEPI5Q=';
FORMPARAMS = 'TextBox1=Issam&Button1=Button';
URL = 'http://issamsoft.com/app2/page1.aspx';
__VIEWSATE = '__VIEWSTATE';
__EVENTVALIDATION = '__EVENTVALIDATION';
var
VIEWSTATE: string;
EVENTVALIDATION: string;
getHttp: TIdHttp;
getRequest: string;
postHttp: TIdHttp;
ParametersStringStream: TStringStream;
postRequest: string;
begin
LogClear();
getHttp := TIdHTTP.Create(self);
try
getRequest := getHttp.Get(URL);
Log('GET Request', getRequest);
VIEWSTATE := ExtractHiddenParameter(__VIEWSATE, getRequest);
EVENTVALIDATION := ExtractHiddenParameter(__EVENTVALIDATION, getRequest);
Log('Extracted VIEWSTATE', VIEWSTATE);
Log('Extracted EVENTVALIDATION', EVENTVALIDATION);
finally
getHttp.Free();
end;
postHttp := TIdHTTP.Create(self);
{$IFDEF FIDDLER}
postHttp.ProxyParams.ProxyServer := '127.0.0.1';
postHttp.ProxyParams.ProxyPort := 8888;
{$ENDIF FIDDLER}
postHttp.HTTPOptions := postHttp.HTTPOptions + [hoKeepOrigProtocol];
ParametersStringStream := TStringStream.Create('');
try
AddFormParameter(ParametersStringStream, __VIEWSATE, VIEWSTATE);
AddFormParameterSeparator(ParametersStringStream);
AddFormParameter(ParametersStringStream, __EVENTVALIDATION, EVENTVALIDATION);
AddFormParameterSeparator(ParametersStringStream);
ParametersStringStream.WriteString(FORMPARAMS);
postHttp.Request.ContentType := 'application/x-www-form-urlencoded';
ParametersStringStream.Seek(0, soFromBeginning);
Log('POST Parameters', ParametersStringStream.DataString);
postRequest := postHttp.Post(url, ParametersStringStream);
Log('POST Request', postRequest);
finally
postHttp.Free;
ParametersStringStream.Free;
end;
end;
procedure THttpPostExampleForm.Log(const What, Content: string);
begin
Memo1.Lines.Add(What + '=');
Memo1.Lines.Add(Content);
end;
procedure THttpPostExampleForm.LogClear;
begin
Memo1.Lines.Clear;
end;
end.
Run Code Online (Sandbox Code Playgroud)
和 THttpUtility 类:
unit HttpUtilityUnit;
interface
type
THttpUtility = class
private
class function IsSafe(const ch: Char): boolean;
public
class function UrlEncode(s: string): string;
end;
implementation
uses
Classes, SysUtils;
class function THttpUtility.IsSafe(const ch: Char): boolean;
begin
if ((((ch >= 'a') and (ch <= 'z')) or ((ch >= 'A') and (ch <= 'Z'))) or ((ch >= '0') and (ch <= '9'))) then
Result := True
else
case ch of
'''',
'(',
')',
'*',
'-',
'.',
'_',
'!':
Result := True;
else
Result := False;
end;
end;
class function THttpUtility.UrlEncode(s: string): string;
var
ch: Char;
HexCh: string;
StringStream: TStringStream;
Index: Integer;
Ordinal: Integer;
begin
StringStream := TStringStream.Create('');
try
//Note: this is not yet UTF-16 compatible; check before porting to Delphi 2009
for Index := 1 to Length(s) do
begin
ch := s[Index];
if IsSafe(ch) then
StringStream.WriteString(Ch)
else
begin
Ordinal := Ord(Ch);
HexCh := IntToHex(Ordinal, 2);
StringStream.WriteString('%'+HexCh);
end;
end;
Result := StringStream.DataString;
finally
StringStream.Free;
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)
这应该能让你继续前进。
--杰罗恩